智能体降本增效:资源感知、推理控制与监控全攻略 开门见山说一句如果你正在做智能体类应用大概率已经经历过来自账单的惊吓。一个看起来并不复杂的问答任务最后却消耗了几十万token一个本该三步结束的工具调用因为模型绕来绕去的思考而变成十几步。这些问题如果不在设计阶段就处理等Agent跑起来之后再去优化成本会呈指数级上升。这篇主要讲三件事资源感知优化、推理技术、评估与监控。这三者放在一起本质上是在解决同一个问题让智能体不仅“能做”而且“做得起、做得快、做得好”。很多人把资源感知当成省钱工具其实不止。一次长时间运行的Agent任务如果上下文越来越长响应速度会越来越慢最终可能直接超时。资源问题会传导到产品体验、稳定性和可观测性是Agent能否从Demo走向生产的核心约束。所以这期的内容不聊概念全部按可落地的思路来讲。1. 资源感知优化让智能体像老会计一样精打细算1.1 资源感知不是提前压预算而是让Agent知道自己还能花多少首先要纠正一个误区资源感知优化不是把所有Prompt压缩到极致也不是一律选用小模型。这些东西如果做得太激进Agent会变得“听不懂人话”最终靠重试和反复运行来补救总体成本反而更高。我理解的资源感知是Agent在每一步行动时都清楚自己当前还有多少Token预算、多少步骤预算、多少成本限额并能根据这些约束主动调整策略。比如当上下文还剩15000个Token时模型应当决定是否调用一个可能返回大量内容的工具当任务已经消耗了90%预算但还没找到答案时Agent不应该继续埋头执行而应该明确告诉上层“我建议换一种方式”。本质上这就是给Agent加了一个“大脑里的记账本”。每一次模型调用、每一轮工具返回、每一步思考消耗都要被记录并且反馈到下一步决策中。很多框架已经支持usage回传但真正把usage数据当决策依据的项目很少。大多数情况是日志里记了代码里没用。1.2 先把常见模式的资源消耗摸透再谈优化先看一张我平时做设计时经常用到的对照表把常见的Agent模式、主要消耗和优化方向放在一起看模式主要资源消耗点典型风险推荐优化方向基础循环LLM调用工具执行Prompt中的上下文重复、模型输出token上下文膨胀响应变慢缓存历史、裁剪对话、压缩总结单轮工具调用工具返回结果直接塞进上下文工具输出过大导致超限截断、结构化提取、按需获取字段检索增强生成每轮检索重复Embedding、文档片段过多检索片段占满上下文缓存向量、只取关键片段、重排序多Agent协作多个模型并行调用协商轮次多token按倍数消耗延迟高限制对话轮数、引入仲裁模型自我反思/自我修正重复生成反思结果与原答案反思过度导致成本翻倍设定反思次数上限只在小范围重试长文档处理长文本分段、多轮摘要、压缩单次处理成本过高先粗筛再精读、增量式摘要这张表其实揭示了一个规律Agent消耗资源的真正大头往往不是回答本身而是“反复”。上下文反复携带、工具反复调用、思考反复生成、错误反复修正。要控制资源最重要的是控制重复。1.3 三种立刻能用的资源控制手段预算、缓存、降级先说预算。很多开源Agent框架都有max_iterations这类参数但它只限制步数不限制Token和成本。更合理的做法是三元预算步数预算、Token预算、成本预算。任意一个被击中就触发终止或者降级。举个例子可以这样定义一个运行上下文class AgentBudget: def __init__(self, max_steps, max_cost, max_tokens): self.max_steps max_steps self.max_cost max_cost self.max_tokens max_tokens self.current_steps 0 self.total_cost 0 self.total_tokens 0 def can_continue(self): return ( self.current_steps self.max_steps and self.total_cost self.max_cost and self.total_tokens self.max_tokens ) def register_usage(self, usage_data, cost_data): self.current_steps 1 self.total_tokens usage_data.get(total_tokens, 0) self.total_cost cost_data每次模型返回后把usage和cost注册进去循环判断can_continue。这套逻辑大概半小时就能接完但对稳定性的提升非常明显。再说缓存。缓存分三层Prompt缓存同一段系统提示词在大模型侧本身就可能有缓存这部分能省就省不要在每次请求里动态拼接重复内容。工具结果缓存同一个查询条件、同一个用户、同一个工具在5分钟内返回过相同结果可以直接复用。向量检索缓存相同Query命中的文档片段结果可以缓存避免重复Embedding。第三是降级。不要全局只用一个大模型。判断任务难度后可以用一条简单的路由规则需要复杂推理时走大模型简单分类、提取、改写直接走小模型。这个路由不一定要靠模型来判用关键词、参数数量、工具类型等规则就能覆盖80%的场景。预算越紧张路由越要前置。2. 推理技术既要答得对又要算得快2.1 控制推理深度比控制模型参数更有效控制推理技术最容易犯的错是把所有任务都设计成“先让模型想一遍再回答”。对于复杂任务这没问题但对于明确的任务比如“把这个地址解析成结构化字段”“将日期转换成时间戳”让模型做深度推理就是纯浪费。如果你检查一下真实项目里的账单会发现大量Token都花在了模型重新发明轮子上。模型在推理时把JSON schema重新描述了一遍把工具说明重新理解了一遍甚至把用户问题转述了一遍。这些都属于可压缩成本。一个比较有效的办法是在Prompt中显式设置推理预算。不是只设置max_tokens而是把“推理应该多长”写进系统提示词例如对于简单指令“直接返回结果不要解释过程。”对于中等任务“最多给出三条推理过程然后直接输出。”对于复杂任务“允许分步思考但每步不超过50个Token。”这样模型会倾向于在给定范围内输出。滥用长思考链在正确率上不一定有回报但在账单上一定有回报。2.2 用“守门员模式”拦截明显可以零成本解决的问题推理优化不是每次都要请大模型出场。很多请求在到达大模型之前就可以用规则、函数或者小模型解决这就是守门员模式。我常写的一个基础拦截逻辑大致是这样def preflight_check(user_input, available_tools): # 1. 如果输入已经是合法JSON直接解析不调用LLM if looks_like_json(user_input): return parse_and_return(user_input) # 2. 如果用户明确要求调用某个工具且参数齐全 if extract_intent(user_input) in available_tools: return call_tool_directly(user_input) # 3. 如果这是一个数学计算或时间日期查询 if is_calculator_query(user_input): return run_calculator(user_input) # 4. 以上都不满足才进入LLM return route_to_llm(user_input)这个模式看起来简单但大多数人不敢做因为担心规则太脆。实际经验是只需要拦截掉最明显的几个高频场景就能省下10%到30%的推理成本而且这些场景的规则几乎不会误杀。2.3 用结构化输出压缩往返次数推理优化另一个大头是重试。模型输出不符合预期然后解析失败、再调用一次模型、再失败这种循环比模型本身贵得多。解决思路是把输出格式从“自由文本”变成“强约束结构”。在调用模型时直接声明输出JSON Schema并要求模型按Schema返回。如果是工具调用优先使用函数调用模式让模型输出参数而不是自由结果。这里有个容易被忽略的细节点很多模型在输出结构化对象时会把多余的说明文字也带出来。要解决可以在解析时只提取第一个合法JSON块其余内容全部丢弃不要因为旁边多了几个字就判定失败并重试。当然也不要因为校验失败就直接重试整个推理过程。更好的做法是如果格式差一点点就做修正如果语义都错了才需要重新走模型。重试本身也应该消耗预算否则模型会利用“反正可以无限重来”的空间反复尝试。2.4 并行与串行的选择该并行时不要等待推理技术的另一个关键点是任务拆分。当一个Agent任务需要执行多个独立工具调用时串行执行不仅慢而且每一步都会把前一步结果重新塞进上下文造成Token重复增长。如果工具之间没有依赖关系一定要设计成并行调用。比如同时查询天气、日历、航班信息这三个调用互相独立完全可以在同一个循环里发出然后统一接收结果。并行不仅能降低延迟还能减少上下文里的中间轮次。核心原则能独立就并行能合并就合并能缓存就缓存。不过并行也要有上限不能一次开几十个线程去调外部接口。一般我会给Agent设置一个“最大并发工具数”默认3到5个避免外部服务限流或者下游系统被打爆。运行时还要有超时控制单个工具超过10秒就标记失败并继续其他任务。3. 评估与监控没有观测感的智能体就是一只深不见底的黑箱3.1 先定义“好”再把“好”变成可测指标很多项目把Agent写好以后靠人工点几个页面觉得“效果不错”就上线了。这在技术评审上还凑合一旦用户规模上来问题根本没法定位。评估和监控的前提是先有一套统一指标。我自己常用的Agent效果指标体系如下指标类别具体指标用途任务成功率目标是否完成、最终回答是否满足要求判断Agent有没有能力效率指标完成步数、耗时、总Token数判断Agent有没有绕路稳定指标超时率、失败率、重试次数判断Agent可不可靠成本指标单任务成本、模型调用次数判断Agent值不值得跑质量指标工具调用正确率、上下文命中率判断中间决策是否准确这套指标不是给监控面板看的它必须能拆到每一次运行里。一个任务为什么花了20步拆开看可能是某一步反复调用了同一个工具一个任务为什么Token消耗巨大拆开看可能是某一个中间结果太大了。不能只看最终结果过程指标才是定位问题的关键。3.2 离线评估用“考场”把Agent的底细摸清楚在把Agent投入线上之前最好先建一个离线评估集。不要追求规模大要追求覆盖到真实场景。至少包含三类样本简单指令明确、单步能完成用于检验基础执行能力。复杂任务需要多步推理、工具联动用于检验规划能力。边界场景缺参数、条件冲突、需要拒绝执行用于检验安全能力。评估脚本里需要同时校验最终结果和中间过程。最终结果可以用字符串匹配、语义相似度或LLM裁判来打分中间过程要检查“是否调用了预期工具”“参数是否正确”“是否出现了多余步骤”。这一步比最终结果评估更重要因为很多错误会在中间环节被补救掉但补救本身也意味着资源浪费。离线评估不是做一次就结束。每次修改Prompt、模型或工具逻辑都应该重跑同一套基线集。我个人习惯把评估结果写入每次提交的备注里确保“效果变好”是有数据支撑的而不是“感觉变好”。3.3 线上监控每次Agent动作都要能回放监控的第一原则所有关键信息都要落日志。不要只记录最终答案要记录每一个步骤的输入、输出、模型名称、Token用量、耗时、工具名、参数、异常信息。举个例子一次运行的日志可以这样组织{ trace_id: a1b2c3, session_id: user-123-session-456, step: 2, model: large-model-v3, input_tokens: 4521, output_tokens: 126, cost_usd: 0.012, latency_ms: 834, tool_name: search_documents, tool_arguments: {q: site architecture}, error: null }每行日志都必须带上trace_id和session_id。这样一旦线上出现高成本任务或异常回答可以直接把整条链路拉出来复盘而不是对着一个错误信息猜。监控指标上至少要有四块面板成本、延迟、错误率、Token消耗分布。成本面板要能按用户、按模型、按工具下钻延迟面板要能按模型和工具维度分析错误率面板要重点盯“同一工具连续失败”和“Agent进入死循环”Token分布面板要看上下文重复率和高消耗单步。3.4 用“死循环检测”保护运行时智能体最常见的线上事故就是陷入某个回路反复执行。比如Agent发现查询结果不够调用搜索搜索返回更多结果又把结果全部塞进上下文继续搜索……这种循环不消耗步骤预算吗不一定因为很多死循环里的每一步都算步骤预算但步骤预算往往设置得很大。我建议至少做三件事设置最大步骤限制默认不超过10到15步。设置“同一工具重复调用检测”同一工具连续调用超过3次且参数相似立即终止。设置“状态无变化检测”如果前后两轮的工具结果和模型输出没有实质差异就说明在空转。这些检测优先级很高比模型本身是否聪明更重要。因为模型偶尔会犯糊涂但系统不能跟着一起糊涂。4. 从资源感知到运营的闭环一个可以直接抄作业的最小样板4.1 给Agent循环加装“仪表盘限速器”把资源感知、推理优化、评估监控串起来的方式不是去改每一个Prompt而是在Agent运行循环外加一层统一运行时。这层运行时负责预检、预算判断、模型路由、结构化校验、日志埋点、循环检测。一个最小实现可以这样写def run_agent_with_guard(agent, user_input, config): budget AgentBudget( max_stepsconfig[max_steps], max_costconfig[max_cost], max_tokensconfig[max_tokens] ) session_log [] context initialize_context(user_input) while budget.can_continue(): # 预检先用规则/小模型判断可以直接回复还是需要工具 preflight_result preflight_check(context) if preflight_result.should_stop: return preflight_result.answer, session_log # 模型路由根据任务复杂度选择不同模型 selected_model route_to_model(context, budget) # 推理预算动态设置max_tokens max_tokens calculate_dynamic_max_tokens(context, selected_model) # 调用模型 response, usage selected_model.invoke( context, max_tokensmax_tokens, output_schemapreflight_result.expected_schema ) # 记录用量更新预算 budget.register_usage(usage, estimate_cost(usage, selected_model)) # 校验输出 if not validate_step(response): handle_fallback(response, context) continue # 死循环检测 if is_repeat_without_change(session_log, response): return 检测到重复执行已自动终止。, session_log # 记录日志 session_log.append({ step: budget.current_steps, model: selected_model.name, token_usage: usage, cost: budget.total_cost, response: response, }) # 更新上下文可能裁剪、压缩 context update_context_under_budget(context, response, budget) return handle_budget_exceeded(context), session_log这里每一步都有对应函数每个函数都不复杂组合起来就能覆盖绝大多数场景。不需要一开始就上一套复杂框架先把这条循环跑通再逐步扩展。4.2 上线前一定要避开的五个坑第一坑为了省Token把系统提示词删得只剩下关键词。结果模型输出质量肉眼可见下降靠重试找回效果成本反而更高。提示词压缩可以但不能把约束和示例全部删光。第二坑只设max_steps不检查步骤内容。步骤上限能挡死循环但挡不住重复劳动。就算只跑6步可能6步都在调同一个工具所以必须有重复调用检测。第三坑评估只看最终回答不看中间规划。这样Agent会变成“结果对了但路全走错”的选手。一旦环境变化或工具参数变化正确率会立刻崩塌。第四坑日志里什么都有但没有关联ID。离线排查时根本没有办法把一次用户会话的过程串起来只能靠时间戳碰运气。建议从第一天起就强制设计trace_id和session_id。第五坑刚开始做模型路由就追求“所有任务都用小模型”最后小模型反复无法处理任务大模型又被降级整体体验和成本双输。路由要先跑日志分析清楚哪些任务高频、哪些任务廉价再定策略。4.3 迭代节奏先跑通再省钱再上监控如果你现在手头已经有一个Agent建议按这个顺序改造先把运行日志补齐能回放每一步再跑一周线上数据找出成本最高的20%任务针对这些任务做预算限制和模型路由然后离线评估集跟上最后把监控面板和预警接好。不要一上来就同时做所有优化。我见过不少团队第一天就把Prompt压缩、动态模型路由、日志埋点全部铺开结果反而无法判断是哪个改动带来的效果变化。一步一步来每一步都有对照组比一次性改造可维护得多。回到开头那句话智能体不是“在思考”而是在“消费”。每一次推理消耗Token每一次工具调用消耗时间和成本每一次错误重试消耗预算。做资源感知优化、推理控制、评估监控不是为了显得工程严谨而是让Agent作为产品能长期立得住。这套东西越早落地后期返工就越少。