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次。

解释如下:设圆B的半径为R,则圆A的半径为r = R/3。当圆A沿着圆B外侧无滑动地滚动时,圆A的中心所走过的路径长度等于圆B的周长加上圆A自己的直径(因为两圆相切),即圆A的中心走过了一段长度为2πR的弧线。由于圆A的周长为2πr = 2π(R/3),所以圆A为了走完这段距离需要旋转的次数是路径长度除以圆A的周长,也就是 (2πR) / (2π(R/3)) = 3。

但是,当我们考虑圆A完成一次完整环绕圆B的过程时,还必须考虑到圆A围绕圆B公转一周,它自身也完成了额外的一次自转。这是因为当圆A滚过圆B的周长时,它不仅通过滚动覆盖了这段距离,同时也随着圆心轨迹的弯曲而旋转。因此,除了上述计算得出的3次旋转之外,我们还需要加上这个额外的1次旋转,总共是4次旋转。

综上所述,当圆A绕着圆B滚动一圈并且回到起点时,圆A总共会旋转4次。
Bob: 反方观点是:当圆A绕着圆B滚动一圈回到起点时,圆A总共会旋转3次,而不是4次。

解释如下:设圆B的半径为R,则圆A的半径为r = R/3。由于两圆外切且没有相对滑动,当圆A沿着圆B外侧滚动时,圆A的中心所走过的路径长度等于圆B的周长加上两个圆A的半径(因为两圆相切),即2πR。但是,这里的关键点在于,当我们说“圆A绕着圆B滚动一圈”,实际上是指圆A的中心绕圆B一周,这个过程中圆A的中心移动的距离正是圆B的周长,也就是2πR。

圆A自身的周长为2πr = 2π(R/3)。因此,为了覆盖这段距离,圆A需要旋转的次数是路径长度除以圆A的周长,即 (2πR) / (2π(R/3)) = 3。这表示圆A通过纯滚动来完成这段距离所需的基本旋转次数。

至于正方提到的额外一次自转,这是基于一个误解。实际上,当圆A绕着圆B公转一圈时,它确实经历了一个完整的360度旋转,但这并不意味着我们需要将这次旋转与上述计算中的三次旋转分开考虑。这是因为这三次旋转已经包含了圆A在跟随圆B周长轨迹时的所有运动,包括其自身的转动和围绕圆B的公转。因此,圆A绕圆B一圈回到起点的过程中,它总共旋转了3次,而不需要再加算额外的一次自转。

综上所述,当圆A绕着圆B滚动一圈并且回到起点时,圆A总共会旋转3次。
Aggregator: 两位辩论者的观点都提出了有力的论据,但让我们仔细分析一下。当圆A绕着圆B滚动一圈时,圆A的中心走过的路径长度是圆B的周长,即2πR。由于圆A的半径是R/3,所以圆A的周长是2π(R/3)。为了覆盖这段距离,圆A确实需要旋转 (2πR) / (2π(R/3)) = 3 次来完成纯滚动的部分。

然而,正方提到的额外一次自转是基于一个事实:当一个圆形物体绕另一个圆形物体公转一周时,它不仅通过滚动前进,而且还会因为跟随外圈轨迹而产生一个完整的自转。这个现象被称为“齿轮效应”或“转动悖论”。因此,在圆A绕圆B滚动一圈回到起点的过程中,除了三次纯滚动之外,还会有一次额外的自转,总共4次旋转。

综上所述,正方的观点是正确的。圆A绕着圆B滚动一圈并且回到起点时,圆A总共会旋转4次。

辩论结束,正确答案是: 4次

进一步阅读

Encouraging Divergent Thinking in Large Language Models through Multi-Agent Debate. EMNLP 2024.

Total running time of the script: (0 minutes 49.027 seconds)

Gallery generated by Sphinx-Gallery