MetaGPT/examples/debate.py

110 lines
3.6 KiB
Python
Raw Normal View History

'''
Filename: MetaGPT/examples/debate.py
Created Date: Tuesday, September 19th 2023, 6:52:25 pm
Author: garylin2099
'''
2023-09-15 22:40:22 +08:00
import asyncio
import platform
import fire
from metagpt.team import Team
from metagpt.actions import Action, UserRequirement
2023-09-15 22:40:22 +08:00
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.logs import logger
class SpeakAloud(Action):
"""Action: Speak out aloud in a debate (quarrel)"""
2023-09-15 22:40:22 +08:00
PROMPT_TEMPLATE = """
## BACKGROUND
Suppose you are {name}, you are in a debate with {opponent_name}.
## DEBATE HISTORY
Previous rounds:
{context}
## YOUR TURN
Now it's your turn, you should closely respond to your opponent's latest argument, state your position, defend your arguments, and attack your opponent's arguments,
craft a strong and emotional response in 80 words, in {name}'s rhetoric and viewpoints, your will argue:
"""
def __init__(self, name="SpeakAloud", context=None, llm=None):
2023-09-15 22:40:22 +08:00
super().__init__(name, context, llm)
2023-09-20 11:42:41 +08:00
2023-09-15 22:40:22 +08:00
async def run(self, context: str, name: str, opponent_name: str):
prompt = self.PROMPT_TEMPLATE.format(context=context, name=name, opponent_name=opponent_name)
# logger.info(prompt)
rsp = await self._aask(prompt)
return rsp
class Debator(Role):
2023-09-15 22:40:22 +08:00
def __init__(
self,
name: str,
profile: str,
opponent_name: str,
2023-09-15 22:40:22 +08:00
**kwargs,
):
super().__init__(name, profile, **kwargs)
self._init_actions([SpeakAloud])
self._watch([UserRequirement, SpeakAloud])
self.name = name
self.opponent_name = opponent_name
2023-09-20 11:42:41 +08:00
2023-09-15 22:40:22 +08:00
async def _observe(self) -> int:
await super()._observe()
2023-09-20 11:42:41 +08:00
# accept 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.send_to == self.name]
2023-09-15 22:40:22 +08:00
return len(self._rc.news)
async def _act(self) -> Message:
logger.info(f"{self._setting}: ready to {self._rc.todo}")
todo = self._rc.todo # An instance of SpeakAloud
2023-09-20 11:42:41 +08:00
memories = self.get_memories()
context = "\n".join(f"{msg.sent_from}: {msg.content}" for msg in memories)
# print(context)
2023-09-15 22:40:22 +08:00
rsp = await todo.run(context=context, name=self.name, opponent_name=self.opponent_name)
2023-09-15 22:40:22 +08:00
msg = Message(
content=rsp,
role=self.profile,
cause_by=type(todo),
2023-09-15 22:40:22 +08:00
sent_from=self.name,
send_to=self.opponent_name,
)
self._rc.memory.add(msg)
2023-09-15 22:40:22 +08:00
return msg
async def debate(idea: str, investment: float = 3.0, n_round: int = 5):
"""Run a team of presidents and watch they quarrel. :) """
Biden = Debator(name="Biden", profile="Democrat", opponent_name="Trump")
Trump = Debator(name="Trump", profile="Republican", opponent_name="Biden")
team = Team()
team.hire([Biden, Trump])
team.invest(investment)
1. 动作优化 1. SummarizeCode动作:用于基于代码进行总结,思考bug、逻辑、todo 2. CodeReview动作优化:目前强制要求回答问题,有更高的成功率了 1. 增加了LGTM/LBTM的回答,在LGTM时会及时停止,不重写代码 2. 目前增加了设置中的参数code_review_k_times,与reflexion类似,设置为2 3. 仍然有概率发生指令不遵循,尤其是会有比较高的概率发生同时review多个代码文件,还没想好怎么解决 #FIXME 3. 增加了env到Action结构中,现在可以直接调用环境接口了 4. WriteDesign:去除了对project_name的纠正代码,现在引导下可以一次生成对 1. 修改了提示词中的##格式,改为了JSON格式 2. 数据结构 1. Document的标准化:Env->Repo->Document,其中Document/Asset/Code都是Document 1. 原用于检索的Document改为IndexableDocument 2. Repo结构引入:用于Document装载与元数据装载 3. RepoParser引入:写了一个简单的AST parser(后续可能要换tree-sitter),给出了整库symbol 4. Env中增加了set/get/set_doc/get_doc接口,用于set/get单个变量或者一个Document。这个逻辑后续或许会进一步简化 3. 配置优化 1. 默认更换为gpt-4-1106-preview,以获得最好的效果与成本 2. 提供~/.metagpt作为配置最高优先级目录,从中读取config.yaml 3. workspace可以灵活指定了,在config中配置 4. project_name可以由命令行指定,并且改为由ProductManager生成 4. metagpt作为默认命令行,而非python startup.py metagpt --help metagpt --project-name game_2048 "make a 2048 game" metagpt "make a 2048 game" metagpt --project-name game_2048 --inc "将2048改为4096" metagpt --project-name game_2048 --auto-inc "make a 2048 game" 1. 使用新的METAGPT_ROOT生成方式,而非寻找git,以便cli安装 2. 命令行由fire换为了typer,它会带来相对更好的体验 3. project_name可以灵活指定了,在metagpt命令行输入中配置 5. 其他 1. 现在支持多国语言了,中文已测试 2. BossRequirement -> UserRequirement 3. 大量错误文本的修正,增加了可读性 4. 中量提示词优化,稍微提升了一些准确率 5. 暂时屏蔽了LongtermMemory相关逻辑,这个逻辑底层调用了langchain的FAISS,会带来~5秒加载耗时 6. 修复了安装包中的部分描述错误 7. 去除了config中在openai_proxy设定时对base的重复修改,这个修改应该在openai初始化时发生 8. 修复了JSON在中文存储时的特定问题,ensure_ascii=False
2023-11-27 15:36:50 +08:00
team.run_project(idea, send_to="Biden") # send debate topic to Biden and let him speak first
await team.run(n_round=n_round)
2023-09-15 22:40:22 +08:00
def main(idea: str, investment: float = 3.0, n_round: int = 10):
2023-09-15 22:40:22 +08:00
"""
2023-09-20 11:42:41 +08:00
:param idea: Debate topic, such as "Topic: The U.S. should commit more in climate change fighting"
or "Trump: Climate change is a hoax"
:param investment: contribute a certain dollar amount to watch the debate
:param n_round: maximum rounds of the debate
2023-09-15 22:40:22 +08:00
:return:
"""
if platform.system() == "Windows":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(debate(idea, investment, n_round))
2023-09-15 22:40:22 +08:00
if __name__ == '__main__':
fire.Fire(main)