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 绑死。

相关推荐
天天代码码天天1 小时前
C# OnnxRuntime 部署 DAViD 表面法线估计
人工智能·david 表面法线估计
墨染天姬1 小时前
【AI】2026年4月开源模型排行榜
人工智能·开源
zhexiao271 小时前
AI提效工具使用实践 Claude Code、NEXT AI DRAW.IO、XREAD
人工智能·draw.io
wangqiaowq1 小时前
RSA2 非对称加密签名
人工智能
踩着两条虫1 小时前
VTJ.PRO 企业级应用开发实战指南
前端·人工智能·低代码·重构·架构
薛定猫AI2 小时前
【深度解析】Graphify 如何为 AI 编程助手构建项目级知识图谱:降低 Token 消耗、提升代码理解效率
人工智能·知识图谱
ok_hahaha2 小时前
AI从头开始-黑马LongGraph-简单学习
人工智能·学习·langchain·lang graph
子午2 小时前
文本情感识别系统~Python+textCNN算法+深度学习+人工智能
人工智能·python·算法
黑金IT2 小时前
通过“套壳”架构打造工业级 AI 视频生成流水线
人工智能·架构·ai视频