LangChain.js核心概念:LCEL的魔力
2026/8/11 5:26:39 网站建设 项目流程
上次我们初步了解了 LangChain.js的基础知识。今天,我要带大家深入探索LangChain.js最核心的概念之一: LangChain表达式语言(LCEL)。这个概念可能会彻底改变你构建AI应用的方式!

什么是LCEL?

LangChain表达式语言(LangChain Expression Language,简称LCEL)是一种声明式的方法,用于轻松组合链式操作。如果将AI应用比作一道美食,那么LCEL就是现代化的烹饪流程 - 它不仅告诉你需要哪些食材,还提供了一种优雅的方式来描述这些食材如何组合在一起。

LCEL从设计之初就支持将原型直接投入生产,无需代码更改,从最简单的"提示词+LLM"链到最复杂的链(有人成功在生产环境中运行包含数百个步骤的LCEL链)。

为什么需要LCEL?

当我刚开始构建AI应用时,我的代码是这样的:

// 调用模型获取结果 const result1 = await llm.invoke(prompt1); // 处理结果 const processedResult = processResult(result1); // 再次调用模型 const result2 = await llm.invoke(prompt2 + processedResult); // 更多处理.

看起来很简单,对吧?但随着应用复杂度增加,这种方式很快就会变得难以维护。LCEL的出现解决了这个问题,它让我们能够:

  1. 一流的流式处理支持:当你使用LCEL构建链时,你可以获得最佳的首字符输出时间(从请求到第一个输出块出现的时间)
  2. 优化的并行执行:当LCEL链中有可以并行执行的步骤时,系统会自动并行处理以获得最小的延迟
  3. 重试和回退机制:为LCEL链的任何部分配置重试和回退,使你的链在大规模运行时更可靠
  4. 访问中间结果:对于复杂的链,访问中间步骤的结果非常有用,可以让终端用户知道正在发生什么,或者用于调试
  5. 输入和输出模式:每个LCEL链都有从链结构推断出的模式,可用于验证输入和输出
  6. 无缝LangSmith跟踪:随着链变得越来越复杂,了解每一步到底发生了什么变得越来越重要,使用LCEL,所有步骤都会自动记录到LangSmith中,以获得最大的可观察性和可调试性

LCEL的基本用法

让我们看看如何使用LCEL构建一个简单的链:

import { ChatDeepSeek } from "@langchain/deepseek"; import { PromptTemplate } from "@langchain/core/prompts"; import { StringOutputParser } from "@langchain/core/output_parsers"; // 加载环境变量process.env.DEEPSEEK_API_KEY import * as dotenv from 'dotenv' dotenv.config(); // 初始化语言模型 const llm = new ChatDeepSeek({ apiKey: process.env.DEEPSEEK_API_KEY, // 请替换为您的DeepSeek API密钥 temperature: 0.7, modelName: "deepseek-chat", // 指定模型名称 maxTokens: 100, // 设置最大token数,最生成回答的长度,我这里为了测试,限制了100,实际情况自定 }); // 创建提示模板 const promptTemplate = PromptTemplate.fromTemplate( "给我讲一个关于{topic}的笑话" ); // 创建输出解析器 const outputParser = new StringOutputParser(); // 使用LCEL构建链 const jokeChain = promptTemplate.pipe(llm).pipe(outputParser); // 运行链 const result = await jokeChain.invoke({ topic: "程序员" }); console.log(result); // 输出一个关于程序员的笑话

LCEL的高级用法

1. 顺序处理

当我们需要将一个步骤的输出作为下一个步骤的输入时:

import { ChatDeepSeek } from "@langchain/deepseek"; import { PromptTemplate } from "@langchain/core/prompts"; import { StringOutputParser } from "@langchain/core/output_parsers"; // 这个方法主要用来在调用链的时候,可以输出链中每一个节点的输入输出,好进行debug import { ConsoleCallbackHandler } from "@langchain/core/tracers/console"; // 记载环境变量 import * as dotenv from 'dotenv'; dotenv.config(); // 初始化语言模型 const llm = new ChatDeepSeek({ apiKey: process.env.DEEPSEEK_API_KEY, // 请替换为您的DeepSeek API密钥 temperature: 0.7, modelName: "deepseek-chat", // 指定模型名称 maxTokens: 100, // 设置最大token数 }); // 第一个提示模板:生成故事主题 const themePrompt = PromptTemplate.fromTemplate( "生成一个{genre}故事的主题" ); // 第二个提示模板:根据主题创建故事 const storyPrompt = PromptTemplate.fromTemplate( "根据主题'{theme}'写一个短故事" ); const outputParser = new StringOutputParser(); // 使用LCEL构建链,用于生成主题(主题生成器) const storyGenerationChain = themePrompt // 主题词模版 .pipe(llm) // 调用llm,生成主题 .pipe(outputParser) // 解析输出 .pipe((theme) => ({ theme })) // 输出内容转them参数传给下一个主题提示词模版 .pipe(storyPrompt) // 故事词模版 .pipe(llm) // 调用llm,生成故事 .pipe(outputParser) // 解析输出 // 运行链,输入初始的参数 const result = await storyGenerationChain.invoke({ genre: "科幻" }, { //这个配置用来输出每个节点的输入输出,好进行调试 callbacks: [ new ConsoleCallbackHandler() ] }); console.log(result);

