LLM 成为新时代的解析器:如何处理不稳定的 AI 输出内容
- 作者

- 姓名
- Nino
- 职业
- Senior Tech Editor
软件工程的历史,在很大程度上就是一部解析(Parsing)的历史。如果你在 2000 年代初从事过网页爬虫开发或集成过旧有的遗留系统,你一定对那种痛苦记忆犹新。那是一个“防御性编程”盛行的时代,我们的首要目标是从外部世界抛给我们的垃圾数据中幸存下来。无论是那些看起来像古代咒语的正则表达式(Regex) HTML 提取器,还是试图理解十七种不同“合法”格式的 XML 反序列化工具,亦或是必须猜测引号内的逗号是否为分隔符的 CSV 读取器,其核心模式始终如一:世界给你垃圾,你写代码来提取其中的意义。
随后,在一段短暂而美好的时光里,我们似乎赢得了这场战争。API 变成了行业标准,带有严格 Schema 的 JSON、类型安全的客户端以及 OpenAPI 规范为混乱带来了秩序。我们终于“驯服”了机器。然而,随着大语言模型(LLM)的兴起,摆钟又荡了回去。我们再次回到了“垃圾产出”的时代,只不过这一次,垃圾是由拥有万亿参数的神经网络生成的,而不是破损的 Web 服务器。今天,LLM 就是新时代的解析器,我们必须重新挖掘过去的防御性模式,才能构建出可靠的现代应用程序。
不稳定输出的回归
在构建复杂的 AI 工作流时——例如使用 LLaVA 进行图像分析,或者通过 n1n.ai 调用 Claude 3.5 Sonnet 进行文档提取——开发者经常会掉进“Markdown 陷阱”。你明确要求返回一个干净的 JSON 对象,而模型为了显得“有礼貌”,往往会将 JSON 包裹在 Markdown 代码块中(```json ... ```)。或者,它可能会加上一段开场白:“好的,这是为您准备的数据。”
有时问题更加底层。模型可能会忘记闭合花括号 {},或者在你的 Schema 中幻觉出一个根本不存在的字段。即使是像 DeepSeek-V3 或 GPT-4o 这样的顶级模型,如果提示词(Prompt)上下文稍有歧义,也偶尔会返回 YAML 而不是 JSON。这种不确定性成了 AI 时代的“IE 6 浏览器”。
2025 年的防御性解析策略
为了构建生产级别的应用,我们不能简单地依赖 json.loads()。我们需要一套多层防御体系。以下是处理 LLM 输出的实战建议:
1. 预处理器:清理杂音
在尝试解析输出之前,必须剥离掉所有的对话修饰。这包括识别并移除 Markdown 围栏以及任何前导或尾随文字。
def clean_llm_json(raw_response: str) -> str:
# 移除 Markdown 代码块
if "```" in raw_response:
parts = raw_response.split("```")
for part in parts:
# 匹配 json 标识或直接以花括号开头的块
stripped_part = part.strip()
if stripped_part.startswith("json"):
return stripped_part[4:].strip()
if stripped_part.startswith("{"):
return stripped_part
return raw_response.strip()
2. 启发式修复:平衡括号
如果 LLM 达到了 Token 限制或者干脆“忘了”完成对象,你通常可以通过简单的启发式方法挽救这个请求。计算开口和闭合括号的数量,可以防止 RAG(检索增强生成)流程彻底崩溃。
def repair_json(json_str: str) -> str:
open_braces = json_str.count("{")
close_braces = json_str.count("}")
if open_braces > close_braces:
# 自动补全缺失的闭合括号
json_str += "}" * (open_braces - close_braces)
return json_str
利用聚合平台确保稳定性
降低解析失败率的最佳方法之一是使用高质量的 LLM 聚合器,例如 n1n.ai。通过 n1n.ai,你可以通过单一、统一的接口访问多个模型供应商。这使你能够实现“模型降级(Fallback)”策略。如果 DeepSeek-V3 返回了无法解析的内容,你的代码可以自动切换到 Claude 3.5 Sonnet 或 OpenAI o3 重新尝试。
| 模型名称 | JSON 可靠性 | 响应速度 (Tokens/s) | 最佳适用场景 |
|---|---|---|---|
| DeepSeek-V3 | 高 | 120+ | 高性价比数据提取 |
| Claude 3.5 Sonnet | 极高 | 80+ | 复杂逻辑推理 |
| GPT-4o | 极高 | 100+ | 通用任务 |
| Llama 3.1 70B | 中 | 150+ | 高吞吐量任务 |
结构化输出 API:现代解决方案
虽然防御性解析是必要的,但行业正在向“结构化输出(Structured Outputs)”模式演进。现在,许多供应商提供了强制模型遵循特定 JSON Schema 的参数。在 n1n.ai 上,你可以利用这些高级特性,确保输出不仅“看起来像 JSON”,而且严格符合你的 Pydantic 模型定义。
结合使用 Instructor 或 Outlines 等库,并配合 n1n.ai 提供的稳定 API,可以确保当模型决定在语法上“搞创作”时,你的应用程序不会直接崩溃。这些库在采样层面使用正则表达式来限制 LLM,使其无法生成违反 Schema 的 Token。
专家提示:少样本锚点 (Few-Shot Anchor)
如果你发现解析仍然频繁失败,请使用少样本提示词。为 LLM 提供 2-3 个你期望的 精确 JSON 格式示例。这在神经网络中起到了“语法锚点”的作用,能显著降低出现 Markdown 围栏或格式错误的概率。
总结
现代 AI 开发的讽刺之处在于,我们构建了能够写诗、能够解释量子物理的系统,但它们却在花括号这种基础语法上挣扎。LLM 已经成为了终极解析器——一个将现实世界的非结构化混乱(图像、音频、文档)转化为半结构化数据的工具。作为开发者的任务,就是提供最后一层结构化保障,将这些“半结构化”输出转化为系统所需的类型安全数据。
通过将防御性编程实践与 n1n.ai 提供的低延迟、高可靠基础设施相结合,你可以构建出像过去二十年里我们不断完善的遗留系统一样稳健的 AI 应用。
立即在 n1n.ai 获取免费 API 密钥。