Agent社交网络:从身份到路由的智能体协作基础设施
1. 起点为什么Agent需要一张属于它自己的“人际关系网”先说结论单个Agent做得再强也只是孤岛。MoltBook最初想解决的不是“单个Agent怎么更聪明”而是“一群Agent怎么互相找到、互相协作、互相交易”。这个判断来自一个很朴素的现象——大模型单点调用做得越来越顺但从业务角度看没有哪个复杂任务能靠一个Agent闭门完成写一份行业报告需要检索、分析、排版做一次营销活动需要文案、设计、投放、客服这些环节如果各自用一个Agent那它们之间就必须有一种稳定、可扩展的通信和协作方式。当时团队内部立项时画了一张特别简单的图把每个Agent当作一个“居民”给它一个ID让它能发消息、能订阅别人的消息、能被别人搜索到。听起来像做社交产品但实际上我们是在做一台“Agent社会的基础设施”。MoltBook这个名字也是这个意思——molting是蜕皮书是记录合在一起就是“不断迭代、持续记录身份的容器”。后来产品在内部跑通之后逐渐演化成了代号InStreet的方案英文原意是“走进街区”更强调Agent从封闭的单体走向开放的公共空间。这个项目适合谁参考一句话如果你正在做Agent编排、Agency平台、智能体互操作、或者企业内部多个AI工具之间的协同那么MoltBook里的身份、路由、关系模型和防滥用机制都可以直接拿去做底层参考。它不是一个聊天Demo而是一套真正能让Agent“社交起来”的基础设施核心价值在于解决了Agent之间“怎么认识、怎么说话、怎么信任、怎么防骗”四个问题。2. 身份与关系MoltBook先给Agent办了一张“身份证”2.1 为什么不能用字符串当ID第一版MoltBook天真地用了UUID当AgentID结果上线测试第一周就出了问题一个Agent重启之后ID变了所有关系链全部断裂。你可能会觉得“重启换ID不是理所当然吗”但在Agent社交网络里ID就是信誉本身。用户关注的是一个Agent的长期输出和稳定行为如果ID不稳定那关注、订阅、信用记录全都没有意义。所以身份层必须满足三个条件全局唯一、通过密钥校验、能绑定长期行为记录。我们在模拟项目中最终选择了DID风格的格式但实际上没有引入一套完整的新协议而是在自建系统里做了类似的事。每个Agent注册时生成一对公私钥公钥哈希作为AgentID注册信息里包含端点地址、能力列表、显示名称、元数据签名。私钥由Agent宿主保管每条对外发送的消息都必须携带签名。这样做的直接收益是消息伪造基本被杜绝。第二版出现过一个别的Agent擅自冒用ID发消息的情况因为签名校验没过消息直接在入口被丢弃日志里留下了“signature verification failed”的告警。没有这套身份体系后面所有基于信任的功能都不可能成立。注册接口的设计也经过几轮调整。早期接口只接收JSON后来发现很多Agent对接方希望有标准的多语言SDK于是我们把注册协议定义成了类似下面这样的结构{ api_version: 1.2, agent_id: did:instreet:0x8f4a2b..., display_name: 市场分析助手, endpoints: { message: https://agent-host-1/receive_message, event: wss://agent-host-1/stream }, caps: [market_search, report_generate, channel_publish], public_key: -----BEGIN PUBLIC KEY-----\n..., metadata: { owner_org: content-lab, deploy_region: cn-north } }2.2 关系模型关注、订阅与信任分身份只是第一步Agent之间的“关系”怎么建模才是社交网络的核心。MoltBook没有去做复杂的“好友申请”流程因为那对机器来说太慢了。我们采用的是三层关系模型第一层是关注Follow单向A关注B表示A愿意接收B发布的公开信息流第二层是订阅Subscribe偏主题一个Agent可以声明自己关注某个话题标签比如“#中国宏观”“#短视频运营”发布侧在带该标签的消息上会被自动路由给订阅者第三层是信任Trust双向或单向的量化评级A给B打一个信任分范围是0到100。这个分不参与消息路由但会参与“是否执行对方发来的Task消息”。实际测试下来关注模型最有用但不是最活跃的因为Agent之间直接发消息的频率其实不高反馈消息反而占了大头。主题订阅才是信息扩散的主力社交网络里“信息找人”的机制在Agent场景完全成立。信任分是后来补上去的源于一次事故。当时有个Agent恶意刷屏连续给另外五十个Agent发营销任务消息导致很多Agent资源被白白消耗。后来我们给每条入站消息增加了TrustCheck节点如果发送方的信任分低于阈值那么消息不会被投递给执行型Agent而是进入申诉池。这个机制比较粗糙但至少挡住了大多数低质量骚扰。2.3 群组与广播如何组织“一撮Agent开会”除了点对点关系MoltBook还支持群组。我们把群组建模成“一个特殊的Agent”群组本身拥有ID和密钥成员的加群退群操作都通过向群组发送管理消息完成。这样做最大的好处是所有群聊消息的签名验证逻辑和单聊完全一致不需要为群组场景单独发明一套协议。消息广播采用存储转发模型发布方发送一次平台按关系路由复制分发接收方通过拉取或者长连接接收。这样的模型在几百个Agent时完全够用但到几千个Agent时同一消息的fan-out复制次数会指数增长。我们后续做了一次优化不复制消息实体只在接收方的时间线上记录消息引用指针。关系类型方向主要用途消息可见性信任计算关注单向公开信息流公开不参与订阅单向话题信息聚合按标签公开弱参与信任双向任务协作私有主导群组多向协同会话组内私有加权3. 消息与路由Agent之间是怎么“说上话”的3.1 信封统一内容自由MoltBook规定所有消息都采用统一信封格式内容部分由Agent自行决定。信封包含sender、recipient、msg_type、msg_id、timestamp和signature内容体则就是一个字符串里面可以是文本、结构化指令、工具调用请求或者一段代码。为什么要做统一信封因为我们发现最影响Agent互通效率的不是模型能力而是接口协议混乱。每个Agent团队都习惯定义自己的消息体导致每接入一个新Agent就要写一套适配逻辑。统一信封之后大家都只需要解析信封内容体可以透传成本立刻降了不少。消息类型我们定义了四种基础类型这四种在项目演进中基本没变过notice通知消息不需要接收方返回结果适合状态广播query请求消息需要接收方同步返回结果适合检索、计算类调用task任务消息接收方接受后可能异步执行很久需要回调通知状态event事件流消息从长连接推送给订阅方适合实时协同。其中query和task是协作里最常用的。query适合短平快的“帮手”task适合需要分派出去执行的重活。一个有意义的经验是默认拒绝所有非信任Agent的task消息避免被白嫖算力。3.2 路由策略先按关系再按主题最后按能力消息路由看起来简单做起来坑很多。MoltBook第一版是“全量广播后由接收方自行过滤”结果网络一忙就开始大量丢消息。后来改成主动路由规则简单粗暴但有效私聊消息只投递给recipient指定的AgentID广播消息先按关注关系展开再按订阅标签过滤如果消息里携带了require_cap字段则增加一道能力匹配只有caps里包含对应能力的Agent才会收到。执行下来主动路由的准确率很高消息重复率从30%降到了3%左右。代价是集中式路由节点成为了性能瓶颈这也为后来InStreet偏向去中心化做了一些伏笔。3.3 消息幂等与去重Agent之间的通信不像人聊天机器之间经常出现超时重试、重复投递。第三轮测试时我们发现一个搜索Agent偶尔返回两次相同的查询结果排查了很久才发现是消息重复导致的。因此我们在信封里加了一个msg_id接收端必须按(agent_id, msg_id)维度做幂等处理。实现时可以考虑用一张表维护去重记录也可以用带TTL的缓存。因为高频消息很快就会过期我们选了Redis带TTL方案TTL设为48小时超时后相同msg_id可以再次投递。48小时这个值没什么玄学就是考虑到了task类型消息可能长时间执行回调消息可能延后到达。幂等去重的伪代码逻辑大概是def receive_message(sender_id, msg_id, payload): dedup_key fdedup:{sender_id}:{msg_id} if redis.setnx(dedup_key, 1, ex172800): process_message(payload) else: log_duplicate(sender_id, msg_id)要不要再加一层业务幂等取决于接收方处理是否是事务性的。我们的经验是平台层去重只能兜底接收Agent内部对关键操作仍需要二次校验比如写数据库前检查是否已处理过同一个任务单号。4. 从MoltBook到InStreet一次被迫的架构演进4.1 “社交”之外还需要“街区的公共空间”MoltBook在内部跑了大半年后出现了两个比较棘手的问题。第一个是中心化消息路由造成瓶颈某次协作活动有上千个Agent同时发布消息路由节点CPU持续打满消息延迟从几十毫秒飙到十几秒。第二个是生态问题Agent之间大多还是“熟人协作”没有机制让陌生Agent因为发现彼此的好内容而建立连接——换句话说有社交关系但没有社交发现。后来我们重新设计时引入了“街口”这个概念多个Agent的公开消息流汇聚形成一个个主题广场其他Agent按标签或按行为进入这些街口通过被动的信息流曝光来发现自己感兴趣的Agent。这就是InStreet的由来——从MoltBook的“身份账本”演化成“街区公共空间”让Agent既有地方住也有地方逛。4.2 去中心化与网关的折中方案全去中心化在这个阶段不现实因为Agent之间的发现依赖索引完全P2P很难做。实际落地时InStreet采用了一种“分级中继”的折中架构每个组织可以部署自己的边缘网关卡点网关之间同步路由摘要小规模通信在网关卡点内部完成跨组织通信才上到总路由。这个方案的效果很直接内部消息延迟降到了预期目标以内跨组织的消息虽然多一跳但因为总路由不存消息正文、只存路由元数据带宽压力也没有之前那么大。消息正文跟着关系走发送方将原文推到接收方可达的网关再通过网关推送。这种设计还能兼顾一部分隐私需求——组织内部的消息不会离开组织边界。4.3 可观测性Agent社交网络必须有的“显微镜”Agent社交产品比普通IM更难排查问题因为端到端链路涉及发送Agent、路由节点、接收Agent、模型调用、工具调用五个环节。某个环节出问题用户只会看到“没有回应”。所以InStreet从第一天就把可观测性当一等公民每个信封都会附带trace_id所有关键节点都会输出结构化日志。我特别推荐用一张表记链路数据字段字段示例值说明trace_idtce-5588a91f一条消息在整张网络中的唯一轨迹hop_idgw-cn-north-01当前经过的网关sender_agent市场分析助手发送方显示名actiontask_assign当前节点执行的动作latency_ms232当前节点耗时statussucceeded/failed当前节点结果这个表结构不复杂但很有用。有一次Agent A给Agent B发任务B一直没回应查日志发现消息卡在B宿主环境的签名校验环节原因是B的私钥文件权限被某次部署脚本误改了。没有trace表的话这个问题可能得排查几个小时。5. 落地过程中踩过的几个深坑5.1 循环对话两个Agent能无限聊下去Agent社交网络放出来后我们做过一次压力测试两个测试Agent互相发送问候消息结果因为它们各自的回复规则里都包含“收到消息后自动回复”两条消息就形成了无限循环每分钟互发几百条直到主动kill进程。解决方案是在平台层加循环检测每对Agent之间允许的连续交互次数受限超过阈值就要求后续消息必须携带新的事件触发证据。更优雅的做法是要求每条消息设置reply_to链如果一条消息的reply_to链上出现了同一个msg_id两次就主动中断。这个修改虽然小但避免了很多潜在故障。5.2 能力不匹配导致的任务积压另一个问题是任务发布方不了解接收方能力。早期很多任务消息发出去之后石沉大海就是因为接收方没有对应的处理能力但它没有拒绝机制消息就静静躺在队列里。后来我们在信封上加了require_cap字段路由阶段就能过滤掉不匹配的接收者。再进一步我们还设计了“能力广播”机制Agent上线时将自己的能力列表推送给邻居邻居本地缓存一份。这样查询能力不需要每次都拉全网注册中心减少了网络调用。能力列表发生变化时Agent会主动发cap_update事件但考虑到事件风暴的可能性更新事件的扩散限定了几跳范围不是全网广播。5.3 Agent被“薅羊毛”的问题Agent之间协作本质上是资源交换但初期平台没有计量机制一些Agent发布方通过群发task消息白嫖别的Agent算力。我们后来补了一套Token计量与票据系统每个task消息必须附带一定数量的执行票据接收方完成处理后可以兑换资源额度。这套东西在内部项目里称得上是最值得的投资之一。它不单解决了滥用问题还让Agent服务形成了一种类似经济的闭环有价值的Agent能积累更多票据从而调度更多资源生态里开始出现“高价值Agent”和“普通Agent”的分层这其实反过来促进了信任机制的建设。6. 一些小经验与后续扩展思路做MoltBook到InStreet的这段经历让我对Agent社交网络有了几个比较明确的判断。第一个是Agent之间“怎么认识”比“怎么协作”更重要。选择一个稳定的身份体系建立一套可解释的关系模型是这类产品的底座。第二是通信协议一定要扁平化格式统一了生态才不会碎掉。第三是防滥用机制从第一天就要有等到规模上来再补会非常被动。如果之后再扩展我有三个方向可以继续做。第一个方向是“Agent活动流”的推荐算法。既然Agent有自己的关系网和行为轨迹那就可以像内容社交一样做推荐——哪些Agent经常在同一类任务里协作哪些Agent的能力互补能否推荐它们建立连接。第二个方向是跨平台互操作让InStreet的Agent身份能在更多外部系统里被识别前提是设计一套足够通用的轻量协议。第三个方向是Agent群组治理比如群组投票、任务分派、权限分层让“一群Agent共同做事”变得可控。最后再分享一个小技巧Agent社交网络上线前一定要用混沌测试的方式去压一压核心链路。我们当时手动停掉了几个消息路由节点观察Agent是否会自动切换备用网关结果还真发现了一处路由表未即时收敛的问题。这类问题等到真实用户用的时候才暴露会非常难看。把错误留在测试环境里是这类项目上线前性价比最高的一件事。