跳到主要内容

你的智能体是一个“话唠”客户端:数据引力开始影响工具循环

· 阅读需 11 分钟
Tian Pan
Software Engineer

15 年前,我们学会了畏惧 N+1 查询:一个在代码审查中看起来人畜无害的 ORM,会针对列表发起一次查询,然后为每一行数据再发起一次查询。一个本该只需要两次数据库调用的页面,最终却发起了两百次。我们通过预加载 (eager loading)、批处理 (batching) 和一代又一代的 Linter 解决了这个问题。然而,现在我们构建了 AI Agent,却在昂贵得多的层级上重犯了同样的错误。

一个单一的 Agent 任务——比如“核对这些发票”或“处理此故障”——通常会进行几十次串行的工具调用。每一次调用都是一次完整的网络往返:从 Agent 到工具,从工具到数据存储,数据返回工具,结果序列化到模型的上下文中,再进行一次推理以决定下一步操作。如果你的推理运行在一个云端,而数据存在于另一个云端,那么每一次跳转都会跨越一个计费且高延迟的边界。此时,Agent 系统成本的主要项不再是模型,而是地理位置。

没有人把这笔账算清楚。延迟预算是按次调用的,出网流量 (Egress) 只是存储账单中的舍入误差,而模型发票则受到了所有的关注。与此同时,工具循环悄然成为了你的基础设施所服务的通信最频繁 (chattiest) 的客户端。

N+1 问题在工具层重生

这种失败的结构与 ORM 版本完全一致,只是换了个位置。Agent 不了解你的数据模型,它只知道工具。因此,它不会提出一个精心设计的问题,而是提出一系列小问题:获取工单,然后获取客户,接着获取客户的套餐,再获取套餐的额度,最后检查使用情况表。为了回答一个 SQL Join 就能解决的问题,它进行了五次往返。

ORM 版本的 Bug 在数据中心内部消耗你几毫秒的时间。而 Agent 版本的 Bug 在每一次跳转中都会让你付出三项代价:

  • 网络时间:现在是跨云而非跨机架。一个普通的 Agent 循环每个任务会进行 5 到 10 次往返;按每次跨区域延迟 50 毫秒计算,在进行任何推理或工具执行之前,纯网络开销就达到了 250 到 500 毫秒。
  • 推理过程:因为在每次工具返回结果后,模型必须读取完整的累积上下文并决定下一步。三次往返意味着处理的输入 Token 数量大约增加了三倍——据测算,重复发送的上下文约占 Agent 推理总费用的 62%。
  • 出网流量 (Egress):因为工具跨云边界返回的每一个字节,在主要供应商那里的计费标准是每 GB 0.09 到 0.12 美元——通常比存储本身的成本还要高。

每一项单独看起来都在可接受范围内。问题在于它们会随调用次数而倍增,而 Agent 的调用次数非常多。

为什么单次调用的延迟预算具有误导性

工具服务器的标准运行指南表面上看起来很合理:保持 p50 在 50 毫秒以下,p95 在 200 毫秒以下。团队达到了这些目标,仪表盘显示绿色,但 Agent 完成一个任务仍需 90 秒。这是因为预算是在错误的高度上衡量的。

单次调用的百分位数描述的是单次跳转。而一个 Agent 任务是一棵跳转的“树”——算上检索、子 Agent 委派和验证步骤,深度通常达 40 层——且这些跳转大多是串行的,因为每个工具的结果都会影响模型对下一次调用的决策。实际执行时间 (Wall-clock time) 是最长路径上的总和,而不是其中任何节点的 p95。即便工具集群中每台服务器都符合 200 毫秒的 p95 标准,仍然可能产生一个在传输中就耗时 8 秒的任务。因为 40 次串行跳转,即使每次只有 200 毫秒,在生成第一个 Token 之前,网络延迟就已经消耗了 8 秒。

尾部行为使得情况比算术计算出的还要糟糕。在 40 次串行调用中,至少有一次 落在 p95 尾部的概率接近 100%——任务级的延迟分布被那些你认为可以接受的单次调用离群值所主导。当一次缓慢的调用变成超时,Agent 会重试,这又会重新发送完整的对话上下文:对一次数据库读取采用“三次重试”模式,会使该步骤的 Token 成本翻三倍。重试循环将延迟问题转化为了计费问题。

真正能预测用户体验和成本的指标是任务级的:每个任务的往返次数、每个任务的网络延迟、每个任务重复处理的 Token。如果你只关注单次调用的百分位数,你的 Agent 在每次迭代中可能会变得越来越慢、越来越贵,而所有的仪表盘却依然显示绿色。

让同城协作计算显式化的 Egress 账单项

数据重力过去是关于分析的论据:你的 PB 级数据在一个云里,所以你的数据仓库也会落户在那里。Agent 强化了这一论据,因为它们不只是读取一次数据,而是生活在数据中。在每一个推理周期中,上下文都会被重新获取:对话历史、政策文档、检索结果、工具 Schema。数据不是工作负载的输入,它在很大程度上就是工作负载本身。

