让回复可核对:资料出处与失败边界

给每个结果一个可追溯的来源,并把「无法回答」当成正常结果。

学习目录与本页目录阶段 1AI Agent 基础入门阶段 2用 Python 跑通第一个回复草稿 Demo阶段 2用 Python 完成第一次真实模型调用阶段 3让回复可核对:资料出处与失败边界阶段 4从本地到上线:部署前要检查什么
01先定义结构化结果02来源应当指向具体资料03把缺失与冲突显式展示04保留人工确认

01先定义结构化结果

不要让界面只接收一段文本。沿用上一个 Demo,输出 status、draft 和 sources 三个字段。状态用于控制界面,草稿用于阅读,来源用于核对。

{
  'status': 'draft',
  'draft': '体验版试用期为 7 天……',
  'sources': ['D01']
}

status 为 missing 时,sources 应为空,草稿明确说明缺少依据;invalid 表示输入为空或超过长度限制。

02来源应当指向具体资料

每条资料有稳定编号。真实业务还需要文档标题、版本、更新时间和片段位置。不要只给出「来自知识库」,那无法帮助审核者核对。

检索命中仅说明找到了候选资料,不说明答案一定正确。如果引入模型生成,逐条检查回复中的事实是否得到检索片段支持。模型给出的引用编号也需要验证,不能直接相信。

03把缺失与冲突显式展示

资料缺失时返回可理解的说明,要求补充资料或转交人工。资料冲突时列出冲突来源,由业务负责人确认当前版本。请求超时、解析失败和无权限应有不同状态,不能伪装成成功回复。

本例只实现固定资料的匹配和缺失分支。版本冲突、权限过滤、模型超时和重试尚未实现,生产项目需要补齐。

04保留人工确认

回复先标成「草稿」。审核人核对出处、适用范围和具体措辞,再决定是否发送。不要把生成草稿和对外发送绑在一起。若以后接入邮件或客服工具,发送动作应有独立权限、确认和审计。

动手:验证资料缺失,再恢复资料

先完成上一课的 Python Demo,保留原始 reply_assistant.py。不要直接删掉源码中的 D01 后再启动:启动检查预期 D01 存在,会先触发 AssertionError。下面通过导入函数,在测试进程内临时移除资料,不修改原文件。

在同一目录新建 check_missing.py,复制以下代码:

from reply_assistant import DOCUMENTS, answer

original = DOCUMENTS.copy()
assert answer('试用几天?')['sources'] == ['D01']
try:
    DOCUMENTS[:] = [doc for doc in original if doc[0] != 'D01']
    result = answer('试用几天?')
    assert result['status'] == 'missing'
    assert result['sources'] == []
    print(result['draft'])
finally:
    DOCUMENTS[:] = original

assert answer('试用几天?')['sources'] == ['D01']
print('检查通过:缺失时不编造,恢复后可核对来源。')

在该目录运行:

python check_missing.py

Windows 也可以使用 py check_missing.py。预期输出两行:

资料不足,请补充资料或转交人工。
检查通过:缺失时不编造,恢复后可核对来源。

为什么导入不会进入提问循环?原示例把启动检查与输入循环放在 if __name__ == '__main__': 内;导入时只加载资料和函数。可参考 Python 3.10 官方说明。本练习适用于 Python 3.10 及更新版本,仍只测试固定关键词匹配,不包含模型或真实检索。

完成标准:资料存在时引用 D01;移除后返回 missing 且来源为空;恢复后再次引用 D01。不要通过删除断言或使用 python -O 跳过检查来获得「通过」。最后运行原示例确认启动检查仍通过,再进入下一篇部署检查。