Secrets such as password, tokens, or personal information needs to be protected from capture. AG2 provides dependency injection as a way to secure this sensitive information while still allowing agents to perform their tasks effectively, even when working with large language models (LLMs).

Benefits of dependency injection:

  • Enhanced Security: Your sensitive data is never directly exposed to the LLM or telemetry.
  • Simplified Development: Secure data can be seamlessly accessed by functions without requiring complex configurations.
  • Unmatched Flexibility: Supports safe integration of diverse workflows, allowing you to scale and adapt with ease.

In this walk-through we’ll show how you could support 3rd party system credentials using specific agents and their respective tools and dependency injection.

# Imports and an LLM configuration for all agents
import os
from typing import Annotated, Literal

from pydantic import BaseModel

from autogen import GroupChat, GroupChatManager
from autogen.agentchat import ConversableAgent, UserProxyAgent
from autogen.tools.dependency_injection import BaseContext, Depends

config_list = [{"model": "gpt-4o-mini", "api_key": os.environ["OPENAI_API_KEY"]}]

We have 2 external systems and have 2 related login credentials. We don’t want or need the LLM to be aware of these credentials.

Mock third party systems

Here are two functions which, we’ll assume, are accessing a third party system using a username and password.

We have username and password going into the functions, but we don’t want to have that information stored in our messages, sent to the LLM, or tracked through telemetry.

Soon we’ll see how dependency injection can help.

# Mock functions accessing 3rd party systems

def weather_api_call(username: str, password: str, location: str) -> str:
    print(f"Accessing third party Weather System using username {username}")
    return "It's sunny and 40 degrees Celsius in Sydney, Australia."


def my_ticketing_system_availability(username: str, password: str, concert: str) -> bool:
    print(f"Accessing third party Ticketing System using username {username}")
    return False

Our credentials structure

Here we define a BaseContext class for account credentials. This will act as the base structure for dependency injection with information in these not being exposed to the LLM.

# Credentials class based on BaseContext
class ThirdPartyCredentials(BaseContext, BaseModel):
    username: str
    password: str

Agents for each system

An agent is created for each 3rd party system.

# Our two 3rd party system accessing agents
weather_agent = ConversableAgent(
    name="weather_agent",
    system_message="You are a Weather Agent, you can only get the weather.",
    description="Weather Agent solely used for getting weather.",
    llm_config={"config_list": config_list},
)

ticket_agent = ConversableAgent(
    name="ticket_agent",
    system_message="You are a Ticketing Agent, you can only get ticket availability.",
    description="Ticketing Agent solely used for getting ticket availability.",
    llm_config={"config_list": config_list},
)

# Our user proxy agent, used to execute the tools
user_proxy = UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    llm_config=False,
)

Creating credentials and tools with dependency injection

For each 3rd party system we create the credentials and a tool.

Take note that we are setting the credentials parameter as a ThirdPartyCredential and are injecting the respective credentials, e.g. Depends(weather_account).

The credentials parameters will not be visible to the LLM, it’ll be completely unaware of it.

# Weather API
weather_account = ThirdPartyCredentials(username="ag2weather", password="wbkvEehV1A")


@user_proxy.register_for_execution()
@weather_agent.register_for_llm(description="Get the weather for a location")
def get_weather(
    location: str,
    credentials: Annotated[ThirdPartyCredentials, Depends(weather_account)],
) -> str:
    # Access the Weather API using the credentials
    return weather_api_call(username=credentials.username, password=credentials.password, location=location)


# Ticketing System API
ticket_system_account = ThirdPartyCredentials(username="ag2tickets", password="EZRIVeVWvA")


@user_proxy.register_for_execution()
@ticket_agent.register_for_llm(description="Get the availability of tickets for a concert")
def tickets_available(
    concert_name: str,
    credentials: Annotated[ThirdPartyCredentials, Depends(ticket_system_account)],
) -> bool:
    return my_ticketing_system_availability(
        username=credentials.username, password=credentials.password, concert=concert_name
    )

Create Group Chat and run

# Create a GroupChat
groupchat = GroupChat(agents=[user_proxy, weather_agent, ticket_agent], messages=[], max_round=5)
manager = GroupChatManager(groupchat=groupchat, llm_config={"config_list": config_list})

# Here's our task for our LLM to help with
message = (
    "Start by getting the weather for Sydney, Australia, and follow that up by checking "
    "if there are tickets for the 'AG2 Live' concert."
)
user_proxy.initiate_chat(manager, message=message, max_turns=1)

Below is the output of the chat, broken up so we can understand what’s happening.

user_proxy (to chat_manager):

Start by getting the weather for Sydney, Australia, and follow that up by checking if there are tickets for the 'AG2 Live' concert.

--------------------------------------------------------------------------------

Next speaker: weather_agent


>>>>>>>> USING AUTO REPLY...
weather_agent (to chat_manager):

***** Suggested tool call (call_4ZWdbwuuojMxGXoxQDPzXpRl): get_weather *****
Arguments:
{"location": "Sydney, Australia"}
****************************************************************************

We can see that the LLM has suggested a tool call for get_weather and it only has location, credentials is not part of the LLM request or response.

--------------------------------------------------------------------------------

Next speaker: user_proxy


>>>>>>>> EXECUTING FUNCTION get_weather...
Call ID: call_4ZWdbwuuojMxGXoxQDPzXpRl
Input arguments: {'location': 'Sydney, Australia'}
Accessing third party Weather System using username ag2weather
user_proxy (to chat_manager):

***** Response from calling tool (call_4ZWdbwuuojMxGXoxQDPzXpRl) *****
It's sunny and 40 degrees Celsius in Sydney, Australia.
**********************************************************************

Similarly, when the tool’s function is called we can see that our view of it shows only the location parameter, with the credentials being injected automatically. Our function is printing out the username to prove that credentials are being passed in.

--------------------------------------------------------------------------------

Next speaker: ticket_agent


>>>>>>>> USING AUTO REPLY...
ticket_agent (to chat_manager):

***** Suggested tool call (call_MQVDpFTDcdNdKxH7LsikfR1z): tickets_available *****
Arguments:
{"concert_name":"AG2 Live"}
**********************************************************************************

--------------------------------------------------------------------------------

Next speaker: user_proxy


>>>>>>>> EXECUTING FUNCTION tickets_available...
Call ID: call_MQVDpFTDcdNdKxH7LsikfR1z
Input arguments: {'concert_name': 'AG2 Live'}
Accessing third party Ticketing System using username ag2tickets
user_proxy (to chat_manager):

***** Response from calling tool (call_MQVDpFTDcdNdKxH7LsikfR1z) *****
false
**********************************************************************

--------------------------------------------------------------------------------

The same occurred for the other 3rd party tool and function, with all credentials silently injected.

More Tool with Dependency Injection examples

See the Tools with Dependency Injection notebook.

API