前几章的智能体是主角(让 GPT 写公众号、让文心批量出稿、让知乎智能体写图文)。本章的智能体是一个配角——它是【异常处理台】:正常件根本不需要跟它说话,只有被挑出来的那几条才需要它。而它能不能答好,八成不取决于它多聪明,取决于你喂给它什么。
6.3.1 造好了"识别"这条工作流(机器部分);本节造那个"人机对话"的入口(人部分)。 它落在 6.2 那张流程图的第 ④ 格(人工复核)——这一格是"人"的位置,而智能体的作用是让人在这一格里看得更快。 与第二章 2.3.3 的对照:那一节的智能体是个"前台"(服务人的对话入口);本节的智能体是"异常答疑台"——同样服务人,但服务的是一个非常具体的场景。
一、本章的分工:智能体是配角,工作流是主角
先把角色摆正,这是本节最重要的一件事。
前几章的智能体都是主入口:2.3.3 的图文助手、3.3.1 的公众号 GPT、4.3.1 的文心智能体、5.3.2 的知乎智能体——用户是要跟它对话的。
本章不一样:正常件由工作流自动处理(识别 → 校验 → 填报),根本不经过对话。
| 前面几章 | 本章 | |
|---|---|---|
| 工作流 | 服务机器(管道) | 服务机器(管道)—— 主体 |
| 智能体 | 服务人(前台)—— 主体 | 服务人(异常答疑)—— 配角 |
| 什么时候用 | 每次都经过 | 只有异常经过 |
为什么本章是这个分工? 回到 6.2 那条规律:本章的批量是【行数 × 单数】,正常件太多,人看不完也问不完。
内容侧:每一篇都需要人做判断(写得好不好、有没有人味),所以对话入口是刚需。 数据侧:绝大多数单据不需要判断(数字抄对就行),所以对话入口只在出问题时才被用到。 一个反过来说的判据:如果你发现"每条都要跟智能体聊两句",那说明你的校验规则写得不够——该交给规则的事,别推给人。
二、人设设计:一个"审单员"助手
沿用第二章那套四段式人设,但每一段的内容都要按本章重写:
| 段 | 内容 |
|---|---|
| 我是谁 | 采购订单录入助手,负责解释某条为什么被标异常、并给出处理建议 |
| 我能做什么 | 解释校验发现;对照主数据说明"哪个字段有问题";给出建议值(并说明依据) |
| 我不能做什么 | ① 不能替人确认;② 不能擅自改金额、税率、数量;③ 不能补全图上看不见的字段;④ 不能凭印象报数据 |
| 怎么开场 | 收到一条异常记录的完整上下文后,先复述"这条卡在哪",再给建议 |
第二段和第三段是这个助手的全部价值所在。
第三段("我不能做什么")为什么最重要
这是全课反复出现的一条(2.4.3 的合规闸门、5.4.3 的创作声明都是同一个思路):限制比能力更重要。
具体到本章,那四条限制各自防着一个具体的坏结果:
| 限制 | 防的是什么 |
|---|---|
| 不能替人确认 | 防"责任无人承担"——6.1.2 的合规账说过:账要有人签字 |
| 不能擅自改金额、税率、数量 | 防"智能体把错数改成一个看起来对的数"——金额和税率是审计直接看的东西 |
| 不能补全看不见的字段 | 防"它替你猜"——6.3.1 那条"禁止虚构、推断、补全"的同一条规矩 |
| 不能凭印象报数据 | 防"它编一个像真的供应商、像真的单价" |
因为它是唯一一条"能力越大越危险"的。 一个只会解释的助手是安全的;一个"能替你把单子提交了"的助手,是本章最不能有的东西——因为它会抹掉那个签字的人。 这也正好接上 6.1.2 的合规账:这一章的价值里有一笔叫"合规",而合规的核心就是"谁负责"。
三、知识库放什么:本章的知识库比前几章都重要
前几章的知识库放的是"参考材料"(代表作、写作风格、平台规则)。本章的知识库放的是"这家公司的内部真相"——没有它,助手什么都答不了。
| 放什么 | 为什么必须放 |
|---|---|
| 物料主数据(编码 ↔ 名称 ↔ 规格) | 助手要把"图上写的名字"和"系统里的编码"对上 |
| 供应商主数据(名称 ↔ 编码 ↔ 结算方式) | 同上,且用于判断"这个供应商名是不是编的" |
| 税率规则(哪些税率合法、什么品类适用) | 助手要能说清"14 为什么不对" |
| 常见异常处理 SOP | 让建议保持一致,而不是每次现编 |
| 历史处理记录(同一供应商/物料的过往) | 本节 Demo 会专门演示它带来的差别 |
注意最后一行:历史处理记录是本课之前所有章节都没有的一类知识——因为前几章写文章不需要"过去怎么写",而录单据非常需要"上次遇到同样情况怎么处理的"。
因为它把"只能靠老师傅"的那部分经验变成了可检索的资料。 6.1.1 的现状三提到一个风险:RPA 干得越久,组织越可能失去懂这条流程的人(SME 流失)。 把历史处理记录沉淀进知识库,正是对抗这个风险的唯一办法——否则机器人一坏,没人知道当初为什么这么设计。
四、提示词的关键三段
本章的提示词比前几章短,但要更"硬":
第一段:输入是"完整上下文",不是"一个问题"
不要这样问:"这条为什么异常?" ← 助手只能反问你
要这样喂(6.2 那张异常表的五个块):
【单据】来源、文件名
【识别结果】完整的字段 JSON
【校验发现】系统发现了什么(可能有几条)
【主数据对照】每个编码/供应商在系统里命中了没有
【历史处理】同一供应商/物料以前怎么处理的(可选)
第五块可以没有,但前四块一块都不能少——缺一块,助手就会用猜来补。
第二段:输出是"给人看的说明",不是 JSON
这一条容易搞反:很多人会让智能体也输出 JSON(因为下游是 RPA)。 但本章的智能体下游是人——它的输出应该是一段人话:
这条卡在:第 1 行的物料编码置信度只有 0.62(低于 0.80)。
建议:请对照原图确认该编码。系统里 M1001 对应"内六角螺栓 M6×20",与图上描述一致。
依据:该供应商上月同款成交价 2.45 元,本次 2.5 元属正常浮动。
注意它有三段:卡在哪 / 建议什么 / 依据是什么。 第三段是它区别于"随口一说"的关键。
第三段:禁忌(那四条限制的提示词版)
禁止替人做最终确认。
禁止修改金额、税率、数量,只能【建议】。
禁止补全上下文中没有的字段。
所有数据必须来自给出的上下文,不得凭印象补充。
五、什么时候用智能体、什么时候用规则
这一张表是本节最实用的部分:
| 问题类型 | 交给谁 | 为什么 |
|---|---|---|
| 编码在不在主数据里 | 规则 | 确定性的查表 |
| 合计对不对 | 规则 | 确定性的算术 |
| 税率合不合法 | 规则 | 确定性的集合判断 |
| 这条为什么被判异常 | 智能体 | 需要综合上下文生成解释 |
| 该怎么改 | 智能体(给建议) | 需要结合历史与主数据推理 |
| 改完能不能放行 | 人 | 要担责 |
| 点保存 | 人 | 要担责 |
规律很清楚:前三行都是"机器能算出来的",后四行都是"要解释或要担责的"。 而中间那两行(为什么错、该怎么改)正是智能体的全部地盘——不多不少。
如果你发现智能体在做加法、在比对字符串、在查表——那它随时可能算错,而且它的错很难发现。 智能体的地盘是"解释"和"建议",不是"计算"和"判断"。 这与第一章 1.2.3 那条"确定的外框 + 弹性的内芯"是同一句话:能确定的就别交给模型。
六、动手 Demo:异常上下文装配器
它不是"演示智能体",是演示"怎么把料备齐"——因为这一节真正的技术含量在这里。
# -*- coding: utf-8 -*-
"""6.3.2 Demo:异常上下文装配器(纯标准库)
把一条异常记录装配成一段【给智能体看的上下文】,并检查五块是否齐全。
"""
import json
# 五块内容:① 单据 ② 识别结果 ③ 校验发现 ④ 主数据对照 ⑤ 历史处理(可选)
EXC = [
{"id": "E01", "src": "传真扫描件", "file": "scan_0913_02.jpg",
"recog": {"supplier": "宜昌三峡五金有限公司", "po_no": "PO-2026-0912",
"item": "M1001", "qty": 100, "unit": "个", "price": 2.5, "conf": 0.62},
"check": ["第 1 行 item_code 字符置信度 0.62,低于 0.80"],
"master": {"M1001": "命中|内六角螺栓 M6×20", "M1002": "未命中"},
"history": ["该供应商上月同款物料成交价 2.45 元"]},
{"id": "E02", "src": "Excel 报价单", "file": "quote_0913.xlsx",
"recog": {"supplier": "湖北兴发物资", "po_no": "PO-2026-0913",
"item": "M2001", "qty": 20, "unit": "箱", "price": 45.0, "conf": 0.97},
"check": ["行小计 900.00 与合计栏 950.00 不相等"],
"master": {"M2001": "命中|工业清洗剂 20kg"},
"history": []},
{"id": "E03", "src": "微信截图", "file": "wx_0913_1147.png",
"recog": {"supplier": "某五金公司", "po_no": "", "item": "M4001",
"qty": 30, "unit": "个", "price": 6.0, "conf": 0.91},
"check": ["供应商名含模糊指代【某五金公司】", "缺 po_no"],
"master": {},
"history": []},
{"id": "E04", "src": "手写送货单", "file": "hand_0913_03.jpg",
"recog": {"supplier": "宜昌长江轴承", "po_no": "PO-2026-0914",
"item": "M3001", "qty": 10, "unit": "", "price": 120.0, "conf": 0.41},
"check": ["整体置信度 0.65 低于阻断线", "unit 未识别"],
"master": {"M3001": "命中|深沟球轴承 6205"},
"history": ["该供应商惯用【套】作单位"]},
{"id": "E05", "src": "PDF 电子单", "file": "po_0915.pdf",
"recog": {"supplier": "宜昌恒达机电", "po_no": "PO-2026-0916",
"item": "M5001", "qty": 15, "unit": "个", "price": 9.5, "conf": 0.96},
"check": [],
"master": {"M5001": "命中|接线端子 6mm²"},
"history": ["该供应商历史税率均为 13"]},
]
def build(r):
return (
"【单据】来源=%s;文件=%s\n" % (r["src"], r["file"])
+ "【识别结果】%s\n" % json.dumps(r["recog"], ensure_ascii=False)
+ "【校验发现】%s\n" % ";".join(r["check"])
+ "【主数据对照】%s\n" % ";".join("%s → %s" % (k, v) for k, v in r["master"].items())
+ "【历史处理】%s" % (";".join(r["history"]) if r["history"] else "(无)")
)
def missing(r):
miss = []
if not r["src"] or not r["file"]:
miss.append("单据")
if not r["recog"]:
miss.append("识别结果")
if not r["check"]:
miss.append("校验发现")
if not r["master"]:
miss.append("主数据对照")
return miss
print("=" * 78)
print("一、装配结果(每条一段上下文)")
print("=" * 78)
for r in EXC[:2]:
print()
print(" ── [%s] ──" % r["id"])
for ln in build(r).split("\n"):
print(" " + ln)
print()
print(" (以下略去 E03~E05 的全文,只做完整性检查)")
print()
print("=" * 78)
print("二、完整性检查:五块缺哪块")
print("=" * 78)
print(" %-5s %-8s %-8s %-8s %-10s %s" % ("编号", "单据", "识别", "校验", "主数据", "历史"))
for r in EXC:
miss = missing(r)
def mk(name):
return " ✗ " if name in miss else " ✓ "
his = "有" if r["history"] else "无"
print(" %-5s %s %s %s %s %s" % (
r["id"], mk("单据"), mk("识别结果"), mk("校验发现"), mk("主数据对照"), his))
print()
print("=" * 78)
print("三、为什么这五块一段都不能少")
print("=" * 78)
print(" 本次装配里 E03 缺【主数据对照】、E05 缺【校验发现】—— 这两条在交给助手")
print(" 之前就该补齐,否则助手只能靠猜,而它猜出来的话会被人当成事实。")
print()
print(" · 缺【单据】→ 助手说不清这条是从哪来的,人也回不到原图去核。")
print(" · 缺【识别结果】→ 助手只能泛泛地说【置信度低】,说不出【哪个字段低】。")
print(" · 缺【校验发现】→ 助手不知道系统已经发现了什么,会重复报一遍。")
print(" · 缺【主数据对照】→ 助手会以为【M1002 未命中】是识别错了,")
print(" 其实那是系统里本来就没有这个编码 —— 两件事的处置完全不同。")
print(" · 【历史处理】可有可无,但有它时答案质量明显不同:")
print(" E01 有了【上月同款 2.45 元】,助手就能提示【本次 2.5 元属正常浮动】;")
print(" E04 有了【惯用套作单位】,助手就能直接建议 unit 填【套】。")
print()
print(" 一句话:智能体答得好不好,八成取决于【你喂给它什么】,而不是【它多聪明】。")
实际运行输出:
==============================================================================
一、装配结果(每条一段上下文)
==============================================================================
── [E01] ──
【单据】来源=传真扫描件;文件=scan_0913_02.jpg
【识别结果】{"supplier": "宜昌三峡五金有限公司", "po_no": "PO-2026-0912", "item": "M1001", "qty": 100, "unit": "个", "price": 2.5, "conf": 0.62}
【校验发现】第 1 行 item_code 字符置信度 0.62,低于 0.80
【主数据对照】M1001 → 命中|内六角螺栓 M6×20;M1002 → 未命中
【历史处理】该供应商上月同款物料成交价 2.45 元
── [E02] ──
【单据】来源=Excel 报价单;文件=quote_0913.xlsx
【识别结果】{"supplier": "湖北兴发物资", "po_no": "PO-2026-0913", "item": "M2001", "qty": 20, "unit": "箱", "price": 45.0, "conf": 0.97}
【校验发现】行小计 900.00 与合计栏 950.00 不相等
【主数据对照】M2001 → 命中|工业清洗剂 20kg
【历史处理】(无)
(以下略去 E03~E05 的全文,只做完整性检查)
==============================================================================
二、完整性检查:五块缺哪块
==============================================================================
编号 单据 识别 校验 主数据 历史
E01 ✓ ✓ ✓ ✓ 有
E02 ✓ ✓ ✓ ✓ 无
E03 ✓ ✓ ✓ ✗ 无
E04 ✓ ✓ ✓ ✓ 有
E05 ✓ ✓ ✗ ✓ 有
==============================================================================
三、为什么这五块一段都不能少
==============================================================================
本次装配里 E03 缺【主数据对照】、E05 缺【校验发现】—— 这两条在交给助手
之前就该补齐,否则助手只能靠猜,而它猜出来的话会被人当成事实。
· 缺【单据】→ 助手说不清这条是从哪来的,人也回不到原图去核。
· 缺【识别结果】→ 助手只能泛泛地说【置信度低】,说不出【哪个字段低】。
· 缺【校验发现】→ 助手不知道系统已经发现了什么,会重复报一遍。
· 缺【主数据对照】→ 助手会以为【M1002 未命中】是识别错了,
其实那是系统里本来就没有这个编码 —— 两件事的处置完全不同。
· 【历史处理】可有可无,但有它时答案质量明显不同:
E01 有了【上月同款 2.45 元】,助手就能提示【本次 2.5 元属正常浮动】;
E04 有了【惯用套作单位】,助手就能直接建议 unit 填【套】。
一句话:智能体答得好不好,八成取决于【你喂给它什么】,而不是【它多聪明】。
读结果,五个值得注意的地方:
-
装配器的输出里,第一块是【单据】——来源 + 文件名。 它看起来很不起眼,但它是唯一能让人"回到现场"的东西。 没有它,助手说"置信度 0.62",人不知道去哪张图上看;有了它,人可以直接打开
scan_0913_02.jpg对照。这一块的作用不是给助手看的,是给人看。 -
E01 与 E02 的对比说明了"历史处理"那块的意义。 E02 的历史是空的——助手只能说"合计不相等,请核对"。这句正确但没用,因为人本来就知道要不相等。 E01 有历史——助手能说"上月同款 2.45 元,本次 2.5 元属正常浮动"。这一句是人真正需要的信息。 同一段上下文结构,多一块,答案从"复述"变成"判断"。
-
E03 和 E05 在完整性检查里各缺一块,而这两块的性质不同。 E03 缺【主数据对照】是"漏查"——它明明该去查(供应商名可疑,更该查),但装配时没查; E05 缺【校验发现】是"漏跑"——它连校验都没跑,所以助手会以为"这条没问题"。 两种都该在交给助手之前补上——因为助手不会说"你没给我数据",它只会用上下文里有的东西硬答。
-
那句"它猜出来的话会被人当成事实"是本节最该记住的一句。 智能体的失败方式和识别不一样:识别失败你看得见(置信度低),智能体的失败是"流畅地说出一段听起来很合理的话"——而人最不容易怀疑的,恰恰是流畅的话。 这就是为什么前四块必须齐:不是为了让答案更好,是为了让它没有猜的空间。
-
最后那句"八成取决于你喂它什么",其实还可以再推一层:剩下的两成才是模型能力。 所以在设计上,投入产出比最高的做法不是"换更强的模型",而是"把上下文装配得更完整"——换模型是花钱,补上下文是花心思,而后者的效果通常更明显。
30 秒实验
把 Demo 里 E04 的 history 从 ["该供应商惯用【套】作单位"] 改成 [],再跑一次。
会发生什么:
- 完整性检查里 E04 的"历史"从"有"变成"无";
- 但它的"✓"没有变化——因为历史那一块本来就是可选的。
结论:这一块"可选",但它是"可选里最值钱的一块"。
顺着这个思路想一层:为什么把它设计成可选?因为很多情况确实没有历史(新供应商、新物料、头一回遇到这种异常)。如果强制要求,装配器会卡在"没有历史"上。
而设计成可选之后,需要一条纪律:上下文里没有的那一块,提示词里要明确说"没有"——Demo 里写的是 (无),而不是留空。留空和"填(无)"看起来差不多,但对模型的意义完全不同:留空它可能以为是漏了、从而自己猜一个;写着"(无)",它就知道这里确实没有。
常见误区
-
【本章的智能体像前几章一样是主角】——错,它是配角。 正常件由工作流自动处理(识别 → 校验 → 填报),根本不经过对话;只有被挑出来的异常才需要它。这个分工变化的理由在 6.2:本章的批量是【行数 × 单数】,正常件太多,人看不完也问不完。
-
【人设里"我不能做什么"是客套话】——错,那是全段最重要的一句。 四条限制各防一个具体的坏结果:不能替人确认(防责任无人承担)、不能改金额税率数量(防它把错数改成一个看起来对的数)、不能补全看不见的字段(防它替你猜)、不能凭印象报数据(防它编)。 一个只会解释的助手是安全的;一个"能替你把单子提交了"的助手,是本章最不能有的东西。
-
【让智能体直接输出 JSON 给 RPA 用】——错,搞反了上下游。 本章的智能体下游是人,所以它的输出应该是一段人话(卡在哪 / 建议什么 / 依据是什么);给 RPA 用的结构化结果由 6.3.1 那条工作流负责。两套东西服务两个对象,不要混。
-
【知识库随便放点平台文档就行】——错,本章的知识库必须是"只有这家公司知道"的东西。 物料主数据、供应商主数据、税率规则、异常处理 SOP、历史处理记录——没有这些,助手什么都答不了(它既不知道 M1001 是什么,也不知道 14% 为什么不对)。
-
【异常都交给智能体处理就行】——错,它只负责"解释与建议",最终判断在人。 而且有一条更实用的判据:如果发现智能体在"算"(做加法、比字符串、查表),那就用错了地方——那些是规则的活。智能体的地盘是"解释"和"建议",不多不少。
自测三问(点开对答案)
1. **为什么本章的智能体是"配角",而前面几章的智能体是"主角"?** 因为**本章的批量是【行数 × 单数】**(6.2 的结论):一批 500 张单、每张 20 行,**正常的那 425 张不需要任何对话**——**工作流直接处理掉,人只在被挑出来的少数几条上介入。** 而前几章不一样:内容侧**每一篇都需要人做判断**(写得好不好、有没有人味),所以对话入口是刚需。 **一个反过来说的判据**:**如果你发现"每条都要跟智能体聊两句",那说明校验规则写得不够**——该交给规则的事,别推给人。 2. **上下文的那五块里,哪一块是"给人看的"而不是"给助手看的"?为什么?** 是**【单据】(来源 + 文件名)**。 因为它是**唯一能让人"回到现场"的东西**:助手说"置信度 0.62",**人得知道去哪张图上看**——有了文件名,可以直接打开 `scan_0913_02.jpg` 对照。 **它的作用不是提高答案质量,是让"看不看得懂"这件事变得可能**——**没有它,人只能相信助手说的。** 3. **为什么前四块"一块都不能少"?智能体的失败方式和识别有什么不同?** 因为**助手不会说"你没给我数据",它只会用上下文里有的东西硬答**——**缺主数据对照,它会以为"编码未命中"是识别错了;缺校验发现,它会以为"这条没问题"。** **失败方式的不同**:识别失败你看得见(**置信度低,数字摆在那里**);**智能体的失败是"流畅地说出一段听起来很合理的话"**——**而人最不容易怀疑的,恰恰是流畅的话。** 所以保证前四块齐全,**不是为了让答案更好,是为了让它没有猜的空间**。- ☐ 下一节(6.4.1 RPA发起会话并识别结果)
相关笔记
- 采购订单智能识别工作流 —— 上一节的"机器部分",本节是"人机之间的那一层"
- Agent 创建 —— 四段式人设的来处,本节的"我不能做什么"写得更硬
- 知乎图文创作智能体 —— 上一章的智能体(写内容),本节这个只做"解释与建议"
- 🤖 Agent+RPA实战 · 索引 —— 全课路线图