跳到主内容
10 分钟阅读

Agent 性能问题优化

从链路拆分、模型路由、并行工具、上下文预算到缓存与评测,定位并优化 Agent 的延迟、成本和吞吐。

Agent 的“慢”很少只慢在模型。一次任务可能依次经历鉴权、加载历史、检索知识、模型规划、多个工具、再次推理和结果持久化。盯着总耗时看,只会得到一个没有行动价值的数字。

优化前先把问题分成四个目标:

  • 延迟:用户多久看到首个反馈,多久拿到完整结果;
  • 吞吐:系统同时能处理多少 run;
  • 成本:每个成功任务消耗多少模型与基础设施费用;
  • 质量:任务是否真的完成,工具和引用是否正确。

它们经常互相拉扯。换小模型可能更快,却增加重试;提高并发可能提升吞吐,也可能把下游 API 打挂;砍掉上下文可以省 token,却让 Agent 忘记关键约束。

先画出一次运行的瀑布图

为每个 run、模型调用和工具调用记录 trace,并至少采集:

指标说明
queue time任务等待 worker 的时间
time to first token从请求到首个可见 token
model latency每次模型调用耗时
tool latency每个工具的排队、连接和执行耗时
input/output tokens输入和输出规模
step count一次 run 经过多少轮模型与工具
success rate不靠人工补救的任务完成率
p50 / p95 / p99常态与长尾延迟

总耗时拆开后,优化顺序通常很直白:若 70% 时间耗在串行工具上,换一个生成速度快 10% 的模型意义不大;若工具很快但模型来回规划八轮,就该先减少 step。

平均数还会掩盖问题。用户最容易遇到的是 p95 的超时、冷启动和限流,因此容量规划应围绕分位数,而不是只看一次顺利演示。

减少没有必要的模型轮次

每次模型请求都有网络往返、排队和生成成本。常见浪费包括:先用一轮判断要不要检索,再用一轮改写查询;让模型提取一个可以用确定性代码解析的字段;工具返回后无条件再让模型总结一次。

可以按以下顺序检查:

  1. 能用普通代码、SQL 或规则完成的,不调用模型;
  2. 能合并到同一轮的判断与结构化输出,合并处理;
  3. 彼此独立的模型或工具请求并行执行;
  4. 必须串行的步骤保留,因为后一步确实依赖前一步结果。

不要为了“单次调用”把互不相关的十件事塞进一个巨大 prompt。请求变少不代表系统必然更快,超长上下文和复杂输出同样会拖慢推理,还会降低可测试性。

模型路由按任务难度,而不是按页面

同一 Agent 中的步骤难度差别很大:分类、意图识别、格式转换往往不需要最强模型;跨文档推理、复杂代码修改和最终审核才值得使用能力更强的模型。

路由可以综合任务类型、上下文长度、风险等级与历史失败率:

type TaskClass = 'classify' | 'retrieve' | 'reason' | 'review'

function chooseModel(task: TaskClass, risk: 'low' | 'high') {
  if (risk === 'high' || task === 'reason' || task === 'review')
    return 'quality-tier'

  return 'fast-tier'
}

这里的字符串应映射到配置,而不是写死某家厂商的型号。切换策略前用同一组评测题比较成功率、延迟和成本,不能只看单价。

还可以设计升级路径:快速模型先处理,只有低置信、格式校验失败或工具选择异常时才升级。要把升级条件写成可观测规则,否则“模型自评信心不足”很容易失真。

控制上下文,而不是粗暴清空历史

输入过长会增加成本、传输与处理时间,也可能让关键指令淹没在噪声里。上下文应按用途分层:

  • 固定且稳定的系统指令;
  • 当前任务必须知道的业务状态;
  • 最近对话窗口;
  • 旧对话的结构化摘要;
  • 本轮检索出的证据;
  • 真正可能使用的工具定义。

为每一层设置 token 预算。超预算时优先删除重复工具结果、无关寒暄和已被摘要覆盖的历史,不要从字符串末尾直接截断,因为最末尾可能正好包含用户最新要求。

工具很多时,先按意图搜索候选工具,再只暴露少量定义。几十个冗长 JSON schema 每轮全部发送,既占上下文,也提高选错工具的概率。

让稳定前缀更容易缓存

不少模型服务支持 prompt prefix caching。常见前提是前缀逐项一致,因此应把系统规则、固定工具定义、长期不变的示例放在前面,把用户输入、时间戳、请求 id 等动态内容放在后面。

具体匹配规则仍要看模型服务。以当前 OpenAI GPT-5.6 为例,默认的隐式断点可能包含最新消息中的动态内容;只调整顺序不一定命中。可在稳定前缀末尾设置显式 breakpoint,并按文档配置 prompt_cache_key 与缓存模式。该系列还会单独计量 cache write,因此要同时观察 cache_write_tokenscached_tokens、延迟和实际费用,不能把“写入了缓存”等同于“已经省钱”。

