Agent变慢别急着砍Prompt,性能瓶颈排查指南
2026/9/8 5:28:46 网站建设 项目流程

Agent 慢的时候,很多人第一反应就是砍 Prompt。把 system prompt 从两千字砍到三百字,删掉角色设定,去掉输出格式,重新跑一次,发现该慢还是慢。这不是个别现象。Agent 这类应用的响应延迟,本质上是一条完整链路的累积结果,Prompt 只是其中一个环节。把慢全部归因到 Prompt,甚至指望靠“精简提示词”解决性能问题,基本属于隔靴搔痒。

如果你正在做 Agent 开发,或者已经部署了基于大模型的智能体,发现系统响应慢、批量任务排队严重、单次任务动不动几十秒,这篇文章会帮你重新建立排查顺序:先定位慢在哪一层,再决定要不要动 Prompt。真正的性能瓶颈,往往藏在上下文膨胀、工具调用往返、模型推理时间和重试策略里。

我会按实际落地顺序,把 Agent 性能排查的思路、步骤和判断标准拆开讲一遍。

1. 先搞清楚 Agent 慢,到底慢在哪一层

1.1 一慢就砍 Prompt,为什么经常是瞎忙

先看一个典型场景。你封装了一个 Agent,用来做资料整理和报表生成。用户输入一个查询后,后端要把任务拆成几步:读取历史记录、调用检索工具、让模型推理、生成最终答案。整条链路跑完花了 28 秒。你的第一反应是:是不是 Prompt 写得太长,模型读得太慢?

于是你把 system prompt 里的背景说明删掉,把工具说明压缩成几行,把输出模板精简。结果跑完还是 25 秒。为什么?因为一次 Agent 请求的耗时,往往不是由 Prompt 字符串长短决定的,而是由下面这些因素叠加出来的:

  • 输入 token 总量。Prompt 只是输入 token 的一部分,真正占大头的是历史消息、工具返回结果、上下文文档。
  • 模型推理时间。同样的输入,不同模型的速度差异可能达到数倍。
  • 工具调用次数。Agent 每调用一次外部工具,就多一次网络往返和结果解析。
  • 重试和失败处理。工具超时、模型报错、解析失败,都会让任务从头再来。
  • 并发和排队。同一时刻任务多了,请求只在队列里等着,也会产生明显延迟。

如果这些问题没排查,只盯着 Prompt 字数,基本就是白忙。

1.2 分段计时:把一次 Agent 任务拆成可观测的环节

要解决慢,第一步不是优化,而是测量。建议先把一次 Agent 任务拆成下面几个阶段:

  1. 输入预处理:文本清洗、格式转换、权限校验。
  2. 任务规划:模型判断要调用哪些工具、按什么顺序执行。
  3. 工具调用:外部 API 请求、数据库查询、文件读取。
  4. 模型推理:多轮对话或单轮生成。
  5. 输出后处理:解析 JSON、格式化、落库。
  6. 重试和补偿逻辑:异常情况下额外增加的耗时。

拆完之后,给每个阶段打点计时。最简单的做法是在代码里埋时间戳:

import time def run_agent_task(task_input): result = {} start = time.perf_counter() task_input = preprocess(task_input) result["preprocess_ms"] = (time.perf_counter() - start) * 1000 start = time.perf_counter() tool_results = call_tools(task_input) result["tool_call_ms"] = (time.perf_counter() - start) * 1000 start = time.perf_counter() model_output = call_llm(task_input, tool_results) result["llm_ms"] = (time.perf_counter() - start) * 1000 start = time.perf_counter() final_output = postprocess(model_output) result["postprocess_ms"] = (time.perf_counter() - start) * 1000 return final_output, result

这只是示意,真实项目里可以把它接进日志框架。关键是你要有一份数据,知道 28 秒到底花在哪个环节。如果 tool_call_ms 占了 20 秒,那问题根本不在 Prompt,而在工具接口。如果 llm_ms 占了 20 秒,你该考虑模型选择、上下文长度或推理参数,而不是 Prompt 字数。

判断标准很简单:

  • 单环节耗时占比超过 50%,优先处理这个环节。
  • 优化前和优化后必须对比同一组测试样本。
  • 不要只看一次结果,至少跑 5 次取中位数。

没有数据,所有优化都是猜。

2. 上下文膨胀和重复推理,才是最常见的隐形拖累

2.1 上下文越长,推理成本不是线性增长

很多 Agent 框架会把聊天历史、工具返回结果、系统指令全部拼在一起,作为下一轮模型的输入。每轮对话都会把之前的 token 再重新发送一遍。任务跑得越深,历史越长,后续每一轮请求的输入 token 就越大。

这里有个容易被忽略的点:输入 token 增加,模型处理时间不是简单线性增长。尤其在基于 Transformer 架构的模型里,长上下文的注意力计算开销会明显上升。多轮 Agent 任务跑到十几步之后,每步都在处理越来越长的上下文,整体延迟自然被放大。

