Agent(에이전트)는 LLM이 스스로 판단하여 적절한 도구(Tool)를 선택하고 실행한 후, 그 결과를 바탕으로 최종 답변을 생성하는 시스템입니다.
쉽게 말해, LLM에게 "자율성"을 부여하는 것입니다. 사용자의 요청을 분석하고, 필요한 도구를 선택해 작업을 수행한 뒤, 그 결과를 종합하여 답변합니다.
사용자 질문 → Agent가 Tool 선택 → Tool 실행 → 결과 해석 → 최종 답변
Tool은 Agent가 사용할 수 있는 "기능" 또는 "함수"입니다. LLM은 학습된 지식만으로는 한계가 있기 때문에, 외부 기능을 도구로 제공하여 실시간 정보 조회, 계산, API 호출 등을 수행할 수 있게 합니다.
@tool 데코레이터로 일반 함수를 Tool로 변환!pip install -q -U google-genai
!pip install -U langchain
!pip install -U langchain-google-genai
from langchain.chat_models import init_chat_model
import os
os.environ["GOOGLE_API_KEY"] = "YOUR_API_KEY_HERE"
# 모델 초기화
model = init_chat_model(
"gemini-2.5-flash",
model_provider="google_genai"
)
# 기본 테스트
response = model.invoke("현재 한국 날씨 어때?")
print(response.content)
포인트: 일반 LLM은 실시간 정보를 알 수 없습니다. 여기서 Agent와 Tool이 필요해집니다.
from langchain.tools import tool
@tool
def get_weather(location: str) -> str:
"""특정 지역의 날씨를 제공하는 Tool"""
return f"{location}의 날씨는 맑고 영하2도 입니다."
포인트: @tool 데코레이터와 docstring으로 LLM이 이해할 수 있는 도구를 만듭니다.
from langchain.agents import create_agent
agent = create_agent(model, tools=[get_weather])
result = agent.invoke(
{"messages": [{"role": "user", "content": "서울 날씨 어때요?"}]},
)
print(result["messages"][-1].content)
동작 흐름:
Human Message → AI Tool_calls → Tool Message → AI Message
Agent가 자동으로 get_weather 도구를 호출하고 결과를 해석하여 답변합니다.
from langchain.tools import tool
@tool
def add(a: int, b: int) -> int:
"""'a'와 'b' 덧셈.
Args:
a: First number
b: Second number
"""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""'a'와 'b' 곱셈.
Args:
a: First number
b: Second number
"""
return a * b
@tool
def divide(a: int, b: int) -> int:
"""'a'와 'b' 나눗셈.
Args:
a: First number
b: Second number
"""
return a / b
tools = [add, multiply, divide]
agent = create_agent(
model,
tools,
system_prompt="당신은 유능한 수학 선생님입니다. 사칙 연산 요청 시 모든 단계에서 Tool을 이용하세요"
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "42 + 3 * 23은 무엇인가요?"}]},
)
print(result["messages"][-1].content)
포인트: system_prompt를 통해 Agent의 행동 방식을 제어할 수 있습니다. 프롬프트가 없으면 Tool을 사용하지 않을 수도 있습니다.
from langgraph.checkpoint.memory import InMemorySaver
tools = []
agent = create_agent(model, tools, checkpointer=InMemorySaver())
# 첫 번째 대화 (thread_id: t1)
response = agent.invoke(
{"messages": [{"role": "user", "content": "안녕하세요 저는 치즈입니다"}]},
{"configurable": {"thread_id": "t1"}}
)
print(response["messages"][-1].content)
# 같은 스레드에서 이어지는 대화
response = agent.invoke(
{"messages": [{"role": "user", "content": "제 이름이 뭐라고 했죠?"}]},
{"configurable": {"thread_id": "t1"}}
)
print(response["messages"][-1].content) # "치즈" 기억함
# 다른 스레드 (thread_id: t2)
response = agent.invoke(
{"messages": [{"role": "user", "content": "제 이름이 뭐라고 했죠?"}]},
{"configurable": {"thread_id": "t2"}}
)
print(response["messages"][-1].content) # 기억 못함
포인트: checkpointer를 사용하면 대화 이력을 저장하고, thread_id로 대화 세션을 구분할 수 있습니다.
Middleware는 Agent의 동작 과정에 끼어들어 추가 기능을 제공하는 레이어입니다.
from typing import List, Dict
@tool
def send_email_tool(to: str, subject: str, body: str) -> str:
"""지정한 이메일 주소로 메일을 보내는 도구입니다."""
return f"이메일 전송 성공. \n수신자: {to}\n제목: {subject}\n내용: {body[:50]}..."
@tool
def read_email_tool(limit: int = 3) -> List[Dict[str, str]]:
"""최근 받은 이메일 3개를 읽는 도구입니다."""
return f"이메일 조회 성공"
from langchain.agents.middleware import LLMToolEmulator
from langchain_google_genai import ChatGoogleGenerativeAI
emulator_model = ChatGoogleGenerativeAI(model="gemini-2.5-flash")
tools = [send_email_tool, read_email_tool]
agent = create_agent(
model,
tools,
middleware=[LLMToolEmulator(model=emulator_model)],
)
response = agent.invoke(
{"messages": [{"role": "user", "content": "최근 온 메일 확인해줘"}]}
)
print(response["messages"][-1].content)
포인트: Tool을 실제로 실행하지 않고 LLM이 예상 결과를 시뮬레이션합니다. 테스트나 비용 절감에 유용합니다.
from langchain.agents.middleware import TodoListMiddleware
agent = create_agent(
model,
tools,
middleware=[
LLMToolEmulator(model=emulator_model),
TodoListMiddleware()
],
)
response = agent.invoke(
{"messages": [{"role": "user", "content": "온 메일들 확인후 나한테 요약해줘"}]}
)
print(response["messages"][-1].content)
포인트: 복잡한 요청을 여러 단계로 나누어 계획을 세우고 순차적으로 실행합니다.
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
checkPointer = InMemorySaver()
agent = create_agent(
model,
tools,
checkpointer=checkPointer,
middleware=[
LLMToolEmulator(model=emulator_model),
HumanInTheLoopMiddleware(
interrupt_on={
"send_email_tool": {
"allowed_decisions": ["approve", "edit", "reject"]
},
"read_email_tool": False
}
)
]
)
response = agent.invoke(
{"messages": [{"role": "user", "content": "무슨 메일 왔는지 확인해줘"}]},
{"configurable": {"thread_id": "HIL-a"}}
)
print(response["messages"][-1].content)
포인트: 특정 Tool 실행 전에 사람의 승인을 받습니다. 중요한 작업(이메일 발송 등)에 필수적입니다.
LangChain은 다양한 Middleware를 제공합니다:
이러한 Middleware들을 조합하여 안전하고 효율적인 Agent를 구축할 수 있습니다.
from langchain.agents.middleware import PIIMiddleware
agent = create_agent(
model,
tools,
checkpointer=checkPointer,
middleware=[
# 1단계: PII 감지 (개인정보 필터링)
PIIMiddleware("email", strategy="redact", apply_to_input=True),
PIIMiddleware("credit_card", strategy="mask", apply_to_input=True),
# 2단계: Tool 에뮬레이션
LLMToolEmulator(model=emulator_model),
# 3단계: 사람의 최종 승인
HumanInTheLoopMiddleware(
interrupt_on={
"send_email_tool": {
"allowed_decisions": ["approve", "edit", "reject"]
},
"read_email_tool": False
}
)
]
)
response = agent.invoke(
{"messages": [{"role": "user", "content": "무슨 메일 왔는지 확인해줘"}]},
{"configurable": {"thread_id": "HIL-a"}}
)
print(response["messages"][-1].content)
포인트: 여러 Middleware를 체인으로 연결하여 보안, 시뮬레이션, 승인 프로세스를 순차적으로 적용할 수 있습니다.
이 실습을 통해 배운 내용:
LangChain Agent와 Middleware를 조합하면 안전하고 강력한 AI 자동화 시스템을 구축할 수 있습니다