diff --git a/src/blog/werewolf/index.md b/src/blog/werewolf/index.md index 598395cb..949b2653 100644 --- a/src/blog/werewolf/index.md +++ b/src/blog/werewolf/index.md @@ -97,7 +97,7 @@ One of the essential elements of implementing the Werewolf game lies in facilita 2. A private message from a werewolf, signaling the werewolf partner and the Moderator about a chosen kill (one-to-multiple). 3. A public message from the Moderator instructing all players to awaken (one-to-all). -MetaGPT supports all three communication thanks to the key abstractions `Environment` and `Message`, as well as the agent's (`Role`'s) method of message handling via the `\_publish` and `\_observe` functions. Every time an agent sends a `Message`, it `\_publish` the `Message` to the `Environment`. In turn, receiving agents `\_observe` the `Message` from the `Environment`. All we need to do is to populate the `Message` attributes, such as `send_to` and `restricted_to`, with the intended recipients. MetaGPT handles everything else. +MetaGPT supports all three communication thanks to the key abstractions `Environment` and `Message`, as well as the agent's (`Role`'s) method of message handling via the `\publish_message` and `\_observe` functions. Every time an agent sends a `Message`, it `\publish_message` the `Message` to the `Environment`. In turn, receiving agents `\_observe` the `Message` from the `Environment`. All we need to do is to populate the `Message` attributes, such as `send_to` and `restricted_to`, with the intended recipients. MetaGPT handles everything else. All combined, we vitalize a sophisticated communication topology between agents. For detailed implementation, please feel free to check our code. We are actively working on refining this mechanism and will release a comprehensive guide soon. diff --git a/src/guide/get_started/quickstart.md b/src/guide/get_started/quickstart.md index 0fea5feb..f488d2e5 100644 --- a/src/guide/get_started/quickstart.md +++ b/src/guide/get_started/quickstart.md @@ -49,7 +49,7 @@ async def startup(idea: str): ] ) company.invest(investment=3.0) - company.start_project(idea=idea) + company.run_project(idea=idea) await company.run(n_round=5) ``` diff --git a/src/guide/tutorials/agent_101.md b/src/guide/tutorials/agent_101.md index 47c6a208..04a5e3a1 100644 --- a/src/guide/tutorials/agent_101.md +++ b/src/guide/tutorials/agent_101.md @@ -107,7 +107,7 @@ class SimpleCoder(Role): msg = self.get_memories(k=1)[0] # find the most recent k messages code_text = await todo.run(msg.content) - msg = Message(content=code_text, role=self.profile, cause_by=type(todo)) + msg = Message(content=code_text, role=self.profile, cause_by=todo) return msg ``` @@ -184,7 +184,7 @@ class RunnableCoder(Role): msg = self.get_memories(k=1)[0] # find the most k recent messages result = await todo.run(msg.content) - msg = Message(content=result, role=self.profile, cause_by=type(todo)) + msg = Message(content=result, role=self.profile, cause_by=todo) self._rc.memory.add(msg) return msg ``` diff --git a/src/guide/tutorials/multi_agent_101.md b/src/guide/tutorials/multi_agent_101.md index 7e789f56..af94e253 100644 --- a/src/guide/tutorials/multi_agent_101.md +++ b/src/guide/tutorials/multi_agent_101.md @@ -32,6 +32,8 @@ By giving the outline above, we actually make our SOP clear. We will talk about We list the three `Action`s. ```python +from metagpt.actions import Action + class SimpleWriteCode(Action): PROMPT_TEMPLATE = """ @@ -44,13 +46,9 @@ class SimpleWriteCode(Action): super().__init__(name, context, llm) async def run(self, instruction: str): - prompt = self.PROMPT_TEMPLATE.format(instruction=instruction) - rsp = await self._aask(prompt) - code_text = parse_code(rsp) - return code_text ``` @@ -68,13 +66,9 @@ class SimpleWriteTest(Action): super().__init__(name, context, llm) async def run(self, context: str, k: int = 3): - prompt = self.PROMPT_TEMPLATE.format(context=context, k=k) - rsp = await self._aask(prompt) - code_text = parse_code(rsp) - return code_text ``` ```python @@ -89,17 +83,14 @@ class SimpleWriteReview(Action): super().__init__(name, context, llm) async def run(self, context: str): - prompt = self.PROMPT_TEMPLATE.format(context=context) - rsp = await self._aask(prompt) - return rsp ``` #### Define Role In many multi-agent scenarios, defining a `Role` can be as simple as 10 lines of codes. For `SimpleCoder`, we do two things: 1. Equip the `Role` with the appropriate `Action`s with `_init_actions`, this is identical to setting up a single agent -2. A multi-agent operation: we make the `Role` `_watch` important upstream messages from users or other agents. Recall our SOP, `SimpleCoder` takes user instruction, which is a `Message` caused by `BossRequirement` in MetaGPT. Therefore, we add `self._watch([BossRequirement])`. +2. A multi-agent operation: we make the `Role` `_watch` important upstream messages from users or other agents. Recall our SOP, `SimpleCoder` takes user instruction, which is a `Message` caused by `UserRequirement` in MetaGPT. Therefore, we add `self._watch([UserRequirement])`. That's all users have to do. For those who are interested in the mechanism under the hood, see [Mechanism Explained](#mechanism-explained) of this chapter. @@ -112,7 +103,7 @@ class SimpleCoder(Role): **kwargs, ): super().__init__(name, profile, **kwargs) - self._watch([BossRequirement]) + self._watch([UserRequirement]) self._init_actions([SimpleWriteCode]) ``` @@ -148,7 +139,7 @@ class SimpleTester(Role): code_text = await todo.run(context, k=5) # specify arguments - msg = Message(content=code_text, role=self.profile, cause_by=type(todo)) + msg = Message(content=code_text, role=self.profile, cause_by=todo) return msg ``` @@ -172,10 +163,17 @@ Now that we have defined our three `Role`s, it's time to put them together. We i Run the `Team`, we should see the collaboration between them! ```python -async def main( - idea: str = "write a function that calculates the product of a list", - investment: float = 3.0, - n_round: int = 5, +import asyncio +import typer +from metagpt.logs import logger +from metagpt.team import Team +app = typer.Typer() + +@app.command() +def main( + idea: str = typer.Argument(..., help="write a function that calculates the product of a list"), + investment: float = typer.Option(default=3.0, help="Dollar amount to invest in the AI company."), + n_round: int = typer.Option(default=5, help="Number of rounds for the simulation."), ): logger.info(idea) @@ -189,11 +187,11 @@ async def main( ) team.invest(investment=investment) - team.start_project(idea) - await team.run(n_round=n_round) + team.run_project(idea) + asyncio.run(team.run(n_round=n_round)) if __name__ == '__main__': - fire.Fire(main) + app() ``` ## Complete script of this tutorial @@ -213,10 +211,10 @@ While users can write a few lines of code to set up a running `Role`, it's benef ![img](/image/guide/tutorials/multi_agents_flowchart.png) -Internally, as shown in the right part of the diagram, the `Role` will `_observe` `Message` from the `Environment`. If there is a `Message` caused by the particular `Action`s the `Role` `_watch`, then it is a valid observation, triggering the `Role`'s subsequent thoughts and actions. In `_think`, the `Role` will choose one of its capable `Action`s and set it as todo. During `_act`, `Role` executes the todo, i.e., runs the `Action` and obtains the output. The output is encapsulated in a `Message` to be finally `_publish` to the `Environment`, finishing a complete agent run. +Internally, as shown in the right part of the diagram, the `Role` will `_observe` `Message` from the `Environment`. If there is a `Message` caused by the particular `Action`s the `Role` `_watch`, then it is a valid observation, triggering the `Role`'s subsequent thoughts and actions. In `_think`, the `Role` will choose one of its capable `Action`s and set it as todo. During `_act`, `Role` executes the todo, i.e., runs the `Action` and obtains the output. The output is encapsulated in a `Message` to be finally `publish_message` to the `Environment`, finishing a complete agent run. In each step, either `_observe`, `_think`, or `_act`, the `Role` will interact with its `Memory`, through adding or retrieval. Moreover, MetaGPT provides different modes of the `react` process. For these parts, please see [Use Memories](use_memories) and [Think and act](agent_think_act) When each `Role` is set up appropriately, we may see the corresponding SOP to the example earlier in this tutorial, demonstrated by the left half of the diagram. The dotted box suggests the SOP can be extended if we make `SimpleTester` `_watch` both `SimpleWriteCode` and `SimpleWriteReview`. -We encourage developers with interest to see the [code](https://github.com/geekan/MetaGPT/blob/main/metagpt/roles/role.py) of `Role`, as we believe it is quite readable. Checking out `run`, `_observe`, `react`, `_think`, `_act`, `_publish` should provide one with a decent understanding. +We encourage developers with interest to see the [code](https://github.com/geekan/MetaGPT/blob/main/metagpt/roles/role.py) of `Role`, as we believe it is quite readable. Checking out `run`, `_observe`, `react`, `_think`, `_act`, `publish_message` should provide one with a decent understanding. diff --git a/src/guide/tutorials/use_memories.md b/src/guide/tutorials/use_memories.md index 8788bc67..7de37307 100644 --- a/src/guide/tutorials/use_memories.md +++ b/src/guide/tutorials/use_memories.md @@ -28,7 +28,7 @@ async def _act(self) -> Message: code_text = await todo.run(context, k=5) # specify arguments - msg = Message(content=code_text, role=self.profile, cause_by=type(todo)) + msg = Message(content=code_text, role=self.profile, cause_by=todo) return msg ``` diff --git a/src/guide/use_cases/agent/researcher.md b/src/guide/use_cases/agent/researcher.md index 6884bca4..4b8df71b 100644 --- a/src/guide/use_cases/agent/researcher.md +++ b/src/guide/use_cases/agent/researcher.md @@ -246,14 +246,14 @@ class Researcher(Role): # Search the internet and retrieve URL information if isinstance(todo, CollectLinks): links = await todo.run(topic, 4, 4) - ret = Message("", Report(topic=topic, links=links), role=self.profile, cause_by=type(todo)) + ret = Message("", Report(topic=topic, links=links), role=self.profile, cause_by=todo) # Browse web pages and summarize their content elif isinstance(todo, WebBrowseAndSummarize): links = instruct_content.links todos = (todo.run(*url, query=query, system_text=research_system_text) for (query, url) in links.items()) summaries = await asyncio.gather(*todos) summaries = list((url, summary) for i in summaries for (url, summary) in i.items() if summary) - ret = Message("", Report(topic=topic, summaries=summaries), role=self.profile, cause_by=type(todo)) + ret = Message("", Report(topic=topic, summaries=summaries), role=self.profile, cause_by=todo) # Generate a research report else: summaries = instruct_content.summaries diff --git a/src/guide/use_cases/multi_agent/debate.md b/src/guide/use_cases/multi_agent/debate.md index 73c292f8..9659a853 100644 --- a/src/guide/use_cases/multi_agent/debate.md +++ b/src/guide/use_cases/multi_agent/debate.md @@ -42,7 +42,7 @@ class SpeakAloud(Action): ### Define Role We will define a common `Role` called `Debator`. -Here `_init_actions` make our `Role` possess the `SpeakAloud` action we just define. We also `_watch` both `SpeakAloud` and `BossRequirement`, because we want each debator to pay attention to messages of `SpeakAloud` from his opponent, as well as `BossRequirement` (human instruction) from users. +Here `_init_actions` make our `Role` possess the `SpeakAloud` action we just define. We also `_watch` both `SpeakAloud` and `UserRequirement`, because we want each debator to pay attention to messages of `SpeakAloud` from his opponent, as well as `UserRequirement` (human instruction) from users. ```python class Debator(Role): def __init__( @@ -54,7 +54,7 @@ class Debator(Role): ): super().__init__(name, profile, **kwargs) self._init_actions([SpeakAloud]) - self._watch([BossRequirement, SpeakAloud]) + self._watch([UserRequirement, SpeakAloud]) self.name = name self.opponent_name = opponent_name ``` @@ -81,7 +81,7 @@ async def _act(self) -> Message: msg = Message( content=rsp, role=self.profile, - cause_by=type(todo), + cause_by=todo, sent_from=self.name, send_to=self.opponent_name, ) @@ -102,7 +102,7 @@ class Debator(Role): ): super().__init__(name, profile, **kwargs) self._init_actions([SpeakAloud]) - self._watch([BossRequirement, SpeakAloud]) + self._watch([UserRequirement, SpeakAloud]) self.name = name self.opponent_name = opponent_name @@ -124,7 +124,7 @@ class Debator(Role): msg = Message( content=rsp, role=self.profile, - cause_by=type(todo), + cause_by=todo, sent_from=self.name, send_to=self.opponent_name, ) @@ -134,7 +134,7 @@ class Debator(Role): return msg ``` ### Create a team and add roles -Now that we have defined our `Debator`s, let's put them together to see what will come up. We set up a `Team` and "hire" Biden and Trump. In this example, we will send our instruction (as a `BossRequirement` under the hood) to Biden to have him start first. If you want Trump to speak first, set send_to as "Trump". +Now that we have defined our `Debator`s, let's put them together to see what will come up. We set up a `Team` and "hire" Biden and Trump. In this example, we will send our instruction (as a `UserRequirement` under the hood) to Biden to have him start first. If you want Trump to speak first, set send_to as "Trump". Run the `Team`, we should see the friendly conversation between them! ```python @@ -145,10 +145,21 @@ async def debate(idea: str, investment: float = 3.0, n_round: int = 5): team = Team() team.hire([Biden, Trump]) team.invest(investment) - team.start_project(idea, send_to="Biden") # send debate topic to Biden and let him speak first + team.run_project(idea, send_to="Biden") # send debate topic to Biden and let him speak first await team.run(n_round=n_round) -def main(idea: str, investment: float = 3.0, n_round: int = 10): +import asyncio +import platform +import typer +from metagpt.team import Team +app = typer.Typer() + +@app.command() +def main( + idea: str = typer.Argument(..., help="Economic Policy: Discuss strategies and plans related to taxation, employment, fiscal budgeting, and economic growth."), + investment: float = typer.Option(default=3.0, help="Dollar amount to invest in the AI company."), + n_round: int = typer.Option(default=5, help="Number of rounds for the simulation."), +): """ :param idea: Debate topic, such as "Topic: The U.S. should commit more in climate change fighting" or "Trump: Climate change is a hoax" @@ -161,7 +172,7 @@ def main(idea: str, investment: float = 3.0, n_round: int = 10): asyncio.run(debate(idea, investment, n_round)) if __name__ == '__main__': - fire.Fire(main) + app() ``` ## Complete script of this section diff --git "a/src/rfcs/RFC-116-MetaGPT\344\274\230\345\214\226\346\226\271\346\241\210.md" "b/src/rfcs/RFC-116-MetaGPT\344\274\230\345\214\226\346\226\271\346\241\210.md" index 2a6b6210..904a4a98 100644 --- "a/src/rfcs/RFC-116-MetaGPT\344\274\230\345\214\226\346\226\271\346\241\210.md" +++ "b/src/rfcs/RFC-116-MetaGPT\344\274\230\345\214\226\346\226\271\346\241\210.md" @@ -102,7 +102,7 @@ await super()._observe() # accept the very first human instruction (the debate topic) or messages sent (from opponent) to self, # disregard own messages from the last round - self._rc.news = [msg for msg in self._rc.news if msg.cause_by == BossRequirement or msg.send_to == self.name] + self._rc.news = [msg for msg in self._rc.news if msg.cause_by == UserRequirement or msg.send_to == self.name] return len(self._rc.news) ``` 5. `sent_from`被用作展示时显示的发言者信息。本质是meta信息的一部分。 diff --git a/src/zhcn/guide/get_started/quickstart.md b/src/zhcn/guide/get_started/quickstart.md index 7b60640d..bb869015 100644 --- a/src/zhcn/guide/get_started/quickstart.md +++ b/src/zhcn/guide/get_started/quickstart.md @@ -47,7 +47,7 @@ async def startup(idea: str): ] ) company.invest(investment=3.0) - company.start_project(idea=idea) + company.run_project(idea=idea) await company.run(n_round=5) ``` diff --git a/src/zhcn/guide/tutorials/agent_101.md b/src/zhcn/guide/tutorials/agent_101.md index d6937c3a..27fb7e37 100644 --- a/src/zhcn/guide/tutorials/agent_101.md +++ b/src/zhcn/guide/tutorials/agent_101.md @@ -168,7 +168,7 @@ class RunnableCoder(Role): msg = self.get_memories(k=1)[0] # 得到最相似的 k 条消息 result = await todo.run(msg.content) - msg = Message(content=result, role=self.profile, cause_by=type(todo)) + msg = Message(content=result, role=self.profile, cause_by=todo) self._rc.memory.add(msg) return msg ``` diff --git a/src/zhcn/guide/tutorials/multi_agent_101.md b/src/zhcn/guide/tutorials/multi_agent_101.md index 0b8b4313..25ee867d 100644 --- a/src/zhcn/guide/tutorials/multi_agent_101.md +++ b/src/zhcn/guide/tutorials/multi_agent_101.md @@ -101,7 +101,7 @@ class SimpleWriteReview(Action): #### 定义角色 在许多多智能体场景中,定义`Role`可能只需几行代码。对于`SimpleCoder`,我们做了两件事: 1. 使用 `_init_actions` 为`Role`配备适当的 `Action`,这与设置单智能体相同 -2. 多智能体操作逻辑:我们使`Role` `_watch` 来自用户或其他智能体的重要上游消息。回想我们的SOP,`SimpleCoder`接收用户指令,这是由MetaGPT中的`BossRequirement`引起的`Message`。因此,我们添加了 `self._watch([BossRequirement])`。 +2. 多智能体操作逻辑:我们使`Role` `_watch` 来自用户或其他智能体的重要上游消息。回想我们的SOP,`SimpleCoder`接收用户指令,这是由MetaGPT中的`UserRequirement`引起的`Message`。因此,我们添加了 `self._watch([UserRequirement])`。 这就是用户需要做的全部。对于那些对底层机制感兴趣的人,请参见本教程的本章中的[机制解释](#机制解释)。 @@ -114,7 +114,7 @@ class SimpleCoder(Role): **kwargs, ): super().__init__(name, profile, **kwargs) - self._watch([BossRequirement]) + self._watch([UserRequirement]) self._ init_actions([SimpleWriteCode]) @@ -152,7 +152,7 @@ class SimpleTester(Role): code_text = await todo.run(context, k=5) # 指定参数 - msg = Message(content=code_text, role=self.profile, cause_by=type(todo)) + msg = Message(content=code_text, role=self.profile, cause_by=todo) return msg ``` @@ -176,10 +176,17 @@ class SimpleReviewer(Role): 运行 `Team`,我们应该会看到它们之间的协作! ```python -async def main( - idea: str = "write a function that calculates the product of a list", - investment: float = 3.0, - n_round: int = 5, +import asyncio +import typer +from metagpt.logs import logger +from metagpt.team import Team +app = typer.Typer() + +@app.command() +def main( + idea: str = typer.Argument(..., help="write a function that calculates the product of a list"), + investment: float = typer.Option(default=3.0, help="Dollar amount to invest in the AI company."), + n_round: int = typer.Option(default=5, help="Number of rounds for the simulation."), ): logger.info(idea) @@ -193,11 +200,11 @@ async def main( ) team.invest(investment=investment) - team.start_project(idea) + team.run_project(idea) await team.run(n_round=n_round) if __name__ == '__main__': - fire.Fire(main) + app() ``` ## 本教程的完整脚本 @@ -218,10 +225,10 @@ python3 examples/build_customized_multi_agents.py --idea "write a function that ![img](/image/guide/tutorials/multi_agents_flowchart.png) -如图的右侧部分所示,`Role`将从`Environment`中`_observe` `Message`。如果有一个`Role` `_watch` 的特定 `Action` 引起的 `Message`,那么这是一个有效的观察,触发`Role`的后续思考和操作。在 `_think` 中,`Role`将选择其能力范围内的一个 `Action` 并将其设置为要做的事情。在 `_act` 中,`Role`执行要做的事情,即运行 `Action` 并获取输出。将输出封装在 `Message` 中,最终 `_publish` 到 `Environment`,完成了一个完整的智能体运行。 +如图的右侧部分所示,`Role`将从`Environment`中`_observe` `Message`。如果有一个`Role` `_watch` 的特定 `Action` 引起的 `Message`,那么这是一个有效的观察,触发`Role`的后续思考和操作。在 `_think` 中,`Role`将选择其能力范围内的一个 `Action` 并将其设置为要做的事情。在 `_act` 中,`Role`执行要做的事情,即运行 `Action` 并获取输出。将输出封装在 `Message` 中,最终 `publish_message` 到 `Environment`,完成了一个完整的智能体运行。 在每个步骤中,无论是 `_observe`、`_think` 还是 `_act`,`Role`都将与其 `Memory` 交互,通过添加或检索来实现。此外,MetaGPT提供了 `react` 过程的不同模式。这些部分的详细内容,请参阅[使用记忆](use_memories) 和 [思考与行动](agent_think_act)。 当每个 `Role` 被适当设置时,我们可以看到与本教程中前面示例相应的SOP,如图的左侧部分所示。虚线框表明如果我们使 `SimpleTester` 同时 `_watch` `SimpleWriteCode` 和 `SimpleWriteReview`,则可以扩展 SOP。 -我们鼓励对此感兴趣的开发人员查看 `Role` 的[代码](https://github.com/geekan/MetaGPT/blob/main/metagpt/roles/role.py),因为它相当易读。可以 `run`、`_observe`、`react`、`_think`、`_act`、`_publish`的内容,应该能够让你对其有一个相当不错的理解。 +我们鼓励对此感兴趣的开发人员查看 `Role` 的[代码](https://github.com/geekan/MetaGPT/blob/main/metagpt/roles/role.py),因为它相当易读。可以 `run`、`_observe`、`react`、`_think`、`_act`、`publish_message`的内容,应该能够让你对其有一个相当不错的理解。 diff --git a/src/zhcn/guide/tutorials/use_memories.md b/src/zhcn/guide/tutorials/use_memories.md index 879cab74..ccced14c 100644 --- a/src/zhcn/guide/tutorials/use_memories.md +++ b/src/zhcn/guide/tutorials/use_memories.md @@ -28,7 +28,7 @@ async def _act(self) -> Message: code_text = await todo.run(context, k=5) # specify arguments - msg = Message(content=code_text, role=self.profile, cause_by=type(todo)) + msg = Message(content=code_text, role=self.profile, cause_by=todo) return msg ``` diff --git a/src/zhcn/guide/use_cases/agent/researcher.md b/src/zhcn/guide/use_cases/agent/researcher.md index 2c1fe0be..b94cedc6 100644 --- a/src/zhcn/guide/use_cases/agent/researcher.md +++ b/src/zhcn/guide/use_cases/agent/researcher.md @@ -242,14 +242,14 @@ class Researcher(Role): # 从搜索引擎进行搜索,并获取Url地址列表 if isinstance(todo, CollectLinks): links = await todo.run(topic, 4, 4) - ret = Message("", Report(topic=topic, links=links), role=self.profile, cause_by=type(todo)) + ret = Message("", Report(topic=topic, links=links), role=self.profile, cause_by=todo) # 浏览网页并总结网页内容 elif isinstance(todo, WebBrowseAndSummarize): links = instruct_content.links todos = (todo.run(*url, query=query, system_text=research_system_text) for (query, url) in links.items()) summaries = await asyncio.gather(*todos) summaries = list((url, summary) for i in summaries for (url, summary) in i.items() if summary) - ret = Message("", Report(topic=topic, summaries=summaries), role=self.profile, cause_by=type(todo)) + ret = Message("", Report(topic=topic, summaries=summaries), role=self.profile, cause_by=todo) # 生成调研报告 else: summaries = instruct_content.summaries diff --git a/src/zhcn/guide/use_cases/multi_agent/debate.md b/src/zhcn/guide/use_cases/multi_agent/debate.md index 83bda244..015ec340 100644 --- a/src/zhcn/guide/use_cases/multi_agent/debate.md +++ b/src/zhcn/guide/use_cases/multi_agent/debate.md @@ -42,7 +42,7 @@ class SpeakAloud(Action): ### 定义角色 我们将定义一个通用的 `Role`,称为 `Debator`。 -在这里,`_init_actions` 使我们的 `Role` 拥有我们刚刚定义的 `SpeakAloud` 动作。我们还使用 `_watch` 监视了 `SpeakAloud` 和 `BossRequirement`,因为我们希望每个辩手关注来自对手的 `SpeakAloud` 消息,以及来自用户的 `BossRequirement`(人类指令)。 +在这里,`_init_actions` 使我们的 `Role` 拥有我们刚刚定义的 `SpeakAloud` 动作。我们还使用 `_watch` 监视了 `SpeakAloud` 和 `UserRequirement`,因为我们希望每个辩手关注来自对手的 `SpeakAloud` 消息,以及来自用户的 `UserRequirement`(人类指令)。 ```python class Debator(Role): def __init__( @@ -54,7 +54,7 @@ class Debator(Role): ): super().__init__(name, profile, **kwargs) self._init_actions([SpeakAloud]) - self._watch([BossRequirement, SpeakAloud]) + self._watch([UserRequirement, SpeakAloud]) self.name = name self.opponent_name = opponent_name ``` @@ -81,7 +81,7 @@ async def _act(self) -> Message: msg = Message( content=rsp, role=self.profile, - cause_by=type(todo), + cause_by=todo, sent_from=self.name, send_to=self.opponent_name, ) @@ -102,7 +102,7 @@ class Debator(Role): ): super().__init__(name, profile, **kwargs) self._init_actions([SpeakAloud]) - self._watch([BossRequirement, SpeakAloud]) + self._watch([UserRequirement, SpeakAloud]) self.name = name self.opponent_name = opponent_name @@ -124,7 +124,7 @@ class Debator(Role): msg = Message( content=rsp, role=self.profile, - cause_by=type(todo), + cause_by=todo, sent_from=self.name, send_to=self.opponent_name, ) @@ -132,7 +132,7 @@ class Debator(Role): return msg ``` ### 创建团队并添加角色 -现在我们已经定义了我们的 `Debator`,让我们将它们组合起来看看会发生什么。我们建立一个 `Team` 并“雇佣”了拜登和特朗普。在这个例子中,我们将通过将我们的指令(作为 `BossRequirement`)发送给拜登,让他先开始。如果你想让特朗普先说话,将 `send_to` 设置为 "Trump"。 +现在我们已经定义了我们的 `Debator`,让我们将它们组合起来看看会发生什么。我们建立一个 `Team` 并“雇佣”了拜登和特朗普。在这个例子中,我们将通过将我们的指令(作为 `UserRequirement`)发送给拜登,让他先开始。如果你想让特朗普先说话,将 `send_to` 设置为 "Trump"。 运行这个 `Team`,我们应该看到他们之间友好的对话! ```python @@ -143,10 +143,22 @@ async def debate(idea: str, investment: float = 3.0, n_round: int = 5): team = Team() team.hire([Biden, Trump]) team.invest(investment) - team.start_project(idea, send_to="Biden") # 将辩论主题发送给拜登,让他先说话 + team.run_project(idea, send_to="Biden") # 将辩论主题发送给拜登,让他先说话 await team.run(n_round=n_round) -def main(idea: str, investment: float = 3.0, n_round: int = 10): + +import asyncio +import platform +import typer +from metagpt.team import Team +app = typer.Typer() + +@app.command() +def main( + idea: str = typer.Argument(..., help="Economic Policy: Discuss strategies and plans related to taxation, employment, fiscal budgeting, and economic growth."), + investment: float = typer.Option(default=3.0, help="Dollar amount to invest in the AI company."), + n_round: int = typer.Option(default=5, help="Number of rounds for the simulation."), +): """ :param idea: Debate topic, such as "Topic: The U.S. should commit more in climate change fighting" or "Trump: Climate change is a hoax" @@ -159,7 +171,7 @@ def main(idea: str, investment: float = 3.0, n_round: int = 10): asyncio.run(debate(idea, investment, n_round)) if __name__ == '__main__': - fire.Fire(main) + app() ``` ### 本节的完整脚本