LangChain.js核心概念:LCEL的魔力 上次我们初步了解了 LangChain.js的基础知识。今天我要带大家深入探索LangChain.js最核心的概念之一 LangChain表达式语言LCEL。这个概念可能会彻底改变你构建AI应用的方式什么是LCELLangChain表达式语言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的出现解决了这个问题它让我们能够一流的流式处理支持当你使用LCEL构建链时你可以获得最佳的首字符输出时间从请求到第一个输出块出现的时间优化的并行执行当LCEL链中有可以并行执行的步骤时系统会自动并行处理以获得最小的延迟重试和回退机制为LCEL链的任何部分配置重试和回退使你的链在大规模运行时更可靠访问中间结果对于复杂的链访问中间步骤的结果非常有用可以让终端用户知道正在发生什么或者用于调试输入和输出模式每个LCEL链都有从链结构推断出的模式可用于验证输入和输出无缝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构建了多个应用后我总结了一些最佳实践利用流式处理LCEL的一流流式处理支持可以大大提高用户体验特别是对于长回复合理使用并行识别可以并行执行的步骤让LCEL为你优化执行添加错误处理使用重试和回退机制增强链的可靠性监控中间结果在开发过程中查看中间结果帮助调试和理解链的行为集成LangSmith利用LangSmith进行跟踪和监控特别是在生产环境中保持模块化将复杂链分解为更小、可重用的组件结语LangChain表达式语言LCEL是LangChain.js的灵魂掌握了LCEL你就掌握了构建复杂AI应用的核心能力。它让我们能够以一种声明式、可维护的方式组合AI能力从原型快速过渡到生产。LCEL不仅提供了一种优雅的方式来描述复杂的AI工作流还自动为我们处理了许多底层细节如流式处理、并行执行和错误处理。这使我们能够专注于应用逻辑而不是基础设施问题。