ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Agent Network Protocol 解析:基于 HTTP 与 DID 的智能体通信协议设计

Agent Network Protocol 解析:基于 HTTP 与 DID 的智能体通信协议设计 1. 为什么我们需要重新审视智能体通信这件事过去大半年我一直在折腾多智能体协作系统的落地。从最早用简单的函数调用把几个模型串起来到后来尝试让不同框架下的智能体互相“对话”踩的坑一个接一个。最让我头疼的不是模型能力不够而是智能体之间根本没法好好说话。A框架的智能体输出一段JSONB框架的智能体期望的是另一种结构C平台用gRPC做传输D平台只认HTTP回调。每接入一个新智能体就要写一层适配代码项目里一半的时间花在“翻译”上而不是业务逻辑本身。这就是Agent Network Protocol后面简称ANP试图解决的核心问题。它想做的事情用一句话概括给智能体之间的通信定一套大家都认的规矩让不同来源、不同框架、不同部署环境的智能体能够像浏览器访问网页一样用统一的方式发现彼此、理解彼此、协作完成任务。ANP不是一个具体的代码库而是一份技术白皮书草案它定义了协议的分层结构、身份机制、消息格式和交互模式。适合谁来读如果你正在做多智能体系统、AI Agent平台、或者任何需要让多个自动化实体协同工作的项目这份协议的设计思路值得你花时间研究。哪怕你暂时不打算实现它理解它的取舍逻辑也能帮你在自己的系统里做出更好的架构决策。我读这份白皮书草案最大的感受是它没有重新发明轮子而是很聪明地站在了HTTP和W3C DID这两个成熟标准的肩膀上。下面我就按自己的理解把这份协议的核心设计、实操要点和落地时会遇到的问题拆开来讲。2. 协议整体设计与分层思路拆解2.1 为什么是“网络协议”而不是“通信框架”市面上已经有不少智能体通信方案比如某些平台自研的消息总线、基于消息队列的异步通信、或者直接暴露RESTful接口。这些方案在单一平台内很好用但一旦跨平台就歇菜。ANP的定位很明确它要做的不是又一个框架而是协议。框架和协议的区别在于框架规定了你必须怎么实现协议只规定了你必须怎么交互。就像HTTP不关心你的服务器是Nginx还是ApacheANP也不关心你的智能体是用LangChain还是AutoGen写的只要你能按照协议规定的格式收发消息就能接入网络。这个定位决定了ANP的设计必须足够抽象抽象到不依赖任何具体的技术栈。白皮书里把协议分成了四层我从下往上梳理一下自己的理解。最底层是传输层直接复用HTTP/HTTPS。这个选择非常务实。HTTP的生态太成熟了任何语言、任何平台都有成熟的HTTP客户端和服务端实现调试工具curl、Postman、Wireshark一应俱全。用HTTP做传输意味着ANP天然支持请求-响应模式和流式传输通过SSE或WebSocket升级而且能直接受益于HTTP连接复用、缓存、压缩等现有优化。白皮书里特别提到连接复用这一点因为智能体之间的通信往往是高频小消息如果每次请求都新建TCP连接握手开销会吃掉大量性能。HTTP/1.1的keep-alive和HTTP/2的多路复用都能直接拿来用。往上一层是身份层采用W3C DID去中心化标识符。这是整个协议里我觉得最值得细看的设计。传统方案里智能体的身份通常是一个API Key或者OAuth Token由某个中心化平台颁发。问题在于当智能体跨平台协作时A平台的Token在B平台不认你又得走一遍授权流程。DID的思路是让每个智能体拥有一个全局唯一的、自证明的标识符不需要中心化机构背书。白皮书里用的DID方法应该是did:web或类似的轻量级方案因为纯链上DID对大多数应用来说太重了。DID文档里包含公钥信息智能体之间可以通过签名验证消息来源不需要每次都问“你是谁颁发的”。再往上是消息层定义了智能体之间交换的消息格式。这部分是协议的核心白皮书里应该规定了消息的头部字段发送者DID、接收者DID、消息类型、时间戳、签名等和载荷结构。载荷部分我猜测会采用JSON-LD或者类似的语义化格式因为不同智能体对同一个概念的理解可能不同需要一套共享的词汇表来消除歧义。比如“任务”这个词在客服智能体里可能指一次对话在物流智能体里可能指一次配送如果没有语义标注接收方根本不知道该怎么处理。最顶层是交互层定义了智能体之间可以进行的交互模式。白皮书里提到了请求-响应、发布-订阅、协商等模式。这一层最像传统的多智能体系统设计但ANP把它标准化了。比如协商模式两个智能体可以就任务分工、价格、时间窗口等进行多轮对话直到达成一致或失败。这种模式在自动化交易、资源调度场景里非常有用。2.2 与HTTP的关系不是替代是寄生很多人看到ANP的第一反应是“这不就是HTTP上加了一层吗”。没错但这一层加得很有讲究。ANP没有重新定义一套传输机制而是把HTTP当作“公路”自己在上面跑“货车”。这样做的好处是任何支持HTTP的环境都能跑ANP不需要特殊的网络配置或防火墙规则。坏处是HTTP的一些限制也会传导上来比如请求-响应模式对长时任务的支撑不够好需要额外的心跳或轮询机制。白皮书里应该讨论了这个问题我猜测解决方案是结合SSEServer-Sent Events做服务端推送或者用HTTP/2的流做双向通信。实际落地时我建议对短任务直接用请求-响应对长任务用“提交任务-轮询状态-获取结果”的三段式模式这样最稳妥也最容易调试。2.3 与W3C DID的整合身份问题的优雅解法DID的引入解决了一个很实际的问题跨平台身份互认。假设你有一个客服智能体部署在阿里云一个物流智能体部署在腾讯云它们要协作处理一个退换货请求。传统方案下客服智能体需要先调用腾讯云的API获取访问令牌然后才能发消息给物流智能体。令牌有过期时间需要刷新刷新逻辑又要处理各种异常。用DID的话每个智能体在初始化时生成自己的DID和密钥对DID文档托管在一个可公开访问的URL上比如https://example.com/.well-known/did.json。协作时客服智能体直接用自己的私钥签名消息物流智能体从DID文档里拿到公钥验证签名。整个过程不需要任何中心化授权服务器。当然DID也不是银弹。密钥管理是个大问题。私钥丢了智能体的身份就丢了所有历史消息的签名都无法验证。白皮书里应该提到了密钥轮换和恢复机制但具体实现起来复杂度不低。我的建议是在早期落地时先用中心化的密钥托管服务过渡等DID生态成熟了再逐步去中心化。3. 核心细节解析与实操要点3.1 消息格式设计让机器能读懂彼此ANP的消息格式设计直接决定了协议的可用性。白皮书里应该定义了一套基础消息结构我根据常见实践推测一下核心字段。消息头部至少包含以下内容字段名类型说明sender_didstring发送者的DID标识符receiver_didstring接收者的DID标识符message_idstring全局唯一消息ID用于去重和追踪timestampintegerUnix时间戳毫秒级message_typestring消息类型如request、response、eventsignaturestring对消息内容的数字签名content_typestring载荷的MIME类型如application/json载荷部分则根据message_type不同而不同。请求消息的载荷包含action要执行的操作和parameters操作参数。响应消息的载荷包含status成功/失败、result结果数据和error错误信息。这里有个细节值得注意白皮书里应该规定了消息的序列化方式。JSON是最自然的选择但JSON有个问题——数字精度。JavaScript的Number类型是双精度浮点数处理大整数时会丢精度。如果智能体之间传递的是金额、ID之类的数据用JSON就要特别小心。我的做法是在JSON里把大整数序列化成字符串接收方再按需转换。这个技巧在跨语言通信时尤其重要因为不同语言对JSON数字的解析行为不一致。另一个细节是消息签名。签名应该覆盖哪些字段如果只签载荷头部可以被篡改如果签整个消息那message_id和timestamp就不能在签名后修改。白皮书的做法应该是签一个规范化的消息摘要包含所有关键字段。实操时要注意JSON的规范化问题——同样的数据字段顺序不同、空格不同序列化出来的字符串就不同签名验证就会失败。解决方案是用JCSJSON Canonicalization Scheme之类的规范化算法确保序列化结果唯一。3.2 身份验证流程从DID到可信通信DID的验证流程比传统的API Key复杂但安全性更高。我梳理一下完整的验证步骤。第一步发送方构造消息用自己的私钥对消息摘要签名。私钥存储在安全的地方比如硬件安全模块或加密的密钥库。第二步发送方通过HTTP POST把消息发到接收方的ANP端点。端点地址可以从接收方的DID文档里解析出来DID文档里会有一个service字段指明ANP服务的URL。第三步接收方收到消息后先从消息头部提取sender_did然后解析这个DID对应的DID文档。DID文档的获取方式取决于DID方法如果是did:web就是访问https://domain/.well-known/did.json。第四步接收方从DID文档里提取发送方的公钥用公钥验证消息签名。如果验证通过说明消息确实来自该DID的持有者且内容未被篡改。第五步接收方检查消息的timestamp是否在可接受的时间窗口内防止重放攻击。通常窗口设为5分钟超过就拒绝。第六步接收方根据message_type和action执行相应逻辑构造响应消息用自己的私钥签名后返回。这个流程看起来步骤多但大部分可以封装成库函数业务代码只需要调用send_message(receiver_did, action, params)和on_message(callback)两个接口。实操时的性能瓶颈主要在DID文档的获取上如果每次收消息都去远程拉DID文档延迟会很高。解决方案是加缓存DID文档通常变化不频繁可以缓存几分钟到几小时。缓存失效策略可以用TTL加主动刷新收到签名验证失败时强制刷新一次。3.3 交互模式请求-响应之外的更多可能白皮书里定义的交互模式应该不止请求-响应一种。我根据多智能体系统的常见需求推测还包括以下几种。发布-订阅模式智能体可以订阅某个主题的消息当有其他智能体发布该主题的消息时订阅者会收到通知。这种模式适合事件驱动的场景比如监控智能体订阅“异常事件”主题一旦有智能体发布异常监控智能体立即响应。实现上可以用HTTP长轮询或SSE但更优雅的方式是让ANP端点支持WebSocket升级。协商模式两个智能体就某个议题进行多轮对话直到达成一致。比如任务分配场景协调者智能体向多个执行者智能体发送任务提案执行者返回接受、拒绝或还价协调者根据反馈调整提案。这种模式需要消息里带一个conversation_id把多轮消息关联起来。流式模式对于大结果集或持续输出的场景接收方可以流式获取结果。比如一个数据分析智能体处理完数据后不是一次性返回所有结果而是分批次推送。这需要HTTP的chunked transfer encoding或SSE支持。这几种模式的组合使用能让ANP覆盖大部分多智能体协作场景。但要注意模式越多实现复杂度越高。我的建议是第一版实现只做请求-响应把基础打牢后续再逐步加其他模式。4. 实操过程与核心环节实现4.1 环境准备与依赖选型要跑通一个最小的ANP demo你需要准备以下环境。运行时Python 3.10或Node.js 18。我选Python因为DID和加密相关的库更成熟。需要安装的包包括cryptography密钥生成和签名、httpx异步HTTP客户端、fastapi服务端框架、uvicornASGI服务器、pydantic消息模型定义。DID方法用did:web因为不需要区块链只需要一个能托管JSON文件的HTTP服务器。本地开发时可以用localhost作为域名但要注意DID规范对localhost的支持可能不完整建议用ngrok之类的工具暴露一个公网域名。密钥算法用Ed25519因为密钥短、签名快、安全性高。cryptography库原生支持。消息序列化用JSON配合JCS规范化。Python的json模块默认不保证字段顺序需要自己实现规范化或者用canonicaljson库。4.2 生成DID和密钥对第一步是生成智能体的身份。Ed25519的私钥是32字节随机数公钥是32字节。DID的生成规则是did:web:domain比如did:web:agent-a.example.com。DID文档的URL是https://agent-a.example.com/.well-known/did.json。DID文档的内容大致如下{ id: did:web:agent-a.example.com, verificationMethod: [ { id: did:web:agent-a.example.com#key-1, type: Ed25519VerificationKey2020, controller: did:web:agent-a.example.com, publicKeyMultibase: z6Mk... } ], service: [ { id: did:web:agent-a.example.com#anp, type: ANPMessaging, serviceEndpoint: https://agent-a.example.com/anp } ] }publicKeyMultibase是公钥的Multibase编码前缀z表示base58btc。生成密钥对后把公钥编码进去私钥自己保存好。4.3 实现消息签名与验证签名流程先把消息体不含signature字段用JCS规范化得到字节串然后用Ed25519私钥签名签名结果用base64url编码后填入signature字段。验证流程收到消息后先提取signature字段从消息体里移除它对剩余部分做JCS规范化然后用发送方DID文档里的公钥验证签名。这里有个坑JCS规范化对浮点数的处理有明确规定但不同库的实现可能有细微差异。我的做法是消息里尽量避免浮点数金额用整数分表示比例用整数千分比表示。这样规范化结果稳定签名验证不会因为浮点精度问题失败。4.4 搭建ANP服务端服务端需要暴露两个端点/.well-known/did.json返回DID文档/anp接收ANP消息。用FastAPI实现的话/anp端点接收POST请求请求体是JSON格式的ANP消息。处理逻辑是解析消息、验证签名、检查时间戳、根据action字段路由到对应的处理函数、构造响应、签名、返回。响应消息的message_type设为responsestatus字段表示成功或失败。如果失败error字段里放错误码和描述。错误码建议用字符串而不是数字比如INVALID_SIGNATURE、UNKNOWN_ACTION、TIMEOUT这样更易读。4.5 客户端发送消息客户端逻辑更简单构造消息、签名、POST到接收方的ANP端点、等待响应、验证响应签名、返回结果。发送时要注意HTTP超时设置。智能体处理任务可能需要几秒到几分钟超时设太短会误判失败设太长会阻塞。我的做法是短任务超时30秒长任务用异步模式——先发一个submit请求接收方立即返回一个task_id然后客户端轮询/anp/status/{task_id}获取进度最后用/anp/result/{task_id}拿结果。4.6 端到端测试测试时至少需要两个智能体分别跑在不同的端口或不同的机器上。用curl手动构造消息测试签名验证逻辑用Python脚本测试完整的请求-响应流程。重点测试以下场景正常请求-响应、签名错误、时间戳过期、未知action、接收方不可达。每个场景都要确认错误处理符合预期不会泄露内部信息。5. 常见问题与排查技巧实录5.1 签名验证失败的几种典型原因签名验证失败是调试ANP时最常见的问题。我整理了一个排查表。现象可能原因排查方法所有消息都验证失败公钥不匹配检查DID文档里的公钥是否与私钥对应部分消息验证失败JSON规范化不一致对比发送方和接收方的规范化结果间歇性验证失败时间戳漂移检查双方系统时间是否同步特定字段修改后失败签名字段范围不对确认签名覆盖了所有关键字段base64解码失败编码方式不一致统一用base64url去掉paddingJSON规范化不一致是最隐蔽的问题。比如Python的json.dumps默认会在逗号后加空格而JavaScript的JSON.stringify不加。如果发送方用Python序列化接收方用JavaScript验证规范化结果就不同。解决方案是双方都用同一套JCS实现或者约定一个固定的序列化库。5.2 DID文档获取超时或失败DID文档托管在HTTP服务器上网络问题会导致获取失败。排查步骤先用curl直接访问DID文档URL确认能返回200和正确的JSON检查DNS解析是否正常检查是否有防火墙拦截检查DID文档的Content-Type是否是application/json。如果DID文档服务器不稳定可以考虑加CDN或缓存层。但要注意DID文档里的公钥如果被缓存了密钥轮换后缓存不会立即失效。解决方案是在DID文档里加updated字段接收方发现缓存文档的updated时间早于消息时间戳时强制刷新。5.3 消息重复与幂等性处理HTTP重试、网络抖动都可能导致消息重复。ANP消息里的message_id就是用来做去重的。接收方应该维护一个最近处理过的message_id集合收到重复ID时直接返回上次的响应不重复执行。这个集合不能无限增长需要设置过期时间。我的做法是用一个带TTL的LRU缓存容量10000条TTL 1小时。对于超过1小时的消息即使重复也重新处理因为业务上通常不会隔这么久重试。5.4 长任务的处理策略HTTP请求-响应模式不适合长任务。如果智能体处理一个任务需要5分钟客户端等5分钟才收到响应中间任何网络中断都会导致失败。我的策略是异步化客户端发submit请求服务端立即返回task_id然后客户端轮询状态。轮询间隔要合理太短浪费资源太长延迟高。我的经验值是前10秒每秒轮询一次10秒到1分钟每5秒一次1分钟以上每30秒一次。这个退避策略能平衡实时性和资源消耗。5.5 跨语言实现的兼容性问题ANP是协议不同语言都可以实现。但不同语言的加密库、JSON库、HTTP库行为有差异。我踩过的坑包括Java的BigInteger序列化成JSON时默认输出数字Python的int也是但JavaScript的Number精度不够Go的time.Time序列化格式与Python的datetime不同Rust的serde_json默认不保证字段顺序。解决方案是制定一份“实现者指南”明确规定每个字段的类型、格式、序列化方式。比如时间戳统一用Unix毫秒整数大整数统一用字符串JSON字段顺序按字母序排列。这份指南比协议本身更重要因为它决定了不同实现能否互通。5.6 安全相关的注意事项ANP的消息签名能防篡改但不能防重放。攻击者可以截获一条合法消息原样重发。时间戳窗口能缓解这个问题但窗口内重放仍然可能。更严格的方案是接收方维护一个message_id黑名单但黑名单的同步是个问题。另一个安全问题是DID文档的托管安全。如果攻击者控制了DID文档的托管服务器就能替换公钥从而伪造签名。解决方案是用HTTPS加证书固定或者把DID文档的哈希写到DNS TXT记录里接收方验证哈希后再使用。还有一个容易被忽视的问题错误消息可能泄露内部信息。比如签名验证失败时不要返回“公钥不匹配期望的指纹是xxx”只返回“签名验证失败”即可。详细的错误信息应该记在服务端日志里不返回给客户端。6. 我对ANP落地的一些个人判断ANP的设计思路是对的它抓住了多智能体协作的核心矛盾——身份和消息的标准化。但它毕竟是一份草案距离生产级可用还有距离。我在实际折腾过程中最大的体会是协议本身不复杂复杂的是生态。DID的解析、密钥的管理、消息的规范化、错误的处理每一项都需要大量工程投入。如果你只是想在自己的系统里让几个智能体协作不一定非要上ANP用简单的HTTPJSONAPI Key也能跑。但如果你要做的是一个开放平台让第三方智能体接入那ANP的DID身份体系和标准化消息格式就很有价值了。最后分享一个我在调试时常用的小技巧写一个“消息录制回放”工具把所有进出的ANP消息原样存到文件里包括签名和DID文档快照。出问题时用这个工具离线重放能快速定位是签名问题、序列化问题还是业务逻辑问题。这个工具帮我省了大量调试时间建议你也搭一个。
返回列表