mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-17 15:35:21 +02:00
Merge branch 'ga_game' into ga_game_cathy_plan
This commit is contained in:
commit
cacde32c91
16 changed files with 468 additions and 318 deletions
0
examples/__init__.py
Normal file
0
examples/__init__.py
Normal file
36
examples/st_game/actions/inner_voice_action.py
Normal file
36
examples/st_game/actions/inner_voice_action.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import re
|
||||
from examples.st_game.actions.st_action import STAction
|
||||
from examples.st_game.memory.agent_memory import BasicMemory
|
||||
from metagpt.logs import logger
|
||||
|
||||
class AgentWhisperThoughtAction(STAction):
|
||||
|
||||
def __init__(self, name="AgentWhisperThoughtAction", context: list[BasicMemory] = None, llm=None):
|
||||
super().__init__(name, context, llm)
|
||||
|
||||
def _func_validate(self, llm_resp: str, prompt: str) -> bool:
|
||||
try:
|
||||
self._func_cleanup(llm_resp, prompt)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list:
|
||||
return llm_resp.split('"')[0].strip()
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def create_prompt_input(role: "STRole", statements, test_input=None):
|
||||
prompt_input = [role.scratch.name, statements]
|
||||
return prompt_input
|
||||
|
||||
prompt_input = create_prompt_input(role, statements)
|
||||
prompt = self.generate_prompt_with_tmpl_filename(prompt_input,
|
||||
"whisper_inner_thought_v1.txt")
|
||||
|
||||
output = await self._run_v1(prompt)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
return output
|
||||
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
# @Desc : Integration Reflect Action
|
||||
|
||||
import re
|
||||
|
||||
from metagpt.logs import logger
|
||||
|
||||
from examples.st_game.actions.st_action import STAction
|
||||
|
|
@ -23,16 +24,18 @@ class AgentFocusPt(STAction):
|
|||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
llm_resp = "1) " + llm_resp.strip()
|
||||
ret = []
|
||||
for i in llm_resp.split("\n"):
|
||||
ret += [i.split(") ")[-1]]
|
||||
return ret
|
||||
try:
|
||||
"""
|
||||
Cleanup handling has been completed for run_v2
|
||||
"""
|
||||
return llm_resp
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, n: int, test_input=None) -> str:
|
||||
def run(self, role: "STRole", statements: str, n: int, test_input=None) -> str:
|
||||
def create_prompt_input(role: "STRole", statements, n, test_input=None):
|
||||
prompt_input = [statements, str(n)]
|
||||
return prompt_input
|
||||
|
|
@ -43,9 +46,9 @@ class AgentFocusPt(STAction):
|
|||
|
||||
example_output = '["What should Jane do for lunch", "Does Jane like strawberry", "Who is Jane"]'
|
||||
special_instruction = "Output must be a list of str."
|
||||
output = await self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
output = self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
return output
|
||||
|
||||
|
|
@ -63,23 +66,26 @@ class AgentInsightAndGuidance(STAction):
|
|||
except:
|
||||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
llm_resp = "1. " + llm_resp.strip()
|
||||
ret = dict()
|
||||
for i in llm_resp.split("\n"):
|
||||
row = i.split(". ")[-1]
|
||||
thought = row.split("(because of ")[0].strip()
|
||||
evi_raw = row.split("(because of ")[1].split(")")[0].strip()
|
||||
evi_raw = re.findall(r'\d+', evi_raw)
|
||||
evi_raw = [int(i.strip()) for i in evi_raw]
|
||||
ret[thought] = evi_raw
|
||||
return ret
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> dict:
|
||||
try:
|
||||
llm_resp = "1. " + llm_resp.strip()
|
||||
ret = dict()
|
||||
for i in llm_resp.split("\n"):
|
||||
row = i.split(". ")[-1]
|
||||
thought = row.split("(because of ")[0].strip()
|
||||
evi_raw = row.split("(because of ")[1].split(")")[0].strip()
|
||||
evi_raw = re.findall(r'\d+', evi_raw)
|
||||
evi_raw = [int(i.strip()) for i in evi_raw]
|
||||
ret[thought] = evi_raw
|
||||
return ret
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, n: int, test_input=None) -> str:
|
||||
def create_prompt_input(role: "STRole", statements, n, test_input=None):
|
||||
def run(self, role: "STRole", statements: str, n: int, test_input=None) -> dict:
|
||||
def create_prompt_input(role, statements, n, test_input=None):
|
||||
prompt_input = [statements, str(n)]
|
||||
return prompt_input
|
||||
|
||||
|
|
@ -87,7 +93,7 @@ class AgentInsightAndGuidance(STAction):
|
|||
prompt = self.generate_prompt_with_tmpl_filename(prompt_input,
|
||||
"insight_and_evidence_v1.txt")
|
||||
|
||||
output = await self._run_v1(prompt)
|
||||
output = self._run_v1(prompt)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
return output
|
||||
|
||||
|
|
@ -106,31 +112,37 @@ class AgentEventTriple(STAction):
|
|||
return False
|
||||
return True
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
cr = llm_resp.strip()
|
||||
cr = [i.strip() for i in cr.split(")")[0].split(",")]
|
||||
return cr
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list:
|
||||
try:
|
||||
cr = llm_resp.strip()
|
||||
cr = [i.strip() for i in cr.split(")")[0].split(",")]
|
||||
if len(cr) != 2:
|
||||
return cr[-2:]
|
||||
return cr
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, statements: str, role: "STRole", verbose=False) -> str:
|
||||
def run(self, statements: str, role: "STRole", verbose=False) -> tuple:
|
||||
def create_prompt_input(statements, role):
|
||||
if "(" in statements:
|
||||
statements = statements.split("(")[-1].split(")")[0]
|
||||
prompt_input = [role._rc.scratch.name,
|
||||
prompt_input = [role.scratch.name,
|
||||
statements,
|
||||
role._rc.scratch.name]
|
||||
role.scratch.name]
|
||||
return prompt_input
|
||||
|
||||
prompt_input = create_prompt_input(statements, role)
|
||||
prompt = self.generate_prompt_with_tmpl_filename(prompt_input,
|
||||
"generate_event_triple_v1.txt")
|
||||
|
||||
output = await self._run_v1(prompt)
|
||||
output = self._run_v1(prompt)
|
||||
output = (role.scratch.name, output[0], output[1])
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
|
||||
return output[0]
|
||||
return output
|
||||
|
||||
|
||||
# Run GPT Prompt Event Poignancy
|
||||
|
|
@ -145,18 +157,21 @@ class AgentEventPoignancy(STAction):
|
|||
except:
|
||||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
llm_resp = int(llm_resp.strip())
|
||||
return llm_resp
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int:
|
||||
try:
|
||||
llm_resp = int(llm_resp.strip())
|
||||
return llm_resp
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def create_prompt_input(role: "STRole", statements: str, test_input=None):
|
||||
prompt_input = [role._rc.scratch.name,
|
||||
role._rc.scratch.get_str_iss(),
|
||||
role._rc.scratch.name,
|
||||
prompt_input = [role.scratch.name,
|
||||
role.scratch.get_str_iss(),
|
||||
role.scratch.name,
|
||||
statements]
|
||||
return prompt_input
|
||||
|
||||
|
|
@ -166,9 +181,9 @@ class AgentEventPoignancy(STAction):
|
|||
|
||||
example_output = "5" # ########
|
||||
special_instruction = "The output should ONLY contain ONE integer value on the scale of 1 to 10."
|
||||
output = await self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
output = self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
|
||||
return output
|
||||
|
|
@ -186,18 +201,21 @@ class AgentChatPoignancy(STAction):
|
|||
except:
|
||||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
llm_resp = int(llm_resp.strip())
|
||||
return llm_resp
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int:
|
||||
try:
|
||||
llm_resp = int(llm_resp.strip())
|
||||
return llm_resp
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def create_prompt_input(role: "STRole", statements, test_input=None):
|
||||
prompt_input = [role._rc.scratch.name,
|
||||
role._rc.scratch.get_str_iss(),
|
||||
role._rc.scratch.name,
|
||||
prompt_input = [role.scratch.name,
|
||||
role.scratch.get_str_iss(),
|
||||
role.scratch.name,
|
||||
statements]
|
||||
return prompt_input
|
||||
|
||||
|
|
@ -207,9 +225,9 @@ class AgentChatPoignancy(STAction):
|
|||
|
||||
example_output = "5" # ########
|
||||
special_instruction = "The output should ONLY contain ONE integer value on the scale of 1 to 10."
|
||||
output = await self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
output = self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
|
||||
return output
|
||||
|
|
@ -228,24 +246,27 @@ class AgentPlanThoughtOnConvo(STAction):
|
|||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
return llm_resp.split('"')[0].strip()
|
||||
try:
|
||||
return llm_resp.split('"')[0].strip()
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def create_prompt_input(role, statements, test_input=None):
|
||||
prompt_input = [statements,
|
||||
role._rc.scratch.name,
|
||||
role._rc.scratch.name,
|
||||
role._rc.scratch.name]
|
||||
role.scratch.name,
|
||||
role.scratch.name,
|
||||
role.scratch.name]
|
||||
return prompt_input
|
||||
|
||||
prompt_input = create_prompt_input(role, statements)
|
||||
prompt = self.generate_prompt_with_tmpl_filename(prompt_input,
|
||||
"planning_thought_on_convo_v1.txt")
|
||||
|
||||
output = await self._run_v1(prompt)
|
||||
output = self._run_v1(prompt)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
|
||||
return output
|
||||
|
|
@ -264,17 +285,20 @@ class AgentMemoryOnConvo(STAction):
|
|||
return False
|
||||
|
||||
def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str:
|
||||
return llm_resp.split('"')[0].strip()
|
||||
try:
|
||||
return llm_resp.split('"')[0].strip()
|
||||
except Exception as exp:
|
||||
logger.error(f"{self.__class__.__name__} with error {exp}")
|
||||
|
||||
def _func_fail_default_resp(self) -> str:
|
||||
pass
|
||||
|
||||
async def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def run(self, role: "STRole", statements: str, test_input=None, verbose=False) -> str:
|
||||
def create_prompt_input(role, statements, test_input=None):
|
||||
prompt_input = [statements,
|
||||
role._rc.scratch.name,
|
||||
role._rc.scratch.name,
|
||||
role._rc.scratch.name]
|
||||
role.scratch.name,
|
||||
role.scratch.name,
|
||||
role.scratch.name]
|
||||
return prompt_input
|
||||
|
||||
prompt_input = create_prompt_input(role, statements)
|
||||
|
|
@ -282,9 +306,9 @@ class AgentMemoryOnConvo(STAction):
|
|||
"memo_on_convo_v1.txt")
|
||||
example_output = 'Jane Doe was interesting to talk to.'
|
||||
special_instruction = 'The output should ONLY contain a string that summarizes anything interesting that the agent may have noticed'
|
||||
output = await self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
output = self._run_v2(prompt,
|
||||
example_output,
|
||||
special_instruction)
|
||||
logger.info(f"Run action: {self.__class__.__name__} with result: {output}")
|
||||
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class STAction(Action):
|
|||
def _ask(self, prompt: str, system_msgs: Optional[list[str]] = None) -> str:
|
||||
return self.llm.ask(prompt)
|
||||
|
||||
def _run_v1(self, prompt: str, retry: int = 3) -> str:
|
||||
def _run_v1(self, prompt: str, retry: int = 3) :
|
||||
"""
|
||||
same with `gpt_structure.safe_generate_response`
|
||||
default post-preprocess operations of LLM response
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from datetime import datetime
|
|||
|
||||
from metagpt.memory.memory import Memory
|
||||
from metagpt.schema import Message
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
class BasicMemory(Message):
|
||||
|
|
@ -32,8 +33,8 @@ class BasicMemory(Message):
|
|||
self.memory_id: str = memory_id # 记忆ID
|
||||
self.memory_count: int = memory_count # 第几个记忆,实际数值与Memory相等
|
||||
self.type_count: int = type_count # 第几种记忆,类型为整数(具体不太理解如何生成的)
|
||||
self.type: str = memory_type # 记忆类型,包含 event,thought,chat三种类型
|
||||
self.depth: str = depth # 记忆深度,类型为整数
|
||||
self.memory_type: str = memory_type # 记忆类型,包含 event,thought,chat三种类型
|
||||
self.depth: int = depth # 记忆深度,类型为整数
|
||||
|
||||
self.created: datetime = created # 创建时间
|
||||
self.expiration: datetime = expiration # 记忆失效时间,默认为空()
|
||||
|
|
@ -62,10 +63,10 @@ class BasicMemory(Message):
|
|||
memory_dict[node_id] = dict()
|
||||
memory_dict[node_id]["node_count"] = self.memory_count
|
||||
memory_dict[node_id]["type_count"] = self.type_count
|
||||
memory_dict[node_id]["type"] = self.type
|
||||
memory_dict[node_id]["type"] = self.memory_type
|
||||
memory_dict[node_id]["depth"] = self.depth
|
||||
|
||||
memory_dict[node_id]["cmemory_dicteated"] = self.created.strftime('%Y-%m-%d %H:%M:%S')
|
||||
memory_dict[node_id]["created"] = self.created.strftime('%Y-%m-%d %H:%M:%S')
|
||||
memory_dict[node_id]["expiration"] = None
|
||||
if self.expiration:
|
||||
memory_dict[node_id]["expiration"] = (self.expiration
|
||||
|
|
@ -75,7 +76,7 @@ class BasicMemory(Message):
|
|||
memory_dict[node_id]["predicate"] = self.predicate
|
||||
memory_dict[node_id]["object"] = self.object
|
||||
|
||||
memory_dict[node_id]["description"] = self.description
|
||||
memory_dict[node_id]["description"] = self.content
|
||||
memory_dict[node_id]["embedding_key"] = self.embedding_key
|
||||
memory_dict[node_id]["poignancy"] = self.poignancy
|
||||
memory_dict[node_id]["keywords"] = list(self.keywords)
|
||||
|
|
@ -102,7 +103,7 @@ class AgentMemory(Memory):
|
|||
"""
|
||||
super(AgentMemory, self).__init__()
|
||||
self.id_to_node = dict() # TODO jiayi add
|
||||
self.storage: list[BasicMemory] = [] # 重写Stroage,存储BasicMemory所有节点
|
||||
self.storage: list[BasicMemory] = [] # 重写Storage,存储BasicMemory所有节点
|
||||
self.event_list = [] # 存储event记忆
|
||||
self.thought_list = [] # 存储thought记忆
|
||||
self.chat_list = [] # chat-related memory
|
||||
|
|
@ -114,6 +115,9 @@ class AgentMemory(Memory):
|
|||
self.kw_strength_event = dict() # 关键词影响存储
|
||||
self.kw_strength_thought = dict()
|
||||
|
||||
self.memory_saved = None
|
||||
self.embeddings = None
|
||||
|
||||
# self.load(memory_saved)
|
||||
|
||||
def set_mem_path(self, memory_saved: str):
|
||||
|
|
@ -122,13 +126,14 @@ class AgentMemory(Memory):
|
|||
|
||||
def save(self, memory_saved: str):
|
||||
"""
|
||||
将MemormyBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式
|
||||
将MemoryBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式
|
||||
这里添加一个路径即可
|
||||
TODO 这里在存储时候进行倒序存储,之后需要验证(test_memory通过)
|
||||
"""
|
||||
|
||||
memory_json = dict()
|
||||
for i in range(len(self.storage)):
|
||||
memory_node = self.storage[i]
|
||||
memory_node = self.storage[len(self.storage)-i-1]
|
||||
memory_node = memory_node.save_to_dict()
|
||||
memory_json.update(memory_node)
|
||||
with open(memory_saved + "/nodes.json", "w") as outfile:
|
||||
json.dump(memory_json, outfile)
|
||||
|
|
@ -152,16 +157,13 @@ class AgentMemory(Memory):
|
|||
node_id = f"node_{str(count + 1)}"
|
||||
node_details = memory_load[node_id]
|
||||
node_type = node_details["type"]
|
||||
created = datetime.datetime.strptime(node_details["created"],
|
||||
created = datetime.strptime(node_details["created"],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
expiration = None
|
||||
if node_details["expiration"]:
|
||||
expiration = datetime.datetime.strptime(node_details["expiration"],
|
||||
expiration = datetime.strptime(node_details["expiration"],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
|
||||
if node_details["cause_by"]:
|
||||
cause_by = node_details["cause_by"]
|
||||
|
||||
s = node_details["subject"]
|
||||
p = node_details["predicate"]
|
||||
o = node_details["object"]
|
||||
|
|
@ -172,16 +174,16 @@ class AgentMemory(Memory):
|
|||
poignancy = node_details["poignancy"]
|
||||
keywords = set(node_details["keywords"])
|
||||
filling = node_details["filling"]
|
||||
|
||||
if node_type == "thought":
|
||||
self.add_thought(created, expiration, s, p, o,
|
||||
description, keywords, poignancy, embedding_pair, filling)
|
||||
if node_type == "event":
|
||||
self.add_event(created, expiration, s, p, o,
|
||||
description, keywords, poignancy, embedding_pair, filling)
|
||||
elif node_type == "chat":
|
||||
if node_type == "chat":
|
||||
self.add_chat(created, expiration, s, p, o,
|
||||
description, keywords, poignancy, embedding_pair, filling, cause_by)
|
||||
elif node_type == "thought":
|
||||
self.add_thought(created, expiration, s, p, o,
|
||||
description, keywords, poignancy, embedding_pair, filling)
|
||||
description, keywords, poignancy, embedding_pair, filling)
|
||||
|
||||
|
||||
strength_keywords_load = json.load(open(memory_saved + "/kw_strength.json"))
|
||||
if strength_keywords_load["kw_strength_event"]:
|
||||
|
|
@ -194,29 +196,30 @@ class AgentMemory(Memory):
|
|||
Add a new message to storage, while updating the index
|
||||
重写add方法,修改原有的Message类为BasicMemory类,并添加不同的记忆类型添加方式
|
||||
"""
|
||||
if memory_basic in self.storage:
|
||||
if memory_basic.memory_id in self.storage:
|
||||
return
|
||||
self.storage.append(memory_basic)
|
||||
if memory_basic.cause_by:
|
||||
self.index[memory_basic.cause_by][0:0] = [memory_basic]
|
||||
if memory_basic.memory_type == "chat":
|
||||
self.chat_list[0:0] = [memory_basic]
|
||||
return
|
||||
if memory_basic.type == "thought":
|
||||
if memory_basic.memory_type == "thought":
|
||||
self.thought_list[0:0] = [memory_basic]
|
||||
return
|
||||
if memory_basic.type == "event":
|
||||
if memory_basic.memory_type == "event":
|
||||
self.event_list[0:0] = [memory_basic]
|
||||
return
|
||||
|
||||
def add_chat(self, created, expiration, s, p, o,
|
||||
content, keywords, poignancy,
|
||||
embedding_pair, filling,
|
||||
cause_by):
|
||||
cause_by = ''):
|
||||
"""
|
||||
调用add方法,初始化chat,在创建的时候就需要调用embeeding函数
|
||||
调用add方法,初始化chat,在创建的时候就需要调用embedding函数
|
||||
"""
|
||||
memory_count = len(self.storage) + 1
|
||||
type_count = len(self.thought_list) + 1
|
||||
memory_type = "chat"
|
||||
memory_id = f"memory_{str(memory_count)}"
|
||||
memory_id = f"node_{str(memory_count)}"
|
||||
depth = 1
|
||||
|
||||
memory_node = BasicMemory(memory_id, memory_count, type_count, memory_type, depth,
|
||||
|
|
@ -246,8 +249,8 @@ class AgentMemory(Memory):
|
|||
"""
|
||||
memory_count = len(self.storage) + 1
|
||||
type_count = len(self.thought_list) + 1
|
||||
memory_type = "event"
|
||||
memory_id = f"memory_{str(memory_count)}"
|
||||
memory_type = "thought"
|
||||
memory_id = f"node_{str(memory_count)}"
|
||||
depth = 1
|
||||
|
||||
try:
|
||||
|
|
@ -255,6 +258,7 @@ class AgentMemory(Memory):
|
|||
depth_list = [memory_node.depth for memory_node in self.storage if memory_node.memory_id in filling]
|
||||
depth += max(depth_list)
|
||||
except Exception as exp:
|
||||
logger.warning(f"filling init occur {exp}")
|
||||
pass
|
||||
|
||||
memory_node = BasicMemory(memory_id, memory_count, type_count, memory_type, depth,
|
||||
|
|
@ -291,7 +295,7 @@ class AgentMemory(Memory):
|
|||
memory_count = len(self.storage) + 1
|
||||
type_count = len(self.event_list) + 1
|
||||
memory_type = "event"
|
||||
memory_id = f"memory_{str(memory_count)}"
|
||||
memory_id = f"node_{str(memory_count)}"
|
||||
depth = 0
|
||||
|
||||
if "(" in content:
|
||||
|
|
@ -330,7 +334,7 @@ class AgentMemory(Memory):
|
|||
ret_set.add(e_node.summary())
|
||||
return ret_set
|
||||
|
||||
def get_last_chat(self, target_role_name: str) -> str:
|
||||
def get_last_chat(self, target_role_name: str):
|
||||
if target_role_name.lower() in self.chat_keywords:
|
||||
return self.chat_keywords[target_role_name.lower()][0]
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@
|
|||
# @Desc : Retrieve函数实现
|
||||
|
||||
import datetime
|
||||
from typing import Union
|
||||
|
||||
from numpy import dot
|
||||
from numpy.linalg import norm
|
||||
|
||||
from examples.st_game.memory.agent_memory import AgentMemory, BasicMemory
|
||||
from examples.st_game.memory.agent_memory import BasicMemory
|
||||
from examples.st_game.utils.utils import get_embedding
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memory_forget: float, query: str,
|
||||
topk: int = 4) -> list[BasicMemory]:
|
||||
def agent_retrieve(agent_memory, curr_time: datetime.datetime, memory_forget: float, query: str, nodes: list[BasicMemory],
|
||||
topk: int = 4, ) -> list[BasicMemory]:
|
||||
"""
|
||||
Retrieve需要集合Role使用,原因在于Role才具有AgentMemory,scratch
|
||||
逻辑:Role调用该函数,self._rc.AgentMemory,self._rc.scratch.curr_time,self._rc.scratch.memory_forget
|
||||
|
|
@ -27,13 +27,14 @@ def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memo
|
|||
"relevance": 搜索结果
|
||||
}
|
||||
"""
|
||||
memories = agent_memory.storage
|
||||
memories = nodes
|
||||
agent_memory_embedding = agent_memory.embeddings
|
||||
memories = sorted(memories, key=lambda memory_node: memory_node.last_accessed, reverse=True)
|
||||
|
||||
score_list = []
|
||||
score_list = extract_importance(memories, score_list)
|
||||
score_list = extract_recency(curr_time, memory_forget, score_list)
|
||||
score_list = extract_relevance(query, score_list)
|
||||
score_list = extract_relevance(agent_memory_embedding,query, score_list)
|
||||
score_list = normalize_score_floats(score_list, 0, 1)
|
||||
|
||||
total_dict = {}
|
||||
|
|
@ -43,31 +44,37 @@ def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memo
|
|||
score_list[i]['recency'] * gw[1] +
|
||||
score_list[i]['relevance'] * gw[2]
|
||||
)
|
||||
total_dict[score_list[i]['memory']] = total_score
|
||||
total_dict[score_list[i]['memory'].memory_id] = total_score
|
||||
|
||||
result = top_highest_x_values(total_dict, topk)
|
||||
|
||||
return result # 返回的是一个BasicMemory列表
|
||||
|
||||
|
||||
def new_agent_retrieve(strole: "STRole", focus_points: list, n_count=30):
|
||||
def new_agent_retrieve(role, focus_points: list, n_count=30) -> dict:
|
||||
"""
|
||||
输入为Strole,关注点列表,返回记忆数量
|
||||
输入为role,关注点列表,返回记忆数量
|
||||
输出为字典,键为focus_point,值为对应的记忆列表
|
||||
"""
|
||||
retrieved = dict()
|
||||
for focal_pt in focus_points:
|
||||
nodes = [[i.last_accessed, i]
|
||||
for i in strole._rc.memory.event_list + strole._rc.memory.thought_list
|
||||
for i in role.memory.event_list + role.memory.thought_list
|
||||
if "idle" not in i.embedding_key]
|
||||
nodes = sorted(nodes, key=lambda x: x[0])
|
||||
nodes = [i for created, i in nodes]
|
||||
results = agent_retrieve(strole._rc.memory, strole._rc.scratch.curr_time, strole._rc.scratch.recency_decay,
|
||||
focal_pt, n_count)
|
||||
results = agent_retrieve(role.memory, role.scratch.curr_time, role.scratch.recency_decay,
|
||||
focal_pt, nodes, n_count)
|
||||
final_result = []
|
||||
for n in results:
|
||||
n.last_accessed = strole._rc.scratch.curr_time
|
||||
for i in role.memory.storage:
|
||||
if i.memory_id == n:
|
||||
i.last_accessed = role.scratch.curr_time
|
||||
final_result.append(i)
|
||||
|
||||
retrieved[focal_pt] = results
|
||||
retrieved[focal_pt] = final_result
|
||||
|
||||
return retrieved
|
||||
|
||||
|
||||
def top_highest_x_values(d, x):
|
||||
|
|
@ -91,14 +98,15 @@ def extract_importance(memories, score_list):
|
|||
return score_list
|
||||
|
||||
|
||||
def extract_relevance(query, score_list):
|
||||
def extract_relevance(agent_memory_embedding,query, score_list):
|
||||
"""
|
||||
抽取相关性
|
||||
"""
|
||||
query_embedding = get_embedding(query)
|
||||
# 进行
|
||||
for i in range(len(score_list)):
|
||||
result = cos_sim(score_list[i]["memory"].embedding_key, query_embedding)
|
||||
node_embedding = agent_memory_embedding[score_list[i]["memory"].embedding_key]
|
||||
result = cos_sim(node_embedding, query_embedding)
|
||||
score_list[i]['relevance'] = result
|
||||
|
||||
return score_list
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ Variables:
|
|||
Input:
|
||||
!<INPUT 0>!
|
||||
|
||||
What !<INPUT 1>! high-level insights can you infer from the above statements? (example format: insight (because of 1, 5, 3))
|
||||
What !<INPUT 1>! high-level insights can you infer from the above statements? Please ensure it includes 'because of' and generates according to the example format.(example format: insight (because of 1, 5, 3)) .
|
||||
1.
|
||||
11
examples/st_game/prompts/whisper_inner_thought_v1.txt
Normal file
11
examples/st_game/prompts/whisper_inner_thought_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
whisper_inner_thought_v1.txt
|
||||
|
||||
Variables:
|
||||
!<INPUT 0>! -- init persona name
|
||||
!<INPUT 1>! -- whisper
|
||||
|
||||
<commentblockmarker>###</commentblockmarker>
|
||||
Translate the following thought into a statement about !<INPUT 0>!.
|
||||
|
||||
Thought: "!<INPUT 1>!"
|
||||
Statement: "
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# author: didi
|
||||
# Date:9.25
|
||||
|
||||
import openai
|
||||
from metagpt.llm import DEFAULT_LLM
|
||||
# 直接调用Prompt生成
|
||||
# ga的prompt构建格式和metagpt完全不同。没有办法融合。
|
||||
|
||||
|
||||
# 特殊指令加入Prompt生成
|
||||
|
||||
|
||||
async def final_response(prompt, special_instruction, example_output=None):
|
||||
"""
|
||||
通过将特殊指令加入Prompt生成最终的响应。
|
||||
|
||||
参数:
|
||||
- prompt:要生成响应的提示文本。
|
||||
- special_instruction:要加入Prompt的特殊指令。
|
||||
- example_output(可选):示例输出的JSON字符串。
|
||||
|
||||
返回:
|
||||
生成的最终响应。
|
||||
|
||||
"""
|
||||
prompt = '"""\n' + prompt + '\n"""\n'
|
||||
prompt += f"Output the response to the prompt above in json. {special_instruction}\n"
|
||||
if example_output:
|
||||
prompt += "Example output json:\n"
|
||||
prompt += '{"output": "' + str(example_output) + '"}'
|
||||
return await DEFAULT_LLM.aask(prompt)
|
||||
|
||||
# prompt填充模板
|
||||
|
||||
|
||||
def prompt_generate(curr_input, prompt_lib_file):
|
||||
"""
|
||||
Takes in the current input (e.g. comment that you want to classifiy) and
|
||||
the path to a prompt file. The prompt file contains the raw str prompt that
|
||||
will be used, which contains the following substr: !<INPUT>! -- this
|
||||
function replaces this substr with the actual curr_input to produce the
|
||||
final promopt that will be sent to the GPT3 server.
|
||||
ARGS:
|
||||
curr_input: the input we want to feed in (IF THERE ARE MORE THAN ONE
|
||||
INPUT, THIS CAN BE A LIST.)
|
||||
prompt_lib_file: the path to the promopt file.
|
||||
RETURNS:
|
||||
a str prompt that will be sent to OpenAI's GPT server.
|
||||
"""
|
||||
if isinstance(curr_input, str):
|
||||
curr_input = [curr_input]
|
||||
curr_input = [str(i) for i in curr_input]
|
||||
|
||||
f = open(prompt_lib_file, "r")
|
||||
prompt = f.read()
|
||||
f.close()
|
||||
for count, i in enumerate(curr_input):
|
||||
prompt = prompt.replace(f"!<INPUT {count}>!", i)
|
||||
if "<commentblockmarker>###</commentblockmarker>" in prompt:
|
||||
prompt = prompt.split(
|
||||
"<commentblockmarker>###</commentblockmarker>")[1]
|
||||
return prompt.strip()
|
||||
|
|
@ -5,7 +5,6 @@
|
|||
import datetime
|
||||
|
||||
from metagpt.logs import logger
|
||||
|
||||
from examples.st_game.utils.utils import get_embedding
|
||||
from examples.st_game.actions.run_reflect_action import (
|
||||
AgentFocusPt, AgentInsightAndGuidance, AgentEventTriple,
|
||||
|
|
@ -17,14 +16,14 @@ from examples.st_game.actions.run_reflect_action import (
|
|||
def generate_focal_points(role: "STRole", n=3):
|
||||
nodes = [
|
||||
[i.last_accessed, i] for i in
|
||||
role._rc.memory.event_list + role._rc.memory.thought_list
|
||||
role.memory.event_list + role.memory.thought_list
|
||||
if "idle" not in i.embedding_key
|
||||
]
|
||||
nodes = sorted(nodes, key=lambda x: x[0])
|
||||
nodes = [i for _, i in nodes]
|
||||
|
||||
statements = ""
|
||||
for node in nodes[-1 * role._rc.scratch.importance_ele_n:]:
|
||||
for node in nodes[-1 * role.scratch.importance_ele_n:]:
|
||||
statements += node.embedding_key + "\n"
|
||||
run_focal_pt = AgentFocusPt()
|
||||
return run_focal_pt.run(role, statements, n)
|
||||
|
|
@ -38,12 +37,14 @@ def generate_insights_and_evidence(role, nodes, n=5):
|
|||
ret = run_insight_and_guidance.run(role, statements, n)
|
||||
|
||||
logger.info(ret)
|
||||
|
||||
try:
|
||||
for thought, evi_raw in ret.items():
|
||||
evidence_node_id = [nodes[i].node_id for i in evi_raw]
|
||||
evidence_node_id = [nodes[i].memory_id for i in evi_raw]
|
||||
ret[thought] = evidence_node_id
|
||||
return ret
|
||||
except:
|
||||
except Exception as exp:
|
||||
logger.error(f"generate_insights_and_evidence error:{exp}")
|
||||
return {"this is blank": "node_1"}
|
||||
|
||||
|
||||
|
|
@ -59,7 +60,8 @@ def generate_action_event_triple(act_desp, role):
|
|||
"🧈🍞"
|
||||
"""
|
||||
run_event_triple = AgentEventTriple()
|
||||
return AgentEventTriple(act_desp, role)
|
||||
result = run_event_triple.run(act_desp, role)
|
||||
return result
|
||||
|
||||
|
||||
def generate_poig_score(role: "STRole", event_type, description):
|
||||
|
|
@ -68,11 +70,11 @@ def generate_poig_score(role: "STRole", event_type, description):
|
|||
|
||||
if event_type == "event" or event_type == "thought":
|
||||
run_event_poignancy = AgentEventPoignancy()
|
||||
return run_event_poignancy.run(role, description)[0]
|
||||
return run_event_poignancy.run(role, description)
|
||||
elif event_type == "chat":
|
||||
run_chat_poignancy = AgentChatPoignancy()
|
||||
return run_chat_poignancy.run(role,
|
||||
role._rc.scratch.act_description)[0]
|
||||
role.scratch.act_description)
|
||||
|
||||
|
||||
def generate_planning_thought_on_convo(role, all_utt):
|
||||
|
|
@ -98,7 +100,7 @@ def run_reflect(role: "STRole"):
|
|||
"""
|
||||
# Reflection requires certain focal points. Generate that first.
|
||||
focal_points = generate_focal_points(role, 3)
|
||||
# Retrieve the relevant Nodes object for each of the focal points.
|
||||
# Retrieve the relevant Nodesobject for each of the focal points.
|
||||
# <retrieved> has keys of focal points, and values of the associated Nodes.
|
||||
retrieved = role.retrieve(focal_points)
|
||||
|
||||
|
|
@ -106,25 +108,25 @@ def run_reflect(role: "STRole"):
|
|||
# agent's memory.
|
||||
for focal_pt, nodes in retrieved.items():
|
||||
xx = [i.embedding_key for i in nodes]
|
||||
for xxx in xx: logger.info(xxx)
|
||||
for xxx in xx: logger.info(f"Nodes retrieved for {focal_pt} are {xxx}.")
|
||||
|
||||
thoughts = generate_insights_and_evidence(role, nodes, 5)
|
||||
# 生成的是字典类型
|
||||
for thought, evidence in thoughts.items():
|
||||
created = role.scratch.curr_time
|
||||
expiration = created + datetime.timedelta(days=30)
|
||||
s, p, o = generate_action_event_triple(thought, role)
|
||||
s, p, o = generate_action_event_triple("(" + thought + ")", role)
|
||||
keywords = set([s, p, o])
|
||||
thought_poignancy = generate_poig_score(role, "thought", thought)
|
||||
thought_embedding_pair = (thought, get_embedding(thought))
|
||||
|
||||
role._rc.memory.add_thought(
|
||||
role.memory.add_thought(
|
||||
created, expiration, s, p, o, thought, keywords,
|
||||
thought_poignancy, thought_embedding_pair, evidence
|
||||
)
|
||||
logger.info(f"add thought memory: {thought}")
|
||||
|
||||
|
||||
# Done
|
||||
def reflection_trigger(role: "STRole"):
|
||||
"""
|
||||
Given the current role, determine whether the role should run a
|
||||
|
|
@ -139,14 +141,10 @@ def reflection_trigger(role: "STRole"):
|
|||
True if we are running a new reflection.
|
||||
False otherwise.
|
||||
"""
|
||||
logger.info(
|
||||
role._rc.scratch.name, "role.scratch.importance_trigger_curr::",
|
||||
role._rc.scratch.importance_trigger_curr
|
||||
)
|
||||
logger.info(role._rc.scratch.importance_trigger_max)
|
||||
logger.info(f"{role.scratch.name} role.scratch.importance_trigger_curr:: {role.scratch.importance_trigger_curr}"),
|
||||
|
||||
if (role._rc.scratch.importance_trigger_curr <= 0 and
|
||||
[] != role._rc.memory.seq_event + role._rc.memory.seq_thought):
|
||||
if (role.scratch.importance_trigger_curr <= 0 and
|
||||
[] != role.memory.event_list + role.memory.thought_list):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
@ -161,13 +159,12 @@ def reset_reflection_counter(role: "STRole"):
|
|||
Output:
|
||||
None
|
||||
"""
|
||||
role_imt_max = role._rc.scratch.importance_trigger_max
|
||||
role._rc.scratch.importance_trigger_curr = role_imt_max
|
||||
role._rc.scratch.importance_ele_n = 0
|
||||
role_imt_max = role.scratch.importance_trigger_max
|
||||
role.scratch.importance_trigger_curr = role_imt_max
|
||||
role.scratch.importance_ele_n = 0
|
||||
|
||||
|
||||
# Question 1 chat函数
|
||||
def reflect(role: "STRole"):
|
||||
def role_reflect(role: "STRole"):
|
||||
"""
|
||||
The main reflection module for the role. We first check if the trigger
|
||||
conditions are met, and if so, run the reflection and reset any of the
|
||||
|
|
@ -182,42 +179,41 @@ def reflect(role: "STRole"):
|
|||
run_reflect(role)
|
||||
reset_reflection_counter(role)
|
||||
|
||||
if role._rc.scratch.chatting_end_time:
|
||||
if role._rc.scratch.curr_time + datetime.timedelta(0, 10) == role._rc.scratch.chatting_end_time:
|
||||
if role.scratch.chatting_end_time:
|
||||
if role.scratch.curr_time + datetime.timedelta(0, 10) == role.scratch.chatting_end_time:
|
||||
all_utt = ""
|
||||
if role._rc.scratch.chat:
|
||||
for row in role._rc.scratch.chat:
|
||||
if role.scratch.chat:
|
||||
for row in role.scratch.chat:
|
||||
all_utt += f"{row[0]}: {row[1]}\n"
|
||||
|
||||
# Question memory添加对话函数
|
||||
evidence = [role._rc.memory.get_last_chat(role._rc.scratch.chatting_with).memory_id]
|
||||
evidence = [role.memory.get_last_chat(role.scratch.chatting_with).memory_id]
|
||||
|
||||
planning_thought = generate_planning_thought_on_convo(role, all_utt)
|
||||
planning_thought = f"For {role._rc.scratch.name}'s planning: {planning_thought}"
|
||||
planning_thought = f"For {role.scratch.name}'s planning: {planning_thought}"
|
||||
|
||||
created = role._rc.scratch.curr_time
|
||||
created = role.scratch.curr_time
|
||||
expiration = created + datetime.timedelta(days=30)
|
||||
s, p, o = generate_action_event_triple(planning_thought, role)
|
||||
keywords = set([s, p, o])
|
||||
thought_poignancy = generate_poig_score(role, "thought", planning_thought)
|
||||
thought_embedding_pair = (planning_thought, get_embedding(planning_thought))
|
||||
|
||||
role._rc.memory.add_thought(
|
||||
role.memory.add_thought(
|
||||
created, expiration, s, p, o, planning_thought, keywords,
|
||||
thought_poignancy, thought_embedding_pair, evidence
|
||||
)
|
||||
|
||||
memo_thought = generate_memo_on_convo(role, all_utt)
|
||||
memo_thought = f"{role._rc.scratch.name} {memo_thought}"
|
||||
memo_thought = f"{role.scratch.name} {memo_thought}"
|
||||
|
||||
created = role._rc.scratch.curr_time
|
||||
created = role.scratch.curr_time
|
||||
expiration = created + datetime.timedelta(days=30)
|
||||
s, p, o = generate_action_event_triple(memo_thought, role)
|
||||
keywords = set([s, p, o])
|
||||
thought_poignancy = generate_poig_score(role, "thought", memo_thought)
|
||||
thought_embedding_pair = (memo_thought, get_embedding(memo_thought))
|
||||
|
||||
role._rc.memory.add_thought(
|
||||
role.memory.add_thought(
|
||||
created, expiration, s, p, o, memo_thought, keywords,
|
||||
thought_poignancy, thought_embedding_pair, evidence
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Desc : st's reflection execution
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from metagpt.logs import logger
|
||||
|
||||
from examples.st_game.prompts.wrapper_prompt import special_response_generate
|
||||
from examples.st_game.memory.agent_memory import BasicMemory
|
||||
|
||||
|
||||
async def agent_reflect(memories_list):
|
||||
"""
|
||||
代理反思函数:生成关注点并生成洞察和证据
|
||||
|
||||
"""
|
||||
A = await generate_focus_point(memories_list)
|
||||
|
||||
for i in A:
|
||||
B = await generate_insights_and_evidence(memories_list, question=i)
|
||||
|
||||
|
||||
async def generate_focus_point(memories_list: list[BasicMemory], n=3):
|
||||
"""
|
||||
生成关注点函数:根据记忆列表生成关注点
|
||||
"""
|
||||
wait_sorted_mem = [[i.accessed_time, i] for i in memories_list]
|
||||
sorted_memories = sorted(wait_sorted_mem, key=lambda x: x[0])
|
||||
memorys = [i for created, i in sorted_memories]
|
||||
statements = ''
|
||||
for i in memorys:
|
||||
statements += i.description + "\n"
|
||||
prompt = '''
|
||||
{statements}
|
||||
Given only the information above, what are {num_question} most salient high-level questions we can answer about the subjects grounded in the statements?
|
||||
'''
|
||||
example_output = '["What should Jane do for lunch", "Does Jane like strawberry", "Who is Jane"]'
|
||||
out = await final_response(prompt.format(statements=statements, num_question=n),
|
||||
"Output must be a list of str.", example_output)
|
||||
try:
|
||||
poi_dict = json.loads(out)
|
||||
return poi_dict['output']
|
||||
except ValueError:
|
||||
print(out)
|
||||
logger.error('无法返回正常结果')
|
||||
return out
|
||||
|
||||
|
||||
async def generate_insights_and_evidence(memories_list: list[BasicMemory], question: str, n=5):
|
||||
"""
|
||||
生成洞察和证据函数:根据问题生成洞察和证据
|
||||
"""
|
||||
memories_list = await agent_retrieve(agent, question, 50, 10)
|
||||
statements = ""
|
||||
for count, mem in enumerate(memories_list):
|
||||
statements += f'{str(count)}. {mem.description}\n'
|
||||
prompt = '''
|
||||
Input:
|
||||
{statements}
|
||||
|
||||
What {n} high-level insights can you infer from the above statements?
|
||||
You should return a list of list[str,list]. The first element is the insight you have found. The second element is the
|
||||
'''
|
||||
|
||||
ret = final_response(prompt.format(
|
||||
question=question, statements=statements, n=n), "['insightA',[1,2,3]]")
|
||||
try:
|
||||
insight_list = json.loads(ret)
|
||||
for insight, index in insight_list:
|
||||
agent.memory_list.append(BasicMemory(
|
||||
time.time(), None, insight, None, None))
|
||||
return insight_list
|
||||
except:
|
||||
logger.error('我们无法获得想要的返回。')
|
||||
return ret
|
||||
|
||||
|
||||
""" if __name__ == "__main__":
|
||||
# 例子,构建John Agent,实现retrive
|
||||
John_iss = "John Lin is a pharmacy shopkeeper at the Willow Market and Pharmacy who loves to help people. He is always looking for ways to make the process of getting medication easier for his customers; John Lin is living with his wife, Mei Lin, who is a college professor, and son, Eddy Lin, who is a student studying music theory; John Lin loves his family very much; John Lin has known the old couple next-door, Sam Moore and Jennifer Moore, for a few years; John Lin thinks Sam Moore is a kind and nice man; John Lin knows his neighbor, Yuriko Yamamoto, well; John Lin knows of his neighbors, Tamara Taylor and Carmen Ortiz, but has not met them before; John Lin and Tom Moreno are colleagues at The Willows Market and Pharmacy; John Lin and Tom Moreno are friends and like to discuss local politics together; John Lin knows the Moreno family somewhat well — the husband Tom Moreno and the wife Jane Moreno."
|
||||
John = AgentMemory(
|
||||
"John", John_iss, memory_path="agent_memories/John_memory.json")
|
||||
|
||||
# John的相关信息:{'Had a friendly chat with Yuriko about her garden.': 2.4992317730827667, 'Helped Mrs. Moore carry groceries into her house.': 1.957656720441911, 'Discussed local politics with Tom Moreno.': 1.9458268038234035}
|
||||
asyncio.run(agent_reflect(John))
|
||||
'''
|
||||
这里是输出,list形式,返回给记忆。
|
||||
[['The pharmacy is a friendly and helpful community.', [0, 2, 9, 12]], ['The pharmacy is a place where people come for more than just medication.', [3, 5, 13, 14]], ['The pharmacy is a place where people come for advice and conversation.', [0, 2, 6, 9, 12]], ['The pharmacy is a place where people come for assistance with daily tasks.', [3, 5, 13, 14]], ['The pharmacy is a place where people come for political discussions.', [1]]]
|
||||
'''
|
||||
"""
|
||||
|
|
@ -34,6 +34,9 @@ from examples.st_game.utils.utils import get_embedding, path_finder
|
|||
from examples.st_game.utils.const import collision_block_id, STORAGE_PATH
|
||||
from examples.st_game.reflect.reflect import generate_poig_score
|
||||
from examples.st_game.utils.mg_ga_transform import save_movement, get_role_environment
|
||||
from examples.st_game.actions.inner_voice_action import AgentWhisperThoughtAction
|
||||
from examples.st_game.actions.run_reflect_action import AgentEventTriple
|
||||
from examples.st_game.reflect.reflect import role_reflect
|
||||
|
||||
|
||||
class STRoleContext(RoleContext):
|
||||
|
|
@ -112,6 +115,10 @@ class STRole(Role):
|
|||
def s_mem(self):
|
||||
return self._rc.spatial_memory
|
||||
|
||||
@property
|
||||
def memory(self):
|
||||
return self._rc.memory
|
||||
|
||||
def load_from(self, folder: Path):
|
||||
"""
|
||||
load role data from `storage/{simulation_name}/personas/{role_name}
|
||||
|
|
@ -131,15 +138,31 @@ class STRole(Role):
|
|||
observed = self._rc.env.memory.get_by_actions(self._rc.watch)
|
||||
self._rc.news = self._rc.memory.remember(observed)
|
||||
if len(self._rc.news) == 1 and self._rc.news[0].cause_by == UserRequirement:
|
||||
# add inner voice
|
||||
# TODO
|
||||
self.add_inner_voice(self._rc.news[0].content)
|
||||
logger.warning(f"Role: {self.name} add inner voice: {self._rc.news[0].content}")
|
||||
|
||||
return 1 # always return 1 to execute role's `_react`
|
||||
|
||||
def add_inner_voice(self):
|
||||
def add_inner_voice(self, whisper):
|
||||
# TODO
|
||||
pass
|
||||
def generate_inner_thought(role: STRole, whisper):
|
||||
run_whisper_thought = AgentWhisperThoughtAction()
|
||||
inner_thought = run_whisper_thought.run(self, whisper)
|
||||
return inner_thought
|
||||
|
||||
whisper = input("Enter Input: ")
|
||||
thought = generate_inner_thought(whisper)
|
||||
|
||||
created = self._rc.scratch.curr_time
|
||||
expiration = self._rc.scratch.curr_time + datetime.timedelta(days=30)
|
||||
run_event_triple = AgentEventTriple()
|
||||
s, p, o = run_event_triple.run(thought, self)
|
||||
keywords = set([s, p, o])
|
||||
thought_poignancy = generate_poig_score(self, "event", whisper)
|
||||
thought_embedding_pair = (thought, get_embedding(thought))
|
||||
self._rc.memory.add_thought(created, expiration, s, p, o,
|
||||
thought, keywords, thought_poignancy,
|
||||
thought_embedding_pair, None)
|
||||
|
||||
def observe(self) -> list[BasicMemory]:
|
||||
# TODO observe info from maze_env
|
||||
|
|
@ -282,7 +305,7 @@ class STRole(Role):
|
|||
|
||||
return ret_events
|
||||
|
||||
async def retrieve(self, focus_points, n=30):
|
||||
def retrieve(self, focus_points, n=30) -> dict:
|
||||
# TODO retrieve memories from agent_memory
|
||||
retrieve_memories = new_agent_retrieve(self, focus_points, n)
|
||||
return retrieve_memories
|
||||
|
|
@ -297,11 +320,11 @@ class STRole(Role):
|
|||
# TODO re-add result into memory
|
||||
pass
|
||||
|
||||
async def reflect(self):
|
||||
def reflect(self):
|
||||
# TODO reflection if meet reflect condition
|
||||
|
||||
result = role_reflect(self)
|
||||
# TODO re-add result to memory
|
||||
pass
|
||||
# 已封装到Reflect函数之中
|
||||
|
||||
def execute(self, plan: str):
|
||||
"""
|
||||
|
|
|
|||
73
examples/st_game/tests/test_agent_memory.py
Normal file
73
examples/st_game/tests/test_agent_memory.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import pytest
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from metagpt.logs import logger
|
||||
from examples.st_game.memory.agent_memory import AgentMemory
|
||||
from examples.st_game.utils.const import STORAGE_PATH
|
||||
from examples.st_game.memory.retrieve import agent_retrieve
|
||||
|
||||
"""
|
||||
memory测试思路
|
||||
1. Basic Memory测试
|
||||
2. Agent Memory测试
|
||||
2.1 Load & Save方法测试; Load方法中使用了add方法,验证Load即可验证所有add
|
||||
2.2 Get方法测试
|
||||
"""
|
||||
memory_easy_storage_path = os.path.join(STORAGE_PATH,"July1_the_ville_isabella_maria_klaus-step-3-4/personas/Isabella Rodriguez/bootstrap_memory/associative_memory")
|
||||
memroy_chat_storage_path = os.path.join(STORAGE_PATH,"July1_the_ville_isabella_maria_klaus-step-3-11/personas/Isabella Rodriguez/bootstrap_memory/associative_memory")
|
||||
memory_save_easy_test_path = os.path.join(STORAGE_PATH,"July1_the_ville_isabella_maria_klaus-step-3-4/personas/Isabella Rodriguez/bootstrap_memory/test_memory")
|
||||
memory_save_chat_test_path = os.path.join(STORAGE_PATH,"July1_the_ville_isabella_maria_klaus-step-3-11/personas/Isabella Rodriguez/bootstrap_memory/test_memory")
|
||||
class TestAgentMemory:
|
||||
@pytest.fixture
|
||||
def agent_memory(self):
|
||||
# 创建一个AgentMemory实例并返回,可以在所有测试用例中共享
|
||||
test_agent_memory = AgentMemory()
|
||||
test_agent_memory.set_mem_path(memroy_chat_storage_path)
|
||||
return test_agent_memory
|
||||
|
||||
def test_load(self,agent_memory):
|
||||
logger.info(f"存储路径为:{agent_memory.memory_saved}")
|
||||
logger.info(f"存储记忆条数为:{len(agent_memory.storage)}")
|
||||
logger.info(f"kw_strength为{agent_memory.kw_strength_event},{agent_memory.kw_strength_thought}")
|
||||
logger.info(f"embeeding.json条数为{len(agent_memory.embeddings)}")
|
||||
|
||||
assert agent_memory.embeddings != None
|
||||
|
||||
def test_save(self,agent_memory):
|
||||
try:
|
||||
agent_memory.save(memory_save_chat_test_path)
|
||||
logger.info("成功存储")
|
||||
except:
|
||||
pass
|
||||
|
||||
def test_summary_function(self, agent_memory):
|
||||
logger.info(f"event长度为{len(agent_memory.event_list)}")
|
||||
logger.info(f"thought长度为{len(agent_memory.thought_list)}")
|
||||
logger.info(f"chat长度为{len(agent_memory.chat_list)}")
|
||||
result1 = agent_memory.get_summarized_latest_events(4)
|
||||
logger.info(f"总结最近事件结果为:{result1}")
|
||||
def test_get_last_chat_function(self,agent_memory):
|
||||
result2 = agent_memory.get_last_chat("customers")
|
||||
logger.info(f"上一次对话是{result2}")
|
||||
|
||||
def test_retrieve_function(self,agent_memory):
|
||||
focus_points = ["who i love?"]
|
||||
retrieved = dict()
|
||||
for focal_pt in focus_points:
|
||||
nodes = [[i.last_accessed, i]
|
||||
for i in agent_memory.event_list + agent_memory.thought_list
|
||||
if "idle" not in i.embedding_key]
|
||||
nodes = sorted(nodes, key=lambda x: x[0])
|
||||
nodes = [i for created, i in nodes]
|
||||
results = agent_retrieve(agent_memory, datetime.now()-timedelta(days=120), 0.99,
|
||||
focal_pt, nodes, 5)
|
||||
final_result = []
|
||||
for n in results:
|
||||
for i in agent_memory.storage:
|
||||
if i.memory_id == n:
|
||||
i.last_accessed = datetime.now()-timedelta(days=120)
|
||||
final_result.append(i)
|
||||
|
||||
retrieved[focal_pt] = final_result
|
||||
logger.info(f"检索结果为{retrieved}")
|
||||
66
examples/st_game/tests/test_basic_memory.py
Normal file
66
examples/st_game/tests/test_basic_memory.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
from datetime import datetime, timedelta
|
||||
from metagpt.logs import logger
|
||||
from examples.st_game.memory.agent_memory import BasicMemory
|
||||
import pytest
|
||||
|
||||
"""
|
||||
memory测试思路
|
||||
1. Basic Memory测试
|
||||
2. Agent Memory测试
|
||||
2.1 Load & Save方法测试
|
||||
2.2 Add方法测试
|
||||
2.3 Get方法测试
|
||||
"""
|
||||
|
||||
# Create some sample BasicMemory instances
|
||||
memory1 = BasicMemory(
|
||||
memory_id="1",
|
||||
memory_count=1,
|
||||
type_count=1,
|
||||
memory_type="event",
|
||||
depth=1,
|
||||
created=datetime.now(),
|
||||
expiration=datetime.now() + timedelta(days=30),
|
||||
subject="Subject1",
|
||||
predicate="Predicate1",
|
||||
object="Object1",
|
||||
content="This is content 1",
|
||||
embedding_key="embedding_key_1",
|
||||
poignancy=1,
|
||||
keywords=["keyword1", "keyword2"],
|
||||
filling=["memory_id_2"]
|
||||
)
|
||||
memory2 = BasicMemory(
|
||||
memory_id="2",
|
||||
memory_count=2,
|
||||
type_count=2,
|
||||
memory_type="thought",
|
||||
depth=2,
|
||||
created=datetime.now(),
|
||||
expiration=datetime.now() + timedelta(days=30),
|
||||
subject="Subject2",
|
||||
predicate="Predicate2",
|
||||
object="Object2",
|
||||
content="This is content 2",
|
||||
embedding_key="embedding_key_2",
|
||||
poignancy=2,
|
||||
keywords=["keyword3", "keyword4"],
|
||||
filling=[]
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def basic_mem_set():
|
||||
basic_mem2 = memory2
|
||||
yield basic_mem2
|
||||
|
||||
def test_basic_mem_function(basic_mem_set):
|
||||
a, b, c = basic_mem_set.summary()
|
||||
logger.info(f"{a}{b}{c}")
|
||||
assert a == "Subject2"
|
||||
|
||||
def test_basic_mem_save(basic_mem_set):
|
||||
result = basic_mem_set.save_to_dict()
|
||||
logger.info(f"save结果为{result}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main()
|
||||
65
examples/st_game/tests/test_reflect.py
Normal file
65
examples/st_game/tests/test_reflect.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import pytest
|
||||
from examples.st_game.roles.st_role import STRole
|
||||
from examples.st_game.actions.run_reflect_action import AgentFocusPt, AgentInsightAndGuidance, AgentEventTriple, \
|
||||
AgentEventPoignancy, AgentChatPoignancy, AgentPlanThoughtOnConvo, AgentMemoryOnConvo
|
||||
from metagpt.logs import logger
|
||||
|
||||
|
||||
class TestReflectFunction:
|
||||
@pytest.fixture
|
||||
def init_agent(self):
|
||||
"""
|
||||
init STRole form local json, set sim_code(path),curr_time & start_date
|
||||
"""
|
||||
role = STRole(sim_code="July1_the_ville_isabella_maria_klaus-step-3-11", start_date='February 13, 2023',
|
||||
curr_time='February 13, 2023, 14:53:10')
|
||||
return role
|
||||
|
||||
def test_function_focus_and_insight_action(self, init_agent):
|
||||
"""
|
||||
test for AgentFocusPt & AgentInsightAndGuidance
|
||||
"""
|
||||
logger.info(f"{__name__}函数启动")
|
||||
run_focus = AgentFocusPt()
|
||||
statements = ""
|
||||
run_focus.run(init_agent, statements, n=3)
|
||||
|
||||
"""
|
||||
这里有通过测试的结果,但是更多时候LLM生成的结果缺少了because of;考虑修改一下prompt
|
||||
result = {'Klaus Mueller and Maria Lopez have a close relationship because they have been friends for a long time and have a strong bond': [1, 2, 5, 9, 11, 14], 'Klaus Mueller has a crush on Maria Lopez': [8, 15, 24], 'Klaus Mueller is academically inclined and actively researching a topic': [13, 20], 'Klaus Mueller is socially active and acquainted with Isabella Rodriguez': [17, 21, 22], 'Klaus Mueller is organized and prepared': [19]}
|
||||
"""
|
||||
run_insight = AgentInsightAndGuidance()
|
||||
statements = "[user: Klaus Mueller has a close relationship with Maria Lopez, user:s Mueller and Maria Lopez have a close relationship, user: Klaus Mueller has a close relationship with Maria Lopez, user: Klaus Mueller has a close relationship with Maria Lopez, user: Klaus Mueller and Maria Lopez have a strong relationship, user: Klaus Mueller is a dormmate of Maria Lopez., user: Klaus Mueller and Maria Lopez have a strong bond, user: Klaus Mueller has a crush on Maria Lopez, user: Klaus Mueller and Maria Lopez have been friends for more than 2 years., user: Klaus Mueller has a close relationship with Maria Lopez, user: Klaus Mueller Maria Lopez is heading off to college., user: Klaus Mueller and Maria Lopez have a close relationship, user: Klaus Mueller is actively researching a topic, user: Klaus Mueller is close friends and classmates with Maria Lopez., user: Klaus Mueller is socially active, user: Klaus Mueller has a crush on Maria Lopez., user: Klaus Mueller and Maria Lopez have been friends for a long time, user: Klaus Mueller is academically inclined, user: For Klaus Mueller's planning: should remember to ask Maria Lopez about her research paper, as she found it interesting that he mentioned it., user: Klaus Mueller is acquainted with Isabella Rodriguez, user: Klaus Mueller is organized and prepared, user: Maria Lopez is conversing about conversing about Maria's research paper mentioned by Klaus, user: Klaus Mueller is conversing about conversing about Maria's research paper mentioned by Klaus, user: Klaus Mueller is a student, user: Klaus Mueller is a student, user: Klaus Mueller is conversing about two friends named Klaus Mueller and Maria Lopez discussing their morning plans and progress on a research paper before Maria heads off to college., user: Klaus Mueller is socially active, user: Klaus Mueller is socially active, user: Klaus Mueller is socially active and acquainted with Isabella Rodriguez, user: Klaus Mueller has a crush on Maria Lopez]"
|
||||
run_insight.run(init_agent, statements, n=5)
|
||||
|
||||
def test_event_triple_action(self, init_agent):
|
||||
"""
|
||||
test for AgentEventTriple
|
||||
error:遇到复杂情况时(多个Object)无法正确归纳,
|
||||
solution: 限制MaxTokens为15
|
||||
"""
|
||||
run_triple = AgentEventTriple()
|
||||
statements = "(Klaus Mueller is academically inclined)"
|
||||
run_triple.run(statements, init_agent)
|
||||
|
||||
def test_poignancy_action(self, init_agent):
|
||||
"""
|
||||
test for AgentEventPoignancy, AgentChatPoignancy
|
||||
done in reflect test
|
||||
"""
|
||||
pass
|
||||
|
||||
def test_convo_action(self, init_agent):
|
||||
"""
|
||||
test for AgentPlanThoughtOnConvo, AgentMemoryOnConvo
|
||||
TODO Undone
|
||||
"""
|
||||
pass
|
||||
|
||||
def test_reflect_function(self, init_agent):
|
||||
"""
|
||||
test for reflection
|
||||
modify importance_trigger_curr to trigger reflect
|
||||
"""
|
||||
init_agent.scratch.importance_trigger_curr = -1
|
||||
init_agent.reflect()
|
||||
Loading…
Add table
Add a link
Reference in a new issue