LangChain 框架深度解析:从 LCEL 到 Agent 架构的核心原理

LangChain 框架深度解析:从 LCEL 到 Agent 架构的核心原理

摘要

本文深入剖析 LangChain 框架的核心架构与实现原理,涵盖 LCEL(LangChain Expression Language)的声明式链式组合机制、Runnable 统一接口设计、Agent 工作流模式(ReAct、Tool Calling),以及 LangGraph 状态图编排系统。通过源码级分析揭示其设计思想,帮助开发者掌握构建生产级 AI 应用架构的关键技术。

引言

LangChain 自 2022 年发布以来,已成为构建 LLM 应用最广泛使用的开源框架之一。2025 年 LangChain 1.0 和 LangGraph 1.0 正式发布,标志着框架进入生产就绪阶段。

核心问题

  • LangChain 如何实现模块化组件的统一编排?
  • LCEL 的声明式语法背后隐藏着什么设计模式?
  • Agent 如何实现自主决策与工具调用的闭环?
  • LangChain 与 LangGraph 的定位有何不同?

文章结构:首先解析核心组件与 Runnable 接口,深入 LCEL 组合机制,然后剖析 Agent 架构与工作流模式,最后介绍 LangGraph 的状态编排系统。

核心组件架构

组件层次结构

LangChain 采用分层架构设计:

层次 组件 职责
编排层 LCEL / LangGraph 组合、流程控制
逻辑层 Agents 决策、工具调用
模型层 Models LLM 接口封装
数据层 Memory / Retrievers 状态持久化、数据检索
工具层 Tools 外部能力扩展

Runnable 统一接口

Runnable 是 LangChain 的基石接口,定义了组件执行的标准协议:

python 复制代码
class Runnable(Generic[Input, Output]):
    # 核心方法
    def invoke(self, input: Input, config: RunnableConfig) -> Output
    def batch(self, inputs: List[Input], config: RunnableConfig) -> List[Output]
    def stream(self, input: Input, config: RunnableConfig) -> Iterator[Output]
    
    # 异步方法
    async def ainvoke(self, input: Input, config: RunnableConfig) -> Output
    async def abatch(self, inputs: List[Input]) -> List[Output]
    async def astream(self, input: Input) -> AsyncIterator[Output]
    
    # 组合方法
    def pipe(self, other: Runnable) -> RunnableSequence
    def bind(self, **kwargs) -> Runnable
    def with_retry(self, retry_policy) -> Runnable
    def with_fallbacks(self, fallbacks: List[Runnable]) -> Runnable

设计思想

  1. 统一协议:所有组件(PromptTemplate、LLM、Retriever、Tool)都实现 Runnable,实现"可插拔"架构
  2. 多态执行:invoke(单次)、batch(批量)、stream(流式)三种执行模式
  3. 异步原生:所有方法都有 async 版本,支持高并发场景
  4. 组合优先:pipe 方法支持链式组合,bind 方法支持参数绑定

RunnableSequence 与 RunnableParallel

Runnable 的组合通过两个核心原语实现:

RunnableSequence(顺序执行)

python 复制代码
# 使用 | 运算符构建顺序链
sequence = RunnableLambda(lambda x: x + 1) | RunnableLambda(lambda x: x * 2)
sequence.invoke(1)  # 输出: 4
sequence.batch([1, 2, 3])  # 输出: [4, 6, 8]

RunnableParallel(并行执行)

python 复制代码
# 使用字典构建并行分支
sequence = RunnableLambda(lambda x: x + 1) | {
    "mul_2": RunnableLambda(lambda x: x * 2),
    "mul_5": RunnableLambda(lambda x: x * 5),
}
sequence.invoke(1)  # 输出: {'mul_2': 4, 'mul_5': 10}

关键要点

  • Runnable 接口实现了"一切皆可组合"的设计哲学
  • 组合后的 Chain 自动继承 invoke/batch/stream/async 能力
  • | 运算符语法糖使链式组合直观简洁

LCEL:声明式链式编排

LCEL 语法解析

LangChain Expression Language (LCEL) 是 Runnable 的声明式 DSL:

