LangChain Expression Language,是 LangChain 提供的一种声明式构建 链式 调用流程的方式。它允许开发者用 .pipe() 操作符将不同的模块(如提示模板、模型、解析器等)连接起来,形成一个完整的“链(Chain)”。
LCEL 的设计理念:
- 所有模块都实现统一接口:
Runnable - 任意模块之间都可以
.pipe()链接组合 - 逻辑更清晰、组合更自由、调试也更友好
下面是一个快速上手示例:
import { ChatOllama } from '@langchain/ollama'import { PromptTemplate } from '@langchain/core/prompts'import { StringOutputParser } from '@langchain/core/output_parsers'
// 创建模块:提示词模块、模型模块、解析器模块
// 1. 创建提示词const pt = PromptTemplate.fromTemplate('请严格使用中文解释:{question}')
// 2. 创建模型const model = new ChatOllama({ model: 'llama3', temperature: 0.7,})
// 3. 创建一个解析器const parser = new StringOutputParser()
// 4. 将上面的 3 个模块连接起来:pipe// 相当于创建了一个链条const chain = pt.pipe(model).pipe(parser)
// 5. 使用 chain 这个链条const res = await chain.invoke({ question: '什么是闭包',})
console.log(res)可以把 .pipe() 理解成模块之间的数据通道:
pt接收原始输入,并生成提示文本model根据提示生成回答parser把模型响应格式化成字符串输出
从输入到输出,整个流程结构清晰、逻辑统一,而且每个环节都可以随时替换或插拔,非常适合真实项目开发。在 LCEL 中,所有组件都抽象为一种“可执行单元”,都实现了统一的 Runnable 接口,从而都都变成可以链式组合的模块。
核心方法#
1. invoke#
这是最常用的同步执行方式,该方法会执行整条链,返回完整结果。
import { ChatOllama } from '@langchain/ollama'import { PromptTemplate } from '@langchain/core/prompts'import { StringOutputParser } from '@langchain/core/output_parsers'
// 创建模块const prompt = PromptTemplate.fromTemplate('请使用中文解释:{topic}')const llm = new ChatOllama({ model: 'llama3', temperature: 0.7 })const parser = new StringOutputParser()
// 构建链式流程const chain = prompt.pipe(llm).pipe(parser)
// 执行链式调用const result = await chain.invoke({ topic: '闭包(closure)是什么?' })
console.log('LLM 输出:', result)2. pipe#
这是用于 组合模块 的方法,会将输出“接入”下一个模块,主要用于拼接模块构建 chain,比如:
Prompt -> 模型 -> 解析器例如我们上面例子中的:
const chain = prompt.pipe(llm).pipe(parser)// 你可以继续 pipe 更多环节,比如日志记录、后处理本质上 .pipe() 会返回一个新的 Runnable,你可以链式无限拼接。换句话说,只要模块实现了 Runnable 接口,就可以进行相互拼接。
3. stream#
该方法用于获取流式结果,逐块返回 LLM 输出,适合实现 ChatGPT 风格对话输出。
import { ChatOllama } from '@langchain/ollama'import { PromptTemplate } from '@langchain/core/prompts'import { StringOutputParser } from '@langchain/core/output_parsers'
// 创建模块:提示词模块、模型模块、解析器模块
// 1. 创建提示词const pt = PromptTemplate.fromTemplate('请严格使用中文解释:{question}')
// 2. 创建模型const model = new ChatOllama({ model: 'llama3', temperature: 0.7,})
// 3. 创建一个解析器const parser = new StringOutputParser()
// 4. 将上面的 3 个模块连接起来:pipe// 相当于创建了一个链条const chain = pt.pipe(model).pipe(parser)
// 5. 使用 chain 这个链条const res = await chain.stream({ question: '什么是闭包',})
for await (const chunk of res) { process.stdout.write(chunk)}4. batch#
该方法用于同时处理多个输入,适合批量问答、摘要等场景,返回一个结果数组。
import { ChatOllama } from '@langchain/ollama'import { PromptTemplate } from '@langchain/core/prompts'import { StringOutputParser } from '@langchain/core/output_parsers'
// 创建模块:提示词模块、模型模块、解析器模块
// 1. 创建提示词const pt = PromptTemplate.fromTemplate('请严格使用中文解释:{question}')
// 2. 创建模型const model = new ChatOllama({ model: 'llama3', temperature: 0.7,})
// 3. 创建一个解析器const parser = new StringOutputParser()
// 4. 将上面的 3 个模块连接起来:pipe// 相当于创建了一个链条const chain = pt.pipe(model).pipe(parser)
// 5. 多条输入const inputs = [ { question: '闭包' }, { question: '原型链' }, { question: '事件循环' },]
const res = await chain.batch(inputs)
// console.log(res);res.forEach((r, idx) => { console.log(`第${idx + 1}条结果:`, r)})🤔 这个时候,有的同学可能会想:能不能一边批量处理多个输入(batch),一边使用流式输出(stream)逐条显示结果?
很遗憾这是不行的,因为:
chain.batch() 和 chain.stream() 不是同一套返回范式,不能在一次调用里既 batch 又拿到 token 级别的流。
batch()返回的是“多个完整结果”的Promise<string[]>stream()返回的是“单输入的异步迭代器(token 流)
那有没有办法实现“批量 + 流式”呢?当然也可以,我们可以自己来控制并发。下节课介绍。