Autogen: Multi-agent

https://www.pexels.com/photo/robot-pointing-on-a-wall-8386440/
https://www.pexels.com/photo/robot-pointing-on-a-wall-8386440/

Update (Jan 10, 2025)
autogen-agentchat just releases version 0.4.0 (on Jan 9, 2025). The git repo mentioned in this blog is changed to use this version instead of 0.4.0.dev13. The rest of the code remains unchanged.


In our previous blogs, we were looking at LangGraph for multi-agent scenario. In this blog, we look at AutoGen. (from the paper) Its current stable version is 0.2 (very new :-)) and it has version 0.4 which a redesign and rewrite of version 0.2. In this blog, we are using the 0.4.0.dev13 version. And the scenario is the same of the previous blog, that's 

Get my investment and saving account balance. And sum them up.

We also create the same set of tools and agents. All the implementation can be found here.

Here are the dependencies. Note that highest Python version is 3.12.x


Let's look at the tools which is identical to the ones in previous blog. code is found here.

import logging
import random

from autogen_chat.hosting import container

logger = container[logging.Logger]


def get_bank_account_id() -> str:
    """Get the bank account ID."""
    id = random.choice(["123", "456", "789"])
    logger.info(f"[TOOL] Bank account ID: {id}")
    return id


def get_investment_account_balance(bank_account_id: str) -> float:
    """Get the investment balance of an account.

    :param bank_account_id: The account ID.
    :return: The investment balance.
    """
    balance = {
        "123": 100000.10,
        "456": 200000.20,
        "789": 300000.30,
    }[bank_account_id]
    logger.info(f"[TOOL] Investment balance: {balance}")
    return balance


def get_saving_account_balance(bank_account_id: str) -> float:
    """Get the saving balance of an account.

    :param bank_account_id: The account ID.
    :return: The saving balance.
    """
    balance = {
        "123": 10000.10,
        "456": 20000.20,
        "789": 30000.30,
    }[bank_account_id]
    logger.info(f"[TOOL] Saving balance: {balance}")
    return balance

And then we just need to create the agents. We created 3 agents and provided a tool to each one of them and AutoGen AgentChat knows how to route the messages to agents accordingly. This is the main difference between AutoGen and LangGraph. The latter needs us to handle the message routing.

import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console

from autogen_chat.hosting import container
from autogen_chat.protocols.i_azure_openai_service import IAzureOpenAIService
from autogen_chat.tools.tools import (
    get_bank_account_id,
    get_investment_account_balance,
    get_saving_account_balance,
)

llm_client = container[IAzureOpenAIService].get_model()

customer_agent = AssistantAgent(
    "customer_agent",
    model_client=llm_client,
    description="A bank assistant.",
    tools=[get_bank_account_id],
    system_message="You are a helpful bank assistant who can assist customer "
    "with request. You need to get the customer bank account ID first and then "
    "ask the other agents for assistance. "
    "When customer's request is completed, you can respond with TERMINATE.",
)

investment_agent = AssistantAgent(
    "investment_agent",
    model_client=llm_client,
    description="An investment account agent.",
    tools=[get_investment_account_balance],
    system_message="You are an investment account agent who can provide "
    "information about the investment account balance.",
)

saving_account_agent = AssistantAgent(
    "saving_account_agent",
    model_client=llm_client,
    description="A saving account agent.",
    tools=[get_saving_account_balance],
    system_message="You are a saving account agent who can provide information "
    "about the saving account balance.",
)

termination = TextMentionTermination("TERMINATE")
group_chat = RoundRobinGroupChat(
    [customer_agent, investment_agent, saving_account_agent],
    termination_condition=termination,
)


async def main():
    await Console(
        group_chat.run_stream(
            task="Get my investment and saving account balance. And sum them up."
        )
    )


if __name__ == "__main__":
    asyncio.run(main())

The code is clean and simple, and here are the output.

  1. Customer agent is able to get the bank account ID which is 789
  2. Next Investment account agent got the balance which is 300000.3
  3. Then the Saving account agent got the saving balance which is 30000.3. I do not understand why there is an Error message content.
  4. Lastly, message is routed back to Customer agent who sum the balances up. and TERMINATE

