关于 AVEL
AVEL 是用于代理间付款前核验付款方和收款方身份与信誉的 Python 客户端及服务。它只返回核验结果,不处理付款,并支持原生签名以及 x402、AP2 和 MPP 的付款证明。
主要功能
- 01核验付款方和收款方身份与信誉
- 02返回批准或拒绝的核验结果
- 03支持 x402、AP2 和 MPP 证明
- 04签发并核验卖方签署的挑战
- 05允许交易双方读取交易结果
- 06向 Agent 框架提供付款与余额工具
适用场景
- 01在 Agent 付款前核验交易对手
- 02由卖方设定并签署交易条款
- 03让交易任一方查看核验结果
- 04通过 LangChain、CrewAI 或 AutoGen 提供付款核验
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx agent-interchangeAVEL_BASE_URLBase URL of the AVEL instance to verify against (default: https://aisrail.fly.dev)AVEL_PRIVATE_KEY密钥EVM private key of the agent identity this MCP server represents — signs every verify()/issue_challenge()/verify_challenge()/get_verdict() call. Never exposed as a tool argument.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
agent-interchange
用于 AVEL(Agent Verification Layer,Agent 验证层)的 Python SDK——验证付款方和收款方的身份/信誉,适用于任何支付方式,且绝不托管资金。服务端为闭源;此软件包是客户端层,旨在公开并供他人复用(MIT 许可证)。可独立使用——不依赖服务端代码,只需 httpx、eth-account 和一个可访问实例的 URL(https://aisrail.fly.dev)。
安装
pip install -e .
用法
from agent_interchange import InterchangeClient
client = InterchangeClient("https://aisrail.fly.dev")
result = client.verify(
payer_address=agent_a_address,
payee_id="merchant-42",
amount=25.0,
currency="EUR",
private_key=agent_a_private_key,
fee_payment_method_id="pm_...", # con cosa si paga LA VERIFICA
)
两个 Agent 之间的付款不会经过这里。 此调用只判断是否可以安全继续;之后,Agent 通过自己已有的支付渠道付款。我们只收取已执行检查的服务费(已验证金额的 1%,银行卡支付最低 0,50)——即使判定结果为 DENIED,也仍需支付,前提是调用方的签名有效:这是检查的费用,而不是结果的费用。
有三种可能的结果:
| 响应 | 含义 |
|---|---|
verdict: "APPROVED" | 检查通过,已收取服务费:可以继续 |
verdict: "DENIED" | 不要继续。如果调用方的签名有效,仍需支付服务费——只有签名无效时才免费(无法确定向谁收费) |
verdict_withheld: true | 已执行验证,但尚未收取服务费:判定结果(APPROVED 或 DENIED)将暂时保留,直到付款完成 |
private_key 是 Agent 的 EVM 密钥(绝不是我们的密钥)。首次通过身份验证的使用会将该身份绑定到签名地址(首次使用即信任):之后的每次调用都必须使用同一个密钥签名。无需提前注册。
verify() 使用 protocol="native"。如果 Agent 已在使用 x402、AP2 或 MPP 付款,则无需再次签名:只需提交其已有的付款证明——scripts/protocol_adapters_demo.py 中提供了每种协议的示例。
B 方的对称验证
如果卖方(B)声明了一个地址(payee_address),就必须证明自己能控制该地址——否则判定结果为拒绝。签名应由 B(或代表其进行协商的一方)针对 build_counterparty_message(payer_address, payee_id, amount, currency, nonce) 计算,并作为 payee_signature 传入:
from agent_interchange.client import build_counterparty_message
message = build_counterparty_message(payer_address, payee_id, amount, currency, nonce)
payee_signature = "0x" + Account.sign_message(encode_defunct(text=message), private_key=b_private_key).signature.hex()
result = client.verify(
payer_address=a_address, payee_id="merchant-42", amount=25.0, currency="EUR",
private_key=a_private_key, nonce=nonce,
payee_address=b_address, payee_signature=payee_signature,
)
由 B 发起的模式(challenge 协议)
这更接近 x402/MPP 的实际运作方式:由卖方(B)设定价格和条款并首先签名,买方(A)签署相同文本以接受这些条款。
# Lato B — nessuna chiamata di rete, va consegnato ad A fuori banda
challenge = client.issue_challenge(
payee_address=b_address, payee_id="merchant-42", amount=25.0, currency="EUR",
private_key=b_private_key, ttl_seconds=600,
)
# Lato A — accetta il challenge e chiede il verdetto in un colpo solo
result = client.verify_challenge(
challenge, payer_address=a_address, private_key=a_private_key,
fee_payment_method_id="pm_...", # o fee_method="x402" per pagare in stablecoin
)
challenge 仅对接受它的那笔确切交易有效一次:相同内容的重试(在 402 后完成佣金付款所必需)仍被允许,但不能以不同条款重复使用。
双向判定
双方都可以读取特定交易的结果——不只是调用 verify()/verify_challenge() 的一方:
verdetto = client.get_verdict(
payee_address=b_address, nonce=nonce,
address=b_address, private_key=b_private_key, # o quella di A
)
需要提供签名,以证明自己是该笔交易的付款方或收款方——与汇总历史记录(GET /ais/reputation/{address},公开)不同,单笔交易详情并非公开信息。
Marketplace 场景
当 payee_id/payee_address 指向的是店面,而非真正提供产品/服务的一方时,verify() 也接受 sub_merchant_address/sub_merchant_signature(与 B 方采用相同原则:签名应针对 build_sub_merchant_message(payer_address, payee_id, amount, currency, nonce, sub_merchant_address) 计算)。如果声明了该地址,其信誉(响应中的 sub_merchant_reputation)会和 B 方的信誉一样影响判定结果。
请参阅 example.py,了解可执行的基础流程示例。
Agent Vaults 方法 — 已关闭
pay()、get_balance()、deposit() 和 withdraw() 属于旧模型,在该模型中,服务会托管内部余额。服务器现在会对这些端点返回 410:我们不再托管资金,哪怕一瞬间也不托管。代码仍然保留,可通过服务器端的 AGENT_VAULTS_ENABLED=true 重新启用;下方文档作为历史参考保留。
InterchangeClient
-
verify(payer_address, payee_id, amount, currency, private_key, nonce="", payee_address=None, payee_signature=None, sub_merchant_address=None, sub_merchant_signature=None, fee_payment_method_id=None)→dict。用于“A 声明,B 确认”模型的方法。对交易的规范文本进行 EIP-191 签名,请求判定结果并支付手续费。402不是错误,而是预期的响应(“验证通过,现在付款”):会直接返回,不会抛出异常。 -
issue_challenge(payee_address, payee_id, amount, currency, private_key, ttl_seconds=600)→dict。B 端(卖家)的 B 驱动模型:签发并签署具有约束力的 challenge,不进行网络调用。结果应通过带外方式交给 A。 -
verify_challenge(challenge, payer_address, private_key, fee_payment_method_id=None, fee_method=None)→dict。A 端(买家):接受issue_challenge()签发的 challenge,并通过一次调用请求判定结果。 -
get_verdict(payee_address, nonce, address, private_key)→dict。双向判定:读取特定交易的结果,交易双方均可使用。如果address既不是该交易的付款方,也不是收款方,则抛出InterchangeAPIError(403);如果该payee_address/nonce没有已记录的判定结果,则抛出InterchangeAPIError(404)。 -
get_agent_reputation不是客户端方法 — 它是公开且无需身份验证的:使用简单的 HTTP 请求访问GET {base_url}/ais/reputation/{address}。 -
(已关闭,410) →pay(payer_ref, payee_ref, amount, private_key, currency="USDC", task_id=None)PaymentResult。private_key会对绑定此精确交易的 EIP-191 消息进行签名(首次使用时信任——参见上方用法);由于 Interchange 在/pay中加入了钱包身份验证,因此该参数必填。 会从task_id和调用自身的参数自动推导agent_request_id(参见client._derive_request_id)——请传入 Agent 框架自身的任务/运行 ID,这样真正的重试(相同的 task_id、相同的参数)就能安全地实现幂等,而相同 task_id 下的不同付款也不会与其发生误冲突。省略task_id仍可正常工作,但会失去重试安全性(会使用新的随机 ID,因此真正的重试会被视为全新交易)。抛出:
InsufficientBalanceError— 付款方的余额不足以支付金额和手续费。RequestConflictError— HTTP 409:推导出的 ID 已用于不同内容(不可信中间件可能重放/劫持捕获的付款证明——此类请求会被拒绝,不会执行),或该 ID 已被预留但交易尚未完成(绝不会自动重试)。InterchangeAPIError— 任何其他非 2xx 响应,或无法连接 Interchange。401 表示private_key与签名不匹配;403 表示payer_ref已绑定到其他地址(并非此密钥对应的地址)。
风险评分为
DENY时(余额不足除外)不会抛出异常——它会作为普通的PaymentResult返回,且.success == False;请检查.decision/.reasons了解原因。 -
get_balance(agent_ref, private_key)→dict[str, int],按货币计量的原子单位余额,例如{"USDC": 500000}。private_key用于证明对agent_ref的控制权(与pay()的首次使用时信任绑定相同);如果agent_ref之前尚未用于pay()/withdraw(),则允许使用任意密钥。 -
withdraw(agent_ref, amount_usdc, payout_address, private_key, task_id=None)→dict。private_key是agent_ref自己的密钥,用于证明其控制着待提现的余额——提现仍由 Interchange 自有金库签名并在链上支付,private_key在此仅用于验证提现请求。task_id的派生方式和异常约定与pay()相同(HTTP 402 时抛出InsufficientBalanceError,409 时抛出RequestConflictError;401/403 的含义与pay()相同);其他任何非 2xx 响应(例如,未列入白名单的平台金库提现返回 403)都会抛出InterchangeAPIError。 -
await deposit(agent_ref, amount_usdc, private_key, task_id=None)→dict。异步(与其他三个方法不同),并且需要安装deposit附加依赖——pip install agent-interchange[deposit]——因为它会使用存款 Agent 自己的密钥签署真实的 x402 支付。未安装该附加依赖时调用会抛出InterchangeAPIError(而非 ImportError),并附带相关说明。基础安装(pip install -e .)不需要x402/eth-account,除非你调用此方法。
已在运行中的 Interchange 上完成实时验证(2026 年 9 月 4 日):正常支付(费用正确地从 amount 中扣除,而非额外叠加);pay()/withdraw() 金额过大时抛出 InsufficientBalanceError;幂等重试(相同的 task_id 和参数)会返回完全相同的缓存结果,且不会发生第二次转账/提现;相同的 task_id 搭配不同参数会作为不同支付执行(不会误报冲突);伪造的“相同 ID、不同内容”请求会被正确拒绝并抛出 RequestConflictError,模拟 Interchange 自身 P1 绑定机制防范的重放/劫持场景(主仓库中的 interchange/security.py);执行真实的链上 withdraw() 和 deposit(),并在 Base Sepolia 上确认各自生成的交易;以及未安装 deposit 附加依赖时 deposit() 的清晰失败提示(通过拦截导入进行模拟)。
InterchangeTool — LangChain / CrewAI / AutoGen
from agent_interchange import InterchangeClient, InterchangeTool
client = InterchangeClient("http://localhost:8000")
tool = InterchangeTool(client)
langchain_tools = tool.for_langchain() # requires: pip install langchain-core
crewai_tools = tool.for_crewai() # requires: pip install crewai
autogen_tools = tool.for_autogen() # requires: pip install autogen-core
仅将 pay/get_balance 封装为 Agent 可调用的工具——有意不包含 deposit/withdraw:这些操作会转移真实资金,而且 deposit 需要原始私钥;默认将它们暴露给 LLM 的工具调用循环,需要更谨慎地权衡。请在自己的代码中直接通过 client 调用它们。
延迟导入:构造 InterchangeTool 并直接调用其 pay()/get_balance(),始终不需要安装这三个框架中的任何一个——只有调用 for_langchain()/for_crewai()/for_autogen() 时才需要;若未安装相应软件包,每个方法都会干净地失败(ModuleNotFoundError)。已完成实时验证(构造、底层 _get_balance 调用,以及三个工厂方法各自的干净失败路径);工具装饰后的输出本身,其验证级别与主仓库 framework_tools.py 相同——有关如何根据各框架实际发布的源代码确认底层 @tool/FunctionTool API 形式,请参阅该文件的文档字符串。
此处未包含的内容
主仓库根目录中的 agent_tools.py / framework_tools.py 涵盖相同内容,但并未打包,也无法独立安装——主仓库自身的开发环境之外的用途,请优先使用此 SDK。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。