从调用到架构:用 LangChain.js + DeepSeek 构建可维护的大模型应用
在 2024 到 2025 年间,大语言模型(LLM)的使用已经悄然完成了一次关键跃迁——从“能跑就行”的原型验证,正式迈入工程化落地的新阶段。对于开发者而言,仅仅通过 fetch 调用一个 API 返回一段文本,早已无法满足生产环境对稳定性、可维护性与扩展性的要求。
我们开始面对一系列真实挑战:
- 不同厂商的 API 格式五花八门,切换模型成本极高;
- 提示词散落在代码各处,难以复用和迭代;
- 上下文管理混乱,任务逻辑耦合严重;
- 复杂业务需要多步推理,单次 Prompt 难以胜任。
正是在这样的背景下,LangChain 应运而生。它不是另一个模型,而是一个面向 LLM 应用的工程框架,致力于将 AI 能力封装为模块化、可组合、可测试的软件组件。
本文将以 LangChain.js 与国产优秀模型 DeepSeek(深度求索) 为例,通过四个层层递进的代码示例,带你完成从“简单调用”到“复杂工作流编排”的完整进化路径。
第一步:统一接口 —— 用适配器屏蔽模型差异
在没有框架的时代,调用不同 LLM 意味着要为每个平台写一套独立的 HTTP 请求逻辑。OpenAI 的 JSON 结构、DeepSeek 的鉴权方式、Claude 的消息格式……光是维护这些细节就足以让人崩溃。
LangChain 的第一个价值,就是标准化。
// main.js
import 'dotenv/config';
import { ChatDeepSeek } from '@langchain/deepseek';
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0, // 确定性输出,适合逻辑推理
});
const response = await model.invoke('用一句话解释什么是 RAG?');
console.log(response.content);
关键洞察:适配器模式的威力
ChatDeepSeek 本质上是一个适配器(Adapter)。它对外暴露统一的 .invoke() 接口,内部则封装了:
- 正确的请求端点(baseURL)
- API Key 的自动注入(从
DEEPSEEK_API_KEY环境变量读取) - 符合 DeepSeek 规范的请求体构造
这意味着,未来若要切换至 OpenAI 或其他模型,你只需更换类名(如 ChatOpenAI),其余业务代码完全无需改动。这种解耦,是工程化的第一步。
💡 小贴士:
temperature=0适用于代码生成、数学推理等场景;若需创意发散(如写故事、起名字),可设为 0.7 以上。
第二步:提示词工程化 —— 告别硬编码字符串
直接在 invoke() 中传入拼接好的字符串,看似快捷,实则埋下隐患:提示词无法复用、难以测试、修改成本高。
LangChain 提供了 PromptTemplate,让提示词变成“带参数的模板”。
// prompt-template.js
import { PromptTemplate } from '@langchain/core/prompts';
import { ChatDeepSeek } from '@langchain/deepseek';
const template = PromptTemplate.fromTemplate(`
你是一位{role}。
请用不超过{limit}字回答以下问题:
{question}
`);
const formattedPrompt = await template.format({
role: '前端面试官',
limit: '50',
question: '什么是闭包?'
});
const model = new ChatDeepSeek({ model: 'deepseek-reasoner', temperature: 0.7 });
const res = await model.invoke(formattedPrompt);
console.log(res.content);
为什么这很重要?
- 复用性:同一模板可用于“Java 面试官”、“产品经理”等角色,只需改变参数。
- 可维护性:优化提示逻辑(如增加“请用中文回答”)只需修改一处。
- 类型友好:在 TypeScript 项目中,模板变量可被静态检查,减少运行时错误。
但注意:这段代码仍是“命令式”的——先格式化,再调用。有没有更优雅的方式?
第三步:声明式流水线 —— 用 LCEL 实现自动流转
LangChain 的核心思想之一,是链(Chain)。通过 LangChain 表达式语言(LCEL),我们可以像搭管道一样,把组件串联起来。
// chain.js
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';
const model = new ChatDeepSeek({ model: 'deepseek-reasoner', temperature: 0.7 });
const prompt = PromptTemplate.fromTemplate(`你是一位前端专家,请用一句话解释:{topic}`);
// 关键:用 .pipe() 连接
const chain = prompt.pipe(model);
const result = await chain.invoke({ topic: '闭包' });
console.log(result.content);
声明式编程的魅力
这里我们不再关心“如何传递数据”,而是定义“数据应该流经哪些节点”。LangChain 在运行时会自动:
- 将
{ topic: '闭包' }注入模板,生成完整提示; - 将提示字符串传给模型;
- 返回最终结果。
所有组件(Prompt、Model、Parser)都实现了 Runnable 接口,支持 .invoke()、.stream()、.batch() 等统一操作。这种设计,为构建智能体(Agent)打下了坚实基础。
第四步:复杂任务编排 —— 拆解问题,分而治之
现实中的需求往往不止一步。比如:“先详细解释闭包原理,再提炼三个核心要点”。
如果强行塞进一个 Prompt,模型容易顾此失彼。更好的做法是:任务分解 + 顺序执行。
// workflow.js
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';
import { RunnableSequence } from '@langchain/core/runnables';
const model = new ChatDeepSeek({ model: 'deepseek-reasoner', temperature: 0.7 });
// 步骤一:详细解释
const explainPrompt = PromptTemplate.fromTemplate(`
你是一位前端专家,请详细介绍:{topic}
要求:包含定义、原理、使用方式,不超过300字。
`);
// 步骤二:精简总结
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下内容总结为3个核心要点(每点≤20字):
{explanation}
`);
// 构建子链
const explainChain = explainPrompt.pipe(model);
const summaryChain = summaryPrompt.pipe(model);
// 编排主流程
const fullChain = RunnableSequence.from([
async (input) => {
const explanation = await explainChain.invoke({ topic: input.topic });
return explanation.content;
},
async (explanation) => {
const summary = await summaryChain.invoke({ explanation });
return `【详解】\n${explanation}\n\n【摘要】\n${summary.content}`;
}
]);
const output = await fullChain.invoke({ topic: '闭包' });
console.log(output);
工程化思维的体现
- 关注点分离:解释与总结由两个独立链完成,职责清晰。
- 输入/输出对齐:前一步的输出自然成为后一步的输入变量。
- 调试友好:可单独测试
explainChain的准确性,无需重跑整个流程。 - 发挥模型优势:
deepseek-reasoner在逻辑推理与归纳总结上表现突出,任务拆解能最大化其能力。
总结:从脚本到系统的跃迁
通过这四个阶段,我们见证了 LLM 应用开发的成熟路径:
| 阶段 | 核心思想 | 解决的问题 |
|---|---|---|
| 1. 适配器 | 统一接口 | 模型碎片化、切换成本高 |
| 2. 模板化 | 数据/逻辑分离 | 提示词硬编码、难维护 |
| 3. 链式化 | 声明式流水线 | 手动串联、流程冗余 |
| 4. 编排化 | 任务分解 | 单 Prompt 能力不足 |
LangChain.js + DeepSeek 的组合,不只是让你“调用一个大模型”,而是为你提供了一套构建 AI 原生应用的工程脚手架。
作为前端或全栈开发者,在 AI 时代的核心竞争力,已不再是“会不会调 API”,而是能否用软件工程的方法,将 AI 能力可靠地集成到产品中。
✅ 最后提醒:别忘了在
.env文件中配置DEEPSEEK_API_KEY,并确保环境变量正确加载!
掌握这种“搭积木式”的 AI 开发范式,你就能在 LLM 浪潮中,不仅跟上节奏,更能引领架构。
共同学习,写下你的评论
评论加载中...
作者其他优质文章