LlamaIndex 에이전트 도구

LlamaIndex 에이전트 도구 (Tools)

에이전트가 "할 수 있는 일"을 정의하는 게 바로 도구예요. 도구 추상화가 제대로 갖춰져 있어야 LlamaIndex의 에이전틱 시스템을 만들 수 있어요. 도구 묶음을 정의하는 건 API 인터페이스를 정의하는 것과 비슷한데, 한 가지 차이는 이 도구들이 사람이 아니라 에이전트를 위해 쓰인다는 점이에요. LlamaIndex에서는 Tool 하나를 정의할 수도 있고, 그 아래 여러 함수를 묶은 **ToolSpec**을 정의할 수도 있어요.

함수 호출(function calling)을 쓰는 에이전트나 LLM에서는, 어떤 도구를 선택할지(그리고 그 도구에 어떤 인자를 쓸지)가 **도구 이름(name)**과 **도구의 용도·인자에 대한 설명(description)**에 크게 좌우돼요. 이 파라미터들을 다듬는 데 시간을 쓰면, LLM이 도구를 호출하는 방식이 크게 달라질 수 있어요.

Tool은 아주 일반적인 인터페이스를 구현해요. __call__을 정의하고 이름·설명·함수 스키마 같은 기본 메타데이터를 반환하면 돼요.

LlamaIndex가 제공하는 몇 가지 도구 유형이 있어요.

  • FunctionTool: 사용자가 정의한 함수를 손쉽게 Tool로 바꿔주는 도구. 함수 스키마를 자동으로 추론하거나, 여러 부분을 커스터마이즈할 수 있어요.
  • QueryEngineTool: 기존 쿼리 엔진을 감싸는 도구. 참고로 에이전트 추상화가 BaseQueryEngine을 상속하므로 이 도구는 다른 에이전트도 감쌀 수 있어요.
  • 커뮤니티가 기여한 ToolSpecs: Gmail 같은 단일 서비스 주변에 하나 이상의 도구를 정의한 묶음.
  • 도구에서 대량 데이터를 반환할 때 처리해 주는 유틸리티 도구.

출처: 공식문서

FunctionTool

함수 도구는 기존 함수(동기·비동기 모두 지원돼요!)를 감싸는 단순한 래퍼예요.

from llama_index.core.agent.workflow import ReActAgent
from llama_index.core.tools import FunctionTool




def get_weather(location: str) -> str:
    """Usfeful for getting the weather for a given location."""
    ...




tool = FunctionTool.from_defaults(
    get_weather,
    # async_fn=aget_weather,  # optional!
)


agent = ReActAgent(llm=llm, tools=tools)

더 좋은 함수 정의를 위해 Annotated 타입으로 인자 설명을 지정할 수도 있어요.

from typing import Annotated




def get_weather(
    location: Annotated[
        str, "A city name and state, formatted like '<name>, <state>'"
    ],
) -> str:
    """Useful for getting the weather for a given location."""
    ...




tool = FunctionTool.from_defaults(get_weather)

기본적으로 도구 이름은 함수 이름이 되고, docstring이 도구 설명이 돼요. 물론 이걸 덮어쓸 수도 있어요.

tool = FunctionTool.from_defaults(get_weather, name="...", description="...")

QueryEngineTool

QueryEngineTool을 쓰면 어떤 쿼리 엔진이든 도구로 바꿀 수 있어요.

from llama_index.core.tools import QueryEngineTool


tool = QueryEngineTool.from_defaults(
    query_engine, name="...", description="..."
)

Tool Specs

LlamaHub 🦙를 통해 풍부한 도구·툴 스펙 묶음도 제공돼요.

Tool spec은 함께 쓰라고 만든 도구 묶음이라고 생각하면 돼요. 보통 Gmail처럼 단일 인터페이스/서비스를 다루는 유용한 도구들을 담아요.

에이전트에서 쓰려면 해당 tool spec 통합 패키지를 설치하면 돼요.

pip install llama-index-tools-google

그리고 이렇게 사용해요.

from llama_index.core.agent.workflow import FunctionAgent
from llama_index.tools.google import GmailToolSpec


tool_spec = GmailToolSpec()
agent = FunctionAgent(llm=llm, tools=tool_spec.to_tool_list())

커뮤니티가 기여한 tool spec의 전체 목록은 LlamaHub에서 확인할 수 있어요.

유틸리티 도구

API를 직접 조회하면 엄청난 양의 데이터가 반환되는 경우가 많아요. 그대로면 LLM의 컨텍스트 창을 넘치게 하거나, 최소한 사용하는 토큰 수를 불필요하게 늘리죠.

