AutoGen > Tutorial > Tool Use
https://microsoft.github.io/autogen/0.2/docs/tutorial/tool-use
이번 장에서는 에이전트에게 프로그래밍의 기능을 부여한 code executors(코드 실행기)에 대해 살펴봤다.
AutoGen > Tutorial > Tool Use
https://velog.io/@heyggun/AutoGen-Code-Executors-UserProxyAgent-AssistantAgent
에이전트가 임의의 코드를 작성할 수 있다는 것은 유용하지만, 어떤 코드를 작성하게 할지 제어하는 것은 어려울 수 있다. 이때 Tool 이 등장한다.
Tool은 에이전트가 사용할 수 있는 미리 정의된 함수이다. 에이전트가 임의의 코드를 작성하는 대신, 툴을 호출하여 웹 검색, 계산 수행, 파일 읽기, 원격 API 호출 등의 작업을 수행할 수 있다. 어떤 툴을 에이전트에게 제공할지를 통제함으로써, 에이전트가 수행할 수 있는 작업도 제어할 수 있게 된다.
참고로 Tool 사용은 OpenAI 호환 툴 호출 API(OpenAI-compatible tool call API)를 지원하는 LLM에서만 가능하다
Tools은 일반적인 python 함수로 만들 수 있다.
예를 들어 하나의 연산만 수행할 수 있는 계산기 툴을 아래와 같이 만들어 보자.
from typing import Annotated, Literal
Operator = Literal["+", "-", "*", "/"]
def calculator(a:int, b:int, operator: Annotated[Operator, "operator"]) -> int:
if operator == "+":
return a+b
elif operator == "-":
return a-b
elif operator == "*":
return a*b
elif operator == "/":
return int(a/b)
else:
raise ValueError("Invalid operator")
위 함수는 세 개의 인자를 받는다 a와 b는 연산에 사용될 정수이고, operator는 수행할 연산을 나타낸다. 여기서 type hint를 사용해서 인자와 반환 값의 타입을 정의했다.
arguments(인자)와 return value(반환값)을 정의할 때는 항상 type hint(타입 힌트)를 사용하라. 타입 힌트는 툴의 사용법에 대해 에이저늩에게 유용한 정보를 제공한다.
툴을 만들었으면, 이제 대화에 참여하는 에이전트에게 그 툴을 **register(등록)** 할 수 있다.
import os
from autogen import ConversableAgent
from config import settings
api_key= settings.openai_api_key.get_secret_value()
llm_config = {
"config_list":
[
{
"model" : "gpt-4o-mini",
"api_key" : api_key,
}
]
}
assistant = ConversableAgent(
name = "Assistant",
system_message= """You are a helpful AI assistant. You can help with simple calculations.
Return 'TERMINATE' when the task is done""",
llm_config = llm_config,
)
user_proxy = ConversableAgent(
name="User",
llm_config=False,
is_termination_msg= lambda msg : msg.get("content") is not None and "TERMINATE" in msg["content"],
human_input_mode = "NEVER",
)
assistant.register_for_llm(name="calculator",
description="A simple calculator")(calculator)
user_proxy.register_for_execution(name="calculator")(calculator)
"""
<autogen.tools.tool.Tool at 0x115679810>
"""
위 코드에서는 calculator 함수를 tool로 등록해서, 어시스턴트 에이전트와 유저 프록시 에이전트가 사용할 수 있또록 했다. 또한 어시스턴트 에이전트가 툴의 용도를 이해할 수 있도록 **툴의 이름 (name=calculator)과 설명(description)도 함께 제공한다.
팁:
툴에는 항상 명확하고 간결한 설명을 제공해야 한다.
이는 에이전트 기반의 LLM이 툴의 용도를 이해하는데 큰 도움이 된다.
코드 실행기와 마찬가지로, 도구는 대화에서 유용하게 사용되기 위해 최소한 두 개의 에이전트에 등록되어야 한다
register_for_llm을 통해 도구의 시그니처를 등록한 에이전트는 해당 도구를 call(호출) 할수 있고,
register_for_execution을 통해 도구의 함수 객체를 등록한 에이전트는 도구의 기능을 execute(실행) 할 수 있다.
또는 autogen.register_function 함수를 사용하면 두 에이전트 모두에 한 번에 도구를 등록할 수 있다.
도구가 등록되면, 이제 대화 중에 이를 사용할 수 있다.
아래 코드에서는 assistant 에게 calcuator 도구를 사용해서 산술 계산을 수행하도록 요청하고 있다.
chat_result = user_proxy.initiate_chat(assistant, message="What is (44232+13312 / (232-32)) *5?")
User (to Assistant):
What is (44232+13312 / (232-32)) *5?
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_iqtFUDyewhq7CPCEAoSQ98lG): calculator *****
Arguments:
{"a": 13312, "b": 200, "operator": "/"}
***************************************************************************
***** Suggested tool call (call_iWFBO6P468D4ScbRaakewybm): calculator *****
Arguments:
{"a": 232, "b": 32, "operator": "-"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_iqtFUDyewhq7CPCEAoSQ98lG
Input arguments: {'a': 13312, 'b': 200, 'operator': '/'}
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_iWFBO6P468D4ScbRaakewybm
Input arguments: {'a': 232, 'b': 32, 'operator': '-'}
User (to Assistant):
***** Response from calling tool (call_iqtFUDyewhq7CPCEAoSQ98lG) *****
66
**********************************************************************
--------------------------------------------------------------------------------
***** Response from calling tool (call_iWFBO6P468D4ScbRaakewybm) *****
200
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_DMM8e04s66S9Pc5bUrKbkzJy): calculator *****
Arguments:
{"a":44232,"b":66,"operator":"+"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_DMM8e04s66S9Pc5bUrKbkzJy
Input arguments: {'a': 44232, 'b': 66, 'operator': '+'}
User (to Assistant):
***** Response from calling tool (call_DMM8e04s66S9Pc5bUrKbkzJy) *****
44298
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_aQMfX2XwwybScjiWADeqqLmQ): calculator *****
Arguments:
{"a":44298,"b":5,"operator":"*"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_aQMfX2XwwybScjiWADeqqLmQ
Input arguments: {'a': 44298, 'b': 5, 'operator': '*'}
User (to Assistant):
***** Response from calling tool (call_aQMfX2XwwybScjiWADeqqLmQ) *****
221490
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
The result of the expression \((44232 + \frac{13312}{(232 - 32)}) \times 5\) is \(221490\).
TERMINATE
--------------------------------------------------------------------------------
>>>>>>>> TERMINATING RUN (d18079ce-6608-47bf-a230-61099af9478e): Termination message condition on agent 'User' met
교차검증 해봤을 때
답이 221490으로 맞는 것을 볼 수 있다.
(44232+ int(13312 / (232-32))) *5
"""
211490
"""
OpenAI의 Tool User API에 익숙하다면, 왜 tool schema를 직접 생성하지 않는지에 대한 의문이 생길 수 있다. 사실 tool schema는 function signature와 type hints로부터 자동으로 생성된다.
에이전트의 `llm_config 속성을 확인하면 생성된 도구 스키마를 볼 수 있다.
assistant.llm_config['tools']
"""
[{'type': 'function',
'function': {'description': 'A simple calculator',
'name': 'calculator',
'parameters': {'type': 'object',
'properties': {'a': {'type': 'integer', 'description': 'a'},
'b': {'type': 'integer', 'description': 'b'},
'operator': {'enum': ['+', '-', '*', '/'],
'type': 'string',
'description': 'operator'}},
'required': ['a', 'b', 'operator']}}}]
"""
tool schema는 function signature(함수 시그니처), type hints(타입 힌트), description(설명)으로부터 자동으로 생성된 것을 확인할 수 있다. 이 때문에 타입 힌트를 사용하고 도구에 대해 명확한 설명을 제공하는 것이 중요하다.
LLM은 이를 바탕으로 도구의 사용 방식을 이해한다.
또한 보다 복잡한 type schema를 제공하기 위해, Pydantic 모델을 타입 힌트로 사용할 수도 있다. 아래 예시에는 pydantic 모델을 사용해서 계산기의 입력값을 정의하는 것이다
from pydantic import BaseModel, Field
class CalculatorInput(BaseModel):
a: Annotated[int, Field(description="The first number.")]
b: Annotated[int, Field(descirption="The second number.")]
operator: Annotated[Operator, Field(description="The operator .")]
def calculaotr(input: Annotated[CalculatorInput, "Input to the calculator."]) -> int:
if input.operator == "+":
return input.a + input.b
elif input.operator == "-":
return input.a - input.b
elif input.operator == "*":
return input.a * input.b
elif input.operator == "/":
return int(input.a / input.b)
else:
raise ValueError("Invalid operator")
앞과 마찬가지로 calcuator 라는 이름으로 도구를 에이전트에 등록한다.
💡 팁: 같은 이름으로 도구를 등록하면 이전에 등록된 도구가 덮어쓰기(override) 된다.
assistant.register_for_llm(name="calculator",
description="A calculator tool that accepts nested expression as input")(calculator)
user_proxy.register_for_execution(name="calculator")(calculator)
"""
<autogen.tools.tool.Tool at 0x115679810>
10900
User (to Assistant):
What is (44232+13312 / (232-32)) *5?
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_iqtFUDyewhq7CPCEAoSQ98lG): calculator *****
Arguments:
{"a": 13312, "b": 200, "operator": "/"}
***************************************************************************
***** Suggested tool call (call_iWFBO6P468D4ScbRaakewybm): calculator *****
Arguments:
{"a": 232, "b": 32, "operator": "-"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_iqtFUDyewhq7CPCEAoSQ98lG
Input arguments: {'a': 13312, 'b': 200, 'operator': '/'}
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_iWFBO6P468D4ScbRaakewybm
Input arguments: {'a': 232, 'b': 32, 'operator': '-'}
User (to Assistant):
***** Response from calling tool (call_iqtFUDyewhq7CPCEAoSQ98lG) *****
66
**********************************************************************
--------------------------------------------------------------------------------
***** Response from calling tool (call_iWFBO6P468D4ScbRaakewybm) *****
200
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_DMM8e04s66S9Pc5bUrKbkzJy): calculator *****
Arguments:
{"a":44232,"b":66,"operator":"+"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_DMM8e04s66S9Pc5bUrKbkzJy
Input arguments: {'a': 44232, 'b': 66, 'operator': '+'}
User (to Assistant):
***** Response from calling tool (call_DMM8e04s66S9Pc5bUrKbkzJy) *****
44298
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_aQMfX2XwwybScjiWADeqqLmQ): calculator *****
Arguments:
{"a":44298,"b":5,"operator":"*"}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_aQMfX2XwwybScjiWADeqqLmQ
Input arguments: {'a': 44298, 'b': 5, 'operator': '*'}
User (to Assistant):
***** Response from calling tool (call_aQMfX2XwwybScjiWADeqqLmQ) *****
221490
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
The result of the expression \((44232 + \frac{13312}{(232 - 32)}) \times 5\) is \(221490\).
TERMINATE
--------------------------------------------------------------------------------
>>>>>>>> TERMINATING RUN (d18079ce-6608-47bf-a230-61099af9478e): Termination message condition on agent 'User' met
221490
[{'type': 'function',
'function': {'description': 'A simple calculator',
'name': 'calculator',
'parameters': {'type': 'object',
'properties': {'a': {'type': 'integer', 'description': 'a'},
'b': {'type': 'integer', 'description': 'b'},
'operator': {'enum': ['+', '-', '*', '/'],
'type': 'string',
'description': 'operator'}},
'required': ['a', 'b', 'operator']}}}]
/Users/geonheekim/Library/Caches/pypoetry/virtualenvs/user-prediction-jY4gRI11-py3.11/lib/python3.11/site-packages/autogen/agentchat/conversable_agent.py:3467: UserWarning: Function 'calculator' is being overridden.
warnings.warn(f"Function '{tool_sig['function']['name']}' is being overridden.", UserWarning)
/Users/geonheekim/Library/Caches/pypoetry/virtualenvs/user-prediction-jY4gRI11-py3.11/lib/python3.11/site-packages/autogen/agentchat/conversable_agent.py:3365: UserWarning: Function 'calculator' is being overridden.
warnings.warn(f"Function '{name}' is being overridden.", UserWarning)
"""
도구 스키마가 새로운 타입 스키마를 반영하도록 업데이트 된 것을 확인할 수 있다.
assistant.llm_config["tools"]
"""
[{'type': 'function',
'function': {'description': 'A calculator tool that accepts nested expression as input',
'name': 'calculator',
'parameters': {'type': 'object',
'properties': {'input': {'properties': {'a': {'description': 'The first number.',
'title': 'A',
'type': 'integer'},
'b': {'descirption': 'The second number.',
'title': 'B',
'type': 'integer'},
'operator': {'description': 'The operator .',
'enum': ['+', '-', '*', '/'],
'title': 'Operator',
'type': 'string'}},
'required': ['a', 'b', 'operator'],
'title': 'CalculatorInput',
'type': 'object',
'description': 'Input to the calculator.'}},
'required': ['input']}}}]
"""
이제 대화에서 이 도구를 사용해보자.
chat_result = user_proxy.initiate_chat(assistant, message="What is (1423 - 123) / 3 + (32 + 23) * 5?")
User (to Assistant):
What is (1423 - 123) / 3 + (32 + 23) * 5?
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_uS1MoGvOykLHpSOPYczzQSY5): calculator *****
Arguments:
{"input": {"a": 1423, "b": 123, "operator": "-"}}
***************************************************************************
***** Suggested tool call (call_omZSw7dVuvROKKVEzaXHFDK6): calculator *****
Arguments:
{"input": {"a": 32, "b": 23, "operator": "+"}}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_uS1MoGvOykLHpSOPYczzQSY5
Input arguments: {'input': {'a': 1423, 'b': 123, 'operator': '-'}}
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_omZSw7dVuvROKKVEzaXHFDK6
Input arguments: {'input': {'a': 32, 'b': 23, 'operator': '+'}}
User (to Assistant):
***** Response from calling tool (call_uS1MoGvOykLHpSOPYczzQSY5) *****
1300
**********************************************************************
--------------------------------------------------------------------------------
***** Response from calling tool (call_omZSw7dVuvROKKVEzaXHFDK6) *****
55
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_tum5tOUmOt00enSgYFv4nx2J): calculator *****
Arguments:
{"input":{"a":1300,"b":3,"operator":"/"} }
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_tum5tOUmOt00enSgYFv4nx2J
Input arguments: {'input': {'a': 1300, 'b': 3, 'operator': '/'}}
User (to Assistant):
***** Response from calling tool (call_tum5tOUmOt00enSgYFv4nx2J) *****
433
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_2DHKQYFyvE4o2fVKbQQYaR13): calculator *****
Arguments:
{"input":{"a":55,"b":5,"operator":"*"}}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_2DHKQYFyvE4o2fVKbQQYaR13
Input arguments: {'input': {'a': 55, 'b': 5, 'operator': '*'}}
User (to Assistant):
***** Response from calling tool (call_2DHKQYFyvE4o2fVKbQQYaR13) *****
275
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
***** Suggested tool call (call_a2vRYAfHYHzgsV5EuBKhJoHo): calculator *****
Arguments:
{"input":{"a":433,"b":275,"operator":"+"}}
***************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION calculator...
Call ID: call_a2vRYAfHYHzgsV5EuBKhJoHo
Input arguments: {'input': {'a': 433, 'b': 275, 'operator': '+'}}
User (to Assistant):
***** Response from calling tool (call_a2vRYAfHYHzgsV5EuBKhJoHo) *****
708
**********************************************************************
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Assistant (to User):
The result of the expression \((1423 - 123) / 3 + (32 + 23) * 5\) is 708.
TERMINATE
--------------------------------------------------------------------------------
>>>>>>>> TERMINATING RUN (dffbb03d-5742-4901-abfe-d82346fb109d): Termination message condition on agent 'User' met
708의 답이 나왔는데, 이를 검증해보면
int((1423 - 123) / 3) + (32 + 23) * 5
"""
708
"""
708이 나온 것을 볼 수 있다.
(도구 사용 및 코드 실행을 단일 에이전트 내에서 숨기는 방법)
경우에 따라 도구 사용을 단일 에이전트 내부에서 숨기는 것이 더 적절할 때가 있다
.즉, 도구 호출 및 도구 응답 메시지를 에이전트 외부에서 보이지 않도록 처리하고, 에이전트는 도구 사용을 일종의 internal monologue(내적 독백) 형태로 처리한 후 외부에는 결과는 응답하는 방식이다.
예를 들어, OpenAI의 Assistant처럼 내부적으로 내장 도구를 실행하는 에이전트를 만들고 싶을 수도 있다.
이런 기능을 구현하려면 nested chats(중첩 채팅) 을 사용할 수 있다.
nested chats(중첩 채팅)은 에이전트 내에서 도구를 호출하고 실행할 수 있는 internal monologues(내적 독백)을 생성할 수 있게 해준다.
이는 코드 실행에도 동일하게 적용된다.
도구 사용에 대한 예시는 nested chats for tool use를 참고한다. 추후에 포스팅에 정리할 예정이다.
nested chats for tool use
https://microsoft.github.io/autogen/0.2/docs/notebooks/agentchat_nested_chats_chess/
이 챕터에서는 도구를 생성하고, 등록하고, 사용하는 방법을 알아봤다.
도구를 사용하면 에이전트가 임의의 코드를 작성하지 않고도 동작을 수행할 수 있다.
다음 챕터에서는 conversation patterns(대화 패턴) 을 소개하고, 대화 결과를 어떻게 활용할 수 있을지를 다룰 예정이다.