把模型能力写成可检验的任务契约
把分类与提取任务拆成能力、上下文、输出和拒绝契约,核验结构之外的事实、来源与执行权限。
设计带证据与拒绝状态的任务契约,并用错误样本区分提示、检索和程序校验问题。
资料分类助手收到一份文本,准备给出类别与摘要。需求如果只写“准确理解资料”,开发者无法判断什么输出算成功。把输入来源、可用材料、输出字段、证据与拒绝条件写成任务契约,才能分别检查模型建议和程序执行。
本课用一句虚构价格资料演示提取子任务,再把同一思路用于资料分类。模型调用并未在示例中运行;代码负责核验已经给出的候选答案,说明提示词以外还需要哪些确定性约束。
能力清单要连接到具体任务
文本模型可以用于分类、提取、摘要与候选生成,某些模型还支持视觉、语音或工具调用。能力名称不能直接说明任务质量。分类需要看易混类别,提取需要检查字段与证据,摘要需要判断遗漏,工具调用需要验证选择与参数。
先把需求分成可以观察的动作。资料助手先判断是否属于允许类别,再提取标题与来源,无法判断则标记 needs_review。对只有图片或受损文本的输入,选择支持对应模态的处理路径,或者明确拒绝,而不能把所有输入都硬塞进文本任务。
选择模型时比较相同样本上的结果、延迟、使用成本与可用接口。公开能力声明可以帮助筛选,最终判断仍来自任务评估。复杂推理能力也不意味着简单提取任务值得付出相同资源,应用可以为不同步骤采用不同处理方式。
指令与不可信资料分别安排
提示词可以说明角色、任务、允许材料、输出要求和示例,但不同 API 的消息层级与字段有各自定义。不要把某个平台的 system、developer 或 tool 语义直接当成所有模型的统一协议。实施前应核对对应官方文档。
输入文档中出现“改写规则”或“调用删除工具”,应视为待处理内容。来源文本不能取得授权。把资料与任务说明清楚分开有助于理解边界,但执行权限仍要由程序检查,分隔符不会消除 prompt injection。
示例要展示真实需要的边界,使用合成资料即可。加入一条证据不足输入,并明确返回未知,而不是用编造答案维持格式。不要把某一句“请认真思考”写成可保证成功的技巧;提示效果要通过固定样本和失败类别比较。
上下文由选择与预算构成
上下文可能包括用户问题、有效规则、检索材料、工具结果和已有状态。窗口预算按 token 计算,并与生成输出共享或受具体接口限制;字符长度不能直接作为保证。长历史中已经过时的决定可能干扰当前任务。
先筛选与当前问题有关的状态,再检索需要的材料,保留文档 ID、版本与片段来源。摘要可以减少长度,但应标明它替代了什么,以及哪些细节可能丢失。对精确价格、编号和引文,保留原文通常比再次概括更容易核验。
截断时应有可观察结果,例如返回“材料不完整”或转入分段处理。若关键限制被删掉,不能继续把输出当作完整任务的答案。工具返回也要按信任边界处理,远程错误页或旧数据不能直接混入权威上下文。
输出形状与内容事实分别验证
Structured Outputs 可在受支持的模型和接口中约束指定 schema,官方文档同时说明结构正确的输出仍可能出错。它有产品支持范围与 schema 限制,也需处理 refusal、未完成或截断结果,不能假定每次调用都得到业务对象。
JSON 对象有 item、price、quote 三个字段,只说明形状可解析。item 必须来自输入,price 必须符合提取规则,quote 必须确实出现在来源里。业务校验应在落库或执行前完成,不能让下游把任何合法 JSON 当作正确事实。
下面固定来源为 Item A,要求价格 12,并核验引文。缺失 quote 与 bool 价格也被拒绝,避免类型宽松导致错误接纳。
source = "Item A costs 12 units."
def verify(answer):
if not isinstance(answer, dict):
return False
quote = answer.get("quote")
return (answer.get("item") == "A" and type(answer.get("price")) is int
and answer["price"] == 12 and isinstance(quote, str)
and quote == "costs 12 units" and quote in source)
assert verify({"item": "A", "price": 12, "quote": "costs 12 units"})
assert not verify({"item": "B", "price": 12, "quote": "costs 12 units"})
assert not verify({"item": "A", "price": 12})
assert not verify({"item": "A", "price": True, "quote": "costs 12 units"})
print(verify({"item": "A", "price": 12, "quote": "costs 12 units"}))
实际输出是 True。合法候选通过,错对象、缺引文与不合法价格类型被拒绝。函数硬编码了这个教学样本的正确事实,只能作为契约测试;它不具备通用提取能力,也不能识别另一篇文章是否真实。
拒绝与不确定性属于正常输出
证据不足、冲突、输入损坏和任务不受支持,需要不同的状态与下一步。把这些情况全部当成调用失败,会让重试重复消耗资源;把它们全部补成确定答案,则会掩盖内容问题。为每种状态写明确的界面行为与后台分类。
置信度字段若只是模型自行报出的数字,不能默认当成校准概率。可以评估它与实际错误的关系,但阈值要用独立样本验证。更直接的依据包括必需字段完整性、来源覆盖、候选类别冲突和确定性规则通过情况。
人工复核也要显示需要判断的内容:候选类别、来源片段、缺失原因与修改入口。复核结果可以成为后续评估材料,使用前应确认数据权限与标签质量。用户点了接受不能自动说明答案在事实层面正确。
用评估决定怎样修改应用
准备固定评估集,覆盖正常、短文本、类别相似、证据缺失与注入内容。记录每个阶段的输入与版本:上下文选择、提示配置、模型、schema 和验证规则。修改提示后,比较同一组样本,观察是否改善目标错误并引入其他问题。
若来源没取到,应改检索;若字段校验缺失,应改程序;若类别说明模糊,应改定义与提示。模型输出不稳定时,可能需要缩小任务、增加证据或人工环节。不要把所有失败都归为“模型不够强”,也不要用一次成功替代覆盖性评估。
练习:交付一份可测试的分类契约
为资料助手写输入、类别表、输出字段、引文规则、拒绝状态与禁止副作用。准备至少一个无法分类和一个来源含恶意指令的样本。将价格提取示例改成多个允许对象,核验对象与价格的对应关系。
验收时,错对象不能借正确引文通过;无证据不生成事实;未完成与拒绝不会被当作成功对象;外部资料无法授予工具权限。保存失败样本与修复前后结果,明确离线验证覆盖的是契约规则,真实模型效果、token 使用与响应时间仍需另外测量。
资料来源与延伸阅读
资料核验:2026-11-10。本文为原创工程讲解,教学示例不代表线上实测。