https://docs.langchain.com/oss/python/langchain/agents#model 概览: LangChain 关键核心知识点概览 基于你学习的所有文档和产出的约束,汇总成一张核心知识地图:
一、架构认知 概念 一句话本质 Agent 模型 + 工具 + 提示词 + 记忆,在 ReAct 循环中自主决策的系统 ReAct 循环 推理 → 工具调用 → 观测结果 → 继续推理,直到输出最终答案 LangGraph 底层 Agent 是基于图的运行时,节点(模型、工具、中间件)由边连接 约束工程 不恳求模型遵守规则,而是构建让破坏规 则变得不可能的系统
二、Agent 组装四要素 create_agent(model, tools, system_prompt, checkpointer, middleware) │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ 推理引擎 能力边界 行为边界 会话记忆 扩展钩子 要素 必填 核心约束 model ✅ 用 init_chat_model,显式设 temperature/timeout/max_tokens tools ✅ 用 @tool 装饰,docstring 含 Args/Returns/Raises,函数名 snake_case system_prompt ✅ 含 ## Capabilities + ## Rules,工具名用反引号与函数名严格一致 checkpointer ✅ 开发用 InMemory,生产用 Postgres;同 thread_id 同会话 middleware ❌ 拦截模型调用/工具调用/状态变化,动态模型/工具/prompt
三、模型使用核心要点 要点 规则 初始化 init_chat_model("provider:model") 优先 单次调用 invoke(messages) → AIMessage 流式调用 stream() → 迭代 AIMessageChunk 批量调用 batch(inputs) → 并行处理 逐结果返回 batch_as_completed(inputs) → 异步返回 工具绑定 bind_tools([...]) → .tool_calls 结构化输出 with_structured_output(Schema) → model 实例
四、工具定义规范 @tool def tool_name(param: str) -> str: # snake_case 命名 """一句话描述工具做什么。 # ← 第一行注入模型上下文
Args: param: 参数类型和含义
Returns: 返回值结构和含义
Raises: ExceptionType: 触发条件 """ 关键边界: ● 函数名与 system_prompt 反引号内名称 字符级一致 ● docstring 缺 Args/Returns/Raises → 模型调用可能错误 ● 动态工具需同时实现 wrap_model_call + wrap_tool_call
五、Middleware 拦截节点 Hook 触发时机 用途 @wrap_model_call 模型调用前 动态切换模型/过滤工具列表 @wrap_tool_call 工具执行前 错误处理/动态工具执行 @before_model 模型调用前(不修改请求) 状态预处理/消 息裁剪 @after_model 模型返回后 响应验证/内容过滤 @dynamic_prompt 模型调用前 根据运行时上下文动态生成 system prompt 核心规则: ● 修改请求必须用 request.override(...),不可直接改属性 ● handler 只能调用一次
六、记忆系统分层 层级 机制 持久性 消息历史 checkpointer + thread_id InMemory(开发)/ Postgres(生产) 自定义状态 AgentState TypedDict 扩展 会话内持久,会话间通过 store 长期记忆 store(跨会话持久化) 数据库持久化 核心约束: ● 同会话复用 thread_id,不同会话用不同 thread_id ● 自定义状态必须继承 AgentState 且为 TypedDict(v1 起) ● 长对话必须配消息管理策略(裁剪/摘要 middleware)
七、调用与流式输出
同步
result = agent.invoke({"messages": [{"role": "user", "content": "..."}]})
answer = result["messages"][-1].content_blocks
流式
for chunk in agent.stream({"messages": [...]}, stream_mode="values"):
latest = chunk["messages"][-1]
if isinstance(latest, AIMessage):
if latest.content: print(latest.content)
if latest.tool_calls: print(latest.tool_calls)
核心约束: ● invoke 必须传入消息列表,不可传字符串 ● 流式必须区分消息类型(HumanMessage / AIMessage / ToolMessage) ● 提取结果用 .content_blocks 而非 .content(当有 tool_calls 时 .content 为空)
八、核心决策树 需要多步规划/文件系统中转/子Agent? ├─ 是 → create_deep_agent └─ 否 → create_agent
模型支持原生结构化输出? ├─ 是 → ProviderStrategy(或直接传 Pydantic schema,自动选择) └─ 否 → ToolStrategy
工具在运行时才确定? ├─ 是 → 动态工具(wrap_model_call + wrap_tool_call) └─ 否 → 静态工具(直接传 tools 列表)
需要根据用户/状态决定可见工具? ├─ 是 → 过滤预注册工具(wrap_model_call 中过滤) └─ 否 → 全部工具直接暴露
九、你的约束资产库(已产出) 模块 约束文档 Model 初始化 ✅ Tools 定义 ✅ System Prompt ✅ Memory ✅ Invocation ✅ Streaming ✅ Middleware ✅ Structured Output ✅ Create and Run ✅ Review Results ✅
这张知识地图是你所有提示词资产的索引。后续复刻任何 LangChain 应用,按这张地图定位所需模块,调出对应的约束文档,嵌入你的任务提示词即可。 LangChain 模型选择
约束:LangChain 模型选择的代码规范
技术边界
create_agent的第一个参数可以是字符串(自动解析为 "provider:model")或模型实例(完整控制配置)- 模型标识符字符串 "gpt-5.4" 会被自动推断为 "openai:gpt-5.4"
- 传字符串无法设置 temperature、timeout、max_tokens;传模型实例则全部可控
- 动态模型通过
middleware+@wrap_model_call实现,在每次请求时根据request.state决定用哪个模型 bind_tools已调用的预绑定模型,不能用于需要结构化输出的动态模型场景
生成要求
1. 模型选择决策(优先使用模型实例)
生成代码时,必须遵循以下决策链生成 create_agent 的第一个参数:
if 需要显式设置 temperature/timeout/max_tokens/base_url 中任一参数:
使用模型实例(如 ChatOpenAI(model="...", temperature=..., timeout=...))
elif 模型标识符字符串可以被自动推断(如 "gpt-5.4" → "openai:gpt-5.4"):
可使用字符串 "provider:model"
else:
使用模型实例,显式指定 model_provider 和 model
2. 模型实例(ChatOpenAI / ChatAnthropic 等)
- 必须显式设置
temperature(默认 0.5)和timeout(默认 300 秒) - 从
langchain_openai、langchain_anthropic等独立包导入,不通过 langchain 的顶层导出
3. 动态模型(middleware 模式)
- 使用
from langchain.agents.middleware import wrap_model_call导入 - 使用
@wrap_model_call装饰器定义函数,签名固定为(request: ModelRequest, handler) -> ModelResponse request.state["messages"]可获取当前消息列表- 通过
handler(request.override(model=selected_model))传入替换后的模型 - 传入
create_agent时使用middleware=[...]参数,且model参数必须是默认模型(不预绑定工具)
4. 自动推断约束
- 允许省略 provider 的模型标识符:
"gpt-5.4"可被自动推断为"openai:gpt-5.4" - 非知名模型标识符必须显式写出完整
"provider:model"格式 - 可在生成代码时写
"openai:gpt-5.4",即使只用"gpt-5.4"也能运行
反例
- ❌
create_agent(ChatOpenAI(model="gpt-5.4"))— 缺少 temperature 和 timeout- ✅ FIX:
create_agent(ChatOpenAI(model="gpt-5.4", temperature=0.5, timeout=300))
- ✅ FIX:
- ❌
ChatOpenAI(model="gpt-5.4", temperature=0.5)— 缺 timeout- ✅ FIX:显式追加
timeout=300
- ✅ FIX:显式追加
- ❌ 动态模型 middleware 中
handler(request)直接返回,未调用.override(model=...)- ✅ FIX:
return handler(request.override(model=selected_model))
- ✅ FIX:
- ❌ 动态模型 middleware 传入预绑定工具的模型
- ✅ FIX:middleware 中的模型使用原始实例,非
model.bind_tools(...)的返回值
- ✅ FIX:middleware 中的模型使用原始实例,非
- ❌ 传入未知模型标识符却不显式写 provider
- ✅ FIX:写完整格式
"provider:model_name"
- ✅ FIX:写完整格式
验收标准
-
create_agent的第一个参数是模型实例,除非只使用默认配置 - 模型实例显式设置了
temperature和timeout - 动态模型 middleware 使用
@wrap_model_call,非自定义中间件 -
handler调用时使用.override(model=...)模式 - middleware 中的模型未被
bind_tools预处理
LangChain System Prompt
约束:LangChain 工具(Tools)的代码规范
技术边界
- 工具通过
@tool装饰器注册,或直接传入普通 Python 函数/协程 - 工具列表通过
create_agent的tools参数注入,传入空列表[]则 Agent 不具工具调用能力 - 静态工具在
create_agent时一次性定义;动态工具在 middleware 中通过request.override(tools=...)在运行时增删 - 动态工具分两种模式:过滤预注册工具(
wrap_model_call中过滤)和运行时注册工具(需同时实现wrap_model_call和wrap_tool_call) - 工具名使用
snake_case,禁止包含空格或特殊字符(多 provider 兼容性要求) - Agent 遵循 ReAct 循环:推理 → 工具调用 → 观测结果 → 继续推理/输出答案
生成要求
1. 静态工具定义
- 每个工具函数使用
@tool装饰器,docstring 第一行为功能描述 - 工具函数名全小写+下划线,与
system_prompt中反引号引用的工具名完全一致 - 传递给
create_agent时使用tools=[tool1, tool2]列表形式
2. 动态工具 — 过滤预注册工具
- 使用
@wrap_model_call装饰器,在 middleware 中根据request.state/request.runtime.context/request.runtime.store过滤request.tools - 过滤后必须通过
request.override(tools=filtered_tools)返回 - 适用场景:所有可能的工具在创建 Agent 时已知,但根据权限/状态动态开关
3. 动态工具 — 运行时注册
- 条件:工具在运行时才被发现(MCP 服务器、远程注册表等)
- 必须同时实现两个 middleware hook:
wrap_model_call:通过request.override(tools=[*request.tools, new_tool])添加工具wrap_tool_call:拦截工具调用请求,通过request.override(tool=new_tool)指定执行函数
- 仅当
request.tool_call["name"]匹配动态工具名时才做 override
4. 工具错误处理
- 使用
@wrap_tool_call定义错误处理 middleware - 捕获异常后必须返回
ToolMessage(content=..., tool_call_id=request.tool_call["id"]) tool_call_id必须从request.tool_call["id"]提取,不可硬编码
反例
- ❌ 工具函数用驼峰命名
def searchProduct(...)- ✅ FIX:改为
search_product,system_prompt中引用search_product
- ✅ FIX:改为
- ❌ 动态工具只在
wrap_model_call中注册,未实现wrap_tool_call- ✅ FIX:同时实现两个 hook,
wrap_tool_call中对匹配的动态工具做request.override(tool=...)
- ✅ FIX:同时实现两个 hook,
- ❌ 工具异常处理中用
return f"Error: {e}"返回字符串- ✅ FIX:返回
ToolMessage(content=f"Tool error: ...", tool_call_id=request.tool_call["id"])
- ✅ FIX:返回
- ❌
create_agent(tools=[])但仍期望 Agent 能调用工具- ✅ FIX:传入实际工具列表,或在 middleware 中动态注入
约束:LangChain System Prompt 的代码规范
技术边界
system_prompt参数接受str或SystemMessage对象- 传入
str时,LangChain 自动包装为SystemMessage - 传入
SystemMessage时,可使用 provider 特定功能(如 Anthropic 的cache_control) - 不传
system_prompt时,Agent 直接从消息列表推断任务 - 动态 system prompt 通过
@dynamic_prompt装饰器实现,在 middleware 中根据request.runtime.context生 成
生成要求
1. 静态 System Prompt(字符串形式)
- 直接传入
str:system_prompt="You are a helpful assistant. Be concise and accurate." - 字符串中如果引用工具名,使用反引号包裹,工具名与函数名完全一致
2. 静态 System Prompt(SystemMessage 形式)
- 需要 provider 高级特性(如缓存)时使用
SystemMessage - Anthropic prompt caching 格式:
SystemMessage(content=[{"type": "text", "text": "..."},{"type": "text", "text": "<content>", "cache_control": {"type": "ephemeral"}}])
cache_control字段只在 Anthropic provider 下生效,不兼容其他 provider
3. 动态 System Prompt
- 使用
from langchain.agents.middleware import dynamic_prompt导入 - 函数签名:
(request: ModelRequest) -> str,返回 prompt 字符串 - 从
request.runtime.context中读取上下文数据决定 prompt 内容 - 通过
middleware=[...]传入create_agent,需配合context_schema使用
反例
- ❌
system_prompt=SystemMessage("You are a helpful assistant")— 将字符串直接传入 SystemMessage 构造器- ✅ FIX:使用
system_prompt="You are a helpful assistant"或SystemMessage(content=[...])
- ✅ FIX:使用