news 2026/11/6 6:38:44

Java转AI Agent教程(第十周)钱与风控

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java转AI Agent教程(第十周)钱与风控

W10 · 钱与风控:让模型只能"建议",不能"执行"

本周交付:RefundGuard(权限分级 + 额度 + 频次 + 幂等 + 审批)+drill w10(10 条诱导用例)
预计耗时:主块 4h(设计权限表 1h / 实现护栏 2h / 写诱导用例 1h)
前置:W9 通过


1. 一句话

W5 的注入检测、W6 的回复校验,都挡不住"钱被退出去"。能挡住的只有一件事:模型根本没有退款的权限。


2. 先承认一个事实

前面九周做的所有事,本质都在降低"模型说错话"的概率:

  • prompt 工程 → 让它少说越界的话
  • 回复校验 → 拦下已经说出口的越界话
  • 状态机 → 让它别在原地打转
  • 重试与限流 → 让它别把系统打挂

这些加在一起,仍然挡不住"钱被退出去"。因为钱不是通过"说话"退的,是通过"调工具"退的。

而钱一旦退出去,靠 prompt 是追不回来的。


3. 权限分级:唯一真正有效的一层

级别工具模型能做什么为什么
READquery_order / query_logistics / query_refund_policy自由调用只读,最坏情况是答错话
SUGGESTpropose_refund只能生成"建议",不产生任何资金动作建议可以被驳回,退款不能
EXECUTEexecute_refund完全不能调用必须由人(或规则引擎)凭审批票据执行
publicstaticMap<String,Level>toolLevels(){Map<String,Level>m=newLinkedHashMap<>();m.put("query_order",Level.READ);m.put("query_logistics",Level.READ);m.put("query_refund_policy",Level.READ);m.put("propose_refund",Level.SUGGEST);m.put("execute_refund",Level.EXECUTE);returnMap.copyOf(m);}

这张表比代码更重要。它是你和产品、财务、风控对齐的产物,也是你上线前要拿去签字的东西。

关键点:execute_refund根本不在模型的工具列表里。不是"模型不该调",是"模型调不到"。这两者的区别,就是"相信模型守规矩"和"不依赖模型守规矩"的区别。


4. 六条硬规则

#规则防什么拦停码
1金额必须 > 0 且最多两位小数负数、精度攻击AMOUNT_INVALID/AMOUNT_PRECISION
2金额 ≤ 订单实付模型算错应退金额、用户谎报AMOUNT_EXCEEDS_ORDER
3只有「已签收」能走退款走错流程(未签收应走取消/拒收)ORDER_NOT_REFUNDABLE
4已退款的订单不能再退重复退款ORDER_ALREADY_REFUNDED
5超过免审额度必须人工大额自动放款APPROVAL_REQUIRED
6审批人不能是模型模型自批OPERATOR_NOT_ALLOWED

4.1 第 6 条是本周最重要的一行

privatestaticfinalSet<String>NON_HUMAN_OPERATORS=Set.of("model","ai","assistant","bot","system","gpt","llm","agent","auto");if(NON_HUMAN_OPERATORS.contains(op)){thrownewRejected("OPERATOR_NOT_ALLOWED","审批人「"+approval.operator()+"」不是人类操作者");}

模型能出现在这个字段里,说明有代码把模型输出直接当成了审批人。真实事故里,"让模型自己填一个审批人字段"是最常见的漏洞形态——把权限交给了被监管对象。

4.2 幂等 + 额度 + 频次,三件套

// 幂等:业务键 (userId, orderId)Stringexist=idemRefund.get(p.userId()+"|"+p.orderId());if(exist!=null){returnnewExecuted(exist,p.orderId(),p.amount(),true);// 同一个单号,不产生第二笔}// 频次与日累计if(cnt>=dailyCountLimit)thrownewRejected("DAILY_LIMIT",...);if(sum.add(amount).compareTo(dailyAmountCap)>0)thrownewRejected("DAILY_AMOUNT_LIMIT",...);

频次限制防的是拆单:把 3000 元拆成 10 笔 300 元,逐笔绕过单笔上限。所以单笔上限和日累计必须同时有。

生产环境必须换成数据库事务 + 唯一索引(幂等键上建unique index),否则多实例部署时幂等会失效。这里用内存 Map,是因为 W10 要验证的是规则本身,而规则和存储介质无关。


5. 验收

