多智能体辩论

辩论工作流模拟了不同智能体之间的多轮讨论,主要是若干个解决者和一个聚合者之间的互动。 通常,解决者生成并交换它们的答案,而聚合者则收集并汇总这些答案。

我们实现了EMNLP 2024中的示例,其中两位辩论智能体将按照固定顺序讨论一个话题,并基于之前的辩论历史表达他们的论点。 在每一轮中,主持人智能体会判断当前迭代是否能够得出正确答案。

import asyncio
import os

from pydantic import Field, BaseModel

from agentscope.agent import ReActAgent
from agentscope.formatter import (
    DashScopeMultiAgentFormatter,
    DashScopeChatFormatter,
)
from agentscope.message import Msg
from agentscope.model import DashScopeChatModel
from agentscope.pipeline import MsgHub

# Prepare a topic
topic = (
    "The two circles are externally tangent and there is no relative sliding. "
    "The radius of circle A is 1/3 the radius of circle B. Circle A rolls "
    "around circle B one trip back to its starting point. How many times will "
    "circle A revolve in total?"
)


# Create two debater agents, Alice and Bob, who will discuss the topic.
def create_solver_agent(name: str) -> ReActAgent:
    """Get a solver agent."""
    return ReActAgent(
        name=name,
        sys_prompt=f"You're a debater named {name}. Hello and welcome to the "
        "debate competition. It's unnecessary to fully agree with "
        "each other's perspectives, as our objective is to find "
        "the correct answer. The debate topic is stated as "
        f"follows: {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"]]

# Create a moderator agent
moderator = ReActAgent(
    name="Aggregator",
    sys_prompt=f"""You're a moderator. There will be two debaters involved in a debate competition. They will present their answer and discuss their perspectives on the topic:
``````
{topic}
``````
At the end of each round, you will evaluate both sides' answers and decide which one is correct.""",
    model=DashScopeChatModel(
        model_name="qwen-max",
        api_key=os.environ["DASHSCOPE_API_KEY"],
        stream=False,
    ),
    # Use multiagent formatter because the moderator will receive messages from more than a user and an assistant
    formatter=DashScopeMultiAgentFormatter(),
)


# A structured output model for the moderator
class JudgeModel(BaseModel):
    """The structured output model for the moderator."""

    finished: bool = Field(
        description="Whether the debate is finished.",
    )
    correct_answer: str | None = Field(
        description="The correct answer to the debate topic, only if the debate is finished. Otherwise, leave it as None.",
        default=None,
    )


async def run_multiagent_debate() -> None:
    """Run the multi-agent debate workflow."""
    while True:
        # The reply messages in MsgHub from the participants will be broadcasted to all participants.
        async with MsgHub(participants=[alice, bob, moderator]):
            await alice(
                Msg(
                    "user",
                    "You are affirmative side, Please express your viewpoints.",
                    "user",
                ),
            )
            await bob(
                Msg(
                    "user",
                    "You are negative side. You disagree with the affirmative side. Provide your reason and answer.",
                    "user",
                ),
            )

        # Alice and Bob doesn't need to know the moderator's message, so moderator is called outside the MsgHub.
        msg_judge = await moderator(
            Msg(
                "user",
                "Now you have heard the answers from the others, have the debate finished, and can you get the correct answer?",
                "user",
            ),
            structured_model=JudgeModel,
        )

        if msg_judge.metadata.get("finished"):
            print(
                "\nThe debate is finished, and the correct answer is: ",
                msg_judge.metadata.get("correct_answer"),
            )
            break


asyncio.run(run_multiagent_debate())
Alice: As the affirmative side, I will present a solution to the problem of how many times circle A, with a radius 1/3 that of circle B, will revolve as it rolls around circle B without sliding.

Let's denote:
- The radius of circle B as \( R \).
- The radius of circle A as \( r = \frac{1}{3}R \).

When circle A rolls around circle B, the center of circle A will trace out a circular path whose radius is the sum of the radii of both circles, which is \( R + r = R + \frac{1}{3}R = \frac{4}{3}R \).

The circumference of the path traced by the center of circle A is:
\[ C_{path} = 2\pi \left(\frac{4}{3}R\right) = \frac{8}{3}\pi R \]

The circumference of circle A is:
\[ C_A = 2\pi r = 2\pi \left(\frac{1}{3}R\right) = \frac{2}{3}\pi R \]

The number of revolutions circle A makes as it rolls around circle B is the ratio of the path's circumference to the circumference of circle A:
\[ \text{Number of Revolutions} = \frac{C_{path}}{C_A} = \frac{\frac{8}{3}\pi R}{\frac{2}{3}\pi R} = \frac{8}{3} \times \frac{3}{2} = 4 \]

Therefore, my position is that circle A will revolve 4 times in total as it rolls around circle B and returns to its starting point.
Bob: While the affirmative side has provided a calculation, there appears to be a misunderstanding regarding the number of revolutions circle A will make as it rolls around circle B. Let's re-examine the situation.

The path that the center of circle A traces is indeed a circle with radius \( R + r = \frac{4}{3}R \), and the circumference of this path is \( C_{path} = 2\pi \left(\frac{4}{3}R
ight) = \frac{8}{3}\pi R \). The circumference of circle A itself is \( C_A = \frac{2}{3}\pi R \).

However, when circle A rolls without sliding, for every full revolution it makes, it covers a distance equal to its own circumference, \( C_A \). To find out how many times it revolves, we need to divide the total distance traveled by the center of circle A (the circumference of the path) by the circumference of circle A:

\[      ext{Number of Revolutions} = \frac{C_{path}}{C_A} = \frac{\frac{8}{3}\pi R}{\frac{2}{3}\pi R} = \frac{8}{3}     imes \frac{3}{2} = 4 \]

But here's the key point: As circle A rolls around the outside of circle B, it not only rotates due to the distance it travels along the path but also because it must rotate an additional time to align with the starting orientation after completing the loop around circle B. This is known as the coin rotation paradox or the belt trick in topology. For every complete trip around the larger circle, the smaller circle will make one extra revolution due to this change in orientation.

Therefore, the total number of revolutions made by circle A is the 4 calculated from the distance plus 1 more for the final alignment, making it 5 in total.
Aggregator: The debate has concluded, and the correct answer can be determined. Alice's initial calculation was that circle A would revolve 4 times around its own center as it rolls around the circumference of circle B. Bob agreed with this calculation but added an important point about the coin rotation paradox, which means that after completing the trip around circle B, circle A must make one additional revolution to align with its starting orientation.

Therefore, the total number of revolutions made by circle A is 4 (from the distance traveled) plus 1 (for the final alignment), making a total of 5 revolutions. The correct answer is that circle A will revolve 5 times in total.

The debate is finished, and the correct answer is:  5

扩展阅读

通过多智能体辩论鼓励大型语言模型发散性思维。EMNLP 2024。

脚本总运行时间: (1 分 6.953 秒)

Gallery generated by Sphinx-Gallery