Agent의 **'손발'**입니다. LLM(두뇌)이 실제 세계의 정보를 가져오거나 특정 작업을 수행할 수 있게 해주는 **함수(function)**들입니다.
Agent는 도구를 통해 다음과 같은 강력한 작업을 수행할 수 있습니다.
@tool 데코레이터를 파이썬 함수 위에 붙여주기만 하면 됩니다.
from langchain.tools import tool
@tool
def function_name(parameter: type) -> return_type:
"""
[★매우 중요★] 이 도구가 무엇을 하는지 LLM이 알아볼 수 있게
자세하고 명확하게 설명해야 합니다.
"""
# ... 실제 함수 코드 ...
return result
가장 중요한 것:
""" """안에 있는 **설명(docstring)**입니다. LLM(두뇌)은 이 설명을 읽고 "아, 이런 작업이 필요할 땐 이 도구를 써야겠다!"라고 판단합니다.
from langchain.tools import tool
from langchain.agents import create_agent
# (model은 이전에 정의되었다고 가정)
@tool
def search(query: str) -> str:
"""
최신 정보를 검색할 때 사용합니다.
(예: "오늘 뉴스", "인기 제품")
"""
print(f"DEBUG: search('{query}') 실행")
return f"'{query}'에 대한 검색 결과입니다: [검색된 내용...]"
@tool
def get_weather(location: str) -> str:
"""
특정 위치(location)의 현재 날씨를 가져옵니다.
"""
print(f"DEBUG: get_weather('{location}') 실행")
return f"{location}의 날씨: 맑음, 25°F"
# Agent를 생성할 때, 이 '손발' 목록을 전달합니다.
tools = [search, get_weather]
agent = create_agent(model, tools=tools)
ReAct = Reasoning (추론) + Acting (행동)
Agent는 "생각하고, 도구를 쓰고, 결과를 보고, 다시 생각하는" 과정을 반복합니다.
예시: "가장 인기 있는 무선 헤드폰을 찾고 재고가 있는지 확인해 줘"
search 도구를 써야겠어."search(query="무선 헤드폰") 호출check_inventory 도구가 있네. - 예시에는 없지만 있다고 가정)"check_inventory(product_id="WH-1000XM5") 호출만약 도구가 실행되다가 실패(에러)하면 어떻게 될까요? Agent 전체가 멈출 수 있습니다.
@wrap_tool_call 미들웨어를 사용하면, 도구 실행을 '가로채서' 에러를 처리할 수 있습니다.
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_tool_call
from langchain_core.messages import ToolMessage
# (tools와 model은 이전에 정의되었다고 가정)
@wrap_tool_calldef handle_tool_errors(request, handler):
"""도구 실행을 시도하고, 실패하면 LLM에게 '실패했다'고 알려줍니다."""
try:
# 1. 일단 도구 실행 (handler(request))
return handler(request)
except Exception as e:
# 2. 만약 에러가 발생하면(except), Agent가 멈추는 대신,
# LLM에게 'ToolMessage' (도구 결과 메시지)로 에러 내용을 전달
print(f"DEBUG: 도구 오류 발생! {e}")
return ToolMessage(
content=f"도구 사용 중 오류 발생: 입력값을 확인해주세요. (오류: {str(e)})",
tool_call_id=request.tool_call["id"]
)
# Agent 생성 시, 이 '에러 처리기'를 미들웨어로 등록
agent = create_agent(
model=model,
tools=tools,
middleware=[handle_tool_errors]
)
핵심:
handle_tool_errors덕분에 Agent는 도구 에러가 나도 멈추지 않습니다. LLM(두뇌)은ToolMessage를 받고 "아, 도구 쓰다 실패했네. 입력을 바꿔서 다시 시도해 볼까?"라고 **다시 추론(Reasoning)**할 기회를 얻게 됩니다.
Agent의 '기본 지침서' 또는 **'역할(Personality)'**을 정해줍니다.
가장 간단한 방법. Agent를 만들 때 고정된 지침을 문자열로 전달합니다.
agent = create_agent(
model,
tools,
system_prompt="당신은 친절한 AI 조수입니다. 모든 답변은 간결하고 정확하게 하세요."
)
고급 기능입니다. Agent가 실행되는 상황에 따라 시스템 프롬프트를 바꿔줍니다. @dynamic_prompt 미들웨어를 사용합니다.
예시: 사용자가 '전문가'인지 '초보자'인지에 따라 답변 스타일 바꾸기
from typing import TypedDict
from langchain.agents.middleware import dynamic_prompt, ModelRequest
class Context(TypedDict):
user_role: str # 'expert' 또는 'beginner'
@dynamic_prompt
def user_role_prompt(request: ModelRequest) -> str:
"""사용자 역할(context)에 따라 동적으로 프롬프트를 생성합니다."""
# 1. 현재 실행의 'context'에서 user_role 값을 가져옴 (기본값 'user')
user_role = request.runtime.context.get("user_role", "user")
base_prompt = "당신은 친절한 AI 조수입니다."
if user_role == "expert":
return f"{base_prompt} 기술 용어를 사용하여 자세하게 설명해주세요."
elif user_role == "beginner":
return f"{base_prompt} 전문 용어는 피하고, 쉽게 비유를 들어 설명해주세요."
return base_prompt
agent = create_agent(
model=model,
tools=tools,
middleware=[user_role_prompt], # 💡 동적 프롬프트 미들웨어 등록
context_schema=Context # 💡 context로 이런 걸 받을 거라고 알려줌
)
# 2. 실행(invoke)할 때 'context'를 함께 전달
result = agent.invoke(
{"messages": [{"role": "user", "content": "머신러닝이 뭐야?"}]},
context={"user_role": "expert"} # 💡 'expert'로 실행
)
# -> 이 Agent는 이제 '전문가' 모드로 답변합니다.