update serializers

This commit is contained in:
seehi 2024-07-16 16:39:43 +08:00
parent 0c6786feaa
commit 8b9e992b56
6 changed files with 30 additions and 32 deletions

View file

@ -121,7 +121,7 @@ class ExpCacheHandler(BaseModel):
self.serializer = self.serializer or SimpleSerializer()
self.tag = self.tag or self._generate_tag()
self._req = self.serializer.serialize_req(self.kwargs["req"])
self._req = self.serializer.serialize_req(**self.kwargs)
return self

View file

@ -10,10 +10,10 @@ class BaseSerializer(BaseModel, ABC):
model_config = ConfigDict(arbitrary_types_allowed=True)
@abstractmethod
def serialize_req(self, req: Any) -> str:
def serialize_req(self, **kwargs) -> str:
"""Serializes the request for storage.
Do not modify req. If modification is necessary, use copy.deepcopy to create a copy first.
Do not modify kwargs. If modification is necessary, use copy.deepcopy to create a copy first.
Note that copy.deepcopy may raise errors, such as TypeError: cannot pickle '_thread.RLock' object.
"""

View file

@ -7,7 +7,7 @@ from metagpt.exp_pool.serializers.simple import SimpleSerializer
class RoleZeroSerializer(SimpleSerializer):
def serialize_req(self, req: list[dict]) -> str:
def serialize_req(self, **kwargs) -> str:
"""Serialize the request for database storage, ensuring it is a string.
Only extracts the necessary content from `req` because `req` may be very lengthy and could cause embedding errors.
@ -18,18 +18,20 @@ class RoleZeroSerializer(SimpleSerializer):
{"role": "user", "content": "..."},
{"role": "assistant", "content": "..."},
{"role": "user", "content": "context"},
{"role": "user", "content": "context exp part"},
]
Returns:
str: The serialized request as a JSON string.
"""
req = kwargs.get("req", [])
if not req:
return ""
filtered_req = self._filter_req(req)
filtered_req.append(req[-1])
if state_data := kwargs.get("state_data"):
filtered_req.append({"role": "user", "content": state_data})
return json.dumps(filtered_req)

View file

@ -6,10 +6,10 @@ from metagpt.exp_pool.serializers.base import BaseSerializer
class SimpleSerializer(BaseSerializer):
def serialize_req(self, req: Any) -> str:
def serialize_req(self, **kwargs) -> str:
"""Just use `str` to convert the request object into a string."""
return str(req)
return str(kwargs.get("req", ""))
def serialize_resp(self, resp: Any) -> str:
"""Just use `str` to convert the response object into a string."""

View file

@ -8,16 +8,6 @@ Note:
2. Carefully review your progress at the current task, if your actions so far has not fulfilled the task instruction, you should continue with current task. Otherwise, finish current task by Plan.finish_current_task explicitly.
3. Each time you finish a task, use RoleZero.reply_to_human to report your progress.
"""
CMD_PROMPT_EXP_PART = """
# Current Plan
{plan_status}
# Current Task
{current_task}
# Instruction
{instruction}
"""
# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# Available Commands".
CMD_PROMPT = """
# Data Structure
@ -38,7 +28,14 @@ Special Command: Use {{"command_name": "end"}} to do nothing or indicate complet
# Available Task Types
{task_type_desc}
{cmd_prompt_exp_part}
# Current Plan
{plan_status}
# Current Task
{current_task}
# Instruction
{instruction}
Pay close attention to the Example provided, you can reuse the example for your current situation if it fits.
You may use any of the available commands to create a plan or update the plan. You may output mutiple commands, they will be executed sequentially.

View file

@ -16,7 +16,6 @@ from metagpt.exp_pool.serializers import RoleZeroSerializer
from metagpt.logs import logger
from metagpt.prompts.di.role_zero import (
CMD_PROMPT,
CMD_PROMPT_EXP_PART,
JSON_REPAIR_PROMPT,
QUICK_THINK_PROMPT,
ROLE_INSTRUCTION,
@ -147,39 +146,39 @@ class RoleZero(Role):
tool_info = json.dumps({tool.name: tool.schemas for tool in tools})
### Make Decision Dynamically ###
cmd_prompt_exp_part = CMD_PROMPT_EXP_PART.format(
plan_status=plan_status,
current_task=current_task,
instruction=self.instruction.strip(),
)
instruction = self.instruction.strip()
prompt = self.cmd_prompt.format(
example=example,
available_commands=tool_info,
task_type_desc=self.task_type_desc,
cmd_prompt_exp_part=cmd_prompt_exp_part,
plan_status=plan_status,
current_task=current_task,
instruction=instruction,
)
memory = self.rc.memory.get(self.memory_k)
memory = await self.parse_browser_actions(memory)
req = self.llm.format_msg(memory + [UserMessage(content=prompt), UserMessage(content=cmd_prompt_exp_part)])
req = self.llm.format_msg(memory + [UserMessage(content=prompt)])
async with ThoughtReporter(enable_llm_stream=True) as reporter:
await reporter.async_report({"type": "react"})
self.command_rsp = await self.llm_cached_aask(req=req, system_msgs=self.system_msg)
state_data = dict(
plan_status=plan_status,
current_task=current_task,
instruction=instruction,
)
self.command_rsp = await self.llm_cached_aask(req=req, system_msgs=self.system_msg, state_data=state_data)
self.rc.memory.add(AIMessage(content=self.command_rsp))
return True
@exp_cache(context_builder=RoleZeroContextBuilder(), serializer=RoleZeroSerializer())
async def llm_cached_aask(self, *, req: list[dict], system_msgs: list[str]) -> str:
async def llm_cached_aask(self, *, req: list[dict], system_msgs: list[str], **kwargs) -> str:
"""Use `exp_cache` to automatically manage experiences.
The `RoleZeroContextBuilder` attempts to add experiences to `req`.
The `RoleZeroSerializer` extracts essential parts of `req` for the experience pool, trimming lengthy entries to retain only necessary parts.
"""
# Remove the "cmd_prompt_exp_part", it is only used within the exp_cache decorator.
if req:
req.pop()
return await self.llm.aask(req, system_msgs=system_msgs)