ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangChain.js入门指南:用JavaScript构建AI应用的核心概念与实战

LangChain.js入门指南:用JavaScript构建AI应用的核心概念与实战 1. 从零开始为什么是 LangChain.js如果你最近在捣鼓 AI 应用尤其是想用大语言模型LLM做点自动化的事情比如让 AI 帮你分析文档、总结邮件或者搭建一个智能客服那你大概率会听到一个词LangChain。这个名字在 AI 开发者圈子里火得不行但你可能也发现了官方文档和社区讨论大部分都围绕着 Python 版本的 LangChain。那对于我们这些“前端出身”、或者主要工作流在 Node.js 环境里的开发者来说是不是就没戏了当然不是。这就是LangChain.js存在的意义。简单来说LangChain.js 是 LangChain 生态的 JavaScript/TypeScript 实现。它把 Python 版 LangChain 的核心概念、组件和能力几乎原汁原味地带到了 Node.js 和浏览器环境。这意味着你现在可以用你熟悉的 JavaScript/TypeScript 工具链去构建同样复杂、强大的基于 LLM 的应用。我第一次接触 LangChain.js 是在一个需要快速搭建内部文档问答工具的项目里。当时团队的主力技术栈是 Node.js React如果为了用 AI 能力而引入 Python 后端整个部署、联调和运维成本会陡增。LangChain.js 的出现让我们能直接在现有的 Node.js 服务里集成 AI 链前端通过 API 调用整个架构非常清爽。从那以后无论是简单的脚本工具还是复杂的多步 AI 工作流只要环境允许我都会优先考虑 LangChain.js。它解决的正是“想法”与“工程实现”之间的鸿沟。你不再需要从零开始去处理提示词工程、管理对话历史、连接各种工具比如搜索引擎、数据库或者设计复杂的多步骤推理流程。LangChain.js 提供了一套高层次的、声明式的抽象让你像搭积木一样组合这些功能。对于前端和全栈开发者而言这无疑是进入 AI 应用开发最快的一条路径。2. 核心拼图理解 LangChain.js 的四大基石要玩转 LangChain.js不能只停留在调用 API 的层面得先理解它设计哲学里的几个核心概念。这些概念是构建一切复杂应用的基石理解了它们你就能看懂官方例子甚至自己设计新的链Chain。2.1 模型 I/O与 AI 对话的标准化接口这是最基础的一层。你的应用总要和某个 AI 模型对话可能是 OpenAI 的 GPT也可能是 Anthropic 的 Claude或者是开源的 Llama 系列。每个模型的 API 调用方式、参数命名都可能略有不同。LangChain.js 在这里做了一层抽象提供了统一的LLM大语言模型和ChatModel聊天模型接口。比如你想用 OpenAI 的gpt-3.5-turbo和 Anthropic 的claude-3-haiku在 LangChain.js 里你初始化的是两个不同的ChatModel实例但调用它们的方式是完全一样的model.invoke(messages)。这极大地降低了切换模型供应商的成本。我曾在项目中期将主力模型从 GPT-4 切换到成本更低的 Claude得益于这层抽象除了初始化配置业务逻辑代码一行没改。更重要的是模型 I/O 层还标准化了“消息”的格式。无论是系统指令、用户提问还是 AI 的历史回复都被封装成HumanMessage、AIMessage、SystemMessage这样的对象。这让管理多轮对话变得异常清晰。2.2 提示词模板告别字符串拼接的混乱直接往模型里扔字符串提示词是初级玩法一旦提示词变复杂或者需要动态插入变量代码就会变得难以维护。提示词模板PromptTemplate就是为了解决这个问题。你可以把它理解为一个带有“占位符”的字符串模板。例如一个客服场景的模板可能是“你是一个专业的客服助手。请根据以下用户问题和知识库内容进行回答。用户问题{question}。知识库内容{context}”。这里的{question}和{context}就是占位符。在 LangChain.js 中你首先定义这个模板然后在运行时传入具体的变量值来生成最终的提示词。这样做的好处太多了提示词可以作为配置单独管理方便 A/B 测试可以复用模板更重要的是它让提示词本身也成为了可编程、可组合的对象。我习惯把不同功能的提示词模板放在单独的prompts/目录下像管理组件一样管理它们。2.3 链将单一操作串联成工作流链Chain是 LangChain 的灵魂也是其名字的由来。它的思想很简单把多个步骤每个步骤可以是调用模型、使用工具、处理数据链接起来形成一个完整的、可执行的工作流。一个最经典的链是LLMChain它组合了一个提示词模板和一个 LLM。你给它输入变量它先渲染模板再把结果发给 LLM最后输出 LLM 的回复。但这只是开始。你可以创建更复杂的链比如SequentialChain顺序链让一个链的输出作为另一个链的输入。我曾经构建过一个内容审核链它先让一个 LLM 判断用户输入是否合规如果不合规则直接返回警告如果合规再调用另一个链去生成回答。整个过程在一个链内完成逻辑非常清晰。链的威力在于“组合”。LangChain.js 内置了许多实用的链同时也允许你轻松地自定义链。当你把模型调用、数据查询、条件判断等模块通过链组合起来时你构建的就不再是一个简单的问答接口而是一个有决策能力的 AI 智能体雏形。2.4 记忆Memory让 AI 拥有“上下文”对于聊天应用让 AI 记住之前的对话历史至关重要。这就是记忆Memory组件的作用。它负责在多次调用之间保存和读取状态通常是聊天消息历史。LangChain.js 提供了多种记忆后端从最简单的BufferMemory只保留最近几轮对话到更复杂的ConversationSummaryMemory它会自动用另一个 LLM 来总结过长的历史对话以节省 Token 并保留核心信息。在浏览器环境中你甚至可以使用LocalStorageMemory将对话历史持久化在用户的本地存储中。选择哪种记忆方案取决于你的应用场景。对于短平快的客服对话BufferMemory可能就够了。但对于需要长期、深度交流的陪伴型 AIConversationSummaryMemory几乎是必选。我在一个模拟面试的应用中使用了后者它能确保 AI“考官”在长达一小时的模拟中始终记得面试者在前半段表现出的优缺点从而提出更有针对性的后续问题。实现这个功能只需要在初始化链时传入memory参数剩下的 LangChain.js 会自动处理。3. 实战入门用 LangChain.js 构建你的第一个 AI 链理论说了这么多不如动手来感受一下。让我们从一个最简单的例子开始创建一个能根据公司名和产品类型自动生成简短宣传口号的链。这个例子会串联我们刚才讲到的模型 I/O、提示词模板和链。3.1 环境准备与安装首先确保你有一个 Node.js 环境版本 16 或以上。然后创建一个新目录并初始化项目mkdir my-first-langchain-app cd my-first-langchain-app npm init -y接下来安装 LangChain.js 的核心包以及我们要用到的 OpenAI 模型集成包。这里选择 OpenAI 是因为它最通用但请记住你可以轻松替换为其他模型。npm install langchain langchain/openai你还需要一个 OpenAI 的 API 密钥。如果你没有可以去 OpenAI 官网注册获取。安全提示永远不要将 API 密钥直接硬编码在客户端代码或提交到 Git 仓库。我们使用环境变量来管理它。在项目根目录创建一个.env文件OPENAI_API_KEY你的-api-key-here然后安装dotenv包来加载环境变量npm install dotenv3.2 构建“宣传口号生成器”现在让我们在index.js中编写代码。我们将一步步地引入各个组件。// index.js import { config } from dotenv; config(); // 加载 .env 文件中的环境变量 import { ChatOpenAI } from langchain/openai; import { PromptTemplate } from langchain/core/prompts; import { LLMChain } from langchain/chains; // 1. 初始化模型 // 我们使用 ChatOpenAI它是对 OpenAI 聊天模型接口的封装。 // temperature 参数控制创造性0.0 最保守1.0 最有创意。这里设为 0.7让它有一定发挥空间。 // modelName 指定使用 gpt-3.5-turbo性价比高适合此类任务。 const model new ChatOpenAI({ temperature: 0.7, modelName: gpt-3.5-turbo, }); // 2. 创建提示词模板 // 模板中定义了任务指令并用花括号 {} 标出了两个输入变量company 和 product。 const promptTemplate new PromptTemplate({ template: 你是一个专业的市场营销文案写手。 请为以下公司和产品创作一句吸引人的宣传口号。 公司名称{company} 产品类型{product} 口号 , inputVariables: [company, product], // 声明模板所需的变量 }); // 3. 将模板和模型组合成链 const sloganChain new LLMChain({ llm: model, prompt: promptTemplate, }); // 4. 运行链 async function generateSlogan(company, product) { try { // 调用链的 invoke 方法传入一个包含所有输入变量的对象。 const response await sloganChain.invoke({ company: company, product: product, }); // 链的返回结果是一个对象其中 text 字段包含了模型的输出。 console.log(公司${company} 产品${product}); console.log(生成的口号${response.text}); console.log(---); return response.text; } catch (error) { console.error(生成口号时出错, error); } } // 5. 测试一下 async function main() { await generateSlogan(星辰科技, 智能咖啡机); await generateSlogan(绿野家居, 可降解环保餐具); } main();运行这个脚本node index.js你应该能看到类似以下的输出公司星辰科技 产品智能咖啡机 生成的口号星辰咖啡智煮每一杯香醇。 --- 公司绿野家居 产品可降解环保餐具 生成的口号源自绿野归于自然每一餐都是地球的礼物。 ---看一个最简单的 AI 工作流就完成了虽然功能简单但它已经包含了 LangChain.js 最核心的范式定义模板 - 组合成链 - 调用执行。你可以尝试修改模板里的指令或者调整temperature参数看看生成的标语有什么不同。这就是提示词工程和参数调优的起点。4. 能力进阶探索检索与工具使用只会生成固定格式的文本还远远不够。真正的 AI 应用需要“感知”和“操作”外部世界的能力。这就要用到 LangChain.js 另外两个强大的组件检索器Retrievers和工具Tools。4.1 检索器为 AI 注入外部知识LLM 的知识受限于其训练数据且可能存在时效性问题。检索器的目的是将用户的问题与一个外部的知识库比如你的公司文档、产品手册、最新的新闻文章进行匹配找到最相关的片段然后把这些片段作为“上下文”提供给 LLM让它基于此来回答。这就是常说的“检索增强生成”RAG。在 LangChain.js 中实现一个简单的 RAG 流程非常直观。假设我们有一些本地文档想做一个问答系统。首先你需要将文档“向量化”。简单理解就是把文本转换成一系列数字向量这样计算机可以计算不同文本之间的相似度。LangChain.js 集成了多种向量数据库如ChromaPinecone和嵌入模型如OpenAIEmbeddings。下面是一个高度简化的流程概念代码import { OpenAIEmbeddings } from langchain/openai; import { MemoryVectorStore } from langchain/vectorstores/memory; // 简单起见用内存向量库 import { RecursiveCharacterTextSplitter } from langchain/text_splitter; import { loadQAStuffChain } from langchain/chains; // 1. 准备你的文档这里用字符串模拟 const documents [ “我司的最新政策规定年假必须在当年内休完最多可结转5天到下一年度。”, “报销流程需在费用发生后的30天内提交并附上合规发票。”, “公司核心价值是客户第一、团队合作、拥抱变化、诚信、激情、敬业。” ]; // 2. 分割文本因为模型有输入长度限制 const textSplitter new RecursiveCharacterTextSplitter({ chunkSize: 200, // 每个片段大约200字符 chunkOverlap: 50, // 片段间重叠50字符避免割裂语义 }); const docs await textSplitter.createDocuments(documents); // 3. 创建向量存储 const vectorStore await MemoryVectorStore.fromDocuments( docs, new OpenAIEmbeddings() // 使用 OpenAI 的嵌入模型将文本转为向量 ); // 4. 创建一个检索器 const retriever vectorStore.asRetriever(); // 5. 当用户提问时 const userQuestion “年假可以累积到明年吗”; // 5.1 检索相关文档片段 const relevantDocs await retriever.getRelevantDocuments(userQuestion); // 5.2 将问题和检索到的上下文一起交给 LLM const qaChain loadQAStuffChain(model); // 这是一个内置的、用于问答的简单链 const answer await qaChain.invoke({ input_documents: relevantDocs, question: userQuestion, }); console.log(answer.text); // 输出根据政策年假必须在当年内休完但最多可以结转5天到下一年度。这个例子中AI 并没有从它固有的知识里回答“年假”问题而是先从我们提供的政策文档中检索到最相关的一句再基于此生成答案。这保证了答案的准确性和特异性。在实际项目中你可以将向量数据库换成持久化的如Chroma并定期更新文档源。4.2 工具赋予 AI “手”和“脚”工具Tool的概念更酷。它允许 LLM 在思考过程中主动调用外部函数来获取信息或执行操作。比如让 AI 在回答天气前先调用天气 API或者在帮你订餐前查询一下餐厅数据库。在 LangChain.js 中你可以将任何函数封装成一个工具。然后通过“智能体”Agent这个更高级的抽象让 LLM 自主决定在何时、使用哪个工具。下面是一个让 AI 使用计算器工具的例子import { DynamicTool } from langchain/core/tools; import { initializeAgentExecutorWithOptions } from langchain/agents; import { Calculator } from langchain/tools/calculator; // 1. 定义工具一个获取当前时间的工具 const currentTimeTool new DynamicTool({ name: “get_current_time”, description: “当用户询问当前时间、日期或现在几点时使用此工具。返回一个格式化的时间字符串。”, func: async () { const now new Date(); return now.toLocaleString(‘zh-CN’ { timeZone: ‘Asia/Shanghai’ hour12: false year: ‘numeric’ month: ‘2-digit’ day: ‘2-digit’ hour: ‘2-digit’ minute: ‘2-digit’ second: ‘2-digit’ }); }, }); // 2. 准备工具列表LangChain 内置了计算器工具 const tools [new Calculator() currentTimeTool]; // 3. 创建智能体执行器 const executor await initializeAgentExecutorWithOptions( tools // 工具集 model // 我们之前定义的 ChatOpenAI 模型 { agentType: “openai-functions” // 使用适合 OpenAI 模型的智能体类型 verbose: true // 开启详细日志可以看到 AI 的思考过程 } ); // 4. 向智能体提问 const result await executor.invoke({ input: “现在北京是什么时间如果我从下午3点工作到晚上8点中间休息1小时实际工作了多少分钟”, }); console.log(result.output);当你运行这段代码并开启verbose日志后你会看到类似这样的思考过程AI 思考用户问了两个问题。第一个是当前时间我需要调用 get_current_time 工具。第二个是计算工作时间我需要用计算器。 动作调用 get_current_time 工具。 观察工具返回 “2024-05-27 14:30:15”。 AI 思考现在回答第一个问题北京时间是2024-05-27 14:30:15。接下来计算工作时间从15点到20点是5小时减去休息1小时是4小时。4小时等于多少分钟需要调用计算器。 动作调用 Calculator 工具输入 “4 * 60”。 观察工具返回 “240”。 AI 思考所以实际工作了240分钟。现在可以组织最终答案了。 最终输出当前北京时间是2024-05-27 14:30:15。从下午3点到晚上8点扣除1小时休息您实际工作了4小时也就是240分钟。这个过程展示了智能体的核心能力规划、工具调用、结果整合。你不需要预先告诉 AI 该怎么做只需要给它可用的工具和清晰的描述它就能自己规划步骤来解决问题。这为构建真正自主的 AI 助手打开了大门。5. 避坑指南与性能调优心得LangChain.js 大大降低了开发门槛但在实际生产中使用还是会遇到不少坑。这里分享几个我踩过并总结出的关键点。5.1 错误处理与超时控制LLM API 调用和工具执行都是网络 I/O 操作失败是常态。你必须为链或智能体的调用添加健壮的错误处理。async function robustChainInvoke(chain input maxRetries 2) { for (let i 0; i maxRetries; i) { try { // 为调用设置超时 const controller new AbortController(); const timeoutId setTimeout(() controller.abort() 30000); // 30秒超时 const result await chain.invoke(input { signal: controller.signal }); clearTimeout(timeoutId); return result; } catch (error) { console.error(第 ${i 1} 次调用失败 error.name error.message); if (i maxRetries - 1) { // 最后一次重试也失败返回一个友好的降级响应 return { text: “抱歉服务暂时不可用请稍后再试。” }; } // 简单的指数退避重试 await new Promise(resolve setTimeout(resolve 1000 * Math.pow(2 i))); } } }对于智能体尤其要注意它可能会陷入“思考循环”不断调用工具而不给出最终答案。除了设置总的调用超时还可以通过maxIterations参数限制智能体的最大执行步数。5.2 成本与 Token 管理使用商业 LLM API成本是必须考虑的因素。Token 是计费单位你输入的提示词和模型输出的内容都消耗 Token。关键策略精简提示词模板里不要有多余的空格和换行。在保证清晰的前提下尽量使用简短的指令。控制输出长度使用模型的maxTokens参数来限制单次回复的长度防止 AI“长篇大论”。善用摘要记忆对于长对话使用ConversationSummaryMemory可以显著减少每次投喂给模型的历史 Token 数量。缓存嵌入向量对于 RAG 应用文档的嵌入向量生成是一次性的。务必将其存储在向量数据库中避免每次查询都重新计算这能省下大量嵌入模型的 API 调用费用。一个实用的做法是在开发阶段在初始化模型时加入一个简单的 Token 计数器可以通过拦截请求实现让你对每次调用的消耗心中有数。5.3 提示词工程的稳定性提示词的微小改动可能导致输出结果的巨大差异。为了提升稳定性提供明确示例在提示词模板中使用少样本学习Few-Shot Learning给模型提供一两个输入输出的例子能极大地规范其输出格式和质量。结构化输出要求模型以 JSON、XML 等特定格式输出便于后续代码解析。最新的模型如 GPT-4对此支持得很好。后处理校验不要完全信任模型的输出。对于关键信息如日期、金额编写后处理逻辑进行格式校验或合理性检查。例如一个解析用户预订请求的链其最终输出应该是一个结构化的 JSON 对象。你可以在提示词中严格要求“请以以下 JSON 格式输出{“service”: “...” “date”: “YYYY-MM-DD” “people”: number}”。然后在代码中尝试JSON.parse如果失败则触发重试或降级流程。5.4 开发与调试技巧开启详细日志在初始化链或智能体时设置verbose: true。这会将模型的思考过程、工具调用详情打印到控制台是调试复杂流程不可或缺的手段。使用 LangSmith这是 LangChain 官方推出的监控和调试平台。它能可视化地追踪每一次链的执行过程记录每一步的输入输出、耗时和 Token 使用情况。对于排查复杂链中哪个环节出了问题或者进行性能分析LangSmith 是神器。它有云服务也支持本地部署。从简单链开始不要一开始就设计一个包含十几个步骤的超级智能体。先确保每个独立的小链如检索链、判断链工作正常再将它们组合起来。这符合软件工程的模块化思想也更容易定位问题。6. 展望从链到智能体构建更自主的应用当你熟练掌握了链、检索器和工具的使用后你的视野会自然投向更广阔的领域自主智能体Autonomous Agent。智能体本质上是一个具备规划、记忆和工具使用能力的强化版链。它可以根据目标自我拆解任务动态选择工具并持续执行直到目标达成或无法继续。LangChain.js 提供了构建智能体的框架。除了上面例子中使用的OpenAIFunctionsAgent还有ReAct、Plan-and-Execute等多种架构。社区也涌现了像AutoGPT、BabyAGI这样的著名智能体项目其核心思想都可以用 LangChain.js 来实现。例如你可以构建一个“社交媒体内容智能体”给它设定目标“为我的科技博客寻找本周热门话题并起草一篇短文”。这个智能体可能会自主执行以下步骤调用“网络搜索”工具获取趋势关键词。调用“RSS 订阅读取”工具抓取几个头部科技媒体的文章。用一个“总结链”提炼核心观点。调用“文案生成链”结合总结的观点和特定风格起草博文。最后调用“草稿保存”工具将结果存入你的笔记系统。整个过程无需人工干预。实现这样的智能体挑战不在于 LangChain.js 的 API而在于如何设计稳健的任务规划逻辑、如何为工具编写清晰的描述、以及如何设置有效的安全护栏防止智能体执行危险操作。这标志着你的开发从“制作工具”走向了“创造同事”。LangChain.js 将 AI 能力从研究论文和 Python 脚本中解放出来使其能够无缝融入现代 Web 和 Node.js 应用架构。它可能不是所有场景的最优解对于极其简单或对延迟要求极高的调用直接使用模型 SDK 可能更直接但它无疑是目前将想法快速转化为复杂、可维护的 AI 应用的最佳脚手架之一。开始用它构建点东西吧你会发现让机器理解并执行复杂指令从未如此触手可及。
返回列表