结构化错误分类与自动重试设计
Related topics: [[pydantic-ai-agent-graph]], [[langchain-runnable]], [[llm-error-handling]]
Overview
本文分析五个 LLM 框架中的结构化错误分类与自动重试机制:
| 框架 | 语言 | 定位 |
|---|---|---|
| pydantic-ai | Python | 结构化输出优先的 Agent 框架 |
| langchain | Python | 通用 LLM 编排框架 |
| pi-mono | TypeScript | VSCode 扩展 AI Agent 框架 |
| kosong | Python | 轻量级 Chat Provider 库 |
| republic | Python | 统一接口 LLM 客户端 |
核心关注点:错误层次结构设计、重试策略实现、错误恢复机制以及 Callback 系统中的错误传播。
Key Concepts
1. 错误分类层次结构 (Error Hierarchy)
pydantic-ai 的错误层次
Exception
├── ModelRetry # 工具函数重试信号
├── CallDeferred # 延迟工具调用
├── ApprovalRequired # 需要人工审批
├── UserError # 开发者使用错误
└── AgentRunError # Agent 运行期错误基类
├── UsageLimitExceeded # 用量限制超出
├── ConcurrencyLimitExceeded # 并发限制超出
├── UnexpectedModelBehavior # 模型异常行为
│ └── ContentFilterError # 内容过滤触发
├── ModelAPIError # 模型 API 错误基类
│ └── ModelHTTPError # HTTP 错误 (4xx/5xx)
└── IncompleteToolCall # 工具调用不完整
关键设计 原则:
- 分层明确:
UserError(开发者错误) vsAgentRunError(运行时错误) - 可恢复性标记:
ModelRetry表示可重试,CallDeferred/ApprovalRequired表示需要外部干预 - 上下文丰富:
ModelHTTPError包含 status_code、body、model_name
# pydantic-ai/pydantic_ai_slim/pydantic_ai/exceptions.py
class ModelHTTPError(ModelAPIError):
"""Raised when an model provider response has a status code of 4xx or 5xx."""
status_code: int
body: object | None
def __init__(self, status_code: int, model_name: str, body: object | None = None):
self.status_code = status_code
self.body = body
message = f'status_code: {status_code}, model_name: {model_name}, body: {body}'
super().__init__(model_name=model_name, message=message)
langchain 的错误层次
Exception
└── LangChainException
├── TracerException
├── OutputParserException # 输出解析错误 (可发送到 LLM 修复)
└── ContextOverflowError # 上下文溢出
关键设计特点:
- ErrorCode 枚举: 标准化错误代码 (
OUTPUT_PARSING_FAILURE,MODEL_RATE_LIMIT等) - 可修复标记:
OutputParserException.send_to_llm允许将错误反馈给模型
# langchain/libs/core/langchain_core/exceptions.py
class OutputParserException(ValueError, LangChainException):
def __init__(
self,
error: Any,
observation: str | None = None,
llm_output: str | None = None,
send_to_llm: bool = False,
):
self.observation = observation
self.llm_output = llm_output
self.send_to_llm = send_to_llm # 是否反馈给 LLM 修复