一、工具是什么工具就是可调用函数有明确的输入和输出传递给聊天模型。模型根据对话上下文决定何时调用工具、传什么参数。简单说模型是大脑工具是手脚。模型思考后决定要不要用工具、用哪个工具、怎么调工具。二、创建工具2.1 最简单的方式用 tool 装饰器fromlangchain.toolsimporttooltooldefsearch_database(query:str,limit:int10)-str:Search the customer database for records matching the query. Args: query: Search terms to look for limit: Maximum number of results to return returnfFound{limit}results for {query}关键点类型提示是必需的如 query: str它们定义了工具的输入模式文档字符串很重要默认会成为工具描述帮助模型理解何时使用工具名建议用 snake_case如 web_search不要用空格或特殊字符2.2 自定义工具属性自定义名称tool(web_search)# 自定义名称defsearch(query:str)-str:Search the web for information.returnfResults for:{query}print(search.name)# web_search自定义描述tool(calculator,descriptionPerforms arithmetic calculations. Use this for any math problems.)defcalc(expression:str)-str:Evaluate mathematical expressions.returnstr(eval(expression))用 Pydantic 定义复杂输入frompydanticimportBaseModel,FieldfromtypingimportLiteralclassWeatherInput(BaseModel):Input for weather queries.location:strField(descriptionCity name or coordinates)units:Literal[celsius,fahrenheit]Field(defaultcelsius,descriptionTemperature unit preference)include_forecast:boolField(defaultFalse,descriptionInclude 5-day forecast)tool(args_schemaWeatherInput)defget_weather(location:str,units:strcelsius,include_forecast:boolFalse)-str:Get current weather and optional forecast.temp22ifunitscelsiuselse72resultfCurrent weather in{location}:{temp}degrees{units[0].upper()}ifinclude_forecast:result\nNext 5 days: Sunnyreturnresult2.3 保留参数名这两个名字是保留的不能用作工具参数config —— 保留给 RunnableConfigruntime —— 保留给 ToolRuntime访问状态、上下文、存储三、访问上下文工具可以访问运行时信息功能更强大。通过 ToolRuntime 参数访问。3.1 短期记忆状态state状态是存在于当前对话期间的可变数据消息、计数器、自定义字段。访问状态fromlangchain.toolsimporttool,ToolRuntimefromlangchain.messagesimportHumanMessagetooldefget_last_user_message(runtime:ToolRuntime)-str:Get the most recent message from the user.messagesruntime.state[messages]# 找最后一条人类消息formessageinreversed(messages):ifisinstance(message,HumanMessage):returnmessage.contentreturnNo user messages found关键 runtime 参数会自动注入对 LLM 隐藏——不会出现在工具模式里。还可以用 Command 更新智能体的state状态fromlangchain.agentsimportAgentStatefromlangchain.messagesimportToolMessagefromlangchain.toolsimportToolRuntime,toolfromlanggraph.typesimportCommandclassCustomState(AgentState):user_name:strtooldefset_user_name(new_name:str,runtime:ToolRuntime[None,CustomState])-Command:Set the users name in the conversation state.returnCommand(update{user_name:new_name,messages:[ToolMessage(contentfUser name set to{new_name}.,tool_call_idruntime.tool_call_id,)],})注意 如果工具更新状态变量考虑为这些字段定义 reducer解决并发工具调用时的冲突。3.2 上下文不可变配置context上下文是在调用时传递的不可变配置数据用户 ID、会话信息等。fromdataclassesimportdataclassfromlangchain_openaiimportChatOpenAIfromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttool,ToolRuntimedataclassclassUserContext:user_id:strtooldefget_account_info(runtime:ToolRuntime[UserContext])-str:Get the current users account information.user_idruntime.context.user_idifuser_idinUSER_DATABASE:userUSER_DATABASE[user_id]returnfAccount holder:{user[name]}\nType:{user[account_type]}\nBalance: ${user[balance]}returnUser not found创建代理时传入上下文模式agentcreate_agent(ChatOpenAI(modelgpt-5.4),tools[get_account_info],context_schemaUserContext,system_promptYou are a financial assistant.)调用时传入具体上下文resultagent.invoke({messages:[{role:user,content:Whats my current balance?}]},contextUserContext(user_iduser123))3.3 长期记忆存储存储BaseStore提供跨对话持久存在的存储。与状态不同保存到存储的数据在未来会话仍可用。fromtypingimportAnyfromlanggraph.store.memoryimportInMemoryStorefromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttool,ToolRuntimetooldefget_user_info(user_id:str,runtime:ToolRuntime)-str:Look up user info.storeruntime.store user_infostore.get((users,),user_id)returnstr(user_info.value)ifuser_infoelseUnknown usertooldefsave_user_info(user_id:str,user_info:dict[str,Any],runtime:ToolRuntime)-str:Save user info.storeruntime.store store.put((users,),user_id,user_info)returnSuccessfully saved user info.storeInMemoryStore()# 生产环境用 PostgresStoreagentcreate_agent(ChatOpenAI(modelgpt-5.4),tools[get_user_info,save_user_info],storestore)# 第一次会话保存用户信息agent.invoke({messages:[{role:user,content:Save: user abc123, name: Foo, age: 25}]})# 第二次会话获取用户信息agent.invoke({messages:[{role:user,content:Get user info for abc123}]})# 能拿到之前保存的信息三种记忆的对比核心概念比喻生命周期能否修改访问方式state状态本次通话的草稿纸本次对话结束即丢可读可写runtime.statecontext上下文你的身份工牌本次调用期间不变只读不可变runtime.contextstore存储公司的档案柜跨对话永久保存可读可写runtime.store一句话区分state本次通话中的临时过程数据“通话结束就忘”context本次调用定死的配置如 user_id“通话期间不变”store跨对话永久保存的数据“永远都在”四、工具节点ToolNodeToolNode 是预构建节点用于在 LangGraph 工作流中执行工具。自动处理并行工具执行、错误处理和状态注入。fromlangchain.toolsimporttoolfromlanggraph.prebuiltimportToolNodefromlanggraph.graphimportStateGraph,MessagesState,START,ENDtooldefsearch(query:str)-str:Search for information.returnfResults for:{query}tooldefcalculator(expression:str)-str:Evaluate a math expression.returnstr(eval(expression))# 创建工具节点tool_nodeToolNode([search,calculator])# 在图中使用builderStateGraph(MessagesState)builder.add_node(tools,tool_node)# ... 添加其他节点和边4.1 错误处理配置工具错误的处理方式fromlanggraph.prebuiltimportToolNode# 默认捕获调用错误重新抛出执行错误tool_nodeToolNode(tools)# 捕获所有错误返回错误消息给 LLMtool_nodeToolNode(tools,handle_tool_errorsTrue)# 自定义错误消息tool_nodeToolNode(tools,handle_tool_errorsSomething went wrong, please try again.)# 自定义错误处理器defhandle_error(e:ValueError)-str:returnfInvalid input:{e}tool_nodeToolNode(tools,handle_tool_errorshandle_error)# 只捕获特定异常类型tool_nodeToolNode(tools,handle_tool_errors(ValueError,TypeError))4.2 路由tools_condition根据 LLM 是否进行了工具调用进行条件路由fromlanggraph.prebuiltimportToolNode,tools_conditionfromlanggraph.graphimportStateGraph,MessagesState,START,END builderStateGraph(MessagesState)builder.add_node(llm,call_llm)builder.add_node(tools,ToolNode(tools))builder.add_edge(START,llm)builder.add_conditional_edges(llm,tools_condition)# 路由到 tools 或 ENDbuilder.add_edge(tools,llm)graphbuilder.compile()五、工具返回值5.1 返回字符串提供纯文本供模型读取tooldefget_weather(city:str)-str:Get weather for a city.returnfIt is currently sunny in{city}.行为返回值被转换为 ToolMessage模型看到文本并决定下一步智能体状态字段不会改变5.2 返回对象返回结构化数据如 dicttooldefget_weather_data(city:str)-dict:Get structured weather data for a city.return{city:city,temperature_c:22,conditions:sunny,}行为对象被序列化并作为工具输出返回模型可以读取特定字段并推理5.3 返回 Command当工具需要更新图状态时fromlangchain.messagesimportToolMessagefromlangchain.toolsimportToolRuntime,toolfromlanggraph.typesimportCommandtooldefset_language(language:str,runtime:ToolRuntime)-Command:Set the preferred response language.returnCommand(update{preferred_language:language,messages:[ToolMessage(contentfLanguage set to{language}.,tool_call_idruntime.tool_call_id,)],})行为Command 用 update 更新状态更新后的状态可供后续步骤使用如果模型需要看到工具成功在更新中包含 ToolMessage总结工具 可调用函数用 tool 装饰器创建三种访问上下文的方式- runtime.state —— 短期记忆当前对话- runtime.context —— 不可变配置用户 ID 等- runtime.store —— 长期记忆跨对话持久化三种返回值- 字符串 —— 纯文本结果- 对象 —— 结构化数据- Command —— 更新状态ToolNode —— 在 LangGraph 工作流中执行工具的预构建节点工具是代理的手脚让模型不仅能思考还能行动。通过 ToolRuntime工具可以访问对话历史、用户信息、长期记忆等功能更强大。
LangChain -- 工具(Tools)
一、工具是什么工具就是可调用函数有明确的输入和输出传递给聊天模型。模型根据对话上下文决定何时调用工具、传什么参数。简单说模型是大脑工具是手脚。模型思考后决定要不要用工具、用哪个工具、怎么调工具。二、创建工具2.1 最简单的方式用 tool 装饰器fromlangchain.toolsimporttooltooldefsearch_database(query:str,limit:int10)-str:Search the customer database for records matching the query. Args: query: Search terms to look for limit: Maximum number of results to return returnfFound{limit}results for {query}关键点类型提示是必需的如 query: str它们定义了工具的输入模式文档字符串很重要默认会成为工具描述帮助模型理解何时使用工具名建议用 snake_case如 web_search不要用空格或特殊字符2.2 自定义工具属性自定义名称tool(web_search)# 自定义名称defsearch(query:str)-str:Search the web for information.returnfResults for:{query}print(search.name)# web_search自定义描述tool(calculator,descriptionPerforms arithmetic calculations. Use this for any math problems.)defcalc(expression:str)-str:Evaluate mathematical expressions.returnstr(eval(expression))用 Pydantic 定义复杂输入frompydanticimportBaseModel,FieldfromtypingimportLiteralclassWeatherInput(BaseModel):Input for weather queries.location:strField(descriptionCity name or coordinates)units:Literal[celsius,fahrenheit]Field(defaultcelsius,descriptionTemperature unit preference)include_forecast:boolField(defaultFalse,descriptionInclude 5-day forecast)tool(args_schemaWeatherInput)defget_weather(location:str,units:strcelsius,include_forecast:boolFalse)-str:Get current weather and optional forecast.temp22ifunitscelsiuselse72resultfCurrent weather in{location}:{temp}degrees{units[0].upper()}ifinclude_forecast:result\nNext 5 days: Sunnyreturnresult2.3 保留参数名这两个名字是保留的不能用作工具参数config —— 保留给 RunnableConfigruntime —— 保留给 ToolRuntime访问状态、上下文、存储三、访问上下文工具可以访问运行时信息功能更强大。通过 ToolRuntime 参数访问。3.1 短期记忆状态state状态是存在于当前对话期间的可变数据消息、计数器、自定义字段。访问状态fromlangchain.toolsimporttool,ToolRuntimefromlangchain.messagesimportHumanMessagetooldefget_last_user_message(runtime:ToolRuntime)-str:Get the most recent message from the user.messagesruntime.state[messages]# 找最后一条人类消息formessageinreversed(messages):ifisinstance(message,HumanMessage):returnmessage.contentreturnNo user messages found关键 runtime 参数会自动注入对 LLM 隐藏——不会出现在工具模式里。还可以用 Command 更新智能体的state状态fromlangchain.agentsimportAgentStatefromlangchain.messagesimportToolMessagefromlangchain.toolsimportToolRuntime,toolfromlanggraph.typesimportCommandclassCustomState(AgentState):user_name:strtooldefset_user_name(new_name:str,runtime:ToolRuntime[None,CustomState])-Command:Set the users name in the conversation state.returnCommand(update{user_name:new_name,messages:[ToolMessage(contentfUser name set to{new_name}.,tool_call_idruntime.tool_call_id,)],})注意 如果工具更新状态变量考虑为这些字段定义 reducer解决并发工具调用时的冲突。3.2 上下文不可变配置context上下文是在调用时传递的不可变配置数据用户 ID、会话信息等。fromdataclassesimportdataclassfromlangchain_openaiimportChatOpenAIfromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttool,ToolRuntimedataclassclassUserContext:user_id:strtooldefget_account_info(runtime:ToolRuntime[UserContext])-str:Get the current users account information.user_idruntime.context.user_idifuser_idinUSER_DATABASE:userUSER_DATABASE[user_id]returnfAccount holder:{user[name]}\nType:{user[account_type]}\nBalance: ${user[balance]}returnUser not found创建代理时传入上下文模式agentcreate_agent(ChatOpenAI(modelgpt-5.4),tools[get_account_info],context_schemaUserContext,system_promptYou are a financial assistant.)调用时传入具体上下文resultagent.invoke({messages:[{role:user,content:Whats my current balance?}]},contextUserContext(user_iduser123))3.3 长期记忆存储存储BaseStore提供跨对话持久存在的存储。与状态不同保存到存储的数据在未来会话仍可用。fromtypingimportAnyfromlanggraph.store.memoryimportInMemoryStorefromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttool,ToolRuntimetooldefget_user_info(user_id:str,runtime:ToolRuntime)-str:Look up user info.storeruntime.store user_infostore.get((users,),user_id)returnstr(user_info.value)ifuser_infoelseUnknown usertooldefsave_user_info(user_id:str,user_info:dict[str,Any],runtime:ToolRuntime)-str:Save user info.storeruntime.store store.put((users,),user_id,user_info)returnSuccessfully saved user info.storeInMemoryStore()# 生产环境用 PostgresStoreagentcreate_agent(ChatOpenAI(modelgpt-5.4),tools[get_user_info,save_user_info],storestore)# 第一次会话保存用户信息agent.invoke({messages:[{role:user,content:Save: user abc123, name: Foo, age: 25}]})# 第二次会话获取用户信息agent.invoke({messages:[{role:user,content:Get user info for abc123}]})# 能拿到之前保存的信息三种记忆的对比核心概念比喻生命周期能否修改访问方式state状态本次通话的草稿纸本次对话结束即丢可读可写runtime.statecontext上下文你的身份工牌本次调用期间不变只读不可变runtime.contextstore存储公司的档案柜跨对话永久保存可读可写runtime.store一句话区分state本次通话中的临时过程数据“通话结束就忘”context本次调用定死的配置如 user_id“通话期间不变”store跨对话永久保存的数据“永远都在”四、工具节点ToolNodeToolNode 是预构建节点用于在 LangGraph 工作流中执行工具。自动处理并行工具执行、错误处理和状态注入。fromlangchain.toolsimporttoolfromlanggraph.prebuiltimportToolNodefromlanggraph.graphimportStateGraph,MessagesState,START,ENDtooldefsearch(query:str)-str:Search for information.returnfResults for:{query}tooldefcalculator(expression:str)-str:Evaluate a math expression.returnstr(eval(expression))# 创建工具节点tool_nodeToolNode([search,calculator])# 在图中使用builderStateGraph(MessagesState)builder.add_node(tools,tool_node)# ... 添加其他节点和边4.1 错误处理配置工具错误的处理方式fromlanggraph.prebuiltimportToolNode# 默认捕获调用错误重新抛出执行错误tool_nodeToolNode(tools)# 捕获所有错误返回错误消息给 LLMtool_nodeToolNode(tools,handle_tool_errorsTrue)# 自定义错误消息tool_nodeToolNode(tools,handle_tool_errorsSomething went wrong, please try again.)# 自定义错误处理器defhandle_error(e:ValueError)-str:returnfInvalid input:{e}tool_nodeToolNode(tools,handle_tool_errorshandle_error)# 只捕获特定异常类型tool_nodeToolNode(tools,handle_tool_errors(ValueError,TypeError))4.2 路由tools_condition根据 LLM 是否进行了工具调用进行条件路由fromlanggraph.prebuiltimportToolNode,tools_conditionfromlanggraph.graphimportStateGraph,MessagesState,START,END builderStateGraph(MessagesState)builder.add_node(llm,call_llm)builder.add_node(tools,ToolNode(tools))builder.add_edge(START,llm)builder.add_conditional_edges(llm,tools_condition)# 路由到 tools 或 ENDbuilder.add_edge(tools,llm)graphbuilder.compile()五、工具返回值5.1 返回字符串提供纯文本供模型读取tooldefget_weather(city:str)-str:Get weather for a city.returnfIt is currently sunny in{city}.行为返回值被转换为 ToolMessage模型看到文本并决定下一步智能体状态字段不会改变5.2 返回对象返回结构化数据如 dicttooldefget_weather_data(city:str)-dict:Get structured weather data for a city.return{city:city,temperature_c:22,conditions:sunny,}行为对象被序列化并作为工具输出返回模型可以读取特定字段并推理5.3 返回 Command当工具需要更新图状态时fromlangchain.messagesimportToolMessagefromlangchain.toolsimportToolRuntime,toolfromlanggraph.typesimportCommandtooldefset_language(language:str,runtime:ToolRuntime)-Command:Set the preferred response language.returnCommand(update{preferred_language:language,messages:[ToolMessage(contentfLanguage set to{language}.,tool_call_idruntime.tool_call_id,)],})行为Command 用 update 更新状态更新后的状态可供后续步骤使用如果模型需要看到工具成功在更新中包含 ToolMessage总结工具 可调用函数用 tool 装饰器创建三种访问上下文的方式- runtime.state —— 短期记忆当前对话- runtime.context —— 不可变配置用户 ID 等- runtime.store —— 长期记忆跨对话持久化三种返回值- 字符串 —— 纯文本结果- 对象 —— 结构化数据- Command —— 更新状态ToolNode —— 在 LangGraph 工作流中执行工具的预构建节点工具是代理的手脚让模型不仅能思考还能行动。通过 ToolRuntime工具可以访问对话历史、用户信息、长期记忆等功能更强大。