.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorial/workflow_multiagent_debate.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorial_workflow_multiagent_debate.py: .. _multiagent-debate: 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. .. GENERATED FROM PYTHON SOURCE LINES 15-131 .. code-block:: Python 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()) .. rst-class:: sphx-glr-script-out .. code-block:: none Alice: Thank you. As the affirmative side, I will present the argument that when circle A, with a radius 1/3 that of circle B, rolls around circle B one complete trip back to its starting point, it will revolve 4 times in total. To understand this, let's break down the problem: - Let the radius of circle B be \( r \). - Then, the radius of circle A is \( \frac{r}{3} \). When circle A rolls around circle B, it traces out a path along the circumference of an imaginary circle with a radius equal to the sum of the radii of circles A and B, which is \( r + \frac{r}{3} = \frac{4r}{3} \). The circumference of this larger path (which is the path that the center of circle A follows) is: \[ C_{\text{path}} = 2\pi \left(\frac{4r}{3}\right) = \frac{8\pi r}{3} \] Now, the circumference of circle A itself is: \[ C_{\text{A}} = 2\pi \left(\frac{r}{3}\right) = \frac{2\pi r}{3} \] The number of revolutions circle A makes as it rolls around circle B is the ratio of the path it follows to its own circumference: \[ \text{Number of Revolutions} = \frac{C_{\text{path}}}{C_{\text{A}}} = \frac{\frac{8\pi r}{3}}{\frac{2\pi r}{3}} = \frac{8\pi r}{3} \times \frac{3}{2\pi r} = 4 \] Therefore, circle A will revolve 4 times as it rolls around circle B once. Bob: Thank you, Alice. As the negative side, I will present a counter-argument to the claim that circle A will revolve 4 times as it rolls around circle B. To understand the correct number of revolutions, we need to consider both the path that the center of circle A follows and the additional rotation due to the rolling motion without slipping. - Let the radius of circle B be \( r \). - Then, the radius of circle A is \( \frac{r}{3} \). When circle A rolls around circle B, its center traces out a larger circle with a radius equal to the sum of the radii of circles A and B, which is \( r + \frac{r}{3} = \frac{4r}{3} \). The circumference of this larger path (which is the path that the center of circle A follows) is: \[ C_{\text{path}} = 2\pi \left(\frac{4r}{3}\right) = \frac{8\pi r}{3} \] Now, the circumference of circle A itself is: \[ C_{\text{A}} = 2\pi \left(\frac{r}{3}\right) = \frac{2\pi r}{3} \] The number of times the center of circle A travels around the circumference of the larger path is: \[ \text{Number of Circumference Paths} = \frac{C_{\text{path}}}{C_{\text{A}}} = \frac{\frac{8\pi r}{3}}{\frac{2\pi r}{3}} = 4 \] However, this calculation only accounts for the linear distance traveled by the center of circle A. We must also account for the fact that circle A rotates once for every full circumference it rolls along. Since the center of circle A completes 4 circumferences, circle A will rotate an additional 1 time due to the rolling motion. Therefore, the total number of revolutions of circle A is: \[ \text{Total Revolutions} = 4 + 1 = 5 \] In conclusion, when circle A rolls around circle B one complete trip back to its starting point, it will revolve 5 times in total. /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_10998b36be89463fa02f82" } system: { "type": "tool_result", "id": "call_10998b36be89463fa02f82", "name": "generate_response", "output": [ { "type": "text", "text": "Successfully generated response." } ] } Aggregator: The debate has concluded, and after evaluating the arguments presented by both Alice and Bob, the correct answer is that circle A will revolve 4 times in total as it rolls around circle B one complete trip back to its starting point. Alice's argument correctly calculates the number of revolutions based on the path followed by the center of circle A. The key point is that the rolling motion without slipping means that for every full circumference of the larger path, circle A completes one full revolution. Since the ratio of the circumferences results in 4, this is the total number of revolutions. Bob's additional consideration of an extra rotation due to the rolling motion is a common misconception. In fact, the 4 revolutions already account for the rotations due to the rolling motion. Therefore, no additional revolution is needed. Thus, the correct answer is 4 revolutions. The debate is finished, and the correct answer is: 4 .. GENERATED FROM PYTHON SOURCE LINES 132-140 Further Reading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :ref:`pipeline` .. _EMNLP 2024: Encouraging Divergent Thinking in Large Language Models through Multi-Agent Debate. EMNLP 2024. .. rst-class:: sphx-glr-timing **Total running time of the script:** (1 minutes 3.097 seconds) .. _sphx_glr_download_tutorial_workflow_multiagent_debate.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: workflow_multiagent_debate.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: workflow_multiagent_debate.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: workflow_multiagent_debate.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_