LangGraph 에서 Tool을 활용하여 어떻게 활용할 수 있는지에 대해 설명합니다. ChatBot이 답할 수 없는 질문을 처리하기 위해 웹 검색이 가능한 도구와 통합하여 관련정보를 찾고 더 나은 답변을 제공할 수 있도록 연계합니다.
Tool 사용하기
LangGraph에서 Tool은 함수나 API로 데이터를 처리하는 역할을 합니다. 예를 들어, 검색 기능을 구현하고 싶다면, 웹 검색 API나 데이터베이스 쿼리, 혹은 파일 시스템에서 데이터를 검색하는 도구를 활용할 수 있습니다.
Tool 설정하기
LangGraph에서 Tool을 설정하는 방법은 간단합니다. 먼저, Tool을 정의하고, 그것을 노드에서 사용할 수 있도록 연결해야 합니다.
환경설정
AI Agent 검색 엔진기반의 Tavily 검색엔진 패키지를 설치합니다.
poetry add tavily-python langchain_community
TAVILY API 키 설정
.env
에 TAVILY_API_KEY
를 설정합니다.
TAVILY_API_KEY= "<your-api-key>"
Implementation
1. Tool 정의
검색 기능을 위한 Tool을 정의합니다.
# tools.py
from langchain_community.tools.tavily_search import TavilySearchResults
from dotenv import load_dotenv
load_dotenv()
tools = [TavilySearchResults(max_results=1)]
간단하게 Tavily 검색을 해볼 수 있습니다.
tools[0].invoke("what is Langchain?")
2. Tool 등록
LLM 모델에 bind_tools()
를 사용하여 도구를 바인딩 합니다.
결과는 ToolCall
Object 에 저장되고, .tool_calls
를 확인하여 도구 호출 결과를 확인할 수 있습니다.
# node.py
# LLM에 도구를 바인딩
llm_with_tools = llm.bind_tools(tools)
system_prompt = "Chat with the AI assistant. You can ask questions about anything else."
# 'chatbot' 노드
def chatbot(state):
"""상태에서 메시지를 받아서 LLM을 호출하는 함수"""
messages = state["messages"]
messages = [{"role": "system", "content": system_prompt}] + messages
response = llm_with_tools.invoke(messages)
return {"messages": [response]}
3. Tool 노드(Node) 정의
가장 최근의 메시지에 tool_calls
가 포함되어 있는 경우, 도구를 호출하는 노드를 구현합니다.
# node.py
from langchain_core.messages import ToolMessage
# 도구 노드 정의
class BasicToolNode:
def __init__(self, tools: list) -> None:
self.tool_by_name = {tool.name: tool for tool in tools}
def __call__(self, inputs: dict):
if messages := inputs.get("messages", []):
message = messages[-1]
else:
raise ValueError("No messages found in input")
print(message)
outputs = []
for tool_call in message.tool_calls:
tool_result = self.tool_by_name[tool_call["name"]].invoke(tool_call["args"])
outputs.append(ToolMessage(
content=json.dumps(tool_result),
name=tool_call["name"],
tool_call_id=tool_call["id"]
))
return {"messages": outputs}
# 도구 노드 생성
tool_node = BasicToolNode(tools)
4. 그래프(Graph) 정의
Tool 노드를 그래프에 추가 합니다.
# agent.py
from my_ai_agent.utils.node import tool_node
graph_builder.add_node("tools", tool_node)
도구 노드가 추가되면 conditional_edges
를 정의할 수 있습니다.
5. 조건부엣지(Conditional edges) 정의
조건부 엣지(Conditional edges) 는 현재의 그래프의 상태에 따라 다른 노드로 라우팅을 할 수 있습니다.
- 조건부 엣지는 단일 노드에서 시작합니다. 즉,
chatbot
노드가 실행될 때 다음 동작을 어떻게 처리할지 결정하는 역할을 합니다. - 다음에 호출할 노드를 나타내는 문자열이나 문자열 목록을 반환함.
① 챗봇의 마지막 상태에서 tool_calls
가 있으면, tools
호출하는 함수를 생성합니다.
함수안에 도구 호출이 이루어지지 않으면 END
를 반환 하므로 finish_point
를 명시적으로 설정할 필요가 없습니다.
# agent.py
from langgraph.graph import END
def route_tools(state: AgentState):
"""
Use in the conditional_edge to route to the ToolNode if the last message has tool calls. Otherwise, route to the end.
"""
if isinstance(state, list):
ai_messages = state[-1]
elif messages := state.get("messages", []):
ai_messages = messages[-1]
else:
raise ValueError(f"No messages found in input state to too_edge: {state}")
if hasattr(ai_messages, "tool_calls") and len(ai_messages.tool_calls) > 0: # Check if the last message has tool calls
return "tools"
return END
② 챗봇 노드가 완료될 때마다 이 함수(route_tools
)를 통해 다음으로 어디로 가야 하는지 확인하도록 그래프에 선언합니다. (add_conditional_edges
)
# agent.py
# 'chatbot'에서 'tool_node'로 이동하는 조건 추가
# The `tools_condition` function returns "tools" if the chatbot asks to use a tool, and "END" if
# it is fine directly responding. This conditional routing defines the main agent loop.
graph_builder.add_conditional_edges(
"chatbot",
route_tools,
# The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node
# It defaults to the identity function, but if you
# want to use a node named something else apart from "tools",
# You can update the value of the dictionary to something else
# e.g., "tools": "my_tools"
{"tools": "tools", END: END},
)
③ 그리고, chatbot
노드에서 tool 이 호출되고 난 이후에 chatbot
노드가 다음 스텝을 결정할 수 있도록 경로를 설정합니다.
# agent.py
# Any time a tool is called, we return to the chatbot to decide the next step
graph_builder.add_edge("tools", "chatbot")
그래프 컴파일(Compile)
compile()
메서드는 정의된 그래프를 실행 가능한 형태로 변환합니다.
# agent.py
graph = graph_builder.compile()
그래프의 실행결과를 확인합니다. (LangStudio)