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";const pt = PromptTemplate.fromTemplate("请用一定用中文解释:{question}");const model = new ChatOllama({model: "llama3",temperature: 0.7,
});const parser = new StringOutputParser();const chain = pt.pipe(model).pipe(parser);const res = chain.streamEvents({ question: "什么是AI" }, { version: "v2" });for await (const event of res) {console.log(event);if (event.event === "on_chat_model_stream") {process.stdout.write(event.data?.chunk?.content || "");}
}
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 流)
那有没有办法实现“批量 + 流式”呢?当然也可以,我们可以自己来控制并发。下节课介绍。
-EOF-