1. 从一次 Agent 项目账单失控说起去年底我接手了一个内部知识助手的项目核心逻辑不复杂用户提问Agent 调用几个工具去检索文档、查数据库、最后汇总成答案。Demo 阶段跑得挺顺直到上线第二周财务同事甩过来一张账单截图我才意识到问题的严重性——单次对话的平均 token 消耗比我预估的高出将近一倍多轮工具调用叠加起来成本曲线几乎是垂直往上走的。这不是我一个人的困境。做 Agent 应用的人大概都有类似体会模型能力越来越强但让模型自己决定调什么工具、调几次、怎么把结果串起来这套编排逻辑才是真正烧钱的地方。每一次工具调用都要把上下文重新喂一遍历史消息越滚越长token 就像开了闸的水。所以当我看到 AWS Strands Agents 团队发布开源 Agent 框架Strands harness并且宣称在 6 项基准测试下 token 成本平均降低 28% 时第一反应不是又一个框架而是这个数字是怎么来的。28% 听起来不算惊天动地但在 Agent 这种成本敏感场景里接近三成的降幅意味着什么意味着原本一个月一万块的推理开销能省下近三千意味着很多因为成本卡住没法上线的功能突然变得可行。这篇文章我想聊的不是Strands harness 有多好而是把它拆开来看它到底在哪个环节省下了 token这套思路能不能迁移到你自己正在用的框架上以及如果你打算上手有哪些坑是文档里不会写的。适合正在做 Agent 编排、被 token 账单困扰、或者单纯想理解Agent 框架的成本优化到底优化在哪的开发者。哪怕你最后不用这个框架里面的思路也值得抄。2. Strands harness 到底在解决 Agent 的哪个成本黑洞2.1 Agent 成本失控的三个真实来源要理解 28% 这个数字得先搞清楚 Agent 的 token 到底花在哪。我把自己的项目做过一次拆解成本大致分三块。第一块是系统提示词的重复注入。每一轮对话、每一次工具调用系统提示角色设定、工具描述、输出格式要求都要重新作为上下文的一部分发给模型。一个稍微复杂点的 Agent系统提示动辄两三千 token如果一轮任务里发生五次工具调用这部分就被重复计费五次。第二块是历史消息的无差别累积。大多数框架的默认行为是把完整对话历史一直带着走包括那些已经用完就没用的工具返回结果。比如查数据库返回了一大段 JSONAgent 提取了其中两个字段但整段 JSON 还留在上下文里后续每一轮都在为它付费。第三块是工具调用的试错开销。模型不确定该调哪个工具时可能会先调一个、发现不对、再调另一个。这种试错在复杂任务里很常见而每次试错都是一次完整的模型往返。Strands harness 的优化本质上是在这三块上做文章。它不是一个更聪明的模型而是一套编排层的成本控制机制——同样的模型、同样的任务通过改变上下文怎么组织、工具怎么暴露、历史怎么裁剪把冗余的 token 挤出去。2.2 为什么编排层优化比换更便宜的模型更值得做很多人第一反应是降本就用更小、更便宜的模型。我试过效果往往不理想。Agent 任务对模型的指令遵循能力、工具选择准确性要求很高换成小模型后工具调错率上升试错次数增加最后总成本未必降下来体验还变差了。编排层优化不一样它不动模型本身只动喂给模型什么。这部分是纯赚的——模型能力不变但每次调用携带的信息更精炼。Strands harness 走的就是这条路。它把优化做在框架内部开发者不需要手动去裁剪上下文框架自己会判断哪些信息该留、哪些该丢。这也是我觉得它值得关注的原因它把成本优化从开发者要操心的杂活变成了框架的默认行为。你不需要成为 prompt 工程专家也能享受到优化红利。2.3 28% 这个数字的参照系需要说清楚的是28% 是6 项基准下平均降低不是所有场景都能达到。基准测试通常是标准化的任务集任务结构相对规整优化空间容易被放大。落到你自己的业务上降幅可能更高也可能更低取决于你的 Agent 有多啰嗦。我的经验是如果你的 Agent 单轮任务里工具调用超过 3 次或者系统提示超过 1500 token那么优化空间大概率在 20% 以上。反过来如果只是简单的单轮问答框架带来的差异微乎其微。所以别被数字冲昏头先评估自己的场景。3. 拆开看Strands harness 省 token 的几个关键机制3.1 上下文的分层管理什么该常驻什么该临时Strands harness 在上下文组织上做了一个我认为很关键的设计把上下文分成不同生命周期层级。系统提示、工具定义这类每轮都要用的内容放在常驻层工具返回结果、中间推理这类用完即弃的内容放在临时层。这个区分听起来简单但实现起来需要框架对什么信息在什么阶段有用有判断。举个具体例子Agent 调用搜索工具拿到十条结果模型从中挑了两条作为依据。传统做法是把十条结果全留在历史里Strands 的思路是让框架识别出这两条被引用了其余八条可以压缩或丢弃。我实测过一个类似的手动优化在一个文档问答 Agent 里把工具返回的原始 JSON 只保留被引用的字段其余截断单轮 token 消耗从 4200 降到了 2900 左右降幅超过 30%。Strands harness 把这套逻辑自动化了省去了我写裁剪代码的功夫。注意上下文裁剪有个前提——不能裁掉模型后续可能还需要的信息。Strands 的做法是保留引用关系而不是简单按时间截断。这一点比很多粗暴的只留最近 N 轮方案要靠谱。3.2 工具描述的按需暴露Agent 框架通常会把所有可用工具的描述一次性塞进系统提示。工具一多这部分就膨胀得厉害。我见过一个项目注册了二十多个工具光工具描述就占了 4000 多 token而单次任务实际只会用到其中两三个。Strands harness 支持工具的分组和按需暴露。框架可以根据当前任务意图只把相关工具的描述放进上下文。这背后的逻辑是模型选择工具时候选集越小决策越准试错越少同时描述本身的 token 也省了。这个机制对工具数量多的项目收益特别明显。如果你只有三五个工具效果有限但如果你有十几个甚至几十个工具这一块的优化可能是降本的大头。3.3 工具调用结果的压缩与摘要工具返回的结果往往是原始数据信息密度低。比如一个查询接口返回了完整的记录但 Agent 只需要其中几个字段。Strands harness 在工具返回结果进入上下文之前会做一层处理——可能是结构化提取也可能是摘要压缩。这里有个取舍压缩得太狠模型可能丢失关键信息导致答错压缩得太松省不下 token。框架的默认策略是保守的优先保证信息完整。如果你对成本更敏感可以调紧压缩策略但要配合充分的测试。我自己的做法是对确定性强的工具比如固定格式的数据库查询用激进压缩对开放性工具比如网页搜索用保守策略。因为前者的输出结构可预测压缩风险低后者内容不可控压过头容易出问题。3.4 多轮对话中的历史折叠长对话是 token 消耗的重灾区。Strands harness 对历史消息做了折叠处理——把早期的、已经完成使命的对话轮次压缩成摘要只保留关键结论。这跟简单的滑动窗口不一样。滑动窗口是直接丢弃旧消息可能导致上下文断裂折叠是保留语义把我们讨论过 A、B、C最终决定用 B压缩成一句话。模型看到的是浓缩后的历史既省 token 又不丢逻辑。实测下来这个机制在超过 10 轮的长对话里效果最明显。我有个客服场景的 Agent平均对话轮次在 15 轮左右开启历史折叠后后半程每轮的 token 消耗比前半程还低整体降幅接近 25%。4. 上手 Strands harness环境准备与第一个可跑通的 Agent4.1 安装与依赖别急着 pip installStrands harness 是 Python 生态的框架安装本身不复杂但有几个前置条件容易被忽略。首先是 Python 版本。框架依赖一些较新的语言特性建议用 3.10 及以上。如果你机器上还是 3.8先升级否则会在安装依赖时遇到各种兼容报错。我踩过一次坑本地 3.9 环境装到一半失败排查半天才发现是某个依赖要求 3.10。其次是虚拟环境。强烈建议用 venv 或 conda 隔离别在全局环境里装。Agent 框架的依赖树通常比较深跟其他项目混在一起容易冲突。python -m venv strands-env source strands-env/bin/activate # Windows 用 strands-env\Scripts\activate pip install strands-harness安装完成后先跑一个最小验证确认框架能正常导入import strands_harness print(strands_harness.__version__)如果这一步报错大概率是依赖没装全或者版本冲突别往下走先解决环境问题。4.2 配置模型接入Bedrock 还是其他Strands harness 原生对接 AWS 的模型服务但通过适配层也能接其他模型提供方。如果你在 AWS 生态里直接用 Bedrock 最省事如果不在需要额外配置适配器。配置的核心是凭证管理。别把密钥硬编码在代码里用环境变量或者配置文件。我见过太多项目把 key 写在源码里然后不小心提交到仓库的案例。import os os.environ[AWS_REGION] us-east-1 # 凭证通过标准的环境变量或 IAM 角色提供不要硬编码提示如果你用的是临时凭证STS注意刷新机制。Agent 任务可能跑很久凭证过期会导致中途调用失败。框架一般有自动刷新但要确认配置正确。4.3 定义第一个工具并跑通完整链路Agent 的价值在于调用工具所以第一个能跑通的例子一定要包含工具调用。下面是一个最简单的示例定义一个查询天气的工具让 Agent 根据用户问题决定是否调用。from strands_harness import Agent, tool tool def get_weather(city: str) - str: 查询指定城市的天气 # 实际项目里这里会调用真实接口 return f{city}今天晴气温 22 度 agent Agent( tools[get_weather], system_prompt你是一个助手需要天气信息时调用工具查询。 ) response agent.run(北京今天天气怎么样) print(response)跑通这个例子后你会看到框架自动处理了模型决定调用工具 → 执行工具 → 把结果喂回模型 → 生成最终回答的完整链路。重点观察一下框架在日志里输出的 token 消耗这是你后续优化的基线。4.4 打开成本监控不看数字等于白优化框架一般会提供 token 消耗的统计接口。上手第一件事就是把它打开记录基线数据。没有基线你根本不知道优化有没有生效。我习惯在每次run之后打印消耗response agent.run(北京今天天气怎么样) print(f本次消耗: {agent.last_usage})把不同任务类型的消耗记录下来形成自己的成本画像。哪些任务贵、贵在哪一目了然。这一步花十分钟能帮你后面省下大量盲目调优的时间。5. 把 28% 的降幅复现到自己的项目里5.1 先做成本审计别盲目套框架框架再好也得知道自己的钱花在哪。我建议在接入 Strands harness 之前先给自己的现有 Agent 做一次成本审计。方法很简单把一次典型任务的完整上下文打印出来逐段标注 token 数看看哪部分占比最大。我做过的一次审计结果是这样的系统提示 1800 token工具描述 2200 token历史消息 3500 token工具返回结果 4000 token模型输出 800 token。一眼就能看出工具返回结果和历史消息是大头优化应该往这两个方向使劲。审计完你会发现不同项目的成本结构差异巨大。有的项目系统提示是重灾区有的是工具返回。Strands harness 的各个机制针对不同环节你得知道自己该重点用哪个。5.2 工具返回结果的裁剪策略这是最容易见效的优化点。核心思路是工具返回的原始数据不要直接进上下文先过一层处理。具体做法分两种。对于结构化数据JSON、表格做字段提取只保留模型需要的字段。对于非结构化数据长文本、网页内容做摘要或截断。tool def search_docs(query: str) - str: 搜索文档 raw_results do_search(query) # 返回完整结果 # 只保留标题和摘要丢弃全文 trimmed [ {title: r[title], snippet: r[snippet][:200]} for r in raw_results[:5] ] return str(trimmed)这个改动看起来简单但在我的项目里单这一项就砍掉了近 30% 的 token。关键是在工具层面做裁剪而不是在框架层面这样逻辑清晰也方便针对不同工具定制策略。5.3 系统提示的精简删掉那些以防万一的话系统提示里最容易堆积冗余。我见过很多提示词写得像说明书把各种边界情况都列一遍结果大部分内容在 99% 的任务里都用不上。精简的原则是只保留模型必须知道的信息把以防万一的内容移到工具描述或按需注入。比如输出格式要求如果只在特定任务里需要就别放在全局系统提示里。我把自己项目的系统提示从 1800 token 压到 700 token方法是删掉重复的强调、合并相似的规则、把示例从三个减到一个。压完之后任务成功率没有下降因为剩下的都是真正有用的信息。5.4 用基准测试验证别凭感觉优化做完一定要用数据验证。Strands harness 提到的 6 项基准思路值得借鉴准备一组有代表性的任务固定下来每次优化后跑一遍对比 token 消耗和任务成功率。我自己的基准集包含 20 个任务覆盖简单问答、多工具调用、长对话、错误处理等场景。每次改动后跑一遍记录两个数字平均 token 消耗、任务成功率。只有两个数字都达标成本降、成功率不降的优化才算成功。注意别只看 token 降幅。如果为了省 token 导致任务失败率上升用户重试反而更费钱。成本和质量要一起看。6. 实测中遇到的坑与应对6.1 上下文裁剪裁过头模型开始失忆这是最常见的坑。裁剪策略太激进模型在后续轮次里找不到之前的关键信息开始重复提问或者答非所问。我的应对方法是设置保护字段在裁剪逻辑里明确标注哪些信息绝对不能丢比如用户的原始需求、已经确认的关键参数。这些字段无论上下文多长都保留其余部分才做压缩。另一个技巧是保留引用链。如果某个工具结果被模型引用过就标记为已使用后续裁剪时优先保留。Strands harness 内部有类似机制但如果你自己写裁剪逻辑这一点要手动实现。6.2 工具按需暴露导致模型找不到工具按需暴露工具能省 token但如果暴露逻辑判断错了模型会以为某个工具不存在转而用错误的方式解决问题。我遇到过一次任务需要查数据库但框架判断当前意图是闲聊没把数据库工具暴露出来模型就编了一个答案。这种错误很隐蔽因为模型不会报错它会自信地给出错误结果。解决办法是给暴露逻辑留冗余宁可多暴露一两个相关工具也不要漏掉关键工具。同时加一层校验如果模型输出的答案涉及它没被暴露的工具触发告警。6.3 历史折叠丢失了关键决策依据历史折叠把旧对话压成摘要但摘要可能丢掉为什么这么决定的推理过程。后续如果任务方向变了模型不知道之前的决策依据可能做出矛盾的选择。我的做法是在折叠时保留决策和理由只压缩过程。比如我们比较了方案 A 和 B最终选 A 因为成本更低这句话要完整保留而中间的比较细节可以压掉。6.4 成本监控本身的开销有些框架的监控会记录完整上下文这本身也占存储和计算。如果你的任务量很大监控数据的体量可能很可观。建议只记录关键指标token 数、耗时、成功率不要存完整上下文。需要排查问题时再临时开启详细日志。我吃过这个亏监控数据把数据库撑爆了清理起来很麻烦。7. 这套思路能迁移到其他 Agent 框架吗7.1 成本优化的通用原则Strands harness 的具体实现是它自己的但背后的原则是通用的。我总结成四条第一上下文分层。区分常驻信息和临时信息临时信息用完就清。第二按需加载。工具描述、示例、格式要求能按需注入就别全局常驻。第三结果预处理。工具返回的原始数据先加工再进上下文别让模型看生数据。第四历史压缩。长对话要折叠保留结论和依据压缩过程。这四条不依赖任何特定框架你在 LangChain、AutoGen 或者自研框架里都能实现。区别只是 Strands harness 把它们做成了默认行为而你需要自己写代码。7.2 不同框架下的落地差异在 LangChain 里上下文管理主要靠 Memory 组件和自定义的 prompt 模板。你可以通过自定义 Memory 实现历史折叠通过动态构建 prompt 实现按需加载。在 AutoGen 里多 Agent 协作场景下的上下文共享更复杂需要额外注意哪些消息该广播、哪些该定向发送。成本优化的空间更大但实现也更麻烦。自研框架最灵活但也最费功夫。我的建议是如果你的项目已经在某个框架上跑得不错别为了省 token 就迁移。迁移成本可能比省下的钱还高。把上面四条原则在现有框架里实现效果一样。7.3 什么时候值得引入 Strands harness我的判断标准是如果你的 Agent 项目满足以下任意两条就值得试试——工具数量超过 8 个、单轮任务工具调用超过 3 次、平均对话轮次超过 10 轮、月 token 成本超过四位数。反过来如果只是简单的单轮问答或者工具就两三个引入新框架的收益有限不如把精力放在提示词优化上。8. 关于 Agent 成本控制的一点个人体会做 Agent 这两年我最大的感受是成本控制不是一次性的优化而是持续的习惯。框架能帮你省一部分但真正决定成本的是你的设计决策——工具怎么定义、上下文怎么组织、任务怎么拆解。Strands harness 的 28% 是个不错的起点但它不是终点。我见过优化做得好的团队能把成本压到行业平均的一半以下靠的不是某个框架而是对每一分 token 花在哪的持续关注。最后分享一个我一直在用的小习惯每次上线新功能前先估算它的 token 成本跑一周后对比实际值。估算和实际的差距往往能暴露出你没意识到的浪费点。这个习惯帮我避免了好几次功能上线才发现成本失控的尴尬。Agent 这个领域变化很快框架会不断迭代但用更少的 token 做更多的事这个方向不会变。把成本意识刻进设计里比追任何一个新框架都重要。