开发者现在可以通过将修复尝试限制在两次以内,来控制修复大语言模型 (LLM) 生成的错误 JSON 所产生的费用,一个简单的 Python 循环展示了这一点。这种模式——生成、解析、验证、重试,然后接受或失败——将“可能有效的 JSON”转化为可衡量的成功率,并防止了 Token 使用量的失控。
为什么修复循环至关重要
LLM 通常被要求“返回 JSON”,但输出经常包含语法错误、缺失键或违反业务规则的值。如果向期望严格负载的下游系统提供此类输出,系统将会崩溃或产生错误结果。如果没有系统化的方法来捕获并纠正这些问题,团队要么只能接受高失败率,要么只能通过反复提示模型直到其正确为止,从而浪费资金。
三层验证机制
一个可靠的循环将验证分为:
- 语法 (Syntax) – 字符串是否可以解析为 JSON?
- 结构 (Shape) – 顶层对象是否包含完全预期的键?
- 语义 (Semantic) – 值是否符合领域约束(例如,“category”必须属于预定义的集合)?
通过在第一个失败的层级停止,循环可以向模型提供精确的错误消息,从而大大提高下次尝试时正确修复的机会。
极简 Python 示例
以下代码仅使用标准库。它定义了一个微型 Schema(一个包含 category 和 summary 键的字典)以及一个固定的允许类别列表。
import json
CATEGORIES = {"bug", "feature", "question"}
def validate(raw: str):
try:
value = json.loads(raw)
except json.JSONDecodeError as exc:
return None, f"syntax: {exc.msg}"
if not isinstance(value, dict):
return None, "shape: root must be an object"
if set(value) != {"category", "summary"}:
return None, "shape: expected category and summary"
if value["category"] not in CATEGORIES:
return None, "semantic: invalid category"
if not isinstance(value["summary"], str) or not value["summary"].strip():
return None, "semantic: summary must be text"
return value, None
修复循环本身对尝试次数设定了硬上限:
MAX_ATTEMPTS = 2
raw = model_response # initial LLM output
for attempt in range(MAX_ATTEMPTS + 1):
value, error = validate(raw)
if error is None:
break
if attempt == MAX_ATTEMPTS:
raise RuntimeError(f"failed after {MAX_ATTEMPTS} retries: {error}")
# Send the error and schema back to the model for a fix
raw = ask_model_to_repair(raw, error)
如果 JSON 在第一次尝试时通过验证,循环会立即退出。否则,它会进行重试,并向模型提供简洁的负载:原始输出、确切的错误字符串以及预期的 Schema。在两次尝试失败后,流程会抛出一个清晰的异常并中止。
实现高性价比修复的两条规则
保持修复提示词简洁 – 仅包含原始 JSON、错误消息和 Schema。添加冗长的对话历史会增加 Token 使用量,并可能干扰模型,在不提高准确性的情况下推高每次重试的成本。
将验证与事实核查分离 – 解析器可以检测结构问题,但无法验证“summary”陈述是否属实。事实核查属于后续阶段;试图“修复”一个虚假陈述只会让谎言看起来更整洁。
衡量成功
记录每次尝试的错误类型(语法、结构、语义)以及循环是否成功,可以提供一个具体的指标:在限定的重试次数内,LLM 响应变为可用数据的比例。团队可以随时间跟踪此指标、比较不同的提示词风格,或尝试不同的 Schema 定义。
潜在缺点
限制循环意味着在达到上限后,一些格式错误的输出将被丢弃,如果模型的原始质量较低,这可能会增加整体失败率。在每个响应都至关重要的环境中,开发者可能会宁愿牺牲额外的 Token 来换取更高的重试上限。这种权衡是显而易见的:以更高的成本换取更高的覆盖率,或者以可预测的上限来控制预算。
后续关注点
- 针对修复的提示词工程 (Prompt engineering) – 优化错误消息格式可以减少所需的重试次数。
- 替代解析器 – 一些库提供容错解析,可以自动纠正轻微问题;比较它们的成本与限定循环的成本是值得的。
- 模型更新 – 更新版本的 LLM 可能原生就能生成更干净的 JSON,从而可能进一步降低重试限制。
一个受限的 JSON 修复循环为开发者提供了一个实用的工具,可以将模糊的 LLM 输出转化为可靠的数据,而不会导致成本失控。通过将验证视为一等公民步骤并限制重试次数,团队可以同时兼顾预算和下游系统的稳定性。
