尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于LangChain与TypeScript构建AI Agent:从核心概念到工程实践

基于LangChain与TypeScript构建AI Agent:从核心概念到工程实践 1. 项目概述为什么选择 LangChain TypeScript 来构建 AI Agent最近几年AI Agent 的概念火得一塌糊涂从简单的聊天机器人到能自主完成复杂任务的智能体似乎一夜之间成了开发者圈子的新宠。但说实话很多教程要么是 Python 的天下要么就是概念讲得天花乱坠真到动手时却发现无从下手。我自己在尝试了几个项目后发现用 TypeScript 配合 LangChain 来搭建 AI Agent对于前端或全栈开发者来说是一条上手快、生态好、部署也相对平滑的路径。所以这篇手记就记录了我从零开始用 LangChain 和 TypeScript 搭建一个具备基础能力的 AI Agent 的完整过程。这个项目要解决的其实是一个很实际的需求如何让一个程序不仅能理解用户的指令还能调用工具去执行并最终给出一个结构化的结果。比如你让它“查一下北京明天天气然后告诉我是否需要带伞”它需要先理解“查天气”这个意图调用相应的天气 API解析返回的数据再根据“是否需要带伞”这个条件进行逻辑判断最后生成一段自然的回复。这背后涉及的核心就是 LangChain 所擅长的“链”Chains和“代理”Agents的编排能力。而 TypeScript 的强类型系统能在开发阶段就帮我们规避掉很多低级错误尤其是在处理复杂的 AI 响应和工具调用时类型提示简直就是救命稻草。2. 环境准备与项目初始化搭建稳固的开发地基在开始敲代码之前一个清晰、隔离的开发环境是高效工作的前提。我强烈建议不要直接在全局环境里折腾用上现代的前端工程化工具能让后续的依赖管理和部署省心很多。2.1 核心工具链选型与安装首先你需要确保本地已经安装了 Node.js建议 LTS 版本如 18.x 或 20.x和 npm 或 yarn、pnpm 这类包管理器。我个人的选择是 pnpm速度快磁盘空间占用也小。接下来我们初始化项目mkdir my-ai-agent cd my-ai-agent pnpm init -y初始化完成后安装 TypeScript 和必要的类型定义。我们采用一个相对标准的配置pnpm add -D typescript types/node ts-node nodemon pnpm add -D typescript-eslint/eslint-plugin typescript-eslint/parser eslint prettier然后生成tsconfig.json文件。这里我分享一个为 Node.js 后端项目优化的配置特别注意target和module的设置它们会影响代码的编译方式和兼容性。{ compilerOptions: { target: ES2022, module: commonjs, lib: [ES2022], outDir: ./dist, rootDir: ./src, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, resolveJsonModule: true, declaration: true, declarationMap: true, sourceMap: true }, include: [src/**/*], exclude: [node_modules, dist] }注意网上有些老教程可能会提到baseUrl这个选项但在较新的 TypeScript 版本中它已被标记为“已弃用”deprecated并将在 TypeScript 7.0 中停止运行。如果你遇到相关警告应该使用paths选项来配置模块别名或者直接移除baseUrl。这是一个常见的踩坑点务必留意你的 TypeScript 版本和配置。2.2 LangChain 与 AI 模型依赖安装接下来是重头戏安装 LangChain 的核心库。LangChain 为不同的后端提供了多个包对于 TypeScript/JavaScript 项目我们主要使用langchain这个主包。pnpm add langchainLangChain 本身不提供大模型它只是一个编排框架。因此你需要选择一个“模型提供商”。最通用和方便的是 OpenAI 的 API当然你也可以选择 Anthropic、Google Gemini 或其他开源模型通过 Ollama 等本地部署。这里以 OpenAI 为例pnpm add openai为了安全地管理 API 密钥等敏感信息我们还需要安装dotenvpnpm add dotenv现在你的package.json的dependencies应该大致包含这些核心项。完成这一步技术栈的基础就已经搭建完毕了。我建议在src目录下创建一个.env文件记得加入.gitignore用于存放你的 OpenAI API KeyOPENAI_API_KEYsk-your-key-here。这样代码中通过process.env.OPENAI_API_KEY来读取既安全又方便。3. 核心概念解析LangChain 中的链、代理与工具在动手写代码之前花点时间理解 LangChain 的几个核心抽象非常有必要。这能让你在后续开发中清楚地知道自己每一步在做什么而不是机械地复制粘贴。3.1 链Chains可预测的序列化操作你可以把“链”理解为一系列确定性操作的管道。给定输入 A经过链中定义好的步骤 1、2、3...必然得到输出 B。它非常适合那些流程固定的任务。比如一个“翻译链”可能包含接收用户输入 - 调用模型翻译 - 格式化输出。在 LangChain 中最简单的链是LLMChain它就是一个“提示词模板 大模型”的组合。import { OpenAI } from langchain/openai; import { PromptTemplate } from langchain/core/prompts; import { LLMChain } from langchain/chains; const model new OpenAI({ temperature: 0.9 }); const template What is a good name for a company that makes {product}?; const prompt new PromptTemplate({ template: template, inputVariables: [product], }); const chain new LLMChain({ llm: model, prompt: prompt }); // 运行链 const res await chain.call({ product: colorful socks }); console.log(res.text); // 输出模型生成的文本链的优势在于结构清晰、可预测。但它的缺点也很明显不够灵活。如果任务需要根据中间结果动态决定下一步做什么链就力不从心了。这时就需要“代理”登场。3.2 代理Agents与工具Tools赋予 AI 行动能力代理是 LangChain 的灵魂也是构建 AI Agent 的核心。一个代理 一个大语言模型负责思考/规划 一系列工具负责执行动作 一个决策循环负责协调。模型根据用户的目标和当前状态决定下一步是使用某个工具还是直接给出最终答案。工具Tools就是代理可以调用的函数。它可以是任何东西一个计算器函数、一个搜索 API、一个数据库查询甚至是一个发送邮件的函数。LangChain 内置了很多常用工具如搜索、计算你也可以轻松自定义。import { SerpAPI } from langchain/community/tools/serpapi; import { Calculator } from langchain/community/tools/calculator; const tools [new SerpAPI(), new Calculator()];代理的工作流程可以简化为1. 观察用户输入和之前的结果。2. 思考模型决定下一步行动。3. 行动调用工具并获取结果。4. 重复 1-3直到模型认为可以给出最终答案。这个过程由AgentExecutor来驱动和管理它负责处理模型输出、解析工具调用、执行工具、并将结果反馈给模型进行下一轮思考直到任务完成或达到最大迭代次数。3.3 LangChain vs LangGraph何时该用谁在搜索热词里langgraph出现的频率很高。简单来说LangChain 是基础库而 LangGraph 是构建在 LangChain 之上的、用于创建复杂、有状态代理的框架。LangChain提供了构建 AI 应用所需的基础模块如模型封装、提示词、链、简单的代理执行器。它适合大多数线性的、或决策逻辑相对简单的代理场景。LangGraph引入了“图”Graph的概念允许你显式地定义代理中不同“节点”状态、工具、条件判断之间的流转关系。它特别适合需要循环、分支、并行执行或复杂状态管理的多步骤代理。例如一个客服代理可能需要先分类问题然后根据不同类型路由到不同的子流程这些子流程可能还有自己的循环和判断。对于“从零开始”的第一个项目我建议先用纯 LangChain 的createReactAgent或createOpenAIFunctionsAgent来构建。它们已经能处理绝大多数“思考-行动”循环的任务。当你需要更精细地控制代理的每一步状态流转或者构建像“模拟一群角色对话”这样的复杂系统时再考虑引入 LangGraph。4. 实战构建一个能查天气和计算的 AI Agent理论说再多不如一行代码。我们现在就来构建一个具体的 AI Agent它有两个能力1. 使用 SerpAPI 进行网络搜索比如查天气、新闻。2. 进行数学计算。我们将使用 OpenAI 的 Function Calling 能力来构建代理这是目前最稳定和高效的方式之一。4.1 定义自定义工具首先我们定义一个自定义的“获取天气”工具。由于真实的天气 API 需要注册这里我们用一个模拟函数来演示原理。关键是理解工具的定义格式name,description,schema输入参数的 JSON Schema以及func执行函数。// src/tools/weather.ts import { DynamicStructuredTool } from langchain/core/tools; import { z } from zod; export const weatherTool new DynamicStructuredTool({ name: get_weather, description: Get the current weather for a given city. Use this when user asks about weather., schema: z.object({ city: z.string().describe(The city name, e.g. Beijing, Shanghai.), }), func: async ({ city }) { // 模拟 API 调用 console.log([Tool Call] Fetching weather for: ${city}); // 这里应该调用真实的天气 API例如 OpenWeatherMap // const apiKey process.env.OPENWEATHER_API_KEY; // const response await fetch(https://api.openweathermap.org/data/2.5/weather?q${city}appid${apiKey}unitsmetric); // const data await response.json(); // 模拟返回 const mockData { city, temperature: 22, condition: Sunny, humidity: 65, }; return The current weather in ${mockData.city} is ${mockData.condition}, with a temperature of ${mockData.temperature}°C and humidity ${mockData.humidity}%.; }, });注意我们使用了DynamicStructuredTool和zod库来定义带有严格参数模式的工具。这能帮助大模型更准确地理解何时调用此工具以及需要提供什么参数。description字段至关重要模型主要靠它来判断是否要使用这个工具。4.2 初始化模型与创建代理接下来我们初始化 OpenAI 模型并组合工具来创建代理。我们使用createOpenAIFunctionsAgent它专为利用 OpenAI 的 Function Calling 能力而设计。// src/agent/index.ts import { ChatOpenAI } from langchain/openai; import { createOpenAIFunctionsAgent, AgentExecutor } from langchain/agents; import { weatherTool } from ../tools/weather; import { Calculator } from langchain/community/tools/calculator; import { pull } from langchain/hub; import { PromptTemplate } from langchain/core/prompts; export async function initializeAgent() { // 1. 初始化大模型 const llm new ChatOpenAI({ modelName: gpt-4o-mini, // 也可以用 gpt-3.5-turbo但 gpt-4 系列在工具调用上更可靠 temperature: 0, // 对于工具调用低 temperature 更稳定 openAIApiKey: process.env.OPENAI_API_KEY, }); // 2. 定义工具集 const tools [weatherTool, new Calculator()]; // 3. 获取提示词模板。LangChain Hub 是一个共享提示词的地方我们拉取一个为函数调用代理设计好的模板。 const prompt await pullPromptTemplate(hwchase17/openai-functions-agent); // 4. 创建代理 const agent await createOpenAIFunctionsAgent({ llm, tools, prompt, }); // 5. 创建代理执行器它封装了循环执行逻辑 const agentExecutor new AgentExecutor({ agent, tools, // 以下参数用于控制执行防止死循环 verbose: true, // 打印详细的思考过程调试时非常有用 maxIterations: 5, // 最大迭代次数防止代理陷入无限循环 handleParsingErrors: true, // 优雅处理模型输出解析错误 }); return agentExecutor; }这里有几个关键点verbose: true强烈建议在开发阶段开启。你会在控制台看到模型完整的思考过程“Thought”、行动决定“Action”和观察结果“Observation”这对于调试代理的逻辑至关重要。maxIterations必须设置。这是安全阀防止代理因为逻辑错误或工具问题不停地循环调用。Prompt 来自 Hub我们使用了社区维护的openai-functions-agent提示词模板。这个模板已经精心设计能很好地引导模型进行工具调用。你也可以自定义但对于初学者直接用这个是最稳妥的。4.3 运行与测试代理最后我们写一个主函数来运行这个代理。// src/index.ts import * as dotenv from dotenv; import { initializeAgent } from ./agent; dotenv.config(); async function main() { console.log(Initializing AI Agent...); const agentExecutor await initializeAgent(); const testQueries [ Whats the weather like in Tokyo today?, What is 25 multiplied by 4 plus 18?, Find the weather in Paris and then calculate the square root of 144., ]; for (const input of testQueries) { console.log(\n User: ${input} ); try { const result await agentExecutor.invoke({ input }); console.log( Agent: ${result.output} ); } catch (error) { console.error(Error during agent execution:, error); } } } main().catch(console.error);运行ts-node src/index.ts或配置好nodemon进行热重载你应该能在控制台看到类似以下的输出特别是当verbose开启时 User: Whats the weather like in Tokyo today? Initializing AI Agent... [verbose] Thought: The user is asking about the weather in Tokyo. I have a tool called get_weather that can fetch weather for a city. I should use that. [verbose] Action: {name: get_weather, arguments: {city: Tokyo}} [Tool Call] Fetching weather for: Tokyo [verbose] Observation: The current weather in Tokyo is Sunny, with a temperature of 22°C and humidity 65%. [verbose] Thought: I have the weather information. Now I can answer the user. [verbose] Final Answer: The current weather in Tokyo is Sunny, with a temperature of 22°C and humidity 65%. Agent: The current weather in Tokyo is Sunny, with a temperature of 22°C and humidity 65%. 你会看到代理成功地识别了用户意图调用了正确的工具并将工具返回的结果整合成了最终答案。对于计算问题它会调用Calculator工具。对于混合问题它会自主规划顺序先查天气再计算。5. 性能优化与调试技巧让 Agent 更可靠项目跑起来只是第一步。在实际开发中你会遇到代理“犯傻”、工具调用失败、响应慢等问题。下面分享一些我踩过坑后总结的优化和调试经验。5.1 提升工具调用准确性与速度1. 工具描述Description是灵魂模型几乎完全依赖工具的name和description来决定是否调用它。描述要精确、简洁并包含典型用例。差的描述“A tool to get data.”好的描述“Get the current weather for a given city. Use this when user asks about weather, temperature, or forecast.”好的描述能显著减少模型误判。2. 控制上下文长度每次调用模型都会将对话历史、工具定义、当前思考等内容作为提示词发送。如果历史很长会导致 Token 消耗剧增、速度变慢、成本上升甚至可能超过模型上下文窗口限制。策略使用ConversationSummaryBufferMemory或ConversationTokenBufferMemory来压缩历史对话只保留摘要或最近的关键信息。实操在创建AgentExecutor时传入memory参数。3. 选择合适的模型对于工具调用GPT-4 系列如 gpt-4, gpt-4-turbo的准确性和可靠性远高于 GPT-3.5-Turbo但价格也更贵。gpt-4o-mini是一个不错的平衡点它在工具调用上表现尚可且成本较低。如果代理逻辑复杂升级模型往往是解决问题最快的方法。4. 结构化工具参数正如我们使用DynamicStructuredTool和zod为工具参数定义清晰的 JSON Schema 能极大提高模型提供正确参数的几率。避免使用StructuredTool的非结构化模式。5.2 常见错误排查与处理代理执行过程中错误主要来自三个方面模型输出解析错误、工具执行错误、以及代理逻辑错误如无限循环。1. 解析错误Parsing Errors模型有时可能不会输出一个完美的、可解析的 JSON 来调用工具。现象控制台报错OutputParserException。解决在AgentExecutor中设置handleParsingErrors: true。你甚至可以提供一个自定义的处理函数尝试修复输出或给模型一个友好的错误提示让它重试。const agentExecutor new AgentExecutor({ agent, tools, verbose: true, maxIterations: 5, handleParsingErrors: (error) { // 自定义错误处理逻辑 console.warn(Parsing error occurred: ${error}); return I encountered an error trying to process that. Could you please rephrase your request?; }, });2. 工具执行错误Tool Execution Errors工具函数本身可能抛出异常如网络超时、API 返回错误。现象Observation部分是工具抛出的错误堆栈。解决在自定义工具的func内部做好健壮的错误处理返回一个对模型友好的错误信息字符串而不是直接抛出异常。例如func: async ({ city }) { try { // ... API 调用 } catch (error) { return Failed to fetch weather for ${city}. The weather service might be temporarily unavailable.; } }这样模型会接收到这个错误信息并可能决定重试或告知用户。3. 无限循环或无效迭代代理可能陷入“思考-调用无关工具-得到无用结果-再思考”的死循环。现象达到maxIterations限制后终止最终答案可能不理想。调试开启verbose模式仔细观察每一轮的Thought和Action。常见原因有工具描述不清模型不理解某个工具的用途反复调用它。工具返回信息不足工具返回的结果太模糊模型无法基于它做出决策只好再次调用工具或调用其他工具。提示词引导不足可以尝试微调系统提示词prompt明确告诉代理“如果你已经获得了足够信息请直接给出最终答案”。4. 类型安全问题这是 TypeScript 项目的专属福利但也是容易忽略的点。LangChain 的某些类型定义可能比较宽泛在传递数据时如果可能使用 TypeScript 的类型断言或进行运行时检查确保数据形状符合预期避免在运行时出现undefined错误。6. 项目扩展与进阶思考从 Demo 到产品一个能跑通的 Demo 和一个健壮、可维护的 AI Agent 应用之间还有很长的路要走。基于这个基础项目我们可以从以下几个方向进行扩展和深化。6.1 集成更多工具与能力一个实用的 Agent 需要丰富的工具集。除了天气和计算器你可以考虑集成网络搜索使用SerpAPI需注册或TavilySearchAPI让 Agent 获取实时信息。知识库查询RAG结合LangChain的向量存储和检索链让 Agent 能够基于你提供的私有文档如公司手册、产品文档回答问题。这就是 RAG检索增强生成的典型应用。代码执行在安全沙箱中执行代码片段谨慎使用。自定义业务 API连接你的内部系统如 CRM、数据库、订单系统等让 Agent 成为业务助手。每增加一个工具都要仔细打磨它的描述和参数模式并做好错误处理。工具越多对模型规划能力的要求也越高。6.2 引入记忆与状态管理目前的 Agent 是无状态的每次对话都是独立的。要构建能进行多轮对话的智能体需要引入记忆Memory。对话缓冲区记忆ConversationBufferMemory简单存储所有历史消息但容易导致上下文过长。对话摘要记忆ConversationSummaryMemory会定期让模型总结对话历史只保留摘要有效控制长度。向量存储记忆VectorStoreRetrieverMemory将历史对话存入向量数据库每次根据当前问题检索相关历史片段适合长上下文。将记忆对象传递给AgentExecutorAgent 就能在思考时参考之前的对话内容。6.3 探索更复杂的编排LangGraph当你需要实现以下场景时就该考虑 LangGraph 了有明确状态流转的复杂工作流例如一个任务审批 Agent需要经历“提交 - 验证 - 审批/驳回 - 通知”等多个节点每个节点可能有不同的逻辑和工具。支持循环和条件分支比简单的“思考-行动”循环更复杂的控制流。多角色协作模拟多个 Agent 之间的交互和协作。LangGraph 让你用“图”来可视化定义这些流程每个节点是一个函数或一个 LangChain Runnable边定义了流转条件。虽然学习曲线更陡但它提供了无与伦比的灵活性和控制力。6.4 部署与监控将 Agent 部署为服务时需要考虑API 封装使用 FastAPI、Express 或 Hono 等框架将 Agent 包装成 RESTful API 或 WebSocket 服务。异步处理对于耗时的 Agent 任务考虑使用消息队列如 BullMQ进行异步处理避免 HTTP 请求超时。日志与监控详细记录每一次模型调用、工具调用、耗时和 Token 使用量。这有助于分析成本、性能瓶颈和异常情况。可以集成像 LangSmith 这样的 LangChain 官方监控平台。速率限制与容错对用户请求进行限流并对下游 API如 OpenAI、天气 API的调用失败设置重试和降级策略。7. 避坑指南与心得总结回顾整个搭建过程有几个坑是新手几乎一定会遇到的这里集中提一下第一坑环境变量和 API Key 未正确加载。确保dotenv.config()在代码最开头执行并且.env文件在正确的目录下。运行时检查process.env.OPENAI_API_KEY是否存在。第二坑工具调用不触发或触发错误。99% 的问题出在工具的描述description上。描述要具体多用动词开头说明使用场景。用verbose: true查看模型思考过程如果它根本没提你的工具那就是描述不够有吸引力。第三坑代理陷入循环或给出无关答案。首先检查maxIterations是否设置。然后分析verbose日志看模型在“思考”什么。可能是工具返回的结果质量太差导致模型无法理解也可能是提示词需要调整在系统消息里更强调“在获得足够信息后请直接给出最终答案”。第四坑TypeScript 类型报错。LangChain 的 TypeScript 类型定义有时更新很快或者某些深层次嵌套的类型推断会出问题。如果遇到棘手的类型错误可以暂时使用as any断言绕过或者去 GitHub 仓库的 Issue 里寻找解决方案。保持依赖库的更新到稳定版本。最后一点心得从简单开始逐步迭代。不要一开始就想着构建一个全能 Agent。先从一两个工具、一个明确的场景开始确保它能稳定工作。然后像搭积木一样逐步添加新的工具、记忆、或者更复杂的逻辑。每加一个功能都进行充分的测试。AI Agent 的开发具有很强的实验性质耐心调试和观察日志是提升其表现的最有效方法。这个用 LangChain 和 TypeScript 搭建的 AI Agent 骨架已经为你打开了这扇门剩下的就是结合你的具体需求去探索和创造更智能的应用了。
返回列表