AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

风险分级与审批策略

我的学习 →

正在读取学习记录…

订单 Agent 为订单 order-1 提议退款 50 元。正常审批流程让另一位工作人员看到具体订单与金额,同意后才执行一次。预览退款方案不改变订单;真正退款会改变资金状态,因此需要不同的执行规则。

风险分级是根据动作的影响、金额、目标和可逆性选择处理流程。审批是可信人员确认一项具体动作。若审批只保存“同意”两个字,动作金额或目标在等待期间变化,执行器就难以判断该同意适用于哪个请求。

金额用整数分表示:5000 分是 50 元,10000 分是 100 元。这让阈值比较精确,避免浮点金额带来的舍入差异。

把“已同意”变成一张具体动作凭据

Action 保存发起人、租户、操作、目标和金额,冻结字段使夹具中的动作不被原地修改。Approval 保存被同意的动作、另一审批人、到期时间和已使用状态。到期时间与当前时间都采用固定秒数,方便重复观察边界。

risk 把预览归低风险、100元以内退款归中风险,其他动作转高风险流程。decide 对中风险要求审批逐字段匹配,再检查审批人、有效期和使用状态。未使用的有效审批才能改为已使用,返回“执行一次”。

真实系统需要在事务或原子条件更新中完成“验证未使用→标记使用→执行/登记执行请求”,同时配幂等键,即重复请求引用同一业务动作编号。这样才能处理并发和网络重试;Python内存布尔值不能协调多个服务实例。

动作条件等级执行路径
预览方案,无订单变更低直接返回预览
退款0到100元中另一人审批、具体动作匹配、一次使用
退款超过100元或未知操作高转独立高风险流程
负数金额输入拒绝先修正金额
风险分级与审批策略中输入、检查和结果分支的关系
图1:退款先按金额分级;中风险进入审批校验。订单、金额、发起人及有效期一致时允许使用一次,重用或改金额都会被拒绝。

在空目录保存并运行两个文件

在 PowerShell 输入以下命令创建练习目录,并进入目录。目录创建好后,在编辑器中新建下面两份文件并保存到这个目录。

PowerShell
New-Item -ItemType Directory -Force l8-approval
Set-Location l8-approval

macOS 终端:

Bash
mkdir -p l8-approval
cd l8-approval

先保存 approval_demo.py。它包含前面解释的审批绑定以及正常和边界输入。

Python
"""审批绑定具体动作,额度以整数分表示。"""
from dataclasses import dataclass

@dataclass(frozen=True)
class Action:
    actor: str
    tenant: str
    operation: str
    target: str
    cents: int

@dataclass
class Approval:
    action: Action
    approver: str
    expires: int
    used: bool = False

LIMIT = 10000

def risk(action):
    if action.cents < 0:
        return "拒绝"
    if action.operation == "preview":
        return "低"
    if action.operation == "refund" and action.cents <= LIMIT:
        return "中"
    return "高"

def decide(action, approval, now):
    level = risk(action)
    if level == "低":
        return "允许:预览"
    if level != "中":
        return "拒绝:超出自动流程"
    if approval is None:
        return "待审批"
    # 不同金额、目标、租户、操作或发起人都需要重新审批。
    if approval.action != action:
        return "拒绝:审批动作不匹配"
    if approval.approver == action.actor:
        return "拒绝:需另一审批人"
    if now >= approval.expires:
        return "拒绝:审批过期"
    if approval.used:
        return "拒绝:审批已使用"
    approval.used = True
    return "允许:执行一次"

def main():
    action = Action("u1", "A", "refund", "order-1", 5000)
    approval = Approval(action, "u2", 120)
    print("风险等级 ->", risk(action))
    print("无审批 ->", decide(action, None, 100))
    print("已审批 ->", decide(action, approval, 100))
    print("重复执行 ->", decide(action, approval, 100))
    changed = Action("u1", "A", "refund", "order-1", 6000)
    print("金额变化 ->", decide(changed, approval, 100))

if __name__ == "__main__":
    main()

再保存 test_approval.py。测试通过程序的公开函数检查正常路径与拒绝路径;测试文件和主程序放在同一目录,才能按文件名导入。

Python
import unittest
# 固定良性输入检查正常、拒绝和边界路径,不连接外部服务。
from approval_demo import Action, Approval, decide, risk

