LangChain 资深开发者完全指南

版本参考:LangChain v1.x(2026年4月,langchain-core 1.3.0 / langchain 1.1+) 适用读者:有 Python 经验、希望构建生产级 LLM 应用、理解 DAG 与协议型组合的资深工程师 当前 github 地址:github.com/langchain-a...


目录

  1. [框架定位与 v1.0 的范式转变](#框架定位与 v1.0 的范式转变 "#1-%E6%A1%86%E6%9E%B6%E5%AE%9A%E4%BD%8D%E4%B8%8E-v10-%E7%9A%84%E8%8C%83%E5%BC%8F%E8%BD%AC%E5%8F%98")
  2. [Monorepo 结构与包拆分](#Monorepo 结构与包拆分 "#2-monorepo-%E7%BB%93%E6%9E%84%E4%B8%8E%E5%8C%85%E6%8B%86%E5%88%86")
  3. [LCEL 与 Runnable 协议](#LCEL 与 Runnable 协议 "#3-lcel-%E4%B8%8E-runnable-%E5%8D%8F%E8%AE%AE")
  4. [组合原语:Sequence / Parallel / Branch / Lambda / Passthrough](#组合原语:Sequence / Parallel / Branch / Lambda / Passthrough "#4-%E7%BB%84%E5%90%88%E5%8E%9F%E8%AF%AD")
  5. [RunnableConfig、回调传播与 contextvars](#RunnableConfig、回调传播与 contextvars "#5-runnableconfig%E5%9B%9E%E8%B0%83%E4%BC%A0%E6%92%AD%E4%B8%8E-contextvars")
  6. [语言模型层次:BaseChatModel / BaseLLM / init_chat_model](#语言模型层次:BaseChatModel / BaseLLM / init_chat_model "#6-%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%E5%B1%82%E6%AC%A1")
  7. [消息类型与标准化 Content Blocks](#消息类型与标准化 Content Blocks "#7-%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%E4%B8%8E%E6%A0%87%E5%87%86%E5%8C%96-content-blocks")
  8. [Prompt 模板体系](#Prompt 模板体系 "#8-prompt-%E6%A8%A1%E6%9D%BF%E4%BD%93%E7%B3%BB")
  9. 工具定义:@tool、StructuredTool、BaseTool
  10. [工具调用与结构化输出:bind_tools / with_structured_output](#工具调用与结构化输出:bind_tools / with_structured_output "#10-%E5%B7%A5%E5%85%B7%E8%B0%83%E7%94%A8%E4%B8%8E%E7%BB%93%E6%9E%84%E5%8C%96%E8%BE%93%E5%87%BA")
  11. [create_agent:v1.0 唯一的 Agent 抽象](#create_agent:v1.0 唯一的 Agent 抽象 "#11-create_agentv10-%E5%94%AF%E4%B8%80%E7%9A%84-agent-%E6%8A%BD%E8%B1%A1")
  12. [Middleware 子系统(v1.0 旗舰特性)](#Middleware 子系统(v1.0 旗舰特性) "#12-middleware-%E5%AD%90%E7%B3%BB%E7%BB%9F")
  13. [结构化输出策略:Auto / Provider / Tool](#结构化输出策略:Auto / Provider / Tool "#13-%E7%BB%93%E6%9E%84%E5%8C%96%E8%BE%93%E5%87%BA%E7%AD%96%E7%95%A5")
  14. [检索与 RAG 体系](#检索与 RAG 体系 "#14-%E6%A3%80%E7%B4%A2%E4%B8%8E-rag-%E4%BD%93%E7%B3%BB")
  15. [Memory:从旧内存类到 LangGraph Checkpointer](#Memory:从旧内存类到 LangGraph Checkpointer "#15-memory%E4%BB%8E%E6%97%A7%E5%86%85%E5%AD%98%E7%B1%BB%E5%88%B0-langgraph-checkpointer")
  16. [Callbacks 与 LangSmith 追踪](#Callbacks 与 LangSmith 追踪 "#16-callbacks-%E4%B8%8E-langsmith-%E8%BF%BD%E8%B8%AA")
  17. 输出解析器
  18. [Partner 包生态](#Partner 包生态 "#18-partner-%E5%8C%85%E7%94%9F%E6%80%81")
  19. [v0.x → v1.0 迁移要点](#v0.x → v1.0 迁移要点 "#19-v0x--v10-%E8%BF%81%E7%A7%BB%E8%A6%81%E7%82%B9")
  20. [LangChain 与 LangGraph 的关系与选型](#LangChain 与 LangGraph 的关系与选型 "#20-langchain-%E4%B8%8E-langgraph-%E7%9A%84%E5%85%B3%E7%B3%BB%E4%B8%8E%E9%80%89%E5%9E%8B")
  21. 生产最佳实践
  22. [API 快速参考](#API 快速参考 "#22-api-%E5%BF%AB%E9%80%9F%E5%8F%82%E8%80%83")

1. 框架定位与 v1.0 的范式转变

1.1 LangChain 是什么

LangChain 是一套面向 LLM 应用的可组合抽象层,其设计目标是:

提供统一的 模型 / 提示 / 工具 / 检索 / 消息 / 回调 协议,让开发者以声明式方式拼装 LLM 管道,而无需被具体提供商 SDK 锁定。

在 v1.0(2025年10月22日 GA)之后,它的定位更加明确:

  • langchain-core:所有抽象协议的定义(Runnable、BaseChatModel、BaseTool、BaseMessage、Callbacks)
  • langchain :面向用户的主包,核心是 create_agentinit_chat_model、标准化 content blocks
  • langchain-classic:旧版链、旧版 Agent、旧版 memory、旧版检索器的归档
  • partner packages:OpenAI / Anthropic / Google 等供应商实现
  • LangGraph :真正的执行运行时(v1.0 的 create_agent 底层就是 LangGraph)

1.2 v1.0 的核心范式转变

维度 v0.x v1.0
Agent 抽象 AgentExecutor + 多种 create_*_agent 工厂 统一 create_agent,底层编译为 LangGraph
自定义状态 支持 dataclass / Pydantic / TypedDict 仅允许 TypedDict 继承 AgentState
Hooks 系统 散落的 pre_model_hookpost_model_hook 统一的 Middleware 子系统
消息内容 各家 provider 原生格式不一致 标准化 content_blocks 属性
结构化输出 Prompted JSON + 各种 response_format AutoStrategy / ProviderStrategy / ToolStrategy
Memory 18 个 *Memory 委托给 LangGraph Checkpointer + Store
langchain-community 包含 200+ 集成 大多迁出到独立 repo,留骨架

1.3 LangChain、LangGraph、LangSmith 三件套

vbnet 复制代码
LangSmith      --- 观测与评估平台(SaaS,独立)
  ↑ traces
LangChain      --- 高层组合层、Agent、Middleware、检索
  ↓ compiles to
LangGraph      --- 低层有状态执行运行时(StateGraph)
  ↓ built on
langchain-core --- Runnable / BaseMessage / BaseTool / Callbacks 协议

v1.0 之后,这三层边界前所未有地清晰:核心协议 → 执行引擎 → 应用封装


2. Monorepo 结构与包拆分

2.1 目录布局

截至 2026 年 4 月,libs/ 目录结构:

bash 复制代码
langchain-ai/langchain/
├── libs/
│   ├── core/                    # langchain-core (v1.3.0),所有协议
│   ├── langchain_v1/            # langchain (v1.x),主用户包
│   ├── langchain/               # langchain-classic,旧链/旧 Agent/旧 memory
│   ├── partners/                # OpenAI / Anthropic / Ollama 等
│   ├── text-splitters/          # langchain-text-splitters
│   ├── standard-tests/          # 接口一致性测试套件
│   ├── model-profiles/          # 模型能力元数据
│   └── cli/                     # langchain CLI
├── docs/                        # 文档源码
└── cookbook/                    # 示例 notebook

2.2 包职责与依赖

vbnet 复制代码
langchain
    ├── depends on → langchain-core
    └── depends on → langgraph (create_agent 运行时)

langchain-classic
    └── depends on → langchain-core
                   → langchain (部分旧 API 从新包重导出)

langchain-openai / langchain-anthropic / ...
    └── peer dependency → langchain-core

langchain-text-splitters
    └── depends on → langchain-core (仅 Document 类型)

2.3 版本策略

  • 独立版本号langchain-corelangchain 独立发布,4 月中旬时 core 在 1.2.30 → 1.3.0 这条小步快跑的线上。
  • "2.0 前无破坏"承诺:v1.0 GA 之后公开承诺在 2.0 前不再做破坏性变更,只做增量扩展。
  • Partner 包独立节奏:每个 partner 包有自己的 test matrix 与 release 节奏,新模型 ID 直接透传到 provider SDK,无需等 LangChain 发版。
  • standard-tests :强制所有 partner 实现共享的一致性测试(BaseChatModel / Embeddings / VectorStore 都跑同一套用例),是"协议型"架构的质量基石。

2.4 langchain-community 的退场

v0.x 时代 langchain-community 是一个巨大的胶水包,装了 200+ 第三方集成。在 v1.0 时代:

  • 主流集成(Google、AWS、Pinecone、MongoDB 等)各自拆出独立 repo、独立 PyPI 包;
  • langchain-community 保留了小众/低频的集成,以及一些过渡期尚未拆出的模块;
  • 新集成不再向 langchain-community 提交,而是按 partner package 模板新建 repo。

3. LCEL 与 Runnable 协议

3.1 为什么要有 LCEL

LCEL(LangChain Expression Language)是一套管道式组合 DSL。核心动机:

  • 同一套代码覆盖 sync/async/streaming/batchinvoke / ainvoke / stream / astream / batch / abatch 由协议保证。
  • 天然并行RunnableParallelbatch 自动利用线程池 / asyncio.gather。
  • 天然可观测:每一层 Runnable 都通过 CallbackManager 上报 run,LangSmith 自动串联。
  • 运行时可配置with_configwith_retrywith_fallbackswith_listenersconfigurable_fields 全部免费。

3.2 Runnable 协议

所有 LCEL 组件都实现 langchain_core.runnables.base.Runnable[Input, Output]

python 复制代码
class Runnable(Generic[Input, Output], ABC):
    # 同步 API
    def invoke(self, input: Input, config: RunnableConfig | None = None, **kwargs) -> Output: ...
    def stream(self, input: Input, config=None, **kwargs) -> Iterator[Output]: ...
    def batch(self, inputs: list[Input], config=None, *, return_exceptions=False,
              max_concurrency: int | None = None) -> list[Output]: ...
    def batch_as_completed(self, inputs, ...) -> Iterator[tuple[int, Output | Exception]]: ...

    # 异步 API
    async def ainvoke(self, input, config=None, **kwargs) -> Output: ...
    async def astream(self, input, config=None, **kwargs) -> AsyncIterator[Output]: ...
    async def abatch(self, inputs, config=None, *, return_exceptions=False, **kwargs) -> list[Output]: ...
    async def abatch_as_completed(self, inputs, ...) -> AsyncIterator[tuple[int, Output | Exception]]: ...

    # 高保真事件流
    async def astream_events(self, input, config=None, *,
                             version: Literal["v1","v2"]="v2", ...) -> AsyncIterator[StreamEvent]: ...

    # 组合辅助
    def __or__(self, other) -> RunnableSequence: ...
    def __ror__(self, other) -> RunnableSequence: ...
    def with_config(self, config: RunnableConfig) -> Runnable: ...
    def with_retry(self, *, stop_after_attempt=3, wait_exponential_jitter=True, ...) -> Runnable: ...
    def with_fallbacks(self, fallbacks: list[Runnable], *, exceptions_to_handle=(Exception,)) -> Runnable: ...
    def with_types(self, *, input_type=None, output_type=None) -> Runnable: ...
    def with_listeners(self, *, on_start=None, on_end=None, on_error=None) -> Runnable: ...
    def bind(self, **kwargs) -> RunnableBinding: ...
    def assign(self, **mappers: Runnable | Callable) -> Runnable: ...

    # 自省
    def get_graph(self, config=None) -> Graph: ...
    def get_input_schema(self, config=None) -> type[BaseModel]: ...
    def get_output_schema(self, config=None) -> type[BaseModel]: ...
    def config_schema(self, *, include=None) -> type[BaseModel]: ...

3.3 管道操作符 | 的秘密

python 复制代码
chain = prompt | model | parser

|Runnable.__or__ / __ror__ 重载。等价于:

python 复制代码
chain = RunnableSequence(first=prompt, middle=[model], last=parser)

非 Runnable 的 Python 值(如 dict、callable)会被自动包装:

  • dictRunnableParallel
  • callableRunnableLambda

所以 {"ctx": retriever, "q": RunnablePassthrough()} | prompt | model 是合法的。

3.4 batch 与 abatch 的实现细节

  • batch 默认在线程池里跑 invokemax_concurrency 控制并发。
  • abatchasyncio.gather 展开。
  • BaseLLM.batch 特化过:max_concurrency=None 时走 provider 原生批量接口(generate_prompt(prompts=[...]))。因此推理 API 费率敏感时应避免显式传 max_concurrency

3.5 astream_events v2 事件分类

每个事件结构为:

python 复制代码
StreamEvent = TypedDict("StreamEvent", {
    "event": str,                         # "on_chat_model_start" 等
    "name": str,                          # Runnable 名称
    "run_id": str,
    "parent_ids": list[str],              # v2 才有:从 root 到 immediate parent
    "tags": list[str],
    "metadata": dict,
    "data": dict,                         # 具体 payload
})

事件名形如 on_<type>_<start|stream|end><type> 取值:chat_model | llm | chain | tool | retriever | prompt | parser。外加 on_custom_event(v2 专有)用于用户自定义事件。

3.6 LCEL 的经典套路

python 复制代码
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "Answer using the context only."),
    ("human", "Context:\n{ctx}\n\nQuestion: {question}"),
])

rag_chain = (
    RunnableParallel(
        ctx=retriever,
        question=RunnablePassthrough(),
    )
    | prompt
    | model
    | StrOutputParser()
)

answer = rag_chain.invoke("What is LCEL?")

关键理解:每一根 | 都是 Runnable,每一层都可以 stream / batch / trace / retry


4. 组合原语

4.1 核心组合类

用途 典型写法
RunnableSequence 顺序管道 由 `a
RunnableParallel 并发扇出到 N 个 runnable {"a": a, "b": b}RunnableParallel(a=a, b=b)
RunnableLambda 把普通函数变 Runnable RunnableLambda(lambda x: x.upper())
RunnablePassthrough 原样透传 RunnablePassthrough()
RunnablePassthrough.assign 在 dict 上追加计算字段 RunnablePassthrough.assign(length=lambda d: len(d["text"]))
RunnableBranch if/elif/else 分支 RunnableBranch((cond1, branch1), (cond2, branch2), default)
RunnableEach 对列表元素逐个应用 sub_chain.map()
RunnableConfigurableAlternatives 运行时切换实现 model.configurable_alternatives(...)
RunnableConfigurableFields 运行时改参数 model.configurable_fields(temperature=ConfigurableField(id="temp"))

4.2 RunnablePassthrough.assign 的价值

RAG 场景下特别好用:

python 复制代码
chain = (
    RunnablePassthrough.assign(
        ctx=lambda x: retriever.invoke(x["question"])
    )
    | prompt
    | model
)
chain.invoke({"question": "..."})
# ctx 自动算出来,并与 question 合并进下游

它等价于 RunnableAssign(mapper=RunnableParallel(ctx=...)),但代码更短。

4.3 RunnableBranch 的条件分发

python 复制代码
from langchain_core.runnables import RunnableBranch

router = RunnableBranch(
    (lambda x: "code" in x["intent"], code_chain),
    (lambda x: "sql"  in x["intent"], sql_chain),
    fallback_chain,  # 末尾是默认分支
)

每个 predicate 必须同步返回 bool,不能是 Runnable。需要用 LLM 做路由时,先在上游跑一条 chain 产出 intent

4.4 .bind():冻结参数

python 复制代码
strict_json_model = model.bind(response_format={"type": "json_object"})
web_model         = model.bind(tools=[web_search_tool], tool_choice="any")

返回 RunnableBinding,是一个轻量代理:所有调用自动附加绑定的 kwargs。


5. RunnableConfig、回调传播与 contextvars

5.1 RunnableConfig 结构

python 复制代码
class RunnableConfig(TypedDict, total=False):
    tags: list[str]                      # LangSmith 过滤器列列
    metadata: dict[str, Any]             # LangSmith 自定义列
    callbacks: Callbacks                 # 回调处理器列表
    run_name: str                        # 在 trace 里显示的名字
    run_id: UUID                         # 强制指定 run_id
    max_concurrency: int | None          # batch 并发
    recursion_limit: int                 # LangGraph 递归深度
    configurable: dict[str, Any]         # configurable_* 运行时覆盖

任何 Runnable 方法都可以接收 config 作为第二个位置参数:

python 复制代码
chain.invoke(
    {"question": "..."},
    config={"tags": ["prod"], "metadata": {"user_id": "u-42"}, "callbacks": [MyHandler()]},
)

5.2 回调在子 Runnable 中的传播

_call_with_configRunnable 内部的 wrapper,它会:

  1. 基于当前 config 构造一个子 CallbackManager
  2. 触发 on_chain_start
  3. parent_run_id 写入子 Runnable 的 config;
  4. 执行实际逻辑;
  5. 触发 on_chain_end / on_chain_error

于是 prompt | model | parser 整条链上,每一步的 trace 都自动挂到前一步下面。

5.3 Python 3.9/3.10 的 async 陷阱

Python 3.11 开始,contextvarsasyncio.Task 间自动拷贝,RunnableConfig 会自动传播。3.9/3.10 必须手动把 config 传进每层 await

python 复制代码
# 3.9 / 3.10:必须手动 thread config
async def my_node(state, config):
    msg = await model.ainvoke(state["messages"], config)   # ← 一定要显式传
    return {"messages": [msg]}

astream_events 在老版本 Python 上经常因为丢 config 导致 "miss events"。3.11+ 是安全的。

5.4 with_config:永久附加配置

python 复制代码
prod_chain = chain.with_config({"tags": ["prod"], "metadata": {"env": "prod"}})

返回新 Runnable,之后每次 invoke 都带这套 config,不影响原链。


6. 语言模型层次

6.1 继承关系

ini 复制代码
Runnable
  └── RunnableSerializable
       └── BaseLanguageModel[Output]
            ├── BaseChatModel           (Output = AIMessage)
            └── BaseLLM                 (Output = str)
                 └── LLM                (单 prompt 的 BaseLLM 简化)

6.2 BaseChatModel 核心钩子

子类必须实现 _generate,可选 _stream / _agenerate / _astream

python 复制代码
class BaseChatModel(BaseLanguageModel[AIMessage]):
    def _generate(self, messages: list[BaseMessage], stop=None,
                  run_manager: CallbackManagerForLLMRun | None = None, **kwargs) -> ChatResult: ...
    def _stream(self, messages, stop=None, run_manager=None, **kwargs) -> Iterator[ChatGenerationChunk]: ...
    async def _agenerate(...) -> ChatResult: ...
    async def _astream(...) -> AsyncIterator[ChatGenerationChunk]: ...

    # 元数据
    @property
    def _llm_type(self) -> str: ...           # 用于 trace
    @property
    def _identifying_params(self) -> dict: ...

    # 流控
    disable_streaming: Union[bool, Literal["tool_calling"]] = False
    output_version: Optional[str] = None       # v0 / v1 / provider-specific

    # LangSmith
    def _get_ls_params(self, stop=None, **kwargs) -> LangSmithParams: ...

output_version 控制 AIMessage.content 的 shape:v1 会写标准化 content blocks,v0 保留 provider 原生格式。

6.3 init_chat_model:统一工厂

核心 API,位于 langchain.chat_models.init_chat_model

python 复制代码
from langchain.chat_models import init_chat_model

# 简写:自动推断 provider
model = init_chat_model("gpt-5.2")
model = init_chat_model("claude-sonnet-4-6")

# 显式前缀
model = init_chat_model("openai:gpt-4")
model = init_chat_model("anthropic:claude-haiku-4-5-20251001")

# 运行时可切模型
model = init_chat_model(
    model="gpt-5.2",
    configurable_fields=("model", "temperature"),
    config_prefix="llm",
)

# 任意字段可改
model = init_chat_model(configurable_fields="any")

# 用法
model.invoke([HumanMessage("Hi")],
             config={"configurable": {"llm_model": "claude-sonnet-4-6",
                                      "llm_temperature": 0.2}})

configurable_fields="any" 特别强大,也特别危险------永远不要把未经校验的用户输入直接塞进 configurable dict,否则用户可以切换到贵模型或覆盖 system prompt。

6.4 返回类型:_ConfigurableModel

configurable_fields 非空时,init_chat_model 返回一个 _ConfigurableModel,它把实际模型构造推迟到第一次调用时,并按 config["configurable"] 动态 resolve。


7. 消息类型与标准化 Content Blocks

7.1 基础消息类

langchain_core.messages

角色 常见字段
SystemMessage system content
HumanMessage user content(可为 str 或多模态 list)
AIMessage assistant content, tool_calls, additional_kwargs, usage_metadata, response_metadata
ToolMessage tool content, tool_call_id, artifact
FunctionMessage function(legacy) 同上
ChatMessage 自定义 role content, role

每种消息都有对应的 Chunk:AIMessageChunkHumanMessageChunk 等。Chunk 可以用 + 累加

python 复制代码
acc = AIMessageChunk(content="")
async for chunk in model.astream(messages):
    acc = acc + chunk
# acc 就是完整的 AIMessage,tool_call_chunks 也会被正确合并

7.2 AIMessage.tool_calls

v1 时代 tool_calls 字段是一等公民:

python 复制代码
class ToolCall(TypedDict):
    name: str
    args: dict[str, Any]
    id: str
    type: Literal["tool_call"]

流式场景下用 tool_call_chunks

python 复制代码
class ToolCallChunk(TypedDict):
    name: str | None
    args: str | None        # partial JSON string
    id: str | None
    index: int | None

累加时 LangChain 会自动将 partial JSON 拼接并在可解析时 promote 到 tool_calls

7.3 标准化 Content Blocks(v1 旗舰特性)

为了解决各 provider 返回结构迥异的问题(Anthropic 返回 text + thinking + tool_use 的 block list,OpenAI 返回 string + 外挂 tool_calls,Gemini 又不一样),v1 新增懒属性 content_blocks

python 复制代码
from langchain_core.messages import AIMessage

msg: AIMessage = model.invoke(...)

for block in msg.content_blocks:
    match block["type"]:
        case "text":        print(block["text"])
        case "reasoning":   print("[thinking]", block["reasoning"])
        case "citation":    print("[cite]", block["url"])
        case "tool_call":   print("→", block["name"], block["args"])
        case "image":       handle_image(block["source"])
        case "audio":       ...

所有受支持的 provider 适配器都实现了 native → 标准 block 的转换器。msg.content 仍然保留原生结构,你可以按需选择哪一层。

7.4 v1 消息 API 收紧

  • AIMessage.example 字段已移除,改用 additional_kwargs["example"]
  • .text() 由方法改为属性msg.text 能拿到纯文本拼接。方法形式在 v1 还能用但会 warn,v2 将移除。
  • 老代码 if m.text(): 要改成 if m.text:

8. Prompt 模板体系

8.1 类层次

bash 复制代码
BasePromptTemplate
├── StringPromptTemplate
│   ├── PromptTemplate              # 传统字符串模板
│   └── FewShotPromptTemplate
└── BaseChatPromptTemplate
    ├── ChatPromptTemplate          # 主要使用的
    └── FewShotChatMessagePromptTemplate

8.2 ChatPromptTemplate

python 复制代码
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are {persona}."),
    MessagesPlaceholder("history", optional=True),
    ("human", "{question}"),
])

messages = prompt.invoke({
    "persona": "a senior Python engineer",
    "history": [HumanMessage("hi"), AIMessage("hello")],
    "question": "Explain asyncio.",
}).to_messages()
  • 元组简写:("system", ...), ("human", ...), ("ai", ...), ("placeholder", "{var}")
  • 占位符支持 optional=True,允许变量缺失不报错。
  • template_format 可选 "f-string"(默认)或 "jinja2"

8.3 Few-shot 模板

python 复制代码
from langchain_core.prompts import FewShotChatMessagePromptTemplate

example_prompt = ChatPromptTemplate.from_messages([
    ("human", "{input}"), ("ai", "{output}"),
])

few_shot = FewShotChatMessagePromptTemplate(
    example_prompt=example_prompt,
    examples=[
        {"input": "2+2", "output": "4"},
        {"input": "3+3", "output": "6"},
    ],
)

final = ChatPromptTemplate.from_messages([
    ("system", "Do math."),
    few_shot,
    ("human", "{question}"),
])

配合 ExampleSelector(embedding 近邻、长度加权等)可以做动态样例选取。


9. 工具定义

9.1 @tool 装饰器(90% 场景的首选)

python 复制代码
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """Add two integers."""
    return a + b

# 高级形式
@tool("weather", args_schema=WeatherSchema, return_direct=True)
def get_weather(city: str) -> dict: ...

# 带 artifact 的工具
@tool(response_format="content_and_artifact")
def search(q: str) -> tuple[str, list[dict]]:
    hits = do_search(q)
    summary = format_hits(hits)
    return summary, hits      # (content, artifact)
  • 自动从类型注解与 docstring 生成 args_schemadescriptionname
  • response_format="content_and_artifact" 时,content 喂回 LLM,artifact 留在 ToolMessage.artifact 供后续取用。

9.2 StructuredTool

适合从已有函数快速生成工具:

python 复制代码
from langchain_core.tools import StructuredTool

def book(flight_no: str, seat: str) -> str: ...

book_tool = StructuredTool.from_function(
    func=book,
    name="book_flight",
    description="Book a flight seat.",
    args_schema=BookSchema,
)

9.3 BaseTool 手写类

需要细粒度控制(复杂 async、权限校验)时:

python 复制代码
from langchain_core.tools import BaseTool
from pydantic import BaseModel

class QuerySchema(BaseModel):
    sql: str

class SqlTool(BaseTool):
    name: str = "sql_query"
    description: str = "Run a read-only SQL query."
    args_schema: type[BaseModel] = QuerySchema

    def _run(self, sql: str) -> str:
        _assert_readonly(sql)
        return self._db.run(sql)

    async def _arun(self, sql: str) -> str:
        _assert_readonly(sql)
        return await self._db.arun(sql)

9.4 Injected 注解:对 LLM 不可见的参数

python 复制代码
from typing import Annotated
from langchain_core.tools import tool, InjectedToolCallId
from langgraph.prebuilt import InjectedState

@tool
def remember(
    fact: str,
    *,
    state: Annotated[AgentState, InjectedState],
    tool_call_id: Annotated[str, InjectedToolCallId],
) -> str:
    """Save a fact to the user's memory."""
    state["memory"].append(fact)
    return "OK"

InjectedState / InjectedToolCallId / InjectedToolArg 让 LangGraph 在运行时注入值,但生成的 JSON Schema 会自动剔除这些参数------LLM 根本看不到它们。

9.5 把 retriever 变成 tool

python 复制代码
from langchain.tools.retriever import create_retriever_tool

kb_tool = create_retriever_tool(
    retriever,
    name="search_kb",
    description="Search the internal knowledge base.",
)

10. 工具调用与结构化输出

10.1 bind_tools

python 复制代码
model_with_tools = model.bind_tools(
    tools=[add, weather, sql_tool, {"type": "web_search_20250604"}],  # BaseTool / @tool / dict
    tool_choice="auto",                 # "auto" | "any" | "none" | "required" | {"type":"function","function":{"name":"..."}}
    strict=True,                        # OpenAI/xAI:严格 schema 约束
    parallel_tool_calls=True,           # OpenAI
)

msg: AIMessage = model_with_tools.invoke([HumanMessage("用工具加 2 和 3")])
for tc in msg.tool_calls:
    print(tc["name"], tc["args"])
  • dict 类型参数 代表 provider 的内建工具 (如 OpenAI Responses API 的 web_searchfile_searchcomputer_use),LangChain 原样透传。
  • tool_choice="any" 在 Anthropic 表示"必须调用某个工具",OpenAI 对应 "required"

10.2 with_structured_output

python 复制代码
from pydantic import BaseModel, Field

class Answer(BaseModel):
    city: str
    temperature_c: float = Field(description="Celsius")

structured = model.with_structured_output(
    schema=Answer,
    method="json_schema",   # 可选 "function_calling" | "json_mode" | "json_schema"
    include_raw=False,      # True 时返回 {"raw":..., "parsed":..., "parsing_error":...}
    strict=True,
)

ans: Answer = structured.invoke("What's the temperature in Tokyo?")

10.3 两个常见坑

坑 1:with_structured_output(S).bind_tools([t]) 会挂 with_structured_output 返回的是 RunnableSequence(内部已经绑好了一个隐藏抽取工具),没有 bind_tools 方法。解决方案:在 bind_toolstool_choice 指定 schema 对应的工具名,不要再走 with_structured_output

坑 2:流式状态下 tool args 合并不稳 部分 provider 在 .stream(...) 下会把 tool call 的 args 单次吐出(无 partial chunk),导致你等不到增量 JSON。Issue #29129 描述了这一点。Workaround:对 tool call 走 .invoke(非 stream),或只用 .astream_events(version="v2") 来拿 on_chat_model_stream 事件。

10.4 回调注入

python 复制代码
msg = model.invoke(
    messages,
    config={
        "callbacks": [UsageMetadataCallbackHandler()],
        "tags": ["extraction"],
        "metadata": {"task_id": "T-101"},
    },
)

不要通过 model = ChatOpenAI(callbacks=[...]) 旧式绑定------v1.0 已完全改用 config 注入模型。


11. create_agent:v1.0 唯一的 Agent 抽象

11.1 签名

python 复制代码
from langchain.agents import create_agent, AgentState
from langchain.agents.structured_output import ToolStrategy, ProviderStrategy

agent = create_agent(
    model: str | BaseChatModel,
    tools: Sequence[BaseTool | Callable | dict],
    *,
    prompt: str | ChatPromptTemplate | Callable | None = None,
    response_format: ToolStrategy | ProviderStrategy | type | None = None,
    state_schema: type[AgentState] | None = None,
    middleware: Sequence[AgentMiddleware] = (),
    checkpointer: BaseCheckpointSaver | None = None,   # LangGraph
    store: BaseStore | None = None,                    # LangGraph
    context_schema: type | None = None,
    name: str | None = None,
    version: Literal["v1", "v2"] = "v2",
    debug: bool = False,
)

返回值是一个 已编译的 LangGraph CompiledStateGraph :你可以直接 .invoke / .stream / .astream_events / .get_state / .update_state / .get_graph().draw_mermaid()

11.2 最小示例

python 复制代码
from langchain.agents import create_agent
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """Add."""
    return a + b

agent = create_agent(
    model="openai:gpt-5.2",
    tools=[add],
    prompt="You are a math assistant.",
)

result = agent.invoke({"messages": [HumanMessage("1+2+3?")]})
print(result["messages"][-1].content)

11.3 AgentState

python 复制代码
from typing_extensions import TypedDict, Annotated, NotRequired
from langgraph.graph.message import add_messages
from langgraph.managed import RemainingSteps

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    remaining_steps: NotRequired[RemainingSteps]
    structured_response: NotRequired[Any]     # 仅当 response_format 被设置

v1.0 强制要求 :自定义 state 必须继承 AgentState 并且是 TypedDict 。Pydantic / dataclass 不再被接受,这是 v1.0 迁移中最常见的 breaking change。

python 复制代码
class MyState(AgentState):                     # OK
    user_id: str
    notes: list[str]

# 以下都会被拒绝(v1.0):
# class MyState(BaseModel): ...
# @dataclass class MyState: ...

11.4 remaining_steps

remaining_steps = recursion_limit − steps_taken。当它低于 2 且还有 pending tool call 时,agent 会优雅返回一条 "Sorry, need more steps to process this request."而不是GraphRecursionError------这是一个比 v0.x 更友好的兜底。

11.5 Agent 与 prompt 的几种写法

python 复制代码
# 1) 静态字符串 → 变成 SystemMessage
agent = create_agent(model, tools, prompt="You are helpful.")

# 2) ChatPromptTemplate
agent = create_agent(model, tools, prompt=ChatPromptTemplate.from_messages([
    ("system", "You help users with {domain} questions."),
    ("placeholder", "{messages}"),
]))

# 3) Callable(state, runtime) → list[BaseMessage]
def dynamic_prompt(state, runtime):
    persona = runtime.context.persona
    return [SystemMessage(f"Act as {persona}.")] + state["messages"]

agent = create_agent(model, tools, prompt=dynamic_prompt)

11.6 从 AgentExecutor 迁过来

v0.x v1.0
create_tool_calling_agent(llm, tools, prompt) + AgentExecutor(agent, tools) create_agent(model, tools, prompt=prompt)
create_react_agent(llm, tools, prompt)(字符串解析版) create_agent(model, tools, prompt=...)
AgentExecutor(..., return_intermediate_steps=True) 遍历 result["messages"] 自己筛 ToolMessage
AgentExecutor(..., max_iterations=10) agent.invoke(..., config={"recursion_limit": 10*2+1})
pre_model_hook / post_model_hook Middleware 的 before_model / after_model

12. Middleware 子系统

12.1 三种 Hook 风格

风格 钩子 语义
Node-style(观察/修饰) before_agent, before_model, after_model, after_agent 在节点前后运行,可返回 state 增量
Wrap-style(拦截) wrap_model_call, wrap_tool_call 包住 LLM 调用/工具调用,决定是否真正执行
Convenience modify_model_request 一次性改 tools / messages / tool_choice / 输出格式

执行顺序:

css 复制代码
before_agent
  → before_model[各中间件顺序]
    → wrap_model_call[嵌套洋葱]
      → 实际模型调用
    → after_model[各中间件倒序]
  → tool loop / wrap_tool_call
after_agent

12.2 装饰器形式

python 复制代码
from langchain.agents.middleware import before_model, wrap_model_call

@before_model
def inject_user_profile(state, runtime):
    return {"messages": [SystemMessage(f"User: {runtime.context.user_name}")]}

@wrap_model_call
def retry_on_rate_limit(request, handler):
    for i in range(3):
        try:
            return handler(request)
        except RateLimitError:
            time.sleep(2 ** i)
    raise

12.3 类形式(推荐用于复杂场景)

python 复制代码
from langchain.agents.middleware import AgentMiddleware

class AuditMiddleware(AgentMiddleware):
    state_schema = AuditState              # 扩 state 的首选方式

    tools = [audit_tool]                   # 本 middleware scoped 的工具

    def before_model(self, state, runtime):
        log.info("model call", user=runtime.context.user_id)
        return None

    def wrap_tool_call(self, request, handler):
        if is_dangerous(request.tool_call):
            raise PermissionError("blocked")
        return handler(request)

state_schema 属性是 v1.0 扩展 state 的官方 方式------比在 create_agent(state_schema=...) 里手动合并更安全。

12.4 v1 自带 Middleware 清单

Middleware 功能
SummarizationMiddleware 历史超阈值时在 before_model 里做增量总结
ModelRetryMiddleware(v1.1) wrap_model_call 里指数退避重试
PIIMiddleware 输入/输出/工具结果的 PII 掩码/哈希/硬阻断,失败抛 PIIDetectionError
LLMToolSelectorMiddleware 用廉价模型从大 toolset 预选子集
ShellToolMiddleware 注入 shell 工具 + before_agent/after_agent 生命周期管理
AnthropicPromptCachingMiddleware(ttl="5m") 在 langchain-anthropic:自动标记 cache_control
Anthropic text_editor / memory_tool / file_search / bash_tool middleware 把 Anthropic 服务器端工具能力接入 agent

12.5 Middleware vs 旧 hook 的不兼容警告

langgraph.prebuilt.create_react_agentpre_model_hook / post_model_hook 不能与 middleware 共存------混用会触发 runtime error。迁 middleware 时要一并把 hook 删掉。


13. 结构化输出策略

13.1 三种策略

langchain.agents.structured_output

Strategy 适用 原理
AutoStrategy[T] 默认,推 schema 就会选它 优先选 ProviderStrategy,不支持时回落到 ToolStrategy
ProviderStrategy(schema, strict=None) OpenAI JSON schema、Anthropic structured outputs、Gemini JSON mode 使用 provider 原生结构化 endpoint
ToolStrategy(schema, tool_message_content=None, handle_errors=...) 任何支持 tool calling 的模型 合成一个 schema 工具,末回合 tool_choice="any"

13.2 用法

python 复制代码
from pydantic import BaseModel

class TicketTriage(BaseModel):
    severity: Literal["P0","P1","P2","P3"]
    category: str
    summary: str

# 方式 1:直接传 schema(AutoStrategy)
agent = create_agent(model, tools, response_format=TicketTriage)

# 方式 2:手动选 ToolStrategy(跨 provider 最稳)
agent = create_agent(
    model, tools,
    response_format=ToolStrategy(
        schema=TicketTriage,
        handle_errors=lambda e: f"Please fix: {e}",
    ),
)

# 结果在 state["structured_response"]
result = agent.invoke({"messages": [HumanMessage("...")]} )
triage: TicketTriage = result["structured_response"]

13.3 常见问题

  1. 流式受限 :两种策略下最后一轮都是"强制 tool call",几乎没有前置 text,astream 会很短。
  2. Schema 必须静态已知:目前不支持根据运行时状态动态换 schema(路线图上)。
  3. Gemini 3 误路由 :若 Gemini 3 被 AutoStrategy 误选到 ToolStrategy,显式包 ProviderStrategy(TicketTriage) 即可。
  4. 异常StructuredOutputErrorMultipleStructuredOutputsErrorStructuredOutputValidationError

14. 检索与 RAG 体系

14.1 Document 与 BaseLoader

python 复制代码
from langchain_core.documents import Document

doc = Document(
    page_content="LangChain is ...",
    metadata={"source": "README.md", "page": 1},
    id="doc-1",
)

BaseLoader 协议:

python 复制代码
class BaseLoader(ABC):
    def load(self) -> list[Document]: ...
    def lazy_load(self) -> Iterator[Document]: ...
    async def aload(self) -> list[Document]: ...
    async def alazy_load(self) -> AsyncIterator[Document]: ...

常用 loader:TextLoader / CSVLoader / JSONLoader / UnstructuredFileLoader / DirectoryLoader / PyPDFLoader / PyMuPDFLoader / UnstructuredPDFLoader / WebBaseLoader / RecursiveUrlLoader / PlaywrightURLLoader / SitemapLoader,云存储 loader 分散在各自的 partner 包。

14.2 Text Splitters

python 复制代码
from langchain_text_splitters import (
    RecursiveCharacterTextSplitter,
    TokenTextSplitter,
    MarkdownHeaderTextSplitter,
    Language,
)

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", " ", ""],
    length_function=len,
    keep_separator=True,
)

py_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON, chunk_size=1500, chunk_overlap=200,
)

chunks: list[Document] = splitter.split_documents(loader.load())

高级:SemanticChunker(基于 embedding 断句)、MarkdownHeaderTextSplitterHTMLSectionSplitter

14.3 Embeddings 与 VectorStore

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

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
store = FAISS.from_documents(chunks, embeddings)
retriever = store.as_retriever(
    search_type="mmr",
    search_kwargs={"k": 5, "fetch_k": 20, "lambda_mult": 0.5},
)

搜索类型:

  • "similarity":最近邻
  • "mmr":Maximal Marginal Relevance,平衡相关性与多样性
  • "similarity_score_threshold":带阈值过滤

search_kwargs 支持 filter={...} 做 metadata 过滤(各 vectorstore 表达式略有差异)。

14.4 高级检索器(都在 langchain-classic 下)

检索器 用途
MultiQueryRetriever LLM 把查询改写成 N 个不同措辞的 query,取并集
ContextualCompressionRetriever LLMChainExtractor / LLMChainFilter / EmbeddingsFilter 压缩命中
ParentDocumentRetriever 存子块(高召回),返父块(全上下文)
MultiVectorRetriever 索引 summary / HyDE 问题,返回原文
EnsembleRetriever 稀疏(BM25)+ 稠密融合,RRF 加权
SelfQueryRetriever LLM 把自然语言 query 编译成结构化 metadata 过滤
TimeWeightedVectorStoreRetriever 时间衰减加权

14.5 Indexing API(增量同步)

python 复制代码
from langchain.indexes import SQLRecordManager, index

rm = SQLRecordManager(namespace="my_ns", db_url="sqlite:///rm.db")
rm.create_schema()

index(
    docs,
    record_manager=rm,
    vector_store=store,
    cleanup="incremental",         # incremental / full / None
    source_id_key="source",
)

基于内容哈希 + source id 做可重跑的去重同步,生产数据管道必备。

14.6 典型 RAG 链

python 复制代码
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

template = """仅基于上下文回答问题。不知道就说不知道。

上下文:
{context}

问题:{question}
"""

prompt = ChatPromptTemplate.from_template(template)

rag_chain = (
    {"context": retriever | (lambda docs: "\n\n".join(d.page_content for d in docs)),
     "question": RunnablePassthrough()}
    | prompt
    | model
    | StrOutputParser()
)

15. Memory:从旧内存类到 LangGraph Checkpointer

15.1 旧 memory 的终结

下列 v0.x 的类全部在 v1.0 移到 langchain-classic ,并且不再推荐使用

  • ConversationBufferMemory
  • ConversationBufferWindowMemory
  • ConversationSummaryMemory
  • ConversationSummaryBufferMemory
  • ConversationKGMemory
  • ConversationEntityMemory
  • VectorStoreRetrieverMemory
  • CombinedMemory
  • ReadOnlySharedMemory

原因:它们早于 tool calling 时代设计,缺乏 thread/user 维度,且无法跨进程持久化。

15.2 新架构:Checkpointer + Store

arduino 复制代码
Checkpointer(会话内持久化,按 thread_id)
  └── InMemorySaver / MemorySaver        (开发)
  └── SqliteSaver / AsyncSqliteSaver     (本地文件)
  └── PostgresSaver / AsyncPostgresSaver (生产)

Store(跨会话长期记忆,按 namespace)
  └── InMemoryStore
  └── PostgresStore
  └── 自带向量索引(embedding config)

thread_iduser_id 通过 config["configurable"] 在运行时传入:

python 复制代码
agent = create_agent(
    model, tools,
    checkpointer=PostgresSaver.from_conn_string("postgresql://..."),
    store=PostgresStore.from_conn_string("postgresql://..."),
)

agent.invoke(
    {"messages": [HumanMessage("记住我喜欢 Python")]},
    config={"configurable": {"thread_id": "chat-42", "user_id": "u-100"}},
)

15.3 trim_messages 辅助函数

超长历史控制的银弹:

python 复制代码
from langchain_core.messages import trim_messages

trimmed = trim_messages(
    messages,
    max_tokens=4000,
    token_counter=model,          # BaseLanguageModel 或 Callable
    strategy="last",              # "first" | "last"
    start_on="human",             # 确保从 human 开始(保留对话完整性)
    end_on=["human", "tool"],
    include_system=True,
    allow_partial=False,
)

最佳实践:把它写进一个 SummarizationMiddleware 或自定义的 before_model 里,每次模型调用前自动裁剪。

15.4 LangMem

LangMem SDK 构建在 BaseStore 之上,提供语义记忆(用户偏好、事实)与程序记忆(how-to 经验)两种高层 API。适合已经用 Store 做了基础的项目继续深化。


16. Callbacks 与 LangSmith 追踪

16.1 BaseCallbackHandler

位于 langchain_core.callbacks.base,由六个 Mixin 拼成:

lua 复制代码
BaseCallbackHandler
├── LLMManagerMixin       → on_llm_start / new_token / end / error
├── ChainManagerMixin     → on_chain_start / end / error
├── ToolManagerMixin      → on_tool_start / end / error
├── RetrieverManagerMixin → on_retriever_start / end / error
├── CallbackManagerMixin  → on_chat_model_start / on_text
└── RunManagerMixin       → on_agent_action / on_agent_finish / on_custom_event

AsyncCallbackHandler 提供异步镜像。每个钩子都接收 run_idparent_run_idtagsmetadataserialized

16.2 最小 Handler

python 复制代码
from langchain_core.callbacks.base import BaseCallbackHandler

class TokenPrinter(BaseCallbackHandler):
    def on_llm_new_token(self, token: str, **kwargs):
        print(token, end="", flush=True)

chain.invoke({"q": "..."}, config={"callbacks": [TokenPrinter()]})

16.3 CallbackManager 内部机制

handle_event 是核心 dispatch:

  • 同步上下文 + 同步 handler:直接调用。
  • 同步上下文 + 异步 handler :汇集为 coroutine,用 asyncio.Runner(3.11+)或 asyncio.run 跑完。
  • 异步上下文 :走 ahandle_event,用 asyncio.gather 并发所有 async handler。
  • run_inline=True 的 handler 顺序执行,确保关键副作用不并发。
  • Handler 没实现 on_chat_model_start 时,系统自动降级为 on_llm_start + 字符串化消息。

16.4 LangSmith 零配置接入

bash 复制代码
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=lsv2_...
export LANGSMITH_PROJECT=my-agent

langchain_core.tracers.context 会自动注册 LangChainTracer,之后任何 Runnable 的执行都进入 LangSmith:

  • 嵌套 run 依靠 parent_run_id 自动成树;
  • metadata={...}tags=[...] 成为 UI 可筛选列;
  • LLM 调用的 token usage 从 AIMessage.usage_metadata 上报;
  • Agent 的多步执行(model → tool → model → ...)在一个 trace 里完整展开。

16.5 不要再用 model = ChatOpenAI(callbacks=[...])

v1.0 已全面改为 config 注入。模型直接带 handler 会在组合进 LCEL 时丢失继承,导致下游 runnable 看不到这些 handler。


17. 输出解析器

17.1 类层次

css 复制代码
BaseOutputParser[T]                    → invoke 入口
└── BaseTransformOutputParser          → 支持流式
    └── BaseCumulativeTransformOutputParser  → 累加后 emit diff

17.2 关键实现

Parser 输出 特点
StrOutputParser str 直接取 AIMessage.content 的文本
JsonOutputParser(pydantic_object=None) dict 宽容 JSON,流式下能 emit 部分 dict
PydanticOutputParser(pydantic_object, diff=False) Pydantic 实例 diff=True 流式下吐 JSON-Patch
StructuredOutputParser.from_response_schemas([...]) dict 基于 ResponseSchema 描述,轻量但校验弱
XMLOutputParser(tags=[...]) dict XML 结构化
PydanticToolsParser(tools=[M1, M2]) list[Union[M1,M2]] AIMessage.tool_calls 抽取并 dispatch 到对应 Pydantic
JsonOutputToolsParser(first_tool_only=False) list[dict] 同上但 dict 形式
OutputFixingParser.from_llm(parser, llm) T 解析失败时让 LLM 自我修复
RetryOutputParser.from_llm(parser, llm) T 类似但带原始 prompt 上下文

17.3 get_format_instructions 的地位

所有 parser 都提供 get_format_instructions() -> str,用于塞进 prompt:

python 复制代码
parser = PydanticOutputParser(pydantic_object=MySchema)
prompt = ChatPromptTemplate.from_messages([
    ("system", "输出必须严格遵守格式。\n{format_instructions}"),
    ("human", "{query}"),
]).partial(format_instructions=parser.get_format_instructions())

chain = prompt | model | parser

但在 v1.0 时代,结构化输出优先走 model.with_structured_output(Schema),比 parser + 模板更稳定。只有 provider 不支持原生结构化时才回落到 parser。


18. Partner 包生态

18.1 langchain-openai

python 复制代码
from langchain_openai import ChatOpenAI, AzureChatOpenAI, OpenAIEmbeddings

model = ChatOpenAI(
    model="gpt-5.2",
    temperature=0,
    streaming=True,
    use_responses_api=True,             # o-series / server-side tool 必开
    reasoning_effort="medium",
    service_tier="scale",
    logprobs=True,
    top_logprobs=5,
    include=["reasoning.summary"],      # 请求推理摘要回显
    strict=True,                        # structured output 严格 schema
)

emb = OpenAIEmbeddings(model="text-embedding-3-large", dimensions=1024)

18.2 langchain-anthropic

python 复制代码
from langchain_anthropic import ChatAnthropic
from langchain_anthropic.middleware import AnthropicPromptCachingMiddleware

model = ChatAnthropic(
    model="claude-sonnet-4-6",
    max_tokens=8192,
    thinking={"type": "enabled", "budget_tokens": 10_000},   # extended thinking
)

agent = create_agent(
    model,
    tools=[...],
    middleware=[AnthropicPromptCachingMiddleware(ttl="5m")],
)

Anthropic 特殊工具(text_editor、memory_tool、file_search、bash_tool)以 middleware 形式接入,而不是手写 tool。

18.3 langchain-google-genai v4.0.0+

已迁移到合并后的 google-genai SDK,同时覆盖 Gemini Developer API 与 Vertex AI 的 Gemini,取代了部分 langchain-google-vertexai 功能:

python 复制代码
from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings

model = ChatGoogleGenerativeAI(model="gemini-2.5-pro", temperature=0)

18.4 langchain-aws(独立 repo)

python 复制代码
from langchain_aws import ChatBedrockConverse   # 推荐走 Converse API
# from langchain_aws import ChatBedrock         # 旧接口
# from langchain_aws import BedrockLLM, BedrockEmbeddings

model = ChatBedrockConverse(
    model="anthropic.claude-sonnet-4-6",
    region_name="us-east-1",
)

另含 AmazonKendraRetriever、Neptune graph、DynamoDB 对话历史等。

18.5 Partner 包的公约

  • peer depend on langchain-core:升 core 不强制升 partner。
  • standard-tests:模型必须通过同一套 BaseChatModel 测试;否则 PR 无法合并。
  • 模型 ID 透传:新模型一出,provider SDK 能调就能用,不需要 LangChain 升级。

19. v0.x → v1.0 迁移要点

19.1 一眼看懂的变化清单

  1. langchain namespace 大瘦身 :老 chain / 老 agent / 老 memory / MultiQueryRetriever / EnsembleRetriever 等都搬到 langchain-classic
  2. Agent 只剩 create_agentAgentExecutorcreate_tool_calling_agentcreate_openai_tools_agentcreate_openai_functions_agentcreate_react_agent(字符串解析)、create_json_agentcreate_structured_chat_agentinitialize_agent 全部 deprecate。
  3. langgraph.prebuilt.create_react_agent 也 deprecate,别名转发到 langchain.agents.create_agent
  4. 自定义 state 必须是 TypedDict:Pydantic / dataclass 被明确拒绝。
  5. Middleware 取代所有 hookpre_model_hook / post_model_hook / runtime_config 归一到 middleware。
  6. 标准化 content blocksAIMessage.content_blocks 属性统一多模态 / 推理 / 引用。
  7. 消息 API 收紧.text() → 属性;AIMessage.example 移除。
  8. 结构化输出 :prompted JSON response_format 被移除;必须用 Auto/Provider/Tool Strategy 或 with_structured_output
  9. create_agent(tools=...) 拒绝 ToolNode :只接受 BaseTool | Callable | dict
  10. Memory 全部迁移到 LangGraph:Checkpointer + Store。
  11. 文档迁到 docs.langchain.com/oss/python/...

19.2 典型迁移 diff

python 复制代码
# v0.x
from langchain.agents import AgentExecutor, create_tool_calling_agent
prompt = ChatPromptTemplate.from_messages([
    ("system","You are helpful."),
    ("placeholder","{chat_history}"),
    ("human","{input}"),
    ("placeholder","{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=10)
executor.invoke({"input": "...", "chat_history": history})

# v1.0
from langchain.agents import create_agent
agent = create_agent(model, tools, prompt="You are helpful.")
agent.invoke(
    {"messages": history + [HumanMessage("...")]},
    config={"recursion_limit": 21},   # 大致对应 max_iterations=10
)

19.3 v1.1 要点

  • 新增 ModelRetryMiddleware
  • 修复 v1.1.0 的一个 regression:langchain.agents.__init__ 一度漏出 create_agent(patch 版已修)。
  • 稳定性与可观测性增强,无 breaking。

19.4 迁移心法

  • 先跑 classic 兼容pip install langchain-classic,加 from langchain_classic.memory import ConversationBufferMemory 这类 alias 让旧代码先活着。
  • 再拆 Agent :把 AgentExecutor 替换成 create_agent,同步把 hook 改写成 middleware。
  • 最后拆 state :如果用了 Pydantic / dataclass state,必须转成 TypedDict

20. LangChain 与 LangGraph 的关系与选型

20.1 层级关系

scss 复制代码
LangSmith                              ← 可观测(独立平台)
   ↑ trace
LangChain (create_agent / Middleware / Chains / Retrievers)
   ↓ compile
LangGraph (StateGraph / Pregel / Checkpointer / Interrupt)
   ↓ depends on
langchain-core (Runnable / BaseMessage / BaseTool / Callbacks)

20.2 选型决策树

优先用 LangChain create_agent

  • 标准 tool-calling agent
  • 单线性或轻度分支工作流
  • RAG 管道、chatbot、原型
  • 产品首月想快速上线

下沉到 LangGraph 原生

  • 复杂分支 / 循环 / 子图
  • 多 Agent 协作(supervisor / hierarchical / swarm)
  • 需要 time-travel、replay、interrupt
  • 长耗时持久化任务(数小时/数天)
  • 节点级流式、背压控制

混合使用(最常见):

  • 顶层用 LangGraph StateGraph
  • 每个节点内部是 create_agent 或 LCEL chain;
  • Checkpointer、Store、tools、messages 全局共享。

20.3 互操作要点

  • create_agent 的返回值 就是 一个 LangGraph CompiledStateGraph,可以 .invoke / .stream / .astream_events / .get_state / .update_state
  • Middleware 只对 LangChain 有效;在原生 LangGraph 里要靠节点 + 边实现等效行为。
  • 工具、消息、checkpointer、store、模型------两边共享同一套抽象,不存在"LangChain 版 tool"和"LangGraph 版 tool"。

20.4 一条经验法则

如果你不确定,从 LangChain 起步 ,等到遇到 create_agent 的 API 没法表达你的需求时,再切到 LangGraph 原生图。不要一开始就跳到 StateGraph


21. 生产最佳实践

21.1 可观测性

  • 永远开 LangSmithLANGSMITH_TRACING=true 是零成本的。
  • 关键 Runnable 加 with_config({"run_name": "xxx"}),trace 里可读性高一个数量级。
  • metadata={"user_id": ..., "session_id": ..., "env": ...}:这些字段在 LangSmith 里直接可筛可 group。

21.2 可靠性

  • 重试 :关键 LLM 调用走 .with_retry(stop_after_attempt=3, wait_exponential_jitter=True),或用 ModelRetryMiddleware
  • 回退primary.with_fallbacks([fallback_model]) 处理 provider 断线。
  • 超时 :在 provider client 层设置 timeout(OpenAI 的 timeout=...),LangChain 不做全局超时。
  • 幂等 :对外部副作用工具用 tool_call.id 做去重;checkpointer 恢复时同一个 tool call 不会重跑(只要你的工具自身幂等)。

21.3 成本控制

  • UsageMetadataCallbackHandler 聚合 token usage。
  • 大 toolset 走 LLMToolSelectorMiddleware,用廉价模型预筛。
  • 缓存:OpenAI 的 prompt caching 对稳定前缀自动生效;Anthropic 用 AnthropicPromptCachingMiddleware
  • 结构化输出优先走 ProviderStrategy(native JSON mode),比强制 tool call 便宜

21.4 安全

  • PIIPIIMiddleware 做输入/输出/工具结果的掩码或硬阻断。
  • 工具访问控制 :在 wrap_tool_call 中做权限校验;InjectedState 注入用户身份。
  • configurable="any"永不直接暴露给终端用户。
  • prompt injection:retriever 召回的文本应该过滤(或限制到工具使用场景下不执行指令)。

21.5 并发与吞吐

  • .abatch(inputs, max_concurrency=N) 是最直接的并发工具。
  • I/O 密集链路全走 async(ainvoke / astream / abatch)。
  • LangGraph 的多 Agent 并行默认走 Send,不是 asyncio------但底层仍然是 async。

21.6 版本管理

  • langchainlangchain-core、partner 包、langgraph 都 pin 到 minor (例如 langchain~=1.1langchain-core~=1.3)。
  • 关注 langchain/changelog 的 patch 公告;v1 承诺 "no breaking until 2.0",但 bug fix 随时可能改行为细节。

22. API 快速参考

22.1 Runnable 方法速查

方法 返回 用途
invoke(input, config) Output 同步单次
ainvoke(input, config) Output 异步单次
stream(input, config) Iterator[Output] 同步流
astream(input, config) AsyncIterator[Output] 异步流
batch(inputs, config) list[Output] 同步批量
abatch(inputs, config) list[Output] 异步批量
astream_events(input, config, version="v2") AsyncIterator[StreamEvent] 高保真事件流
with_config(config) Runnable 附加配置
with_retry(...) Runnable 重试
with_fallbacks([...]) Runnable 回退
with_listeners(on_start, on_end, on_error) Runnable 侦听
bind(**kwargs) RunnableBinding 冻结参数
assign(**mappers) RunnableAssign dict 追加字段
get_graph(config) Graph 画图

22.2 创建 Agent 速查

python 复制代码
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import (
    AgentMiddleware, before_model, after_model,
    wrap_model_call, wrap_tool_call,
    SummarizationMiddleware, ModelRetryMiddleware, PIIMiddleware,
    LLMToolSelectorMiddleware,
)
from langchain.agents.structured_output import (
    AutoStrategy, ProviderStrategy, ToolStrategy,
    StructuredOutputError, MultipleStructuredOutputsError,
    StructuredOutputValidationError,
)
from langchain.chat_models import init_chat_model

22.3 工具速查

python 复制代码
from langchain_core.tools import (
    tool, BaseTool, StructuredTool, Tool,
    InjectedToolArg, InjectedToolCallId,
)
from langgraph.prebuilt import InjectedState, InjectedStore
from langchain.tools.retriever import create_retriever_tool

22.4 消息速查

python 复制代码
from langchain_core.messages import (
    BaseMessage, HumanMessage, AIMessage, SystemMessage,
    ToolMessage, FunctionMessage, ChatMessage,
    AIMessageChunk, HumanMessageChunk,
    trim_messages,
)
# 标准 content blocks(v1)
# AIMessage.content_blocks: list[TextContentBlock | ReasoningContentBlock |
#   Citation | ToolCall | ServerToolCall | ImageContentBlock |
#   AudioContentBlock | VideoContentBlock | FileContentBlock |
#   NonStandardContentBlock]

22.5 关键源码路径

文件 内容
libs/core/langchain_core/runnables/base.py Runnable, RunnableSequence, RunnableParallel, RunnableBinding
libs/core/langchain_core/runnables/passthrough.py RunnablePassthrough, RunnableAssign
libs/core/langchain_core/runnables/branch.py RunnableBranch
libs/core/langchain_core/runnables/config.py RunnableConfig、回调传播、contextvars
libs/core/langchain_core/language_models/base.py BaseLanguageModel, LangSmithParams
libs/core/langchain_core/language_models/chat_models.py BaseChatModel
libs/core/langchain_core/language_models/llms.py BaseLLM, LLM
libs/core/langchain_core/messages/ 所有消息类
libs/core/langchain_core/messages/content_blocks.py 标准 content blocks
libs/core/langchain_core/prompts/chat.py ChatPromptTemplate, MessagesPlaceholder
libs/core/langchain_core/output_parsers/pydantic.py PydanticOutputParser
libs/core/langchain_core/tools/ BaseTool, StructuredTool, @tool
libs/core/langchain_core/callbacks/base.py BaseCallbackHandler
libs/core/langchain_core/callbacks/manager.py CallbackManager, handle_event
libs/core/langchain_core/tracers/context.py LangSmith tracer 注入
libs/langchain_v1/langchain/agents/ create_agent, AgentState
libs/langchain_v1/langchain/agents/middleware/ 所有 Middleware
libs/langchain_v1/langchain/agents/structured_output/ Auto/Provider/Tool Strategy
libs/langchain_v1/langchain/chat_models/base.py init_chat_model
libs/text-splitters/langchain_text_splitters/ 所有 splitter
libs/langchain/ langchain-classic(legacy)
libs/partners/openai/, anthropic/, ... partner 实现

结语

LangChain v1.0 的核心收获:

  1. Runnable 协议是根 ------所有东西都是 Runnable,| 是协议的糖。
  2. create_agent 是面------别再手写 AgentExecutor,middleware 是新的扩展点。
  3. langchain-core 是骨------只要你在 core 的协议里编程,模型/provider/工具都可替换。
  4. LangGraph 是肌肉------真正的执行运行时在底层,需要时随时下沉。
  5. LangSmith 是神经------零成本接入,线上问题 90% 的答案都在 trace 里。

一句话总结:create_agent 解决 80% 的日常问题,用 LangGraph 解决剩下 20% 的复杂编排,用 LangChain Core 保证你永远不被 provider 绑死。

相关推荐
Raink老师3 小时前
【AI面试临阵磨枪-48】GraphRAG、多模态 RAG、自适应 RAG 原理
人工智能·ai 面试题
波动几何4 小时前
模式驱动的学术选题方法论——四种AI模式处理能力的系统建构与论证
人工智能
飞哥数智坊4 小时前
我为我的龙虾斩分身:OpenClaw 多智能体实操
人工智能·agent
七牛开发者4 小时前
HTML is the new Markdown:来自 Claude Code 团队的实践
前端·人工智能·语言模型·html
飞哥数智坊4 小时前
在二线城市做AI社群,我的五一节后到底有多疯狂?
人工智能
视***间4 小时前
智启边缘,魔盒藏锋——视程空间Pandora系列魔盒,解锁边缘计算普惠新范式
人工智能·区块链·边缘计算·ai算力·视程空间
蛐蛐蛐5 小时前
昇腾910B4上安装新版本CANN的正确流程
人工智能·python·昇腾
沪漂阿龙5 小时前
AI大模型面试题:线性回归是什么?最小二乘法、平方误差、正规方程、Ridge、Lasso 一文讲透
人工智能·机器学习·线性回归·最小二乘法
Lyon198505285 小时前
《文字定律》让AI体验,汉字逻辑与字母逻辑的差异——ChatGPT
人工智能·ai·chatgpt·ai写作
2601_957780846 小时前
Claude 4.6 对阵 GPT-5.4:2026 开发者大模型 API 选型深度解析
人工智能·python·gpt·ai·claude