구조화된 도구(Structured Tools) 소개
요약
본 글은 기존의 단일 문자열 입력에 국한되었던 에이전트 도구 사용 방식의 한계를 극복하고, 구조화된 도구(Structured Tool)를 도입하는 방법을 설명합니다. 이를 통해 에이전트는 임의의 개수와 유형을 가진 복잡한 입력을 처리할 수 있게 되었으며, 이는 더 강력하고 적응성 높은 애플리케이션 구축을 가능하게 합니다.
핵심 포인트
- 기존 도구는 단일 문자열 입력에 제한적이었으나, 구조화된 도구로 확장됨.
- 구조화된 도구는 name, description 외에도 args_schema를 통해 복잡한 입력을 받음.
- 다중 액션(multi-action) 에이전트 프레임워크가 도입되어 여러 행동 계획 가능.
- 이는 언어 모델과 도구 간의 더 정교하고 다면적인 상호 작용을 구현함.
요약: 더 복잡한 도구 사용을 가능하게 하는 새로운 추상화 방식을 도입합니다. 이전 도구들은 단일 문자열 입력을 받았지만, 새로운 도구들은 임의의 개수와 임의의 유형을 가진 입력들을 받을 수 있습니다. 또한 이러한 새로운 유형의 도구들과 잘 작동하는 새로운 에이전트 클래스도 소개합니다.**
중요 링크:
2022년 11월 LangChain을 처음 출시했을 때, 에이전트와 도구 활용은 저희 설계의 중심 역할을 했습니다. 저희는 프롬프팅 프레임워크에서 도구 사용을 전면에 내세운 혁신적인 논문인 ReAct에 기반하여 최초의 체인 중 하나를 구축했습니다.
초기에는 도구 사용이 단순했습니다. 모델은 두 개의 문자열을 생성합니다:
- 도구 이름
- 선택된 도구를 위한 입력 문자열
이러한 접근 방식은 에이전트를 턴당 하나의 도구로 제한했으며, 해당 도구의 입력은 단일 문자열로만 제한되었습니다. 이러한 한계는 주로 모델의 제약 사항 때문이었으며, 모델들은 심지어 이러한 기본적인 작업을 능숙하게 수행하는 데 어려움을 겪었습니다. 여러 도구를 선택하거나 복잡한 스키마를 채우는 등 더 복잡한 작업을 안정적으로 실행하는 것은 불가능에 가까웠습니다.
하지만 text-davinci-003, gpt-3.5-turbo, 그리고 gpt-4와 같은 더욱 발전된 언어 모델들의 급속한 개발은 사용 가능한 모델들이 신뢰성 있게 달성할 수 있는 수준을 높였습니다. 이는 저희로 하여금 LangChain의 에이전트 프레임워크 내 도구 사용에 대한 한계를 재평가하도록 만들었습니다.
올해 초, 저희는 '다중 액션(multi-action)' 에이전트 프레임워크를 도입했는데, 여기서 에이전트는 에이전트 실행기(agent executor)의 각 단계에서 수행할 여러 행동을 계획할 수 있습니다. 이러한 성공에 힘입어, 이제 단일 문자열 입력 제약에서 벗어나 구조화된 도구 지원을 자랑스럽게 제공합니다!
구조화된 도구는 언어 모델과 도구 간의 더 복잡하고 다면적인 상호 작용을 가능하게 하여, 혁신적이고 적응성이 뛰어나며 강력한 애플리케이션을 구축하는 것을 더욱 쉽게 만듭니다.
'구조화된 도구(Structured Tool)'란 무엇인가요?
구조화된 도구(Structured Tool)란 무엇인가요?
구조화된 도구는 에이전트가 수행할 수 있는 행동을 나타냅니다. 이는 제공하는 모든 함수를 감싸서 에이전트가 쉽게 인터페이스 할 수 있도록 합니다. 구조화된 도구 객체는 다음 요소들로 정의됩니다:
name
: 에이전트에게 어떤 도구를 선택해야 하는지 알려주는 레이블입니다. 예를 들어, “GetCurrentWeather”라는 이름의 도구는 에이전트에게 현재 날씨를 찾는 용도임을 알려줍니다.
description
: 에이전트가 언제 그리고 왜 이 도구를 사용해야 하는지를 설명하는 짧은 사용 설명서입니다.
args_schema
: 에이전트를 위해 도구의 인터페이스를 전달합니다. 이는 일반적으로 감싸진 함수의 시그니처(signature)에서 가져오며, 도구 입력에 대한 추가적인 유효성 검사 로직을 허용합니다.
_run
및 _arun 함수: 이들은 도구의 내부 작동 방식을 정의합니다. 현재 시간을 반환하는 것과 같은 간단한 것이거나 메시지를 보내거나 로봇을 제어하는 것과 같이 더 복잡할 수 있습니다.
도구의 name은 고유 식별자입니다. 좋은 이름은 무엇을 하는지 모호하지 않게 전달하므로, “GetCurrentWeather”라는 도구는 “GCTW”보다 훨씬 유용합니다. 만약 도구의 이름이 불분명하다면, 에이전트에게도 그럴 가능성이 높습니다. 만약 여러 도구를 에이전트가 사용하도록 제공한다면, 이 이름은 그들의 관계에 대한 정보도 제공할 수 있습니다. 예를 들어, “AmazonSearch”와 “AmazonCurrentBalance”, 그리고 “NikeShoppingCart”라는 도구들이 있다면, 에이전트는 설명서를 읽지 않아도 처음 두 개는 관련되어 있다는 것을 추론할 수 있습니다.
description은 도구를 사용하는 방법에 대한 더 상세한 지침을 제공합니다. 좋은 설명은 간결하면서도 도구가 무엇을 하는지 효과적으로 전달해야 합니다. 필요하다면 짧은 예시(또는 반례)를 제공하는 공간으로도 활용될 수 있습니다.
args_schema는 에이전트에게 입력되어야 할 인자들(및 그 타입 정보)을 정의하는 Pydantic BaseModel입니다. 이 모델은 두 가지 주요 역할을 합니다. 첫째, 에이전트로부터 어떤 정보가 필요한지 전달합니다. 둘째, 도구의 내부 기능을 실행하기 전에 해당 입력을 검증합니다.
마지막으로, _run과 동기화된 비동기(async) _arun은...
메서드는 도구의 로직을 정의합니다. 여기에는 산술 연산부터 API 요청, 다른 LLM Chain 호출까지 무엇이든 넣을 수 있습니다.
새로운 구조화된 도구 (New Structured Tools)
이 새로운 기본 클래스 외에도, 다음 두 가지 새로운 도구를 출시하며, 이들은 모두 이 구조화된 도구 클래스를 상속받습니다.
- 파일 관리(File management) - 쓰기(write), grep, 이동(move), 복사(copy), list_dir, find를 포함하여 원하는 모든 파일 시스템 작업에 대한 툴킷입니다.
- 웹 브라우저(Web Browser) - 이전에 문서 로더용 브라우저는 있었지만, 이제 에이전트가 웹사이트로 이동하고, 클릭하고, 양식을 제출하고, 데이터를 조회할 수 있게 해주는 공식적인 상태 저장(stateful) PlayWright 브라우저 툴킷을 출시합니다.
모든 도구(오래된 것과 새로운 것 모두) 목록은 여기의 문서를 참조하십시오.
자체 구조화된 도구 구현하기 (Implementing your own Structured Tools)
시작하는 가장 빠른 방법은 StructuredTool.from_function(your_callable) 생성자를 호출하는 것입니다.
예를 들어, requests 라이브러리를 통해 Hugging Face 모델과 상호 작용할 도구를 만들고 싶다고 가정해 봅시다.
import requests
from langchain.tools.base import StructuredTool
API_KEY = "<MY-API-KEY>"
def get_huggingface_models(
path: Optional[str] = None, query_params: Optional[dict] = None
) -> dict:
"""Tool that calls GET on <https://huggingface.co/models*> apis. Valid params include "search":"search", "author":"author", "filter":"filter" and "sort":"sort"."""
base_url = "<https://huggingface.co/api/models>"
headers = {"authorization": f"Bearer {API_KEY}"}
result = requests.get(base_url + (path or ""), params=query_params, headers=headers)
return result.json()
get_huggingface_models_tool = StructuredTool.from_function(get_huggingface_models)
models = get_huggingface_models_tool.run({"query_params": {"search": "gpt-j"}})
print(models)
내부적으로, 이는 함수 시그니처에서 args_schema를 추론합니다. 이를 통해 에이전트에게 검색을 위한 쿼리 매개변수뿐만 아니라 다른 자식 엔드포인트를 호출하기 위한 경로 매개변수를 제공할 수 있음을 알려줍니다.
도구 정의에 대해 더 많은 제어력을 원한다면, BaseTool을 직접 상속받아 사용할 수 있습니다. 예를 들어, API 키를 환경 변수에서 자동으로 로드하고 싶다고 가정해 봅시다.
from typing import Optional, Type
import aiohttp
import requests
from langchain.callbacks.manager import (
AsyncCallbackManagerForToolRun,
CallbackManagerForToolRun,
)
from langchain.tools import BaseTool
from pydantic import BaseModel, BaseSettings, Field
class GetHuggingFaceModelsToolSchema(BaseModel):
path: str = Field(default="", description="the api path")
query_params: Optional[dict] = Field(
default=None, description="Optional search parameters"
)
class GetHuggingFaceModelsTool(BaseTool, BaseSettings):
"""My custom tool."""
name: str = "get_huggingface_models"
description: str = "<https://huggingface.co/models*>에 GET을 호출하는 도구입니다. 유효한 매개변수에는 \"search\":\"search\", \"author\":\"author\", \"filter\":\"filter\", 그리고 \"sort\":\"sort\"가 포함됩니다."
args_schema: Type[GetHuggingFaceModelsToolSchema] = GetHuggingFaceModelsToolSchema
base_url: str = "<https://huggingface.co/api/models>"
api_key: str = Field(..., env="HUGGINGFACE_API_KEY")
@property
def _headers(self) -> dict:
return {"authorization": f"Bearer {self.api_key}"}
def _run(
self,
path: str = "",
query_params: Optional[dict] = None,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> dict:
"""도구 실행"""
result = requests.get(
self.base_url + path, params=query_params, headers=self._headers
)
return result.json()
async def _arun(
self,
path: str = "",
query_params: Optional[dict] = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> dict:
"""도구 비동기 실행."""
async with aiohttp.ClientSession() as session:
async with session.get(
self.base_url + path, params=query_params, headers=self._headers
) as response:
return await response.json()
get_models_tool = GetHuggingFaceModelsTool()
models = get_models_tool.run({"query_params": {"search": "gpt-j"}})\n\n## 구조화된 도구(Structured Tools)는 어떻게 사용하나요?\n\n저희는 이러한 구조화된 도구와 네이티브하게 작동하는 새로운 `StructuredChatAgent`를 추가했습니다. 자세한 내용은 이 페이지에서 확인하실 수 있습니다.\n\n기존 에이전트들의 기본 프롬프트 및 출력 파서에 제한 사항이 있어, 별도의 사용자 정의 없이는 구조화된 도구와 효과적으로 작동하지 않습니다.\n\n시작하려면 다음 코드 스니펫을 사용하여 구조화된 채팅 에이전트 실행기(executor)를 인스턴스화할 수 있습니다:\n\n`from langchain.agents import initialize_agent, AgentType`\n\n`from langchain.chat_models import ChatAnthropic`\n\ntools = [] # 여기에 도구를 추가하세요\n\nllm = ChatAnthropic(temperature=0) # 또는 다른 LLM을 사용하세요\n\nagent_chain = initialize_agent(tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION)\n\n이러한 도구들은 또한 `langchain.experimental`의 `AutoGPT` 에이전트와도 호환됩니다.\n\n## FAQ\n\n**질문: 기존 에이전트에 구조화된 도구를 사용할 수 있나요?**\n\n답변: 만약 구조화된 도구가 하나의 문자열 인자(string argument)를 받는다면: **예**, 여전히 기존 에이전트와 작동합니다. 하지만, 하나 이상의 인자를 받는 구조화된 도구는 다음 에이전트들과 추가적인 사용자 정의 없이는 직접적으로 호환되지 않습니다:\n\n`zero-shot-react-description`\n\n`react-docstore`\n\n`self-ask-with-search`\n\n`conversational-react-description`\n\n`chat-zero-shot-react-description`\n\n`chat-conversational-react-description`\n\n**질문: 여전히 문자열 도구(string Tools)를 만들 수 있나요?**\n\n답변: `Tool` 생성자와 `@tool` 데코레이터를 사용하여 간단한 문자열 도구를 정의할 수 있습니다. `BaseTool` 클래스를 상속받고 단일 문자열 인자를 받는 도구들은 여전히 문자열 도구로 처리됩니다.\n\n**질문: 이전에 정의된 문자열 BaseTool을 구조화된 도구를 위해 새로 구축된 에이전트에서 사용할 수 있나요?**\n\n답변: 네! 구조화된 도구는 새로운 에이전트 실행기를 필요로 하지 않으며, 이전 도구들은 미래 호환성(forwards compatible)을 가집니다. 원래의 `Tool` 클래스는 `StructuredTool`과 동일한 기본 클래스를 공유합니다.
, 즉 여러분의 도구들이 별도의 수정 없이 바로 작동해야 한다는 의미입니다.
JSON 직렬화된 문자열 입력을 예상하는 도구들은 최신 에이전트의 출력 파서와 상호 운용성을 위해 일부 수정이 필요할 수 있습니다. 또는 더 복잡한 인터페이스에 대한 향상된 지원을 제공할 새로운 형식으로 업데이트될 수도 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 LangChain Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기