ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TypeScript + LangChain 实战:从零构建具备工具调用能力的 AI Agent

TypeScript + LangChain 实战:从零构建具备工具调用能力的 AI Agent 1. 项目缘起为什么选择 LangChain TypeScript 来构建 AI Agent最近和几个做前端和全栈的朋友聊天发现一个挺有意思的现象大家一提到搞 AI 应用尤其是 Agent智能体第一反应就是上 Python。这当然没错Python 生态在 AI 领域确实如鱼得水库多、教程多、社区活跃。但这就让很多深耕 JavaScript/TypeScript 生态的开发者有点尴尬——难道为了玩转 AI就得先把自己变成半个 Python 程序员吗特别是对于那些想快速将 AI 能力集成到现有 Web 应用、Node.js 后端或者桌面工具里的团队来说上下文切换和技术栈割裂带来的成本不容小觑。这正是我决定动手尝试用LangChain TypeScript这套组合拳从零开始搭建一个 AI Agent 的初衷。LangChain 大家不陌生它本质上是一个用于构建由大语言模型驱动的应用程序的框架提供了链Chains、代理Agents、检索Retrieval等高层抽象把调用模型、管理上下文、使用工具这些脏活累活都封装好了。而它的 TypeScript/JavaScript 版本经过这几年的迭代已经相当成熟不再是 Python 版的“附属品”拥有了自己完整的文档、活跃的社区和不断丰富的工具集成。那么用 TypeScript 写 AI Agent 到底香在哪里从我实际的体验来看至少有这么几点实实在在的好处。首先类型安全。当你定义工具Tools、提示词模板Prompt Templates或者解析模型输出时TypeScript 的强类型能极大减少运行时错误特别是在处理复杂的嵌套 JSON 或不确定的模型返回时类型提示和接口定义就是最好的文档和保镖。其次无缝集成。如果你的技术栈本身就是 Node.js、Next.js、Express 或者 Electron那么用 TypeScript 写的 Agent 可以毫无障碍地融入现有项目共享工具函数、配置管理和部署流程避免了跨语言调用的额外开销和复杂度。最后开发体验。对于前端/全栈开发者而言在熟悉的 VS Code 环境里享受着智能补全、一键重构和强大的 npm 生态开发效率自然更高。这次实战我们的目标不是复刻一个 ChatGPT而是构建一个具备特定能力的、可交互的 AI Agent。想象一下一个能帮你查询天气、搜索最新资讯、甚至根据你的指令操作电脑文件的“数字助手”。我们将一步步拆解这个过程从环境搭建、核心概念理解到工具定义、Agent 组装最后让它真正“跑”起来并响应指令。过程中我会穿插很多实际编码时遇到的“坑”和解决思路这些都是在官方文档里不会明说的细节。无论你是想为你的产品添加一个智能客服入口还是单纯对 AI 应用开发感兴趣希望这篇手记都能给你带来一条清晰、可复现的路径。2. 环境奠基搭建稳健的 TypeScript 开发与 LangChain 运行环境工欲善其事必先利其器。在开始写第一行 Agent 代码之前一个干净、可控的开发环境是后续一切顺利的基础。这里我强烈推荐使用Node.js的版本管理工具和TypeScript的现代配置这能帮你避开很多因环境差异导致的诡异问题。2.1 核心运行环境配置首先确保你有一个合适的 Node.js 环境。我个人习惯使用nvm(Node Version Manager) 来管理多个 Node.js 版本这对于同时维护多个不同年代的项目非常友好。如果你还没有安装可以参照其官方仓库的说明进行安装。安装完成后选择一个稳定的长期支持LTS版本比如20.x。在终端中执行nvm install 20 nvm use 20验证安装node --version应该输出类似v20.11.0的版本号。接下来为我们的项目创建一个独立的目录并初始化 npmmkdir my-ai-agent cd my-ai-agent npm init -y这会在目录下生成一个package.json文件。我们马上要安装的依赖会记录在这里。2.2 TypeScript 与必要依赖安装现在安装 TypeScript 编译器以及开发时需要的类型定义。我们使用-D标志将它们安装为开发依赖npm install -D typescript types/node接着初始化 TypeScript 配置。运行npx tsc --init这会在项目根目录生成一个tsconfig.json文件。这个文件决定了 TypeScript 如何编译你的代码。对于 LangChain 项目我建议进行以下关键调整打开tsconfig.json文件修改{ compilerOptions: { target: ES2022, // 使用较新的 ECMAScript 标准 module: NodeNext, // 使用 Node.js 的模块系统 moduleResolution: NodeNext, outDir: ./dist, // 编译输出目录 rootDir: ./src, // 源代码目录 strict: true, // 启用所有严格类型检查选项 esModuleInterop: true, // 改善对 CommonJS 模块的兼容性 skipLibCheck: true, // 跳过库文件的类型检查以加快编译速度对 LangChain 这种大库很实用 forceConsistentCasingInFileNames: true, resolveJsonModule: true // 允许导入 JSON 文件 }, include: [src/**/*], // 包含 src 目录下所有文件 exclude: [node_modules, dist] }这个配置明确了源代码放在src目录编译后的 JavaScript 会输出到dist目录并且开启了严格的类型检查这对构建复杂应用至关重要。2.3 LangChain 与模型接入依赖核心来了安装 LangChain 的 TypeScript SDK。由于我们要构建的 Agent 可能需要调用不同的工具和模型我们先安装核心包和一些常用组件npm install langchain为了让我们写的 Agent 能“思考”和“说话”我们需要连接一个大语言模型。这里有几个主流选择OpenAI API最通用模型能力强但需要付费。本地模型通过ollama、llama.cpp或vLLM等在本地部署免费但需要一定的机器资源。其他云服务如 Anthropic Claude、Google Gemini 等。为了教程的通用性和可复现性我们选择OpenAI API作为示例因为它配置最简单效果也稳定。同时我们也会安装dotenv来管理敏感的环境变量比如 API Key。npm install langchain/openai dotenv安装完成后在项目根目录创建一个.env文件切记要将此文件加入.gitignore不要提交到代码仓库并填入你的 OpenAI API KeyOPENAI_API_KEYsk-your-actual-api-key-here注意在实际项目中请务必使用环境变量或安全的密钥管理服务来存储 API Key绝对不要硬编码在源代码中。2.4 项目结构与启动脚本让我们建立清晰的项目结构。在根目录下创建src文件夹并在其中创建我们的入口文件src/index.ts。为了让开发过程更流畅我们在package.json中添加一些实用的脚本{ scripts: { dev: tsx src/index.ts, // 使用 tsx 进行即时开发运行 build: tsc, // 编译 TypeScript start: node dist/index.js // 运行编译后的代码 } }这里我引入了tsx它是一个极快的 TypeScript 执行器无需先编译就能直接运行.ts文件非常适合开发阶段。安装它npm install -D tsx。至此你的项目目录结构应该大致如下my-ai-agent/ ├── node_modules/ ├── src/ │ └── index.ts ├── .env ├── .gitignore ├── package.json ├── package-lock.json └── tsconfig.json在src/index.ts里写一句简单的console.log(“Hello AI Agent!”)然后运行npm run dev。如果终端成功打印出问候语恭喜你一个坚固的 TypeScript LangChain 开发地基已经打好了。这个环境配置虽然步骤不少但一次配好后续所有的开发、调试、依赖管理都会变得非常顺畅是避免“跑不起来”这类低级错误的最佳投资。3. 概念先行深入理解 LangChain 中 Agent 的核心组件与工作流在动手写代码之前我们必须先搞清楚 LangChain 框架里一个 AI Agent 到底是由哪些“乐高积木”拼装起来的以及它们是如何协同工作的。如果直接跳进代码很容易被各种类和方法搞晕。理解这些核心概念能让你在后续设计和调试时心中有图事半功倍。3.1 大脑语言模型LLM与聊天模型ChatModel这是 Agent 的“思考器官”。在 LangChain 中LLM和ChatModel是两类主要的模型抽象。LLM接收一个字符串提示prompt返回一个字符串补全completion。它更接近于传统的大语言模型调用方式。ChatModel接收一个消息列表BaseMessage[]返回一个消息AIMessage。消息有角色如HumanMessage用户、AIMessage助手、SystemMessage系统。这是与 ChatGPT 这类对话式模型交互的更自然的方式。对于构建交互式 Agent我们几乎总是使用ChatModel因为它天然支持多轮对话的上下文管理。在 TypeScript 中我们这样初始化一个 OpenAI 的聊天模型import { ChatOpenAI } from “langchain/openai”; import ‘dotenv/config’; // 加载 .env 中的环境变量 const llm new ChatOpenAI({ modelName: “gpt-4o”, // 或 “gpt-3.5-turbo” temperature: 0.7, // 控制创造性0为最确定1为最随机 apiKey: process.env.OPENAI_API_KEY, // 从环境变量读取 });这里的temperature参数很重要。对于需要执行确定步骤的 Agent比如进行数学计算或数据查询建议设置较低的值如 0.1-0.3让输出更稳定。对于需要创造性的任务比如写诗可以调高。3.2 手脚工具ToolsAgent 之所以能超越简单的聊天机器人在于它能使用“工具”来与环境互动。一个工具本质上是一个可以被模型调用的函数。它有一个名字、一个描述以及一个执行函数。模型的描述至关重要因为 Agent 是根据你对工具功能的文字描述来决定是否以及何时调用它的。例如一个“获取当前天气”的工具可能这样定义import { DynamicStructuredTool } from “langchain/core/tools”; import { z } from “zod”; // 用于定义输入参数的 schema const fetchWeatherTool new DynamicStructuredTool({ name: “get_current_weather”, description: “获取指定城市的当前天气情况。输入必须是城市名。”, schema: z.object({ location: z.string().describe(“城市名称例如北京 San Francisco”), }), func: async ({ location }) { // 这里模拟一个天气 API 调用 console.log(正在查询 ${location} 的天气...); // 实际项目中这里会是 fetch(‘https://api.weather.com/...‘) const mockWeather 地点${location}天气晴朗温度22°C; return mockWeather; }, });注意我们使用了DynamicStructuredTool和zod库。zod用于定义工具输入参数的结构和类型这能确保模型以正确的格式调用工具也让我们在代码中获得完美的类型提示和验证。description字段要写得清晰、准确让模型明白在什么场景下该用它。3.3 调度中心代理执行器AgentExecutor这是将大脑模型和手脚工具粘合在一起并管理整个推理循环的“调度中心”。你不需要自己写while循环来判断“模型下一步该思考还是该行动”。AgentExecutor帮你处理了这一切将用户输入和对话历史组合成提示。将提示发送给模型。解析模型的输出判断是生成最终答案还是调用某个工具。如果调用工具则执行工具函数并将工具返回的结果作为新的上下文再次发送给模型。重复步骤 2-4直到模型决定给出最终答案。在 LangChain 中你需要先选择一个“代理类型”Agent Type它决定了提示词的模板和推理逻辑。最常用的是createReactAgent它基于 ReAct (Reasoning Acting) 框架让模型以“思考 - 行动 - 观察”的循环来解决问题效果非常好。import { createReactAgent } from “langchain/core/agents”; // 假设我们已经有了 llm 和 tools 数组包含 fetchWeatherTool const tools [fetchWeatherTool]; const agent createReactAgent({ llm, tools, });然后用这个agent和tools来创建AgentExecutorimport { AgentExecutor } from “langchain/agents”; const executor AgentExecutor.fromAgentAndTools({ agent, tools, // 可选的配置项 returnIntermediateSteps: true, // 是否返回中间步骤调试时非常有用 maxIterations: 5, // 最大迭代次数防止死循环 });maxIterations是一个重要的安全阀。因为模型有时会陷入“工具调用 - 观察结果 - 再次调用同一工具”的死循环设置一个上限比如 5-10 次可以强制终止避免浪费 API 调用。3.4 记忆与状态管理对话上下文一个有用的 Agent 应该能记住之前的对话。LangChain 提供了多种“记忆Memory”后端比如BufferMemory保存最近的 N 轮对话、ConversationSummaryMemory总结历史对话等。对于简单的 Agent我们可以使用BufferMemory。import { BufferMemory } from “langchain/memory”; const memory new BufferMemory({ memoryKey: “chat_history”, // 存储在记忆中的键名 returnMessages: true, // 以消息格式返回 });在创建AgentExecutor时可以将memory传入这样执行器会自动管理对话历史的存储和读取。理解了这个工作流用户输入 - 结合记忆形成提示 - 模型推理 - 可能调用工具 - 更新记忆 - 输出你就掌握了 LangChain Agent 最核心的运转机制。接下来我们就可以用这些“积木”搭建一个具体的 Agent 了。4. 实战构建打造一个能查天气、搜新闻的多功能 AI Agent理论铺垫足够现在进入最激动人心的环节亲手组装一个具备真实功能的 AI Agent。我们的目标是构建一个“信息助手”它至少能完成两件事查询指定城市的天气以及搜索最新的新闻摘要。我们将严格按照“定义工具 - 组装代理 - 测试运行”的流程进行并深入每个环节的细节和可能遇到的问题。4.1 定义并封装两个核心工具首先在src目录下创建一个tools文件夹并在其中创建weather.tool.ts和news.tool.ts。将工具定义模块化是个好习惯。工具一天气查询工具 (src/tools/weather.tool.ts)我们将使用一个免费的天气 API 作为示例例如 Open-Meteo。你需要先安装axios或使用原生的fetch。这里用axiosnpm install axios。import { DynamicStructuredTool } from “langchain/core/tools”; import { z } from “zod”; import axios from “axios”; // 定义工具输入参数的 Schema const weatherInputSchema z.object({ location: z.string().describe(“The city and country, e.g., ‘London, UK’ or ‘Tokyo, Japan’.”), }); export const fetchWeatherTool new DynamicStructuredTool({ name: “get_current_weather”, description: “Fetches the current weather conditions for a given location. Use this when the user asks about weather, temperature, or climate.”, schema: weatherInputSchema, func: async ({ location }) { try { // 这里以 Open-Meteo API 为例实际使用时请查阅其最新文档 // 为了简化我们假设 location 是城市名实际 API 可能需要经纬度或城市ID console.log([Tool Call] Fetching weather for: ${location}); // 模拟 API 调用 - 实际代码需要处理地理编码、错误等 // const response await axios.get(https://api.open-meteo.com/v1/forecast?…city${encodeURIComponent(location)}); // const data response.data; // 模拟返回数据 const mockData { location, temperature: 22, condition: “Sunny”, humidity: 65, }; return The current weather in ${mockData.location} is ${mockData.condition} with a temperature of ${mockData.temperature}°C and humidity ${mockData.humidity}%.; } catch (error) { console.error(“Weather tool error:”, error); return Sorry, I couldn’t fetch the weather for ${location} at the moment. Please try again later or check the city name.; } }, });关键点描述description尽可能详细和场景化。告诉模型“当用户询问天气、温度或气候时使用此工具”。清晰的描述是 Agent 正确选择工具的关键。错误处理工具函数内部必须有健壮的try...catch。模型无法处理未捕获的异常一个崩溃的工具会导致整个 Agent 执行失败。返回一个友好的错误信息字符串是更好的做法。结构化输入使用zod定义schema这确保了模型输出的参数格式正确并在代码层面提供了类型安全。工具二新闻搜索工具 (src/tools/news.tool.ts)我们模拟一个新闻搜索功能。在实际项目中你可以集成 SerpAPI、NewsAPI 或任何其他新闻聚合服务。import { DynamicStructuredTool } from “langchain/core/tools”; import { z } from “zod”; const newsInputSchema z.object({ query: z.string().describe(“The search topic or keywords for news, e.g., ‘latest AI developments’, ‘stock market news’.”), maxResults: z.number().optional().default(3).describe(“Maximum number of news results to return.”), }); export const searchNewsTool new DynamicStructuredTool({ name: “search_latest_news”, description: “Searches for the latest news articles based on a topic or keyword. Use this when the user asks for recent news, updates, or headlines about something.”, schema: newsInputSchema, func: async ({ query, maxResults }) { console.log([Tool Call] Searching news for: “${query}”, max results: ${maxResults}); // 模拟调用新闻 API 并返回摘要 // const apiKey process.env.NEWS_API_KEY; // const response await axios.get(https://newsapi.org/v2/everything?q${encodeURIComponent(query)}apiKey${apiKey}); // 模拟返回 const mockArticles [ { title: “Breakthrough in Renewable Energy Storage Announced”, source: “Tech News”, summary: “Scientists have developed a new battery technology…” }, { title: “Global Markets React to New Policy”, source: “Financial Times”, summary: “Stock indices showed mixed responses…” }, { title: ${query} Dominates Annual Conference Discussions, source: “Industry Insider”, summary: “Experts gathered to discuss the future of ${query}…” }, ].slice(0, maxResults); const formattedNews mockArticles.map((article, idx) ${idx 1}. **${article.title}** (Source: ${article.source})\n ${article.summary} ).join(“\n\n”); return Here are the latest news about “${query}”: \n\n${formattedNews}; }, });关键点可选参数注意maxResults被定义为optional().default(3)。这给了模型灵活性它可以选择性地提供这个参数。如果不提供工具会使用默认值 3。格式化输出工具返回的字符串应该清晰、结构化便于模型理解和整合到最终给用户的回复中。良好的格式化能提升最终答案的可读性。4.2 组装代理与执行器现在在src/index.ts中我们将所有部件组装起来。import ‘dotenv/config’; import { ChatOpenAI } from “langchain/openai”; import { createReactAgent } from “langchain/core/agents”; import { AgentExecutor } from “langchain/agents”; import { fetchWeatherTool } from “./tools/weather.tool”; import { searchNewsTool } from “./tools/news.tool”; import { BufferMemory } from “langchain/memory”; async function main() { console.log(“ Initializing AI Agent...”); // 1. 初始化语言模型 const llm new ChatOpenAI({ modelName: “gpt-3.5-turbo”, // 从成本考虑先用 3.5效果足够 temperature: 0.2, // 任务较确定调低温度 apiKey: process.env.OPENAI_API_KEY, }); // 2. 准备工具包 const tools [fetchWeatherTool, searchNewsTool]; // 3. 创建记忆可选但推荐用于多轮对话 const memory new BufferMemory({ memoryKey: “chat_history”, returnMessages: true, }); // 4. 创建 ReAct 代理 const agent createReactAgent({ llm, tools, }); // 5. 创建代理执行器 const executor AgentExecutor.fromAgentAndTools({ agent, tools, memory, // 注入记忆 returnIntermediateSteps: true, // 调试时非常有用 maxIterations: 6, // 防止无限循环 verbose: true, // 在控制台打印详细的执行日志 }); console.log(“✅ Agent is ready. Type your questions (or ‘quit’ to exit).\n”); // 6. 模拟一个交互循环在实际应用中这里可能是 HTTP 服务器或 CLI 界面 const testQueries [ “What’s the weather like in Paris today?”, “Can you find me some news about artificial intelligence?”, “Based on the news you found, what seems to be the main trend?” // 测试记忆功能 ]; for (const input of testQueries) { console.log(\n User: ${input}); try { const response await executor.invoke({ input }); console.log( Assistant: ${response.output}); // 如果开启了 returnIntermediateSteps可以查看思考过程 if (response.intermediateSteps) { console.log(“\n Intermediate Steps (for debugging):”); response.intermediateSteps.forEach((step, i) { console.log( Step ${i 1}:, step.action.tool, “-”, step.observation); }); } } catch (error) { console.error(“❌ Agent execution failed:”, error); } } } main().catch(console.error);关键配置解析verbose: true这是开发阶段的神器。当设置为true时LangChain 会在控制台打印出 Agent 完整的思考链Chain of Thought包括它决定调用哪个工具、传递了什么参数、工具返回了什么结果。这对于调试 Agent 的决策逻辑至关重要。returnIntermediateSteps: true这个选项让我们能在代码中访问到每一步的中间结果方便我们自定义日志或进行更复杂的流程控制。maxIterations: 6一个安全限制。我遇到过 Agent 在某个问题上反复横跳就是不给最终答案的情况设置一个合理的上限可以节省 token 和 API 费用。4.3 运行与观察理解 Agent 的思考过程现在运行npm run dev。你会看到类似以下的输出经过简化 Initializing AI Agent... ✅ Agent is ready. Type your questions (or ‘quit’ to exit). User: What’s the weather like in Paris today? [Agent Log] Thought: The user is asking about the current weather in Paris. I should use the get_current_weather tool. [Agent Log] Action: {“tool”: “get_current_weather”, “toolInput”: {“location”: “Paris, France”}} [Tool Call] Fetching weather for: Paris, France [Agent Log] Observation: The current weather in Paris, France is Sunny with a temperature of 22°C and humidity 65%. [Agent Log] Thought: I have the weather information. I can now provide a final answer. Assistant: The current weather in Paris, France is sunny with a temperature of 22°C and humidity at 65%. User: Can you find me some news about artificial intelligence? [Agent Log] Thought: The user wants news about AI. I should use the search_latest_news tool. [Agent Log] Action: {“tool”: “search_latest_news”, “toolInput”: {“query”: “artificial intelligence”}} [Tool Call] Searching news for: “artificial intelligence”, max results: 3 [Agent Log] Observation: Here are the latest news about “artificial intelligence”: 1. **Breakthrough in Renewable Energy Storage Announced** (Source: Tech News)… [Agent Log] Thought: I have the news results. I should summarize them for the user. Assistant: Here are some of the latest news headlines regarding artificial intelligence: 1. **Breakthrough in Renewable Energy Storage Announced**…通过verbose日志你可以清晰地看到 Agent 的“思考-行动-观察”循环。它首先“思考”需要用什么工具然后以结构化 JSON 格式“行动”调用工具接着“观察”工具返回的结果最后基于所有信息形成最终答案。这个过程完美诠释了 ReAct 框架。当第二个问题涉及对前文信息的引用时如果记忆正常工作你会看到chat_history被包含在提示词中从而使 Agent 具备了上下文感知能力。至此一个具备基础工具调用和记忆功能的多轮对话 AI Agent 就成功运行起来了。你可以尝试问更复杂的问题比如“What’s the weather in Tokyo and then find news related to climate change?”观察它如何顺序或并行地处理多个子任务。5. 避坑指南与效能优化从“跑起来”到“跑得好”让一个 Agent 初步运行起来只是第一步。在实际开发和部署中你会遇到各种预料之外的问题从莫名其妙的错误到高昂的 API 成本。这一章我结合自己的踩坑经历分享如何让 Agent 变得更可靠、更高效、更经济。5.1 常见错误排查与工具调用失败处理问题一模型不调用工具直接回答问题现象你明明定义了天气工具但问“北京天气如何”模型却开始编造一段天气描述。根因最可能的原因是工具描述description不够清晰或不够有针对性。模型是根据描述来判断是否使用工具的。如果描述太模糊或者模型认为自己的知识足以回答它就会选择直接回答。解决方案优化描述在描述中明确使用场景和边界。例如将“获取天气”改为“当用户询问当前、今天或未来的天气状况、温度、湿度、风速等具体气象信息时使用此工具。此工具提供基于真实数据的天气信息不要凭空猜测。”调整提示词createReactAgent使用的是默认的 ReAct 提示模板。如果问题依然存在可以考虑自定义提示词在系统消息System Message中更加强调“你必须使用工具来获取实时信息”。检查模型能力极少数情况下可能是模型本身如某些小参数模型工具调用能力较弱可以尝试换用更新或能力更强的模型如gpt-4o。问题二工具调用参数格式错误现象控制台报错提示工具调用时参数类型不匹配或缺少必需参数。根因模型的输出没有严格按照zod schema定义的结构来生成参数。解决方案强化 Schema 描述在zod的describe方法中为每个参数提供更详细的例子和约束。例如.describe(“城市名称必须是完整的名称例如‘北京市’而不是‘北京’或‘BJ’。”)。使用更严格的模型gpt-4系列在遵循结构化输出方面通常比gpt-3.5-turbo更可靠。启用 LangChain 的容错机制一些高级的 Agent 执行器或自定义链支持“重试”逻辑当解析失败时让模型重新尝试生成正确的参数。问题三Agent 陷入无限循环或重复调用现象Agent 反复调用同一个工具或者在不同工具间来回切换就是不输出最终答案直到达到maxIterations限制。根因可能是工具返回的结果不足以让模型做出决策或者模型的“思考”出现了逻辑闭环。解决方案优化工具输出确保工具返回的信息是明确、完整且格式化的。模糊的工具输出会让模型困惑。例如天气工具不应只返回“22°C”而应返回“当前温度 22°C天气晴朗”。设置合理的maxIterations这是必须的保险丝。根据任务复杂度通常 5-10 次迭代足够。审查verbose日志这是诊断循环问题的关键。观察每次“Observation”后模型的“Thought”看它为什么认为还需要继续行动。可能是它想验证信息也可能是它误解了任务。5.2 性能与成本优化策略构建生产级 Agent不能忽视性能和成本。1. 管理上下文长度与记忆大语言模型有上下文窗口限制如 4K, 8K, 128K tokens。冗长的对话历史会快速消耗 token增加成本并可能触及窗口上限。策略不要无脑使用BufferMemory存储所有历史。对于长对话考虑ConversationSummaryMemory定期总结之前的对话只保留摘要大幅节省 token。VectorStoreRetrieverMemory将历史对话存入向量数据库只检索与当前问题最相关的片段。这是处理超长上下文的高级方案。主动清空在对话自然结束时如用户说“再见”或在服务器端设置超时机制主动清除memory的内容。2. 精细化控制工具调用不必要的工具调用是成本的主要浪费点。策略工具描述精确化如前所述清晰的描述能减少误触发。使用StructuredTool而非DynamicStructuredTool如果工具的输入参数非常复杂DynamicStructuredTool会让模型生成一个完整的 JSON Schema 描述这会消耗额外 token。对于固定参数的工具StructuredTool可能更高效。并行工具调用LangChain 支持某些模型如gpt-4o的并行工具调用。如果多个工具调用间没有依赖关系可以一次性提交减少来回通信次数。在初始化ChatOpenAI时可以配置parallelToolCalls: true。3. 模型选型与缓存策略任务分级对于简单的意图识别或路由可以使用更便宜、更快的模型如gpt-3.5-turbo。对于需要复杂推理和规划的核心 Agent再使用gpt-4o。启用响应缓存对于重复性较高的问题如常见问答可以在 LangChain 层面或外部如 Redis实现缓存避免相同问题重复调用模型。LangChain 内置了InMemoryCache或可以集成RedisCache。考虑本地模型对于数据敏感或调用量极大的场景评估使用本地部署的开源模型通过Ollama、llama.cpp集成。虽然效果可能略逊但成本极低且完全可控。5.3 扩展性与维护性设计当你的 Agent 工具越来越多逻辑越来越复杂时代码结构需要精心设计。1. 工具的动态注册与管理不要把所有工具都硬编码在入口文件里。可以创建一个工具注册中心// src/tools/index.ts import { DynamicStructuredTool } from “langchain/core/tools”; import { fetchWeatherTool } from “./weather.tool”; import { searchNewsTool } from “./news.tool”; // 导入其他工具... export const getAllTools (): DynamicStructuredTool[] { return [ fetchWeatherTool, searchNewsTool, // ... 其他工具 ]; }; // 或者根据配置或用户权限动态加载工具 export const getToolsForSession (sessionConfig: any): DynamicStructuredTool[] { const baseTools [fetchWeatherTool]; if (sessionConfig.canSearchNews) { baseTools.push(searchNewsTool); } return baseTools; };2. 构建可插拔的 Agent 工厂不同的任务可能需要不同配置的 Agent不同的模型、提示词、工具集。// src/agents/agentFactory.ts import { ChatOpenAI } from “langchain/openai”; import { createReactAgent } from “langchain/core/agents”; import { AgentExecutor } from “langchain/agents”; import { BaseChatModel } from “langchain/core/language_models/chat_models”; import { DynamicStructuredTool } from “langchain/core/tools”; export interface AgentConfig { modelName: string; temperature: number; tools: DynamicStructuredTool[]; maxIterations?: number; systemPrompt?: string; } export function createAgentExecutor(config: AgentConfig): AgentExecutor { const llm new ChatOpenAI({ modelName: config.modelName, temperature: config.temperature, apiKey: process.env.OPENAI_API_KEY, }); const agent createReactAgent({ llm, tools: config.tools, // 这里可以传入自定义的 prompt template覆盖 systemPrompt }); return AgentExecutor.fromAgentAndTools({ agent, tools: config.tools, maxIterations: config.maxIterations || 5, verbose: process.env.NODE_ENV “development”, // 仅开发环境打印详细日志 }); }通过这样的设计你的应用可以轻松地根据请求类型创建不同的 Agent 实例代码也更容易测试和维护。记住构建 AI Agent 是一个迭代过程从最小可行产品MVP开始通过持续的测试、观察日志、分析成本逐步优化其可靠性、智能度和经济性。
返回列表