python 复制代码
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# 定义组件
prompt = PromptTemplate.from_template("Question: {question}

Answer: Let's think step by step.")
llm = ChatOpenAI(model="gpt-4", temperature=0)
parser = StrOutputParser()

# 使用 LCEL 组合
chain = prompt | llm | parser

# 执行
chain.invoke({"question": "How much is 2+2?"})

LCEL 内部实现机制

当执行 prompt | llm | parser 时,实际发生:

  1. 第一次 pipeprompt.pipe(llm) → 创建 RunnableSequence([prompt, llm])
  2. 第二次 pipesequence.pipe(parser) → 创建 RunnableSequence([prompt, llm, parser])
  3. invoke 执行:依次调用各组件,前一组件输出作为后一组件输入

流式执行优化

LCEL 的 stream 方法不是简单迭代,而是实现管道式流式传输

python 复制代码
# 流式输出:每个组件产生的中间结果立即传递给下游
for chunk in chain.stream({"question": "What is AI?"}):
    print(chunk, end="", flush=True)

内部实现使用 RunnableSequence.stream(),每个组件的 stream() 方法产生迭代器,上游迭代器元素直接传递给下游。

LCEL 高级组合模式

1. 参数绑定(bind)

python 复制代码
# 绑定固定参数
llm_with_stop = llm.bind(stop=["
"])
chain = prompt | llm_with_stop | parser

2. 条件分支(RunnableBranch)

python 复制代码
from langchain_core.runnables import RunnableBranch

branch = RunnableBranch(
    (lambda x: x["type"] == "math", math_chain),
    (lambda x: x["type"] == "text", text_chain),
    default_chain
)

3. 回退机制(with_fallbacks)

python 复制代码
robust_chain = (prompt | llm | parser).with_fallbacks([
    prompt | backup_llm | parser
])

4. 重试策略(with_retry)

python 复制代码
retry_chain = chain.with_retry(
    stop_after_attempt=3,
    wait_exponential_multiplier=1000
)

关键要点

  • LCEL 实现了声明式、可组合的链式编排
  • | 运算符语法糖背后是 RunnableSequence 组合
  • 组合后的 Chain 自动支持流式、批量、异步执行

Agent 架构深度解析

Agent 核心概念

Agent 是具有自主决策能力的系统,核心特征:

特征 描述
自主决策 LLM 决定执行哪些动作、顺序
工具调用 通过 Tool 接口调用外部能力
状态感知 记忆对话历史、中间结果
反闭环 观察工具返回结果,调整后续决策

Agent 工作流模式

1. ReAct 模式(Reasoning + Acting)

ReAct 是经典的 Agent 模式,遵循"思考-行动-观察"循环:

复制代码
Thought: 我需要查询天气信息
Action: search_weather("北京")
Observation: 北京今天晴,气温 25°C
Thought: 我已获得天气信息,可以回答用户
Answer: 北京今天天气晴朗,气温 25°C

ReAct Agent 实现

python 复制代码
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)

agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

agent.run("北京今天天气如何?计算25的平方")

2. Tool Calling 模式

现代 LLM(如 GPT-4、Claude)原生支持 Function Calling,Agent 可直接调用:

python 复制代码
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.tools import Tool

# 定义工具
def get_weather(city: str) -> str:
    return f"{city}今天晴,气温25°C"

tools = [
    Tool(name="get_weather", func=get_weather, 
         description="获取指定城市的天气信息")
]

# 创建 Agent
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)

agent_executor.invoke({"input": "北京天气如何?"})

Agent 执行循环

Agent 的核心是执行循环(Agent Loop):

复制代码
┌─────────────┐
│  用户输入   │
└──────┬──────┘
       ↓
┌─────────────┐
│  LLM 决策   │ ← 分析输入,决定是否调用工具
└──────┬──────┘
       ↓
   有工具调用?
    ├─ Yes ──→ ┌─────────────┐
    │          │  执行工具   │
    │          └──────┬──────┘
    │                 ↓
    │          ┌─────────────┐
    │          │  观察结果   │ → Tool Message
    │          └──────┬──────┘
    │                 ↓
    │          ┌─────────────┐
    │          │  继续决策   │ ← 将观察结果加入对话
    │          └──────┬──────┘
    │                 │
    └─────────────────┘
       
    └─ No ──→ ┌─────────────┐
             │  返回答案   │
             └──────┬──────┘
                    ↓
             ┌─────────────┐
             │  执行结束   │
             └─────────────┘

Tool 接口设计

Tool 是 Agent 与外部世界交互的标准接口:

python 复制代码
from langchain.tools import tool

@tool
def calculate(expression: str) -> float:
    """计算数学表达式。
    
    Args:
        expression: 数学表达式,如 '2+2' 或 'sqrt(16)'
    """
    return eval(expression)

# Tool 的核心属性
# - name: 工具名称
# - description: 工具描述(LLM 用于决策)
# - args_schema: 参数 Schema(JSON Schema 格式)

关键要点

  • Agent 通过 LLM 自主决定执行路径
  • ReAct 模式:显式的思考-行动-观察循环
  • Tool Calling 模式:利用 LLM 原生 Function Calling
  • 执行循环:LLM 决策 → 工具执行 → 观察反馈 → 继续决策

LangGraph:状态图编排系统

LangChain vs LangGraph 定位

特性 LangChain LangGraph
定位 高层抽象框架 低层编排引擎
组合方式 链式(LCEL) 图式(StateGraph)
控制流 线性为主 支持复杂循环、分支
状态管理 隐式(Memory) 显式(TypedDict State)
持久化 需额外配置 内置 Checkpointer
适用场景 快速原型、简单流程 生产级复杂 Agent

LangGraph 核心概念

LangGraph 将 Agent 工作流建模为状态图

python 复制代码
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict, Annotated
import operator

# 1. 定义状态
class AgentState(TypedDict):
    messages: Annotated[list, operator.add]  # 消息累加
    llm_calls: int  # LLM 调用次数

# 2. 定义节点(Node)
def llm_node(state: AgentState) -> dict:
    """LLM 决策节点"""
    response = llm.invoke(state["messages"])
    return {
        "messages": [response],
        "llm_calls": state.get("llm_calls", 0) + 1
    }

def tool_node(state: AgentState) -> dict:
    """工具执行节点"""
    results = []
    for tool_call in state["messages"][-1].tool_calls:
        result = tools[tool_call["name"]].invoke(tool_call["args"])
        results.append(ToolMessage(content=result, tool_call_id=tool_call["id"]))
    return {"messages": results}

# 3. 定义边(Edge)
def should_continue(state: AgentState) -> str:
    """条件边:决定下一节点"""
    if state["messages"][-1].tool_calls:
        return "tool_node"
    return END

# 4. 构建图
graph = StateGraph(AgentState)
graph.add_node("llm", llm_node)
graph.add_node("tool", tool_node)
graph.add_edge(START, "llm")
graph.add_conditional_edges("llm", should_continue, ["tool", END])
graph.add_edge("tool", "llm")  # 工具执行后返回 LLM

# 5. 编译并执行
agent = graph.compile()
result = agent.invoke({"messages": [HumanMessage("计算 25 的平方")]})

LangGraph 架构要素

1. State(状态)

python 复制代码
class State(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]
    # operator.add 表示新消息累加到列表

2. Node(节点)

  • 函数接收当前 State,返回 State 更新(dict)
  • 是 Agent 逻辑的封装单元

3. Edge(边)

  • 普通边 :固定流转路径 graph.add_edge("A", "B")
  • 条件边 :根据状态动态路由 graph.add_conditional_edges("A", router, ["B", "C", END])

LangGraph 执行模型

LangGraph 的执行模型:

复制代码
START → llm_node → [条件判断]
                        ├─ tool_calls 存在 → tool_node → llm_node (循环)
                        └─ 无 tool_calls → END

关键特性

  1. 循环支持tool_node → llm_node 形成闭环,实现 Agent 的多轮决策
  2. 状态持久化:Checkpointer 可保存执行状态,支持暂停恢复
  3. Human-in-the-Loop:可在任意节点插入人工干预

关键要点

  • LangGraph 使用显式 State + Node + Edge 模型
  • 条件边实现复杂路由逻辑
  • 循环边支持 Agent 的多轮决策闭环

Memory 与 Retrieval 系统

Memory 架构

LangChain Memory 系统管理对话上下文:

python 复制代码
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True
)