이 문제를 다루기 위해 LlamaHub Tools에 "유틸리티 도구" 묶음이 마련돼 있어요. 유틸리티 도구는 Gmail·Notion 같은 특정 서비스에 묶여 있지 않고, 기존 도구의 능력을 확장해 주는 역할을 해요. 특히 API 요청에서 반환된 데이터를 캐시/인덱싱하고 조회해야 하는 흔한 패턴을 추상화해 줘요.

OnDemandLoaderTool

이 도구는 기존의 LlamaIndex 데이터 로더(BaseReader 클래스)를 에이전트가 사용할 수 있는 도구로 바꿔줘요. 도구를 호출할 때데이터 로더의 load_data를 실행하는 데 필요한 모든 파라미터와 함께 자연어 쿼리 문자열을 넘길 수 있어요. 실행 중에는 데이터 로더에서 데이터를 로드하고, (예를 들어 벡터 스토어로) 인덱싱한 뒤 "온디맨드(on-demand)"로 조회해요. 이 세 단계가 모두 단일 도구 호출 안에서 이뤄져요.

API 데이터를 직접 로드·인덱싱하는 방법을 고민하는 것보다 이걸 쓰는 게 나은 경우가 많아요. 데이터를 재사용하고 싶을 수도 있지만, 대부분은 어떤 API 호출이든 프롬프트 창 제한을 추상화할 만한 임시(ad-hoc) 인덱스가 필요하기 때문이에요.

용법 예시는 아래와 같아요.

pip install llama-index-readers-wikipedia
from llama_index.readers.wikipedia import WikipediaReader
from llama_index.core.tools.ondemand_loader_tool import OnDemandLoaderTool


tool = OnDemandLoaderTool.from_defaults(
    reader,
    name="Wikipedia Tool",
    description="A tool for loading data and querying articles from Wikipedia",
)

LoadAndSearchToolSpec

LoadAndSearchToolSpec은 기존 도구를 입력으로 받아요. tool spec이므로 to_tool_list를 구현하는데, 이 함수를 호출하면 load 도구와 search 도구 두 개가 반환돼요.

load 도구는 내부 도구를 실행하고 출력을(기본적으로 벡터 인덱스로) 인덱싱해요. search 도구는 쿼리 문자열을 입력받아 내부 인덱스를 조회해요.

기본적으로 대량의 데이터를 반환하는 API 엔드포인트에 유용해요. 예를 들어 WikipediaToolSpec은 기본적으로 위키피디아 페이지 전체를 반환해서, 대부분의 LLM 컨텍스트 창을 쉽게 넘치게 해요.

예시는 아래와 같아요.

pip install llama-index-tools-wikipedia
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.tools.tool_spec.load_and_search import (
    LoadAndSearchToolSpec,
)
from llama_index.tools.wikipedia import WikipediaToolSpec




wiki_spec = WikipediaToolSpec()
# Get the search wikipedia tool
tool = wiki_spec.to_tool_list()[1]


# Create the Agent with load/search tools
agent = FunctionAgent(
    llm=llm, tools=LoadAndSearchToolSpec.from_defaults(tool).to_tool_list()
)

return_direct

도구 클래스 생성자에 return_direct 옵션이 보일 거예요. 이 값을 True로 설정하면, 에이전트가 응답을 해석하고 다시 쓰지 않고 도구의 응답을 그대로 반환해요. 런타임을 줄이거나, 에이전트의 추론 루프를 끝내는 도구를 설계·지정할 때 유용해요.

예를 들어 이런 도구를 지정했다고 해볼게요.

tool = QueryEngineTool.from_defaults(
    query_engine,
    name="<name>",
    description="<description>",
    return_direct=True,
)


agent = FunctionAgent(llm=llm, tools=[tool])


response = await agent.run("<question that invokes tool>")

위 예제에서 쿼리 엔진 도구가 호출되고, 그 도구의 응답이 그대로 최종 응답으로 반환되면서 실행 루프가 끝나요.

return_direct=False라면 에이전트가 채팅 히스토리 맥락을 이용해 응답을 다시 쓰거나, 심지어 또 다른 도구 호출을 할 수도 있어요.

return_direct 사용법에 대한 예제 노트북도 준비돼 있어요.

도구 디버깅

API에 어떤 도구 정의가 전송되는지 정확히 디버깅하고 싶을 때가 있어요.

OpenAI·Anthropic 같은 API에서 활용되는 현재 도구 스키마를 얻는 기본 함수를 쓰면 잘 살펴볼 수 있어요.

schema = tool.metadata.get_parameters_dict()
print(schema)

더 알아보기