Skip to content

Commit

Permalink
Removing tool use from Use-Cases/agent_chat (microsoft#2120)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekzhu authored Mar 23, 2024
1 parent b34a899 commit 9e34273
Showing 1 changed file with 8 additions and 246 deletions.
254 changes: 8 additions & 246 deletions website/docs/Use-Cases/agent_chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,258 +31,20 @@ One can also easily extend it by registering reply functions with the [`register
In the following code, we create an [`AssistantAgent`](../reference/agentchat/assistant_agent.md#assistantagent-objects) named "assistant" to serve as the assistant and a [`UserProxyAgent`](../reference/agentchat/user_proxy_agent.md#userproxyagent-objects) named "user_proxy" to serve as a proxy for the human user. We will later employ these two agents to solve a task.

```python
import os
from autogen import AssistantAgent, UserProxyAgent
from autogen.coding import DockerCommandLineCodeExecutor

# create an AssistantAgent instance named "assistant"
assistant = AssistantAgent(name="assistant")
config_list = [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]

# create a UserProxyAgent instance named "user_proxy"
user_proxy = UserProxyAgent(name="user_proxy")
```
#### Tool calling

Tool calling enables agents to interact with external tools and APIs more efficiently.
This feature allows the AI model to intelligently choose to output a JSON object containing
arguments to call specific tools based on the user's input. A tool to be called is
specified with a JSON schema describing its parameters and their types. Writing such JSON schema
is complex and error-prone and that is why AutoGen framework provides two high level function decorators for automatically generating such schema using type hints on standard Python datatypes
or Pydantic models:

1. [`ConversableAgent.register_for_llm`](../reference/agentchat/conversable_agent#register_for_llm) is used to register the function as a Tool in the `llm_config` of a ConversableAgent. The ConversableAgent agent can propose execution of a registered Tool, but the actual execution will be performed by a UserProxy agent.

2. [`ConversableAgent.register_for_execution`](../reference/agentchat/conversable_agent#register_for_execution) is used to register the function in the `function_map` of a UserProxy agent.

The following examples illustrate the process of registering a custom function for currency exchange calculation that uses type hints and standard Python datatypes:

1. First, we import necessary libraries and configure models using [`autogen.config_list_from_json`](/docs/FAQ#set-your-api-endpoints) function:

``` python
from typing import Literal

from pydantic import BaseModel, Field
from typing_extensions import Annotated

import autogen

config_list = autogen.config_list_from_json(
"OAI_CONFIG_LIST",
filter_dict={
"model": ["gpt-4", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"],
},
)
```

2. We create an assistant agent and user proxy. The assistant will be responsible for suggesting which functions to call and the user proxy for the actual execution of a proposed function:

``` python
llm_config = {
"config_list": config_list,
"timeout": 120,
}

chatbot = autogen.AssistantAgent(
name="chatbot",
system_message="For currency exchange tasks, only use the functions you have been provided with. Reply TERMINATE when the task is done.",
llm_config=llm_config,
)

# create a UserProxyAgent instance named "user_proxy"
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
)
```
# create an AssistantAgent instance named "assistant" with the LLM configuration.
assistant = AssistantAgent(name="assistant", llm_config={"config_list": config_list})

3. We define the function `currency_calculator` below as follows and decorate it with two decorators:
- [`@user_proxy.register_for_execution()`](../reference/agentchat/conversable_agent#register_for_execution) adding the function `currency_calculator` to `user_proxy.function_map`, and
- [`@chatbot.register_for_llm`](../reference/agentchat/conversable_agent#register_for_llm) adding a generated JSON schema of the function to `llm_config` of `chatbot`.

``` python
CurrencySymbol = Literal["USD", "EUR"]

def exchange_rate(base_currency: CurrencySymbol, quote_currency: CurrencySymbol) -> float:
if base_currency == quote_currency:
return 1.0
elif base_currency == "USD" and quote_currency == "EUR":
return 1 / 1.1
elif base_currency == "EUR" and quote_currency == "USD":
return 1.1
else:
raise ValueError(f"Unknown currencies {base_currency}, {quote_currency}")

# NOTE: for Azure OpenAI, please use API version 2023-12-01-preview or later as
# support for earlier versions will be deprecated.
# For API versions 2023-10-01-preview or earlier you may
# need to set `api_style="function"` in the decorator if the default value does not work:
# `register_for_llm(description=..., api_style="function")`.
@user_proxy.register_for_execution()
@chatbot.register_for_llm(description="Currency exchange calculator.")
def currency_calculator(
base_amount: Annotated[float, "Amount of currency in base_currency"],
base_currency: Annotated[CurrencySymbol, "Base currency"] = "USD",
quote_currency: Annotated[CurrencySymbol, "Quote currency"] = "EUR",
) -> str:
quote_amount = exchange_rate(base_currency, quote_currency) * base_amount
return f"{quote_amount} {quote_currency}"
```

Notice the use of [Annotated](https://docs.python.org/3/library/typing.html?highlight=annotated#typing.Annotated) to specify the type and the description of each parameter. The return value of the function must be either string or serializable to string using the [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps) or [`Pydantic` model dump to JSON](https://docs.pydantic.dev/latest/concepts/serialization/#modelmodel_dump_json) (both version 1.x and 2.x are supported).

You can check the JSON schema generated by the decorator `chatbot.llm_config["tools"]`:
```python
[{'type': 'function', 'function':
{'description': 'Currency exchange calculator.',
'name': 'currency_calculator',
'parameters': {'type': 'object',
'properties': {'base_amount': {'type': 'number',
'description': 'Amount of currency in base_currency'},
'base_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'USD',
'description': 'Base currency'},
'quote_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'EUR',
'description': 'Quote currency'}},
'required': ['base_amount']}}}]
# create a UserProxyAgent instance named "user_proxy" with code execution on docker.
code_executor = DockerCommandLineCodeExecutor()
user_proxy = UserProxyAgent(name="user_proxy", code_execution_config={"executor": code_executor})
```

Python decorators are functions themselves. If you do not want to use the
`@chatbot.register...` decorator syntax,
you can call the decorators as functions:

```python
# Register the function with the chatbot's llm_config.
currency_calculator = chatbot.register_for_llm(description="Currency exchange calculator.")(currency_calculator)

