
做 Agent 开发这行总会遇到一个特别让人兴奋的问题如果给我一百万个 Agent系统会变成什么样很多人第一反应是模型、提示词、技能库、编排框架。但以我看过不少平台级 Agent 项目的经验来说问题会先一步变成分布式系统问题。一百万这个数字一出现你马上要面对的就是调度、状态、通信、一致性、故障恢复这些老掉牙又躲不掉的东西。这篇文章就是聊聊为什么 Agent 规模上去了本质就是在做分布式系统以及落到实操上要解决哪些具体问题、怎么设计架构、有哪些参数值得提前想清楚。适合正在做 Agent 平台、多 Agent 协作系统或者被并发问题困扰的后端和平台工程师参考。1. 百万 Agent 的真正瓶颈藏在分布式系统的老问题里1.1 从单个 Agent 到百万 Agent问题性质完全变了单个 Agent 跑通 demo 是件很爽的事。你给它一个目标它自己规划、调用工具、迭代执行偶尔出点小错也不影响你感叹“这玩意儿真聪明”。这时候你关注的是上下文窗口、提示词结构、工具调用格式、模型选型这些本质上都属于“让一个 Agent 变聪明”的问题。但当你开始做平台要把 Agent 数量推到一万、十万、一百万关注点就完全漂移了。一个 Agent 是聪明的个体一百万个 Agent 就是一座城市。城市能不能运转不取决于某个市民有多聪明而取决于交通、供水、供电、治安这些基础设施。对应到系统里就是任务怎么调度、状态放哪里、Agent 之间怎么通信、挂了怎么恢复、谁该先跑谁该等。这些不再是 AI 问题而是分布式系统的经典问题。我见过不少团队死磕 Agent 的规划能力却在 1000 个并发会话时把服务压垮。原因是他们没意识到每多一个 Agent就多一分网络开销、多一块状态要维护、多一种故障可能。单个 Agent 出故障只是重试一次的问题百万 Agent 出故障就是集群雪崩的问题。所以与其说是 Agent 开发不如说你在用一套分布式系统的思路养一群 AI 打工仔。1.2 分布式系统三大经典问题Agent 场景全都踩中分布式系统讲了这么多年核心问题就三件事一致性、可用性、分区容错。你往 Agent 场景里一对照发现一个都躲不开。一致性多个 Agent 同时读写同一个共享状态时你怎么保证不脏读、不重复执行比如两个 Agent 同时看到一个订单待支付状态各自去调用支付工具那就重复扣款了。这跟多个线程同时改一个数据库记录本质同源。可用性某一个 Agent Runtime 节点宕机、某台机器上的几十个 Agent 会话全部消失平台不能整体挂掉。这不是“重启一下就好了”的事而是要有探活、有摘除、有会话迁移机制。一个节点挂是常态关键是剩下的九十九万九千九百九十九个 Agent 还活着。分区容错Agent 之间靠网络通信网络抖动、消息丢失、延迟飙升都是家常便饭。典型场景是一个 Agent 发出任务后没收到回复它到底该重试还是放弃重试可能重复执行放弃可能丢任务。这就是分布式系统里最经典的“网络不可靠”问题。记住一句话消息可能丢失也可能重复时序还可能颠倒。Agent 平台的设计里这一条要刻在脑门上。情调一句题外话Agent 这个词在不同领域含义差别很大比如 ROS2 里的 Micro-ROS Agent 是设备和 ROS 总线之间的通信代理跟我们说的 AI Agent 不是一回事。但只要数量上来了底层都要面对连接并发和消息可靠性的问题。这就是分布式系统的魅力它不管你上面跑的是 AI 还是机器人。2. 先拆解再搭建Agent 平台的分层架构设计2.1 Agent 不是一个进程而是一套“角色组合”很多人理解 Agent 就是“一个程序或一个进程”。这在单机 demo 里没问题但到了百万规模必须把一个 Agent 拆成多个可独立扩展的角色。我习惯把一个 Agent 平台拆成四层执行层Runtime负责跑 Agent 循环包括感知、规划、调用工具、生成输出。这一层是“苦力”需要能快速创建和销毁。编排层Orchestrator负责决定哪个 Agent 在什么时候干什么负责任务切分、流程控制、结果汇总。这是“管理者”。状态层State/Memory保存 Agent 的 working memory、长期记忆、会话状态、任务结果。这是“记忆力”。通信层Message Bus负责 Agent 与 Agent 之间、Agent 与平台之间的消息传递。这是“神经系统”。有了这个拆分你才能做到“跑一百万个 Agent”而不是“启动一百万个进程”。Agent 本身只是逻辑上的一个工作单元真正运行的时候执行层复用它、编排层调度它、状态层记住它、通信层串联它。四层各自水平扩展才是百万规模的正确姿势。顺带聊聊“harness 和 Agent 的区别”。Harness 是 Agent 的执行外壳负责跑循环、管理工具上下文、控制调用的进出Agent 是里面的决策逻辑也就是那个根据目标思考和行动的东西。你可以理解成 harness 是操作台Agent 是操作员。平台层面做规模的第一优先级是把 harness 做扎实——它才是真正承载并发的东西。2.2 框架与编排为什么“能跑”和“能规模化”是两码事现在主流 Agent 框架比如 LangGraph、CrewAI、AutoGen包括 Spring AI都很擅长让你快速搭出能跑的 Agent。这些框架的默认假设是你已经在一个可控的小环境里。你定义一个图、塞几个节点、指定工具然后跑通一个任务体验确实不错。但如果你把它直接搬到百万 Agent 的场景就会撞墙。框架默认帮你管理的是“一个 Agent 的生命周期”不是“一百万个 Agent 的系统”。你要自己做持久化状态不然重启全丢要做重试和幂等不然重复执行要接队列不然同步调用全卡死还要做配额和隔离不然一个別扭的 Agent 拖垮整个集群。编排层设计这里有个很容易犯的错一开始就用复杂的 DAG 编排。我建议优先考虑事件驱动。任务粒度要小每个任务尽量是一个独立可重试的单元Agent 之间的协作通过事件解耦而不是通过直接调用解耦。控制面和数据面最好分离调度决策是一套逻辑实际执行任务是另一套逻辑否则你会在高峰期发现调度器自己成了瓶颈。框架可以帮你起跑但跑得远不远取决于你是否有自己的调度和状态设计。框架是轮子不是整辆车。2.3 多 Agent 协作消息协议比角色定义更重要多 Agent 系统里很多人把精力花在“给每个 Agent 写角色人设”上。这个当然有意义但到了规模化阶段真正决定系统能不能稳定运转的是消息协议。Agent 之间通信要定义清楚几种基本消息类型任务消息、结果消息、状态消息、错误消息。每种消息要有唯一 ID、来源、目标、时间戳、上下文引用还要有明确的幂等标识。没有这些你在排查问题的时候会完全抓瞎因为你不知道一条消息是哪个 Agent 发的、处理到哪一步了、是不是重复的。通信模式上我强烈建议少用同步阻塞调用多用异步消息。想象一下 A Agent 调 B Agent 拿结果B 又调 CC 再调回来如果中间某一步网络抖了一下整条链路的超时会把资源全占住。异步化以后A 发完任务就去干别的结果回来再继续系统的吞吐能力会完全不一样。消息中间件的选型也是老生常谈的问题。Redis Streams 适合轻量级场景部署简单吞吐够用RabbitMQ 可靠性和路由能力好适合任务分发Kafka 适合高吞吐事件流适合做审计日志和事件溯源NATS 则是轻量高并发消息的好选择云原生场景很舒服。不要神化任何一个按吞吐、可靠性、运维成本来选关键是别把消息队列当成数据库用。3. 百万 Agent 扛并发调度、存储与通信的实操设计3.1 并发模型Actor 是 Agent 最自然的形态如果你要硬扛百万级 Agent你首先要想清楚一个问题一百万个 Agent 在计算上到底怎么共存为每个 Agent 起一个进程显然不现实开一万个线程也够呛。这里最自然的答案是 Actor 模型。Actor 的特点是每个实体有自己独立的状态不和其他 Actor 共享内存通过消息通信。这不就是 Agent 的完美映射吗Agent 有自己的记忆和状态Agent 之间不直接共享变量只能通过消息协作。用 Actor 模型实现 Agent对应关系特别干净。Erlang、Akka 这些老牌 Actor 生态以及 Kotlin 在 JVM 上的协程 Actor 实现比如最近很火的一些 Agent 框架就在这么干都是这个思路。Rust 这两年受关注多也跟这个有关。Rust 的内存安全和无 GC 特性加上强大的并发原语让它在写 Agent Runtime 时很有优势。你不用担心某个 Agent 的状态被另一个线程搞坏也不用为垃圾回收停顿牺牲延迟。一个高并发 Agent Runtime 用 Rust 写底层稳上层就可以放心堆业务逻辑。实际操作上我的建议是一个进程里跑 N 个 Agent 会话而不是一个 Agent 一个进程。Agent 大部分时间都在等大模型接口返回这是 I/O 密集型不是 CPU 密集型用协程或 Actor 可以轻松做到每个 Agent 的“虚拟并发”。同时要做 Agent 池化复用 Runtime、复用上下文构建避免每个任务都从零开始初始化那点开销在百万规模下会被放大得非常惊人。3.2 调度关键参数怎么拍很多人问我百万 Agent 的并发参数怎么定我说别凭感觉拍拿数据算。先估算活跃比例。一百万个注册 Agent 不可能同时干活大部分时间是休眠的。按经验峰值活跃率 5% 已经很高了也就是 5 万个 Agent 同时在线。每个 Agent 一轮完整的“感知-决策-行动”如果平均耗时 3 秒主要花在大模型接口等待上那单个 Agent 每秒大约产生 0.3 次操作。5 万活跃 Agent 加起来的平台操作吞吐就是 1.5 万 QPS 左右。如果单个节点稳定处理 2000 QPS 的任务调度与转发那你至少需要 8 个节点再算上 30% 到 50% 的冗余准备 12 个节点比较稳妥。注意这只是任务调度层不含模型调用层模型 API 的 QPS 可能还要翻几倍。再说到队列长度、超时时间这些参数我的推荐起点是参数推荐值设计理由最大并发数节点数 × 单节点并发上限防止单节点过载队列长度并发数的 3~5 倍吸收流量尖峰又不至于积压过期任务超时30 秒给模型调用留足时间又不拖垮全局模型调用超时15 秒单次 API 调用比任务粒度更短背压策略限流 退避重试拒绝不如排队排队不如通知上游降速这些数值不要死抄要拿你自己的压测数据调。但设计思路可以抄队列不是为了无限堆积而是为了吸收抖动超时是为了防止一个慢 Agent 占住资源不放背压是为了让整个系统在过载时优雅降级而不是直接崩掉。3.3 记忆与状态working memory 和长期记忆必须分层Agent 的记忆问题在百万级系统里特别容易出事故。如果你把每个 Agent 的完整对话历史全部放在内存里10 万个活跃 Agent 每人 8K token按每个 token 两三字节算光上下文就是 1.6GB 到 3.2GB这还只是放得下而没算检索开销。真到线上你还要考虑索引、序列化、网络传输内存会越滚越大。所以记忆必须分层而且层与层之间要边界清晰。第一层是 working memory也就是当前 Agent 正在用的上下文。它的特点是热、小、快适合放进程内或 Redis按 Agent ID 做 key存最近几轮的关键信息。第二层是长期记忆包括历史对话摘要、用户偏好、任务结果、知识片段适合放数据库或对象存储。第三层是向量检索库用于做语义召回给 Agent 提供“想起来”的能力。状态设计上有几个细节很值得注意。一是状态要精简一个 Agent 的工作状态如果能用 JSON 表达就不要搞成几十个字段的大对象。二是状态要做 checkpoint一个任务执行到一半挂了恢复时可以接着跑而不是从头开始。三是状态要有 TTL尤其是 working memory过期了就要归档或清理不然系统内存会被历史包袱拖垮。还有一个很容易忽略的点Agent 长时间运行后对话轮数越来越多上下文最终一定会超出模型窗口。我的方案是滑动窗口加自动摘要。超过 N 轮之后把最老的几轮压缩成一段摘要再丢进长期记忆同时保留关键结论在 working memory 里。这样 Agent 既不会丢全局信息内存也不会无限膨胀。4. 真实故障复盘百万 Agent 场景下的排查与避坑4.1 四个典型事故复盘先说一个我碰过的真实事故同步调用链引发的级联超时。当时两个 Agent 通过工具互相调用A 调用 B 的执行接口拿结果B 内部又调用 C结果某个环节延迟从 2 秒飙到 20 秒A 一直占着线程等响应大量请求积压最终整个服务超时雪崩。排查出来以后我们把所有跨 Agent 调用全部改成异步消息A 发任务后立即释放资源结果通过消息回传。改动以后同样流量下响应时间反而更稳定了。血的教训Agent 之间的调用一定不要同步链路消息总线才是正解。第二个事故关于消息重放。一个消费者节点处理任务时崩溃了任务重新入队后再次执行外部支付接口被重复调用。原因是没有幂等设计。后来每个任务都带幂等键外部 API 调用前先去重表检查状态才彻底解决。这种事不要心存侥幸分布式环境下消息重放是常态不是异常。第三个事故是内存逐渐增长最后 OOM。一个 Agent 会话设计成“永不结束”上下文越积越多几万个这样的会话直接吃光内存。排查时看了一眼状态存储的大小就知道问题在哪了。后来加了上下文滑动窗口和自动摘要内存立刻稳定下来。Agent 会话要有生命周期该归档就归档该终结就终结。第四个事故是热点 Agent 打满队列。某个 Agent 因为一个热点事件被大量触发短时间内产生了十万条任务把消息队列全部占满其他 Agent 的任务全饿死。解决办法是给每个 Agent 和每个租户都做独立配额和队列分片一个热点只能在自己的桶里爆炸不能炸到别人。4.2 排查问题的方法论与速查表Agent 平台的问题排查跟传统分布式系统没有本质区别核心是先定位瓶颈在哪一层。我的排查顺序永远是先看队列积压再看模型调用延迟再查状态存储最后才怀疑业务代码。症状可能原因排查手段修复方向Agent 集体超时同步调用链阻塞、模型 API 延迟飙升查看调用链追踪看 P99 延迟异步化改造、熔断降级部分 Agent 丢消息消费者崩溃未确认、无重试机制检查队列积压和消费组状态开启手动 ack、死信队列、重试内存持续上涨上下文无限累积、会话不回收监控内存占用与状态存储大小滑动窗口、摘要压缩、会话 TTL某类任务延迟变大热点 Agent 占满队列、消费能力不够查看队列积压分布按 Agent ID 分片、独立配额工具层面Prometheus 加 Grafana 做指标监控Jaeger 这类分布式追踪做链路追踪再加上结构化日志基本是标配。给每个任务分配一个 trace_id从触发到执行完毕全程带上去排查问题的时候能省你半天时间。这个习惯一定要从第一天养成别等出事故再补。4.3 安全与资源隔离多租户 Agent 平台的红线Agent 平台的安全不是最后才补的是架构设计时就该定死的红线。首先是执行环境隔离。Agent 调用工具、执行代码一定要在沙盒环境里跑不能让 LLM 的输出直接变成生产环境的任意命令。你要把工具调用白名单化LLM 只负责表达意图实际执行要经过一套权限校验。这个没得商量线上环境任何一个指令被恶意拼接后果都可能很灾难。其次是凭据管理。每个 Agent 的 API 密钥、数据库密码一定要走密钥管理服务不要塞到 prompt 里更不要打日志。给每个 Agent 的权限尽可能最小化它能干的事越少出事范围就越小。别为了省事让一个 Agent 拿到整个平台的默认权限。然后是配额与审计。每个 Agent、每个租户都要有资源配额包括 token 数、API 调用次数、并发上限、存储大小。审计日志记录每个 Agent 的关键行为谁在什么时间调了什么工具、结果是什么。出问题能查账也是多租户平台的基本信任基础。5. 演进路线从单体 Demo 到百万级平台我建议按这个顺序走5.1 四步演进别一口气追求完美架构如果你现在是从零开始做 Agent 系统别一上来就铺 Kafka 加 K8s 加一百个微服务。先走一条务实的演进路线。第一步把单个 Agent 做扎实。把提示词、工具、上下文、模型评估这些都调好让一个 Agent 在真实任务上稳定可用。这一步没走好后面所有分布式设计都是在给垃圾系统扩容。第二步异步化改造。引入消息队列把 Agent 之间的同步调用改成异步事件同时把日志、监控、追踪三件套补上。这一步做完你会发现并发能力突然上了一个台阶而且出问题能查了。第三步状态外置与水平伸缩。把 working memory 和长期记忆从进程内搬到 Redis 和数据库Runtime 节点变成无状态的随便扩容缩容。这一步做完你就真正具备了从几千到几万并发的底子。第四步多租户隔离与配额治理。引入沙盒安全机制、配额、审计、分片隔离让平台上跑着不同的团队、不同的业务也不会互相干扰。这一阶段做完你才敢说这是一个企业级的 Agent 平台。每一步的触发信号要想清楚。比如第二步当集群堵在同步超时、你开始天天重启服务时就该做了。第三步当单节点内存已经扛不住会话状态时别犹豫马上做。别为了架构好看而超前设计架构是被流量逼出来的。5.2 写在后面的一些个人心得聊到这里我最深的体会是分布式系统和 Agent 从来就不是两套技术而是同一件事的两面。很多团队前期死磕 Agent 的“聪明程度”把幂等、背压、状态分层这些基本功晾在一边结果规模一上来就返工重写。你要是现在正在搭 Agent 平台我真心建议把每一行消息都当成可能会重发来设计把每一个状态都当成可能被多节点同时访问来设计。还有一个不小的收获是Agent 的失败和下游系统的失败要区分对待。Agent 自己判断错了可以靠模型迭代慢慢改善但下游支付、通知、数据写入这些系统一旦因为 Agent 平台的重试而重复执行那就是事故。所以面对外部系统的调用幂等键、状态机、审计日志这三样什么时候都不过时。最后分享一个小技巧给每个 Agent 设定明确的“终结条件”不要让它无限循环下去。从工程视角看一个不知道什么时候结束的 Agent就是一个永远占着资源的分布式任务跟一个死循环的 goroutine 没有本质区别。给 Agent 加一个最大步数、最大耗时、最大成本预算你会发现系统的稳定性和可预测性会大幅提升。