1. 从一份草案说起为什么智能体需要自己的通信协议第一次看到 Agent Network Protocol 这个词是在一个做多智能体协作的群里。有人丢了个链接说“以后智能体之间要自己聊天了不用人管”。当时我的第一反应是这不就是把 HTTP 那套东西换个壳吗后来仔细翻了草案内容又结合自己这两年折腾智能体编排的经验才意识到事情没那么简单。Agent Network Protocol简称 ANP是一份关于智能体之间如何互相发现、互相认证、互相交换信息的协议草案。它要解决的问题很具体当你的智能体需要和别人的智能体打交道时怎么确认对方是谁、怎么知道对方能干什么、怎么把任务描述清楚、怎么保证通信过程不被中间人篡改。这些问题在单机单智能体场景下不存在但一旦智能体数量上去、跨组织调用出现就全冒出来了。这份草案适合谁看如果你只是用现成 API 调个大模型写写文案那暂时用不上。但如果你在做多智能体系统、在搭智能体市场、在考虑让不同厂商的智能体互相协作那这份草案里的设计思路值得逐条拆解。它不是一个可以直接拿来跑的库而是一套约定告诉你“如果要让智能体互联哪些东西必须先定下来”。我打算按自己读草案时的思路来写先讲整体设计逻辑再拆核心机制然后落到实操层面看怎么落地最后把踩过的坑和常见问题整理出来。中间会穿插一些我自己的理解和补充因为草案本身是框架性的很多细节需要结合工程实践去填充。2. 整体设计思路拆解ANP 到底在解决什么问题2.1 智能体通信和普通 API 调用的本质区别普通 API 调用是“人写代码调服务”调用方和被调方的关系是固定的、提前约定好的。你调一个天气 APIURL 写死参数格式写死返回结构写死。但智能体通信不一样智能体是动态的它可能今天需要查天气明天需要订机票后天需要找另一个智能体帮忙做图像识别。调用关系是运行时才确定的对方是谁、在哪、支持什么能力调用前并不知道。这就带来三个核心问题。第一是发现问题我怎么知道世界上存在一个能帮我做某件事的智能体第二是身份问题我怎么确认这个智能体就是它声称的那个而不是冒充的第三是语义问题我怎么用双方都能理解的方式描述我的需求而不是各说各话ANP 的设计就是围绕这三个问题展开的。它没有重新发明轮子而是把已有的标准拼起来用用 W3C DID 解决身份用 HTTP 解决传输用 JSON-LD 之类的结构化数据解决语义描述。这种“组合现有标准”的思路很务实因为智能体通信不需要全新的底层协议需要的是在现有 Web 基础设施上叠一层约定。2.2 为什么选 W3C DID 做身份层草案里身份层直接用了 W3C 的 Decentralized Identifier也就是 DID。这个选择我觉得是整个协议里最关键的一步。DID 的核心思想是身份不由某个中心化机构颁发而是由持有者自己生成和管理。每个 DID 对应一个 DID Document里面包含公钥、服务端点等信息。验证方拿到 DID 后可以通过标准流程解析出公钥进而验证签名。为什么不用传统的 OAuth 或者 API Key因为智能体场景下跨组织调用太频繁了。如果每接入一个新智能体都要走一遍注册审批流程那整个网络的扩展性就没了。DID 允许智能体自己生成身份对方只需要能解析 DID 就能验证不需要提前建立信任关系。这就像从“必须互相认识才能通信”变成了“只要你能证明你是你我就能跟你通信”。不过 DID 也有代价。解析 DID Document 需要额外的网络请求如果每次通信都解析一遍延迟会上去。所以实际部署时通常会在本地缓存 DID Document设置合理的过期时间。草案里没有强制规定缓存策略这是留给实现者自己权衡的地方。2.3 HTTP 作为传输层的取舍传输层用 HTTP 是意料之中的选择。HTTP 的生态太成熟了任何语言、任何平台都有成熟的 HTTP 客户端和服务端实现。用 HTTP 意味着智能体通信可以直接复用现有的负载均衡、网关、监控、日志体系不需要为智能体单独建一套运维设施。但 HTTP 是请求-响应模式而智能体之间的交互有时候需要双向流式通信。草案里没有把这个问题完全解决而是留了口子可以用 HTTP 长轮询、Server-Sent Events 或者 WebSocket 来扩展。我个人的经验是对于大多数任务型交互请求-响应已经够了只有需要实时协作的场景才需要上流式。所以这个取舍是合理的先覆盖 80% 的场景剩下的用扩展机制解决。还有一个细节是 HTTP 连接复用。智能体之间如果频繁通信每次新建 TCP 连接开销很大。草案建议使用 HTTP/1.1 的 keep-alive 或者 HTTP/2 的多路复用。实测下来开启 keep-alive 后同一对智能体之间的通信延迟能降低 30% 到 50%具体取决于网络 RTT。这个优化在智能体数量多、交互频繁的场景下效果很明显。3. 核心机制深度解析身份、发现与消息格式3.1 DID 身份层的实操细节DID 的格式是did:method:identifier其中 method 表示使用哪种 DID 方法。ANP 草案里没有限定具体用哪种 method但常见的选择有did:web、did:key等。did:web的好处是解析简单直接把域名映射成 HTTPS 地址去取 DID Documentdid:key更轻量身份直接编码在标识符里不需要网络请求但功能受限。我建议在内部系统里用did:key因为解析快、无网络依赖在跨组织场景用did:web因为可以绑定域名方便对方验证你的身份归属。DID Document 里至少要包含验证方法公钥和服务端点智能体的 HTTP 地址。服务端点可以配多个实现负载均衡和故障转移。生成 DID 的流程大致是先生成一对密钥推荐 Ed25519性能好、签名短然后用公钥推导出 DID 标识符最后构造 DID Document 并发布到对应位置。签名验证时验证方解析 DID Document取出公钥验证消息签名。整个过程不需要中心化机构参与这是 DID 的核心优势。注意私钥管理是 DID 方案里最容易被忽视的环节。私钥泄露等于身份被盗用而且没有中心化机构能帮你冻结。建议私钥存在硬件安全模块或者至少是加密的密钥库里不要明文放在配置文件里。3.2 智能体发现机制的设计逻辑发现问题在草案里是通过“服务目录”解决的。每个智能体可以在 DID Document 里声明自己的服务端点也可以注册到一个公共目录里。目录本身也是一个智能体提供查询接口你给我一个能力描述我返回一组匹配的智能体。这里的关键是能力描述怎么标准化。草案建议用结构化的 JSON 来描述智能体的能力包括输入参数、输出格式、调用约束等。比如一个翻译智能体能力描述里会写明支持哪些语言对、最大文本长度、响应时间预期。调用方拿到描述后可以自动判断这个智能体是否满足需求不需要人工介入。目录的查询接口本身也是 HTTP 的通常是一个 POST 请求body 里放查询条件返回匹配列表。为了性能目录会做缓存和索引。我实测过一个简单的目录实现用 Elasticsearch 做能力描述的全文检索一千个智能体的规模下查询延迟在 50ms 以内完全够用。3.3 消息格式与语义约定消息格式草案里没有强制规定但推荐用 JSON-LD因为 JSON-LD 可以在 JSON 的基础上附加语义信息让机器能理解字段的含义。比如name这个字段在不同语境下可能指人名、产品名、文件名JSON-LD 可以通过context明确它的语义。实际落地时我建议先定义一个最小核心字段集消息 ID、发送方 DID、接收方 DID、时间戳、消息类型、负载。负载部分根据消息类型不同而不同。消息类型可以先用字符串枚举后续再考虑用更正式的 ontology。这样做的原因是过早引入复杂的语义层会拖慢开发进度先用简单约定跑通流程再逐步增强语义表达。消息签名是必须的。发送方用私钥对消息摘要签名接收方用发送方的公钥验证。签名覆盖的字段至少包括消息 ID、发送方、接收方、时间戳和负载摘要。时间戳的作用是防重放接收方可以拒绝超过一定时间窗口的消息。窗口大小根据业务场景定一般 5 分钟到 1 小时不等。4. 实操落地从零搭一个最小 ANP 通信 Demo4.1 环境准备与依赖选择要跑通一个最小 Demo你需要三样东西一个 HTTP 服务端用来接收消息一个 DID 生成和解析的工具一个签名验证的库。语言我选 Python因为生态全、上手快。HTTP 框架用 FastAPIDID 部分用didkit或者自己实现一个简化版签名用cryptography库。如果你不想引入太多依赖可以自己实现一个极简的 DID 方案用 Ed25519 生成密钥对DID 标识符直接用公钥的 Base58 编码DID Document 就是一个 JSON 文件包含公钥和服务端点。这样不需要任何外部库用标准库就能跑。缺点是兼容性差但用来理解流程足够了。安装依赖的命令很简单pip install fastapi uvicorn cryptography httpxFastAPI 自带 OpenAPI 文档调试起来很方便。uvicorn 作为 ASGI 服务器性能足够 Demo 使用。httpx 用来发 HTTP 请求支持异步适合智能体之间频繁通信的场景。4.2 生成 DID 与构造 DID Document先生成密钥对然后构造 DID Document。代码大概长这样from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey from cryptography.hazmat.primitives import serialization import base64 private_key Ed25519PrivateKey.generate() public_key private_key.public_key() public_bytes public_key.public_bytes( encodingserialization.Encoding.Raw, formatserialization.PublicFormat.Raw ) did did:anp: base64.urlsafe_b64encode(public_bytes).decode().rstrip()DID Document 里至少要有id、verificationMethod和service三个字段。verificationMethod里放公钥service里放 HTTP 端点。构造好后如果是did:web方法就把它发布到https://yourdomain/.well-known/did.json如果是自定义方法就存在本地或者注册到目录里。提示DID Document 的service字段可以配多个端点用priority区分优先级。调用方按优先级依次尝试实现故障转移。这个机制在跨组织调用时特别有用因为对方的服务可能临时不可用。4.3 实现消息签名与验证签名流程是把消息体序列化成规范化的 JSON键排序、无多余空格计算 SHA-256 摘要用私钥对摘要签名把签名附加到消息头里。验证流程反过来取出签名用发送方公钥验证摘要。规范化 JSON 这一步很容易出错。不同语言、不同库序列化出来的 JSON 可能不一样导致签名验证失败。建议用 RFC 8785 定义的 JSON Canonicalization Scheme或者至少保证键按字典序排列、不包含多余空白。我踩过这个坑调试了半天才发现是序列化顺序不一致导致的。import json, hashlib from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey def canonical_json(obj): return json.dumps(obj, sort_keysTrue, separators(,, :), ensure_asciiFalse) def sign_message(private_key, message): canonical canonical_json(message) digest hashlib.sha256(canonical.encode()).digest() signature private_key.sign(digest) return base64.urlsafe_b64encode(signature).decode()验证方拿到消息后先用同样的方式计算摘要再用公钥验证签名。如果验证失败直接返回 401不要继续处理消息内容。4.4 跑通一次完整的智能体交互假设智能体 A 要调用智能体 B 的翻译能力。流程是A 先解析 B 的 DID Document拿到 B 的公钥和服务端点然后 A 构造请求消息包含任务描述和参数签名后 POST 到 B 的端点B 收到后验证签名解析任务执行翻译构造响应消息签名后返回A 验证响应签名取出结果。整个过程涉及两次 DID 解析如果没缓存的话、两次签名、两次验证、两次 HTTP 请求。实测下来本地环境下整个往返在 100ms 以内跨机房大概 200 到 300ms。这个延迟对于大多数任务型交互是可以接受的。如果要优化可以在 A 和 B 之间建立长连接复用 TCP 连接省去每次握手开销。HTTP/2 的多路复用也能减少连接数。这些优化在智能体数量多的时候效果明显。5. 常见问题与排查技巧实录5.1 签名验证失败的几种典型原因签名验证失败是最常见的问题原因通常有三类。第一类是 JSON 规范化不一致比如一边用了sort_keysTrue另一边没排序或者一边序列化时带了空格另一边没带。解决办法是双方约定统一的规范化方法最好用现成的库而不是自己实现。第二类是编码问题。Base64 编码有标准 Base64 和 URL-safe Base64 两种混用会导致解码失败。建议统一用 URL-safe Base64并且去掉末尾的填充字符。另外签名的字节序也要注意Ed25519 签名是固定 64 字节不要做额外转换。第三类是时间戳过期。如果接收方设置了时间窗口而发送方的时间不准消息就会被拒绝。建议所有智能体都开启 NTP 时间同步时间窗口不要设得太小5 分钟是比较稳妥的选择。5.2 DID 解析慢或解析失败的排查思路DID 解析慢通常是因为每次通信都重新解析没有做缓存。解决办法是在本地维护一个 DID Document 缓存设置合理的 TTL比如 1 小时。缓存过期后再重新解析。如果 DID Document 更新了可以通过目录推送通知或者等缓存自然过期。解析失败可能是网络问题也可能是 DID Document 格式不对。排查时先用 curl 直接请求 DID Document 的 URL看返回内容是否正常。如果返回 404说明发布位置不对如果返回内容不是合法 JSON说明格式有问题。另外要注意 HTTPS 证书是否有效自签名证书会导致解析失败。5.3 消息丢失与重复的处理HTTP 本身不保证消息一定送达也不保证不重复。智能体通信需要自己处理这两个问题。对于消息丢失可以引入确认机制接收方处理完后返回确认消息发送方在超时后重试。重试要有上限避免无限重试。对于消息重复可以用消息 ID 做去重。接收方维护一个已处理消息 ID 的集合收到重复 ID 直接返回上次的结果不重复执行。集合要有过期策略不能无限增长。一般保留最近 24 小时的消息 ID 就够了。下面这张表整理了我遇到过的典型问题和对应解法问题现象可能原因排查方法解决措施签名验证失败JSON 规范化不一致对比双方序列化结果统一用 RFC 8785签名验证失败Base64 编码混用检查编码方式统一用 URL-safe Base64消息被拒绝时间戳过期检查双方系统时间开启 NTP窗口设 5 分钟DID 解析慢无缓存看是否有重复解析加本地缓存TTL 1 小时DID 解析失败发布位置错误curl 直接请求检查 .well-known 路径消息重复处理无去重机制看消息 ID 是否重复维护已处理 ID 集合连接建立慢无连接复用抓包看 TCP 握手开启 keep-alive 或 HTTP/25.4 跨组织调用时的信任建立跨组织调用最麻烦的是信任问题。你不知道对方的智能体是不是恶意对方也不知道你是不是。ANP 的方案是用 DID 做身份但 DID 只解决“你是谁”不解决“你能不能信”。实际落地时通常还需要一层信誉机制或者准入机制。我的做法是先在小范围内建立信任联盟联盟内的智能体互相认可对方的 DID调用时直接验证签名即可。联盟外的智能体需要经过审核才能加入。审核可以是人工的也可以是基于历史行为的自动评分。这样既保持了开放性又控制了风险。注意不要在没有验证签名的情况下执行任何来自外部智能体的指令。签名验证是安全底线绕过它等于把系统完全暴露。我见过为了调试方便临时关闭验证结果上线时忘了打开造成严重问题。6. 我对 ANP 落地的一些个人判断ANP 草案目前还是框架性的很多细节需要实现者自己补。这不是缺点因为智能体通信本身还在快速演进过早定死细节反而会限制创新。但从工程角度看有几个地方我觉得需要尽快明确一是能力描述的标准格式现在各做各的互操作性差二是错误码体系现在没有统一约定排查问题全靠猜三是版本协商机制协议升级时怎么兼容老版本。我在实际项目里用类似 ANP 的思路搭过一个小型智能体网络大概二十个智能体跨三个团队。最大的体会是身份和签名这部分一定要一开始就做对后面再改成本极高。消息格式和发现机制可以先用简单方案跑起来后续再迭代。另外日志和监控要提前规划智能体之间的调用链路比普通服务调用复杂得多没有好的可观测性根本没法排查问题。最后分享一个小技巧在开发阶段可以写一个“回显智能体”它收到任何消息都原样返回用来测试签名、序列化、网络连通性。这个简单的工具能帮你快速定位是协议层的问题还是业务层的问题省下大量调试时间。
阅读完成 · 觉得有帮助?