供应商的 prompt_cache_key 用于路由或前缀匹配,不等于应用自己的结果缓存,也不能代替权限校验。下面这些应用侧缓存,key 才需要纳入租户、权限、prompt/索引版本和模型版本,避免跨用户复用不该共享的结果:

应用侧也可以缓存确定性结果:

  • embedding 与文档解析结果按内容哈希缓存;
  • 只读工具按参数、权限和数据版本缓存;
  • 查询改写和 rerank 结果按查询、权限与索引版本设置短 TTL;
  • 完整回答只有在来源、身份和时效边界明确时才缓存。

工具写操作、个人数据和依赖实时状态的结果不适合随意缓存。

并行工具要有边界

天气与日历查询互不依赖,可以并行;“创建文档后把链接发到群里”则必须串行。执行器可以根据依赖关系组成 DAG,而不是把所有 tool call 一股脑 Promise.all

并行还要受控:

  • 每个用户、租户和工具设置并发上限;
  • 对外部 API 使用连接池、超时和指数退避;
  • 遇到 429 尊重服务端的重试提示;
  • 使用带抖动的退避,避免所有 worker 同时重试;
  • 非关键工具失败时允许降级,不拖死整次 run;
  • 写操作用幂等键,避免超时后重复创建。

当下游已经拥塞时,继续提高并发只会扩大排队。系统需要背压:限制新任务进入、把非实时任务移入队列,并在界面上显示真实等待状态。

流式输出优化的是感知延迟

流式响应不一定缩短总耗时,但能显著改善首屏反馈。页面可以先展示任务已接收、当前步骤和工具进度,再逐段显示文本。

不过不要流出尚未确认的高风险结论。涉及审批、付款或删除时,先渲染结构化操作预览;检索型回答也可以等引用绑定完成后再展示完整句子,避免后续大幅撤回。

对于长任务,前端不应一直维持一个脆弱连接。服务端把事件持久化,客户端断线后按 event id 续传,后台 run 则继续执行。

RAG 的性能先查召回链路

知识库场景常见的慢点包括查询改写、两路召回、rerank 和过多片段进入生成。可以这样处理:

  • 关键词与向量检索并行;
  • 先用元数据过滤缩小搜索空间;
  • 控制召回候选和 rerank 数量;
  • 对相同文档版本缓存 embedding;
  • 去重后再组上下文,避免重复 token;
  • 低风险、高置信 FAQ 可走直接命中快路径。

不要只为提速降低 Top K。先看评测集中正确证据的 Recall@K,再决定能削到哪里。召回少一次错误答案,可能比多花几十毫秒更重要。

把失败控制在预算内

一次 run 应有明确预算:最大模型轮次、工具调用数、总 token、总耗时和金额。达到上限时返回已完成步骤、失败原因和可恢复状态,而不是无限循环“换一种方式再试”。

重试策略按错误分类:

  • 网络抖动、临时限流:带抖动的指数退避;
  • 参数校验失败:最多让模型修正一次;
  • 权限拒绝:不重试,直接请求授权或换方案;
  • 业务校验失败:保留证据并交给用户处理;
  • 不确定的写操作结果:先按幂等键查询状态,不直接重放。

熔断器可以隔离持续故障的工具,降级响应则告诉模型该能力暂不可用。让模型在工具已坏时反复尝试,只会把一次外部故障放大成整个平台拥塞。

优化后必须做回归评测

性能改动常以质量退化为代价。每次调整模型、prompt、上下文、并发或检索参数,都应在固定评测集上比较:

任务成功率 / 工具选择准确率 / 引用忠实度
p50、p95 首 token 与总延迟
平均模型轮次 / 输入输出 token / 单次成功成本
超时率 / 重试率 / 人工接管率

最值得优化的指标通常是“每个成功任务的成本和耗时”,而不是“每次模型调用”的数字。一个便宜但经常失败的方案,会通过重试和人工补救把总成本推得更高。

面试回答可以怎么组织

遇到“怎么优化 Agent 性能”,先说明性能包含延迟、吞吐、成本和质量;然后提出用 trace 拆解模型、检索和工具耗时;接着按瓶颈讨论减少轮次、模型路由、上下文预算、缓存、并行和背压;最后补上预算、降级与评测闭环。

比起罗列“换小模型、加缓存”,能说清楚测量方式和质量边界,更接近真实工程问题。

参考资料

Agent 性能问题优化

https://setobox.me/blog/2026/agent-performance
作者
Setobox(姬顶盒)
发布于
许可协议
CC BY-NC-SA 4.0