本节用 middleware 在运行时选择模型:短对话使用标准模型,长对话切换到更大的模型。
同一个 Agent 不一定每次都要用同一个模型。短问题可以用便宜快速的标准模型,长上下文或复杂任务可以切到更强模型。
| 场景 | 模型策略 |
|---|---|
| 短对话、简单问题 | 标准模型,降低成本和延迟 |
| 长对话、上下文很多 | 大模型或更长上下文模型 |
| 高风险推理 | 更强模型或专用模型 |
@wrap_model_call 可以拦截模型调用前的 request,并用 request.override(model=...) 替换本次调用的模型。
Notebook 准备了两个 DeepSeek 模型对象:standard_model 和 large_model。
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
large_model = deepseek_model("deepseek-v4-pro")
standard_model = deepseek_model()这里两个变量都是 LangChain chat model。区别只在模型名称和能力配置。
Middleware 读取 request.messages,根据消息数量判断对话长短。超过 10 条消息就切换到大模型。
@wrap_model_call
def state_based_model(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
"""Select model based on State conversation length."""
message_count = len(request.messages)
if message_count > 10:
model = large_model
else:
model = standard_model
request = request.override(model=model)
return handler(request)Middleware 修改 request 后仍然要调用 handler(request),否则模型调用不会继续执行。
Agent 创建时仍然传一个默认模型,但实际调用会被 middleware 改写。系统提示让 Agent 扮演办公室实习生。
agent = create_agent(
model=deepseek_model(),
middleware=[state_based_model],
system_prompt="You are roleplaying a real life helpful office intern.",
)默认模型是兜底配置;middleware 可以在每次模型调用前按条件覆盖。
Notebook 分别运行一个短问题和一个超过 10 条消息的长对话,并打印响应 metadata 里的 model_name,确认模型是否按条件切换。
response = agent.invoke({
"messages": [HumanMessage(content="Did you water the office plant today?")]
})
print(response["messages"][-1].response_metadata["model_name"])
response = agent.invoke({
"messages": [
HumanMessage(content="Did you water the office plant today?"),
AIMessage(content="Yes, I gave it a light watering this morning."),
HumanMessage(content="Has it grown much this week?"),
AIMessage(content="It's sprouted two new leaves since Monday."),
HumanMessage(content="Are the leaves still turning yellow on the edges?"),
AIMessage(content="A little, but it's looking healthier overall."),
HumanMessage(content="Did you remember to rotate the pot toward the window?"),
AIMessage(content="I rotated it a quarter turn so it gets more even light."),
HumanMessage(content="How often should we be fertilizing this plant?"),
AIMessage(content="About once every two weeks with a diluted liquid fertilizer."),
HumanMessage(content="When should we expect to have to replace the pot?"),
]
})
print(response["messages"][-1].response_metadata["model_name"])不要只看回答文本。动态模型逻辑应该通过 metadata、日志或 tracing 明确验证。
wrap_model_call 是模型调用前后的拦截点。request.override 可以替换本次调用的模型。