当前位置: 首页 > news >正文

16.人工智能实战:大模型回答格式总是不稳定?JSON Schema 约束、重试修复与结构化输出完整方案

人工智能实战:大模型回答格式总是不稳定?JSON Schema 约束、重试修复与结构化输出完整方案


一、问题场景:AI 回答内容对了,但系统解析失败

在很多 AI 应用中,模型不是只负责聊天,而是要输出结构化结果。

例如:

1. 从简历中抽取姓名、学历、技能 2. 从合同中抽取甲方、乙方、金额 3. 对客服对话做分类 4. 根据用户需求生成任务 JSON 5. Agent 调用工具前生成参数

这类场景最怕的问题是:

模型回答看起来对,但不是合法 JSON。

真实线上问题包括:

1. 多输出了一段解释文字 2. JSON 少了逗号 3. 字段名不一致 4. 数组变成字符串 5. null、空字符串、缺字段混用 6. 中文引号导致解析失败

例如我们希望模型输出:

{"name":"张三","skills":["Python","FastAPI"],"level":"senior"}

但模型可能输出:

以下是提取结果: { 姓名: "张三", 技能: "Python, FastAPI" }

对人来说能看懂,对系统来说就是失败。

这篇文章解决的问题是:

如何让大模型稳定输出可解析、可校验、可修复的结构化 JSON。

二、错误做法:只在 Prompt 里说“请输出 JSON”

很多人第一版会这样写:

请严格输出 JSON,不要输出多余内容。

这在简单场景下有效,但线上不稳定。

因为模型仍然可能:

1. 加解释 2. 字段漏掉 3. 类型错误 4. 输出 Markdown 代码块 5. 输出不符合业务枚举

所以结构化输出不能只靠 Prompt。

需要完整链路:

Prompt 约束 ↓ JSON 解析 ↓ Schema 校验 ↓ 失败修复 ↓ 兜底处理

三、目标结构定义

假设我们要做简历信息抽取。

期望输出:

{"name":"张三","education":"本科","skills":["Python","FastAPI","PyTorch"],"years_of_experience":5,"level":"senior"}

字段规则:

name:字符串 education:字符串 skills:字符串数组 years_of_experience:整数 level:只能是 junior / middle / senior

四、项目结构

structured-output-demo/ ├── app.py ├── schema.py ├── parser.py ├── prompt.py └── repair.py

安装依赖:

pipinstallfastapi uvicorn pydantic

五、定义 Schema

frompydanticimportBaseModel,FieldfromtypingimportList,LiteralclassResumeExtractResult(BaseModel):name:str=Field(...,description="候选人姓名")education:str=Field(...,description="最高学历")skills:List[str]=Field(...,description="技能列表")years_of_experience:int=Field(...,ge=0,le=50)level:Literal["junior","middle","senior"]

这个 Schema 很关键。

它不只是类型声明,也是后续校验标准。


六、构造强约束 Prompt

defbuild_extract_prompt(resume_text:str):returnf""" 你是一个信息抽取助手。 请从简历文本中抽取信息,并只输出合法 JSON。 【字段要求】 {{ "name": "字符串,候选人姓名", "education": "字符串,最高学历", "skills": ["字符串数组,技能列表"], "years_of_experience": "整数,工作年限", "level": "只能是 junior / middle / senior" }} 【规则】 1. 只能输出 JSON,不要输出解释。 2. 不要使用 Markdown 代码块。 3. skills 必须是数组。 4. years_of_experience 必须是整数。 5. level 只能是 junior、middle、senior。 6. 如果信息缺失,请根据文本保守判断,不要编造。 【简历文本】{resume_text}"""

这里要注意:

字段要求和规则要分开写。

模型更容易遵守。


七、JSON 解析器 parser.py

importjsonimportredefextract_json(text:str):text=text.strip()# 去掉 markdown 代码块text=text.replace("```json","").replace("```","").strip()# 如果前后有解释,尝试截取 JSON 对象match=re.search(r"\{.*\}",text,re.S)ifnotmatch:raiseValueError("No JSON object found")json_text=match.group(0)returnjson.loads(json_text)

