LangGraph Agent 开发指南(9~工具 Tools)
一、什么是工具1.1 通俗解释想象你有一个智能助手没有工具 你: 帮我查一下北京明天的天气 助手: 抱歉我没有联网功能无法查询实时天气 有工具 你: 帮我查一下北京明天的天气 助手: 好的让我调用天气查询工具... 助手: 北京明天晴天温度 25°C工具就是 Agent 的手和眼Agent 大脑LLM 工具执行能力 大脑理解用户意图决定调用什么工具 工具实际执行操作获取结果1.2 工具的作用作用说明例子扩展能力让 Agent 能做 LLM 做不到的事查实时天气、搜索网页与外界交互连接数据库、API、文件系统查询数据库、调用 API执行操作完成具体任务发送邮件、创建文件获取信息检索外部知识搜索文档、查 Wikipedia1.3 核心概念┌─────────────────────────────────────────────────────────────┐ │ 工具调用流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. 用户提问 │ │ │ │ │ ▼ │ │ 2. LLM 分析意图 │ │ │ │ │ ▼ │ │ 3. LLM 决定调用工具生成 tool_calls │ │ │ │ │ ▼ │ │ 4. 执行工具获取结果 │ │ │ │ │ ▼ │ │ 5. LLM 根据结果生成回复 │ │ │ └─────────────────────────────────────────────────────────────┘二、工具调用原理2.1 LLM 如何决定是否调用工具关键原则LLM 根据输入的相关性决定是否使用工具 情况1输入与工具无关 用户: 你好 LLM: 不调用工具直接回复 你好 情况2输入与工具相关 用户: 2 乘以 3 等于多少 LLM: 调用 multiply 工具参数 a2, b32.2 tool_calls 结构当 LLM 决定调用工具时会生成tool_callsresult.tool_calls [ { name: multiply, # 工具名称 args: {a: 2, b: 3}, # 参数 id: xxx, # 调用ID type: tool_call # 类型 } ]2.3 执行流程图用户输入: 2 乘以 3 等于多少 │ ▼ LLM 分析 │ ▼ 生成 tool_calls: {name: multiply, args: {a: 2, b: 3}} │ ▼ 执行工具: multiply(2, 3) 6 │ ▼ 返回结果: 2 乘以 3 等于 6三、创建工具3.1 方法一使用 tool 装饰器推荐from langchain_core.tools import tool tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 工具会自动提取 # - 名称multiply # - 参数a (int), b (int) # - 描述Multiply two numbers.3.2 方法二普通函数def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 使用 ToolNode 或 create_react_agent 时会自动转换3.3 方法三自定义工具from langchain_core.tools import tool tool(multiply_tool, parse_docstringTrue) def multiply(a: int, b: int) - int: Multiply two numbers. Args: a: First operand b: Second operand return a * b3.4 方法四使用 Pydantic 定义输入模式from pydantic import BaseModel, Field from langchain_core.tools import tool class MultiplyInput(BaseModel): Multiply two numbers a: int Field(description第一个数) b: int Field(description第二个数) tool(multiply, args_schemaMultiplyInput) def multiply(a: int, b: int) - int: return a * b3.5 工具定义要点要点 1. 函数名作为工具名称 2. 参数类型LLM 会根据类型生成正确的参数 3. 文档字符串LLM 会根据描述决定何时调用 4. 返回值工具执行的结果四、使用工具4.1 将工具绑定到模型from langchain_core.tools import tool from langchain_openai import ChatOpenAI # 定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 创建模型 model ChatOpenAI(modelgpt-4) # 绑定工具 model_with_tools model.bind_tools([multiply]) # 调用 response model_with_tools.invoke(42 乘以 7 等于多少) print(response.tool_calls) # [{name: multiply, args: {a: 42, b: 7}, ...}]4.2 执行工具# 方法1直接调用 result multiply.invoke({a: 42, b: 7}) print(result) # 294 # 方法2使用 tool_call tool_call { type: tool_call, id: 1, args: {a: 42, b: 7} } result multiply.invoke(tool_call) print(result) # ToolMessage(content294, ...)4.3 完整流程示例from langchain_core.tools import tool from langchain_openai import ChatOpenAI # 定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 绑定工具 model ChatOpenAI(modelgpt-4) model_with_tools model.bind_tools([multiply]) # 1. LLM 决定调用工具 response model_with_tools.invoke(42 乘以 7 等于多少) tool_call response.tool_calls[0] # 2. 执行工具 tool_result multiply.invoke(tool_call) print(tool_result) # ToolMessage(content294, ...) # 3. 将结果返回给 LLM final_response model_with_tools.invoke([ {role: user, content: 42 乘以 7 等于多少}, response, tool_result ]) print(final_response.content) # 42 乘以 7 等于 294五、使用预构建组件5.1 使用 create_react_agent最简单的方式创建一个 ReAct Agentfrom langchain_core.tools import tool from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI # 定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b tool def add(a: int, b: int) - int: Add two numbers. return a b # 创建 Agent model ChatOpenAI(modelgpt-4) agent create_react_agent(model, tools[multiply, add]) # 执行 result agent.invoke({ messages: [{role: user, content: 42 乘以 7 等于多少}] }) print(result[messages][-1].content)5.2 使用 ToolNode更灵活的方式在自定义图中使用from langchain_core.tools import tool from langgraph.prebuilt import ToolNode from langgraph.graph import StateGraph, MessagesState, START # 定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 创建 ToolNode tool_node ToolNode([multiply]) # 在图中使用 builder StateGraph(MessagesState) builder.add_node(tools, tool_node) # ... 添加其他节点和边5.3 ToolNode 的优势优势 1. 支持同步和异步工具 2. 并行执行多个工具 3. 自动错误处理 4. 可集成到自定义图中六、在工具中访问配置和状态6.1 访问配置RunnableConfigfrom langchain_core.tools import tool from langchain_core.runnables import RunnableConfig tool def get_user_info(config: RunnableConfig) - str: 查询用户信息 user_id config[configurable].get(user_id) return f用户ID: {user_id} # 使用时传入配置 agent.invoke( {messages: 查询用户信息}, config{configurable: {user_id: user_123}} )6.2 访问状态InjectedStatefrom typing import Annotated from langchain_core.tools import tool from langgraph.prebuilt import InjectedState class CustomState(TypedDict): messages: list user_id: str tool def get_user_info(state: Annotated[CustomState, InjectedState]) - str: 查询用户信息 user_id state[user_id] return f用户ID: {user_id}6.3 更新状态返回 Commandfrom langchain_core.tools import tool, InjectedToolCallId from langgraph.types import Command from langchain_core.messages import ToolMessage tool def update_user_info( tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig ) - Command: 更新用户信息 user_id config[configurable].get(user_id) name 张三 if user_id user_123 else 未知用户 return Command(update{ user_name: name, messages: [ ToolMessage(更新成功, tool_call_idtool_call_id) ] })七、长期记忆7.1 读取长期记忆from langchain_core.tools import tool from langgraph.config import get_store tool def get_user_info(config: RunnableConfig) - str: 查询用户信息 store get_store() user_id config[configurable].get(user_id) user_info store.get((users,), user_id) return str(user_info.value) if user_info else 未知用户7.2 更新长期记忆from langchain_core.tools import tool from langgraph.config import get_store tool def save_user_info(user_info: str, config: RunnableConfig) - str: 保存用户信息 store get_store() user_id config[configurable].get(user_id) store.put((users,), user_id, user_info) return 保存成功7.3 完整示例from langchain_core.tools import tool from langgraph.config import get_store from langgraph.prebuilt import create_react_agent from langgraph.store.memory import InMemoryStore from langchain_openai import ChatOpenAI # 创建存储 store InMemoryStore() store.put((users,), user_123, {name: 张三, language: 中文}) # 定义工具 tool def get_user_info(config: RunnableConfig) - str: 查询用户信息 store get_store() user_id config[configurable].get(user_id) user_info store.get((users,), user_id) return str(user_info.value) if user_info else 未知用户 # 创建 Agent model ChatOpenAI(modelgpt-4) agent create_react_agent(model, tools[get_user_info], storestore) # 执行 result agent.invoke( {messages: 查询用户信息}, config{configurable: {user_id: user_123}} )八、预构建工具8.1 常用工具类别类别工具说明搜索Tavily, SerpAPI, DuckDuckGo网页搜索代码执行Python REPL执行代码数据库SQL, MongoDB数据库查询网页WebBaseLoader网页抓取APIOpenWeatherMap, NewsAPIAPI 调用8.2 使用预构建工具from langchain_community.tools import DuckDuckGoSearchRun from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI # 使用预构建的搜索工具 search DuckDuckGoSearchRun() # 创建 Agent model ChatOpenAI(modelgpt-4) agent create_react_agent(model, tools[search]) # 执行 result agent.invoke({ messages: 搜索 LangGraph 的最新教程 })8.3 自定义工具 预构建工具from langchain_core.tools import tool from langchain_community.tools import DuckDuckGoSearchRun # 自定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b # 预构建工具 search DuckDuckGoSearchRun() # 组合使用 agent create_react_agent(model, tools[multiply, search])九、错误处理9.1 ToolNode 自动错误处理from langgraph.prebuilt import ToolNode # 默认启用错误处理 tool_node ToolNode([multiply], handle_tool_errorsTrue) # 如果工具执行出错会返回错误信息而不是崩溃9.2 自定义错误处理tool def divide(a: int, b: int) - float: Divide two numbers. if b 0: return 错误除数不能为零 return a / b十、完整示例10.1 数学计算 Agentfrom langchain_core.tools import tool from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI # 定义工具 tool def multiply(a: int, b: int) - int: Multiply two numbers. return a * b tool def add(a: int, b: int) - int: Add two numbers. return a b tool def divide(a: int, b: int) - float: Divide two numbers. if b 0: return 错误除数不能为零 return a / b # 创建 Agent model ChatOpenAI(modelgpt-4) agent create_react_agent(model, tools[multiply, add, divide]) # 执行 result agent.invoke({ messages: 计算 (42 7) * 3 / 5 等于多少 }) print(result[messages][-1].content)10.2 带搜索功能的 Agentfrom langchain_core.tools import tool from langchain_community.tools import DuckDuckGoSearchRun from langgraph.prebuilt import create_react_agent from langchain_openai import ChatOpenAI # 自定义工具 tool def get_current_time() - str: 获取当前时间 from datetime import datetime return datetime.now().strftime(%Y-%m-%d %H:%M:%S) # 预构建工具 search DuckDuckGoSearchRun() # 创建 Agent model ChatOpenAI(modelgpt-4) agent create_react_agent(model, tools[get_current_time, search]) # 执行 result agent.invoke({ messages: 现在几点了另外搜索一下今天的新闻 }) print(result[messages][-1].content)十一、常见问题Q1: 工具描述重要吗非常重要LLM 根据工具描述决定何时调用。 好的描述 tool def search_web(query: str) - str: 搜索网页内容用于查找实时信息 ... 不好的描述 tool def search_web(query: str) - str: 搜索 # 太简单LLM 不知道何时使用 ...Q2: 如何限制工具参数from pydantic import BaseModel, Field class SearchInput(BaseModel): query: str Field(description搜索关键词) max_results: int Field(default5, ge1, le10) # 限制1-10 tool(args_schemaSearchInput) def search(query: str, max_results: int 5) - str: 搜索网页 ...Q3: 工具可以返回复杂对象吗tool def get_user_info(user_id: str) - dict: 获取用户信息 return { name: 张三, age: 25, email: zhangsanexample.com } # 注意返回值会被转换为字符串Q4: 如何处理工具执行失败# 方法1在工具内部处理 tool def risky_operation() - str: try: # 执行可能失败的操作 result do_something() return result except Exception as e: return f操作失败: {str(e)} # 方法2使用 ToolNode 的错误处理 tool_node ToolNode([risky_operation], handle_tool_errorsTrue)十二、API 速查表12.1 创建工具方法说明tool装饰器方式推荐tool(name, args_schema...)自定义工具普通函数自动转换12.2 使用工具方法说明model.bind_tools([tools])绑定到模型tool.invoke(args)执行工具create_react_agent(model, tools)创建 AgentToolNode([tools])创建工具节点12.3 访问上下文注解说明RunnableConfig访问配置InjectedState访问状态InjectedToolCallId获取工具调用IDget_store()访问长期记忆十三、延伸阅读LangGraph 官方文档 - 工具LangChain 工具集成自定义工具指南总结工具的核心要点定义工具使用 tool 装饰器提供清晰的描述绑定工具使用 bind_tools() 或 create_react_agent()执行工具LLM 决定何时调用自动执行访问上下文通过特殊注解访问配置和状态工具的作用扩展 Agent 能力与外界交互执行具体操作获取外部信息一句话总结工具是 Agent 的手和眼让 LLM 能够执行实际操作与外界交互。