class ApprovalTests(unittest.TestCase):
    def setUp(self):
        self.action = Action("u1", "A", "refund", "order-1", 5000)
        self.approval = Approval(self.action, "u2", 120)

    def test_pending_and_once(self):
        self.assertEqual(decide(self.action, None, 100), "待审批")
        self.assertEqual(decide(self.action, self.approval, 100), "允许:执行一次")
        self.assertEqual(decide(self.action, self.approval, 100), "拒绝:审批已使用")

    def test_amount_change(self):
        changed = Action("u1", "A", "refund", "order-1", 6000)
        self.assertEqual(decide(changed, self.approval, 100), "拒绝:审批动作不匹配")
        self.assertFalse(self.approval.used)

    def test_expiry_boundary(self):
        self.assertEqual(decide(self.action, self.approval, 120), "拒绝:审批过期")

    def test_self_approval(self):
        approval = Approval(self.action, "u1", 120)
        self.assertEqual(decide(self.action, approval, 100), "拒绝:需另一审批人")

    def test_risk_boundaries(self):
        self.assertEqual(risk(Action("u1", "A", "refund", "x", 10000)), "中")
        self.assertEqual(risk(Action("u1", "A", "refund", "x", 10001)), "高")
        self.assertEqual(risk(Action("u1", "A", "refund", "x", -1)), "拒绝")

    def test_low_risk(self):
        self.assertEqual(decide(Action("u1", "A", "preview", "x", 0), None, 100),
                         "允许:预览")

    def test_binding_tenant(self):
        changed = Action("u1", "B", "refund", "order-1", 5000)
        self.assertEqual(decide(changed, self.approval, 100), "拒绝:审批动作不匹配")

if __name__ == "__main__":
    unittest.main()

返回同一个终端,先列出当前目录内容,确认两个文件名都以 .py 结尾,然后运行主程序。

Bash
ls
python -X utf8 approval_demo.py

程序输出:

TXT
风险等级 -> 中
无审批 -> 待审批
已审批 -> 允许:执行一次
重复执行 -> 拒绝:审批已使用
金额变化 -> 拒绝:审批动作不匹配

50元被分到中风险,没有审批时等待。有效审批第一次允许、第二次因已经使用而拒绝。金额改为60元后,虽然仍然属于中风险,审批却不再匹配。这能说明风险等级和审批绑定各自解决不同问题:同等级的两笔操作也可能需要不同审批。程序返回执行决定,实际退款账务没有接入。

运行测试:

Bash
python -X utf8 -m unittest -v test_approval.py

末尾应显示 Ran 7 tests 和 OK。若提示找不到模块,先用 dir 核对目录与文件名。

改一处,观察决定怎样变化

把 LIMIT = 10000 改成 LIMIT = 4000,重新运行主程序。第一行由 风险等级 -> 中 变成 风险等级 -> 高,后面的执行决定改为 拒绝:超出自动流程。50元超过新阈值,已有审批也不能绕过分级。恢复10000。

Bash
python -X utf8 approval_demo.py

恢复原值后,重新运行测试。

等待审批期间发生了什么

现象需要核对对应处理
审批后订单或金额变化动作完整字段生成新动作,重新审批
审批正好到期now >= expires到期拒绝,刷新审批
两个执行请求都成功使用标记更新是否原子数据库条件更新、事务、幂等键
发起人自己完成审批可信审批人身份在审批服务校验角色与职责分离
门槛改小仍沿用旧决定当前策略是否重新计算执行前重新检查,记录策略版本

审批页面应展示操作、对象、金额、目标位置和重要参数,使工作人员能确认真实副作用。审批服务还要认证审批人并检查其审批额度;示例把审批对象当作可信夹具创建,未实现签名凭据或审批人登录。执行失败后的审批是否可再次使用,应由事务状态和业务补偿流程决定,不能直接把 used 改回 False。

OWASP 交易授权指南强调授权与具体交易数据绑定,以及步骤顺序与服务端校验。将它用于 Agent 时,要在实际工具副作用之前落实校验。

课后练习展开习题收起习题

4 道练习 · 客观题规则评分 · 其余题目待批改

正在读取本地记录…

不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。

练习 1 / 4 · v1.0.1

选择题 · 先判断边界

关于“风险分级与审批策略”,哪种做法更稳妥?

对应知识点:L8-approval

选择一个答案
练习 2 / 4 · v1.0.0

简答题 · 解释失败

写出一个失败输入并说明记录字段。

对应知识点:L8-approval

练习 3 / 4 · v1.0.0

代码题 · 边界测试

补充正常、边界、失败三组输入和预期结果。

对应知识点:L8-approval

练习 4 / 4 · v1.0.0

场景题 · 结果未知

证据不足时如何设计状态和人工接管?

对应知识点:L8-approval

图片查看器
100%

文章配图 · 按 Esc 关闭