2. 并行处理

当我们需要同时执行多个操作并合并结果时:

import { ChatDeepSeek } from "@langchain/deepseek"; import { PromptTemplate } from "@langchain/core/prompts"; import { StringOutputParser } from "@langchain/core/output_parsers"; import { RunnableMap, RunnableSequence } from "@langchain/core/runnables"; // 记载环境变量 import * as dotenv from 'dotenv' dotenv.config(); // 初始化语言模型 const llm = new ChatDeepSeek({ apiKey: process.env.DEEPSEEK_API_KEY, // 请替换为您的DeepSeek API密钥 temperature: 0.7, modelName: "deepseek-chat", // 指定模型名称 maxTokens: 100, // 设置最大token数 }); const positivePrompt = PromptTemplate.fromTemplate( "请根据以下辩题提出一个正方观点: {text}" ); const negativePrompt = PromptTemplate.fromTemplate( "请根据以下辩题提出一个反方观点: {text}" ); const outputParser = new StringOutputParser(); // 创建两个独立的链 const positiveChain = positivePrompt.pipe(llm).pipe(outputParser); const negativeChain = negativePrompt.pipe(llm).pipe(outputParser); // 并行执行这两个链 const parallelChain = RunnableMap.from({ positive: positiveChain, negative: negativeChain }); // 将并行结果传递给最终处理 const finalPrompt = PromptTemplate.fromTemplate( "正方观点: {positive}\n\n反方观点: {negative}\n\n请对比这两个内容并给出分析。" ); // 可以沿用pipe链式的方式,将parallelChain链入调用链中 // const finalChain = parallelChain // .pipe(finalPrompt) // .pipe(llm) // .pipe(outputParser) //也可以通过RunnableSequence,两者效果相同 const finalChain = RunnableSequence.from([ parallelChain, finalPrompt, llm, outputParser ]); // 运行链 const result = await finalChain.invoke({ text: "肉体和灵魂哪个更重要?,正方肉体,反方灵魂" }); console.log(result);

3. 条件分支处理

使用LCEL实现条件逻辑:

import { ChatDeepSeek } from "@langchain/deepseek"; import { RunnableBranch } from "@langchain/core/runnables"; // 记载环境变量 import * as dotenv from 'dotenv' dotenv.config(); // 初始化语言模型 const llm = new ChatDeepSeek({ apiKey: process.env.DEEPSEEK_API_KEY, // 请替换为您的DeepSeek API密钥 temperature: 0.7, modelName: "deepseek-chat", // 指定模型名称 maxTokens: 100, // 设置最大token数 }); // 创建三个独立的链,这里只是简单的返回字符串,实际应用中可以返回更复杂的数据,去调用专门的llm文生图,写代码,文生视频等 const weatherChain = () => "今天天气晴朗,气温25度,适合外出活动"; const newsChain = () => "今日头条:人工智能技术持续发展,为各行业带来新机遇"; const generalQAChain = () => "这是一个通用回答:请具体描述您的问题,我会为您解答"; // 创建条件分支,实际应用中可以通过llm判断,这里只是简单的判断 const branchChain = RunnableBranch.from([ [ (input) => input.query.includes("天气"), weatherChain ], [ (input) => input.query.includes("新闻"), newsChain ], generalQAChain // 默认分支 ]); // 运行链 const result = await branchChain.invoke({ query: "今天天气如何" }); console.log(result);

LCEL的最佳实践

在我使用LCEL构建了多个应用后,我总结了一些最佳实践:

  1. 利用流式处理:LCEL的一流流式处理支持可以大大提高用户体验,特别是对于长回复
  2. 合理使用并行:识别可以并行执行的步骤,让LCEL为你优化执行
  3. 添加错误处理:使用重试和回退机制增强链的可靠性
  4. 监控中间结果:在开发过程中查看中间结果,帮助调试和理解链的行为
  5. 集成LangSmith:利用LangSmith进行跟踪和监控,特别是在生产环境中
  6. 保持模块化:将复杂链分解为更小、可重用的组件

结语

LangChain表达式语言(LCEL)是LangChain.js的灵魂,掌握了LCEL,你就掌握了构建复杂AI应用的核心能力。它让我们能够以一种声明式、可维护的方式组合AI能力,从原型快速过渡到生产。

LCEL不仅提供了一种优雅的方式来描述复杂的AI工作流,还自动为我们处理了许多底层细节,如流式处理、并行执行和错误处理。这使我们能够专注于应用逻辑,而不是基础设施问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询