复杂JSON Schema结构与输出校验

要分清一点:"解析失败、字段缺失、字段格式错误"虽然表现不同,但都属于 Structured Output 数据契约没有满足。处理上不要一律重试,而应该"分类 → 修复/重试 → 最终兜底"。

结合你的 DBA Agent,推荐下面这套机制。

问题 典型情况 首选处理 最终兜底
解析失败 不是合法 JSON、JSON 截断、夹杂文本 Parser/Structured Output Retry JSON Extract/Repair → Fallback
字段缺失 clustersql Schema Validation → LLM重试 默认值/补全/人工
字段格式错误 need_explain:"yes"risk_level:"VERY_HIGH" Pydantic Validation → LLM重试 类型转换/Repair → Fallback

1. 解析失败:先修复结构,再重试

例如模型返回:

text 复制代码
分析结果如下:

{
  "cluster": "mysql-prod-01",
  "database": "order",
  "sql": "SELECT * FROM orders"

}

这时候还没有进入 Pydantic,因为:

python 复制代码
json.loads(raw)

已经失败。

推荐:

text 复制代码
LLM
 ↓
Parser
 ↓
解析失败
 ↓
Repair
 ↓
Parser
 ↓
成功?

如果是 LangChain Structured Output,可以让框架/模型重新生成结构化结果;如果你走的是自由文本解析路线,可以做:

text 复制代码
JSON Extract
 ↓
JSON Repair
 ↓
Pydantic

例如:

python 复制代码
try:
    data = json.loads(raw)
except JSONDecodeError:
    data = repair_json(raw)

但这里不建议自己大量写正则修 JSON。

JSON Repair 可以作为兼容层,但不要把它当核心方案。

更推荐:

text 复制代码
Structured Output
+
Pydantic
+
有限 Retry

2. 字段缺失:让 Schema 告诉 LLM"缺了什么"

例如 Schema:

python 复制代码
class SQLAnalysis(BaseModel):
    cluster: str
    database: str
    sql: str
    risk_level: Literal["LOW", "MEDIUM", "HIGH"]
    need_explain: bool

模型返回:

json 复制代码
{
  "cluster": "mysql-prod-01",
  "database": "order",
  "sql": "SELECT * FROM orders"
}

缺:

text 复制代码
risk_level
need_explain

Pydantic:

text 复制代码
ValidationError
 ↓
missing field

这时候不要直接让整个 Agent Loop 结束。

应该:

text 复制代码
        LLM
         ↓
Structured Output
         ↓
Pydantic
         ↓
   ❌ missing field
         ↓
Error Handler
         ↓
把校验错误反馈给 LLM
         ↓
       Retry
         ↓
      Pydantic
         ↓
         OK

例如给模型:

text 复制代码
Structured output validation failed.

Missing required fields:
- risk_level
- need_explain

Please regenerate the complete structured output.

模型重新生成:

json 复制代码
{
  "cluster": "mysql-prod-01",
  "database": "order",
  "sql": "SELECT * FROM orders",
  "risk_level": "MEDIUM",
  "need_explain": true
}

通过。


3. 字段格式错误:Pydantic 最适合处理

例如:

json 复制代码
{
  "cluster": "mysql-prod-01",
  "database": "order",
  "sql": "SELECT ...",
  "risk_level": "HIGH",
  "need_explain": "yes"
}

Schema:

python 复制代码
need_explain: bool

但是:

text 复制代码
"yes" ≠ boolean

Pydantic 校验失败。

处理:

text 复制代码
Pydantic
 ↓
ValidationError
 ↓
Error Handler
 ↓
Retry
 ↓
LLM重新生成

再比如:

json 复制代码
{
  "risk_level": "VERY_HIGH"
}

Schema:

python 复制代码
Literal["LOW", "MEDIUM", "HIGH"]

同样失败。


4. 三种错误实际上应该统一成一个 Error Handler

不要在每个 Node 里面自己处理。

建议:

text 复制代码
                    Agent
                      │
                Structured Output
                      │
                Pydantic Validate
                      │
             ┌────────┴────────┐
             │                 │
            OK               Error
             │                 │
             ↓                 ↓
          Next Node       Error Handler
                               │
                 ┌─────────────┼─────────────┐
                 ↓             ↓             ↓
              Parse         Missing       Type Error
                 │             │             │
                 └─────────────┼─────────────┘
                               ↓
                             Retry
                               ↓
                              LLM