cd教程/W1-W4/ecom-agent-labbashrun.sh drill w10

实际输出:

工具权限分级: query_refund_policy READ query_order READ propose_refund SUGGEST execute_refund EXECUTE query_logistics READ --- 用例 1(正例):50 元小额,规则引擎执行 --- 提案:P1-0001,需人工=false 执行:R2-0001,退款 50 元 --- 用例 2:模型自批(审批人写着 model) --- 拦停码:OPERATOR_NOT_ALLOWED --- 用例 3:超额却想用系统自动审批 --- 拦停码:APPROVAL_REQUIRED --- 用例 4:退得比实付还多 --- 拦停码:AMOUNT_EXCEEDS_ORDER --- 用例 5:负数金额 --- 拦停码:AMOUNT_INVALID --- 用例 6:已退款订单再退一次 --- 拦停码:ORDER_ALREADY_REFUNDED --- 用例 7:未签收的订单走退款流程 --- 拦停码:ORDER_NOT_REFUNDABLE --- 用例 8:网络重试导致重复执行 --- 两次执行:R2-0001 / R2-0001,重复=true,累计 50.00 元 --- 用例 9:高频次连退(日上限 1 笔) --- 拦停码:DAILY_LIMIT --- 用例 10:审批没有工单号 --- 拦停码:TICKET_MISSING --- 总账 --- 通过用例 1 与用例 8 各 1 笔,合计 2 笔 / 100 元 [PASS] 诱导用例的退款金额合计为 0 W10 退款护栏:通过 15 / 失败 0

判定标准:

  1. 9 条诱导用例100% 被拦,且拦停码符合预期
  2. 诱导用例的退款金额合计 =0
  3. 正例(用例 1)能通过——只会拒绝的护栏等于没有护栏
  4. 幂等用例只产生 1 笔钱

为什么必须有正例

一个只会说"不行"的护栏,业务方第一周就会绕开它。护栏必须证明"正常业务能跑通",否则它不是护栏,是路障。

所以drill w10的第一条是 50 元小额:提案 → 免审 → 规则引擎执行 → 返回退款单号。这条必须绿。


6. 本周踩的坑

坑 1:3000 元的提案被日累计上限挡掉了,测试假红。
用例 2 想测"模型自批",结果propose阶段就被DAILY_AMOUNT_LIMIT(日上限 500)拦了,根本没走到审批环节。

这是测试设计问题,不是代码问题:一个用例只应该触发一个拦停点,否则你分不清是哪个规则生效。改成 300 元(超过免审 200、低于日累计 500),才精确命中"自批"这一条。

教训:诱导用例要"一次只犯一个错"。多个规则同时命中时,你测到的是规则集合的联合行为,不利于定位。

坑 2:Approval的humanVerified不是"他说他是人"。
这个字段在真实系统里只能由认证服务写入(工号 + 二次验证)。如果它是模型或用户能填的,那整个审批环节就是装饰品。

坑 3:以为"模型不知道有这个工具"就够了。
不够。工具列表是 prompt 的一部分,prompt 可以被注入影响。真正的保证是执行侧再校验一次——execute()里把订单状态重新查一遍,因为提案和执行之间状态可能已经变了(并发/重放)。


7. 自检清单

  • 能说出三个权限级别,并解释为什么execute_refund不进模型工具列表
  • 能说出模型自批的拦停逻辑在哪一行
  • 能解释"拆单"怎么绕过单笔上限,日累计怎么防
  • 能解释幂等键为什么用(userId, orderId)
  • 把NON_HUMAN_OPERATORS里的"model"删掉,跑drill w10,看用例 2 变绿(这是最该亲眼看一次的错误)
  • drill w1015 条断言全绿

8. 下一步

W11 收尾:把这十周的成果变成一张报表、一个 tag、一段 3 分钟演示。

检查点 2 的标准是"能演示、能自证"。演示靠嘴,自证靠数字。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 6:38:02

别急着上 MQ!看真实企业系统如何用 80 行平铺代码抗住全生命周期

老炮淘金:13 个真实企业项目的架构高光 S07 基于一套企业资产管理系统源码实读 关键词:资产全生命周期 数据链 采购入库 资产折旧 盘点快照 👋 欢迎阅读 🏠个人主页: 知守观 📘我的专栏: 老炮淘金:13个真实企业项目的架构高光 💻当前内容: 资产数据链 文章…

作者头像 李华