这改变了许多团队误打误撞采用的“拆分云架构”的经济学模型。这种模式很常见,因为在每一步中它在局部都是合理的:GPU(或模型 API)在 A 云,因为那里容量最充足或价格最优;运营数据在 B 云,因为它已经在那儿待了十年了。现在,每个 Agent 任务都会在那个边界上来回传送几十次工具结果,而计费器在你关注的两个维度上都在跳动——每一次跳转的延迟,以及每一个字节的出网费用。

从某种微妙的角度来看,Egress 费用是系统中唯一“诚实”的部分。延迟税在你进行测量之前是隐形的;Token 的重复处理隐藏在你本就预期会很庞大的账单中。但 Egress 作为一个独立的账单项出现,按 GB 计费,可归因于特定的边界跨越。它是强制将同城协作 (Co-location) 问题摆到桌面上的关键数字:55% 的 IT 负责人已经将 Egress 成本列为切换供应商的最大障碍,而专门的 GPU 云服务商已经开始推广“零 Egress”层级,正是因为这个账单项已经成为了交易的破坏者。当 2026 年初推理费用占到 AI 云基础设施总支出的半数以上时,部署位置不再是一个采购细节,而是成为了架构本身。

部署位置是一个设计决策,且只有三个坦诚的选择

一旦你接受了工具循环(tool loop)本质上是一个高频交互的客户端,响应空间就会变得很小。你可以将工具移近模型,将模型移近数据,或者重构循环以减少部署中的往返次数。大多数实际系统需要混合使用这些方案。

将工具移近模型。 在推理节点旁边复制或缓存热数据切片:在模型所在区域建立只读副本、与 GPU 集群同处一地的向量索引、每小时刷新一次的策略文档缓存。当 Agent 的工作集较小且读密集时,这种方法非常有效,而这种情况比团队预想的要普遍得多 —— 大多数 Agent 任务只是反复触达一小部分参考数据。代价是你现在必须自己处理一致性问题。

将模型移近数据。 在数据已经存在的云端和区域运行推理,即使 GPU 价格更高或模型选择更少。这是“数据引力”的答案,对于受监管的数据,这通常是唯一的答案 —— 主权和合规约束在任何架构讨论开始之前就固定了数据的位置。当你诚实地计算跳跃成本时,为了在每个任务中消除 40 次跨云跳跃而为每个 GPU 小时多支付 20% 的费用,通常是更划算的交易。

通过批处理消除往返。 这是最被低估的选择:重构循环,使中间结果根本不经过模型。与其让模型编排 20 个串行工具调用(每一次都是一次网络跳跃加一次推理过程),不如让模型编写一段在工具侧执行的小程序,只将最终答案返回给上下文。Anthropic 的 MCP 代码执行模式演示了一个代表性工作流:Token 消耗从 150,000 个降至 2,000 个,同时消除了 19 次推理。对于真正独立的调用,并行调度将延迟从总和降至最大值 —— LLMCompiler 等编排层研究报告称,与串行循环相比,延迟缩短了高达 3.7 倍,成本降低了高达 6 倍。这就是 Agent 领域的“预加载(eager loading)”:与 ORM 时代相同的药方,只是上升了一个层级。

错误的答案是默认选择 —— 让部署位置保持模糊,让每个团队独立选择云平台,直到收到账单时才第一次发现 Agent 系统的拓扑结构。

为任务设定预算,而非单次调用

实际的转变是将 Agent 任务视为 N+1 时代中的页面加载:将其作为获得预算的单位。

为每类任务设定实际时间(wall-time)预算和往返次数预算,并使执行树可见 —— 端到端地追踪工具调用,以便看到最长的串行路径,而不仅仅是单服务器的统计图表。将每个任务的出向流量(egress)作为与 Token 成本同等重要的核心指标进行追踪;两者的比例会告诉你问题出在交互过于频繁(chattiness)还是部署位置不对。当一个任务超出预算时,修复方法通常是结构性的而非渐进式的:将五个细碎的工具合并为一个能直接回答核心问题的工具,将循环推入同处一地的代码执行中,或者迁移数据。

那些深刻理解 N+1 问题的团队并不是通过加快每个查询的速度来解决问题的。他们通过让查询次数成为代码可审查的属性来达成目标。Agent 需要在更高层级具备同样的纪律:每个任务的往返次数应该是 Review 时能看到的数字,当它增长时需要附带说明。数据引力不会减弱 —— 模型变得更快,数据变得更重,它们之间的边界跨越成本变得更高。那些能够保持经济性的 Agent 系统,必然是那些从一开始就围绕数据实际所在地进行设计的系统。

References:Let's stay in touch and Follow me for more thoughts and updates