# Register the function with the user_proxy's function_map.
user_proxy.register_for_execution()(currency_calculator)
```

Alternatevely, you can also use `autogen.agentchat.register_function()` instead as follows:
```python
def currency_calculator(
base_amount: Annotated[float, "Amount of currency in base_currency"],
base_currency: Annotated[CurrencySymbol, "Base currency"] = "USD",
quote_currency: Annotated[CurrencySymbol, "Quote currency"] = "EUR",
) -> str:
quote_amount = exchange_rate(base_currency, quote_currency) * base_amount
return f"{quote_amount} {quote_currency}"

autogen.agentchat.register_function(
currency_calculator,
caller=chatbot,
executor=user_proxy,
description="Currency exchange calculator.",
)
```

4. Agents can now use the function as follows:
```python
user_proxy.initiate_chat(
chatbot,
message="How much is 123.45 USD in EUR?",
)
```
Output:
```
user_proxy (to chatbot):
How much is 123.45 USD in EUR?
--------------------------------------------------------------------------------
chatbot (to user_proxy):
***** Suggested tool Call: currency_calculator *****
Arguments:
{"base_amount":123.45,"base_currency":"USD","quote_currency":"EUR"}
********************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION currency_calculator...
user_proxy (to chatbot):
***** Response from calling function "currency_calculator" *****
112.22727272727272 EUR
****************************************************************
--------------------------------------------------------------------------------
chatbot (to user_proxy):
123.45 USD is equivalent to approximately 112.23 EUR.
...
TERMINATE
```

Use of Pydantic models further simplifies writing of such functions. Pydantic models can be used
for both the parameters of a function and for its return type. Parameters of such functions will
be constructed from JSON provided by an AI model, while the output will be serialized as JSON
encoded string automatically.

The following example shows how we could rewrite our currency exchange calculator example:

``` python
# defines a Pydantic model
class Currency(BaseModel):
# parameter of type CurrencySymbol
currency: Annotated[CurrencySymbol, Field(..., description="Currency symbol")]
# parameter of type float, must be greater or equal to 0 with default value 0
amount: Annotated[float, Field(0, description="Amount of currency", ge=0)]

def currency_calculator(
base: Annotated[Currency, "Base currency: amount and currency symbol"],
quote_currency: Annotated[CurrencySymbol, "Quote currency symbol"] = "USD",
) -> Currency:
quote_amount = exchange_rate(base.currency, quote_currency) * base.amount
return Currency(amount=quote_amount, currency=quote_currency)

autogen.agentchat.register_function(
currency_calculator,
agent=chatbot,
executor=user_proxy,
description="Currency exchange calculator.",
)
```

The generated JSON schema has additional properties such as minimum value encoded:
```python
[{'type': 'function', 'function':
{'description': 'Currency exchange calculator.',
'name': 'currency_calculator',
'parameters': {'type': 'object',
'properties': {'base': {'properties': {'currency': {'description': 'Currency symbol',
'enum': ['USD', 'EUR'],
'title': 'Currency',
'type': 'string'},
'amount': {'default': 0,
'description': 'Amount of currency',
'minimum': 0.0,
'title': 'Amount',
'type': 'number'}},
'required': ['currency'],
'title': 'Currency',
'type': 'object',
'description': 'Base currency: amount and currency symbol'},
'quote_currency': {'enum': ['USD', 'EUR'],
'type': 'string',
'default': 'USD',
'description': 'Quote currency symbol'}},
'required': ['base']}}}]
```

For more in-depth examples, please check the following:

- Currency calculator examples - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_function_call_currency_calculator.ipynb)

- Use Provided Tools as Functions - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_function_call.ipynb)

- Use Tools via Sync and Async Function Calling - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_function_call_async.ipynb)


## Multi-agent Conversations

### A Basic Two-Agent Conversation Example
Expand Down

0 comments on commit 9e34273

Please sign in to comment.