LCEL 表达式语言 LangChain 的核心语法:一切皆 Runnable,管道 | 连一切。
核心概念:Runnable 所有 LangChain 组件(Model、Prompt、Parser、Tool)都实现了 Runnable 接口 :
1 2 3 4 5 class Runnable (Protocol ): def invoke (input , config=None ) → Any def ainvoke (input , config=None ) → Any def batch (inputs, config=None ) → List [Any ] def stream (input , config=None ) → Iterator
这意味着 :任何 Runnable 都可以用 | 管道符组合。
管道组合语法 1 2 3 chain = prompt | model | output_parser result = chain.invoke({"question" : "什么是热力学" })
对比:不使用 LCEL 1 2 3 4 prompt = prompt_template.format (question="什么是热力学" ) response = llm.invoke(prompt) output = output_parser.invoke(response)
使用 LCEL 1 2 3 chain = prompt_template | llm | output_parser output = chain.invoke({"question" : "什么是热力学" })
LCEL 支持的功能 1. 并行执行 1 2 3 4 5 6 7 8 9 10 11 from langchain_core.runnables import RunnableParallelretriever = RunnableParallel({ "web" : web_retriever, "docs" : doc_retriever }) results = retriever.invoke({"query" : "LangChain 是什么" })
2. 备用链(Fallback) 1 2 chain = prompt | llm.with_fallbacks([fallback_llm]) | parser
3. 动态配置 1 2 3 4 5 6 7 from langchain_core.runnables import RunnableConfigconfig = RunnableConfig( configurable={"temperature" : 0.9 } ) result = chain.invoke({"query" : "..." }, config=config)
4. 批量处理 1 2 3 4 5 6 results = chain.batch([ {"query" : "什么是热力学" }, {"query" : "什么是量子力学" }, {"query" : "什么是相对论" } ])
5. 流式输出 1 2 3 for chunk in chain.stream({"query" : "写一首诗" }): print (chunk, end="" , flush=True )
6. 异步支持 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import asynciofrom langchain_core.runnables import RunnableLambdaasync def async_chain (query: str ): chain = prompt | llm | parser result = await chain.ainvoke({"query" : query}) return result results = await asyncio.gather( async_chain("问题1" ), async_chain("问题2" ), async_chain("问题3" ) )
RunnableLambda(自定义逻辑) 将普通 Python 函数转换为 Runnable:
1 2 3 4 5 6 7 8 9 10 11 12 13 from langchain_core.runnables import RunnableLambdadef extract_keywords (text: str ) -> dict : """自定义处理逻辑""" keywords = text.lower().split()[:5 ] return {"keywords" : keywords, "original" : text} chain = ( prompt_template | llm | RunnableLambda(extract_keywords) | StrOutputParser() )
RunnableBranch(条件分支) 1 2 3 4 5 6 7 8 9 10 11 12 13 from langchain_core.runnables import RunnableBranchbranch = RunnableBranch( (lambda x: "search" in x["intent" ], search_chain), (lambda x: "calculate" in x["intent" ], calc_chain), chat_chain ) result = branch.invoke({"intent" : "search" , "query" : "今天天气" })
LCEL 的优势 特性 说明 Zero-change 投产 原型代码 = 生产代码,无需改写 流式支持 天然支持 stream,从头到尾都是流 异步支持 异步从头到尾,性能更好 批量处理 batch 自动并行 调试友好 每一步都是独立 Runnable,可单独测试
实战:RAG 流水线 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from langchain_openai import ChatOpenAIfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.runnables import RunnableParallelretriever = vectorstore.as_retriever(search_kwargs={"k" : 3 }) system_prompt = """你是一个AI助手。基于以下上下文回答问题。 如果上下文中没有相关信息,说"我不知道"。 上下文: {context} """ prompt = ChatPromptTemplate.from_messages([ ("system" , system_prompt), ("human" , "{question}" ) ]) llm = ChatOpenAI(model="gpt-4o" , temperature=0 ) rag_chain = ( RunnableParallel({ "context" : lambda x: retriever.invoke(x["question" ]), "question" : lambda x: x["question" ] }) | prompt | llm | StrOutputParser() ) result = rag_chain.invoke({"question" : "LangChain 是什么" })