资讯详情

面试官问:如何应对 JSON 幻觉?别只会加 Prompt

📅 2026/10/8 7:17:36 | 华诺云谱 👁 阅读
面试官问:如何应对 JSON 幻觉?别只会加 Prompt
导读面试官问“如何应对 JSON 格式幻觉”真正考的不是json.loads()而是你能不能让模型输出在进入生产链路前被一层层拦住。读完本篇你会拿到 30 秒与 90 秒两套回答也能带走一套能写进 Agent 系统的防线。你做过 Agent。面试官问“模型输出不是预期 JSON你怎么处理”大多数人会先答“我会在 Prompt 里要求它只返回 JSON解析失败就重试。”这句话不算错。但面试官如果接着问“JSON 解析成功了却把普通告警判成 P1它建议回滚一个不存在的发布版本重试两次还是错你让它继续猜吗”这时如果只会说“再优化 Prompt”基本就暴露了你做的是会说话的 Demo不是能进生产的 Agent。能解析 JSON只说明模型交了答题卡不说明它答对了题。一、先让你答错一次一段 JSON差点让服务回滚小明给团队做了一个值班 Agent。它会读取监控摘要、最近一次发布记录和错误日志然后输出一张“故障处置建议卡”供告警平台决定是通知值班同学还是调用受控的回滚工具。下游最早的代码很朴素import jsondef handle_incident_response(response_str: str) - None: data json.loads(response_str) # alert_platform 换成你自己告警平台的客户端这里仅示意下游怎么消费这三个字段 alert_platform.create_ticket( servicedata[service], severitydata[severity], actiondata[recommended_action], )测试时模型每次都返回{ service: checkout-api, severity: P2, recommended_action: escalate}跑得很顺。直到小明一度觉得结构化输出嘛一行json.loads()的事。然后值班环境给他上了一课。1.1 第一种翻车连 JSON 都不是模型先解释了两句再给 JSON根据最近 5 分钟的错误率我建议优先观察json{service: checkout-api, severity: P2, recommended_action: observe}也可能是模型输出被截断{service: checkout-api, severity:这类问题会让json.loads()抛异常。它刺耳但不算最可怕——至少你立刻知道系统坏了。1.2 第二种翻车JSON 合法接口契约却变了有一次模型返回{ target_service: checkout-api, priority: P2, action: escalate}括号、引号、逗号都很完美。可下游要的是service、severity、recommended_action。于是有的框架抛KeyError有的框架把缺失字段吞成None最后出现一张“未知服务、未知等级”的工单。1.3 第三种翻车最危险——格式完美判断却错了{ service: checkout-api, severity: P1, recommended_action: rollback, change_id: deploy-2026-09-04-999}它是合法 JSON字段名也对rollback甚至是系统允许的动作。但真实监控只是单个机房短暂抖动当前没有正在生效的发布变更change_id也是模型自己编的。如果这段 JSON 直接进入工具执行链路问题就从“模型答错了”升级为“系统替模型做错了事”。生产里最危险的幻觉不是让程序报错而是让程序平静地执行错误。这就是这道面试题的核心。你要解决的从来不是“怎样把文本切成 JSON”而是怎样把不可信的模型建议变成可验证、可拒绝、可审计的工程输入。二、这题真正考什么不是格式是信任边界面试官问 JSON 幻觉通常在考三件事。考察维度他想听什么容易失分的回答有生产味的回答机制边界Prompt、Json Mode、Structured Outputs 各管什么“让模型严格返回json”“先区分语法、结构、语义和执行风险”数据契约字段、枚举、范围、来源由谁裁决“能parse就能用”“Schema 定型业务代码验证事实”故障治理出错后如何止损、恢复、追踪“失败就无限重试”“分类、限额 重试、降级、挂起、审计”换句话说面试官在确认你把 LLM 当作可信服务还是当作一个必须验收的外部依赖我的答案很明确模型可以很聪明但不能因此跳过验收。三、先给你 30 秒回答版本时间紧时可以直接这样答“我不会只靠 Prompt 要求模型返回 JSON。生成侧会优先使用 Structured Outputs 或严格的 Tool Calling Schema把字段、类型、枚举和额外字段约束住先降低语法和结构错误。服务端仍然会用 Pydantic 或 JSON Schema 再校验一次并用数据库、权限和状态机验证业务事实因为格式合法不代表内容真实。失败时我会区分拒答、截断、Schema 失败、业务校验失败和下游故障只有可修复的格式或结构问题才做一到两次定向重试业务事实错误不能让模型猜。高风险工具调用还要经过确认、幂等和审计模型只能提议最终执行权在服务端。”这段回答里有五个关键词原生结构化输出、服务端校验、业务事实、有限重试、执行隔离。如果你能把它们串成因果关系而不是背成名词列表这题就稳了一半。四、第一道门别把 Prompt 当成约束4.1 三档机制到底差在哪很多文章把“让模型返回 JSON”的办法混在一起讲。其实它们的防线建在不同位置。要分清一个方案就回答三个问题它是干啥的怎么用优点和缺点各是什么先看一张总览表方案是干啥的怎么用优点缺点Prompt约束在提示词里“口头要求”返回JSON直接改提示词文本零成本、所有模型通用只是概率随时可能失效JSON Mode打开“只输出合法JSON的开关”response_format{“type”:“json_object”}专治括号没闭合、混进解释中文不管字段名和内容对不对Structured Outputs用JSON Schema 在生成阶段锁死结构response_format 传json_schema字段、类型、枚举都锁死只保证“长得对”不保证“是真的”Tool Calling把操作定义成受约束的工具结果传tools 参数参数严格遵循工具契约不保证调用被授权、后果安全下面逐个展开先看最原始的一种。Prompt 像这样请只返回 JSON禁止输出解释文字。优点不用改任何代码所有模型都吃这一套写起来最省事。缺点它只是“提高概率”不是“保证”。上下文变长、用户输入夹带干扰、模型换版本、温度升高都可能让模型“不小心话多了”。用 Prompt 守生产协议就像在机房门口贴纸未经允许请不要进入。礼貌有了。门禁没有。4.2 JSON Mode箱子能打开不代表里面装对了JSON Mode 是各家 API 提供的一个输出开关意思是“你只给我 JSON别的话少说”。怎么用以 OpenAI 为例其他家参数名略有不同import jsonfrom openai import OpenAIclient OpenAI()resp client.chat.completions.create( modelgpt-5, messages[ # 小坑OpenAI 要求提示词里必须出现 JSON 这个词否则会报错 {role: system, content: 把结果以 JSON 格式返回。}, {role: user, content: 当前 checkout-api 状态如何}, ], response_format{type: json_object}, # 关键打开 JSON Mode)print(json.loads(resp.choices[0].message.content))开了它你就更有把握执行json.loads(response)优点专治“没闭合大括号”“混进解释文字”这类语法病能放心json.loads()。缺点它只承诺“是合法 JSON”不承诺“内容符合你的接口”。你期待{ service: checkout-api, severity: P2}它仍可能给你{ system: checkout-api, level: 严重, note: 建议尽快关注}这也是合法 JSON。你的下游不认识它。4.3 Structured Outputs把 Schema 变成生成边界Structured Outputs 的关键不是“模型更听话”而是平台在生成阶段根据 JSON Schema 施加约束。不同平台的实现与支持子集并不完全相同常见做法是 grammar 或约束解码当前只允许生成符合 Schema 的 token。怎么用先把你想要的字段结构写成 JSON Schema这份“图纸”长这样再塞进response_format以 OpenAI 为例from openai import OpenAIclient OpenAI()# 故障处置建议的图纸字段、类型、枚举都在这里定死incident_schema { type: object, additionalProperties: False, required: [service, severity, recommended_action], properties: { service: {type: string, enum: [checkout-api, search-api, profile-api]}, severity: {type: string, enum: [P1, P2, P3, none]}, recommended_action: {type: string, enum: [rollback, restart, escalate, observe]}, },}resp client.chat.completions.create( modelgpt-5, messages[{role: system, content: 根据监控信息输出故障处置建议。}], response_format{ type: json_schema, json_schema: { name: incident_decision, strict: True, # 严格模式禁止出现 Schema 之外的字段 schema: incident_schema, }, },)print(resp.choices[0].message.content)在严格模式下模型不应把service偷换成target_service也不该临时增加一个run_shell_command字段。优点字段、类型、枚举、额外字段都被约束在生成阶段结构错误大幅下降。缺点它只保证数据“长得对”不保证“是真的”。但注意这个转折Structured Outputs 能让数据“长得对”不能让数据“是真的”。模型仍可能在允许的枚举中错选P1也可能选对rollback却给出一个不存在的change_id。这也是为什么我不喜欢把它宣传成“彻底解决 JSON 幻觉”。它解决的是协议层的一大块麻烦不是生产正确性的全部。五、第二道门Schema 之后谁来验证事实5.1 一句话定义生产级结构化输出不是让模型生成一段漂亮 JSON而是让每个字段都接受与其风险匹配的验收。可以把 JSON Schema 想成故障工单的模板服务名写在哪、等级能选什么、动作有哪几种。Pydantic、监控系统、发布平台和权限系统则像真正的事故指挥台告警是否存在服务是否真的异常有没有可回滚的版本当前账号有没有执行资格工单写得工整不等于故障真的发生过。5.2 三层验收链路模型响应状态与 JSON 语法 ↓应用 Schema字段、类型、枚举、范围、跨字段关系 ↓可信业务系统监控事实、发布记录、权限、状态机 ↓受控工具执行确认、幂等、审计验收层拦截什么例子响应与语法非JSON、截断、拒答、空输出少右括号、输出长度耗尽应用Schema缺字段、多字段、非法枚举、错误范围severity“critical”、多出危险参数业务事实模型编造的ID、错误判断、越权状态不存在的发布版本、普通波动被判P1执行控制重复调用、未确认的高风险操作重复回滚、无授权重启服务5.3 一段能直接运行的最小示例下面不绑定任何模型厂商 API只演示最重要的边界模型候选输出通过应用 Schema 后仍要再做可信事实校验。先安装依赖pip install pydantic2.0这段代码做五件事限制服务、故障等级与动作的可选范围规定rollback必须同时具备 P1 等级和发布版本号模拟模型第一次返回合法 JSON、但违反契约将一条精确错误摘要交给下一轮修复通过 Schema 后再检查发布记录是否真实存在。import jsonfrom typing import Literalfrom pydantic import BaseModel, ConfigDict, ValidationError, model_validatorclass StructuredOutputFailed(Exception): 模型在限定修复次数内仍无法满足输出契约。class IncidentDecision(BaseModel): # 禁止模型自行增加未定义字段 model_config ConfigDict(extraforbid) service: Literal[checkout-api, search-api, profile-api] severity: Literal[P1, P2, P3, none] recommended_action: Literal[rollback, restart, escalate, observe] change_id: str | None None model_validator(modeafter) def validate_action_contract(self): # 回滚是高风险动作必须由最高等级告警触发且必须指定发布版本 if self.recommended_action rollback: if self.severity ! P1 or not self.change_id: raise ValueError(rollback 必须同时具备 P1 severity 与 change_id) # 没有故障时只能观察不能让模型顺手重启服务 if self.severity none and self.recommended_action ! observe: raise ValueError(severity 为 none 时recommended_action 必须为 observe) return selfdef summarize_error(error: Exception) - str: 只保留首条关键错误避免把整段堆栈灌回模型上下文。 if isinstance(error, ValidationError): first error.errors()[0] location ..join(str(part) for part in first[loc]) or 对象 return f字段 {location} 校验失败{first[msg]}实际输入为 {first.get(input)!r} return fJSON 解析失败{error}def deployment_exists(service: str, change_id: str | None) - bool: 真实项目中应查询发布平台此处用可信记录模拟。 active_changes { checkout-api: {deploy-2026-09-04-042}, search-api: set(), profile-api: {deploy-2026-09-04-017}, } return change_id in active_changes[service]def validate_candidates(candidate_outputs: list[str]) - IncidentDecision: max_repairs 1 last_error for attempt, raw in enumerate(candidate_outputs): if attempt max_repairs: break try: payload json.loads(raw) decision IncidentDecision.model_validate(payload) # 这一层不是模型能证明的必须到发布平台查真实记录 if decision.recommended_action rollback: if not deployment_exists(decision.service, decision.change_id): raise StructuredOutputFailed(change_id 不存在或不属于目标服务阻断回滚) return decision except (json.JSONDecodeError, ValidationError) as error: last_error summarize_error(error) print(f第 {attempt 1} 次校验失败{last_error}) # 真实接 LLM 时仅回传 last_error让模型按原 Schema 定向修复。 raise StructuredOutputFailed( f结构化输出在 {max_repairs 1} 次尝试后仍失败{last_error} )if __name__ __main__: candidates [ # JSON 合法但 severity 不在契约允许的枚举中 {service: checkout-api, severity: critical, recommended_action: rollback, change_id: deploy-2026-09-04-042}, # 模拟模型根据错误摘要修复后的输出 {service: checkout-api, severity: P1, recommended_action: rollback, change_id: deploy-2026-09-04-042}, ] result validate_candidates(candidates) print(验收通过, result.model_dump())运行结果第 1 次校验失败字段 severity 校验失败Input should be P1, P2, P3 or none实际输入为 critical验收通过 {service: checkout-api, severity: P1, recommended_action: rollback, change_id: deploy-2026-09-04-042}这里最值得记住的不是 Pydantic 语法而是顺序模型说“应该回滚”≠系统允许它回滚Pydantic 通过只说明应用层契约通过deployment_exists()通过才说明这条变更在可信发布系统里真的存在。Schema 校验负责判断“像不像”业务校验负责判断“是不是真的”。六、第三道门失败后怎么做才不把错误变贵6.1 先分类再谈重试“校验失败就重试”是最常见的半对答案。对在哪里格式错误确实可能靠一次定向修复解决。错在哪里有些错误根本不该让模型再猜。失败类型典型现象是否让模型重试应对动作安全拒答模型明确拒绝生成否返回安全兜底或转人工响应截断输出未完成、长度耗尽视情况调整输出预算后重试一次JSON/Schema失败非法枚举、缺字段、类型错误是回传精确错误摘要最多1-2次业务事实失败发布版本不存在、告警已恢复通常否查询可信系统、追问或阻断下游暂时故障发布平台503、数据库超时是但不访问模型调用层退避重试保留幂等键例如change_id不存在不是模型“格式没写好”而是它在编造事实。你让它再写十次只是在让它换十种方式编。6.2 自纠错循环的三条铁律第一限制次数。重试一般给一到两次。第一次可能是模型忽略了某条约束第二次仍错就应该怀疑输入信息、Schema 设计或任务边界而不是追加第 37 次重试。第二回传精确摘要。不要把几十行ValidationError原样扔回上下文。模型真正需要的是哪个字段错、规则是什么、刚才填了什么。字段 severity 必须是 P1、P2、P3、none 之一实际值为 critical。第三修复后重新验收。第二次输出仍然是不可信输入。它不能因为“已经被修过”就自动获得绿灯。重试不是给模型发免死金牌而是再给它一次参加验收的机会。6.3 降级要预先定义不要临时糊弄“流程不能停所以先塞一个默认值”是典型的生产事故预备动作。可以降级的是展示型字段例如故障摘要、建议观察时长。它们失败时可以明确展示“暂无法生成”。不能降级的是决策型字段服务名、严重等级、发布版本、执行动作。一旦它们不可信就应该阻断、要求人工确认或者把任务挂起。字段性质是否降级示例展示型、非核心可以明确标记未知告警摘要、观察建议决策型、核心不可以severity、service有副作用参数绝对不可以change_id、回滚目标、删除资源id6.4 观测别只盯“成功率”如果你只看“Agent 调用成功率 99%”那剩下的 1% 可能正好是一条错误回滚指令。建议记录如下指标并对日志中的用户数据、密钥、命令参数做脱敏request_idschema_versionmodel_namefinish_reasonstructured_output_successschema_validation_failurebusiness_validation_failureretry_countfallback_typetool_nametool_execution_resultlatency_mstoken_usage有这些数据才看得出问题到底来自模型升级、Schema 演进、输入缺失还是下游服务不稳定。没有观测的重试就像在黑屋里反复按电灯开关。七、最后一道门Agent 调工具时模型只能提议7.1 不要让模型吐出“动作 JSON”就直接执行初学者很容易定义这种协议{ action: rollback_deployment, service: checkout-api, change_id: deploy-2026-09-04-042}然后服务端看到actionrollback_deployment直接调发布平台。危险不在于 JSON而在于你让模型同时决定了做什么、对谁做、什么时候执行。更合理的方式是 Tool Calling把操作定义成受约束的工具接口rollback_deployment( service: checkout-api | search-api | profile-api, change_id: string, reason: confirmed_regression | security_incident)模型只能提出调用建议。真正的执行器仍必须从发布平台读取变更是否存在、是否仍可回滚校验当前操作者、Agent 身份与环境权限判断是否满足回滚策略和审批条件向值班同学展示目标服务、版本和影响范围要求确认生成幂等键并写入审计日志执行后回查实际结果而不是相信“工具已调用”。模型可以提议代码必须裁决模型可以调用工具系统不能交出主权。7.2 幂等性真正容易被追问的细节假设回滚请求已经到达发布平台但网络在返回结果前超时。Agent 不知道操作是否成功于是又发了一次。第一次已经回滚。第二次可能回滚到更早的版本或者直接触发异常。因此发布、重启、发消息、删数据这类操作都应该带由服务端生成并持久化的幂等键。关键不是某个固定拼接公式而是同一个业务意图重放时系统必须识别它并返回第一次的结果而不是再执行一次。这也是为什么“JSON 幻觉”最终会讲到权限、状态机、确认和审计——模型输出只是这条风险链的入口。八、面试官继续追问你怎么接追问一“开了 Structured Outputs还要 Pydantic 吗”容易失分“不用Structured Outputs 已经保证 JSON Schema 了。”加分回答“还需要。Structured Outputs 是生成侧防线主要降低语法和结构偏离Pydantic 是应用服务侧防线确保进入业务代码的数据符合应用模型。两者之后还要查监控、发布记录、权限和状态机因为它们验证的是事实和授权不是 JSON 形状。”追问二“为什么不能无限重试直到它合法”容易失分“多试几次总会成功。”加分回答“我会按错误类型给重试预算。截断和 Schema 失败可以带精确错误摘要修复一到两次发布版本不存在、无权限这类业务事实错误不能让模型猜。发布平台 503 则由调用层按退避策略重试不应该重新让模型决策。每一类重试都要有幂等和日志。”追问三“模型建议回滚怎么保证不会误操作”容易失分“工具参数也做 JSON Schema 校验。”加分回答“工具 Schema 只解决参数格式。模型只是提议者执行前我会从发布平台重新读取变更记录校验当前环境、用户权限、审批规则与状态机高风险操作需要人类确认、限额或白名单。执行请求带幂等键并记录审计日志最终操作结果还要回查。模型没有最终执行权。”九、最后复述90 秒回答框架面试时你可以这样完整回答“我会把 LLM 输出当作不可信的外部输入而不是把 JSON 解析成功当作正确。生成侧优先使用 Structured Outputs 或 Tool Calling Schema约束字段、类型、枚举和额外字段降低语法和结构幻觉但这不保证业务事实正确。服务端我会用 Pydantic 或 JSON Schema 再校验应用模型并到监控、数据库、发布平台和权限系统验证真实状态。失败处理按类型区分拒答和业务事实错误不盲目重试截断或可修复的 Schema 错误带精确错误摘要最多修复一到两次下游临时故障由调用层按退避和幂等策略处理。重试耗尽后非核心展示字段可以明确降级核心决策字段则阻断或转人工。对回滚、删除等有副作用的工具模型只能提议调用服务端还要做事实校验、权限、确认、幂等和审计确保最终执行权不在模型手里。”说完之后停一下。你没有背一串 API 参数但你把模型、协议、业务系统和执行器的责任边界说清楚了。这才是面试官真正想听的东西。十、把它记成一个工程公式结构化生成 应用 Schema 校验 可信事实与权限校验 有预算的重试与降级 幂等、确认、审计 可被信任的 Agent 执行链路格式正确是模型通过了格式检查业务正确才是它真的答对了题。不要让模型裸写 JSON 进入业务系统。模型负责建议契约负责约束代码负责拍板。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