作者通过构建wallet-agent真实打通了支付流程,发现"AI询问后再买"这一看似简单的需求背后,隐藏着身份验证、额度限制、卡归属、授权确认四个完全不同的问题域,每个都需要独立的技术方案。
为什么"只问授权"是不够的
想象你把信用卡交给一个新员工,然后说"买东西之前先问问我"。这一条指令实际上依赖于你根本没意识到的一堆假设。这个人真的是你雇的那个员工吗,还是有人假冒的?他们的消费额度和时效是怎样的?当他们递卡给收银员时,那张卡实际上是谁的?当他们回来说"你说可以了"——你真的说过吗,还是有人在撒谎?
能花钱的 AI agent 必须回答完全相同的四个问题,只是所有答案都不能依赖"我认得这张脸"。一切都必须用计算机能验证的方式证明。下面是 wallet-agent 如何回答每一个问题——以及目前哪里还没答上。

第一个问题和钱还没关系。更简单的问题是:当某个东西调用 Amazon 的支付服务并说"让我用这个钱包"时,Amazon 怎么知道这个请求真的是来自我的 agent,而不是别人写的一个随机脚本?
答案是某种 ID badge,在 AWS 里叫 IAM role。我专门为这个 agent 创建了一个,并告诉 AWS 两件事:只有我的 agent 的运行时可以佩戴这个 badge;而且即使戴着它,也只能查询这个特定的支付设置——不能查其他人的。
{
"Effect": "Allow",
"Principal": { "Service": "bedrock-agentcore.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "aws:SourceAccount": "761018866498" },
"ArnLike": {
"aws:SourceArn": "arn:aws:bedrock-agentcore:us-east-1:761018866498:payment-manager/walletagentpm*"
}
}
}
翻译成大白话:"只有 AgentCore 服务本身可以分发这个 badge,而且只发给来自我账户的请求,且只针对名称以 walletagentpm 开头的支付设置。"这就好像一个 badge 不仅有你的照片,而且只能打开它该打开的那扇门。没有这个,任何拿到了有效 AWS 凭证的人都可以冒充我的 agent 来试探支付系统。
这个检查点回答的是"谁在问?"——仅此而已。还不能说明他们能花多少钱。
通过检查点 1 只是让 agent 进了门,并不等于给它开了张空白支票。第二个问题是:即使这真的是我的 agent,它现在到底被允许做什么?
这就引出了 payment session——一张临时的一次性通行证,只在当前对话期间有效。每次我和 agent 开始新对话并给出消费限额,它就会创建一个新的 session,其中内嵌了这个限额和过期时间:
sess_resp = dp.create_payment_session(
userId=user_id,
paymentManagerArn=manager_arn,
expiryTimeInMinutes=60,
limits={
"maxSpendAmount": {"value": "1.00", "currency": "USD"}
},
)
可以把它想象成家长给孩子一张恰好加载了五美元的零花钱卡,且仅限今天有效。卡能用——但商店无法从上面扣六美元,而且无论孩子有没有花完,明天这张卡就失效了。agent 从来不会拿到一个没有限额的钱包;它每次拿到的都是一个新的、有上限的、有时效的钱包。如果它试图超过限额,支付系统本身就会拒绝,不会等到钱真的流动。阻止它的不是 agent 自身的自觉行为——而是一道 agent 碰不到的天花板。
这个检查点回答的是"它最多能走多远?"
这里开始有意思了,也是我卡了好几天的部分。即使有合法的 badge 和受限的额度,仍然需要有一个人来实际签署交易——相当于在支票上签名。这个签名才是真正让区块链上资金流动的东西。那么谁来签呢?
不是我的 AWS 账户。是有意为之的。钱包的私钥存在于一个独立的服务中(我用的是一家叫 Privy 的公司),它永远不会碰到我的代码。取而代之的是,我生成了一把特殊的签名密钥,并在 Privy 上注册为该钱包的已批准"联署人":
body = {"additional_signers": [{"signer_id": signer_id}]}
# PATCH https://api.privy.io/v1/wallets/{wallet_id}
这就好像银行的保险柜不在我的楼里。我不能走进去直接拿钱——我在银行注册了一把特定的密钥,只有用那把密钥签名的请求才会被银行的系统认可,而不是我的系统。当 AWS 的支付服务需要签署一笔交易时,它不会问我要钱包的实际密钥——而是让 Privy 用它已经信任的联署密钥来签名。真正掌管资金流动的秘密从不放在我能泄露、遗失或不小心提交到 GitHub 的地方。
这部分也是最先出问题的。我注册了密钥,但 Privy 并不会自动信任它——我需要在单独的一步中明确将其附加为签名者,否则什么都跑不通。我最初几次尝试只收到一句"access denied",花了很久才意识到 badge(检查点 1)和额度(检查点 2)都没问题——真正缺的是签名这一步。
这个检查点回答的是"谁被允许实际签署?"
三个检查点都过了,而这一个本该是最重要的,因为它是四个中唯一有真人参与的。agent 在花钱之前,必须停下来,展示一张卡片说明它想买什么、为什么买,然后等待:
entry = approvals.request_approval(
resource=resource_id,
amount_usd=amount_usd,
justification=justification,
)
# ...打印审批卡片,然后阻塞直到有人做出决定...
final = approvals.wait_for_decision(entry["approval_id"])
人类看到卡片,点击"批准"或"拒绝"。很简单。但——这也是我想要诚实说的一部分——这个流程里没有任何机制去验证是谁点了批准。审批系统记录的是决定,而不是做决定的人的身份。任何能看到或猜到审批链接的人都可以点"是",而 agent 没有任何方式区分真正的所有者批准了一笔购买还是一个偶然看到同个页面的陌生人。
对比其他三个检查点。AWS 的 badge 在密码学层面绑定了我的账户。消费上限由 AWS 自己的服务器强制执行,而不是靠 agent 的自觉。签名只能来自一把注册过的密钥。每一个都有真正的锁。而人类审批这一步——本来应该是最后的安全网——目前根本没有锁。就像银行金库上装了个纱门:门后面的一切都是真正安全的,但那扇门本身只需要轻轻一推就能打开。
这个检查点本该回答"对的人真的说'是'了吗?"——而现在它只能回答"有人说'是'了吗?"
四个检查点串联起来是这样的:
身份——这真的是我的 agent 吗,由 AWS IAM role 支撑,只有我的 agent 运行时才能 assum
范围——它能花多少、有效期到什么时候,由一个新鲜的、有上限的、会过期的 payment session 来支撑
托管——谁实际持有签名密钥,完全在我的代码之外,由一个只认一把注册密钥的服务来支撑
同意——一个真实的、经过验证的人类说了"是"了吗——而这一点目前还只是靠自觉
前三项是安全人员说"零信任"时通常真正在说的东西——不假设任何事,所有检查都由系统而非良好意愿来执行。构建它们当时感觉繁琐(光是那个缺失签名者的 bug 就花了我一个晚上),但每一个都关闭了一扇本来会敞开的门。
第四项提醒我们,"在流程中加一个人"并不自动等同于安全功能。人类审批步骤只有在有东西真正验证了点击"批准"的人就是任务创建者本人的情况下,才是可靠的。目前我的实现什么都没验证——它穿了一件安全的外衣,实际只是个好的 UX 模式而已。修复方法正是你想到的:在审批页面前加上真正的用户登录,并检查点击"批准"的人和任务创建者是不是同一个人。我还没做到这一步,而我认为承认这一点比悄悄带过更有用。
如果你在构建任何涉及 AI agent 代表他人花钱、签署文件或采取任何现实行动的系统,值得对照这四个问题走一遍你自己的系统:它是谁、它能走多远、谁实际持有钥匙,以及——人们通常会跳过的那一个——你能证明谁真的说"是"了吗?
完整源码,包括 IAM 策略、payment session 代码和审批流程:github.com/yama3133/wallet-agent