记忆不足就转人工:财务 Agent 的决策边界
应付账款 Agent Precedent 使用 Hindsight 保存历史处理先例,结合合同约束判断发票异常。关键记忆缺失时,系统降低决策信心并转交人工,而非继续自动处理。
AI 深度解读
一张比采购单贵了 4.52% 的发票,该拦下来,还是交给人判断?作者做的应付账款 Agent 给出了一个明确约束:信心必须来自历史处理记录。记得过去为什么拒付,才能处理今天的异常;找不到依据,就把决定交还给人。
这套叫 Precedent 的系统,把 Hindsight 记忆库变成了决策证据。它值得程序员读几分钟的地方,是把「检索到一些材料」推进到了「证据决定自动化权限」,也暴露了一个容易忽略的问题:最关键的历史案例,可能恰好最难被检索出来。
记忆要保存处理依据,不能只保存聊天内容
应付账款(AP)通常要核对采购单、收货记录和发票,这叫三方匹配。匹配不上的单据进入异常处理:价格差异、数量差异、计量单位、GST 类型、额外费用、重复发票,以及银行账户变更。
这些异常经常重复出现。粮食供应商按公担开票,采购单却用公斤;物流商第一次部分发货,就开出整张采购单的金额;标签印刷商重发未付款发票,在编号末尾加上 /R。处理方法往往掌握在某个资深员工手里。
包装供应商的合同第 7.2 条允许最高 2.5% 的附加费。但作者给模型的材料没有包含这条依据,相关知识存在过去的处理记录里。开头那张上涨 4.52% 的发票之所以能被拦下,是因为同一供应商此前上涨 4.26% 的案例曾被退回采购部门。
Precedent 因此把工作分成三步:确定性程序先找异常;Agent 按供应商和异常类型从 Hindsight 调用 recall;Groq 上的 gpt-oss-120b 结合证据推理,通过函数调用提交决定,再由可审计的推理器检查。最终结果通过 retain 写回,包括人工改判及其理由。
记忆同时面向两个读者:自然语言供 Hindsight 提取事实,标签供程序精确查询。作者还为每个案例设置 document_id,避免一份记录提取出多个事实后,被重复算成多票。
这一步很关键。检索结果有三条,不等于存在三个独立案例。
Hindsight 的 reflect 则负责归纳,能够根据记忆生成供应商处理手册,并通过 JSON response schema 让 UI 渲染成表格。它把过去的处理经验变成了新人能查阅的材料。
为什么模型再有把握,也不能越过记忆
这套系统的置信度上限由历史证据决定。
空记忆库里的异常全部得到 0% 置信度,交给人工。置信度高于 75% 才进入自动处理,低于这一水平由人一键确认;原文没有交代恰好等于 75% 时的行为。银行账户变更始终交给财资部门,不受置信度影响。
价格差异和额外费用也不能简单采用多数表决。作者用历史批准案例确定可接受上界,用暂扣案例确定拒绝边界,两者之间的灰区交给人。供应商邮件、欺诈提醒等难以用标签表达的上下文,仍由模型参与判断。
下面这段代码解决的是:模型给出的信心,怎样被证据限制。
if out["action"] == proposal.action and not no_backing:
d.confidence = round(min(llm_conf, proposal.confidence), 2)
elif no_backing:
# 记忆中没有覆盖此情况的先例:模型可以建议,不能独自行动。
d.confidence = round(min(llm_conf, 0.4), 2)
要看的是两处 min():模型与证据方案一致时,取双方置信度的较低值;没有先例覆盖时,最高只有 0.4,也就是 40%。如果模型与记忆结论冲突,另有规则把置信度封顶在 50%,由人工决定。
作者还用 Hindsight directive 在反思阶段执行「账户变更未经回拨确认不得付款」。一次账户变更处理中,系统找回其他供应商的三个相关案例,其中两个已确认欺诈,加上一封内部预警邮件,最终阻止付款并转入财资回拨确认。
不过,规则、记忆和模型各自负责什么,需要读者分清。账户变更必须转人工是明确规则;历史案例帮助解释风险,不能替代这条规则。
最危险的检索遗漏,可能只有一条
作者在 Hindsight Cloud 上遇到过一次与本地测试不同的结果:4.52% 的发票没有被直接判为暂扣,而是升级给人工。
原因出在检索。这个供应商有十一条批准记录,只有一条暂扣记录。Hindsight 在 token 预算内按相关性排序,十一条近似批准挤掉了唯一的暂扣案例。推理器只看到最高批准幅度 2.43%,看不到拒绝边界,于是把 4.52% 判断为「超过所有已见范围」,选择人工处理。
修复方法是额外检索边界案例:
if exc.type in MAGNITUDE_TYPES:
for action in BOUNDARY_ACTIONS: # hold_for_procurement, return_to_vendor
batches.append(self.memory.recall(
f"{inv['vendor_name']} {exc.label} {ACTIONS[action]}: amount above the accepted limit",
tags=[v, t, f"action:{action}"], tags_match="all_strict", limit=10))
这里要看 tags_match="all_strict" 和动作标签:查询同时限定供应商、异常类型和处理动作,并设置 limit=10,给稀少的暂扣、退回案例单独留出检索机会。
相似案例最多的那一类,未必包含决定边界的证据。
作者还补了两类工程故障。Groq 的函数调用有时返回 tool_use_failed 或畸形 JSON,他们依次重新提示、修复参数、切换备用模型;全部失败后,仅根据记忆证据决策,并显示警告。
另一类来自 Hindsight Python SDK:它基于 aiohttp,同步包装器会把 HTTP session 绑定到首次使用的事件循环。Flask 请求落在不同线程时会出问题,作者最终把全部 SDK 调用放到一个专用事件循环。
我的判断
我认可这套设计把「能解释」和「获准自动执行」分开了。相比让模型读完材料自行报一个置信度,它至少提供了可追查的约束;相比只做相似案例检索,它又考虑了去重、边界记录和人工改判。
但效果数字需要限定范围。作者回放了 11 周、12 家供应商、96 张发票的数据,业务以海得拉巴一家中型食品公司为模型,并让 Agent 在每次已记录的人工决定前给建议。第 1 周匹配率为 0%;最后 4 周为 100%,88% 的异常无需人工处理;全程错误自动放行为零。
这些是作者报告的回放结果,不能直接当作真实生产部署的可靠性证明。原文没有说明第 1 周的弃权如何计入匹配率,也没有给出独立测试集、各类异常数量或不同方案的对照数据。
关闭记忆后,系统出现零先例、0% 置信度并全部升级人工,符合它的程序设计,但不足以证明 Hindsight 优于其他存储方案。若团队已有结构化审批日志,数据库查询加规则引擎同样值得比较。自然语言经验很多、需要跨案例归纳时,Hindsight 的价值更容易体现。
还要防止旧决定固化成旧错误。原文强调保留人工改判,却没说清合同更新、案例失效和相互矛盾的历史记录该怎么管理,这仍是落地前要补的部分。
能拿来做什么
- 给日常 AI Agent 建立可追溯的案例记录,至少保存对象、异常类型、处理动作、人工理由和唯一 ID,避免把多条检索片段当成多个独立证据。
- 对涉及金额或阈值的重复决策,单独查询拒绝、暂扣和退回案例,验证边界证据会不会被大量批准记录挤掉。
- 在前端审核界面展示引用案例、升级原因和人工改判入口,让审核人的理由能够进入下一次决策,而不是只留下一个确认按钮。
- 为函数调用设计明确的失败路径,覆盖参数校验、重试和备用模型,并让界面显示降级状态,避免调用失败被包装成正常完成。