# Memory 自动管理对话历史
chain = ConversationChain(llm=llm, memory=memory)

Memory 类型对比

类型 特点 适用场景
ConversationBufferMemory 保存完整对话 短对话
ConversationBufferWindowMemory 保留最近 N 轮 控制长度
ConversationSummaryMemory LLM 摘要历史 长对话
VectorStoreMemory 向量检索相关历史 大规模历史

Retriever 接口

Retriever 是 Runnable 的特化实现,用于数据检索:

python 复制代码
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

vectorstore = FAISS.from_texts(documents, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# Retriever 本身是 Runnable
docs = retriever.invoke("query")  # 返回相关文档

LCEL 中集成 Retriever

python 复制代码
from langchain_core.runnables import RunnableParallel

# RAG Chain 示例
rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | parser
)

实战案例:构建完整 Agent

场景描述

构建一个具备计算、搜索、记忆能力的多功能 Agent。

解决方案

python 复制代码
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START, END

# 1. 定义工具
@tool
def calculator(expression: str) -> float:
    """计算数学表达式"""
    return eval(expression)

@tool
def search(query: str) -> str:
    """搜索信息"""
    # 实际实现调用搜索 API
    return f"搜索结果: {query}"

# 2. 配置 LLM
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
tools = [calculator, search]
llm_with_tools = llm.bind_tools(tools)

