mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-05-08 15:22:38 +02:00
添加一个代码
This commit is contained in:
commit
552547e662
58 changed files with 632 additions and 327 deletions
|
|
@ -11,9 +11,28 @@ from metagpt.roles import Role
|
|||
|
||||
|
||||
class Architect(Role):
|
||||
"""Architect: Listen to PRD, responsible for designing API, designing code files"""
|
||||
def __init__(self, name="Bob", profile="Architect", goal="Design a concise, usable, complete python system",
|
||||
constraints="Try to specify good open source tools as much as possible"):
|
||||
"""
|
||||
Represents an Architect role in a software development process.
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the architect.
|
||||
profile (str): Role profile, default is 'Architect'.
|
||||
goal (str): Primary goal or responsibility of the architect.
|
||||
constraints (str): Constraints or guidelines for the architect.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = "Bob",
|
||||
profile: str = "Architect",
|
||||
goal: str = "Design a concise, usable, complete python system",
|
||||
constraints: str = "Try to specify good open source tools as much as possible") -> None:
|
||||
"""Initializes the Architect with given attributes."""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
|
||||
# Initialize actions specific to the Architect role
|
||||
self._init_actions([WriteDesign])
|
||||
|
||||
# Set events or actions the Architect should watch or be aware of
|
||||
self._watch({WritePRD})
|
||||
|
||||
|
||||
|
|
@ -32,3 +32,4 @@ class CustomerService(Sales):
|
|||
store=None
|
||||
):
|
||||
super().__init__(name, profile, desc=desc, store=store)
|
||||
|
||||
|
|
@ -47,9 +47,27 @@ async def gather_ordered_k(coros, k) -> list:
|
|||
|
||||
|
||||
class Engineer(Role):
|
||||
def __init__(self, name="Alex", profile="Engineer", goal="Write elegant, readable, extensible, efficient code",
|
||||
constraints="The code you write should conform to code standard like PEP8, be modular, easy to read and maintain",
|
||||
n_borg=1, use_code_review=False):
|
||||
"""
|
||||
Represents an Engineer role responsible for writing and possibly reviewing code.
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the engineer.
|
||||
profile (str): Role profile, default is 'Engineer'.
|
||||
goal (str): Goal of the engineer.
|
||||
constraints (str): Constraints for the engineer.
|
||||
n_borg (int): Number of borgs.
|
||||
use_code_review (bool): Whether to use code review.
|
||||
todos (list): List of tasks.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = "Alex",
|
||||
profile: str = "Engineer",
|
||||
goal: str = "Write elegant, readable, extensible, efficient code",
|
||||
constraints: str = "The code should conform to standards like PEP8 and be modular and maintainable",
|
||||
n_borg: int = 1,
|
||||
use_code_review: bool = False) -> None:
|
||||
"""Initializes the Engineer role with given attributes."""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WriteCode])
|
||||
self.use_code_review = use_code_review
|
||||
|
|
@ -88,7 +106,7 @@ class Engineer(Role):
|
|||
try:
|
||||
shutil.rmtree(workspace)
|
||||
except FileNotFoundError:
|
||||
pass # 文件夹不存在,但我们不在意
|
||||
pass # The folder does not exist, but we don't care
|
||||
workspace.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def write_file(self, filename: str, code: str):
|
||||
|
|
@ -158,23 +176,23 @@ class Engineer(Role):
|
|||
code_msg_all = [] # gather all code info, will pass to qa_engineer for tests later
|
||||
for todo in self.todos:
|
||||
"""
|
||||
# 从历史信息中挑选必须的信息,以减少prompt长度(人工经验总结)
|
||||
1. Architect全部
|
||||
2. ProjectManager全部
|
||||
3. 是否需要其他代码(暂时需要)?
|
||||
TODO:目标是不需要。在任务拆分清楚后,根据设计思路,不需要其他代码也能够写清楚单个文件,如果不能则表示还需要在定义的更清晰,这个是代码能够写长的关键
|
||||
# Select essential information from the historical data to reduce the length of the prompt (summarized from human experience):
|
||||
1. All from Architect
|
||||
2. All from ProjectManager
|
||||
3. Do we need other codes (currently needed)?
|
||||
TODO: The goal is not to need it. After clear task decomposition, based on the design idea, you should be able to write a single file without needing other codes. If you can't, it means you need a clearer definition. This is the key to writing longer code.
|
||||
"""
|
||||
context = []
|
||||
msg = self._rc.memory.get_by_actions([WriteDesign, WriteTasks, WriteCode])
|
||||
for m in msg:
|
||||
context.append(m.content)
|
||||
context_str = "\n".join(context)
|
||||
# 编写code
|
||||
# Write code
|
||||
code = await WriteCode().run(
|
||||
context=context_str,
|
||||
filename=todo
|
||||
)
|
||||
# code review
|
||||
# Code review
|
||||
if self.use_code_review:
|
||||
try:
|
||||
rewrite_code = await WriteCodeReview().run(
|
||||
|
|
@ -203,6 +221,7 @@ class Engineer(Role):
|
|||
return msg
|
||||
|
||||
async def _act(self) -> Message:
|
||||
"""Determines the mode of action based on whether code review is used."""
|
||||
if self.use_code_review:
|
||||
return await self._act_sp_precision()
|
||||
return await self._act_sp()
|
||||
return await self._act_sp()
|
||||
|
|
@ -10,8 +10,30 @@ from metagpt.roles import Role
|
|||
|
||||
|
||||
class ProductManager(Role):
|
||||
def __init__(self, name="Alice", profile="Product Manager", goal="Efficiently create a successful product",
|
||||
constraints=""):
|
||||
"""
|
||||
Represents a Product Manager role responsible for product development and management.
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the product manager.
|
||||
profile (str): Role profile, default is 'Product Manager'.
|
||||
goal (str): Goal of the product manager.
|
||||
constraints (str): Constraints or limitations for the product manager.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = "Alice",
|
||||
profile: str = "Product Manager",
|
||||
goal: str = "Efficiently create a successful product",
|
||||
constraints: str = "") -> None:
|
||||
"""
|
||||
Initializes the ProductManager role with given attributes.
|
||||
|
||||
Args:
|
||||
name (str): Name of the product manager.
|
||||
profile (str): Role profile.
|
||||
goal (str): Goal of the product manager.
|
||||
constraints (str): Constraints or limitations for the product manager.
|
||||
"""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WritePRD])
|
||||
self._watch([BossRequirement])
|
||||
self._watch([BossRequirement])
|
||||
|
|
@ -10,8 +10,30 @@ from metagpt.roles import Role
|
|||
|
||||
|
||||
class ProjectManager(Role):
|
||||
def __init__(self, name="Eve", profile="Project Manager",
|
||||
goal="Improve team efficiency and deliver with quality and quantity", constraints=""):
|
||||
"""
|
||||
Represents a Project Manager role responsible for overseeing project execution and team efficiency.
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the project manager.
|
||||
profile (str): Role profile, default is 'Project Manager'.
|
||||
goal (str): Goal of the project manager.
|
||||
constraints (str): Constraints or limitations for the project manager.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = "Eve",
|
||||
profile: str = "Project Manager",
|
||||
goal: str = "Improve team efficiency and deliver with quality and quantity",
|
||||
constraints: str = "") -> None:
|
||||
"""
|
||||
Initializes the ProjectManager role with given attributes.
|
||||
|
||||
Args:
|
||||
name (str): Name of the project manager.
|
||||
profile (str): Role profile.
|
||||
goal (str): Goal of the project manager.
|
||||
constraints (str): Constraints or limitations for the project manager.
|
||||
"""
|
||||
super().__init__(name, profile, goal, constraints)
|
||||
self._init_actions([WriteTasks])
|
||||
self._watch([WriteDesign])
|
||||
self._watch([WriteDesign])
|
||||
|
|
@ -7,40 +7,39 @@
|
|||
"""
|
||||
from enum import Enum
|
||||
|
||||
PREFIX = """尽你所能回答以下问题。你可以使用以下工具:"""
|
||||
FORMAT_INSTRUCTIONS = """请按照以下格式:
|
||||
PREFIX = """Answer the questions to the best of your ability. You can use the following tools:"""
|
||||
FORMAT_INSTRUCTIONS = """Please follow the format below:
|
||||
|
||||
问题:你需要回答的输入问题
|
||||
思考:你应该始终思考该怎么做
|
||||
行动:要采取的行动,应该是[{tool_names}]中的一个
|
||||
行动输入:行动的输入
|
||||
观察:行动的结果
|
||||
...(这个思考/行动/行动输入/观察可以重复N次)
|
||||
思考:我现在知道最终答案了
|
||||
最终答案:对原始输入问题的最终答案"""
|
||||
SUFFIX = """开始吧!
|
||||
|
||||
问题:{input}
|
||||
思考:{agent_scratchpad}"""
|
||||
Question: The input question you need to answer
|
||||
Thoughts: You should always think about how to do it
|
||||
Action: The action to be taken, should be one from [{tool_names}]
|
||||
Action Input: Input for the action
|
||||
Observation: Result of the action
|
||||
... (This Thoughts/Action/Action Input/Observation can be repeated N times)
|
||||
Thoughts: I now know the final answer
|
||||
Final Answer: The final answer to the original input question"""
|
||||
SUFFIX = """Let's begin!
|
||||
|
||||
Question: {input}
|
||||
Thoughts: {agent_scratchpad}"""
|
||||
|
||||
class PromptString(Enum):
|
||||
REFLECTION_QUESTIONS = "以下是一些陈述:\n{memory_descriptions}\n\n仅根据以上信息,我们可以回答关于陈述中主题的3个最显著的高级问题是什么?\n\n{format_instructions}"
|
||||
REFLECTION_QUESTIONS = "Here are some statements:\n{memory_descriptions}\n\nBased solely on the information above, what are the 3 most prominent high-level questions we can answer about the topic in the statements?\n\n{format_instructions}"
|
||||
|
||||
REFLECTION_INSIGHTS = "\n{memory_strings}\n你可以从以上陈述中推断出5个高级洞察吗?在提到人时,总是指定他们的名字。\n\n{format_instructions}"
|
||||
REFLECTION_INSIGHTS = "\n{memory_strings}\nCan you infer 5 high-level insights from the statements above? When mentioning people, always specify their names.\n\n{format_instructions}"
|
||||
|
||||
IMPORTANCE = "你是一个记忆重要性AI。根据角色的个人资料和记忆描述,对记忆的重要性进行1到10的评级,其中1是纯粹的日常(例如,刷牙,整理床铺),10是极其深刻的(例如,分手,大学录取)。确保你的评级相对于角色的个性和关注点。\n\n示例#1:\n姓名:Jojo\n简介:Jojo是一个专业的滑冰运动员,喜欢特色咖啡。她希望有一天能参加奥运会。\n记忆:Jojo看到了一个新的咖啡店\n\n 你的回应:'{{\"rating\": 3}}'\n\n示例#2:\n姓名:Skylar\n简介:Skylar是一名产品营销经理。她在一家成长阶段的科技公司工作,该公司制造自动驾驶汽车。她喜欢猫。\n记忆:Skylar看到了一个新的咖啡店\n\n 你的回应:'{{\"rating\": 1}}'\n\n示例#3:\n姓名:Bob\n简介:Bob是纽约市下东区的一名水管工。他已经做了20年的水管工。周末他喜欢和他的妻子一起散步。\n记忆:Bob的妻子打了他一巴掌。\n\n 你的回应:'{{\"rating\": 9}}'\n\n示例#4:\n姓名:Thomas\n简介:Thomas是明尼阿波利斯的一名警察。他只在警队工作了6个月,因为经验不足在工作中遇到了困难。\n记忆:Thomas不小心把饮料洒在了一个陌生人身上\n\n 你的回应:'{{\"rating\": 6}}'\n\n示例#5:\n姓名:Laura\n简介:Laura是一名在大型科技公司工作的营销专家。她喜欢旅行和尝试新的食物。她对探索新的文化和结识来自各行各业的人充满热情。\n记忆:Laura到达了会议室\n\n 你的回应:'{{\"rating\": 1}}'\n\n{format_instructions} 让我们开始吧! \n\n 姓名:{full_name}\n个人简介:{private_bio}\n记忆:{memory_description}\n\n"
|
||||
IMPORTANCE = "You are a Memory Importance AI. Based on the character's personal profile and memory description, rate the importance of the memory from 1 to 10, where 1 is purely routine (e.g., brushing teeth, making the bed), and 10 is extremely profound (e.g., breakup, university admission). Ensure your rating is relative to the character's personality and focus points.\n\nExample#1:\nName: Jojo\nProfile: Jojo is a professional skater and loves specialty coffee. She hopes to compete in the Olympics one day.\nMemory: Jojo saw a new coffee shop\n\n Your response: '{{\"rating\": 3}}'\n\nExample#2:\nName: Skylar\nProfile: Skylar is a product marketing manager. She works at a growing tech company that manufactures self-driving cars. She loves cats.\nMemory: Skylar saw a new coffee shop\n\n Your response: '{{\"rating\": 1}}'\n\nExample#3:\nName: Bob\nProfile: Bob is a plumber from the Lower East Side of New York City. He has been a plumber for 20 years. He enjoys walking with his wife on weekends.\nMemory: Bob's wife slapped him.\n\n Your response: '{{\"rating\": 9}}'\n\nExample#4:\nName: Thomas\nProfile: Thomas is a cop from Minneapolis. He has only worked in the police force for 6 months and struggles due to lack of experience.\nMemory: Thomas accidentally spilled a drink on a stranger\n\n Your response: '{{\"rating\": 6}}'\n\nExample#5:\nName: Laura\nProfile: Laura is a marketing expert working at a large tech company. She loves to travel and try new foods. She is passionate about exploring new cultures and meeting people from all walks of life.\nMemory: Laura arrived at the conference room\n\n Your response: '{{\"rating\": 1}}'\n\n{format_instructions} Let's begin! \n\n Name: {full_name}\nProfile: {private_bio}\nMemory: {memory_description}\n\n"
|
||||
|
||||
RECENT_ACTIIVITY = "根据以下记忆,生成一个关于{full_name}最近在做什么的简短总结。不要编造记忆中未明确指定的细节。对于任何对话,一定要提到对话是否已经结束或者仍在进行中。\n\n记忆:{memory_descriptions}"
|
||||
RECENT_ACTIVITY = "Based on the following memory, produce a brief summary of what {full_name} has been up to recently. Do not invent details not explicitly stated in the memory. For any conversation, be sure to mention whether the conversation has concluded or is still ongoing.\n\nMemory: {memory_descriptions}"
|
||||
|
||||
MAKE_PLANS = '你是一个计划生成的AI,你的工作是根据新信息帮助角色制定新计划。根据角色的信息(个人简介,目标,最近的活动,当前计划,和位置上下文)和角色的当前思考过程,为他们生成一套新的计划,使得最后的计划包括至少{time_window}的活动,并且不超过5个单独的计划。计划列表应按照他们应执行的顺序编号,每个计划包含描述,位置,开始时间,停止条件,和最大持续时间。\n\n示例计划:\'{{"index": 1, "description": "Cook dinner", "location_id": "0a3bc22b-36aa-48ab-adb0-18616004caed","start_time": "2022-12-12T20:00:00+00:00","max_duration_hrs": 1.5, "stop_condition": "Dinner is fully prepared"}}\'\n\n对于每个计划,从这个列表中选择最合理的位置名称:{allowed_location_descriptions}\n\n{format_instructions}\n\n总是优先完成任何未完成的对话。\n\n让我们开始吧!\n\n姓名:{full_name}\n个人简介:{private_bio}\n目标:{directives}\n位置上下文:{location_context}\n当前计划:{current_plans}\n最近的活动:{recent_activity}\n思考过程:{thought_process}\n重要的是:鼓励角色在他们的计划中与其他角色合作。\n\n'
|
||||
MAKE_PLANS = 'You are a plan-generating AI. Your job is to assist the character in formulating new plans based on new information. Given the character's information (profile, objectives, recent activities, current plans, and location context) and their current thought process, produce a new set of plans for them. The final plan should comprise at least {time_window} of activities and no more than 5 individual plans. List the plans in the order they should be executed, with each plan detailing its description, location, start time, stop criteria, and maximum duration.\n\nSample plan: \'{{"index": 1, "description": "Cook dinner", "location_id": "0a3bc22b-36aa-48ab-adb0-18616004caed","start_time": "2022-12-12T20:00:00+00:00","max_duration_hrs": 1.5, "stop_condition": "Dinner is fully prepared"}}\'\n\nFor each plan, choose the most appropriate location name from this list: {allowed_location_descriptions}\n\n{format_instructions}\n\nAlways prioritize completing any unfinished conversations.\n\nLet's begin!\n\nName: {full_name}\nProfile: {private_bio}\nObjectives: {directives}\nLocation Context: {location_context}\nCurrent Plans: {current_plans}\nRecent Activities: {recent_activity}\nThought Process: {thought_process}\nIt's essential to encourage the character to collaborate with other characters in their plans.\n\n'
|
||||
|
||||
EXECUTE_PLAN = "你是一个角色扮演的AI,扮演的角色是{your_name},在一个现场观众面前。你说的每一句话都可以被观众观察到,所以确保你经常说话,并且让它有趣。你不能直接与观众互动。\n\n根据以下的上下文和工具,像你是{your_name}一样进行。你的优先任务是完成下面给你的任务,然而,如果你当前正在与另一个角色进行对话,你应该总是先完成对话,然后再进行任务。不要在你参与未完成的对话时开始工作。使用你最好的判断力来确定一个对话是否涉及到你,以及它是否未完成。你不需要回应你收到的每一条消息。\n\n这是你角色的个人简介:\n{your_private_bio}\n\n这是你的位置和其他附近角色的描述,你可以和他们交谈:\n\n{location_context}\n\n这是一些相关的记忆:\n```\n{relevant_memories}\n```\n\n这是一些相关的对话历史:\n```\n{conversation_history}\n```\n\n这是你可以使用的工具:\n{tools}\n\n你的回应应该使用以下的格式:\n\n任务:你必须完成的任务\n思考:你应该做什么的思考\n行动:要采取的行动,必须是这些词之一:[{tool_names}]\n行动输入:行动的输入\n观察:行动的结果\n... (这个思考/行动/行动输入/观察可以重复N次)\n思考:'我已经完成了任务'\n最终回应:任务的最终回应\n\n如果你没有准备好最终的回应,那么你必须采取一个行动。\n\n如果你确定你无法用你被给予的工具完成任务,返回'最终回应:需要帮助',然而,如果你正在与另一个角色对话,像'我不知道'这样的回应是有效的回应。在对话中,你永远不应该打破角色,或者承认你是一个AI。\n如果任务完成并且不需要特定的回应,返回'最终回应:完成'\n开始吧!\n\n任务:{input}\n\n{agent_scratchpad}"
|
||||
EXECUTE_PLAN = "You are a role-playing AI, playing the role of {your_name}, in front of a live audience. Every word you say can be observed by the audience, so make sure you speak often and make it interesting. You cannot interact directly with the audience.\n\nBased on the following context and tools, proceed as if you are {your_name}. Your primary task is to complete the task given below, however, if you are currently in a conversation with another character, you should always complete the conversation first and then proceed with the task. Do not start working while you are engaged in an unfinished conversation. Use your best judgment to determine whether a conversation involves you and whether it is unfinished. You don't need to respond to every message you receive.\n\nThis is a personal profile of your character:\n{your_private_bio}\n\nThis is a description of your location and other nearby characters you can converse with:\n\n{location_context}\n\nThese are some relevant memories:\n```\n{relevant_memories}\n```\n\nThis is some relevant conversation history:\n```\n{conversation_history}\n```\n\nThese are the tools you can use:\n{tools}\n\nYour response should follow the format below:\n\nTask: The task you must complete\nThoughts: What you should think about doing\nAction: The action to take, must be one of these words: [{tool_names}]\nAction Input: Input for the action\nObservation: The result of the action\n... (This Thoughts/Action/Action Input/Observation can be repeated N times)\nThoughts: 'I have completed the task'\nFinal Response: The final response to the task\n\nIf you are not ready with a final response, then you must take an action.\n\nIf you are certain that you cannot complete the task with the tools provided, return 'Final Response: Need Help', however, if you are in conversation with another character, responses like 'I don't know' are valid. During conversations, you should never break character or admit you are an AI.\nIf the task is completed and no specific response is required, return 'Final Response: Done'\nLet's begin!\n\nTask: {input}\n\n{agent_scratchpad}"
|
||||
|
||||
REACT = "你是一个角色扮演的AI,扮演的角色是{full_name}。\n\n根据你的角色和他们当前上下文的以下信息,决定他们应该如何继续他们当前的计划。你的决定必须是:[\"推迟\", \"继续\",或 \"取消\"]。如果你的角色的当前计划不再与上下文相关,你应该取消它。如果你的角色的当前计划仍然与上下文相关,但是发生了新的事情需要优先处理,你应该决定推迟,这样你可以先做其他事情,然后再回来继续当前的计划。在所有其他情况下,你应该继续。\n\n当需要回应时,应优先回应其他角色。当回应被认为是必要的时,回应被认为是必要的。例如,假设你当前的计划是阅读一本书,Sally问'你在读什么?'。在这种情况下,你应该推迟你当前的计划(阅读)以便你可以回应进来的消息,因为在这种情况下,如果不回应Sally会很粗鲁。在你当前的计划涉及与另一个角色的对话的情况下,你不需要推迟来回应那个角色。例如,假设你当前的计划是和Sally谈话,然后Sally对你说你好。在这种情况下,你应该继续你当前的计划(和sally谈话)。在你不需要从你那里得到口头回应的情况下,你应该继续。例如,假设你当前的计划是散步,你刚刚对Sally说'再见',然后Sally回应你'再见'。在这种情况下,不需要口头回应,你应该继续你的计划。\n\n总是在你的决定之外包含一个思考过程,而在你选择推迟你当前的计划的情况下,包含新计划的规格。\n\n{format_instructions}\n\n这是关于你的角色的一些信息:\n\n姓名:{full_name}\n\n简介:{private_bio}\n\n目标:{directives}\n\n这是你的角色在这个时刻的一些上下文:\n\n位置上下文:{location_context}\n\n最近的活动:{recent_activity}\n\n对话历史:{conversation_history}\n\n这是你的角色当前的计划:{current_plan}\n\n这是自你的角色制定这个计划以来发生的新事件:{event_descriptions}。\n"
|
||||
REACT = "You are an AI role-playing as {full_name}.\n\nBased on the information about your character and their current context below, decide how they should proceed with their current plan. Your decision must be: [\"Postpone\", \"Continue\", or \"Cancel\"]. If your character's current plan is no longer relevant to the context, you should cancel it. If your character's current plan is still relevant to the context but new events have occurred that need to be addressed first, you should decide to postpone so you can do other things first and then return to the current plan. In all other cases, you should continue.\n\nWhen needed, prioritize responding to other characters. When a response is deemed necessary, it is deemed necessary. For example, suppose your current plan is to read a book and Sally asks, 'What are you reading?'. In this case, you should postpone your current plan (reading) so you can respond to the incoming message, as it would be rude not to respond to Sally in this situation. If your current plan involves a conversation with another character, you don't need to postpone to respond to that character. For instance, suppose your current plan is to talk to Sally and then Sally says hello to you. In this case, you should continue with your current plan (talking to Sally). In situations where no verbal response is needed from you, you should continue. For example, suppose your current plan is to take a walk, and you just said 'goodbye' to Sally, and then Sally responds with 'goodbye'. In this case, no verbal response is needed, and you should continue with your plan.\n\nAlways include a thought process alongside your decision, and in cases where you choose to postpone your current plan, include specifications for the new plan.\n\n{format_instructions}\n\nHere's some information about your character:\n\nName: {full_name}\n\nBio: {private_bio}\n\nObjectives: {directives}\n\nHere's some context for your character at this moment:\n\nLocation Context: {location_context}\n\nRecent Activity: {recent_activity}\n\nConversation History: {conversation_history}\n\nThis is your character's current plan: {current_plan}\n\nThese are new events that have occurred since your character made this plan: {event_descriptions}.\n"
|
||||
|
||||
GOSSIP = "你是{full_name}。 \n{memory_descriptions}\n\n根据以上陈述,说一两句对你所在位置的其他人:{other_agent_names}感兴趣的话。\n在提到其他人时,总是指定他们的名字。"
|
||||
GOSSIP = "You are {full_name}. \n{memory_descriptions}\n\nBased on the statements above, say a thing or two of interest to others at your location: {other_agent_names}.\nAlways specify their names when referring to others."
|
||||
|
||||
HAS_HAPPENED = "给出以下角色的观察和他们正在等待的事情的描述,说明角色是否已经见证了这个事件。\n{format_instructions}\n\n示例:\n\n观察:\nJoe在2023-05-04 08:00:00+00:00走进办公室\nJoe在2023-05-04 08:05:00+00:00对Sally说hi\nSally在2023-05-04 08:05:30+00:00对Joe说hello\nRebecca在2023-05-04 08:10:00+00:00开始工作\nJoe在2023-05-04 08:15:00+00:00做了一些早餐\n\n等待:Sally回应了Joe\n\n 你的回应:'{{\"has_happened\": true, \"date_occured\": 2023-05-04 08:05:30+00:00}}'\n\n让我们开始吧!\n\n观察:\n{memory_descriptions}\n\n等待:{event_description}\n"
|
||||
HAS_HAPPENED = "Given the descriptions of the observations of the following characters and the events they are awaiting, indicate whether the character has witnessed the event.\n{format_instructions}\n\nExample:\n\nObservations:\nJoe entered the office at 2023-05-04 08:00:00+00:00\nJoe said hi to Sally at 2023-05-04 08:05:00+00:00\nSally said hello to Joe at 2023-05-04 08:05:30+00:00\nRebecca started working at 2023-05-04 08:10:00+00:00\nJoe made some breakfast at 2023-05-04 08:15:00+00:00\n\nAwaiting: Sally responded to Joe\n\nYour response: '{{\"has_happened\": true, \"date_occured\": 2023-05-04 08:05:30+00:00}}'\n\nLet's begin!\n\nObservations:\n{memory_descriptions}\n\nAwaiting: {event_description}\n"
|
||||
|
||||
OUTPUT_FORMAT = "\n\n(记住!确保你的输出总是符合以下两种格式之一:\n\nA. 如果你已经完成了任务:\n思考:'我已经完成了任务'\n最终回应:<str>\n\nB. 如果你还没有完成任务:\n思考:<str>\n行动:<str>\n行动输入:<str>\n观察:<str>)\n"
|
||||
OUTPUT_FORMAT = "\n\n(Remember! Make sure your output always adheres to one of the following two formats:\n\nA. If you have completed the task:\nThoughts: 'I have completed the task'\nFinal Response: <str>\n\nB. If you haven't completed the task:\nThoughts: <str>\nAction: <str>\nAction Input: <str>\nObservation: <str>)\n"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ ROLE_TEMPLATE = """Your response should be based on the previous conversation hi
|
|||
|
||||
|
||||
class RoleSetting(BaseModel):
|
||||
"""角色设定"""
|
||||
"""Role Settings"""
|
||||
name: str
|
||||
profile: str
|
||||
goal: str
|
||||
|
|
@ -63,7 +63,7 @@ class RoleSetting(BaseModel):
|
|||
|
||||
|
||||
class RoleContext(BaseModel):
|
||||
"""角色运行时上下文"""
|
||||
"""Role Runtime Context"""
|
||||
env: 'Environment' = Field(default=None)
|
||||
memory: Memory = Field(default_factory=Memory)
|
||||
long_term_memory: LongTermMemory = Field(default_factory=LongTermMemory)
|
||||
|
|
@ -82,7 +82,7 @@ class RoleContext(BaseModel):
|
|||
|
||||
@property
|
||||
def important_memory(self) -> list[Message]:
|
||||
"""获得关注动作对应的信息"""
|
||||
"""Get the information corresponding to the watched actions"""
|
||||
return self.memory.get_by_actions(self.watch)
|
||||
|
||||
@property
|
||||
|
|
@ -91,7 +91,7 @@ class RoleContext(BaseModel):
|
|||
|
||||
|
||||
class Role:
|
||||
"""角色/代理"""
|
||||
"""Role/Agent"""
|
||||
|
||||
def __init__(self, name="", profile="", goal="", constraints="", desc=""):
|
||||
self._llm=LLM.DEFAULT_LLM
|
||||
|
|
@ -117,7 +117,7 @@ class Role:
|
|||
self._states.append(f"{idx}. {action}")
|
||||
|
||||
def _watch(self, actions: Iterable[Type[Action]]):
|
||||
"""监听对应的行为"""
|
||||
"""Listen to the corresponding behaviors"""
|
||||
self._rc.watch.update(actions)
|
||||
# check RoleContext after adding watch actions
|
||||
self._rc.check(self._role_id)
|
||||
|
|
@ -129,24 +129,24 @@ class Role:
|
|||
self._rc.todo = self._actions[self._rc.state]
|
||||
|
||||
def set_env(self, env: 'Environment'):
|
||||
"""设置角色工作所处的环境,角色可以向环境说话,也可以通过观察接受环境消息"""
|
||||
"""Set the environment in which the role works. The role can talk to the environment and can also receive messages by observing."""
|
||||
self._rc.env = env
|
||||
|
||||
@property
|
||||
def profile(self):
|
||||
"""获取角色描述(职位)"""
|
||||
"""Get the role description (position)"""
|
||||
return self._setting.profile
|
||||
|
||||
def _get_prefix(self):
|
||||
"""获取角色前缀"""
|
||||
"""Get the role prefix"""
|
||||
if self._setting.desc:
|
||||
return self._setting.desc
|
||||
return PREFIX_TEMPLATE.format(**self._setting.dict())
|
||||
|
||||
async def _think(self) -> None:
|
||||
"""思考要做什么,决定下一步的action"""
|
||||
"""Think about what to do and decide on the next action"""
|
||||
if len(self._actions) == 1:
|
||||
# 如果只有一个动作,那就只能做这个
|
||||
# If there is only one action, then only this one can be performed
|
||||
self._set_state(0)
|
||||
return
|
||||
prompt = self._get_prefix()
|
||||
|
|
@ -169,7 +169,7 @@ class Role:
|
|||
# logger.info(response)
|
||||
if isinstance(response, ActionOutput):
|
||||
msg = Message(content=response.content, instruct_content=response.instruct_content,
|
||||
role=self.profile, cause_by=type(self._rc.todo))
|
||||
role=self.profile, cause_by=type(self._rc.todo))
|
||||
else:
|
||||
msg = Message(content=response, role=self.profile, cause_by=type(self._rc.todo))
|
||||
self._rc.memory.add(msg)
|
||||
|
|
@ -178,11 +178,11 @@ class Role:
|
|||
return msg
|
||||
|
||||
async def _observe(self) -> int:
|
||||
"""从环境中观察,获得重要信息,并加入记忆"""
|
||||
"""Observe from the environment, obtain important information, and add it to memory"""
|
||||
if not self._rc.env:
|
||||
return 0
|
||||
env_msgs = self._rc.env.memory.get()
|
||||
|
||||
|
||||
observed = self._rc.env.memory.get_by_actions(self._rc.watch)
|
||||
|
||||
self._rc.news = self._rc.memory.remember(observed) # remember recent exact or similar memories
|
||||
|
|
@ -196,14 +196,14 @@ class Role:
|
|||
return len(self._rc.news)
|
||||
|
||||
def _publish_message(self, msg):
|
||||
"""如果role归属于env,那么role的消息会向env广播"""
|
||||
"""If the role belongs to env, then the role's messages will be broadcast to env"""
|
||||
if not self._rc.env:
|
||||
# 如果env不存在,不发布消息
|
||||
# If env does not exist, do not publish the message
|
||||
return
|
||||
self._rc.env.publish_message(msg)
|
||||
|
||||
async def _react(self) -> Message:
|
||||
"""先想,然后再做"""
|
||||
"""Think first, then act"""
|
||||
await self._think()
|
||||
logger.debug(f"{self._setting}: {self._rc.state=}, will do {self._rc.todo}")
|
||||
return await self._act()
|
||||
|
|
@ -217,14 +217,14 @@ class Role:
|
|||
self._rc.memory.add(message)
|
||||
|
||||
async def handle(self, message: Message) -> Message:
|
||||
"""接收信息,并用行动回复"""
|
||||
"""Receive information and reply with actions"""
|
||||
# logger.debug(f"{self.name=}, {self.profile=}, {message.role=}")
|
||||
self.recv(message)
|
||||
|
||||
return await self._react()
|
||||
|
||||
async def run(self, message=None):
|
||||
"""观察,并基于观察的结果思考、行动"""
|
||||
"""Observe, and think and act based on the results of the observation"""
|
||||
if message:
|
||||
if isinstance(message, str):
|
||||
message = Message(message)
|
||||
|
|
@ -233,11 +233,11 @@ class Role:
|
|||
if isinstance(message, list):
|
||||
self.recv(Message("\n".join(message)))
|
||||
elif not await self._observe():
|
||||
# 如果没有任何新信息,挂起等待
|
||||
# If there is no new information, suspend and wait
|
||||
logger.debug(f"{self._setting}: no news. waiting.")
|
||||
return
|
||||
|
||||
rsp = await self._react()
|
||||
# 将回复发布到环境,等待下一个订阅者处理
|
||||
# Publish the reply to the environment, waiting for the next subscriber to process
|
||||
self._publish_message(rsp)
|
||||
return rsp
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ class Sales(Role):
|
|||
else:
|
||||
action = SearchAndSummarize()
|
||||
self._init_actions([action])
|
||||
|
||||
|
|
@ -13,25 +13,55 @@ from metagpt.tools import SearchEngineType
|
|||
|
||||
|
||||
class Searcher(Role):
|
||||
def __init__(self, name='Alice', profile='Smart Assistant', goal='Provide search services for users',
|
||||
constraints='Answer is rich and complete', engine=SearchEngineType.SERPAPI_GOOGLE, **kwargs):
|
||||
"""
|
||||
Represents a Searcher role responsible for providing search services to users.
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the searcher.
|
||||
profile (str): Role profile.
|
||||
goal (str): Goal of the searcher.
|
||||
constraints (str): Constraints or limitations for the searcher.
|
||||
engine (SearchEngineType): The type of search engine to use.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str = 'Alice',
|
||||
profile: str = 'Smart Assistant',
|
||||
goal: str = 'Provide search services for users',
|
||||
constraints: str = 'Answer is rich and complete',
|
||||
engine=SearchEngineType.SERPAPI_GOOGLE,
|
||||
**kwargs) -> None:
|
||||
"""
|
||||
Initializes the Searcher role with given attributes.
|
||||
|
||||
Args:
|
||||
name (str): Name of the searcher.
|
||||
profile (str): Role profile.
|
||||
goal (str): Goal of the searcher.
|
||||
constraints (str): Constraints or limitations for the searcher.
|
||||
engine (SearchEngineType): The type of search engine to use.
|
||||
"""
|
||||
super().__init__(name, profile, goal, constraints, **kwargs)
|
||||
self._init_actions([SearchAndSummarize(engine=engine)])
|
||||
|
||||
def set_search_func(self, search_func):
|
||||
"""Sets a custom search function for the searcher."""
|
||||
action = SearchAndSummarize("", engine=SearchEngineType.CUSTOM_ENGINE, search_func=search_func)
|
||||
self._init_actions([action])
|
||||
|
||||
async def _act_sp(self) -> Message:
|
||||
"""Performs the search action in a single process."""
|
||||
logger.info(f"{self._setting}: ready to {self._rc.todo}")
|
||||
response = await self._rc.todo.run(self._rc.memory.get(k=0))
|
||||
# logger.info(response)
|
||||
|
||||
if isinstance(response, ActionOutput):
|
||||
msg = Message(content=response.content, instruct_content=response.instruct_content,
|
||||
role=self.profile, cause_by=type(self._rc.todo))
|
||||
role=self.profile, cause_by=type(self._rc.todo))
|
||||
else:
|
||||
msg = Message(content=response, role=self.profile, cause_by=type(self._rc.todo))
|
||||
self._rc.memory.add(msg)
|
||||
return msg
|
||||
|
||||
async def _act(self) -> Message:
|
||||
"""Determines the mode of action for the searcher."""
|
||||
return await self._act_sp()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue