Files
zhuangang/topics/ai/langchain/01-lcel-structured-agent.md
T

5.1 KiB
Raw Blame History

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
id title type domain stack tags level prerequisites est_hours related week order
ai.langchain.lcel-structured-agent LangChain 1.x:模型和消息、LCEL、结构化输出、create_agent 和中间件 lesson ai
langchain
LangChain
LCEL
init_chat_model
结构化输出
create_agent
middleware
重试
备用模型
intermediate
ai.function-calling.tool-loop
3
ai.langgraph.state-graph
ai.langchain.scenario.ticket-triage
ai.langchain.interview
6
11
1

LangChain 1.x:模型和消息、LCEL、结构化输出、create_agent 和中间件

LangChain 在 2025 年发布 1.0,API 和 0.x 有较大变化(例如 Agent 统一为 create_agent,基于 LangGraph 构建,并引入中间件)。网上大量教程是 0.x 写法(AgentExecutor、initialize_agent、LLMChain),不要照抄。本课基于 langchain 1.4 编写,以官方文档为准:https://docs.langchain.com/oss/python/langchain/overview

解释说明

核心组件

组件 说明
聊天模型 统一接口调用不同提供方:init_chat_model("提供方:模型名");方法 invoke / stream / batch 及异步版本
消息 SystemMessage、HumanMessage、AIMessage(可带 tool_calls)、ToolMessage
提示词模板 ChatPromptTemplate.from_messages([...]),用 {变量} 占位
输出解析器 StrOutputParser、PydanticOutputParser;支持原生结构化输出的模型优先用 model.with_structured_output(Schema)
工具 @tool 装饰的函数,文档字符串就是工具描述
Agent create_agent(model, tools, system_prompt=..., middleware=[...], response_format=...)

LCEL(LangChain 表达式语言)

用 | 把组件串成链:prompt | model | parser。每个组件都是 Runnable,统一支持 invoke / stream / batch / 异步,并且可以加:

  • .with_retry(stop_after_attempt=3):失败重试;
  • .with_fallbacks([备用链]):失败时切换到备用(例如另一个模型提供方);
  • RunnableParallel:并行执行多个分支。

create_agent 和中间件

create_agent 实现了标准的工具调用循环(就是第 10 周手写的那个循环),返回一个 LangGraph 图,所以也支持检查点、流式、interrupt。1.x 的中间件可以在模型调用 / 工具调用前后插入逻辑,内置的有:调用次数限制、人工审批(HumanInTheLoop)、历史摘要(Summarization)、备用模型(ModelFallback)、PII 检测、工具重试等(名称和参数以官方文档为准)。

什么时候用 LangChain,什么时候直接用 SDK? 需要切换多个模型提供方、需要现成的检索 / 工具 / 中间件生态时用 LangChain;逻辑简单、追求最少依赖和完全可控时直接用厂商 SDK。面试时要能说出理由。

案例

工单分类服务:用 PydanticOutputParser(或 with_structured_output)输出 {category, urgent};模型偶尔返回不合法格式,with_retry 重试一次;主模型提供方超时时 with_fallbacks 切换到备用提供方;批量历史工单用 batch 并发处理。

代码示例

完整可运行版本(假模型离线运行):examples/lc-basics/lc_basics.py。

from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool


class Triage(BaseModel):
    category: str = Field(pattern="^(refund|bug|question)$")
    urgent: bool


parser = PydanticOutputParser(pydantic_object=Triage)
prompt = ChatPromptTemplate.from_messages([
    ("system", "对工单分类。{format_instructions}"),
    ("human", "{ticket}"),
]).partial(format_instructions=parser.get_format_instructions())

chain = (prompt | model | parser).with_retry(stop_after_attempt=2).with_fallbacks([prompt | backup_model | parser])
print(chain.invoke({"ticket": "我要退款,很急"}))        # category='refund' urgent=True


@tool
def get_order_status(order_id: str) -> str:
    """查询订单的物流状态。order_id 形如 A1001。"""
    ...


agent = create_agent(model, tools=[get_order_status], system_prompt="你是售后客服。",
                     middleware=[ModelCallLimitMiddleware(run_limit=5)])
out = agent.invoke({"messages": [{"role": "user", "content": "A1001 到哪了"}]})

易错点

  • 照抄 0.x 教程:AgentExecutor、LLMChain 等在 1.x 中已移到 langchain-classic 或不再推荐。
  • 各模型提供方是独立的包(langchain-openai、langchain-anthropic 等),版本要和 langchain-core 匹配。
  • 结构化输出只靠提示词约束,不做校验。
  • with_fallbacks 的备用链输入输出格式和主链不一致。
  • 工具的文档字符串写得太简单,模型不知道何时调用。
  • 过度封装:简单的一次调用也套很多层链,调试困难。

面试常问

  • LangChain 1.x 和 0.x 有什么变化?
  • LCEL 是什么?有什么好处?
  • 怎么保证结构化输出可靠?
  • 什么时候不用 LangChain?