From 4008ce3b1503d524a51a9cbf392ae476b8f1178f Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Tue, 3 Oct 2023 18:30:00 +0800 Subject: [PATCH 01/12] add_inner_voice & reflect_role & agent_memory bug fixs --- examples/__init__.py | 0 .../st_game/actions/inner_voice_action.py | 37 +++++++++++ .../st_game/actions/run_reflect_action.py | 6 +- examples/st_game/memory/agent_memory.py | 28 ++++---- examples/st_game/memory/retrieve.py | 1 - .../prompts/whisper_inner_thought_v1.txt | 11 ++++ examples/st_game/reflect/reflect.py | 6 +- examples/st_game/roles/st_role.py | 30 +++++++-- .../st_game/tests/actions/test_reflect.py | 0 .../st_game/tests/actions/test_retrieve.py | 0 examples/st_game/tests/test_memory.py | 65 +++++++++++++++++++ 11 files changed, 158 insertions(+), 26 deletions(-) create mode 100644 examples/__init__.py create mode 100644 examples/st_game/actions/inner_voice_action.py create mode 100644 examples/st_game/prompts/whisper_inner_thought_v1.txt create mode 100644 examples/st_game/tests/actions/test_reflect.py create mode 100644 examples/st_game/tests/actions/test_retrieve.py create mode 100644 examples/st_game/tests/test_memory.py diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/st_game/actions/inner_voice_action.py b/examples/st_game/actions/inner_voice_action.py new file mode 100644 index 000000000..2a9bb0afc --- /dev/null +++ b/examples/st_game/actions/inner_voice_action.py @@ -0,0 +1,37 @@ +import re +from examples.st_game.roles.st_role import STRole +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 + diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index ab83a22ee..923cf68eb 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -22,7 +22,7 @@ class AgentFocusPt(STAction): except: return False - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list: llm_resp = "1) " + llm_resp.strip() ret = [] for i in llm_resp.split("\n"): @@ -145,7 +145,7 @@ class AgentEventPoignancy(STAction): except: return False - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int: llm_resp = int(llm_resp.strip()) return llm_resp @@ -186,7 +186,7 @@ class AgentChatPoignancy(STAction): except: return False - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int: llm_resp = int(llm_resp.strip()) return llm_resp diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index 60aa4ae81..617603195 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -33,7 +33,7 @@ class BasicMemory(Message): self.memory_count: int = memory_count # 第几个记忆,实际数值与Memory相等 self.type_count: int = type_count # 第几种记忆,类型为整数(具体不太理解如何生成的) self.memory_type: str = memory_type # 记忆类型,包含 event,thought,chat三种类型 - self.depth: str = depth # 记忆深度,类型为整数 + self.depth: int = depth # 记忆深度,类型为整数 self.created: datetime = created # 创建时间 self.expiration: datetime = expiration # 记忆失效时间,默认为空() @@ -62,10 +62,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 +75,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 +102,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 @@ -122,7 +122,7 @@ class AgentMemory(Memory): def save(self, memory_saved: str): """ - 将MemormyBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式 + 将MemoryBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式 这里添加一个路径即可 """ @@ -152,16 +152,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"] @@ -177,6 +174,7 @@ class AgentMemory(Memory): self.add_event(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) elif node_type == "chat": + cause_by = node_details["cause_by"] self.add_chat(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling, cause_by) elif node_type == "thought": @@ -200,10 +198,10 @@ class AgentMemory(Memory): if memory_basic.cause_by: self.index[memory_basic.cause_by][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] def add_chat(self, created, expiration, s, p, o, @@ -211,7 +209,7 @@ class AgentMemory(Memory): embedding_pair, filling, cause_by): """ - 调用add方法,初始化chat,在创建的时候就需要调用embeeding函数 + 调用add方法,初始化chat,在创建的时候就需要调用embedding函数 """ memory_count = len(self.storage) + 1 type_count = len(self.thought_list) + 1 @@ -330,7 +328,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: diff --git a/examples/st_game/memory/retrieve.py b/examples/st_game/memory/retrieve.py index 9f19a41d4..0656d5c05 100644 --- a/examples/st_game/memory/retrieve.py +++ b/examples/st_game/memory/retrieve.py @@ -3,7 +3,6 @@ # @Desc : Retrieve函数实现 import datetime -from typing import Union from numpy import dot from numpy.linalg import norm diff --git a/examples/st_game/prompts/whisper_inner_thought_v1.txt b/examples/st_game/prompts/whisper_inner_thought_v1.txt new file mode 100644 index 000000000..b1ed50aaa --- /dev/null +++ b/examples/st_game/prompts/whisper_inner_thought_v1.txt @@ -0,0 +1,11 @@ +whisper_inner_thought_v1.txt + +Variables: +!! -- init persona name +!! -- whisper + +### +Translate the following thought into a statement about !!. + +Thought: "!!" +Statement: " \ No newline at end of file diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 6c19cf3fc..6cb7d86f2 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -5,7 +5,7 @@ import datetime from metagpt.logs import logger - +from examples.st_game.roles.st_role import STRole from examples.st_game.utils.utils import get_embedding from examples.st_game.actions.run_reflect_action import ( AgentFocusPt, AgentInsightAndGuidance, AgentEventTriple, @@ -62,7 +62,7 @@ def generate_action_event_triple(act_desp, role): return AgentEventTriple(act_desp, role) -def generate_poig_score(role: "STRole", event_type, description): +def generate_poig_score(role: STRole, event_type, description): if "is idle" in description: return 1 @@ -167,7 +167,7 @@ def reset_reflection_counter(role: "STRole"): # 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 diff --git a/examples/st_game/roles/st_role.py b/examples/st_game/roles/st_role.py index bd96b70c6..43e2e0472 100644 --- a/examples/st_game/roles/st_role.py +++ b/examples/st_game/roles/st_role.py @@ -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): @@ -122,13 +125,32 @@ class STRole(Role): if len(self._rc.news) == 1 and isinstance(self._rc.news[0], 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(strole: 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(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) + async def observe(self) -> list[BasicMemory]: # TODO observe info from maze_env @@ -288,9 +310,9 @@ class STRole(Role): async def reflect(self): # TODO reflection if meet reflect condition - + role_reflect(self) # TODO re-add result to memory - pass + # 已封装到Reflect函数之中 def execute(self, plan: str): """ diff --git a/examples/st_game/tests/actions/test_reflect.py b/examples/st_game/tests/actions/test_reflect.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/st_game/tests/actions/test_retrieve.py b/examples/st_game/tests/actions/test_retrieve.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/st_game/tests/test_memory.py b/examples/st_game/tests/test_memory.py new file mode 100644 index 000000000..9c0354b36 --- /dev/null +++ b/examples/st_game/tests/test_memory.py @@ -0,0 +1,65 @@ +from datetime import datetime +from metagpt.logs import logger +from ..memory.agent_memory import AgentMemory, BasicMemory + +# 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(), + 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=None, + subject="Subject2", + predicate="Predicate2", + object="Object2", + content="This is content 2", + embedding_key="embedding_key_2", + poignancy=2, + keywords=["keyword3", "keyword4"], + filling=[] +) + +if __name__ == "__main__": + # Create an AgentMemory instance and add the created BasicMemory instances + agent_memory = AgentMemory(memory_saved="sample_memory_folder") + agent_memory.add_event(memory1) + agent_memory.add_thought(memory2) + + # Save the AgentMemory to a JSON file + agent_memory.save("sample_memory_folder") + + # Load the AgentMemory from the JSON file + loaded_agent_memory = AgentMemory(memory_saved="sample_memory_folder") + + # Get the summarized latest events + latest_events = loaded_agent_memory.get_summarized_latest_events(retention=2) + print("Summarized Latest Events:") + for event in latest_events: + print(event) + + # Get the last chat for a specific role + last_chat = loaded_agent_memory.get_last_chat(target_role_name="role1") + if last_chat: + print(f"Last chat for role1: {last_chat.content}") + else: + print("No chat found for role1") From ba7897a2ab29848980a201e4a5f8feb964f3dba7 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Tue, 3 Oct 2023 23:00:22 +0800 Subject: [PATCH 02/12] Retrieve & Reflect bug fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了Retrieve与Reflect函数中的bug --- .../st_game/actions/run_reflect_action.py | 88 +++++++++--------- examples/st_game/actions/st_action.py | 2 +- examples/st_game/memory/agent_memory.py | 6 ++ examples/st_game/memory/retrieve.py | 23 +++-- .../st_game/reflect/ga_prompt_generator.py | 64 ------------- examples/st_game/reflect/reflect.py | 58 ++++++------ examples/st_game/reflect/st_reflect.py | 92 ------------------- examples/st_game/roles/st_role.py | 21 +++-- .../st_game/tests/actions/test_reflect.py | 0 .../st_game/tests/actions/test_retrieve.py | 0 examples/st_game/tests/test_memory.py | 2 +- 11 files changed, 105 insertions(+), 251 deletions(-) delete mode 100644 examples/st_game/reflect/ga_prompt_generator.py delete mode 100644 examples/st_game/reflect/st_reflect.py delete mode 100644 examples/st_game/tests/actions/test_reflect.py delete mode 100644 examples/st_game/tests/actions/test_retrieve.py diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 923cf68eb..4f53e5647 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -7,6 +7,7 @@ from metagpt.logs import logger from examples.st_game.actions.st_action import STAction from examples.st_game.memory.agent_memory import BasicMemory +from examples.st_game.roles.st_role import STRole # Run GPT Prompt Focal Point method @@ -32,8 +33,8 @@ class AgentFocusPt(STAction): 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) -> str: + def create_prompt_input(role: STRole, statements, n, test_input=None): prompt_input = [statements, str(n)] return prompt_input @@ -43,9 +44,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,7 +64,7 @@ class AgentInsightAndGuidance(STAction): except: return False - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> dict: llm_resp = "1. " + llm_resp.strip() ret = dict() for i in llm_resp.split("\n"): @@ -78,8 +79,8 @@ class AgentInsightAndGuidance(STAction): 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 +88,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,7 +107,7 @@ class AgentEventTriple(STAction): return False return True - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list: cr = llm_resp.strip() cr = [i.strip() for i in cr.split(")")[0].split(",")] return cr @@ -114,23 +115,24 @@ class AgentEventTriple(STAction): 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) -> str: 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 @@ -152,11 +154,11 @@ class AgentEventPoignancy(STAction): 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: str, test_input=None): - prompt_input = [role._rc.scratch.name, - role._rc.scratch.get_str_iss(), - role._rc.scratch.name, + 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.scratch.name, + role.scratch.get_str_iss(), + role.scratch.name, statements] return prompt_input @@ -166,9 +168,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 @@ -193,11 +195,11 @@ class AgentChatPoignancy(STAction): 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._rc.scratch.name, - role._rc.scratch.get_str_iss(), - role._rc.scratch.name, + 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, + role.scratch.get_str_iss(), + role.scratch.name, statements] return prompt_input @@ -207,9 +209,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 @@ -233,19 +235,19 @@ class AgentPlanThoughtOnConvo(STAction): 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 @@ -269,12 +271,12 @@ class AgentMemoryOnConvo(STAction): 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 +284,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 diff --git a/examples/st_game/actions/st_action.py b/examples/st_game/actions/st_action.py index 60f73f36d..e5c048b4e 100644 --- a/examples/st_game/actions/st_action.py +++ b/examples/st_game/actions/st_action.py @@ -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 diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index 617603195..5c23c9e24 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -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): @@ -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): @@ -129,6 +133,7 @@ class AgentMemory(Memory): memory_json = dict() for i in range(len(self.storage)): memory_node = self.storage[i] + 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) @@ -253,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, diff --git a/examples/st_game/memory/retrieve.py b/examples/st_game/memory/retrieve.py index 0656d5c05..55e5b873f 100644 --- a/examples/st_game/memory/retrieve.py +++ b/examples/st_game/memory/retrieve.py @@ -7,12 +7,13 @@ import datetime 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 examples.st_game.roles.st_role import STRole -def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memory_forget: float, query: str, - topk: int = 4) -> list[BasicMemory]: +def agent_retrieve(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 @@ -26,7 +27,7 @@ def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memo "relevance": 搜索结果 } """ - memories = agent_memory.storage + memories = nodes memories = sorted(memories, key=lambda memory_node: memory_node.last_accessed, reverse=True) score_list = [] @@ -49,25 +50,27 @@ def agent_retrieve(agent_memory: AgentMemory, curr_time: datetime.datetime, memo return result # 返回的是一个BasicMemory列表 -def new_agent_retrieve(strole: "STRole", focus_points: list, n_count=30): +def new_agent_retrieve(role: STRole, 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.scratch.curr_time, role.scratch.recency_decay, + focal_pt, nodes, n_count) for n in results: - n.last_accessed = strole._rc.scratch.curr_time + n.last_accessed = role.scratch.curr_time retrieved[focal_pt] = results + return retrieved + def top_highest_x_values(d, x): """ diff --git a/examples/st_game/reflect/ga_prompt_generator.py b/examples/st_game/reflect/ga_prompt_generator.py deleted file mode 100644 index 81ed5e7f7..000000000 --- a/examples/st_game/reflect/ga_prompt_generator.py +++ /dev/null @@ -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: !! -- 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"!!", i) - if "###" in prompt: - prompt = prompt.split( - "###")[1] - return prompt.strip() diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 6cb7d86f2..1ff0c16ab 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -17,14 +17,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) @@ -59,7 +59,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): @@ -72,7 +73,7 @@ def generate_poig_score(role: STRole, event_type, 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)[0] def generate_planning_thought_on_convo(role, all_utt): @@ -114,17 +115,16 @@ def run_reflect(role: "STRole"): created = role.scratch.curr_time expiration = created + datetime.timedelta(days=30) s, p, o = generate_action_event_triple(thought, role) - keywords = set([s, p, o]) + keywords = {[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 ) -# Done def reflection_trigger(role: "STRole"): """ Given the current role, determine whether the role should run a @@ -140,13 +140,13 @@ def reflection_trigger(role: "STRole"): False otherwise. """ logger.info( - role._rc.scratch.name, "role.scratch.importance_trigger_curr::", - role._rc.scratch.importance_trigger_curr + role.scratch.name, "role.scratch.importance_trigger_curr::", + role.scratch.importance_trigger_curr ) - logger.info(role._rc.scratch.importance_trigger_max) + logger.info(role.scratch.importance_trigger_max) - 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.seq_event + role.memory.seq_thought): return True return False @@ -161,12 +161,11 @@ 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 role_reflect(role: "STRole"): """ The main reflection module for the role. We first check if the trigger @@ -182,42 +181,41 @@ def role_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]) + keywords = {[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]) + keywords = {[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 ) diff --git a/examples/st_game/reflect/st_reflect.py b/examples/st_game/reflect/st_reflect.py deleted file mode 100644 index f4b4c448c..000000000 --- a/examples/st_game/reflect/st_reflect.py +++ /dev/null @@ -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]]] - ''' - """ diff --git a/examples/st_game/roles/st_role.py b/examples/st_game/roles/st_role.py index 1ca6db09d..ad53dc4c7 100644 --- a/examples/st_game/roles/st_role.py +++ b/examples/st_game/roles/st_role.py @@ -104,6 +104,10 @@ class STRole(Role): def scratch(self): return self._rc.scratch + @property + def memory(self): + return self._rc.memory + def load_from(self, folder: Path): """ load role data from `storage/{simulation_name}/personas/{role_name} @@ -123,8 +127,6 @@ 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}") @@ -132,25 +134,24 @@ class STRole(Role): def add_inner_voice(self, whisper): # TODO - def generate_inner_thought(strole: STRole, whisper): + 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(thought, self) + 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) - + self._rc.memory.add_thought(created, expiration, s, p, o, + thought, keywords, thought_poignancy, + thought_embedding_pair, None) async def observe(self) -> list[BasicMemory]: # TODO observe info from maze_env @@ -293,7 +294,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 diff --git a/examples/st_game/tests/actions/test_reflect.py b/examples/st_game/tests/actions/test_reflect.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/st_game/tests/actions/test_retrieve.py b/examples/st_game/tests/actions/test_retrieve.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/st_game/tests/test_memory.py b/examples/st_game/tests/test_memory.py index 9c0354b36..451addc8b 100644 --- a/examples/st_game/tests/test_memory.py +++ b/examples/st_game/tests/test_memory.py @@ -1,6 +1,6 @@ from datetime import datetime from metagpt.logs import logger -from ..memory.agent_memory import AgentMemory, BasicMemory +from examples.st_game.memory.agent_memory import AgentMemory, BasicMemory # Create some sample BasicMemory instances memory1 = BasicMemory( From 33fb645d5d29645a3cb291e5e4d602c842886a08 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Wed, 4 Oct 2023 01:52:16 +0800 Subject: [PATCH 03/12] fix --- config/config.yaml | 2 +- examples/st_game/actions/run_reflect_action.py | 5 +++-- examples/st_game/memory/agent_memory.py | 1 + examples/st_game/tests/test_reflect.py | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 examples/st_game/tests/test_reflect.py diff --git a/config/config.yaml b/config/config.yaml index 444f55efd..a13068639 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ ## Or, you can configure OPENAI_PROXY to access official OPENAI_API_BASE. OPENAI_API_BASE: "https://api.openai.com/v1" #OPENAI_PROXY: "http://127.0.0.1:8118" -#OPENAI_API_KEY: "YOUR_API_KEY" +OPENAI_API_KEY: "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" OPENAI_API_MODEL: "gpt-4" MAX_TOKENS: 1500 RPM: 10 diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 4f53e5647..40bb54d7b 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -3,6 +3,7 @@ # @Desc : Integration Reflect Action import re + from metagpt.logs import logger from examples.st_game.actions.st_action import STAction @@ -115,7 +116,7 @@ class AgentEventTriple(STAction): def _func_fail_default_resp(self) -> str: pass - 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] @@ -129,7 +130,7 @@ class AgentEventTriple(STAction): "generate_event_triple_v1.txt") output = self._run_v1(prompt) - output = (role.scratch.name,output[0],output[1]) + output = (role.scratch.name, output[0], output[1]) logger.info(f"Run action: {self.__class__.__name__} with result: {output}") return output diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index 5c23c9e24..1db2566f6 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -128,6 +128,7 @@ class AgentMemory(Memory): """ 将MemoryBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式 这里添加一个路径即可 + TODO 这里需要添加Const常量 """ memory_json = dict() diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py new file mode 100644 index 000000000..54544f051 --- /dev/null +++ b/examples/st_game/tests/test_reflect.py @@ -0,0 +1,8 @@ + +from metagpt.logs import logger +from examples.st_game.memory.agent_memory import AgentMemory, BasicMemory + +""" +测试思路 +1. +""" \ No newline at end of file From 6e0701eb7ea892fdd5c15355da47f80a678234c3 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Wed, 4 Oct 2023 12:58:50 +0800 Subject: [PATCH 04/12] Update config.yaml --- config/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index a13068639..e76deac50 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -7,7 +7,7 @@ ## Or, you can configure OPENAI_PROXY to access official OPENAI_API_BASE. OPENAI_API_BASE: "https://api.openai.com/v1" #OPENAI_PROXY: "http://127.0.0.1:8118" -OPENAI_API_KEY: "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" +#OPENAI_API_KEY: "YOUR OPENAI KEY" OPENAI_API_MODEL: "gpt-4" MAX_TOKENS: 1500 RPM: 10 From 11bef70fd7c6579cb7ab784a6550e8e52ca143d7 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Wed, 4 Oct 2023 17:36:52 +0800 Subject: [PATCH 05/12] =?UTF-8?q?memory=20&=20retrieve=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/st_game/memory/agent_memory.py | 26 ++++---- examples/st_game/memory/retrieve.py | 26 +++++--- examples/st_game/tests/test_agent_memory.py | 72 +++++++++++++++++++++ examples/st_game/tests/test_basic_memory.py | 66 +++++++++++++++++++ examples/st_game/tests/test_memory.py | 65 ------------------- 5 files changed, 167 insertions(+), 88 deletions(-) create mode 100644 examples/st_game/tests/test_agent_memory.py create mode 100644 examples/st_game/tests/test_basic_memory.py delete mode 100644 examples/st_game/tests/test_memory.py diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index 1db2566f6..97644c5b8 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -128,12 +128,11 @@ class AgentMemory(Memory): """ 将MemoryBasic类存储为Nodes.json形式。复现GA中的Kw Strength.json形式 这里添加一个路径即可 - TODO 这里需要添加Const常量 + 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: @@ -175,14 +174,15 @@ class AgentMemory(Memory): poignancy = node_details["poignancy"] keywords = set(node_details["keywords"]) filling = node_details["filling"] - + # print(node_type) if node_type == "event": self.add_event(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) elif node_type == "chat": - cause_by = node_details["cause_by"] + # cause_by = node_details["cause_by"] + logger.info(f"{node_id}") self.add_chat(created, expiration, s, p, o, - description, keywords, poignancy, embedding_pair, filling, cause_by) + description, keywords, poignancy, embedding_pair, filling) elif node_type == "thought": self.add_thought(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) @@ -198,11 +198,11 @@ 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.memory_type == "thought": self.thought_list[0:0] = [memory_basic] @@ -213,14 +213,14 @@ class AgentMemory(Memory): def add_chat(self, created, expiration, s, p, o, content, keywords, poignancy, embedding_pair, filling, - cause_by): + cause_by = ''): """ 调用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, @@ -251,7 +251,7 @@ 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_id = f"node_{str(memory_count)}" depth = 1 try: @@ -296,7 +296,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: diff --git a/examples/st_game/memory/retrieve.py b/examples/st_game/memory/retrieve.py index 55e5b873f..ffba5dcbb 100644 --- a/examples/st_game/memory/retrieve.py +++ b/examples/st_game/memory/retrieve.py @@ -9,10 +9,10 @@ from numpy.linalg import norm from examples.st_game.memory.agent_memory import BasicMemory from examples.st_game.utils.utils import get_embedding -from examples.st_game.roles.st_role import STRole +from metagpt.logs import logger -def agent_retrieve(curr_time: datetime.datetime, memory_forget: float, query: str, nodes: 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 @@ -28,12 +28,13 @@ def agent_retrieve(curr_time: datetime.datetime, memory_forget: float, query: st } """ 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,14 +44,14 @@ def agent_retrieve(curr_time: datetime.datetime, memory_forget: float, query: st 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(role: STRole, focus_points: list, n_count=30) -> dict: +def new_agent_retrieve(role, focus_points: list, n_count=30) -> dict: """ 输入为role,关注点列表,返回记忆数量 输出为字典,键为focus_point,值为对应的记忆列表 @@ -62,12 +63,16 @@ def new_agent_retrieve(role: STRole, focus_points: list, n_count=30) -> dict: 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(role.scratch.curr_time, role.scratch.recency_decay, + 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 = role.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.content) - retrieved[focal_pt] = results + retrieved[focal_pt] = final_result return retrieved @@ -93,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 diff --git a/examples/st_game/tests/test_agent_memory.py b/examples/st_game/tests/test_agent_memory.py new file mode 100644 index 000000000..08d065afd --- /dev/null +++ b/examples/st_game/tests/test_agent_memory.py @@ -0,0 +1,72 @@ +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)}") + 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.content) + + retrieved[focal_pt] = final_result + logger.info(f"检索结果为{retrieved}") \ No newline at end of file diff --git a/examples/st_game/tests/test_basic_memory.py b/examples/st_game/tests/test_basic_memory.py new file mode 100644 index 000000000..79184ceae --- /dev/null +++ b/examples/st_game/tests/test_basic_memory.py @@ -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() diff --git a/examples/st_game/tests/test_memory.py b/examples/st_game/tests/test_memory.py deleted file mode 100644 index 451addc8b..000000000 --- a/examples/st_game/tests/test_memory.py +++ /dev/null @@ -1,65 +0,0 @@ -from datetime import datetime -from metagpt.logs import logger -from examples.st_game.memory.agent_memory import AgentMemory, BasicMemory - -# 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(), - 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=None, - subject="Subject2", - predicate="Predicate2", - object="Object2", - content="This is content 2", - embedding_key="embedding_key_2", - poignancy=2, - keywords=["keyword3", "keyword4"], - filling=[] -) - -if __name__ == "__main__": - # Create an AgentMemory instance and add the created BasicMemory instances - agent_memory = AgentMemory(memory_saved="sample_memory_folder") - agent_memory.add_event(memory1) - agent_memory.add_thought(memory2) - - # Save the AgentMemory to a JSON file - agent_memory.save("sample_memory_folder") - - # Load the AgentMemory from the JSON file - loaded_agent_memory = AgentMemory(memory_saved="sample_memory_folder") - - # Get the summarized latest events - latest_events = loaded_agent_memory.get_summarized_latest_events(retention=2) - print("Summarized Latest Events:") - for event in latest_events: - print(event) - - # Get the last chat for a specific role - last_chat = loaded_agent_memory.get_last_chat(target_role_name="role1") - if last_chat: - print(f"Last chat for role1: {last_chat.content}") - else: - print("No chat found for role1") From 4e4a3bce584e5f14ea5c396320a4766061d18163 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Wed, 4 Oct 2023 23:19:47 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E8=AE=B0=E5=BF=86=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/st_game/memory/agent_memory.py | 21 ++++++++++----------- examples/st_game/tests/test_agent_memory.py | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index 97644c5b8..f80361395 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -174,18 +174,16 @@ class AgentMemory(Memory): poignancy = node_details["poignancy"] keywords = set(node_details["keywords"]) filling = node_details["filling"] - # print(node_type) - if node_type == "event": - self.add_event(created, expiration, s, p, o, - description, keywords, poignancy, embedding_pair, filling) - elif node_type == "chat": - # cause_by = node_details["cause_by"] - logger.info(f"{node_id}") - self.add_chat(created, expiration, s, p, o, - description, keywords, poignancy, embedding_pair, filling) - elif node_type == "thought": + if node_details["type"] == "thought": self.add_thought(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) + if node_details["type"] == "event": + self.add_event(created, expiration, s, p, o, + description, keywords, poignancy, embedding_pair, filling) + if node_details["type"] == "chat": + self.add_chat(created, expiration, s, p, o, + description, keywords, poignancy, embedding_pair, filling) + strength_keywords_load = json.load(open(memory_saved + "/kw_strength.json")) if strength_keywords_load["kw_strength_event"]: @@ -209,6 +207,7 @@ class AgentMemory(Memory): return 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, @@ -250,7 +249,7 @@ class AgentMemory(Memory): """ memory_count = len(self.storage) + 1 type_count = len(self.thought_list) + 1 - memory_type = "event" + memory_type = "thought" memory_id = f"node_{str(memory_count)}" depth = 1 diff --git a/examples/st_game/tests/test_agent_memory.py b/examples/st_game/tests/test_agent_memory.py index 08d065afd..f487218ea 100644 --- a/examples/st_game/tests/test_agent_memory.py +++ b/examples/st_game/tests/test_agent_memory.py @@ -44,6 +44,7 @@ class TestAgentMemory: 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): From 90bb3f94f61ade18777a232044f88085249add91 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Wed, 4 Oct 2023 23:36:29 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E5=BE=AA=E7=8E=AFimport=E8=A7=A3?= =?UTF-8?q?=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../st_game/actions/inner_voice_action.py | 5 ++--- .../st_game/actions/run_reflect_action.py | 21 +++++++++---------- examples/st_game/reflect/reflect.py | 3 +-- examples/st_game/tests/test_reflect.py | 13 +++++++++++- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/examples/st_game/actions/inner_voice_action.py b/examples/st_game/actions/inner_voice_action.py index 2a9bb0afc..082921554 100644 --- a/examples/st_game/actions/inner_voice_action.py +++ b/examples/st_game/actions/inner_voice_action.py @@ -1,5 +1,4 @@ import re -from examples.st_game.roles.st_role import STRole from examples.st_game.actions.st_action import STAction from examples.st_game.memory.agent_memory import BasicMemory from metagpt.logs import logger @@ -22,8 +21,8 @@ class AgentWhisperThoughtAction(STAction): 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): + 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 diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 40bb54d7b..1e26145c2 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -8,7 +8,6 @@ from metagpt.logs import logger from examples.st_game.actions.st_action import STAction from examples.st_game.memory.agent_memory import BasicMemory -from examples.st_game.roles.st_role import STRole # Run GPT Prompt Focal Point method @@ -34,8 +33,8 @@ class AgentFocusPt(STAction): def _func_fail_default_resp(self) -> str: pass - 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) -> str: + def create_prompt_input(role: "STRole", statements, n, test_input=None): prompt_input = [statements, str(n)] return prompt_input @@ -80,7 +79,7 @@ class AgentInsightAndGuidance(STAction): def _func_fail_default_resp(self) -> str: pass - def run(self, role: STRole, statements: str, n: int, test_input=None) -> dict: + 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 @@ -116,7 +115,7 @@ class AgentEventTriple(STAction): def _func_fail_default_resp(self) -> str: pass - def run(self, statements: str, role: STRole, verbose=False) -> tuple: + 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] @@ -155,8 +154,8 @@ class AgentEventPoignancy(STAction): def _func_fail_default_resp(self) -> str: pass - def run(self, role: STRole, statements: str, test_input=None, verbose=False) -> str: - def create_prompt_input(role: STRole, statements: str, test_input=None): + 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.scratch.name, role.scratch.get_str_iss(), role.scratch.name, @@ -196,8 +195,8 @@ class AgentChatPoignancy(STAction): def _func_fail_default_resp(self) -> str: pass - def run(self, role: STRole, statements: str, test_input=None, verbose=False) -> str: - def create_prompt_input(role: STRole, statements, test_input=None): + 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, role.scratch.get_str_iss(), role.scratch.name, @@ -236,7 +235,7 @@ class AgentPlanThoughtOnConvo(STAction): def _func_fail_default_resp(self) -> str: pass - 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.scratch.name, @@ -272,7 +271,7 @@ class AgentMemoryOnConvo(STAction): def _func_fail_default_resp(self) -> str: pass - 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.scratch.name, diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 1ff0c16ab..77a1554e6 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -5,7 +5,6 @@ import datetime from metagpt.logs import logger -from examples.st_game.roles.st_role import STRole from examples.st_game.utils.utils import get_embedding from examples.st_game.actions.run_reflect_action import ( AgentFocusPt, AgentInsightAndGuidance, AgentEventTriple, @@ -63,7 +62,7 @@ def generate_action_event_triple(act_desp, role): return result -def generate_poig_score(role: STRole, event_type, description): +def generate_poig_score(role: "STRole", event_type, description): if "is idle" in description: return 1 diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py index 54544f051..e1b77a591 100644 --- a/examples/st_game/tests/test_reflect.py +++ b/examples/st_game/tests/test_reflect.py @@ -1,7 +1,18 @@ +import pytest +from examples.st_game.roles.st_role import STRole from metagpt.logs import logger -from examples.st_game.memory.agent_memory import AgentMemory, BasicMemory + +class TestReflect: + @pytest.fixture + def init_agent(self): + # 创建一个AgentMemory实例并返回,可以在所有测试用例中共享 + role = STRole('Isabella Rodriguez', 'STMember', 'base_the_vile_isabella_maria_klaus') + return role + + def test_focus(self, init_agent): + init_agent.reflect() """ 测试思路 1. From 6f449f1505be9779884ff3423f07eed060947449 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Thu, 5 Oct 2023 01:22:12 +0800 Subject: [PATCH 08/12] =?UTF-8?q?Reflect=E6=B5=8B=E8=AF=95=E6=A0=B7?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../st_game/actions/run_reflect_action.py | 14 ++++++---- examples/st_game/memory/agent_memory.py | 6 ++--- examples/st_game/reflect/reflect.py | 9 +++---- examples/st_game/roles/st_role.py | 4 +-- examples/st_game/tests/test_reflect.py | 26 +++++++++++++------ 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 1e26145c2..9c688421c 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -24,11 +24,15 @@ class AgentFocusPt(STAction): return False def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list: - llm_resp = "1) " + llm_resp.strip() - ret = [] - for i in llm_resp.split("\n"): - ret += [i.split(") ")[-1]] - return ret + try: + return llm_resp + # llm_resp = "1) " + llm_resp.strip() + # ret = [] + # for i in llm_resp.split("\n"): + # ret += [i.split(") ")[-1]] + # return ret + except Exception as exp: + print(f"cleanup 错误 {exp}") def _func_fail_default_resp(self) -> str: pass diff --git a/examples/st_game/memory/agent_memory.py b/examples/st_game/memory/agent_memory.py index f80361395..869f94a4d 100644 --- a/examples/st_game/memory/agent_memory.py +++ b/examples/st_game/memory/agent_memory.py @@ -174,13 +174,13 @@ class AgentMemory(Memory): poignancy = node_details["poignancy"] keywords = set(node_details["keywords"]) filling = node_details["filling"] - if node_details["type"] == "thought": + if node_type == "thought": self.add_thought(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) - if node_details["type"] == "event": + if node_type == "event": self.add_event(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) - if node_details["type"] == "chat": + if node_type == "chat": self.add_chat(created, expiration, s, p, o, description, keywords, poignancy, embedding_pair, filling) diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 77a1554e6..d32d64200 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -122,6 +122,7 @@ def run_reflect(role: "STRole"): created, expiration, s, p, o, thought, keywords, thought_poignancy, thought_embedding_pair, evidence ) + logger.info(f"主谓宾为:{s}{p}{o},描述为{thought}") def reflection_trigger(role: "STRole"): @@ -138,14 +139,10 @@ def reflection_trigger(role: "STRole"): True if we are running a new reflection. False otherwise. """ - logger.info( - role.scratch.name, "role.scratch.importance_trigger_curr::", - role.scratch.importance_trigger_curr - ) - logger.info(role.scratch.importance_trigger_max) + logger.info(f"{role.scratch.name} role.scratch.importance_trigger_curr:: {role.scratch.importance_trigger_curr}"), if (role.scratch.importance_trigger_curr <= 0 and - [] != role.memory.seq_event + role.memory.seq_thought): + [] != role.memory.event_list + role.memory.thought_list): return True return False diff --git a/examples/st_game/roles/st_role.py b/examples/st_game/roles/st_role.py index ad53dc4c7..ca1bac6e0 100644 --- a/examples/st_game/roles/st_role.py +++ b/examples/st_game/roles/st_role.py @@ -309,9 +309,9 @@ class STRole(Role): # TODO re-add result into memory pass - async def reflect(self): + def reflect(self): # TODO reflection if meet reflect condition - role_reflect(self) + result = role_reflect(self) # TODO re-add result to memory # 已封装到Reflect函数之中 diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py index e1b77a591..307e17729 100644 --- a/examples/st_game/tests/test_reflect.py +++ b/examples/st_game/tests/test_reflect.py @@ -1,19 +1,29 @@ import pytest from examples.st_game.roles.st_role import STRole +from examples.st_game.actions.run_reflect_action import AgentFocusPt from metagpt.logs import logger -class TestReflect: +class TestReflectFunction: @pytest.fixture def init_agent(self): - # 创建一个AgentMemory实例并返回,可以在所有测试用例中共享 - role = STRole('Isabella Rodriguez', 'STMember', 'base_the_vile_isabella_maria_klaus') + # 创建一个STRole实例,注意从GA中copy过来JSON文件 + 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') + logger.info(role.scratch.name) + logger.info(f"记忆长度为{len(role.memory.storage)}") return role - def test_focus(self, init_agent): + def test_fuction_point_action(self,init_agent): + """ + + """ + run_focus = AgentFocusPt() + statements = "" # 这个statements 与 n 设置是遵循reflect里面实际设置# 来的,你写的时候可以对应代码看一下 + run_focus.run(init_agent, statements, n=3) + + # 测试全部Reflection功能 + def test_reflect_function(self, init_agent): + # 修改 近期 importace 确保Reflect机制能够触发 + init_agent.scratch.importance_trigger_curr = -1 init_agent.reflect() -""" -测试思路 -1. -""" \ No newline at end of file From d79ed767e2a28e0fd66ab8a46659403d253a0c63 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Thu, 5 Oct 2023 01:28:33 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/st_game/memory/retrieve.py | 2 +- examples/st_game/reflect/reflect.py | 1 + examples/st_game/tests/test_agent_memory.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/st_game/memory/retrieve.py b/examples/st_game/memory/retrieve.py index ffba5dcbb..9478b1f9f 100644 --- a/examples/st_game/memory/retrieve.py +++ b/examples/st_game/memory/retrieve.py @@ -70,7 +70,7 @@ def new_agent_retrieve(role, focus_points: list, n_count=30) -> dict: for i in role.memory.storage: if i.memory_id == n: i.last_accessed = role.scratch.curr_time - final_result.append(i.content) + final_result.append(i) retrieved[focal_pt] = final_result diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index d32d64200..761f3d943 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -105,6 +105,7 @@ def run_reflect(role: "STRole"): # For each of the focal points, generate thoughts and save it in the # 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) diff --git a/examples/st_game/tests/test_agent_memory.py b/examples/st_game/tests/test_agent_memory.py index f487218ea..9596f97d4 100644 --- a/examples/st_game/tests/test_agent_memory.py +++ b/examples/st_game/tests/test_agent_memory.py @@ -67,7 +67,7 @@ class TestAgentMemory: for i in agent_memory.storage: if i.memory_id == n: i.last_accessed = datetime.now()-timedelta(days=120) - final_result.append(i.content) + final_result.append(i) retrieved[focal_pt] = final_result logger.info(f"检索结果为{retrieved}") \ No newline at end of file From 1ec2b922c13c87cc9d48c08a1f3246f43c2386e2 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Thu, 5 Oct 2023 19:45:37 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E6=B5=8B=E8=AF=95Agent=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/st_game/tests/test_reflect.py | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py index 307e17729..43139de4b 100644 --- a/examples/st_game/tests/test_reflect.py +++ b/examples/st_game/tests/test_reflect.py @@ -1,7 +1,7 @@ import pytest from examples.st_game.roles.st_role import STRole -from examples.st_game.actions.run_reflect_action import AgentFocusPt +from examples.st_game.actions.run_reflect_action import AgentFocusPt, AgentInsightAndGuidance, AgentEventTriple, AgentEventPoignancy, AgentChatPoignancy, AgentPlanThoughtOnConvo, AgentMemoryOnConvo from metagpt.logs import logger @@ -14,14 +14,36 @@ class TestReflectFunction: logger.info(f"记忆长度为{len(role.memory.storage)}") return role - def test_fuction_point_action(self,init_agent): + def test_function_focus_and_insight_action(self,init_agent): """ - + 单个Action测试样例 """ run_focus = AgentFocusPt() statements = "" # 这个statements 与 n 设置是遵循reflect里面实际设置# 来的,你写的时候可以对应代码看一下 run_focus.run(init_agent, statements, n=3) + run_insight = AgentInsightAndGuidance() + # 这里主要需要查看,Looger.info(filling) + # 完善代码 + + def test_event_triple_action(self,init_agent): + """ + 测试tripleAgent Action + """ + pass + + def test_poignancy_action(self,init_agent): + """ + 测试两个关于poignancy的Action + """ + pass + + def test_convo_action(self,init_agent): + """ + 测试两个convo相关的类 + """ + pass + # 测试全部Reflection功能 def test_reflect_function(self, init_agent): # 修改 近期 importace 确保Reflect机制能够触发 From e40e3bacc56c4b42f279372677d3978e7733e645 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Fri, 6 Oct 2023 01:44:45 +0800 Subject: [PATCH 11/12] =?UTF-8?q?Reflect=E6=B5=8B=E8=AF=95=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 能通过 2. insight不稳定 --- .../st_game/actions/run_reflect_action.py | 63 ++++++++++++------- .../prompts/insight_and_evidence_v1.txt | 2 +- examples/st_game/reflect/reflect.py | 27 ++++---- examples/st_game/tests/test_reflect.py | 25 +++++--- 4 files changed, 74 insertions(+), 43 deletions(-) diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 9c688421c..10e22dbcf 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -69,16 +69,20 @@ class AgentInsightAndGuidance(STAction): return False def _func_cleanup(self, llm_resp: str, prompt: str = "") -> dict: - 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 + try: + logger.info(f"Run prompt Insight get {llm_resp}") + 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"AGent Insight 报错{exp}") def _func_fail_default_resp(self) -> str: pass @@ -112,9 +116,15 @@ class AgentEventTriple(STAction): return True def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list: - cr = llm_resp.strip() - cr = [i.strip() for i in cr.split(")")[0].split(",")] - return cr + try: + cr = llm_resp.strip() + cr = [i.strip() for i in cr.split(")")[0].split(",")] + if len(cr) != 2: + return cr[-2:] + logger.info(f"cr结果为{cr}") + return cr + except Exception as exp: + logger.error(f"AGent Triple 报错{exp}") def _func_fail_default_resp(self) -> str: pass @@ -152,9 +162,11 @@ class AgentEventPoignancy(STAction): return False def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int: - llm_resp = int(llm_resp.strip()) - return llm_resp - + try: + llm_resp = int(llm_resp.strip()) + return llm_resp + except Exception as exp: + logger.error(f"AGent Event poignancy 报错{exp}") def _func_fail_default_resp(self) -> str: pass @@ -193,9 +205,11 @@ class AgentChatPoignancy(STAction): return False def _func_cleanup(self, llm_resp: str, prompt: str = "") -> int: - llm_resp = int(llm_resp.strip()) - return llm_resp - + try: + llm_resp = int(llm_resp.strip()) + return llm_resp + except Exception as exp: + logger.error(f"AGent Chat poignancy 报错{exp}") def _func_fail_default_resp(self) -> str: pass @@ -234,7 +248,10 @@ 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"AGent PlanThought 报错{exp}") def _func_fail_default_resp(self) -> str: pass @@ -270,8 +287,10 @@ 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"AGent MemoryOnconvo 报错{exp}") def _func_fail_default_resp(self) -> str: pass diff --git a/examples/st_game/prompts/insight_and_evidence_v1.txt b/examples/st_game/prompts/insight_and_evidence_v1.txt index 579c81637..35671023b 100644 --- a/examples/st_game/prompts/insight_and_evidence_v1.txt +++ b/examples/st_game/prompts/insight_and_evidence_v1.txt @@ -8,5 +8,5 @@ Variables: Input: !! -What !! high-level insights can you infer from the above statements? (example format: insight (because of 1, 5, 3)) +What !! 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. \ No newline at end of file diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 761f3d943..5423e52bf 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -37,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.info(f"insight处理错误为{exp}") return {"this is blank": "node_1"} @@ -57,6 +59,7 @@ def generate_action_event_triple(act_desp, role): EXAMPLE OUTPUT: "🧈🍞" """ + logger.info(f"event Triple 输入为:{act_desp}") run_event_triple = AgentEventTriple() result = run_event_triple.run(act_desp, role) return result @@ -68,11 +71,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.scratch.act_description)[0] + role.scratch.act_description) def generate_planning_thought_on_convo(role, all_utt): @@ -98,24 +101,24 @@ 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. # has keys of focal points, and values of the associated Nodes. retrieved = role.retrieve(focal_points) # For each of the focal points, generate thoughts and save it in the # 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) + logger.info(f"检索结果为{nodes}") + # xx = [i.embedding_key for i in nodes] + # for xxx in xx: logger.info(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) - keywords = {[s, p, o]} + 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)) @@ -193,7 +196,7 @@ def role_reflect(role: "STRole"): created = role.scratch.curr_time expiration = created + datetime.timedelta(days=30) s, p, o = generate_action_event_triple(planning_thought, role) - keywords = {[s, p, o]} + keywords = set([s, p, o]) thought_poignancy = generate_poig_score(role, "thought", planning_thought) thought_embedding_pair = (planning_thought, get_embedding(planning_thought)) @@ -208,7 +211,7 @@ def role_reflect(role: "STRole"): created = role.scratch.curr_time expiration = created + datetime.timedelta(days=30) s, p, o = generate_action_event_triple(memo_thought, role) - keywords = {[s, p, o]} + keywords = set([s, p, o]) thought_poignancy = generate_poig_score(role, "thought", memo_thought) thought_embedding_pair = (memo_thought, get_embedding(memo_thought)) diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py index 43139de4b..1593d9aaa 100644 --- a/examples/st_game/tests/test_reflect.py +++ b/examples/st_game/tests/test_reflect.py @@ -10,32 +10,41 @@ class TestReflectFunction: def init_agent(self): # 创建一个STRole实例,注意从GA中copy过来JSON文件 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') - logger.info(role.scratch.name) - logger.info(f"记忆长度为{len(role.memory.storage)}") return role def test_function_focus_and_insight_action(self,init_agent): """ 单个Action测试样例 """ - run_focus = AgentFocusPt() - statements = "" # 这个statements 与 n 设置是遵循reflect里面实际设置# 来的,你写的时候可以对应代码看一下 - run_focus.run(init_agent, statements, n=3) + logger.info(f"{__name__}函数启动") + # run_focus = AgentFocusPt() + # statements = "" # 这个statements 与 n 设置是遵循reflect里面实际设置# 来的,你写的时候可以对应代码看一下 + # out_put = run_focus.run(init_agent, statements, n=3) - run_insight = AgentInsightAndGuidance() - # 这里主要需要查看,Looger.info(filling) - # 完善代码 + """ + 这里有通过测试的结果,但是更多时候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): """ 测试tripleAgent Action + 我们需要限制生成字数在15之内,生成字数没有限制的时候很容易跑通 + Prompt同样存在问题,但是我做了处理 """ + run_triple = AgentEventTriple() + statements = "(Klaus Mueller is academically inclined)" + run_triple.run(statements,init_agent) pass def test_poignancy_action(self,init_agent): """ 测试两个关于poignancy的Action """ + pass def test_convo_action(self,init_agent): From da44e12677142f003f23a7211a27eb068f6e2326 Mon Sep 17 00:00:00 2001 From: didi <2020201387@ruc.edu.cn> Date: Fri, 6 Oct 2023 20:13:46 +0800 Subject: [PATCH 12/12] =?UTF-8?q?PEP8=E6=A0=BC=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../st_game/actions/run_reflect_action.py | 29 +++++---- examples/st_game/reflect/reflect.py | 12 ++-- examples/st_game/tests/test_reflect.py | 63 ++++++++++--------- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/examples/st_game/actions/run_reflect_action.py b/examples/st_game/actions/run_reflect_action.py index 10e22dbcf..d29b654f8 100644 --- a/examples/st_game/actions/run_reflect_action.py +++ b/examples/st_game/actions/run_reflect_action.py @@ -23,16 +23,14 @@ class AgentFocusPt(STAction): except: return False - def _func_cleanup(self, llm_resp: str, prompt: str = "") -> list: + def _func_cleanup(self, llm_resp: str, prompt: str = "") -> str: try: + """ + Cleanup handling has been completed for run_v2 + """ return llm_resp - # llm_resp = "1) " + llm_resp.strip() - # ret = [] - # for i in llm_resp.split("\n"): - # ret += [i.split(") ")[-1]] - # return ret except Exception as exp: - print(f"cleanup 错误 {exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") def _func_fail_default_resp(self) -> str: pass @@ -70,7 +68,6 @@ class AgentInsightAndGuidance(STAction): def _func_cleanup(self, llm_resp: str, prompt: str = "") -> dict: try: - logger.info(f"Run prompt Insight get {llm_resp}") llm_resp = "1. " + llm_resp.strip() ret = dict() for i in llm_resp.split("\n"): @@ -82,7 +79,7 @@ class AgentInsightAndGuidance(STAction): ret[thought] = evi_raw return ret except Exception as exp: - logger.error(f"AGent Insight 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") def _func_fail_default_resp(self) -> str: pass @@ -121,10 +118,9 @@ class AgentEventTriple(STAction): cr = [i.strip() for i in cr.split(")")[0].split(",")] if len(cr) != 2: return cr[-2:] - logger.info(f"cr结果为{cr}") return cr except Exception as exp: - logger.error(f"AGent Triple 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") def _func_fail_default_resp(self) -> str: pass @@ -166,7 +162,8 @@ class AgentEventPoignancy(STAction): llm_resp = int(llm_resp.strip()) return llm_resp except Exception as exp: - logger.error(f"AGent Event poignancy 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") + def _func_fail_default_resp(self) -> str: pass @@ -209,7 +206,8 @@ class AgentChatPoignancy(STAction): llm_resp = int(llm_resp.strip()) return llm_resp except Exception as exp: - logger.error(f"AGent Chat poignancy 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") + def _func_fail_default_resp(self) -> str: pass @@ -251,7 +249,7 @@ class AgentPlanThoughtOnConvo(STAction): try: return llm_resp.split('"')[0].strip() except Exception as exp: - logger.error(f"AGent PlanThought 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") def _func_fail_default_resp(self) -> str: pass @@ -290,7 +288,8 @@ class AgentMemoryOnConvo(STAction): try: return llm_resp.split('"')[0].strip() except Exception as exp: - logger.error(f"AGent MemoryOnconvo 报错{exp}") + logger.error(f"{self.__class__.__name__} with error {exp}") + def _func_fail_default_resp(self) -> str: pass diff --git a/examples/st_game/reflect/reflect.py b/examples/st_game/reflect/reflect.py index 5423e52bf..62f835e1a 100644 --- a/examples/st_game/reflect/reflect.py +++ b/examples/st_game/reflect/reflect.py @@ -44,7 +44,7 @@ def generate_insights_and_evidence(role, nodes, n=5): ret[thought] = evidence_node_id return ret except Exception as exp: - logger.info(f"insight处理错误为{exp}") + logger.error(f"generate_insights_and_evidence error:{exp}") return {"this is blank": "node_1"} @@ -59,7 +59,6 @@ def generate_action_event_triple(act_desp, role): EXAMPLE OUTPUT: "🧈🍞" """ - logger.info(f"event Triple 输入为:{act_desp}") run_event_triple = AgentEventTriple() result = run_event_triple.run(act_desp, role) return result @@ -108,16 +107,15 @@ def run_reflect(role: "STRole"): # For each of the focal points, generate thoughts and save it in the # agent's memory. for focal_pt, nodes in retrieved.items(): - logger.info(f"检索结果为{nodes}") - # xx = [i.embedding_key for i in nodes] - # for xxx in xx: logger.info(xxx) + xx = [i.embedding_key for i in nodes] + 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)) @@ -126,7 +124,7 @@ def run_reflect(role: "STRole"): created, expiration, s, p, o, thought, keywords, thought_poignancy, thought_embedding_pair, evidence ) - logger.info(f"主谓宾为:{s}{p}{o},描述为{thought}") + logger.info(f"add thought memory: {thought}") def reflection_trigger(role: "STRole"): diff --git a/examples/st_game/tests/test_reflect.py b/examples/st_game/tests/test_reflect.py index 1593d9aaa..191e46279 100644 --- a/examples/st_game/tests/test_reflect.py +++ b/examples/st_game/tests/test_reflect.py @@ -1,60 +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 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): - # 创建一个STRole实例,注意从GA中copy过来JSON文件 - 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') + """ + 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): + def test_function_focus_and_insight_action(self, init_agent): """ - 单个Action测试样例 + test for AgentFocusPt & AgentInsightAndGuidance """ logger.info(f"{__name__}函数启动") - # run_focus = AgentFocusPt() - # statements = "" # 这个statements 与 n 设置是遵循reflect里面实际设置# 来的,你写的时候可以对应代码看一下 - # out_put = run_focus.run(init_agent, statements, n=3) + 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) + 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): + def test_event_triple_action(self, init_agent): """ - 测试tripleAgent Action - 我们需要限制生成字数在15之内,生成字数没有限制的时候很容易跑通 - Prompt同样存在问题,但是我做了处理 + test for AgentEventTriple + error:遇到复杂情况时(多个Object)无法正确归纳, + solution: 限制MaxTokens为15 """ run_triple = AgentEventTriple() statements = "(Klaus Mueller is academically inclined)" - run_triple.run(statements,init_agent) - pass + run_triple.run(statements, init_agent) - def test_poignancy_action(self,init_agent): + def test_poignancy_action(self, init_agent): """ - 测试两个关于poignancy的Action - """ - - pass - - def test_convo_action(self,init_agent): - """ - 测试两个convo相关的类 + test for AgentEventPoignancy, AgentChatPoignancy + done in reflect test + """ + pass + + def test_convo_action(self, init_agent): + """ + test for AgentPlanThoughtOnConvo, AgentMemoryOnConvo + TODO Undone """ pass - # 测试全部Reflection功能 def test_reflect_function(self, init_agent): - # 修改 近期 importace 确保Reflect机制能够触发 + """ + test for reflection + modify importance_trigger_curr to trigger reflect + """ init_agent.scratch.importance_trigger_curr = -1 init_agent.reflect()