把 AI 智能体从 Demo 推到线上,最让我意外的事情不是模型能力,而是基础设施。过去一年多,我们团队陆续接了十几个智能体项目:有做客服自动应答的,有做数据分析的,有帮运营写周报的。Demo 阶段全都跑得挺顺,可真要一上线,问题就全冒出来了:并发上来之后实例怎么扩,会话记忆放哪儿,工具调用超时了怎么重试,一个死循环的智能体把账单价钱跑穿怎么办。折腾了几个月,我们干脆盘了盘需求,做了一个专门为 AI 智能体设计的按需运行平台,项目代号就叫 Agent Droplets 服务器。它不是一台物理服务器,而是一套“面向智能体会话的云基础设施”:按事件拉起独立运行实例、用完自动销毁、状态通过事件流保存,开发者只需要定义智能体行为和工具集,剩下执行、调度、容错、观测都交给平台。这篇文章不是官方文档复读,而是把设计和上线过程中那些真实的取舍、踩过的坑、以及“为什么这样设计”讲清楚。如果你正在考虑把智能体从脚本升级成长期运行的线上服务,或者正在纠结要不要自建一套智能体调度平台,那这篇应该能帮你省不少弯路。1. 为什么拿普通虚拟机跑智能体总是不得劲:Agent 工作负载的真实画像1.1 传统服务的假设,在智能体这里全部失效我先说结论:智能体本质上不是“网站”,不是“API 服务”,也不是“定时任务”,它是一个被事件驱动的、有上下文状态的、会主动调用外部工具的短时计算流程。最开始我们也偷懒,直接把智能体进程挂在一台常驻虚拟机上,24 小时跑个 Python 服务监听消息。第一版 demo 没什么问题,可一旦放真实流量就非常别扭。常驻虚拟机天然假设流量是相对平稳的:每个请求昂进来,处理完,返回响应,服务器一直活着等下一个。但智能体的流量是按会话、按事件触发的,波动极其剧烈。上午十点可能只有 3 个活跃会话,下午搞活动突然涌进 300 个,每个会话内部还要为了回答一个问题连续做十几次工具调用。这种负载跑在固定资源池上,要么闲时白掏钱,要么忙时疯狂排队。而且智能体的计算特点和普通请求很不一样。普通 web 请求通常一两秒就结束,CPU 和内存的占用相对规律。智能体不同:它在等大模型推理响应的时候基本不占 CPU,等结果一回来立刻进入工具执行阶段,可能又要调数据库、抓网页、算表格,一下子就飙起来。你很难用“QPS”去衡量它,唯一合理的衡量单位是“活跃会话数”,以及“一个会话内产生了多少次工具调用”。1.2 会话状态:最容易被低估的麻烦另一个让我非常头大的点是状态管理。普通服务是无状态的,数据库再存一份就行。智能体天然必须有状态:聊到一半,它得记得刚刚说过什么;执行到第三步,它得知道第一步查出来的订单 ID;用户中断了一次,下次回来还得能接着上一段继续。我们最早把状态直接存在进程内存里,结果服务一重启,所有会话全断了,用户骂声一片。后来换数据库,把整段会话历史当一个大 JSON 存进去,又出现并发写覆盖、拉取慢、历史长了大模型输入超限这些问题。状态不是一个“存下来”这么简单的事,状态是智能体的命根子,它的保存方式直接决定了系统能不能续跑、能不能调试、能不能回滚。我们当时的判断是:需要一种“按会话生命周期来设计的运行模型”。智能体会话一旦触发,平台给它起一个隔离的运行环境,环境里加载好工具、系统提示词、历史状态;执行完一步,立刻把这一步的事件追加到持久化存储;整个会话结束或者闲置超时,运行实例可以销毁,但状态留着,随时可以重新拉起继续跑。这就是 Agent Droplets 的原始出发点。一张表可以很直白地看出差别:维度传统长驻服务智能体会话负载运行周期常驻,以月计按事件启动,一般只有几十秒到几十分钟资源特征相对平稳的并发突发、间歇,等待和计算交替出现状态特性无状态或依赖数据库强上下文,必须支持中途续跑外部依赖数据库、缓存、外部 API大模型接口、各种工具 API、数据库,且工具调用频繁成本颗粒度按实例/按月按会话/按步骤最合理故障方式崩溃、超时、过载死循环、反复调用同一工具、状态错乱看这张表你就能明白,为什么我们最后没有选择“在虚拟机上堆智能体进程”,而是专门做了一个平台层。虚拟机能解决“算力从哪来”,但解决不了“会话怎么管理”“状态怎么续”“工具调用怎么隔离”这些问题。2. Agent Droplets 的形态:按需启动、自动销毁、状态可续的架构拆解2.1 不是云主机,不是 PaaS,是“智能体执行器”Agent Droplets 服务器这个名字,关键在 Droplets。我们内部约定,一个 droplet 就是一个“智能体运行实例的虚拟化单元”。当某个事件触发一个智能体会话,调度器就创建一个 droplet:分配内存、CPU、容器环境的隔离边界、配置好的模型调用凭证和工具权限。它在只够完成当前这一步或当前这一段会话的时间内存活,干完就销毁,绝不赖着不走。有人会问,这是不是就是 Serverless 容器?接近,但不完全一样。普通的 Serverless 函数是“无状态、单次执行”,智能体需要多步推理、记忆上下文、工具调用链路,这些都要在 droplet 内部被编排好。所以我们在 droplet 之上封装了三个核心组件:调度控制面、沙箱运行时、状态总线。三者配合,才让“按需启动、自动销毁、状态可续跑”真正成立。2.2 调度控制面:负责拉起、排队、回收调度控制面是平台的入口,它接收三类触发:HTTP 回调、消息队列事件、定时任务。每次触发都会携带会话 ID,控制面根据会话 ID 判断:这是新会话,还是已有状态需要继续执行的分支?如果是续跑,它会先把历史事件从状态总线拉出来,组装成上下文,再分配 droplet。控制面另一个关键职责是配额管理。我们不允许一个用户无限拉起 droplet。每个账号有并发上限,有事件速率限制,有全局超时。这些参数不是拍脑袋定的,而是来自我们对真实故障的复盘,后面我会专门讲那些故障。控制面还有一个容易被忽略的功能:回收。一个 droplet 到了闲置阈值必须回收,到了会话最大时长必须回收,外呼 API 连续失败达到次数也会触发熔断回收。回收不是粗暴杀进程,而是先通知 agent 保存检查点,再销毁实例,保证下一次还能从状态总线里续上。2.3 沙箱运行时:让工具调用不失控智能体的核心动作是工具调用。工具包括:查订单库的 SQL、调内部 HTTP API、外呼某个搜索结果页面、读写文件、甚至模拟浏览器操作。这些动作涉及权限、密钥、网络边界,绝不能让它直接在宿主环境里裸奔。我们的做法是:每个 droplet 运行在轻量级容器段中,给最小化系统权限;外部网络访问走代理网关,网关做域名白名单和协议白名单;敏感密钥不写进环境变量明文,而是通过密钥注入组件在运行时注入到进程内部。也就是说,智能体自己拿不到明文密钥,它只能通过平台封装的工具令牌去调外部服务。一个特别容易踩的坑是,智能体在调用工具之后的返回结果往往很长,数据量很大,如果直接把原始返回值塞回上下文,很快就把大模型的输入窗口塞爆了。我们在运行时里做了返回体压缩和截断策略:大结果先存对象存储,上下文里只放摘要和引用地址,等智能体真正需要全量数据时再按需拉取。这个设计一开始不觉得重要,后续在长会话场景里救了我们很多次。2.4 状态总线:事件流追加,而不是整表覆盖说到状态,这可能是 Agent Droplets 和普通容器平台最不一样的地方。我们没用常规的关系型数据库去存“当前会话状态”,而是把状态设计成一条持续追加的事件流。每个会话产生的事件包括:user_input:用户发来的原始消息。model_call:大模型推理的请求和响应摘要。tool_call:工具调用名称、参数摘要、返回结果摘要。checkpoint:平台定期打的状态快照。system_event:超时、重试、配额命中、熔断。事件流按会话 ID 分片存储,写入采用追加模式,不存在“修改某一行”的需求。要恢复一个会话时,从最近的 checkpoint 开始,往后重放事件,就能精确还原到任意一步。这种设计带来了三个好处:一是并发安全,不会出现两个人同时改一条会话记录的冲突;二是可调试,每步都留痕,出了错能精确知道是哪一步、哪个工具、哪次模型调用导致的;三是可回退,如果新版本智能体跑出了坏结果,可以直接在同一事件流上分叉,回退到上一个 checkpoint 再试。创建一个 AgentRuntime 的配置大概长这样:apiVersion: droplets.agent/v1 kind: AgentRuntime metadata: name: customer-service-agent namespace: production spec: runtime: image: runtime-agent-base memoryLimit: 512Mi cpuLimit: "1" lifecycle: trigger: message idleTimeoutSeconds: 60 maxSessionMinutes: 30 state: store: event-bus checkpointEverySteps: 5 ttl: 7d tools: - order.query - order.batch_query - customer.lookup policies: maxConcurrencyPerSession: 1 stepTimeoutSeconds: 15 maxToolCallsPerStep: 4 fatalErrorRetries: 2这个配置描述了一个客服智能体的运行定义:每条新消息触发一个 droplet,单会话内不并发,闲置 60 秒自动回收,每条消息处理时长最多 30 分钟,状态保留 7 天,每 5 步打一次快照,每一步超时 15 秒,每一步最多调用 4 次工具。这些默认值背后,是对“失控比稀疏更可怕”的深刻理解。3. 上线前补齐的三个关键细节:冷启动、配额限制和状态续跑3.1 冷启动:用户没有耐心等一个 8 秒的“联网思考”智能体平台的冷启动体验,直接影响产品口碑。用户在聊天框里发一条消息,如果三秒没反应,很多人就已经关页面了。而智能体的冷启动原本是重操作:要拉起容器,加载运行库,拼装系统提示词,恢复历史状态,建立大模型连接池,初始化各种工具客户端。这套流程如果每次实时做一遍,少说也要五六秒。我们的解法分两层:热池和快启。热池里常驻一批已经初始化好的基础运行时实例,镜像已经加载完毕,工具注册表已经填充,事件流连接已经建立。新的 droplet 不是从零创建,而是从热池里拿一个实例,把会话 ID 和状态检查点绑定上去,允许用户代码在进程内完成。快启层的优化更细:模型上下文拼接复用模板,历史事件重放做了并行预取,工具客户端延迟初始化,只在第一次真正调用时才创建连接。实测优化之后,绝大多数会话在 1 到 2 秒内可以开始处理第一条消息,如果状态较长,会额外慢一点,但核心链路不会因为等待基础环境而抖动。值得说的是,热池不是越大越好。热池里的空闲实例也在吃内存,太多会浪费成本。我们的策略是根据近 5 分钟活跃会话量的预测动态调整热池大小,高峰期提前扩容,低谷期自动收缩。这块逻辑目前还在持续调优,但方向明确:按活跃会话趋势来预测,而不是按固定数量配置。3.2 配额:给失控智能体准备好“保险丝”智能体失控这件事,我们上线第一周就撞上了。某开发者写了一个循环调用工具的逻辑,智能体在一个会话里反复查询订单接口,每分钟打几十次。要不是监控报警,系统差点把业务数据库拖垮。从那以后,配额和熔断成了最高优先级的设计。现在的配额模型分三层:第一层是账号级并发数。比如每个正常账号最多同时运行 20 个活跃 droplet,超出的排队等待。这一层是控制整体资源池不被单一账号打爆。第二层是会话内速率。每个会话内部,工具调用频率、模型调用频率分别做令牌桶限流。如果某个行为超过了每分钟 30 次工具调用的阈值,平台直接中断该步骤,返回一个 quota_hit 事件,而不是让循环继续烧钱。第三层是全局时长预算。每个会话有累计处理时长上限,每条消息有步骤超时上限。国债时长用完,会话自动终止并要求开发者介入。这一层特别重要——智能体不像普通程序有明确的“结束”概念,它天然倾向于继续对话、继续尝试,没有预算,它就能永远跑下去。配套的还有循环检测启发式:当同一个工具、相同参数前缀在一个会话中连续出现多次时,平台会标记并暂停该 session,提示开发者确认是否为死循环。这个启发式不完美,会有误伤,但在真正出 bug 时,它能大幅降低损失。3.3 状态续跑:从“存会话”到“重放会话”的思路转换上线前我们犯过一个比较大的设计错误:我们最初想用云数据库存“会话快照”,每次对话结束后覆盖写一条最新状态。看起来很简单,但立刻遇到问题:并发写覆盖、半写状态、长上下文恢复慢,以及无法回答“为什么智能体这一步做出了这个决定”。后来切换成事件流模型,一切顺了很多。每个事件只做追加,不做修改,天然有审计能力。不同的会话分支也能表达——假如同一个会话有两个候选分支,每个分支都是基于同一段父事件流的延伸,最终可以选一条作为最终结果提交。事件流存得久了,还会有存储成本问题,所以我们又加入了分层保留策略:热事件保留 24 小时,用于实时调试;快照保留 7 天,用于一般续跑;线上需要长期归档的会话再转到对象存储做冷存。目前看,这种“事件流 + 快照 + 冷存”的组合,在成本、延展性、可恢复性之间是比较均衡的取舍。状态续跑的代码侧用法也很直接,调用方只需指定会话标识即可:droplets-cli invoke customer-service-agent \ --session 0d6a04b2-1c3e-4f89-9c2a \ --input "继续之前的订单查询"平台自动判断该会话是全新触发还是续跑,续跑时不需要调用方自己去组装历史上下文,这对前端同学非常友好。4. 跑起来之后的账单、超时和循环风暴:运维侧的真实情况与治理对策4.1 一次被 200 个容器冲垮的账单教训Agent Droplets 上线后第二周,我们的开发环境突然出现了几百个并发 droplet 同时被拉起的情况。查了半天,发现是某个开发者在调试时为每条消息都创建了全新会话,而且业务侧代码在异常时反复重试,每个重试都会触发一个新的智能体会话。结果就是:一分钟内,200 个 droplet 同时运行,账单快速上升,风控部门都被惊动了。这件事让我深刻明白一件事:智能体基础设施给的自由度越大,用户滥用造成的破坏就越大,必须提供“强制安全默认值”。现在新创建的 AgentRuntime 配置文件,如果开发者什么都没填,平台会自动套上一组安全默认值:配置项默认值为什么这么设单会话最大并发1防止同一会话并行导致状态错乱账号并发上限20防止单个账号打爆整个池单步骤超时15 秒模型或工具卡住能快速暴露单会话总时长30 分钟防止长尾会话无限占用资源工具调用速率30 次/分钟防止循环刷工具接口失败重试次数2防止无限重试放大人为故障这些默认值上线后被骂了一阵“太严格”,但跑了一个月,再也没有出现过账单失控或会话泛滥的事故。我始终认为:智能体平台的默认值应该宁可严格、不能宽松,开发者有特殊需要可以显式调高,但决不能默认放开。4.2 工具调用超时和重试:表面是网络问题,深层是设计问题运维过程中我们反复和“工具调用超时”打交道。智能体调用一个内部 API,本来 100 毫秒就好,结果对方服务偶发 5 秒才返回,智能体就会陷入等待;等待太久触发步骤超时,重试之后又是同样结果,整个会话看起来像卡死了一样。后来我们做了两件事。第一件,所有工具调用都走统一网关,网关负责设置合理的上游超时(默认 8 秒),并把重试策略统一收口:只有幂等工具才允许自动重试,非幂等工具失败后必须返回错误事件、由智能体自行决策。第二件,在状态事件流里拆分明细计时,把模型等待时间、工具调用时间、内部编排时间分开统计,这样定位问题能一眼看出瓶颈在哪,而不是每次都要盲猜。比如一个典型的事件记录:{ "session_id": "0d6a04b2-1c3e-4f89-9c2a", "event_type": "tool_call", "step_index": 7, "tool_name": "order.query", "status": "timeout", "latency_ms": 8520, "retry_count": 0, "quota_remaining": 12, "memory_peak_mb": 168, "ts": 1730503200 }把这样的结构打成结构化日志之后,再配合查询面板,我们可以按会话追出每一个工具调用的耗时分布,也可以在巡检时直接发现“某个上游接口的调用失败率突然攀升”,不用等用户投诉才知道系统出了故障。4.3 日志切分:一个步骤里发生了什么,必须拆开看智能体日志最让人头疼的地方是:模型输出、工具返回、代码内部逻辑全都混在一次执行里。如果按普通应用那样统一打到一个日志流,排查问题基本等于大海捞针。我们把每个步骤的埋点拆成了三类独立通道:模型轨迹:记录发送给模型的上下文长度、模型返回内容摘要、推理耗时。工具轨迹:记录工具名、入参摘要、出参摘要、耗时、状态码。编排轨迹:记录智能体代码内部的决策路径,包括条件分支、错误捕获、重试动作。三类通道分别用不同的标签做索引,但共享同一个会话 ID 和步序号。当问题发生时,先看编排轨迹确认代码走了哪条路;再看工具轨迹确认外部调用是否正常;最后才需要看模型轨迹确认是不是大模型理解偏了。这套设计不需要什么高深技术,但非常管用,它是我们调试智能体问题时最重要的利器。5. 什么场景适合放在 Agent Droplets 上,以及什么时候我建议你再想想5.1 适合这里的人:事件驱动、会话型、需要工具的智能体上线踩了这么多坑,同时服务了内部多个智能体项目之后,我们对“什么场景适合用这套基础设施”有了比较清晰的判断。最适合的场景首先是对话型助手。客服、售前、售后、内网知识问答,这些智能体天然是事件驱动的:用户来了消息才需要启动会话,会话有上下文,需要调内部系统查数据,完成后可闲置可销毁。放在 Agent Droplets 上,成本是弹性的,用户不聊就不产生成本,聊起来也能扛住并发。其次是自动化的任务分解型智能体。比如给运营写周报,它会先拉数、再总结、再排版;比如做竞品分析,它会先列关键词、再检索网页、再汇总结论。这类任务的特点是步骤多、耗时长,中间会有大量等待,状态续跑的价值非常明显。写一半断了也不怕,回去能从检查点继续执行。我们还有一拨用户在平台上面跑多租户的智能体服务,也就是开发者把自己的智能体包成 API 卖给下游客户。对他们来说,按会话计费、资源隔离、配额治理是一站式的,这比自己在云上搭一套省心太多。5.2 不适合硬套的场景:密集计算和长驻流式任务也有两类场景,我不建议硬塞进来。第一类是纯密集计算任务。比如对几百万行日志做聚合分析,或者跑批量推理评分。这些任务没有会话上下文,也不需要外部工具编排,用专用计算集群更高效。在 Agent Droplets 上跑纯计算,既浪费了状态总线的能力,也受单会话时长上限的制约,属于用错工具。第二类是长时间流式监听任务。比如一个智能体要持续监听某个消息队列,实时处理每一条流式记录并保持会话永不结束。这在产品形态上更像常驻消费者,更适合用常规的流处理框架,把智能体只作为其中的一个处理节点来调用,而不是让整个消费进程在 droplet 里长期挂机。第三类其实是“不适合直接裸跑”:高权限敏感操作型智能体。比如能直接改数据库、能执行资金操作的智能体。不是平台不支持,而是这类场景必须有严格的人机复确认机制,不能纯靠智能体自主决策。我们建议这类业务在工具层再加一道审批策略,否则一旦智能体误判,损失无法挽回。5.3 给准备自建平台的人一份实践清单最后分享一份针对“要不要自建”的实践清单。如果你只是做一个内部小工具,那没必要搭建完整平台,用脚本加队列就能跑。但如果你想把智能体产品化、规模化,至少要确认下面这几点没有漏:状态管理别贪图省事。会话状态请优先考虑事件流或至少是 append-only 设计,而不是覆盖式数据库,否则并发、审计、回退全都会成为问题。所有外部出口必须统一收口。智能体访问任何外部系统,都走统一网关,统一超时、统一鉴权、统一日志,不要放任智能体代码自己拼 HTTP 请求。默认配额必须保守。并发上限、速率限制、时间预算全部要有默认值,上线前先评估业务峰值再决定是否调宽,别把“改成高并发”当成标准动作。日志必须能按步骤还原。模型调用、工具调用、编排决策分轨记录,并且保证每一条都带会话 ID,否则出问题你既无法定位也无法复盘。可续跑是底线能力。无论你用什么架构,都要保证一个会话中断后能基于已保存状态恢复,而不是强制用户重来一遍。我个人在实际操作中的体会是:智能体本身就是个“不可完全预测的系统”,基础设施能做的不是让智能体永远不出错,而是让出错时损失可控、恢复要快、账算得清。Agent Droplets 服务器走到今天,核心原则没有变过——按会话给你独立的运行单元,按事件保存完整状态,按默认值兜住各种意外。这个思路我可以很确定地说,比单纯搞一堆虚拟机挂个调度器靠谱得多。如果你正好也在做类似的基础设施选型,欢迎聊聊你在智能体上线时碰到过哪些坑,尤其是那些“日志里根本看不出来”的诡异问题——我们交换一下案例,可能比读十份文档都值。
把 AI 智能体从 Demo 推到线上,最让我意外的事情不是模型能力,而是基础设施。过去一年多,我们团队陆续接了十几个智能体项目:有做客服自动应答的,有做数据分析的,有帮运营写周报的。Demo 阶段全都跑得挺顺,可真要一上线,问题就全冒出来了:并发上来之后实例怎么扩,会话记忆放哪儿,工具调用超时了怎么重试,一个死循环的智能体把账单价钱跑穿怎么办。折腾了几个月,我们干脆盘了盘需求,做了一个专门为 AI 智能体设计的按需运行平台,项目代号就叫 Agent Droplets 服务器。它不是一台物理服务器,而是一套“面向智能体会话的云基础设施”:按事件拉起独立运行实例、用完自动销毁、状态通过事件流保存,开发者只需要定义智能体行为和工具集,剩下执行、调度、容错、观测都交给平台。这篇文章不是官方文档复读,而是把设计和上线过程中那些真实的取舍、踩过的坑、以及“为什么这样设计”讲清楚。如果你正在考虑把智能体从脚本升级成长期运行的线上服务,或者正在纠结要不要自建一套智能体调度平台,那这篇应该能帮你省不少弯路。1. 为什么拿普通虚拟机跑智能体总是不得劲:Agent 工作负载的真实画像1.1 传统服务的假设,在智能体这里全部失效我先说结论:智能体本质上不是“网站”,不是“API 服务”,也不是“定时任务”,它是一个被事件驱动的、有上下文状态的、会主动调用外部工具的短时计算流程。最开始我们也偷懒,直接把智能体进程挂在一台常驻虚拟机上,24 小时跑个 Python 服务监听消息。第一版 demo 没什么问题,可一旦放真实流量就非常别扭。常驻虚拟机天然假设流量是相对平稳的:每个请求昂进来,处理完,返回响应,服务器一直活着等下一个。但智能体的流量是按会话、按事件触发的,波动极其剧烈。上午十点可能只有 3 个活跃会话,下午搞活动突然涌进 300 个,每个会话内部还要为了回答一个问题连续做十几次工具调用。这种负载跑在固定资源池上,要么闲时白掏钱,要么忙时疯狂排队。而且智能体的计算特点和普通请求很不一样。普通 web 请求通常一两秒就结束,CPU 和内存的占用相对规律。智能体不同:它在等大模型推理响应的时候基本不占 CPU,等结果一回来立刻进入工具执行阶段,可能又要调数据库、抓网页、算表格,一下子就飙起来。你很难用“QPS”去衡量它,唯一合理的衡量单位是“活跃会话数”,以及“一个会话内产生了多少次工具调用”。1.2 会话状态:最容易被低估的麻烦另一个让我非常头大的点是状态管理。普通服务是无状态的,数据库再存一份就行。智能体天然必须有状态:聊到一半,它得记得刚刚说过什么;执行到第三步,它得知道第一步查出来的订单 ID;用户中断了一次,下次回来还得能接着上一段继续。我们最早把状态直接存在进程内存里,结果服务一重启,所有会话全断了,用户骂声一片。后来换数据库,把整段会话历史当一个大 JSON 存进去,又出现并发写覆盖、拉取慢、历史长了大模型输入超限这些问题。状态不是一个“存下来”这么简单的事,状态是智能体的命根子,它的保存方式直接决定了系统能不能续跑、能不能调试、能不能回滚。我们当时的判断是:需要一种“按会话生命周期来设计的运行模型”。智能体会话一旦触发,平台给它起一个隔离的运行环境,环境里加载好工具、系统提示词、历史状态;执行完一步,立刻把这一步的事件追加到持久化存储;整个会话结束或者闲置超时,运行实例可以销毁,但状态留着,随时可以重新拉起继续跑。这就是 Agent Droplets 的原始出发点。一张表可以很直白地看出差别:维度传统长驻服务智能体会话负载运行周期常驻,以月计按事件启动,一般只有几十秒到几十分钟资源特征相对平稳的并发突发、间歇,等待和计算交替出现状态特性无状态或依赖数据库强上下文,必须支持中途续跑外部依赖数据库、缓存、外部 API大模型接口、各种工具 API、数据库,且工具调用频繁成本颗粒度按实例/按月按会话/按步骤最合理故障方式崩溃、超时、过载死循环、反复调用同一工具、状态错乱看这张表你就能明白,为什么我们最后没有选择“在虚拟机上堆智能体进程”,而是专门做了一个平台层。虚拟机能解决“算力从哪来”,但解决不了“会话怎么管理”“状态怎么续”“工具调用怎么隔离”这些问题。2. Agent Droplets 的形态:按需启动、自动销毁、状态可续的架构拆解2.1 不是云主机,不是 PaaS,是“智能体执行器”Agent Droplets 服务器这个名字,关键在 Droplets。我们内部约定,一个 droplet 就是一个“智能体运行实例的虚拟化单元”。当某个事件触发一个智能体会话,调度器就创建一个 droplet:分配内存、CPU、容器环境的隔离边界、配置好的模型调用凭证和工具权限。它在只够完成当前这一步或当前这一段会话的时间内存活,干完就销毁,绝不赖着不走。有人会问,这是不是就是 Serverless 容器?接近,但不完全一样。普通的 Serverless 函数是“无状态、单次执行”,智能体需要多步推理、记忆上下文、工具调用链路,这些都要在 droplet 内部被编排好。所以我们在 droplet 之上封装了三个核心组件:调度控制面、沙箱运行时、状态总线。三者配合,才让“按需启动、自动销毁、状态可续跑”真正成立。2.2 调度控制面:负责拉起、排队、回收调度控制面是平台的入口,它接收三类触发:HTTP 回调、消息队列事件、定时任务。每次触发都会携带会话 ID,控制面根据会话 ID 判断:这是新会话,还是已有状态需要继续执行的分支?如果是续跑,它会先把历史事件从状态总线拉出来,组装成上下文,再分配 droplet。控制面另一个关键职责是配额管理。我们不允许一个用户无限拉起 droplet。每个账号有并发上限,有事件速率限制,有全局超时。这些参数不是拍脑袋定的,而是来自我们对真实故障的复盘,后面我会专门讲那些故障。控制面还有一个容易被忽略的功能:回收。一个 droplet 到了闲置阈值必须回收,到了会话最大时长必须回收,外呼 API 连续失败达到次数也会触发熔断回收。回收不是粗暴杀进程,而是先通知 agent 保存检查点,再销毁实例,保证下一次还能从状态总线里续上。2.3 沙箱运行时:让工具调用不失控智能体的核心动作是工具调用。工具包括:查订单库的 SQL、调内部 HTTP API、外呼某个搜索结果页面、读写文件、甚至模拟浏览器操作。这些动作涉及权限、密钥、网络边界,绝不能让它直接在宿主环境里裸奔。我们的做法是:每个 droplet 运行在轻量级容器段中,给最小化系统权限;外部网络访问走代理网关,网关做域名白名单和协议白名单;敏感密钥不写进环境变量明文,而是通过密钥注入组件在运行时注入到进程内部。也就是说,智能体自己拿不到明文密钥,它只能通过平台封装的工具令牌去调外部服务。一个特别容易踩的坑是,智能体在调用工具之后的返回结果往往很长,数据量很大,如果直接把原始返回值塞回上下文,很快就把大模型的输入窗口塞爆了。我们在运行时里做了返回体压缩和截断策略:大结果先存对象存储,上下文里只放摘要和引用地址,等智能体真正需要全量数据时再按需拉取。这个设计一开始不觉得重要,后续在长会话场景里救了我们很多次。2.4 状态总线:事件流追加,而不是整表覆盖说到状态,这可能是 Agent Droplets 和普通容器平台最不一样的地方。我们没用常规的关系型数据库去存“当前会话状态”,而是把状态设计成一条持续追加的事件流。每个会话产生的事件包括:user_input:用户发来的原始消息。model_call:大模型推理的请求和响应摘要。tool_call:工具调用名称、参数摘要、返回结果摘要。checkpoint:平台定期打的状态快照。system_event:超时、重试、配额命中、熔断。事件流按会话 ID 分片存储,写入采用追加模式,不存在“修改某一行”的需求。要恢复一个会话时,从最近的 checkpoint 开始,往后重放事件,就能精确还原到任意一步。这种设计带来了三个好处:一是并发安全,不会出现两个人同时改一条会话记录的冲突;二是可调试,每步都留痕,出了错能精确知道是哪一步、哪个工具、哪次模型调用导致的;三是可回退,如果新版本智能体跑出了坏结果,可以直接在同一事件流上分叉,回退到上一个 checkpoint 再试。创建一个 AgentRuntime 的配置大概长这样:apiVersion: droplets.agent/v1 kind: AgentRuntime metadata: name: customer-service-agent namespace: production spec: runtime: image: runtime-agent-base memoryLimit: 512Mi cpuLimit: "1" lifecycle: trigger: message idleTimeoutSeconds: 60 maxSessionMinutes: 30 state: store: event-bus checkpointEverySteps: 5 ttl: 7d tools: - order.query - order.batch_query - customer.lookup policies: maxConcurrencyPerSession: 1 stepTimeoutSeconds: 15 maxToolCallsPerStep: 4 fatalErrorRetries: 2这个配置描述了一个客服智能体的运行定义:每条新消息触发一个 droplet,单会话内不并发,闲置 60 秒自动回收,每条消息处理时长最多 30 分钟,状态保留 7 天,每 5 步打一次快照,每一步超时 15 秒,每一步最多调用 4 次工具。这些默认值背后,是对“失控比稀疏更可怕”的深刻理解。3. 上线前补齐的三个关键细节:冷启动、配额限制和状态续跑3.1 冷启动:用户没有耐心等一个 8 秒的“联网思考”智能体平台的冷启动体验,直接影响产品口碑。用户在聊天框里发一条消息,如果三秒没反应,很多人就已经关页面了。而智能体的冷启动原本是重操作:要拉起容器,加载运行库,拼装系统提示词,恢复历史状态,建立大模型连接池,初始化各种工具客户端。这套流程如果每次实时做一遍,少说也要五六秒。我们的解法分两层:热池和快启。热池里常驻一批已经初始化好的基础运行时实例,镜像已经加载完毕,工具注册表已经填充,事件流连接已经建立。新的 droplet 不是从零创建,而是从热池里拿一个实例,把会话 ID 和状态检查点绑定上去,允许用户代码在进程内完成。快启层的优化更细:模型上下文拼接复用模板,历史事件重放做了并行预取,工具客户端延迟初始化,只在第一次真正调用时才创建连接。实测优化之后,绝大多数会话在 1 到 2 秒内可以开始处理第一条消息,如果状态较长,会额外慢一点,但核心链路不会因为等待基础环境而抖动。值得说的是,热池不是越大越好。热池里的空闲实例也在吃内存,太多会浪费成本。我们的策略是根据近 5 分钟活跃会话量的预测动态调整热池大小,高峰期提前扩容,低谷期自动收缩。这块逻辑目前还在持续调优,但方向明确:按活跃会话趋势来预测,而不是按固定数量配置。3.2 配额:给失控智能体准备好“保险丝”智能体失控这件事,我们上线第一周就撞上了。某开发者写了一个循环调用工具的逻辑,智能体在一个会话里反复查询订单接口,每分钟打几十次。要不是监控报警,系统差点把业务数据库拖垮。从那以后,配额和熔断成了最高优先级的设计。现在的配额模型分三层:第一层是账号级并发数。比如每个正常账号最多同时运行 20 个活跃 droplet,超出的排队等待。这一层是控制整体资源池不被单一账号打爆。第二层是会话内速率。每个会话内部,工具调用频率、模型调用频率分别做令牌桶限流。如果某个行为超过了每分钟 30 次工具调用的阈值,平台直接中断该步骤,返回一个 quota_hit 事件,而不是让循环继续烧钱。第三层是全局时长预算。每个会话有累计处理时长上限,每条消息有步骤超时上限。国债时长用完,会话自动终止并要求开发者介入。这一层特别重要——智能体不像普通程序有明确的“结束”概念,它天然倾向于继续对话、继续尝试,没有预算,它就能永远跑下去。配套的还有循环检测启发式:当同一个工具、相同参数前缀在一个会话中连续出现多次时,平台会标记并暂停该 session,提示开发者确认是否为死循环。这个启发式不完美,会有误伤,但在真正出 bug 时,它能大幅降低损失。3.3 状态续跑:从“存会话”到“重放会话”的思路转换上线前我们犯过一个比较大的设计错误:我们最初想用云数据库存“会话快照”,每次对话结束后覆盖写一条最新状态。看起来很简单,但立刻遇到问题:并发写覆盖、半写状态、长上下文恢复慢,以及无法回答“为什么智能体这一步做出了这个决定”。后来切换成事件流模型,一切顺了很多。每个事件只做追加,不做修改,天然有审计能力。不同的会话分支也能表达——假如同一个会话有两个候选分支,每个分支都是基于同一段父事件流的延伸,最终可以选一条作为最终结果提交。事件流存得久了,还会有存储成本问题,所以我们又加入了分层保留策略:热事件保留 24 小时,用于实时调试;快照保留 7 天,用于一般续跑;线上需要长期归档的会话再转到对象存储做冷存。目前看,这种“事件流 + 快照 + 冷存”的组合,在成本、延展性、可恢复性之间是比较均衡的取舍。状态续跑的代码侧用法也很直接,调用方只需指定会话标识即可:droplets-cli invoke customer-service-agent \ --session 0d6a04b2-1c3e-4f89-9c2a \ --input "继续之前的订单查询"平台自动判断该会话是全新触发还是续跑,续跑时不需要调用方自己去组装历史上下文,这对前端同学非常友好。4. 跑起来之后的账单、超时和循环风暴:运维侧的真实情况与治理对策4.1 一次被 200 个容器冲垮的账单教训Agent Droplets 上线后第二周,我们的开发环境突然出现了几百个并发 droplet 同时被拉起的情况。查了半天,发现是某个开发者在调试时为每条消息都创建了全新会话,而且业务侧代码在异常时反复重试,每个重试都会触发一个新的智能体会话。结果就是:一分钟内,200 个 droplet 同时运行,账单快速上升,风控部门都被惊动了。这件事让我深刻明白一件事:智能体基础设施给的自由度越大,用户滥用造成的破坏就越大,必须提供“强制安全默认值”。现在新创建的 AgentRuntime 配置文件,如果开发者什么都没填,平台会自动套上一组安全默认值:配置项默认值为什么这么设单会话最大并发1防止同一会话并行导致状态错乱账号并发上限20防止单个账号打爆整个池单步骤超时15 秒模型或工具卡住能快速暴露单会话总时长30 分钟防止长尾会话无限占用资源工具调用速率30 次/分钟防止循环刷工具接口失败重试次数2防止无限重试放大人为故障这些默认值上线后被骂了一阵“太严格”,但跑了一个月,再也没有出现过账单失控或会话泛滥的事故。我始终认为:智能体平台的默认值应该宁可严格、不能宽松,开发者有特殊需要可以显式调高,但决不能默认放开。4.2 工具调用超时和重试:表面是网络问题,深层是设计问题运维过程中我们反复和“工具调用超时”打交道。智能体调用一个内部 API,本来 100 毫秒就好,结果对方服务偶发 5 秒才返回,智能体就会陷入等待;等待太久触发步骤超时,重试之后又是同样结果,整个会话看起来像卡死了一样。后来我们做了两件事。第一件,所有工具调用都走统一网关,网关负责设置合理的上游超时(默认 8 秒),并把重试策略统一收口:只有幂等工具才允许自动重试,非幂等工具失败后必须返回错误事件、由智能体自行决策。第二件,在状态事件流里拆分明细计时,把模型等待时间、工具调用时间、内部编排时间分开统计,这样定位问题能一眼看出瓶颈在哪,而不是每次都要盲猜。比如一个典型的事件记录:{ "session_id": "0d6a04b2-1c3e-4f89-9c2a", "event_type": "tool_call", "step_index": 7, "tool_name": "order.query", "status": "timeout", "latency_ms": 8520, "retry_count": 0, "quota_remaining": 12, "memory_peak_mb": 168, "ts": 1730503200 }把这样的结构打成结构化日志之后,再配合查询面板,我们可以按会话追出每一个工具调用的耗时分布,也可以在巡检时直接发现“某个上游接口的调用失败率突然攀升”,不用等用户投诉才知道系统出了故障。4.3 日志切分:一个步骤里发生了什么,必须拆开看智能体日志最让人头疼的地方是:模型输出、工具返回、代码内部逻辑全都混在一次执行里。如果按普通应用那样统一打到一个日志流,排查问题基本等于大海捞针。我们把每个步骤的埋点拆成了三类独立通道:模型轨迹:记录发送给模型的上下文长度、模型返回内容摘要、推理耗时。工具轨迹:记录工具名、入参摘要、出参摘要、耗时、状态码。编排轨迹:记录智能体代码内部的决策路径,包括条件分支、错误捕获、重试动作。三类通道分别用不同的标签做索引,但共享同一个会话 ID 和步序号。当问题发生时,先看编排轨迹确认代码走了哪条路;再看工具轨迹确认外部调用是否正常;最后才需要看模型轨迹确认是不是大模型理解偏了。这套设计不需要什么高深技术,但非常管用,它是我们调试智能体问题时最重要的利器。5. 什么场景适合放在 Agent Droplets 上,以及什么时候我建议你再想想5.1 适合这里的人:事件驱动、会话型、需要工具的智能体上线踩了这么多坑,同时服务了内部多个智能体项目之后,我们对“什么场景适合用这套基础设施”有了比较清晰的判断。最适合的场景首先是对话型助手。客服、售前、售后、内网知识问答,这些智能体天然是事件驱动的:用户来了消息才需要启动会话,会话有上下文,需要调内部系统查数据,完成后可闲置可销毁。放在 Agent Droplets 上,成本是弹性的,用户不聊就不产生成本,聊起来也能扛住并发。其次是自动化的任务分解型智能体。比如给运营写周报,它会先拉数、再总结、再排版;比如做竞品分析,它会先列关键词、再检索网页、再汇总结论。这类任务的特点是步骤多、耗时长,中间会有大量等待,状态续跑的价值非常明显。写一半断了也不怕,回去能从检查点继续执行。我们还有一拨用户在平台上面跑多租户的智能体服务,也就是开发者把自己的智能体包成 API 卖给下游客户。对他们来说,按会话计费、资源隔离、配额治理是一站式的,这比自己在云上搭一套省心太多。5.2 不适合硬套的场景:密集计算和长驻流式任务也有两类场景,我不建议硬塞进来。第一类是纯密集计算任务。比如对几百万行日志做聚合分析,或者跑批量推理评分。这些任务没有会话上下文,也不需要外部工具编排,用专用计算集群更高效。在 Agent Droplets 上跑纯计算,既浪费了状态总线的能力,也受单会话时长上限的制约,属于用错工具。第二类是长时间流式监听任务。比如一个智能体要持续监听某个消息队列,实时处理每一条流式记录并保持会话永不结束。这在产品形态上更像常驻消费者,更适合用常规的流处理框架,把智能体只作为其中的一个处理节点来调用,而不是让整个消费进程在 droplet 里长期挂机。第三类其实是“不适合直接裸跑”:高权限敏感操作型智能体。比如能直接改数据库、能执行资金操作的智能体。不是平台不支持,而是这类场景必须有严格的人机复确认机制,不能纯靠智能体自主决策。我们建议这类业务在工具层再加一道审批策略,否则一旦智能体误判,损失无法挽回。5.3 给准备自建平台的人一份实践清单最后分享一份针对“要不要自建”的实践清单。如果你只是做一个内部小工具,那没必要搭建完整平台,用脚本加队列就能跑。但如果你想把智能体产品化、规模化,至少要确认下面这几点没有漏:状态管理别贪图省事。会话状态请优先考虑事件流或至少是 append-only 设计,而不是覆盖式数据库,否则并发、审计、回退全都会成为问题。所有外部出口必须统一收口。智能体访问任何外部系统,都走统一网关,统一超时、统一鉴权、统一日志,不要放任智能体代码自己拼 HTTP 请求。默认配额必须保守。并发上限、速率限制、时间预算全部要有默认值,上线前先评估业务峰值再决定是否调宽,别把“改成高并发”当成标准动作。日志必须能按步骤还原。模型调用、工具调用、编排决策分轨记录,并且保证每一条都带会话 ID,否则出问题你既无法定位也无法复盘。可续跑是底线能力。无论你用什么架构,都要保证一个会话中断后能基于已保存状态恢复,而不是强制用户重来一遍。我个人在实际操作中的体会是:智能体本身就是个“不可完全预测的系统”,基础设施能做的不是让智能体永远不出错,而是让出错时损失可控、恢复要快、账算得清。Agent Droplets 服务器走到今天,核心原则没有变过——按会话给你独立的运行单元,按事件保存完整状态,按默认值兜住各种意外。这个思路我可以很确定地说,比单纯搞一堆虚拟机挂个调度器靠谱得多。如果你正好也在做类似的基础设施选型,欢迎聊聊你在智能体上线时碰到过哪些坑,尤其是那些“日志里根本看不出来”的诡异问题——我们交换一下案例,可能比读十份文档都值。