Skip to main content
一个拿着 API key 的智能体,能花掉这把 key 能花掉的一切。有人盯着的时候没事,没人盯着的时候就很尴尬。通常的补救办法都在智能体外部——在某个面板里,或是在一个事后才告诉你出事了的账单告警里。 Venice 支持第二种进入方式。智能体不持有 key,而是持有一个钱包。它通过签名一条消息来做身份认证,每次请求从这个钱包地址关联的 USDC 余额中扣款,每一笔扣费都进入一个它能读回的账本。没有账户、没有面板、也没有会泄露的 key。上限就是余额,而余额是你决定要放多少的。 本指南搭一个正好这么做的智能体,让它在自己强制执行的预算下运行。

在 Google Colab 中运行这个 notebook

下面每一步都是可运行的 notebook。它在钱包没有余额时也能跑,会在支付这一步停下,让你在真的花钱之前先看到整个流程。

它是怎么工作的

四个部件,其中三个不过是 HTTP: 推理本身就是一次普通的 /chat/completions 调用。唯一的区别是你发的是哪个 header。

起步要花多少钱

有两个数字很重要,而它们不是同一个数字。 最小充值金额是五美元。这是 /x402/top-up 会结算的最小额度,它是在 discovery 响应里返回的,而不是在任何地方硬编码,所以要读它,而不要相信这一页的说法。 能发起一次调用的最小余额是十美分。低于这个的钱包即便还有钱,向推理发请求也会拿到一个 402 所以五美元是一个值得充值的最小钱包额度,也就是本指南给智能体的额度。值得知道这点钱能买些什么:向 qwen3-5-9b 提一个简短问题大约要花二十七个输入 token 和二十六个输出 token,按这个模型的价格算大约是七百万分之一美元。五美元大约是七十五万个问题的量级。这里的预算不是一个紧约束,而是一个爆炸半径。

环境准备

x402 SDK 负责支付签名。不要自己手写:转账授权是 EIP-712 typed data,重用一个 nonce 会以让人非常烦的方式导致验证失败。
x402 Python SDK 需要 Python 3.10 或更高版本。Colab 没问题。macOS 自带的系统 Python 未必满足要求。
创建 agent.py,写入配置。BUDGET_USD 是智能体给自己设的上限,这里设成整个钱包的额度。调低它,智能体会在钱花完之前就停下,而这可能是你唯一会改动的旋钮。

一个属于智能体自己的钱包

智能体需要一个密钥对。在生产环境里,这是你刻意充过值、私钥存放在 secret manager 里的钱包。在开发过程中,生成一个用完就丢的钱包是正确的做法,因为一个没有钱的钱包不会不小心把事情搞得很贵。
不要把私钥留在 notebook 里。在 Colab 里,把它放进 Secrets,用 userdata.get("WALLET_KEY") 读取。

用签名而不是密钥来登录

没有 key 可发,每次请求就带一份”钱包持有者本人发起了这次请求”的证明。这份证明是一条 EIP-4361 消息,签名后再 base64 编码进 SIGN-IN-WITH-X header。 消息格式是精确的。Venice 会在它那边重建这些字节,并以此校验你的签名,所以多一个空行就意味着签名会被拒绝,而不是给你一个有用的错误信息。
三条规则约束着这些 header,三条都是为了阻止重放。签名从 Issued At 起的五分钟内有效。每个 nonce 在大约五分半的时间里只能使用一次。而且签名者必须与请求路径里的钱包一致,所以一个钱包不能查看另一个的信息,试图这么做只会拿到 403 实际后果就是你要为每次请求都签一个新的 header,而不是缓存一个来用。签名是本地操作,不花钱,所以这没什么成本。
对一个新钱包:
canConsume 是分支判断该看的字段。它已经把十美分的下限考虑在内了,所以你不用自己处理。

把钱存进去

充值要两次请求。第一次问 Venice 接受什么,这次是不做身份认证的,因为还没有东西可以认证。第二次带上签过名的转账授权。
Discovery 每种通道返回一条。目前是 Base 和 Solana:
里面有两处细节容易被忽略。amount 用的是基本单位,USDC 有六位小数,所以 5000000 是五美元,而不是五百万个什么东西。在 Solana 通道上,extra.feePayer 是一个由 Venice 运营的账户,它替你付交易 gas 费,这就是钱包不必持有 SOL 也能付款的原因。
默认的 spend control 是第一个会挡住你的东西。SDK 出厂时把 max_amount_per_payment 设为一美元,而 Venice 的最小充值是五美元,所以未修改的 client 会拒绝所有提供的通道,在它接触网络之前就抛出 NoMatchingRequirementsError。请刻意把这个上限抬高,而不是干脆关掉 spend control。
从一个没有 USDC 的钱包结算,会拿到一个 400,body 里是 PAYMENT_VERIFICATION_FAILED。这就是失败该有的样子:签名没问题,转账没成功。

按次付费

有了余额之后,推理就是一次带着签名的普通请求。把 Venice 系统 prompt 关掉比看起来更重要:它相当于每次调用大约一千七百个输入 token,比问题本身多出两个数量级。
402 当作正常结果而不是异常来处理,是整个设计的核心。一个自己付钱的智能体最终会把钱花光,而花光钱不是崩溃。

读它花了多少

账本才是权威。与其从 token 数估算,不如问一下实际扣了多少。
每一行都回链到导致它的那次调用:
TOP_UPREFUND 行也会出现在这里,金额是正的。过滤到 CHARGE 得到的就是花费。

有预算的一次运行

现在是主循环。在每次调用之前,智能体会检查已经花了多少,并且拒绝去做它付不起的工作。
用整整五美元跑一次,预算根本不会触发,按这个价格这是老实的结果。想真正看到上限起作用,就把它设成一次调用就会突破的值:

到这里你手上有了什么

这个智能体持有自己的钱,用签名证明身份,也没法超出你设的上限,而且在任何地方都不存在关于它的账户。对于一个定时任务、一个 serverless 函数、或者任何你并不想把一个长期存活的 key 交给它的场景,这在安全姿态上是有实质区别的。 值得接着做的一些事:

在协议里加上限

SDK 里的 spend control 是每次支付一个上限,而不是每个会话一个上限。把它和上面那个预算循环搭配起来,让其中一个出 bug 也无法绕过另一个。

没钱了自动补

捕获 402、去充值、然后重试。TypeScript 版本的 venice-x402-client 帮你做的就是这件事。

在 Solana 上支付

同样的流程,另一条通道。用 Ed25519 签名,并设置返回的 feePayer,这样钱包就不需要 SOL。

给它派点真正的活

把任务列表换成一个工具调用循环,账本就会开始告诉你每一个决策各自花了多少。
完整的 endpoint 参考请见 x402 top-up在 Venice API 中使用 x402