资讯详情

Agent响应慢?别只砍Prompt,系统性性能优化才是关键

📅 2026/10/26 0:01:36 | 华诺云谱 👁 阅读
Agent响应慢?别只砍Prompt,系统性性能优化才是关键
当一个 Agent 响应从 3 秒变成 30 秒群里第一句话往往是prompt 太长了砍一砍。这句话听着在理其实很像骑车放屁——动静不小对前进没有本质帮助偶尔还把自己憋得够呛。更现实的是很多团队把大量时间花在逐字删 prompt 上删完发现 Agent 还是慢甚至因为删掉了关键约束输出质量直接跳水。问题的根源在于Agent 的响应耗时是一个系统工程指标而 prompt 长度只是其中一个输入维度。与其盯着字数做“文案减肥”不如先把链路拆开搞清楚慢在哪个环节再对症下药。本文将围绕“Agent 性能优化”这个话题拆解延迟构成、分析 prompt 优化与性能之间的真实关系并给出可落地的排查和优化方案。文章适合正在做 Agent 应用开发、调试响应延迟、或者在架构设计阶段做性能预判的开发者。1. 为什么“Agent 慢”不能只怪 Prompt先澄清标题里的比喻。骑车时放屁产生的推力微乎其微既不能加速也不解决问题反而可能因为姿势变化影响踩踏节奏。Agent 性能优化里盲目砍 prompt 就是这种“伪动作”看起来在做事实际效果有限还容易引入新问题。1.1 一个反直觉的模型认知很多开发者默认“prompt 越长模型处理越慢”。这个认知对了一半但另一半很关键大语言模型LLM的推理延迟主要由两部分组成。第一部分是预填充prefill阶段即模型读取并理解输入的 prompt。输入 token 越多预填充耗时确实越长这就是“prompt 越长越慢”这一直觉的出处。第二部分是解生成decode阶段即模型逐个生成输出 token。这个阶段的耗时与输出长度成正比通常比预填充更慢因为生成是串行的一个 token 一个 token 地往外蹦。于是问题就来了假设一个 Agent 任务本来就需要模型做复杂推理、输出结构化结果你把 800 字 prompt 删到 200 字预填充时间可能只减少了不到 200 毫秒但如果输出阶段要生成 500 个 token这部分耗时按照单 token 生成速度来算才是真正的大头。前面省 200 毫秒后面一个工具调用多等 3 秒整体优化收益趋近于零。1.2 Agent 慢的真正延迟构成与单次 LLM 调用不同Agent 的完整响应链路通常包含多个 LLM 调用、工具调用、记忆检索、上下文拼接等步骤。以常见的 Agent 执行流程为例用户提问 → 意图识别LLM 调用 ① → 工具选择LLM 调用 ② → 执行工具外部 API / 数据库查询 → 结果摘要LLM 调用 ③ → 回复用户在这个链路里如果每一步都携带完整的系统提示词、历史对话、工具描述那么几十 KB 的上下文会被重复计费延迟也会叠加。此时 Agent 慢本质上不是“prompt 太长”而是“重复的 prompt 太多 串行步骤太多 工具调用太慢 上下文过大”等多个因素叠加后的结果。只盯着 prompt 长度优化相当于看到汽车油耗高不去检查发动机和胎压而是把后备箱里的矿泉水拿出来两瓶——有用但杯水车薪。1.3 核心结论先定位再优化不反对优化 prompt反对的是不加诊断地盲砍。正确的做法是先把 Agent 的延迟拆成可量化的指标LLM 调用次数、输入 token 数、输出 token 数、工具调用耗时、网络往返时间。哪个环节占比高就优化哪个环节。下面的章节会分别讲清楚方法和工具。2. 先搞清楚你的 Agent 慢在哪一段2.1 建立性能基线的四类指标要定位慢的环节第一步是采集指标。建议在 Agent 的每个关键节点打点至少记录以下四类数据指标类别具体指标说明LLM 调用指标prompt_tokens、completion_tokens、total_tokens每次调用的 token 消耗量LLM 耗时指标prefill 耗时、decode 耗时、首 token 延迟区分输入处理和输出生成的时间工具调用指标工具名、请求耗时、响应体大小外部 API、数据库查询的耗时编排指标步骤数、调用次数、总耗时整个 Agent 链路的拓扑和耗时分布以 Python 代码为例可以在工具函数和 LLM 调用外层包一个简单的计时器import time import json from functools import wraps def track_execution(func): 打印函数执行耗时示例用生产环境建议接入链路追踪 wraps(func) def wrapper(*args, **kwargs): start time.perf_counter() result func(*args, **kwargs) elapsed (time.perf_counter() - start) * 1000 print(f[TRACE] {func.__name__} 耗时 {elapsed:.2f} ms) return result return wrapper track_execution def call_weather_api(city: str) - dict: 模拟外部天气 API 调用 time.sleep(0.8) # 模拟网络延迟 return {city: city, temperature: 26} track_execution def call_llm(messages: list, model: str qwen-plus) - str: 模拟 LLM 调用示例用实际按你使用的 SDK 接入 time.sleep(1.2) # 模拟模型推理延迟 return 根据天气 API 结果建议穿短袖。实际生产环境不建议用 print建议接入 OpenTelemetry、SkyWalking、Jaeger 等链路追踪工具把每个 span 的耗时和属性上报到监控系统这样才能看到整条链路的耗时瀑布图。2.2 一次“慢请求”的链路拆解为了直观理解延迟分布下面模拟一次带工具调用的 Agent 请求步骤 耗时毫秒 说明 用户输入解析 50 规则解析不涉及 LLM 意图识别LLM 调用① 2500 输入 5000 token输出 80 token 工具选择LLM 调用② 3000 输入 6000 token输出 120 token 天气 API 调用 800 外部接口 结果摘要LLM 调用③ 3200 输入 6500 token输出 300 token 回复拼装 30 纯字符串操作 总耗时 9580此时砍掉 500 字的 prompt三个 LLM 调用的输入 token 各减少约 100 个预填充时间可能总共减少 300 毫秒左右。但 LLM 调用本身的生成阶段耗时、工具调用耗时、多轮串行开销依然存在总耗时依然在 9 秒以上。这就是“砍 prompt 是骑车放屁”这句话背后的数据逻辑它优化的是整个链路里占比很小的一个子环节而不是主要矛盾。真正值得做的优化可能是把三个 LLM 调用缩减为两个、把工具调用结果缓存、或对历史对话做压缩摘要。这些都直接影响链路结构和次数优化空间远大于删 prompt 本身。3. 优化 Prompt 的正确姿势不是“砍”而是“翻译”前面说了不能盲目砍 prompt但 prompt 依然需要优化。重点不是“删多少字”而是“让模型更快、更稳地给出所需格式和内容”。3.1 不省白不省的 Token减少输出 token 比减少输入 token 更有效输出 token 是逐个生成的直接决定 decode 阶段耗时。如果可以让模型用 100 个 token 输出结构化结果而不是用 300 个 token 输出长篇解释那么每次调用能节省的耗时非常可观。举一个例子下面这段指令希望模型返回“工具是否可用”的判断请阅读用户问题并结合你的知识判断是否需要调用天气查询工具。 如果用户问题中包含城市名且意图是查询天气那么请调用天气查询工具。 如果用户没有明确提到城市或意图不是天气相关那么不要调用工具。 并且请在回复中说明你的理由以及你对用户意图的判断依据。这段 prompt 本身没问题但模型输出时倾向于写一大段解释。更好的做法是给模型一个“最小输出模板”请判断是否需要调用天气查询工具。 要求 - 只需要返回 JSON不要输出任何解释。 - 格式{need_tool: true/false, tool_name: weather_api, params: {city: 北京}} - 如果不需要调用工具params 字段返回空对象。同样是“判断意图”的任务第二种 prompt 通过约束输出格式把输出 token 从 150 降到 30decode 耗时可能减少三分之一以上。这就是典型“不砍输入、砍输出”的优化思路。3.2 结构化提示词用编号、分段替代长篇描述很多 prompt 之所以长是因为内容重复且层次不清。例如你是一个智能助手你需要帮助用户解答问题。你必须保持礼貌。你需要在回答时考虑用户的感受。 同时你必须严格遵守安全限制。当用户问你敏感问题时你必须拒绝回答并且给出理由。 你不需要提及这些安全规则。你的回答需要简洁、准确。这段 100 字左右的指令里“必须”重复了五次信息密度低。改成结构化形式后信息量不变但长度减半你是一个智能助手。回答时遵循以下规则 1. 礼貌、简洁。 2. 涉及违法、危险、隐私等敏感话题时只回复“抱歉我无法回答”。 3. 不主动提及规则内容。这种“翻译”式优化不损失约束效果但减少了模型需要读取的 token 数预填充耗时也随之降低。核心思路是把“散文式 prompt”翻译成“清单式 prompt”。3.3 案例对比一个调优前后的 System Prompt下面是一个实际调优对比示例。优化前你是公司的客户服务助手。请根据用户的问题给出回复。 回复时语气要专业、友好。 如果用户询问订单状态请查询订单系统。 如果用户要退货请查询退货政策。 如果用户要求人工服务请转接人工客服。 如果遇到不懂的问题不要乱编要承诺进一步确认。 回复要给出明确的信息不要含糊。优化后你是客户服务助手。使用以下规则处理问题 - 订单查询 → 调用 order_api 获取状态。 - 退货咨询 → 读取退货政策文档。 - 人工客服 → 返回人工客服工单链接。 - 其他/不确定 → 回复“已记录将尽快答复”不要编造信息。优化后的 prompt 从 150 字降到 90 字并且把“业务动作”和“响应方式”直接绑定模型更容易理解也更依赖工具调用而非自由发挥。这里的收益不只是输入 token 减少还包括决策准确率的提升。3.4 需要避免的误区删除必要的安全约束为了省 token 把安全规则删掉模型可能输出越界内容生产事故成本远高于省下的几毫秒。压缩到模型无法理解过度缩写导致模型不理解指令反而增加重试次数整体延迟上升。只关注 System Prompt不关注用户消息用户消息往往占据更多 token需要做的是截断、摘要、检索而不是跟着用户消息无限增长。4. 真正的性能抓手缓存、并行与上下文工程定位到慢的环节以后常见的性能优化手段集中在四个方面缓存、上下文管理、并行执行和模型/参数选型。4.1 缓存层同一个问题不要问两次Agent 应用中很多 token 消耗和耗时来自重复计算。缓存可以大大减少这类浪费。第一层完整请求缓存。如果用户的问题完全相同直接返回历史答案。适合 FAQ、操作手册查询等场景。代码示例from functools import lru_cache lru_cache(maxsize128) def get_agent_response(user_query: str) - str: 根据用户问题获取 Agent 回复示例用缓存 # 这里实际会调用 Agent 编排逻辑为了演示直接返回固定内容 return f关于「{user_query}」的标准答复第二层语义缓存。用户问题可能措辞不同但语义一致。通过向量化用户问题在向量数据库中查找最相似的历史问答命中则直接返回。这比完整请求缓存更智能适合客服场景。第三层工具调用缓存。天气查询、股票价格、订单状态等外部 API 的返回结果可以缓存一段时间避免同一个数据被反复请求。代码示例import time cache {} def get_weather_with_cache(city: str, ttl: int 600) - dict: 带 TTL 的天气查询缓存600 秒内重复请求直接返回缓存值 now time.time() if city in cache: data, expire_at cache[city] if now expire_at: return data data call_weather_api(city) # 真实调用外部接口 cache[city] (data, now ttl) return data4.2 上下文管理别把整个对话历史都塞给模型Agent 的多轮对话中上下文会不断增长。最直接的优化方案有两个。方案一滑动窗口截断。只保留最近 N 条消息更早的消息丢弃。适合对历史记忆要求不高的场景。def truncate_messages(messages: list, max_messages: int 10) - list: 保留最近 max_messages 条消息保证上下文不无限增长 if len(messages) max_messages: return messages # 保留系统提示词 最近 max_messages - 1 条消息 system_prompts [m for m in messages if m.get(role) system] recent messages[-max_messages:] return system_prompts recent方案二摘要压缩。对较早期的对话调用一次 LLM生成摘要后续只携带摘要而不是完整原文。这个方法能大幅减少输入 token但需要注意摘要调用本身的耗时和成本。方案三RAG 检索。如果 Agent 需要依赖大量文档知识不要把所有文档塞进 prompt而是先用向量检索找到最相关的片段再拼接进上下文。这是目前最通用的大上下文解决方案。def build_context_with_retrieval(query: str, top_k: int 3) - str: 从向量数据库中检索与 query 最相关的 top_k 个片段拼接为上下文 # 假设 vector_db 是已配置好的向量数据库客户端 results vector_db.similarity_search(query, ktop_k) context_blocks [] for idx, doc in enumerate(results, 1): context_blocks.append(f[文档{idx}]\n{doc.page_content}) return \n\n.join(context_blocks)4.3 并行与异步能并行的步骤不要串行在 Agent 链路中有些步骤天然可以并行。例如如果用户一次问了三个问题分别对应三个不同的工具调用理论上可以同时发起三个 LLM 调用而不是等待上一个完成再执行下一个。以 Python 的asyncio为例import asyncio async def call_tool_async(tool_name: str, param: str) - str: 模拟异步工具调用 await asyncio.sleep(1) # 模拟耗时操作 return f{tool_name} 处理结果: {param} async def run_parallel_tools(params: list) - list: 并行执行多个工具调用总耗时约等于最慢的一个 tasks [call_tool_async(tool_a, p) for p in params] return await asyncio.gather(*tasks) # 示例调用 # results asyncio.run(run_parallel_tools([参数1, 参数2]))需要注意的是并行调用可能增加整体 token 消耗峰值也可能触发 API 的限流策略。并行度需要根据实际 API 配额和限流情况做调整不要盲目开大。4.4 模型选型与参数调优不同模型的推理速度和成本差异巨大。一个负责任的性能优化过程应当对模型本身做选型评估。轻量任务用小模型意图识别、实体抽取、格式分类等任务用参数量较小的模型即可耗时可显著降低。复杂推理用大模型代码生成、多步推理、复杂指令遵循仍然建议使用更强的大模型避免因回答质量下降而反复重试。调整 max_tokens 参数如果业务场景不需要超长输出可以限制max_tokens防止模型在生成阶段“自由发挥”。合理设置 temperature低 temperature 更适合事实型问答高 temperature 适合创意型写作。过高的 temperature 可能导致模型绕圈子增加输出长度和耗时。示例如下from openai import OpenAI client OpenAI( api_keyyour-api-key, base_urlhttps://your-llm-gateway.example.com/v1 ) response client.chat.completions.create( modelqwen-turbo, # 轻量模型适合意图识别 messages[ {role: system, content: 判断用户意图只输出 JSON。}, {role: user, content: 北京明天天气怎么样} ], max_tokens50, # 限制输出长度减少 decode 耗时 temperature0.1 # 低温度输出更稳定 )5. 一套可落地的 Agent 性能优化清单结合前面的分析整理出一套可以直接套用的优化动作清单。建议按照优先级顺序执行。第一优先级先建立可观测性。没有监控就没有优化。至少记录每个 LLM 调用的 token 消耗和耗时记录每个工具调用的耗时和成功率。这一步是后续所有优化的前提。第二优先级减少步骤数而不是减少字数。检查 Agent 链路中是否有不必要的 LLM 调用比如“意图识别”和“工具选择”是否可以合并为一个调用。每减少一次 LLM 调用节省的是整个步骤的耗时效果远大于删 prompt。第三优先级控制输入 token用检索替代全量上下文。历史对话无限增长时优先做截断或摘要知识库内容较大时优先用 RAG 检索相关片段而不是全量拼接。这一步能降低预填充耗时也能减少 API 费用。第四优先级控制输出 token。输出 token 是 decode 阶段耗时的直接来源。优先使用格式约束、输出模板、低位采样参数让模型少说废话输出更紧凑。第五优先级加缓存。完整请求缓存、语义缓存、工具调用缓存都能在不同程度上减少重复计算。缓存命中率是关键指标建议周期性统计。第六优先级并行化。检查串行链路中是否存在可以并行的工具调用通过异步方式并发执行。注意限流和配额避免触发 API 429。6. 常见问题排查表常见错误排除思路如下问题现象常见原因解决思路首字延迟高输入 token 过大预填充耗时长检查 LLM 调用日志中的 prompt_tokens做上下文截断或摘要整体响应慢但单次 LLM 调用很快Agent 串行步骤过多用链路追踪查看调用次数尝试合并或并行化总是调用同一个工具重复查询缺少工具结果缓存为外部 API 增加 TTL 缓存删除 prompt 后回答质量下降删掉了必要的约束信息用结构化、编号方式压缩而不是删除语义并发调用频繁报错触发 API 限流降低并行度增加退避重试机制模型生成大段无关内容输出未加格式约束max_tokens 过大强制 JSON 输出限制 max_tokens多轮对话后上下文快速膨胀历史消息全部保留使用滑动窗口截断或摘要压缩prompt 明明很短还是慢慢的根因不在 prompt而在工具调用检查工具 API 响应耗时、网络延迟这里需要特别强调不要因为某个方法在别人项目里有效就直接套用。每个 Agent 的瓶颈不同正确的做法是先看监控数据再决定优化动作。7. 不要做一个“骑在车上放屁”的优化者回到标题。Agent 慢砍 prompt为什么说是骑车放屁不是因为 prompt 不能优化而是因为它只是整个链路中一个局部因素且容易被误当作万能手段。真正的 Agent 性能优化是一套工程方法需要数据、链路追踪、上下文工程和架构调整而不是文案删减。在 Agent 开发实践中更推荐把性能优化看作一个持续迭代的过程先建立可观测性再量化瓶颈然后针对性地做上下文压缩、步骤合并、缓存和并行化。Prompt 本身当然要优化但优化目标是提高信息密度和输出稳定性而不是单纯追求字数减少。如果能把这套思路用在你的 Agent 项目里你大概率会遇到这样的情况prompt 并没有变短多少但整个 Agent 从 20 秒跑进了 5 秒。到那时候你就可以自信地说真正解决慢的问题的不是砍 prompt而是把 Agent 当成一个需要认真对待的系统来优化。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