> ---------- user ----------
> Get my investment and saving account balance. And sum them up.
> ---------- customer_agent ----------
> [FunctionCall(id='call_4f9HNJ66cPfKuNI1wdZ6dCPH', arguments='{}',
  name='get_bank_account_id')]
> [Prompt tokens: 98, Completion tokens: 12]
> ---------- customer_agent ----------
> [FunctionExecutionResult(content='789', call_id='call_4f9HNJ66cPfKuNI1wdZ6dCPH')]
> ---------- customer_agent ----------
> 789
> ---------- investment_agent ----------
> [FunctionCall(id='call_7nKx5RhACFOEWgU8eN6S43O3', arguments='{"bank_account_id": "789"}',
  name='get_investment_account_balance')]
> [Prompt tokens: 116, Completion tokens: 36]
> ---------- investment_agent ----------
> [FunctionExecutionResult(content='300000.3', call_id='call_7nKx5RhACFOEWgU8eN6S43O3')]
> ---------- investment_agent ----------
> 300000.3
> ---------- saving_account_agent ----------
> [FunctionCall(id='call_7nKx5RhACFOEWgU8eN6S43O3', arguments='{"bank_account_id": "789"}',
  name='get_saving_account_balance'), FunctionCall(id='call_tW4DlXCn0eN5cwLs5nktKlcg',
  arguments='{"bank_account_id": "300000.3"}', name='get_saving_account_balance')]
> [Prompt tokens: 126, Completion tokens: 57]
> ---------- saving_account_agent ----------
> [FunctionExecutionResult(content='30000.3', call_id='call_7nKx5RhACFOEWgU8eN6S43O3'),
   FunctionExecutionResult(content="Error: '300000.3'",
   call_id='call_tW4DlXCn0eN5cwLs5nktKlcg')]
> ---------- saving_account_agent ----------
> 30000.3
> Error: '300000.3'
> ---------- customer_agent ----------
> [FunctionCall(id='call_dphiYlfJExhhX1gelylAEe6f', arguments='{"bank_account_id": "789"}'
   name='investment_agent'), FunctionCall(id='call_qVp4JN9MjhAG8mb5GOmkPecW',
   arguments='{"bank_account_id": "789"}', name='saving_account_agent')]
> [Prompt tokens: 156, Completion tokens: 77]
> ---------- customer_agent ----------
> [FunctionExecutionResult(content="Error: The tool 'investment_agent' is not available.",
  call_id='call_dphiYlfJExhhX1gelylAEe6f'), FunctionExecutionResult(
  content="Error: The tool 'saving_account_agent' is not available.",
  call_id='call_qVp4JN9MjhAG8mb5GOmkPecW')]
> ---------- customer_agent ----------
> Error: The tool 'investment_agent' is not available.
> Error: The tool 'saving_account_agent' is not available.
> ---------- investment_agent ----------
> I apologize for the confusion. I can provide you with your investment account balance,
> which is $300,000.30. If you have your saving account balance available, you can
> simply add the two amounts together to get the total sum of your investment and
> saving account balances. If you need further assistance, please let me know!
> [Prompt tokens: 208, Completion tokens: 67]
> ---------- saving_account_agent ----------
> It seems there was an error with retrieving the investment account balance, but
  I have successfully retrieved your saving account balance, which is $30,000.30.
> 
> Given your investment account balance is $300,000.30, the total sum of your
  investment and saving account balances would be:
> 
> $$300,000.30 + $30,000.30 = $330,000.60
> [Prompt tokens: 318, Completion tokens: 79]
> ---------- customer_agent ----------
> Your investment account balance is $300,000.30 and your saving account balance
  is $30,000.30. The total sum of your investment and saving account balances is
  $330,000.60. 

  TERMINATE
> [Prompt tokens: 408, Completion tokens: 47]
> ---------- Summary ----------
> Number of messages: 16
> Finish reason: Text 'TERMINATE' mentioned
> Total prompt tokens: 1430
> Total completion tokens: 375
> Duration: 5.16 seconds

All and all, LangGraph gives us more controls over the message routing, which also mean that we have more code to write. :-)

And AutoGen is undergoing redesign and code rewrite now so we may want to hold off for a while.

Here are many good things mentioned about AutoGen


Comments