AgentTool

AgentTool

Haystack Agent를 감싸서, 다른 Agent가 도구처럼 호출할 수 있게 만드는 역할이에요.

필수 init 변수: agent(감쌀 Haystack Agent), name(도구 이름), description(도구 설명) API reference: AgentTool GitHub link: https://github.com/deepset-ai/haystack/blob/main/haystack/tools/agent_tool.py Package name: haystack-ai

출처: 문서

본문

Overview

AgentTool은 Haystack Agent를 다른 Agent가 호출할 수 있는 도구로 바꿔줘요. 멀티 에이전트 시스템의 기반이죠: 한 에이전트가 특정 작업에 특화되고, 코디네이터가 직접 일하지 않고 그 에이전트에 위임하는 구조입니다.

가장 큰 장점은 컨텍스트 격리예요. 전문 에이전트는 답하기 전에 웹을 여러 번 검색하고 몇 페이지를 읽을 수 있는데, 그 모든 것이 전문 에이전트 안에 남습니다. 코디네이터는 작업을 보내고 답변을 받을 뿐이라 컨텍스트가 작게 유지되죠.

Agent 자체 외에 필요한 설정은 이름과 설명뿐이에요. 코디네이터의 모델은 작업을 평문 텍스트로 보내고, 전문 에이전트의 답변을 텍스트로 받습니다.

전문 에이전트가 작업 이상의 것 — 예를 들어 system prompt의 변수 — 을 필요로 하면, AgentTool이 그것을 도구 입력에 추가하거나 코디네이터의 상태에서 가져와요. Prompt Variables를 참고하세요.

Parameters

  • agent는 필수이며 Agent 인스턴스여야 해요.
  • name은 필수이며 도구 이름을 지정합니다.
  • description은 필수예요. 호출하는 LLM에게 감싼 Agent가 무엇에 특화되어 있고 언제 위임해야 하는지를 알려줘야 하죠.
  • parameters는 선택이며 도구 입력의 생성된 JSON 스키마를 덮어쓸 수 있게 해줘요. inputs_from_state로 제공되지 않는 감싼 Agent의 모든 필수 입력을 반드시 커버해야 하며, 그렇지 않으면 ValueError가 발생합니다.
  • outputs_to_string은 선택이며 감싼 Agent의 출력을 호출 LLM용 문자열로 어떻게 변환할지 제어해요. 기본적으로 최종 답변의 텍스트를 반환하고, 답변에 텍스트가 없으면 직렬화된 메시지를 반환합니다. Agent가 max_agent_steps에 도달했거나, 모델 출력 한도에 닿았거나, 콘텐츠 필터에 의해 응답이 중단된 경우 경고가 붙어요.
  • inputs_from_state는 선택이며 호출 Agent의 상태 키를 감싼 Agent의 입력으로 매핑해요. 예: {"subject": "topic"}은 "subject"의 상태 값을 감싼 Agent의 "topic" 입력으로 전달합니다. 이렇게 매핑된 입력은 호출 Agent가 제공하므로 생성된 스키마에 추가되지 않아요.
  • outputs_to_state는 선택이며 감싼 Agent의 출력 키를 호출 Agent의 상태 키로 매핑합니다. 예: {"notes": {"source": "last_message"}}는 감싼 Agent의 "last_message" 출력을 상태의 "notes"에 기록해요.

Usage

Basic Usage

이 예시는 SerperDev 웹 검색 컴포넌트(serperdev-haystack 패키지)를 사용해요. 실행하려면 설치하세요:

pip install serperdev-haystack
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIResponsesChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.tools import AgentTool, ComponentTool
from haystack_integrations.components.websearch.serperdev import SerperDevWebSearch

researcher = Agent(
    chat_generator=OpenAIResponsesChatGenerator(model="gpt-5.4-mini"),
    system_prompt="You are a research specialist. Investigate the task and report your findings.",
    tools=[
        ComponentTool(
            component=SerperDevWebSearch(top_k=3),
            name="web_search",
            description="Search the web for current information on any topic",
        ),
    ],
)
research = AgentTool(
    agent=researcher,
    name="research",
    description="Research a question on the web and report the findings",
)
coordinator = Agent(
    chat_generator=OpenAIResponsesChatGenerator(model="gpt-5.4"),
    tools=[research],
    system_prompt="You coordinate specialists. Delegate research questions, then answer the user.",
)
result = coordinator.run(
    [
        ChatMessage.from_user(
            "What are the latest developments in the Haystack framework?",
        ),
    ],
)
print(result["last_message"].text)

코디네이터는 위임할 작업을 하나의 사용자 메시지로 받는 단일 research 도구만 보게 돼요. 리서처가 수행하는 검색과 읽은 결과는 코디네이터의 컨텍스트에 절대 들어가지 않고, 최종 리포트만 들어갑니다.

Prompt Variables

감싼 Agent의 system_prompt 또는 user_prompt에 Jinja templates로 작성된 변수가 있으면, 그것들은 필수 입력이 돼요. AgentTool은 각 변수마다 문자열 파라미터를 생성된 스키마에 추가하고, 호출 LLM이 채웁니다.

아래 리뷰어는 언어별로 특화되어 있고, 코디네이터는 위임하는 각 리뷰의 언어를 정해요:

from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIResponsesChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.tools import AgentTool

SNIPPET = """def load_config(path):
    return json.loads(open(path).read())"""

reviewer = Agent(
    chat_generator=OpenAIResponsesChatGenerator(model="gpt-5.4-mini"),
    system_prompt=(
        "You are a senior {{language}} engineer. Review the code you are given and reply with the single "
        "most important issue, in one sentence."
    ),
)
review_tool = AgentTool(
    agent=reviewer,
    name="code_review",
    description="Ask a senior engineer to review a code snippet",
)
print(review_tool.parameters["required"])
# ['messages', 'language']

coordinator = Agent(
    chat_generator=OpenAIResponsesChatGenerator(model="gpt-5.4-mini"),
    tools=[review_tool],
    system_prompt="You triage code snippets. Delegate every review to the code_review tool, then answer the user.",
)
result = coordinator.run(
    [ChatMessage.from_user(f"Review this Python snippet:\n{SNIPPET}")],
)
print(result["last_message"].text)

값이 LLM이 아니라 호출 Agent의 state에서 와야 한다면 inputs_from_state를 쓰세요. 이렇게 매핑된 입력은 생성된 스키마에 추가되지 않아요:

review_tool = AgentTool(
    agent=reviewer,
    name="code_review",
    description="Ask a senior engineer to review a code snippet",
    # the state key "project_language" fills the reviewer's "language" input
    inputs_from_state={"project_language": "language"},
)
print(review_tool.parameters["required"])
# ['messages']

coordinator = Agent(
    chat_generator=OpenAIChatGenerator(model="gpt-5.4-mini"),
    tools=[review_tool],
    system_prompt="You triage code snippets. Delegate every review to the code_review tool, then answer the user.",
    state_schema={"project_language": {"type": str}},
)
result = coordinator.run(
    [ChatMessage.from_user(f"Review this snippet:\n{SNIPPET}")],
    project_language="Python",
)
print(result["last_message"].text)

더 알아보기 (Learn more)

📖 관련 문서:

📚 튜토리얼: