备注
Go to the end to download the full example code.
Multi-Agent Debate¶
Multi-Agent debate 模拟不同智能体之间的多轮讨论场景,通常包括几个 solver 和一个 aggregator。 典型情况下,solver 生成并交换他们的答案,而 aggregator 收集并总结答案。
我们实现了 EMNLP 2024 中的示例,其中两个 solver 智能体将按固定顺序讨论一个话题,根据先前的辩论历史表达他们的论点。 在每一轮中,主持人智能体将决定是否可以在当前轮获得最终的正确答案。
import asyncio
import os
from pydantic import Field, BaseModel
from agentscope.agent import ReActAgent
from agentscope.formatter import (
DashScopeMultiAgentFormatter,
)
from agentscope.message import Msg
from agentscope.model import DashScopeChatModel
from agentscope.pipeline import MsgHub
# 准备一个话题
topic = "两个圆外切且没有相对滑动。圆A的半径是圆B半径的1/3。圆A绕圆B滚动一圈回到起点。圆A总共会旋转多少次?"
# 创建两个辩论者智能体,Alice 和 Bob,他们将讨论这个话题。
def create_solver_agent(name: str) -> ReActAgent:
"""获取一个解决者智能体。"""
return ReActAgent(
name=name,
sys_prompt=f"你是一个名为 {name} 的辩论者。你好,欢迎来到"
"辩论比赛。我们的目标是找到正确答案,因此你没有必要完全同意对方"
f"的观点。辩论话题如下所述:{topic}",
model=DashScopeChatModel(
model_name="qwen-max",
api_key=os.environ["DASHSCOPE_API_KEY"],
stream=False,
),
formatter=DashScopeMultiAgentFormatter(),
)
alice, bob = [create_solver_agent(name) for name in ["Alice", "Bob"]]
# 创建主持人智能体
moderator = ReActAgent(
name="Aggregator",
sys_prompt=f"""你是一个主持人。将有两个辩论者参与辩论比赛。他们将就以下话题提出观点并进行讨论:
``````
{topic}
``````
在每轮讨论结束时,你将评估辩论是否结束,以及话题正确的答案。""",
model=DashScopeChatModel(
model_name="qwen-max",
api_key=os.environ["DASHSCOPE_API_KEY"],
stream=False,
),
# 使用多智能体格式化器,因为主持人将接收来自多于用户和助手的消息
formatter=DashScopeMultiAgentFormatter(),
)
# 主持人的结构化输出模型
class JudgeModel(BaseModel):
"""主持人的结构化输出模型。"""
finished: bool = Field(description="辩论是否结束。")
correct_answer: str | None = Field(
description="辩论话题的正确答案,仅当辩论结束时提供该字段。否则保留为 None。",
default=None,
)
async def run_multiagent_debate() -> None:
"""运行多智能体辩论工作流。"""
while True:
# MsgHub 中参与者的回复消息将广播给所有参与者。
async with MsgHub(participants=[alice, bob, moderator]):
await alice(
Msg(
"user",
"你是正方,请表达你的观点。",
"user",
),
)
await bob(
Msg(
"user",
"你是反方。你不同意正方的观点。请表达你的观点和理由。",
"user",
),
)
# Alice 和 Bob 不需要知道主持人的消息,所以主持人在 MsgHub 外部调用。
msg_judge = await moderator(
Msg(
"user",
"现在你已经听到了他们的辩论,现在判断辩论是否结束,以及你能得到正确答案吗?",
"user",
),
structured_model=JudgeModel,
)
if msg_judge.metadata.get("finished"):
print(
"\n辩论结束,正确答案是:",
msg_judge.metadata.get("correct_answer"),
)
break
asyncio.run(run_multiagent_debate())
Alice: 谢谢。我的观点是,当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转4次。
首先,我们知道圆A的半径是圆B半径的1/3,这意味着圆A的周长也是圆B周长的1/3。当圆A沿着圆B的外部边缘完整地绕行一圈时,它所走过的路径长度等于圆B的周长。由于圆A的周长只有圆B的1/3,因此在没有相对滑动的情况下,为了走过与圆B相同周长的距离,圆A需要自转3圈来覆盖这段距离。
但是,这里有一个关键点需要注意:除了上述的3次旋转之外,还有额外的一次旋转来自于圆A围绕圆B中心进行的整体运动。想象一下,如果将圆A视为一个点而不是一个圆,在它绕着圆B移动一周的过程中,这个“点”也完成了一次完整的旋转(即360度)。因此,对于圆A来说,除了因为其自身滚动而产生的3次旋转外,还会有因跟随圆心轨迹而自然发生的额外一次旋转。
综上所述,当圆A绕圆B滚动一圈回到起点时,圆A总共会旋转4次。
Bob: 谢谢。我不同意Alice的观点,我认为当圆A绕着圆B滚动一圈回到起点时,圆A总共只会旋转3次。
让我们来仔细分析一下这个问题。首先,我们知道圆A的半径是圆B半径的1/3,这意味着圆A的周长也是圆B周长的1/3。当圆A沿着圆B的外部边缘完整地绕行一圈时,它所走过的路径长度等于圆B的周长。由于圆A的周长只有圆B的1/3,因此在没有相对滑动的情况下,为了走过与圆B相同周长的距离,圆A需要自转3圈来覆盖这段距离。
这里的关键在于理解“旋转”的定义。当我们说圆A旋转时,我们指的是相对于地面或固定参考系的旋转次数。在这个问题中,圆A围绕圆B中心的整体运动并不等同于额外的一次旋转。这是因为,虽然圆A的中心点确实绕着圆B中心旋转了一圈,但这并不意味着圆A本身多旋转了一次。相反,这种整体运动实际上已经被包含在了那3次自转之中了。
换句话说,当圆A绕着圆B滚动时,它的接触点始终在变化,但这个过程中并没有额外增加一次完整的360度旋转。因此,当圆A绕圆B滚动一圈回到起点时,圆A总共会旋转3次。
/home/runner/work/agentscope/agentscope/src/agentscope/model/_dashscope_model.py:203: DeprecationWarning: 'required' is not supported by DashScope API. It will be converted to 'auto'.
warnings.warn(
Aggregator: {
"type": "tool_use",
"name": "generate_response",
"input": {
"finished": true,
"correct_answer": "当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转4次。Alice的观点是正确的。虽然圆A的周长只有圆B的1/3,因此在没有相对滑动的情况下为了走过与圆B相同周长的距离,圆A需要自转3圈来覆盖这段距离;但是,还必须考虑圆A中心点围绕圆B中心所做的额外一次360度旋转。这个额外的旋转来自于圆A跟随其自身轨迹的整体运动,使得总旋转次数为4次。"
},
"id": "call_425b6980f6f144838116bd"
}
system: {
"type": "tool_result",
"id": "call_425b6980f6f144838116bd",
"name": "generate_response",
"output": [
{
"type": "text",
"text": "Successfully generated response."
}
]
}
Aggregator: 感谢两位辩论者的精彩讨论。根据你们的论述,现在我来总结并给出正确答案。
Alice认为当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转4次。她指出,由于圆A的半径是圆B半径的1/3,为了覆盖与圆B相同周长的距离,圆A需要自转3圈。此外,圆A中心点围绕圆B中心所做的额外一次360度旋转也应被计算在内。
Bob则认为圆A只会旋转3次。他强调了“旋转”的定义,并指出虽然圆A的中心确实绕着圆B中心旋转了一圈,但这并不意味着圆A本身多旋转了一次,因为这种整体运动实际上已经被包含在了那3次自转之中了。
综合来看,正确的答案是:当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转4次。Alice的观点是正确的。尽管圆A为了覆盖与圆B相同周长的距离需要自转3圈,但我们还必须考虑圆A中心点围绕圆B中心所做的额外一次360度旋转。这个额外的旋转来自于圆A跟随其自身轨迹的整体运动,使得总旋转次数为4次。
因此,本场辩论到此结束,恭喜Alice赢得了这场辩论。再次感谢两位参与者的积极参与!
辩论结束,正确答案是: 当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转4次。Alice的观点是正确的。虽然圆A的周长只有圆B的1/3,因此在没有相对滑动的情况下为了走过与圆B相同周长的距离,圆A需要自转3圈来覆盖这段距离;但是,还必须考虑圆A中心点围绕圆B中心所做的额外一次360度旋转。这个额外的旋转来自于圆A跟随其自身轨迹的整体运动,使得总旋转次数为4次。
进一步阅读¶
Encouraging Divergent Thinking in Large Language Models through Multi-Agent Debate. EMNLP 2024.
Total running time of the script: (1 minutes 2.268 seconds)