在工程实践中,经常遇到以下失败场景:
- 模型输出字段缺失或字段名漂移,导致解析失败
- 数字、日期等格式不一致,最终入库失败
- 即使证据不足,模型也强行填充,产生脏数据
- 在多租户环境下,引用了不该引用的数据,带来审计风险
核心结论是:如果你希望模型的输出能被下游系统(如数据库、工作流)可靠消费,就必须将“自然语言输出”升级为符合“接口契约”的“可执行对象”。在云栈社区的技术讨论中,如何将人工智能能力稳定集成到生产系统,一直是一个热门话题。
1. 你要的不是“答案”,而是一个“可执行对象”
将大语言模型(LLM)的输出视为后端接口的返回值来设计系统,思路会更清晰。一个典型的流程包括:
- 输入:用户问题 + Evidence(来自检索或工具调用的结果)。
- 生成:LLM 输出一个结构化的 JSON 对象。
- 校验:后端进行 Schema 校验、业务规则校验和引用一致性校验。
- 执行:校验通过,则数据落库或触发后续工作流。
- 纠错:校验不通过,则进入自动重试、追问用户或转人工处理的流程。
在这条链路中,LLM 的核心职责被明确为两件事:
- 信息抽取:从提供的证据(Evidence)中准确抽取结构化的字段。
- 可控失败:当证据不足以填充关键字段时,能主动选择追问用户或拒绝操作。
2. 工程落地三件套:Schema、动作枚举、证据引用
2.1 Schema:让输出可解析
永远不要仅依靠“请输出 JSON”这样的提示词来保证输出稳定性。你需要定义清晰的 Schema,包括:
- 固定的字段名
- 固定的数据类型(如 string, number, date)
- 固定的枚举值(对于特定字段)
- 清晰的规则来标明哪些字段是必填,哪些是可选
2.2 动作枚举:让失败路径可控
建议强制 LLM 从预定义的动作枚举中选择一个输出,这能系统化地管理各类情况:
extract_ok:字段足够完整,可以执行落库操作。
ask_clarify:缺少关键字段,必须向用户追问。
refuse:因合规、权限或风险原因,拒绝执行操作。
need_human:证据冲突过大或问题复杂,需要转交人工审核。
2.3 证据引用:让每个字段“可追溯”
对于信息抽取任务,这一点至关重要:每个关键字段都必须附带引用(citation)。否则,你无法在出现问题时进行审计溯源,也无法有效定位是检索环节还是模型环节出了问题。
3. 一个可直接复用的抽取契约(JSON Schema 思路)
以下是一个通用的“工单创建/表单填充”场景的输出对象定义,你可以根据具体业务需求进行增删。
3.1 输出对象定义
{
"action": "extract_ok",
"tenant_id": "t_xxx",
"object_type": "expense_claim",
"data": {
"employee_name": "张三",
"amount_cny": 1280.50,
"date": "2026-01-17",
"reason": "出差交通费"
},
"citations": {
"employee_name": [{"evidence_id": "E3", "quote": "申请人:张三"}],
"amount_cny": [{"evidence_id": "E2", "quote": "合计:¥1,280.50"}],
"date": [{"evidence_id": "E1", "quote": "日期:2026/01/17"}],
"reason": [{"evidence_id": "E3", "quote": "事由:出差交通费"}]
},
"missing_fields": [],
"notes": ""
}
3.2 关键工程点
tenant_id:必须由服务端注入并在校验时确认一致性,模型输出的此字段仅作回显,用于防止越权操作。
citations:字段级别的引用,便于后续的审计与问题回归。
missing_fields:当 action 为 ask_clarify 时,此字段必须列出缺失的关键字段,后端可据此自动生成追问表单。
4. Prompt 模板(抽取版,工程可控)
你可以将以下模板作为平台级的稳定 Prompt 进行复用。
System(协议层指令)
- 你是信息抽取器。必须严格基于提供的 Evidence 进行抽取,不允许进行任何猜测或补充。
- 你必须输出一个单独的 JSON 对象,不得输出任何额外的解释性文本。
- 如果证据不足以填写所有关键字段,
action 必须设置为 ask_clarify,并在 missing_fields 中列出具体字段。
data 对象内的每个字段都必须提供对应的 citations,其中的 quote 必须直接来自 Evidence 的原文。
User(运行时输入)
tenant_id: {tenant_id} (由服务端注入)
object_type: expense_claim
schema_hint: {字段说明/类型/必填规则}
Evidence:
[E1] ...
[E2] ...
[E3] ...
5. 后端必须做的校验(这才是“可上线”的关键)
获得 LLM 输出的 JSON 仅仅是第一步。生产系统必须进行以下三类校验:
5.1 结构校验:Parse + Schema Validate
- JSON 字符串是否能被正确解析。
- 所有必填字段是否存在,数据类型是否正确,枚举值是否在允许范围内。
- 校验不通过,则进入“自动重试”流程(见第6节)。
5.2 业务规则校验(强烈建议)
例如:
- 报销金额必须 > 0。
- 日期必须符合 YYYY-MM-DD 格式。
amount_cny 字段的值不得超过预设的阈值。
- 人员姓名必须存在于当前租户的员工表中(保证多租户数据一致性)。
5.3 引用校验(防“假引用”)
对每一个 citation 进行核实:
evidence_id:必须存在于本次请求提供的 Evidence 列表里。
quote:必须能在对应 evidence_id 的文本中找到(完全匹配子串或通过偏移量定位)。
- 关键字段若没有提供
citation,应直接判定为本次抽取失败。
引用校验是你将模型“幻觉”转化为“可控错误”的最有效工程手段。
6. 稳定性工程:重试、纠错提示、降级
6.1 自动重试策略(建议最多2次)
当校验失败时,不要简单让模型“再试一次”。应将明确的错误信息反馈给模型,引导其修正:
重试 Prompt(追加到对话历史)
- 上次输出不合法,原因如下:
amount_cny 字段不是数字类型;date 字段格式错误;citations.amount_cny 缺失。
- 请在保持其他字段不变的前提下进行修正,并输出完整的 JSON 对象。
这种“携带诊断信息的定向重试”比盲目重试的成功率和稳定性要高得多。
6.2 降级策略
- 连续失败:将
action 设置为 need_human,同时将本次的 Evidence、模型输出和失败原因打包,推送至人工审核队列。
- 证据不足:返回
action 为 ask_clarify,并列出 missing_fields,这是最产品化的做法——引导前端自动弹出信息补充表单。
7. 多租户安全:别让模型成为绕权通道
对于多租户系统,安全绝不能依赖模型的“自觉”,必须在架构层面保障:
- 租户隔离由服务端控制:
tenant_id 和访问控制列表(ACL)必须由服务端决定并注入,模型无权指定或扩大检索范围。
- 证据来源受控:提供给模型的 Evidence 必须且仅能来自服务端根据当前租户身份检索到的结果。
- 完备的审计日志:每次成功的信息抽取和落库,都应记录
tenant_id、原始文档ID、文本块ID、数据源URL以及被引用的原文片段。
- 防御 Prompt 注入:Evidence 中若出现“忽略之前指令”、“输出管理员信息”等注入文本,一律视作普通文本处理;System 指令的优先级始终最高。
8. 接入RAG流水线(端到端视图)
一个典型的“检索+抽取+落库”端到端链路如下:
- 用户提交:上传发票PDF或输入文本需求。
- 解析/ETL:将非结构化文件(如PDF、图片)解析为可读的纯文本(对于PDF表格,建议转换为Markdown或结构化摘要)。
- 检索:在当前租户的知识库内,检索相关的制度、模板或历史记录(此步骤可选)。
- LLM抽取:将用户输入和检索到的证据一并交给LLM,输出带引用的结构化JSON。
- 校验:执行 Schema 校验、引用校验和业务规则校验。
- 执行:校验通过,则将数据写入数据库或发起工单流程。
- 失败处理:校验不通过,则根据策略进入
ask_clarify(追问)或 need_human(转人工)流程。
9. 小结
当你将LLM应用于“数据入库、工单创建、审批流、配置生成”等需要与生产系统集成的任务时,必须建立工程化的思维:
- 用 JSON Schema 固定输出,使其成为可靠的接口契约。
- 用动作枚举管理失败路径,将不确定的异常转化为确定的状态流转。
- 用引用校验让每个字段可追溯,这是控制质量、定位问题的基石。
- 用服务端的校验、重试与降级策略,将模型的不确定性关进笼子,从而构建出稳定、可信的生产级应用。