Agent Droplets 服务器正式上线到现在已经稳定跑了两个多月。这个项目名字听起来有点陌生但简单说它是一套专门为 AI Agent 打造的云基础设施你不用再自己拼装容器、消息队列、工具网关和记忆存储创建好的 Droplet 会被直接注入一套开箱即用的 Agent 运行时环境。这篇文章会把我们团队从立项、架构设计、上线到踩坑的全过程整理出来适合正在做 Agent 应用落地、或者想把现有服务迁移到更省心平台上的开发者参考也适合那些刚接触 Agent 工程化、想弄清楚“云端到底该怎么部署智能体”的朋友。1. 项目缘起Agent 能跑起来和能跑得稳是两码事1.1 AI Agent 落地时那些头疼事过去半年我们接了不下十个智能体项目有做客服工单自动分发的有做私域运营内容生成的还有做内部数据问答的。写业务逻辑本身不难真正难的是让 Agent 在真实业务环境里稳定跑起来。第一类是环境问题。一个 Agent 服务依赖的东西太多了模型 SDK、向量库客户端、工具调用 HTTP 客户端、缓存中间件、任务队列。本地开发环境里跑得欢一上服务器就各种缺依赖、版本冲突。有一次某个项目因为依赖里的一个底层库在服务器上默认装了不同版本导致工具调用结果序列化反复失败排查了整整一个下午。第二类是资源波动问题。Agent 不像传统 Web 服务那样流量相对平稳。它在“思考”阶段 CPU 占用很低一旦进入工具调用阶段会瞬间发起大量并发请求内存和网络带宽突然拉满然后又迅速回落。用固定规格的虚拟机跑要么经常被打满导致任务失败要么为了峰值时刻长期付着高昂的机器费用。我们做过统计大部分 Agent 任务里的有效计算时间占比不到三成剩下的时间都在等待模型响应或者外部接口返回。第三类是状态与可观测问题。很多人以为 Agent 就是“请求进来结果出去”但真实场景下Agent 任务往往要跑几十秒甚至几分钟中间涉及多轮工具调用、状态累积、上下文管理。一旦中间某一步出错整个任务的状态就丢了想追踪问题都无从下手。用户只会看到“请求失败”你却分不清是模型超时、工具接口报错还是代码本身出了 bug。这三类问题的核心矛盾是Agent 需要的不是一台普通的“能跑代码的机器”而是一套围绕智能体生命周期做设计的运行环境。这也是 Agent Droplets 立项的起点。1.2 为什么叫 Droplets我们把 Agent 当成“有水状态的生命体”水滴这个名字不是拍脑袋想的。Agent 的一次完整运行其实很像一滴水从形成到落地的过程模型收到任务指令后开始“凝结”思路然后经过多轮“流动”式的工具调用最终“落地”为可交付的结果。在整个过程中状态是连续的、有生命周期的不能简单用传统无状态服务的思路去管理。所以我们顺手拆出了 Agent 运行的五个核心阶段任务接收、上下文构建、推理循环、工具执行、结果输出。每个阶段对基础设施的要求完全不一样。传统 PaaS 平台用“容器 健康检查 水平扩容”这套逻辑来服务普通后端服务这套逻辑在无状态 Web 服务上没问题但套到 Agent 上就很别扭。比如说健康检查普通服务的健康检查只需要探活端口而 Agent 需要检查的是“推理循环是否陷入死循环”“工具调用是否在合理时间内返回”“上下文窗口是否接近上限”这些都不是简单的 TCP 探测能回答的问题。再比如扩容逻辑普通服务是流量高了多开几个实例但 Agent 的并发单位是“任务”扩容单位是“可同时承载的推理会话数”两者完全不是一个维度。Agent Droplets 的定位就是把这五个阶段的东西全部封装成平台能力任务进来平台自动分配一个干净的运行环境注入密钥和上下文存储执行完自动回收资源并按实际用量计费。用户只需要关心 Agent 的业务逻辑本身。2. 整体架构设计与核心拆解2.1 控制平面与数据平面分离Agent Droplets 的架构一开始就定了一个基调控制平面和数据平面完全分离。控制平面负责的是“大脑”部分管理 API 接入、用户鉴权、Droplet 调度、资源配额、计费数据还有所有 Agent 任务的路由分发。这个平面的特点是请求量相对小但逻辑复杂需要频繁变更。数据平面则是真正跑 Agent 代码的部分它最爱干净、最怕被打扰。一旦一个 Droplet 被创建它会尽量保持稳定不频繁重建所有临时状态都落在本地缓存里保证推理过程的低延迟和高吞吐。这种分离带来一个明显好处升级控制平面的功能比如调整计费策略、优化调度算法完全不影响正在运行的 Agent 任务反过来数据平面里的运行实例出了故障也可以快速摘除而不影响全局调度。我们早期曾经考虑过把所有逻辑塞进一个单体服务里被有经验的前辈直接否了理由很简单Agent 场景下控制逻辑和运行逻辑的变更频率和故障域都不一样硬揉在一起最后一定是谁都改不动。控制平面内部还拆了四个子模块调度器负责给新任务匹配最合适的 Droplet配额中心负责预算控制和资源限制审计服务记录每一次任务的关键操作计费模块把资源消耗折算成具体费用。这些模块各司其职彼此通过内部消息队列异步通信调度器派发任务之后配额中心会立刻冻结对应的预算额度避免出现任务跑到一半发现余额不足的尴尬局面。2.2 Droplet 运行时沙箱与资源模型数据平面里最核心的概念就是 Droplet 实例。每个 Droplet 本质上是一个基于轻量虚拟化技术实现的沙箱环境具备独立的文件系统、进程空间和网络栈但启动速度比传统虚拟机快得多通常在几百毫秒到一两秒内就能完成初始化。为什么不用普通容器因为 Agent 要执行大量不可信的工具调用。比如一个 Agent 需要调用某个外部服务返回的 HTML 内容然后用代码解析提取数据这段代码如果跑在普通容器里一旦内部实现有安全漏洞容器之间隔离不当就会产生横向移动的风险。轻量虚拟化沙箱提供了更严格的内核隔离边界虽然性能上有一点损耗但对 Agent 这类 I/O 密集型任务来说这点损耗可以忽略不计。资源模型我们设计成“CPU 内存 临时存储”三件套规格档位从 1 vCPU / 2 GiB 到 8 vCPU / 32 GiB 不等。很多人问怎么选规格我的建议是从任务类型反推。纯文本分析类任务1 vCPU / 2 GiB 就够涉及本地向量检索的任务先把向量数据量算明白1 万条 384 维的嵌入向量大约是 15 MB但加上索引结构和检索时的临时缓冲区实际占用通常是裸数据的五到十倍所以 10 万条向量至少预留 2 GiB 内存如果 Agent 还会并行调用多个外部工具每个并发请求都需要独立的连接池和缓冲区那么 4 GiB 内存基本是底线。2.3 工具调用网关Agent 基础设施的灵魂如果说 Droplet 沙箱是“厂房”那工具调用网关就是“物流系统”。Agent 每执行一步业务逻辑几乎都要和外部世界打交道查数据库、调内部 API、发 HTTP 回调、读文件、甚至触发人工审批流程。这些操作五花八门不可能让用户一个个自己集成。我们的工具网关统一封装了这些交互。思路很简单Agent 代码不直接发 HTTP 请求而是通过运行时 SDK 发出一个标准化的工具调用请求网关负责鉴权、限流、重试、超时控制然后把结果返回给 Agent。这样做的好处是不言而喻的工具调用具备了统一的可观测性每一次调用是成功还是失败、耗时多久、返回了多少数据全部有记录同时安全策略可以在网关这一层集中管控而不是散落在每一段 Agent 代码里。网关的技术核心是幂等机制。Agent 因为外部接口超时往往会重试如果不做处理同一笔转账请求可能被执行两次。我们给每个工具调用分配一个全局唯一的 request_id网关侧记录每个 id 的执行结果遇到重复请求直接返回上次的结果。这套机制上线后工具调用的重复执行率从百分之五降到了接近零。3. 从 0 到 1 上线实操过程与关键配置3.1 创建一个 Droplet镜像选型与资源参数以我们最常用的“文档问答 Agent”举例。创建 Droplet 的过程很简单控制台填表单或者直接调 API 都行。我们团队习惯用 API方便自动化批量创建。一个典型的创建请求长这样curl -X POST https://api.agentdroplets.example/v1/droplets \ -H Authorization: Bearer $TOKEN \ -d { name: doc-qna-agent, region: ap-se-1, runtime: python3.11, resources: { cpu: 2, memory: 4GiB, ephemeral_storage: 10GiB }, features: [tools_gateway, memory_store, task_queue], idle_timeout: 300s }有几个参数值得展开说。runtime 字段指定的是运行时模板平台会预装好 Python/Node.js 环境、常用模型 SDK、向量客户端和工具网关 SDK。为什么不用用户自己上传任意 Docker 镜像因为完全自由的镜像等于把环境问题又踢回给用户我们只提供经过测试的固定运行时列表用户在此基础上加自己的代码。这样做的代价是灵活性略降但换来的是“跑不起来”的概率大幅下降。idle_timeout 参数表示 Droplet 在空闲多少秒之后自动休眠。这个参数直接关系到成本。我们测试过一个 2 vCPU / 4 GiB 的 Droplet满载运行一天的费用大约是常驻虚拟机的一半不到因为大部分时间它都在休眠状态。休眠之后再次唤醒只需要重新加载上下文耗时在 1 到 3 秒对绝大多数任务来说是可接受的。创建完成之后平台会返回一个 runtime endpoint 和一组临时凭证。Agent 代码只需要通过环境变量读取这些信息不需要硬编码任何地址。3.2 部署 Agent 服务运行时接入Droplet 创建好之后下一步就是部署 Agent 代码。我们在运行时模板里内置了一个轻量级的 Agent SDK用户只需要实现两个核心入口一个是任务处理函数接收任务描述和初始上下文另一个是工具注册函数声明这个 Agent 会用到哪些外部工具。下面是一个简化版的服务端代码结构实际生产会比这个厚实很多但骨架就是这样from agent_droplets_sdk import AgentRuntime, Tool def handle_task(task_input: dict, context: dict): # context 里已经自动加载了历史记忆和用户上下文 user_question task_input[question] # 调用注册过的工具 result runtime.call_tool(search_docs, queryuser_question) answer generate_answer(user_question, result) return {answer: answer} def register_tools(): return [ Tool(namesearch_docs, endpointinternal://vector-store/search), Tool(nameget_user_profile, endpointinternal://user-service/profile), ] runtime AgentRuntime( handlers{default: handle_task}, toolsregister_tools(), ) runtime.start()这里“internal://”前缀的地址是平台虚拟网络内部的服务发现名称Agent 代码不需要关心具体物理地址怎么解析网关会自动路由过去。这意味着即使用户后续迁移了后端服务的位置Agent 代码一行都不用改。部署过程同样走 API 或者控制台上传代码包。平台会把代码包挂载到 Droplet 的指定目录然后重启运行时进程。我们内部测试过一个 200 MB 左右的代码包从上传到服务恢复可用的时间在三秒以内。3.3 配置工具网关、权限策略与安全边界工具网关的配置是 Agent 安全性的命门也是我认为整个文档里最应该花时间读的部分。网关支持三种工具类型平台内置工具向量检索、对象存储、任务队列、用户自定义 HTTP 工具、外部 Webhook 回调。每种工具都需要显式配置访问策略。平台内置一个最小权限原则默认情况下Agent 没有访问任何外部网络的权限用户必须在配置里逐条声明允许访问的域名和路径。# agent-tools.yaml tool_policies: - name: search_docs type: builtin action: [read] rate_limit: 10 timeout: 5s - name: create_ticket type: http method: POST allowed_domains: [ticketing.internal.example] allowed_paths: [/api/v1/tickets] auth: inherit - name: send_email_webhook type: webhook url: https://hooks.internal.example/email/send retry: 3 idempotency: true每个策略都包含明确的超时和重试参数。我建议超时时间不要设得太长尤其是外部工具5 秒已经是比较宽松的阈值。重试次数 2 到 3 次就够再多反而会因为外部服务过载导致雪崩。权限配置还有一个容易忽略的细节工具返回的数据可能包含敏感信息。网关默认会对所有工具响应做脱敏处理比如识别身份证号、银行卡号等模式并自动打码。这功能刚开始同事觉得多余直到有一次向量检索结果里真的带出了用户手机号大家才意识到它的价值。3.4 监控告警与成本控制上线阶段最容易被低估的是监控。Agent 服务不像普通 API不能只看 QPS 和延迟更关键的是“任务完成率”和“工具调用成功率”。我们在每个 Droplet 里都预置了指标采集探针输出标准的 Prometheus 格式指标。我最常盯的四个指标分别是agent_task_state当前处于哪个生命周期阶段、tool_call_latency工具调用的耗时直方图、context_window_usage上下文窗口占用百分比、idle_ratio空闲时间占比。告警规则里最实用的一条是“上下文窗口占用超过 80%”。这个指标一旦冲高意味着 Agent 随时可能因为上下文溢出导致任务失败。处理办法通常是优化提示词、压缩历史记录或者提升当前 Droplet 的内存规格。成本控制方面除了前面提到的自动休眠我们还加了三层保险任务级预算单个任务最多允许消耗多少资源、Droplet 级月度配额、账号级总预算。任意一层被打穿平台都会先发出告警而不是直接中断任务给用户留出人工处理的窗口。这个设计是吸取了初期版本的教训一开始是配额耗尽立刻杀任务结果用户半夜收到一堆告警邮件体验非常差。4. 常见问题排查与避坑实录4.1 Droplet 启动缓慢依赖安装是罪魁祸首上线初期收到最多的问题报告就是“Droplet 启动要十几秒比传统容器慢多了”。排查下来根因几乎都是用户代码里用了 pip install 或 npm install 来装依赖每次启动都要现去拉包网络一波动就卡住。破解办法是依赖缓存预热。平台会记录每个 Droplet 历史使用过的依赖组合在下次创建时提前把对应层缓存到本地镜像仓库。同时要求用户尽量在部署包里直接打好依赖锁文件。这个改动上线后平均启动时间从 9.8 秒降到了 2.1 秒。4.2 内存上限导致 Agent 进程被“杀死”另一个高频问题是 Agent 任务跑到一半进程莫名其妙消失查看事件记录发现是 OOM内存溢出。最常见的原因有两个一是上下文管理不当长对话场景下历史记录无限累积吃光内存二是向量检索结果一次性全量加载到内存。解决方案是双层优化。代码层面建议对历史消息做滑动窗口截断只保留最近 N 轮对话和关键摘要平台层面我们提供了内存达到阈值时的自动 dump 功能会把 Agent 当前状态和调用栈写入持久化存储方便排查。曾经有个用户反馈任务总在 37 分钟的时候崩溃通过 dump 文件发现是他的 Agent 在某个循环里无限制拼接字符串定位过程快得惊人。4.3 工具调用回调失败与超时Agent 调用复杂工具时有些工具是异步的接口先返回“已接收”随后通过回调地址通知结果。这个模式下最经典的问题是回调地址配错、或者回调请求被安全策略拦截。还有回调地址指向公网域名DNS 解析慢导致超时。我们的排查清单基本上是这个顺序先看回调请求是否到达平台入口再看安全策略有没有放行对应来源 IP最后检查回调请求的 payload 格式是否匹配。如果前三步都没问题就看签名校验所有回调请求都必须携带平台签发的签名头用户本地复现时经常漏掉签名。建议在开发阶段直接使用平台的调试模式它会把所有回调请求的详情实时打印出来省去来回抓包的痛苦。4.4 长时任务的优雅退出与状态恢复Agent 任务经常要跑好几分钟这中间平台偶发维护或者用户手动重启 Droplet就会导致任务断掉。最初版本直接丢弃未完成任务的状态用户怨声载道。后来我们实现了检查点机制每完成一个推理循环就把 Agent 的当前状态、已收集的中间结果、上下文摘要写入持久化存储。重新调度时新 Droplet 会自动加载最近一个检查点继续执行而不是把所有流程重头跑一遍。这套机制尤其在离线批量任务里效果明显任务中断恢复的成功率从 43% 提升到了 96%。问题症状排查方向解决方式Droplet 启动慢创建到可用超过 10 秒检查依赖是否触发热加载、镜像源是否拥堵开启依赖缓存预热、固化依赖锁文件进程被 OOM 杀死任务中断日志显示 killed查看内存 dump、检查历史上下文大小滑动窗口压缩历史、升级 Droplet 内存回调超时工具状态永远是 pending检查回调地址可达性、安全策略、签名使用调试模式观察回调详情长任务中断恢复后从头开始跑检查检查点是否生成、恢复逻辑是否触发开启检查点机制、验证恢复链路工具重复执行同一操作被执行多次检查请求是否携带幂等键使用网关幂等机制设置唯一 request_id4.5 一份避坑速查清单最后整理一份实战避坑清单都是我们和市场早期用户一起踩出来的经验所有外部工具调用必须声明超时时间不声明的默认策略是 2 秒超时不少用户刚接入时会觉得“一切正常”等流量一大就开始成片报错这时候才会意识到是超时策略起的作用。上下文记忆要主动管理不要依赖模型自己截断模型截断的结果往往丢掉关键信息而且浪费算力。对于有敏感数据的工具响应脱敏要提前配置不要等事故发生后补救。定期观察 idle_ratio如果长期超过 70%说明规格选大了把 Droplet 降配能省不少钱。回调类型工具的幂等设计从一开始就要做半路补幂等往往涉及数据迁移代价高好几倍。5. 上线后的真实观察与心得体会Agent Droplets 上线以来我们一直在持续观察平台数据。两个月的生产环境运行下来有几个数字让我印象很深。任务整体成功率稳定在 99.2% 以上。这不是说代码没有 bug而是说平台层的调度、重启、检查点机制确实把基础设施故障对业务的影响降到了最低。工具调用的 p99 延迟比我们预期的还要好主要得益于虚拟网络内部服务发现比走公网快了一个数量级。成本方面的变化也很有说服力。之前我们用固定虚拟机跑 Agent 任务资源利用率长期在 25% 左右切换到 Droplets 之后因为自动休眠和按量计费整体成本下降了大约 60%。最夸张的一个测试项目一天只跑了不到十次任务当月成本折算下来几乎可以忽略不计。有一个体会是架构上最值回票价的决策确实是控制平面与数据平面的彻底分离。中间我们大改了两次计费和调度逻辑所有正在运行的 Agent 全程无感这在单体架构下是不可想象的。另一个体会是关于收益分布的。很多人以为“一站式云基础设施”是个名词包装实际跑下来才知道真正让用户留下来的是那些细到尘埃里的功能调试模式里的实时回放、失败之后的断点续跑、权限策略的可视化校验。这些功能单个拿出来都不算耀眼但合在一起就是把“能跑”变成了“好用”。最后分享一个我们内部特别喜欢的小技巧新用户接入时建议先用最小的 Droplet 规格跑一遍完整流程重点关注 idle_ratio 和 context_window_usage 这两个指标再决定要不要升配。大多数情况下问题不是资源不够而是代码对资源的使用方式不对。让 Agent 基础设施替你把环境、状态、链路这些脏活累活都扛了你专注于业务逻辑本身这个组合打出来的效果远比你想象得好。