有一个经验很值得记住:Agent 慢,经常不是因为第一次请求慢,而是因为第 N 次请求慢。第一次请求 prompt 写得好不好,可能只影响一两秒;第十次请求之前累积的历史和工具结果,可能一次就多出几万 token。

2.2 简化 Prompt 不等于压缩上下文

理解了上下文膨胀,再回头看“砍 Prompt”这个动作,就会发现它有多局限。

假设 system prompt 从 2000 字砍到 500 字,省下 1500 字。但每一次请求仍然要携带:

  • 前 20 轮对话历史,每轮可能 500 到 2000 token;
  • 最近 5 个工具返回的 JSON,有的返回结果几千字;
  • 用户上传的文档切片,一个切片就可能覆盖几千 token。

砍掉 1500 字的 system prompt,能影响多少总耗时?很小。

真正需要做的是上下文管理:

  • 历史裁剪:只保留最近几轮的关键信息。
  • 历史摘要:用模型把前面的对话压缩成摘要,而不是全量保留。
  • 工具结果截断:工具返回结果只保留核心字段,不要把整个 JSON 塞进去。
  • 关键文档检索:用检索方式拿相关片段,而不是把长文档全文塞进上下文。

这些操作都属于上下文工程,不是 Prompt 工程。上下文压缩之后,每轮请求的输入 token 会显著下降,延迟也会跟着降。这才是治本方向之一。

3. 让 Agent 真正变快的几条实用路径

3.1 优化任务拆解和工具调用,而不是先精简 Prompt

Agent 和普通单轮补全最大的区别,是会自主决定调用工具。这个能力带来灵活性的同时,也带来了大量额外延迟。

举个例子。一个 Agent 要回答“最近一周各渠道的销售数据”。如果它的设计是先查渠道列表,再逐个渠道查数据,最后再汇总生成结论,那它可能需要 4 到 5 次模型推理,中间还夹着多次工具调用。每一步都有网络延迟和模型推理延迟,整体会非常慢。

如果能把“查渠道列表”和“查各渠道数据”合并成一个工具接口,或者提前在代码层把渠道列表注入,让模型一次拿到所有数据,那整个任务可能只需要两次模型推理。

所以遇到 Agent 慢,先做减法,但这个减法不是减 Prompt,而是减步骤。检查一下:

  • 能不能减少工具调用次数?
  • 能不能把多个独立查询合并成一个?
  • 能不能在代码里预设规则,避免让模型做不必要的规划?
  • 能不能让工具调用超时更快,不要傻等?

另外要单独关注失败重试。工具超时默认 30 秒,如果还允许重试 3 次,最坏情况下一个工具就要 120 秒。这类问题和你写多少 Prompt 一点关系都没有。

3.2 引入缓存、跳步、并行和分批

优化链路之后,再看吞吐层面。常见手段有四类:

第一,缓存。对于同样或高度相似的请求,不要再完整调用模型。可以在两个层面缓存:工具结果缓存和模型输出缓存。工具结果缓存尤其有效,因为很多 Agent 会反复查询相同的数据。模型输出缓存需要评估效果一致性和业务风险,适合那些结果可复用、对时效性不敏感的场景。

第二,跳步。如果 Agent 在某一步已经拿到明确答案,就不需要再走后续流程。可以在代码里加状态判断,提前结束任务。不要为了“规划完整”而让模型做多余的推断。

第三,并行。当一次任务需要调用多个互不依赖的工具时,尽量并发执行,而不是串行等待。很多 Agent 框架默认是按顺序调用工具,时间被简单相加。你可以用 asyncio 或线程池把独立调用并行化。

import asyncio async def fetch_sales_data(channel_ids): tasks = [query_channel(channel_id) for channel_id in channel_ids] results = await asyncio.gather(*tasks, return_exceptions=True) return results

第四,分批。如果是批量任务,比如处理 100 个文件,不要让每个文件都完整跑一遍流程。应该用任务队列,控制并发数,处理失败重试,并保存断点进度。这里有个常见误区:低配置环境也能跑一个文件,不代表能同时跑 100 个文件。并发太高会让模型服务直接排队,反而更慢。

注意:不要把并行数直接拉到最大。先小批量验证接口和资源占用,再逐步提高。

3.3 模型选择和参数设置同样影响延迟

很多人调 Prompt 时,从来没想过换模型。但模型本身的推理速度,是决定延迟最大的变量之一。

同一个任务,用大参数模型可能跑 8 秒,用更快的小模型可能跑 2 秒。如果你的业务对结果质量要求不是极端苛刻,完全可以在 Agent 的不同环节用不同模型:简单分类、意图识别、格式提取用小模型;复杂规划和最终生成用大模型。这类策略叫模型路由,效果通常比死磕 Prompt 明显得多。

参数设置也要检查:

  • max_tokens。有些框架默认给很大,模型会尽量生成到上限附近。如果你的任务只需要几百字,把 max_tokens 调低。
  • temperature。不直接决定速度,但过高的随机性可能导致输出不稳定,增加重试成本。
  • timeout。给每一次模型调用和工具调用设置合理超时,不要默认无限等待。
  • stream。如果用户只需要最终结果,可以不开流式;如果需要“感知速度”,就开流式输出让首字尽快到达。