这个解析器解决:

模型多输出解释 模型输出 Markdown 代码块

八、Schema 校验

fromschemaimportResumeExtractResultfromparserimportextract_jsondefparse_and_validate(raw_output:str):data=extract_json(raw_output)result=ResumeExtractResult(**data)returnresult

测试:

raw=""" ```json{"name":"张三","education":"本科","skills":["Python","FastAPI"],"years_of_experience":5,"level":"senior"}

“”"

result = parse_and_validate(raw)
print(result)

--- ## 九、失败修复 repair.py 真实项目中,第一次输出不合法很常见。 这时不要直接失败,可以让模型修复。 ```python def build_repair_prompt(raw_output: str, error: str): return f""" 下面是一个模型输出的 JSON,但它不符合要求。 【错误信息】 {error} 【原始输出】 {raw_output} 请修复为合法 JSON,并满足以下要求: {{ "name": "字符串", "education": "字符串", "skills": ["字符串数组"], "years_of_experience": "整数", "level": "junior / middle / senior" }} 只输出修复后的 JSON,不要解释。 """

解析流程:

defrobust_parse(raw_output:str,llm_call):try:returnparse_and_validate(raw_output)exceptExceptionase:repair_prompt=build_repair_prompt(raw_output,str(e))repaired=llm_call(repair_prompt)returnparse_and_validate(repaired)

十、完整 FastAPI 示例

fromfastapiimportFastAPI,HTTPExceptionfrompydanticimportBaseModelfrompromptimportbuild_extract_promptfromschemaimportResumeExtractResultfromparserimportparse_and_validatefromrepairimportbuild_repair_prompt app=FastAPI(title="Structured Output Demo")classExtractRequest(BaseModel):resume_text:strdefmock_llm(prompt:str):return""" { "name": "张三", "education": "本科", "skills": ["Python", "FastAPI", "PyTorch"], "years_of_experience": 5, "level": "senior" } """@app.post("/extract",response_model=ResumeExtractResult)defextract(req:ExtractRequest):prompt=build_extract_prompt(req.resume_text)raw_output=mock_llm(prompt)try:result=parse_and_validate(raw_output)returnresultexceptExceptionase:repair_prompt=build_repair_prompt(raw_output,str(e))repaired_output=mock_llm(repair_prompt)try:returnparse_and_validate(repaired_output)exceptExceptionasfinal_error:raiseHTTPException(status_code=500,detail=f"parse failed:{str(final_error)}")

启动:

uvicorn app:app--port8000

请求:

curl-XPOST"http://127.0.0.1:8000/extract"\-H"Content-Type: application/json"\-d'{ "resume_text": "张三,本科学历,5年Python开发经验,熟悉FastAPI和PyTorch。" }'

十一、验证结果

优化前:

模型输出不稳定 JSON 解析经常失败 字段类型不一致

优化后:

Prompt 限制输出 Parser 提取 JSON Pydantic 校验类型 Repair 修复错误 接口返回稳定结构

这套方案的核心是:

不要相信模型一次输出一定正确。

十二、踩坑记录

坑 1:只靠 Prompt

Prompt 能减少错误,但不能消除错误。

必须有程序校验。


坑 2:没有类型校验

JSON 能解析,不代表业务正确。

例如:

{"skills":"Python, FastAPI"}

这是合法 JSON,但不是你要的结构。


坑 3:字段枚举不限制

分类任务必须限制枚举值。

否则模型可能输出:

高级 资深 Senior Engineer

系统很难处理。


坑 4:修复无限重试

最多重试 1~2 次。

否则模型异常时会拖垮系统。


坑 5:错误样本不沉淀

每次解析失败都应该记录:

原始输入 模型输出 错误信息 修复结果

这些是后续优化 Prompt 和 Schema 的关键数据。


十三、适合收藏的结构化输出 Checklist

Prompt: [ ] 是否明确只输出 JSON [ ] 是否给出字段示例 [ ] 是否限制枚举值 [ ] 是否禁止 Markdown 解析: [ ] 是否去掉代码块 [ ] 是否能提取 JSON 对象 [ ] 是否处理多余解释文本 校验: [ ] 是否使用 Schema [ ] 是否校验字段类型 [ ] 是否校验枚举值 [ ] 是否校验数值范围 修复: [ ] 是否支持一次修复 [ ] 是否限制重试次数 [ ] 是否记录失败样本 上线: [ ] 是否有兜底策略 [ ] 是否有错误率监控 [ ] 是否有坏例回收机制

十四、经验总结

结构化输出是大模型落地中非常关键的一环。

聊天场景里,模型多说几句影响不大。

但系统集成场景里,模型输出必须:

可解析 可校验 可修复 可监控

一句话总结:

大模型结构化输出,不能只靠“请输出JSON”,必须靠工程链路兜住。

十五、优化建议

后续可以继续做:

1. 使用 function calling / tools 2. 使用 JSON mode 3. 增加字段级置信度 4. 对高风险字段二次校验 5. 建立结构化输出评测集 6. 将失败样本自动回流 Prompt 优化 7. 对不同业务定义不同 Schema

最后一句经验:

模型负责生成,工程负责兜底。两者缺一不可。
http://www.jsqmd.com/news/745792/

相关文章:

  • 【等保四级医疗系统改造实战白皮书】:20年资深架构师亲授Java系统合规落地的7大生死关卡
  • AI赋能开发:在快马平台直接调用AI模型,智能生成天气预报小程序完整代码
  • 终极指南:如何在Windows上免模拟器安装APK文件?APK Installer完整教程
  • 保姆级教程:用Hugging Face上的VITS-Uma模型,5分钟搞定原神/崩铁角色语音合成
  • OpenClaw技术架构与智能体
  • 前端新手福音:用快马平台和ccswitch轻松理解状态管理
  • 人工智能篇---TensorBoard 和 Weights Biases (WB)
  • 从Blender到Unity:一个低多边形古宅模型的完整美术管线实战(含材质球提取与后期调整)
  • 免费获取金融数据的终极指南:Yahoo Finance API完整教程
  • 自托管AI编码代理编排平台sandboxed.sh部署与配置指南
  • Qt处理CSV文件时,你踩过QTextStream和QByteArray的坑吗?
  • 仅限前200名:Python标注配置黄金配置集(含mypy插件定制+vscode智能提示增强+CI拦截规则),GitHub Star 4.2k项目内部流出
  • 初创团队如何通过 Taotoken 统一管理多个 AI 模型的开发与成本
  • 借助用量看板分析API调用模式并优化模型选型策略
  • 从官方Demo到实战:手把手教你用Odin的ValidateInput和ValueDropdown打造防呆编辑器
  • 5个实战技巧:彻底解决Mesa3D Windows驱动部署难题
  • 17.人工智能实战:Agent 工具调用总是乱选?从意图识别到 Tool Router 的可靠调用架构设计
  • 告别Host模式!PowerJob-Server在Docker桥接网络下的正确配置姿势(附完整Compose文件)
  • World Action Model的本质:视频动作统一建模
  • 当网盘下载不再烦恼:LinkSwift如何让文件获取变得简单
  • 鸿蒙系统开发者如何快速接入大模型服务,使用Taotoken实现多模型调用
  • 别再死磕environment.yml了!手把手教你用pip install逐个搞定TensorFlow 1.14.0环境
  • 人工智能---深度学习中的MLOps与WB
  • 越南黑客组织利用GitHub构建僵尸网络:近一年投放600余个StealC恶意压缩包
  • 在多轮对话场景下感受 Taotoken 对上下文长度的稳定支持
  • Python医疗影像预处理崩溃全记录(CT/MRI/DR三模态调试避坑手册)
  • TouchGal完整指南:打造高效开源Galgame社区平台的终极方案
  • 从零开始学习数字电路 | Learn Digital Circuits From Scratch
  • 高效二维码工具:Chrome-QRCode完整指南,5分钟掌握跨设备内容传输
  • 贵阳西服定制四家本地商家实测|客观分析,帮你选择定制渠道 - 生活测评君