你應該懂的AI 大模型(五)之 LangChain 之 LCEL
本文 對《LangChain》一文中的 Chain 與 LCEL 部分的示例進行詳細的展示。
先回顧下 在LangChain框架中,Chain(鏈) 和 LCEL(LangChain Expression Language) 是兩個密切相關但本質不同的概念。
Chain(鏈): 是LangChain中處理流程的抽象概念,指將多個組件(模型、工具、邏輯)串聯成一個可執行的任務序列。
LangChain Expression Language(LCEL)是一種聲明式語言,可輕松組合不同的調用順序構成 Chain。LCEL 自創立之初就被設計為能夠支持將原型投入生產環境,無需代碼更改,從最簡單的“提示+LLM”鏈到最復雜的鏈(已有用戶成功在生產環境中運行包含數百個步驟的 LCEL Chain)。
在本文中 LCEL 產生的對象,被叫做 runnable 或 chain,經常兩種叫法混用。本質就是一個自定義調用流程。
1、Pipeline 式調用 PromptTemplate, LLM 和 OutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from pydantic import BaseModel, Field, validator
from typing import List, Dict, Optional
from enum import Enum
import json
# 輸出結構
class SortEnum(str, Enum):
data = 'data'
price = 'price'
class OrderingEnum(str, Enum):
ascend = 'ascend'
descend = 'descend'
class Semantics(BaseModel):
name: Optional[str] = Field(description="套餐名稱", default=None)
price_lower: Optional[int] = Field(description="價格下限", default=None)
price_upper: Optional[int] = Field(description="價格上限", default=None)
data_lower: Optional[int] = Field(description="流量下限", default=None)
data_upper: Optional[int] = Field(description="流量上限", default=None)
sort_by: Optional[SortEnum] = Field(description="按價格或流量排序", default=None)
ordering: Optional[OrderingEnum] = Field(description="升序或降序排列", default=None)
# Prompt 模板
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一個語義解析器。你的任務是將用戶的輸入解析成JSON表示。不要回答用戶的問題。"),
("human", "{text}"),
]
)
# 模型
llm = ChatOpenAI(model="gpt-4o", temperature=0)
structured_llm = llm.with_structured_output(Semantics)
# LCEL 表達式
runnable = (
{"text": RunnablePassthrough()} | prompt | structured_llm
)
# 直接運行
ret = runnable.invoke("不超過100元的流量大的套餐有哪些")
print(
json.dumps(
ret.dict(),
indent = 4,
ensure_ascii=False
)
)
輸出結果如下:

流式輸出,就是那種一個字一個字蹦的輸出,大家可以用下面代碼體驗一下玩一玩
prompt = PromptTemplate.from_template("講個關于{topic}的笑話")
runnable = (
{"topic": RunnablePassthrough()} | prompt | llm | StrOutputParser()
)
# 流式輸出
for s in runnable.stream("李華"):
print(s, end="", flush=True)
2、用LECL實現RAG
我們通過分割一個 pdf 文件形成向量庫,示例如下:
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain_community.document_loaders import PyMuPDFLoader
# 加載文檔
loader = PyMuPDFLoader("llama2.pdf")
pages = loader.load_and_split()
# 文檔切分
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=300,
chunk_overlap=100,
length_function=len,
add_start_index=True,
)
texts = text_splitter.create_documents(
[page.page_content for page in pages[:4]]
)
# 灌庫
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
db = FAISS.from_documents(texts, embeddings)
# 檢索 top-2 結果
retriever = db.as_retriever(search_kwargs={"k": 2})
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough
# Prompt模板
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
# Chain
rag_chain = (
{"question": RunnablePassthrough(), "context": retriever}
| prompt
| llm
| StrOutputParser()
)
rag_chain.invoke("Llama 2有多少參數")
輸出結果如下:

3、LECL 的意義是什么
在 LangChain 框架中,LCEL(LangChain Expression Language)的意義主要體現在增強模塊間的解耦能力、提升流程編排的靈活性,并為復雜的 LLM(大語言模型)應用構建提供標準化的邏輯表達工具。以下是具體分析:
一、LangChain 中的模塊解耦需求
LangChain 的核心目標是通過組合不同的組件(如 LLMs、Prompt 模板、工具調用、內存管理等)構建復雜的應用流程。例如:
-
組件類型:LLM 調用、工具(如計算器、數據庫查詢)、內存(對話歷史存儲)、Prompt 模板、鏈(Chain,如 SequentialChain、RouterChain)等。
-
解耦痛點:
傳統方式下,組件間的交互邏輯(如條件分支、數據轉換、循環控制)可能硬編碼在鏈的代碼中,導致:- 鏈的邏輯難以復用或動態調整;
- 組件更換(如從 OpenAI 切換到 Anthropic)時,需修改鏈的控制邏輯;
- 復雜流程(如多輪工具調用、動態路由)的編排缺乏標準化表達。
二、LCEL 的核心意義:作為模塊間的 “邏輯中介”
LCEL 是 LangChain 設計的一套聲明式表達式語言,用于描述組件間的數據流動和邏輯控制。其核心價值體現在以下方面:
1. 分離邏輯控制與組件實現
-
傳統硬編碼問題:
例如,在鏈中通過 Python 代碼實現條件判斷:if result.score > 0.8: return llm.predict(prompt.format(data=result)) else: return tool.query(data=result)
此時,條件邏輯與鏈的代碼強耦合,難以復用或動態修改。 -
LCEL 的解耦作用:
將條件邏輯抽象為 LCEL 表達式,存儲在配置中:condition: "{{ score > 0.8 }}" then: action: llm.predict params: prompt: "用戶輸入:{{ input }}" else: action: tool.query params: data: "{{ input }}"- 鏈的代碼僅負責解析 LCEL 表達式,根據結果調用組件;
- 邏輯變更時只需修改表達式,無需調整鏈的代碼,實現 “邏輯外置”。
2. 標準化組件交互協議
LCEL 定義了一套統一的語法規則(如變量引用、運算符、函數調用),作為不同組件間的 “通信語言”:
數據傳遞:通過{{ variable }}引用上游組件的輸出(如 LLM 的返回結果、工具的查詢數據)。- 邏輯操作:支持算術運算(
+、-)、條件判斷(if-else)、集合操作(map、filter)等,避免不同組件自定義邏輯語法。 - 函數擴展:可注冊自定義函數(如
format_date()、calculate_score()),供表達式調用,實現跨組件的邏輯復用。
示例:
通過 LCEL 表達式編排多步流程:
from langchain.lcel import LCELChain
expression = """
let score = tool.calculate_score(input.data);
if (score > 0.6) {
return llm.generate(prompt: "高分結果:{{ score }}");
} else {
return tool.analyze(input.data);
}
"""
chain = LCELChain.from_expression(expression, components={
"tool": MyCustomTool(),
"llm": OpenAI(temperature=0.1)
})
- 組件(
tool、llm)僅需按約定輸出數據字段,無需關心流程邏輯; - 鏈通過 LCEL 表達式動態調度組件,解耦組件與流程控制。
3. 支持動態流程編排與熱更新
在 LangChain 中,復雜應用(如智能客服、數據分析助手)常需根據實時數據調整流程。LCEL 的聲明式特性使其適合動態場景:
- 場景 1:AB 測試
通過后端配置不同的 LCEL 表達式,控制 A/B 組用戶的流程分支(如優先調用工具 A 或工具 B),無需重啟服務。 - 場景 2:低代碼平臺
用戶通過可視化界面配置 LCEL 表達式(如拖拽生成{{ order.amount > 1000 ? "大客戶" : "普通客戶" }}),快速生成定制化鏈,降低開發門檻。 - 場景 3:實時策略調整
在金融風控場景中,通過動態修改 LCEL 表達式(如調整風險評分閾值score > 0.7→score > 0.75),實時更新風控流程,而無需修改代碼。
4. 提升組件復用性與可測試性
-
組件復用:
標準化的 LCEL 接口使組件可插拔。例如,替換 LLM 提供商時,只需修改組件實例(如從OpenAI改為Cohere),LCEL 表達式無需變更。 -
獨立測試:
可單獨測試 LCEL 表達式的邏輯正確性,如:from langchain.lcel import evaluate # 測試條件表達式 result = evaluate("{{ score > 0.8 ? 'pass' : 'fail' }}", context={"score": 0.9}) assert result == "pass"
無需啟動完整的鏈或依賴外部服務,提升測試效率。
5. 適配多模態與復雜工具調用
LangChain 常需集成多種工具(如 SQL 查詢、API 調用、文件解析),LCEL 可簡化多模態數據的處理邏輯:
-
示例:處理結構化數據
expression = """ let data = sql_tool.query("SELECT * FROM orders WHERE amount > {{ threshold }}"); let summary = llm.summarize(text: json.stringify(data.rows)); return summary; """- 通過 LCEL 鏈式調用 SQL 工具和 LLM,解耦數據查詢與摘要生成邏輯;
- 表達式清晰描述數據流動路徑,避免代碼層面的嵌套回調。
三、LCEL 與 LangChain 架構的協同
LCEL 的設計與 LangChain 的模塊化架構深度協同,目標是構建 **“表達式驅動的智能應用”**:
- 底層組件層:提供標準化接口(如
call()、parse()),供 LCEL 表達式調用; - LCEL 層:作為邏輯編排層,通過表達式描述組件交互規則;
- 應用層:通過配置文件、API 動態注入 LCEL 表達式,快速組裝不同功能的鏈。
這種分層設計使 LangChain 既能保持代碼的簡潔性,又能通過 LCEL 靈活應對復雜業務需求,尤其適合需要頻繁調整邏輯的生成式 AI 場景(如智能文檔處理、對話系統流程控制等)。

浙公網安備 33010602011771號