
工具扩展了 AgentAgent我们下一小节介绍的功能——使它们能够获取实时数据、执行代码、查询外部数据库并在现实世界中采取行动。在底层工具是具有明确定义输入和输出的可调用函数这些函数会被传递给聊天模型。模型会根据对话上下文决定何时调用工具以及需要提供哪些输入参数。Tool 是让 Agent 能够与外部世界交互的核心组件本质上是有明确输入输出定义的可调用函数。模型根据对话上下文决定何时调用工具以及传入什么参数。Tool 由三部分组成名称、描述和参数 schema使用 Zod 定义。模型读取这些信息来理解工具的用途并正确调用。在 LLM 应用开发中Tool 是实现 Agent智能体的核心组件。核心概念在 LangChain 中Tool 本质上就是一个函数它包含三个核心要素名称大模型用来识别和调用该工具的唯一标识。 描述告诉大模型这个工具是做什么的什么时候应该调用它。描述的质量直接决定了模型是否会准确调用 执行逻辑当大模型决定调用该工具时实际运行的代码逻辑。 工作流用户输入 - Agent 判断是否需要使用 Tool - LLM 返回 Tool 名称和参数 - LangChain 执行 Tool - 将执行结果返回给 LLM - LLM 生成最终回答。创建工具基本工具定义创建工具最简单的方法是从包中导入tool函数langchain。可以使用zod定义工具的输入模式使用 tool 函数 最推荐这是目前 LangChain.js 最推荐的声明式写法结合 Zod 进行参数类型校验清晰且安全。import*aszfromzodimport{tool}fromlangchain// 1. 定义 Schema (约束大模型传入的参数)constweatherSchemaz.object({city:z.string().describe(需要查询天气的城市名称),unit:z.enum([celsius,fahrenheit]).optional().describe(温度单位)});// 2. 创建 ToolconstgetWeatherTooltool(async({city,unit}){// 这里的逻辑在实际应用中是调用外部天气 APIif(city北京){return${city}今天晴朗温度 25${unitcelsius?°C:°F};}return${city}今天多云;},{name:get_weather,// 工具名称description:获取指定城市的当前天气情况,// 工具描述schema:weatherSchema,// 绑定 Schema});console.log(awaitgetWeatherTool.invoke({city:北京,unit:celsius}));// 输出: 北京今天晴朗温度 25°C北京今天晴朗温度 25°CTool 的核心属性解析写好 Tool 的关键在于描述和Schema。描述的编写艺术大模型完全依赖 description 来决定是否调用该工具。一个好的描述应该 清晰说明功能不要写“处理数据”要写“根据城市名称获取实时天气数据”。 说明适用场景例如“当用户询问天气、气温、下雨情况时使用此工具”。 说明不适用场景例如“不要用此工具查询新闻”。Zod Schema 的作用z.string(), z.number() 等类型约束可以防止大模型传入错误类型的数据。 .describe() 极其重要它是对单个参数的解释帮助大模型理解应该传什么值进去。错误处理如果工具调用出错了怎么办不应该让程序崩溃而应该将错误信息返回给 LLM让它尝试自我修正。当 LLM 收到“除数不能为0”的返回时它可能会换一个参数重新调用或者向用户解释不能除以0。constsafeCalculatortool(async(input){try{// 模拟可能出错的逻辑if(input.b0)thrownewError(除数不能为0);returninput.a/input.b;}catch(error:any){// 关键将错误信息作为字符串返回而不是 throwreturn工具调用出错:${error.message};}},{name:safe_divide,description:除法计算,schema:z.object({a:z.number(),b:z.number()})});使用内置工具LangChain 社区提供了大量现成的工具如网页搜索、数据库查询等。通过包 langchain/community 引入。npm install langchain/communityimport{SerpAPI}fromlangchain/community/tools/serpapi;// 使用 Google 搜索工具 (需配置 SERPAPI_API_KEY)constsearchToolnewSerpAPI(process.env.SERPAPI_API_KEY,{hl:cn,gl:cn,});Stack trace: Error: SerpAPI API key not set. You can set it as SERPAPI_API_KEY in your .env file, or pass it to SerpAPI. at new SerpAPI (file:///Users/cheney/Documents/trae_projects/js/langchain-demo/node_modules/langchain/community/dist/tools/serpapi.js:315:13) at anonymous:3:20在 Tool 中访问运行时状态有时工具在执行时需要知道当前的用户 ID 或请求上下文。可以通过 RunnableConfig 传递。import{RunnableConfig}fromlangchain/core/runnables;constqueryDatabaseTooltool(async(input,config:RunnableConfig){// 从 config 中获取元数据constuserIdconfig?.configurable?.userId;return查询到了用户${userId}的数据: ...;},{name:query_user_db,description:查询当前用户的数据库信息,schema:z.object({query:z.string()}),});// 调用时传入:// agentExecutor.invoke({ input: ... }, { configurable: { userId: 12345 } });服务器端工具使用某些聊天模型内置了在服务器端执行的工具例如网页搜索、代码解释器。详情请参阅“服务器端工具使用”部分。工具名称最好使用字母数字下划线分割例如web_search而不是空格Web Search。某些模型提供商对包含空格或特殊字符的名称存在兼容性问题甚至会报错。坚持使用字母数字字符、下划线和连字符有助于提高不同提供商之间的兼容性。让Tool更聪明访问上下文工具在能够访问运行时信息例如对话历史记录、用户数据和持久内存时其功能最为强大。只有能够访问到这些信息工具才能根据上下文进行决策和执行。就像给Tool配一个“秘书”让它知道是谁在调用、在什么场景下调用import*aszfromzod;import{ChatOpenAI}fromlangchain/openai;import{createAgent,tool}fromlangchain;constgetUserNametool((user_me,config){// 从配置中读取用户名constuserNameconfig.context.user_name;// 从上下文获取用户名if(user_meuserName){returnuserName;}returnI dont know your name.;},{name:get_user_name,description:Get the current users name.,schema:z.object({}),},);// 定义上下文结构constcontextSchemaz.object({user_name:z.string(),});constagentcreateAgent({model:newChatOpenAI({model:google-genai:gemini-3.5-flash}),tools:[getUserName],contextSchema,// 告诉Agent上下文长什么样});// 调用时传入上下文constresultawaitagent.invoke({messages:[{role:user,content:What is my name?}],},{configurable:{thread_id:crypto.randomUUID()},// 会话IDcontext:{user_name:John Smith},// 上下文数据},);长期记忆Store让Tool拥有“记忆”跨会话记住信息它BaseStore提供持久存储数据可在会话之间保留。与状态短期记忆不同保存到存储中的数据在以后的会话中仍然可用。 通过以下方式访问存储库config.store。存储库使用命名空间/键模式来组织数据import*aszfromzod;import{createAgent,tool}fromlangchain;import{InMemoryStore}fromlangchain/langgraph;import{ChatOpenAI}fromlangchain/openai;conststorenewInMemoryStore();// 内存存储生产环境可用数据库// 写入记忆constsaveUserInfotool(async({user_id,name,age,email}){awaitstore.put([users],user_id,{name,age,email});returnSuccessfully saved user info.;},{name:save_user_info,description:Save user info.,schema:z.object({user_id:z.string(),name:z.string(),age:z.number(),email:z.string(),}),},);// 读取记忆constgetUserInfotool(async({user_id}){constvalueawaitstore.get([users],user_id);returnvalue;},{name:get_user_info,description:Look up user info.,schema:z.object({user_id:z.string()}),},);constagentcreateAgent({model:newChatOpenAI({model:gpt-5.4}),tools:[getUserInfo,saveUserInfo],store,// 把存储交给Agent管理});// 第一次会话保存用户信息awaitagent.invoke({messages:[{role:user,content:Save the following user: userid: abc123, name: Foo, age: 25, email: foolangchain.dev},],});// 第二次会话查询用户信息记忆跨会话保留constresultawaitagent.invoke({messages:[{role:user,content:Get user info for user with id abc123},],});流式输出Stream Writer给Tool加个“进度条”实时告诉用户它在干什么在工具执行过程中实时传输工具的更新信息。这对于在长时间运行的操作期间向用户提供进度反馈非常有用。 用于config.writer发出自定义更新import*aszfromzod;import{tool,ToolRuntime}fromlangchain;constgetWeathertool(({city},config:ToolRuntime){constwriterconfig.writer;// 像打字一样输出进度if(writer){writer(Looking up data for city:${city});// 打印查找数据的进度writer(Acquired data for city:${city});// 打印数据获取完成的进度}returnIts always sunny in${city}!;},{name:get_weather,description:Get weather for a given city.,schema:z.object({city:z.string()}),},);执行信息通过以下方式从工具内部访问线程 ID、运行 ID 和重试状态runtime.execution_infoimport{tool}fromlangchain;import*aszfromzod;constlogExecutionContexttool(async(_input,runtime){constinforuntime.executionInfo;console.log(Thread:${info.threadId}, Run:${info.runId});console.log(Attempt:${info.nodeAttempt});returndone;},{name:log_execution_context,description:Log execution identity information.,schema:z.object({}),});Tool返回值不只是字符串Tool不仅能返回字符串还能返回结构化数据甚至直接控制流程constweatherTooltool(({city}){// 返回对象而不是字符串return{city:city,temperature:25,condition:晴朗,humidity:45,};},{name:get_weather_detailed,description:获取详细天气信息,schema:z.object({city:z.string()}),},);实战组合Tool Agent 完整流程import{ChatOpenAI}fromlangchain/openai;import{createAgent,tool}fromlangchain;import*aszfromzod;// 1. 创建工具constsearchTooltool(({query})搜索结果关于${query}的信息...,{name:web_search,description:搜索互联网获取实时信息,schema:z.object({query:z.string().describe(搜索关键词)}),},);constcalculatorTooltool(({expression}){// 实际应用中这里用eval或数学库return计算结果${expression};},{name:calculator,description:执行数学计算,schema:z.object({expression:z.string().describe(数学表达式)}),},);// 2. 创建AgentconstagentcreateAgent({model:newChatOpenAI({temperature:0}),tools:[searchTool,calculatorTool],});// 3. 运行Agentconstresultawaitagent.invoke({messages:[{role:user,content:搜索一下LangChain最新版本然后计算20242025等于多少},],});console.log(result);