跳转到内容

结构化输出的策略自适应:AutoStrategy 的智能选择

结构化输出的策略自适应:AutoStrategy 的智能选择

学习目标

本章要解决什么问题:当用户希望模型返回结构化数据时,LangChain 如何自动在不同模型之间选择最优的结构化输出策略?

读者将学到:

  • AutoStrategy / ToolStrategy / ProviderStrategy 三种策略的职责
  • 模型能力检测与策略选择逻辑
  • 多结构化输出冲突的检测与重试
  • handle_errors 的灵活配置

前置知识

本章涉及结构化输出策略的通用原理,建议先阅读:

下文假设你已理解上述概念,直接聚焦 LangChain 的具体实现。

项目实践

三种策略在 create_agent 中的协作

create_agent() 中,response_format 参数接受多种类型,框架自动归一化:

# 伪代码:response_format 归一化
if response_format is None:
initial_response_format = None
elif isinstance(response_format, (ToolStrategy, ProviderStrategy, AutoStrategy)):
initial_response_format = response_format # 直接使用
else:
# Pydantic 类 → AutoStrategy(自动检测)
initial_response_format = AutoStrategy(schema=response_format)

策略选择时机:在 Agent 创建时,AutoStrategy 被转换为 ToolStrategy 以预注册工具。在模型调用时,根据模型能力可能再次切换为 ProviderStrategy。

_get_bound_model 中的自动检测

每次模型调用前,_get_bound_model() 执行策略检测:

# 伪代码
def _get_bound_model(request):
response_format = request.response_format
if isinstance(response_format, AutoStrategy):
if _supports_provider_strategy(request.model, tools=request.tools):
# 模型支持原生结构化输出 → 使用 ProviderStrategy
effective = ProviderStrategy(schema=response_format.schema)
else:
# 不支持 → 回退到 ToolStrategy(已在创建时预注册)
effective = tool_strategy_for_setup
else:
effective = response_format # 用户已显式指定策略
# 根据策略绑定模型
if isinstance(effective, ProviderStrategy):
kwargs = effective.to_model_kwargs() # response_format 等
return model.bind_tools(final_tools, strict=True, **kwargs), effective
elif isinstance(effective, ToolStrategy):
return model.bind_tools(final_tools), effective
else:
return model.bind(**model_settings), None

关键设计:ToolStrategy 在 Agent 创建时就预注册了结构化输出工具,即使 AutoStrategy 最终选择了 ProviderStrategy,工具名称和 Schema 也保持一致。

多结构化输出冲突处理

当模型在一次响应中调用了多个结构化输出工具时:

# 伪代码
structured_tool_calls = [tc for tc in output.tool_calls if tc["name"] in structured_output_tools]
if len(structured_tool_calls) > 1:
# 多个结构化输出 → 错误处理
should_retry, error_msg = _handle_structured_output_error(
MultipleStructuredOutputsError(tool_names), effective_response_format
)
if should_retry:
# 注入错误 ToolMessage,引导模型重试
return {"messages": [output, *error_tool_messages]}
else:
raise MultipleStructuredOutputsError(...)

handle_errors 配置支持多种形式:

  • True:始终重试
  • False:不重试
  • str:自定义错误消息模板
  • ExceptionType:仅对特定异常重试
  • callable:自定义处理函数

结构化输出验证失败

模型返回的解析结果可能不符合 Pydantic Schema:

# 伪代码
try:
structured_response = output_tool.parse(tool_call["args"])
except Exception as exc:
should_retry, error_msg = _handle_structured_output_error(
StructuredOutputValidationError(tool_call["name"], exc, output),
effective_response_format
)
if should_retry:
# 注入错误消息,引导模型修正
return {"messages": [output, ToolMessage(content=error_msg)]}
raise

问题与规避

Gemini 工具与结构化输出不兼容

问题:Gemini < 3 系列模型不支持同时使用工具调用和结构化输出。

对策_supports_provider_strategy() 中特殊处理:当 tools 非空且模型名包含 gemini 但不包含 gemini-3 时,返回 False,强制使用 ToolStrategy。

回退模型列表的维护

问题:当模型 profile 数据不可用时,需要依赖硬编码的回退模型列表。

对策FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT 包含常见模型前缀(grokgpt-5gpt-4.1gpt-4o)。该列表需要随新模型发布而更新。

设计取舍

预注册工具 vs 动态注册

方案优势代价
预注册(ToolStrategy)工具列表在 Agent 创建时确定、编译时可验证不灵活,无法在运行时新增结构化输出工具
动态注册运行时可新增工具工具列表不确定、可能产生工具名冲突

LangChain 选择预注册,因为结构化输出的 Schema 通常在 Agent 设计时就确定,动态注册的需求较少。

自动检测 vs 显式策略

方案优势代价
AutoStrategy用户只需关注 Schema,框架自动选择检测逻辑增加复杂度
显式策略行为确定、易于调试用户需要了解模型能力差异

LangChain 推荐 AutoStrategy 作为默认,因为大多数用户不需要关心底层实现细节。

参考来源