Note
Go to the end to download the full example code.
Multi-Agent Debate¶
Debate workflow simulates a multi-turn discussion between different agents, mostly several solvers and an aggregator. Typically, the solvers generate and exchange their answers, while the aggregator collects and summarizes the answers.
We implement the examples in EMNLP 2024, where two debater agents will discuss a topic in a fixed order, and express their arguments based on the previous debate history. At each round a moderator agent will decide whether the correct answer can be obtained in the current iteration.
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: Thank you. As the affirmative side, I will present the argument that when circle A, with a radius one-third that of circle B, rolls around circle B without sliding, it will revolve 4 times in total by the time it returns to its starting point.
To understand this, let's consider the following:
- Let the radius of circle B be \( r_B \).
- The radius of circle A is then \( r_A = \frac{1}{3}r_B \).
When circle A rolls around circle B, it follows a path along the circumference of a larger circle whose radius is the sum of the radii of both circles, which is \( r_B + r_A = r_B + \frac{1}{3}r_B = \frac{4}{3}r_B \).
The distance that circle A travels as it goes around circle B once is the circumference of this larger circle:
\[ \text{Circumference of the larger circle} = 2\pi \left(\frac{4}{3}r_B\right) = \frac{8\pi r_B}{3}. \]
Now, for each complete revolution of circle A, it covers a distance equal to its own circumference:
\[ \text{Circumference of circle A} = 2\pi r_A = 2\pi \left(\frac{1}{3}r_B\right) = \frac{2\pi r_B}{3}. \]
To find out how many revolutions circle A makes, we divide the total distance traveled by the circumference of circle A:
\[ \text{Number of revolutions} = \frac{\frac{8\pi r_B}{3}}{\frac{2\pi r_B}{3}} = \frac{8\pi r_B}{3} \times \frac{3}{2\pi r_B} = 4. \]
Therefore, circle A will make 4 complete revolutions as it rolls around circle B and returns to its starting position.
Bob: Thank you. As the negative side, I will argue that circle A will actually revolve 3 times in total by the time it returns to its starting point, not 4 as proposed by the affirmative side.
Let's revisit the setup and consider the relative motion of the circles:
- Let the radius of circle B be \( r_B \).
- The radius of circle A is \( r_A = \frac{1}{3}r_B \).
When circle A rolls around circle B, it follows a path along the circumference of a larger circle with a radius of \( r_B + r_A = \frac{4}{3}r_B \). The distance traveled by circle A along this path is:
\[ \text{Circumference of the larger circle} = 2\pi \left(\frac{4}{3}r_B\right) = \frac{8\pi r_B}{3}. \]
However, we must also account for the fact that as circle A rolls, it rotates due to its own circumference. Each complete revolution of circle A covers a distance equal to its own circumference:
\[ \text{Circumference of circle A} = 2\pi r_A = 2\pi \left(\frac{1}{3}r_B\right) = \frac{2\pi r_B}{3}. \]
To find out how many revolutions circle A makes, we divide the total distance traveled by the circumference of circle A:
\[ \text{Number of revolutions} = \frac{\frac{8\pi r_B}{3}}{\frac{2\pi r_B}{3}} = 4. \]
Here is the key point: When circle A completes one full trip around circle B, it has also rotated once due to the curvature of the path. This additional rotation means that the number of internal rotations (spins) is one less than the number of external rotations (revolutions around the larger circle).
Thus, the number of internal rotations (spins) is:
\[ \text{Number of spins} = 4 - 1 = 3. \]
Therefore, circle A will make 3 complete internal rotations (spins) as it rolls around circle B and returns to its starting position.
/home/runner/work/agentscope/agentscope/src/agentscope/model/_dashscope_model.py:232: DeprecationWarning: 'required' is not supported by DashScope API. It will be converted to 'auto'.
warnings.warn(
Aggregator: {
"type": "tool_use",
"name": "generate_response",
"input": {
"correct_answer": "4",
"finished": true
},
"id": "call_4f4db0d567a24252a8f8ba"
}
system: {
"type": "tool_result",
"id": "call_4f4db0d567a24252a8f8ba",
"name": "generate_response",
"output": [
{
"type": "text",
"text": "Successfully generated response."
}
]
}
Aggregator: Thank you, Alice and Bob, for your detailed presentations. Let's review the arguments to determine the correct number of revolutions circle A makes as it rolls around circle B.
Alice correctly calculated that the total distance traveled by circle A is \(\frac{8\pi r_B}{3}\), and since the circumference of circle A is \(\frac{2\pi r_B}{3}\), the number of complete revolutions is:
\[ \text{Number of revolutions} = \frac{\frac{8\pi r_B}{3}}{\frac{2\pi r_B}{3}} = 4. \]
Bob introduced an additional consideration, suggesting that the internal rotations (spins) are one less than the external rotations. However, this argument is not applicable here because the problem specifically asks for the number of **revolutions** (i.e., how many times circle A completes a full turn relative to an external observer). The internal spins or rotations due to the curvature of the path do not affect the count of external revolutions.
Therefore, the correct answer is that circle A will revolve 4 times in total as it rolls around circle B and returns to its starting position.
The correct answer is 4.
The debate is finished, and the correct answer is: 4
Further Reading¶
Encouraging Divergent Thinking in Large Language Models through Multi-Agent Debate. EMNLP 2024.
Total running time of the script: (1 minutes 32.779 seconds)