指南:從調(diào)用到 Agent 工具編排的 LLM 應(yīng)用開發(fā))
這次我們來看 LangChain.js。它不是某個聊天應(yīng)用也不是單純的大模型調(diào)用示例而是專門給 JavaScript/TypeScript 開發(fā)者用的 LLM 應(yīng)用開發(fā)框架。簡單說LangChain 在 Python 生態(tài)里積累了很強的模型編排能力LangChain.js 就是把這一套能力搬到 Node.js 環(huán)境里讓前端、全棧和后端團隊可以用熟悉的 JS 技術(shù)棧來搭 AI 應(yīng)用。如果你之前直接調(diào)過大模型 API應(yīng)該會有這種感覺單個接口調(diào)用很簡單但一旦要管理對話歷史、提示詞模板、多個模型切換、工具調(diào)用和流式輸出代碼就很容易變成“面向接口復(fù)制粘貼”。LangChain.js 的核心價值是把整個調(diào)用過程結(jié)構(gòu)化讓模型接入、提示詞、Agent、檢索這些模塊可以被統(tǒng)一組織和復(fù)用而不是每次都在業(yè)務(wù)代碼里拼字符串。這篇文章會圍繞一條完整鏈路展開環(huán)境準(zhǔn)備、安裝依賴、寫第一個對話程序、測試提示詞模板與 Agent 工具調(diào)用、封裝 HTTP API、跑批量任務(wù)、觀察資源占用最后給常見問題和排查方法。你不需要 GPU也不一定需要固定選某家大模型Node.js 環(huán)境加一個模型服務(wù) API Key 就能開始。1. LangChain.js 核心能力速覽能力項說明項目類型LLM 應(yīng)用開發(fā)框架JavaScript/TypeScript所屬生態(tài)LangChain 官方生態(tài)與 Python 版 LangChain 對應(yīng)運行環(huán)境Node.js不依賴 GPU 或特定顯卡主要功能模型調(diào)用封裝、提示詞模板、鏈?zhǔn)骄幣拧gent 工具調(diào)用、流式輸出、多輪對話、檢索增強支持模型通過官方或社區(qū)包接入 OpenAI、Anthropic、Google 等模型服務(wù)也可接入 OpenAI 兼容協(xié)議的本地模型服務(wù)啟動方式npm 項目 Node 腳本啟動可擴展 Express/Fastify 提供 HTTP API接口 API框架本身提供編程 APIHTTP 接口需要自行封裝批量任務(wù)可用 Promise 并發(fā)控制實現(xiàn)需自行設(shè)計隊列與重試適合場景AI 聊天機器人、知識庫問答、Agent 自動化、內(nèi)容生成、內(nèi)部工具集成從表格能看出LangChain.js 不是“裝完就有界面”的工具而是一個開發(fā)框架。它的價值在于把 AI 應(yīng)用里重復(fù)出現(xiàn)的部分抽出來比如模型切換、消息格式轉(zhuǎn)換、Prompt 組織、Agent 調(diào)用外部工具等。這樣你的業(yè)務(wù)代碼不會越寫越亂模型層也被隔離在框架內(nèi)部。另外要注意一點LangChain.js 和 LangChain Python 雖然同源但兩邊并不完全等價。很多新能力會先在 Python 生態(tài)里出現(xiàn)再遷移到 JS 版所以做技術(shù)選型時不要默認(rèn)兩邊 API 一致具體以你安裝版本的官方文檔為準(zhǔn)。2. 適用場景與使用邊界2.1 適合誰LangChain.js 適合以下幾類人寫過 Node.js 后端想快速把大模型能力接進業(yè)務(wù)系統(tǒng)。需要在同一個應(yīng)用里切換不同模型服務(wù)而不想為每家廠商單獨寫適配層。要做 AI Agent讓模型根據(jù)用戶意圖自動調(diào)用工具、查詢數(shù)據(jù)、執(zhí)行動作。團隊已經(jīng)有提示詞模板、對話記錄、檢索邏輯想把這些東西標(biāo)準(zhǔn)化管理。2.2 能解決什么問題它最直接的價值是“統(tǒng)一接入層”。比如你今天用 OpenAI 的模型明天想換成兼容 OpenAI 協(xié)議的本地模型只需要改環(huán)境變量和模型配置不用把業(yè)務(wù)代碼里的 API 調(diào)用全部重寫。Prompt 模板、Agent 工具、對話記憶這些能力也能在項目里形成可復(fù)用的模塊。2.3 不適合什么場景如果只是做一次簡單翻譯、單輪問答直接用官方 SDK 往往更輕沒必要引入框架。如果團隊對依賴體積、啟動速度極其敏感也要評估框架帶來的抽象層是否值得。LangChain.js 是一個快速迭代的框架API 在不同版本里可能有調(diào)整生產(chǎn)環(huán)境必須鎖版本不能無腦升級。2.4 合規(guī)與安全邊界無論把 LangChain.js 接入云模型還是本地模型都要注意API Key 不能提交到 Git 倉庫對話內(nèi)容要按公司或項目的敏感數(shù)據(jù)規(guī)范處理如果 Agent 要調(diào)用內(nèi)部系統(tǒng)、數(shù)據(jù)庫或第三方平臺必須做細(xì)粒度權(quán)限控制生成內(nèi)容要設(shè)置審核機制不能直接把模型輸出當(dāng)作事實結(jié)果。模型輸出可控性有限事實類業(yè)務(wù)不要直接面向最終用戶要加人工確認(rèn)或事實校驗。涉及人臉、聲音、版權(quán)素材或內(nèi)部業(yè)務(wù)數(shù)據(jù)的 AI 應(yīng)用必須確認(rèn)授權(quán)范圍不能拿未授權(quán)數(shù)據(jù)直接丟給大模型。3. 環(huán)境準(zhǔn)備與前置條件3.1 基礎(chǔ)環(huán)境LangChain.js 本身不挑硬件常規(guī)開發(fā)機就能跑。建議準(zhǔn)備以下環(huán)境Node.js 18 以上 LTS 版本。npm 或 pnpm用來安裝依賴。一個終端或 IDE。能訪問你選擇的模型服務(wù)公網(wǎng)模型或內(nèi)網(wǎng)模型都可以。由于不需要 GPU也沒有本地模型文件磁盤占用主要集中在 node_modules 和代碼文件上普通項目幾十到幾百 MB 都很正常。3.2 準(zhǔn)備模型 API Key要跑通示例需要一個大模型服務(wù)的 API Key??梢赃x OpenAI 等云服務(wù)也可以選本地部署的大模型服務(wù)只要它提供 OpenAI 兼容接口即可。比如本地跑一個支持 OpenAI 協(xié)議的模型服務(wù)然后在代碼里配置baseURL指向本地地址LangChain.js 就能把請求發(fā)過去。API Key 不要硬編碼在源碼里。建議統(tǒng)一放在環(huán)境變量文件.env中并通過dotenv加載。3.3 項目目錄規(guī)劃建議先建一個干凈的目錄方便后續(xù)擴展langchain-demo/ ├── .env ├── package.json └── src/ ├── chat.js ├── prompt.js ├── stream.js ├── memory.js ├── agent.js ├── server.js └── batch.jssrc目錄下每個文件對應(yīng)一個測試點后面運行和排查都更清晰。4. 安裝部署與首個對話程序4.1 初始化項目并安裝依賴先創(chuàng)建項目目錄并初始化mkdir langchain-demo cd langchain-demo npm init -y然后安裝核心依賴。LangChain.js 從 0.x 后期開始把模型廠商接入拆到獨立子包所以安裝時會同時裝核心包和 OpenAI 接入包npm install langchain langchain/openai dotenvlangchain/openai負(fù)責(zé) OpenAI 及兼容協(xié)議服務(wù)的接入langchain是核心編排包dotenv用來加載環(huán)境變量。如果你后續(xù)要用其他模型服務(wù)商再按需安裝對應(yīng)的接入包。4.2 創(chuàng)建環(huán)境變量文件在項目根目錄創(chuàng)建.envOPENAI_API_KEY你的API_KEY OPENAI_MODELgpt-4o-mini TEMPERATURE0.7OPENAI_MODEL是可選配置用于默認(rèn)模型名TEMPERATURE控制隨機性。如果你接的是本地模型服務(wù)可以在代碼里額外設(shè)置接口地址具體字段名根據(jù)你使用的服務(wù)來定。4.3 第一個對話調(diào)用在src/chat.js中寫代碼import dotenv/config; import { ChatOpenAI } from langchain/openai; import { HumanMessage } from langchain/core/messages; const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, temperature: parseFloat(process.env.TEMPERATURE || 0.7), }); const response await model.invoke([ new HumanMessage(請用一句話介紹 LangChain.js), ]); console.log(response.content);運行node src/chat.js如果配置正確終端會輸出模型返回的文本。這個例子雖然短但已經(jīng)覆蓋了 LangChain.js 最核心的鏈路加載環(huán)境變量、創(chuàng)建模型實例、構(gòu)造消息、調(diào)用模型、拿到結(jié)果。4.4 啟動驗證啟動后如果正常輸出文本說明環(huán)境沒問題。如果報錯優(yōu)先檢查 API Key 是否正確、網(wǎng)絡(luò)是否通、模型名是否可用。后面第 8 節(jié)會展開常見問題。5. 功能測試與效果驗證5.1 基礎(chǔ)對話測試測試目的驗證模型連通和調(diào)用鏈路的正確性。操作步驟運行node src/chat.js。預(yù)期結(jié)果終端輸出一句關(guān)于 LangChain.js 的介紹。判斷標(biāo)準(zhǔn)拿到文本且無異常報錯基礎(chǔ)鏈路通過。5.2 提示詞模板測試測試目的驗證提示詞模板能否動態(tài)注入?yún)?shù)。在src/prompt.js中寫代碼import dotenv/config; import { ChatOpenAI } from langchain/openai; import { ChatPromptTemplate } from langchain/core/prompts; const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, }); const prompt ChatPromptTemplate.fromMessages([ [system, 你是一名{topic}技術(shù)編輯回答要簡潔、專業(yè)。], [human, 請回答{question}], ]); const chain prompt.pipe(model); const result await chain.invoke({ topic: 前端工程化, question: LangChain.js 在什么場景下值得引入, }); console.log(result.content);運行node src/prompt.js預(yù)期結(jié)果模型按照 system 中設(shè)定的“技術(shù)編輯”角色回答并且回答內(nèi)容圍繞傳入的 question。常見失敗原因模板變量名不匹配{topic}和{question}必須與invoke傳入的字段名一致。5.3 流式輸出測試測試目的驗證流式輸出是否可用為后續(xù)接入聊天界面做準(zhǔn)備。在src/stream.js中寫代碼import dotenv/config; import { ChatOpenAI } from langchain/openai; import { HumanMessage } from langchain/core/messages; const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, }); const stream await model.stream([ new HumanMessage(寫一首關(guān)于 JavaScript 的短詩), ]); for await (const chunk of stream) { process.stdout.write(chunk.content || ); } console.log();運行node src/stream.js預(yù)期結(jié)果終端逐字或逐段出現(xiàn)內(nèi)容而不是一次性打印全部。判斷標(biāo)準(zhǔn)內(nèi)容能持續(xù)輸出且不中斷流式鏈路正常。5.4 多輪對話測試測試目的驗證上下文是否能通過消息數(shù)組正確傳遞。在src/memory.js中寫代碼import dotenv/config; import { ChatOpenAI } from langchain/openai; import { HumanMessage, AIMessage } from langchain/core/messages; const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, }); const messages [ new HumanMessage(請記住我的名字叫小明), ]; let response await model.invoke(messages); console.log(第一輪, response.content); messages.push(new AIMessage(response.content)); messages.push(new HumanMessage(我叫什么名字)); response await model.invoke(messages); console.log(第二輪, response.content);運行node src/memory.js預(yù)期結(jié)果第二輪回答能正確說出“小明”。關(guān)鍵點多輪對話不是框架自動記錄的而是需要把歷史消息按順序放回 messages 數(shù)組。實際項目中可以自己管理一個會話列表或者引入持久化存儲。5.5 Agent 工具調(diào)用測試測試目的驗證模型能否根據(jù)用戶問題自動選擇并調(diào)用外部工具。在src/agent.js中寫代碼import dotenv/config; import { ChatOpenAI } from langchain/openai; import { HumanMessage } from langchain/core/messages; import { tool } from langchain/core/tools; import { createToolCallingAgent, AgentExecutor } from langchain/agents; import { z } from zod; const getWeather tool( async ({ city }) { return ${city}明天多云氣溫 18℃~26℃; }, { name: get_weather, description: 查詢指定城市的天氣, schema: z.object({ city: z.string().describe(城市名稱), }), }, ); const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, }); const agent createToolCallingAgent({ llm: model, tools: [getWeather], }); const executor new AgentExecutor({ agent }); const result await executor.invoke({ messages: [new HumanMessage(北京今天天氣怎么樣)], }); console.log(result.output);運行前先安裝 zodnpm install zod運行node src/agent.js預(yù)期結(jié)果模型識別到問題需要查詢天氣自動調(diào)用get_weather工具并返回包含城市信息的回答。重點提示Agent 相關(guān) API 在不同版本中調(diào)整比較頻繁如果導(dǎo)入路徑或函數(shù)名不一致以你安裝版本的官方文檔為準(zhǔn)。這個例子里的天氣工具是模擬實現(xiàn)真實項目中應(yīng)該接入實際的天氣服務(wù)。5.6 測試結(jié)果判斷與失敗定位現(xiàn)象可能原因排查方向所有調(diào)用直接報錯API Key 錯誤或環(huán)境變量未加載檢查.env文件和dotenv配置提示詞模板報變量缺失模板變量名與傳入字段不一致檢查{xxx}占位符和 invoke 參數(shù)Agent 不調(diào)用工具模型不支持 tool calling 或 description 不夠清晰更換模型或調(diào)整工具描述輸出不按預(yù)期角色回答system 提示詞沒有生效檢查消息順序和模板結(jié)構(gòu)6. 接口 API 與批量任務(wù)6.1 用 Express 封裝 HTTP 接口LangChain.js 本身不提供 HTTP Server但可以非常方便地封裝成標(biāo)準(zhǔn) API。這里用 Express 做一個簡單的/api/chat接口。安裝依賴npm install express在src/server.js中寫代碼import dotenv/config; import express from express; import { ChatOpenAI } from langchain/openai; import { HumanMessage, SystemMessage } from langchain/core/messages; const app express(); app.use(express.json()); const model new ChatOpenAI({ model: process.env.OPENAI_MODEL || gpt-4o-mini, }); app.post(/api/chat, async (req, res) { const { message, system } req.body || {}; try { const messages []; if (system) { messages.push(new SystemMessage(system)); } messages.push(new HumanMessage(message)); const response await model.invoke(messages); res.json({ content: response.content }); } catch (error) { res.status(500).json({ error: error.message }); } }); const port process.env.PORT || 3000; app.listen(port, () { console.log(LangChain.js API 服務(wù)已啟動: http://127.0.0.1:${port}); });啟動node src/server.js6.2 curl 調(diào)用測試接口啟動后可以用 curl 驗證curl -X POST http://127.0.0.1:3000/api/chat \ -H Content-Type: application/json \ -d { system: 你是一個技術(shù)科普作者, message: 用兩句話介紹 LangChain.js }預(yù)期返回{ content: LangChain.js 是 LangChain 的 JavaScript 實現(xiàn)用于構(gòu)建大模型應(yīng)用。它提供了模型封裝、提示詞模板、Agent 工具調(diào)用等能力適合在 Node.js 環(huán)境中快速開發(fā) AI 應(yīng)用。 }判斷標(biāo)準(zhǔn)HTTP 狀態(tài)碼 200返回結(jié)構(gòu)包含content字段。接口能跑通之后就可以接到自己的前端、腳本或其他后端服務(wù)里。6.3 批量任務(wù)批量任務(wù)在 LangChain.js 里本質(zhì)上是并發(fā)執(zhí)行多個invoke。最簡單的方式是Promise.allconst questions [ LangChain.js 和 LangChain(Python) 有什么差異, Node.js 后端接入大模型 API 要注意什么, Agent 工具調(diào)用適合什么業(yè)務(wù)場景, ]; const results await Promise.all( questions.map(async (question) { const response await model.invoke([new HumanMessage(question)]); return { question, answer: response.content }; }), ); console.log(JSON.stringify(results, null, 2));這種方式實現(xiàn)簡單但會把所有請求同時打出去容易觸發(fā)上游限流。更穩(wěn)妥的方式是做一個帶并發(fā)控制的批量處理函數(shù)async function mapWithConcurrency(tasks, limit, worker) { const results []; const queue [...tasks]; async function run() { while (queue.length 0) { const task queue.shift(); results.push(await worker(task)); } } const workers Array.from({ length: limit }, () run()); await Promise.all(workers); return results; } const allResults await mapWithConcurrency( questions, 2, async (question) { const response await model.invoke([new HumanMessage(question)]); return { question, answer: response.content }; }, );limit控制并發(fā)數(shù)比如 2 表示同時最多只有兩個請求在跑能有效降低限流風(fēng)險。6.4 失敗重試大模型 API 調(diào)用可能因為網(wǎng)絡(luò)波動、上游限流等原因失敗。批量任務(wù)里建議加重試邏輯async function runWithRetry(question, retries 2) { for (let i 0; i retries; i) { try { const response await model.invoke([new HumanMessage(question)]); return { question, answer: response.content }; } catch (error) { if (i retries) { return { question, error: error.message }; } await new Promise((resolve) setTimeout(resolve, 1000 * (i 1))); } } } const results await Promise.all( questions.map((question) runWithRetry(question)), );這里采用指數(shù)退避的簡化版本第一次失敗等 1 秒第二次失敗等 2 秒。更復(fù)雜的場景可以記錄失敗詳情把失敗任務(wù)重新投遞到隊列。7. 資源占用與性能觀察7.1 觀察維度LangChain.js 是純 Node.js 框架本身不消耗 GPU。運行時資源主要取決于模型 API 的響應(yīng)時間。并發(fā)請求數(shù)量。單次請求的輸入輸出 token 數(shù)量。內(nèi)存中保留的對話歷史長度。可以在代碼里直接測量耗時和內(nèi)存console.time(invoke); const response await model.invoke([new HumanMessage(測試)]); console.timeEnd(invoke); const memory process.memoryUsage(); console.log(RSS: ${(memory.rss / 1024 / 1024).toFixed(2)} MB); console.log(Heap Used: ${(memory.heapUsed / 1024 / 1024).toFixed(2)} MB);7.2 Token 使用統(tǒng)計很多模型響應(yīng)會附帶 token 使用量LangChain.js 中可以通過響應(yīng)對象拿到。字段名根據(jù)模型廠商不同會有差異常見的是usage_metadata或response_metadata。第一次接入時建議先打印完整響應(yīng)結(jié)構(gòu)再按實際字段寫統(tǒng)計邏輯console.log(JSON.stringify(response, null, 2));7.3 流式與非流式流式輸出適合對話類產(chǎn)品首字延遲更低用戶感知更快。非流式適合批量處理代碼更簡單方便做重試和結(jié)果落庫。如果業(yè)務(wù)場景不要實時打字效果批量處理時建議使用非流式減少連接管理復(fù)雜度。7.4 并發(fā)控制大模型 API 普遍有速率限制。并發(fā)太高會影響穩(wěn)定性和成本。常見做法單用戶場景限制并發(fā)數(shù)為 1 到 3。批量任務(wù)先跑一個小樣本測試觀察限流響應(yīng)再逐步調(diào)整并發(fā)數(shù)。長時間任務(wù)使用任務(wù)隊列配合失敗重試和日志記錄。如果服務(wù)要暴露給外部調(diào)用建議在 HTTP 接口層加限流避免一個上游接口被過度調(diào)用。8. 常見問題與排查方法問題現(xiàn)象可能原因排查方式解決方案dotenv配置不生效環(huán)境變量文件路徑不對或沒有被加載檢查項目根目錄是否存在.env在入口文件最頂部import dotenv/config調(diào)用時報 401API Key 錯誤或已過期檢查.env中的 Key 是否正確重新申請或更新 API Key報模型不存在模型名寫錯或當(dāng)前賬號無權(quán)限對照模型服務(wù)商文檔檢查模型名修改OPENAI_MODEL配置請求超時網(wǎng)絡(luò)不穩(wěn)定或回復(fù)過長查看日志中的超時時間增加超時時間或優(yōu)化提示詞控制輸出長度依賴版本沖突不同包版本不兼容檢查package.json中的版本范圍鎖定版本號重新執(zhí)行npm installAgent 不調(diào)用工具模型不支持 tool calling 或工具描述不明確打印中間消息查看模型意圖換支持 tool calling 的模型優(yōu)化工具描述批量任務(wù)被限流并發(fā)過高或觸發(fā)上游速率限制觀察錯誤響應(yīng)碼降低并發(fā)數(shù)加重試和退避邏輯內(nèi)存持續(xù)增長對話歷史或批量結(jié)果沒有釋放檢查消息數(shù)組是否無限增長設(shè)置對話長度上限定期清理歷史9. 最佳實踐與使用建議9.1 先跑通最小示例第一次接觸 LangChain.js 時不要一上來就搭復(fù)雜 Agent。先把最簡單的model.invoke跑通確認(rèn)環(huán)境、模型服務(wù)和 API Key 沒有問題再逐步引入提示詞模板、流式輸出和工具調(diào)用。9.2 鎖定依賴版本LangChain.js 迭代比較快API 可能存在破壞性變更。生產(chǎn)項目建議在package.json中鎖定主版本范圍升級依賴時單獨驗證核心功能不要直接npm update。9.3 使用單元測試把提示詞模板、模型調(diào)用、Agent 工具邏輯拆成獨立函數(shù)方便做單元測試。模型調(diào)用部分可以 mock 返回結(jié)果這樣測試不依賴真實 API也不消耗 token。9.4 日志與可觀測性模型調(diào)用的輸入、輸出、耗時、token 使用量建議都記錄下來。批量任務(wù)尤其需要日志否則任務(wù)中途失敗時很難定位是哪個輸入導(dǎo)致的。9.5 內(nèi)容安全與權(quán)限控制如果 Agent 要調(diào)用內(nèi)部系統(tǒng)必須在工具函數(shù)里做權(quán)限校驗不能讓用戶通過自然語言繞過限制。所有生成內(nèi)容在正式發(fā)布前需要人工抽查尤其是面向公眾或涉及事實判斷的場景。9.6 密鑰與配置分離API Key、數(shù)據(jù)庫連接串、內(nèi)部服務(wù)地址不要寫在代碼里。統(tǒng)一用環(huán)境變量或配置中心管理并在.gitignore中排除.env文件。10. 總結(jié)與下一步LangChain.js 最值得嘗試的點是它能把 AI 應(yīng)用開發(fā)里的碎片化邏輯串起來。從一次模型調(diào)用開始到提示詞模板、流式輸出、多輪對話、Agent 工具調(diào)用再到 HTTP API 和批量任務(wù)每個環(huán)節(jié)都能在幾行代碼內(nèi)完成。對于已經(jīng)熟悉 Node.js 的團隊它是一套上手成本比較低的 AI 工程化方案。建議優(yōu)先驗證三個功能基礎(chǔ)對話調(diào)用、提示詞模板、Agent 工具調(diào)用。這三個能力確認(rèn)沒問題就已經(jīng)能覆蓋大多數(shù)實際業(yè)務(wù)場景。最容易踩的坑有兩個一是不同版本的 API 差異二是批量任務(wù)并發(fā)控制不當(dāng)導(dǎo)致上游限流。前者靠鎖版本和官方文檔解決后者靠并發(fā)限制和失敗重試緩解。后續(xù)可以繼續(xù)擴展的方向包括接入向量數(shù)據(jù)庫做 RAG 知識庫問答、結(jié)合 LangSmith 做調(diào)用鏈追蹤、用多 Agent 編排處理更復(fù)雜的業(yè)務(wù)流。先把最小示例跑起來再按真實業(yè)務(wù)需求往上加能力是 LangChain.js 項目最穩(wěn)妥的推進方式。建議收藏備用動手時能省不少排錯時間。