这样整个 Agent 的错误处理机制是一致的。


5. Retry 一定要有限制

例如:

python 复制代码
MAX_RETRY = 2

流程:

text 复制代码
第一次
 ↓
失败
 ↓
Retry 1
 ↓
失败
 ↓
Retry 2
 ↓
失败
 ↓
Fallback

不要:

python 复制代码
while True:
    retry()

否则:

text 复制代码
LLM
 ↓
错误
 ↓
LLM
 ↓
错误
 ↓
LLM
 ↓
错误
 ↓
无限循环

这就是你最开始说的:

数据格式问题导致 loop 中断

真正工程化的处理不是让它"永远不失败",而是:

失败可恢复,恢复失败后可控退出。


6. DBA Agent 还应该区分"能自动修复"和"不能自动修复"

例如:

A. 可以自动修复

text 复制代码
JSON少一个 }

→ Repair

text 复制代码
字段缺失

→ Retry

text 复制代码
boolean/string类型错误

→ Retry

text 复制代码
risk_level拼错

→ Retry

这些都属于:

text 复制代码
格式性错误

可以自动恢复。

B. 不应该自动修复

例如:

json 复制代码
{
  "cluster": "mysql-prod-01",
  "sql": "DROP TABLE orders"
}

Schema 完全正确。

但:

text 复制代码
SQL危险

这不是 Structured Output Error。

应该进入:

text 复制代码
Business Validator
        ↓
Security Validator
        ↓
HITL

而不是:

text 复制代码
LLM Retry

这是 DBA Agent 特别重要的区别。


7. 最终推荐的完整链路

你的 DBA Agent 可以做成:

text 复制代码
LLM
 ↓
Structured Output
 ↓
Pydantic
 ↓
┌─────────────────────────────┐
│ Validation                  │
│                             │
│ 解析失败                     │
│ 字段缺失                     │
│ 字段类型错误                 │
└──────────────┬──────────────┘
               ↓
          Error Handler
               ↓
        Retry / Repair
               ↓
             LLM
               ↓
          Pydantic
               ↓
             成功
               ↓
       Business Validator
               ↓
        SQL AST / Rule
               ↓
       Security / ACL
               ↓
              Tool
               ↓
          ToolResult
               ↓
        LangGraph State

最后如果连续失败:

text 复制代码
Retry 1
  ↓
Retry 2
  ↓
仍然失败
  ↓
Fallback
  ↓
END / HITL

可以统一返回:

python 复制代码
class AgentError(BaseModel):
    error_type: Literal[
        "PARSE_ERROR",
        "MISSING_FIELD",
        "INVALID_TYPE",
        "BUSINESS_ERROR",
        "PERMISSION_ERROR",
        "TOOL_ERROR"
    ]
    message: str
    retryable: bool
    retry_count: int

这样 LangGraph 就可以根据:

python 复制代码
error.retryable

决定走:

text 复制代码
Retry

还是:

text 复制代码
Fallback / HITL / END

所以三种错误的核心处理原则是:解析失败 → Repair/Retry;字段缺失 → Schema Validation + Retry;字段格式错误 → Pydantic Validation + Retry。三者最终统一进入 Error Handler,并设置最大重试次数;超过次数必须 Fallback,不能让 Agent Loop 无限跑。

相关推荐
子林super1 小时前
结构化输出解析失败处理策略
github
怕浪猫2 小时前
拆解 Google《AI Agent Handbook》:企业级 Agent 的六层架构与产品矩阵
面试·github·agent
kali-Myon2 小时前
分享一个网络安全 AI 工具导航项目 SecSkills
安全·ai·github·ctf
峰向AI12 小时前
Kage: 一个 244KB 文件,做出百万级视觉效果
github
m4Rk_16 小时前
【论文阅读】Agent 记忆机制(74):CompassMem——从相似度检索走向事件图上的记忆导航
论文阅读·人工智能·学习·开源·github
wflynn17 小时前
GitHub 日榜趋势速报 | 2026-09-18
开源·github
粥里有勺糖19 小时前
视野修炼第133期 | Native 回春了?
前端·github·agent
Mr.朱鹏1 天前
Git 仓库同时推送到 Gitee 与 GitHub 配置指南
git·gitee·开源·github
All for pursuit.1 天前
FastAPI+Ollama 部署本地AI大模型对话助手
python·github·aigc·ollama