判断标准要分开看:端到端耗时、首 token 耗时、单步耗时、成功率和 token 消耗。只盯其中一个指标,很容易被误导。

4. 从“能用”到“稳定快”:日志、追踪和压测怎么落地

4.1 给 Agent 加可观测性,比反复改 Prompt 更值钱

聊到 Agent 性能优化,很多开发者最缺的不是技巧,而是数据。问题在于 Agent 任务链路太长,中间状态又多,光靠肉眼观察根本定位不了瓶颈。

建议至少记录以下字段:

字段说明
task_id每一次任务的唯一标识
step_name当前链路步骤
model_name实际使用的模型
input_tokens输入 token 数
output_tokens输出 token 数
duration_ms该步骤耗时
tool_name调用的工具名称
status成功、失败、超时、重试

可以用 LangSmith、Langfuse 这类追踪工具,也可以自己打结构化日志。关键是数据能串成一条完整的调用链,能够回答三个问题:

  • 慢在哪一步?
  • 每次请求发送了多少 token?
  • 失败和重试占了多少时间?

我一般会先看“错误率”和“重试次数”。很多 Agent 慢,不是正常处理慢,而是失败之后一遍遍重试。这时候优化 Prompt 没有意义,先处理异常路径才对。

4.2 用一份最小基准测试判断优化是否有效

没有基准,你没法判断改动是变好还是变差。建议维护一组固定的测试样本,规模不用大,10 到 20 条就够。

测试样本要覆盖:

  • 正常短任务;
  • 长上下文任务;
  • 需要多次工具调用的任务;
  • 工具返回异常或超时的任务;
  • 用户输入含糊、容易触发误判的任务。

固定模型、参数和并发数。每条样本跑 5 次,取中位数。记录三个核心指标:端到端耗时、成功率、平均 token 消耗。

优化前先跑一轮基线。之后每做一次改动,就在同一组样本上重跑。如果改动之后端到端耗时下降 20%,且成功率没有下降,说明这个改动有效。如果只是某个环节数据变好,但整体没有改善,说明瓶颈不在那里。

注意:不要只测“最好走”的路径。长上下文和失败重试路径,往往是拖垮整体性能的隐藏点。

5. Prompt 该不该调?该调,但要分清优先级

5.1 Prompt 质量影响结果质量,不等于速度

写到这里,不是说要完全放弃 Prompt 工程。Prompt 当然重要,但它的核心价值是控制模型行为,不是控制系统性能。

一段写得很好的 Prompt,可以让模型更准确地理解任务,减少格式错误,减少无效工具调用。这些能力间接会降低重试率,从而让系统看起来更快。但这里有一个前提:你必须先确定慢的根因是模型行为异常,而不是链路本身太重。

如果模型每一步都给出错误格式,导致解析失败,重试三次,那确实该改 Prompt。如果模型输出很稳定,只是每一步都要处理几万 token,那改 Prompt 解决不了问题,应该去改上下文和链路结构。

有个很实用的判断方法:看日志里失败原因分布。如果大量失败来自“输出格式不符合预期”或“JSON 解析失败”,Prompt 是优化重点。如果失败来自“工具超时”“接口限流”“模型排队”,那就别在 Prompt 上浪费时间。

5.2 什么时候该调 Prompt,什么时候别只改它

按优先级排序,我的建议是:

  1. 先看链路耗时分布;
  2. 再看上下文 token 是否有压缩空间;
  3. 再看工具调用是否过多、超时和重试是否合理;
  4. 再看模型选择是否匹配任务难度;
  5. 最后才 review Prompt。

换句话说,Prompt 是排查顺序里的最后一项,不是第一项。

即使要调 Prompt,也要注意边界:

  • 不要把 Prompt 砍到不可读。太简略会导致模型理解错误,反而提高重试率。
  • 不要只删不补。如果系统指令里有必要的安全限制、输出格式、工具使用规范,删掉会引入新的行为问题。
  • 不要反复堆 Prompt。遇到问题就加一句“请务必准确”“不要瞎编”,这类话对性能没有任何帮助。

正确做法是把 Prompt 当成代码来维护:结构化、版本化、可测试。每次修改 Prompt,都当成一次功能变更,记录变更原因、影响范围和测试结果。

6. 写在最后:处理慢问题,先按链路排查,不要凭感觉动刀

我见过太多 Agent 项目,性能一慢就进入“调 Prompt 循环”:今天删一段,明天加一段,后天又改回来,始终没解决真正的问题。

如果让我给一个最直接的建议,那就是在动手之前,先跑一轮完整的数据埋点。把任务拆成步骤,给每一步计时,记录输入 token、输出 token、工具调用耗时和重试次数。拿到数据之后,你自然会知道该动哪里。

这个方案真正落地时,最该盯住的不是 Prompt 写得好不好,而是上下文管理、工具调用效率和失败重试策略。把这三件事做好,Agent 慢的问题基本能解决一大半。等到链路干净了、日志完整了,再回头优化 Prompt,你会发现自己不再靠猜,每一步都看得见效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询