# 3. 使用 LangGraph 构建持久化 Agent
from langgraph.graph import MessagesState

def agent_node(state: MessagesState):
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}

def tool_node(state: MessagesState):
    results = []
    for tc in state["messages"][-1].tool_calls:
        tool = {t.name: t for t in tools}[tc["name"]]
        results.append(ToolMessage(content=str(tool.invoke(tc["args"])), tool_call_id=tc["id"]))
    return {"messages": results}

def should_continue(state):
    if state["messages"][-1].tool_calls:
        return "tools"
    return END

# 构建图
builder = StateGraph(MessagesState)
builder.add_node("agent", agent_node)
builder.add_node("tools", tool_node)
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue)
builder.add_edge("tools", "agent")

# 添加持久化
checkpointer = MemorySaver()
agent = builder.compile(checkpointer=checkpointer)

# 执行(带线程 ID)
result = agent.invoke(
    {"messages": [HumanMessage("计算 15 * 3,然后搜索 Python 教程")]},
    config={"configurable": {"thread_id": "session-1"}}
)

效果评估

  • 工具调用正确性:Agent 依次调用 calculator 和 search
  • 状态持久化:可通过 thread_id 恢复对话
  • 流式输出:支持实时输出中间结果

总结

核心要点回顾

  1. Runnable 接口:LangChain 的统一执行协议,实现 invoke/batch/stream/async 多态执行
  2. LCEL 语法:声明式链式组合,| 运算符语法糖,自动继承执行能力
  3. Agent 架构:自主决策 + 工具调用 + 反馈闭环,ReAct 与 Tool Calling 两种模式
  4. LangGraph:状态图编排系统,显式 State + Node + Edge,支持循环、持久化

最佳实践建议

  1. 简单链优先 LCEL:线性流程使用 | 运算符快速组合
  2. 复杂 Agent 用 LangGraph:多轮决策、循环、条件路由用 StateGraph
  3. 工具定义规范:提供清晰的 description 和 args_schema
  4. 流式优先:长输出场景使用 stream 方法提升用户体验
  5. 持久化配置:生产环境使用 LangGraph Checkpointer 或外部存储

扩展阅读

参考资料

相关推荐
七牛开发者25 分钟前
Is Grep All You Need?Agent 搜索里,Harness 比检索方法更重要
ai
花椒技术1 小时前
企业内部 Agent 落地复盘:Gateway、Skill 和二次确认如何串起受控业务执行
后端·agent·ai编程
冬奇Lab1 小时前
Agent系列(六):记忆管理——让 Agent 记住重要的事
人工智能·agent
AlfredZhao1 小时前
入门:我的第一个Vibe Coding实践程序
ai·codex·vibecoding
Agent手记2 小时前
制造业生产流程自动化,Agent需要具备哪些能力?深度拆解2026工业级智能体落地范式与核心架构
大数据·人工智能·ai·架构·自动化
七牛云行业应用2 小时前
OpenHuman、OpenClaw、Hermes Agent 傻傻分不清楚?一篇说清三者定位
ai·agent·hermes agent
Yunzenn3 小时前
深度分析字节最新研究cola-DLM 第 07 章:推理流水线逐行拆解 —— 从 prompt 到生成文本
人工智能·驱动开发·深度学习·chatgpt·架构·prompt·github
codefan※3 小时前
day05-llm-sampling-params
人工智能·大模型·llm·prompt工程·top-p·temperature·ai应用开发
是Yu欸3 小时前
从 Prompt 到 WebUI:基于 SenseNova U1 封装一个图文技术博客生成工具
大模型·llm·prompt·webui·moe·sensenova u1·商汤科技
颖火虫盟主4 小时前
Linux 系统分层架构:从硬件通电到 systemd 进程管理
linux·运维·架构