DeepSeek Harness 5个官方开关,把Token消耗降75%
发布时间:2026/10/8 4:09:19 锦皓数字建站

上个星期我差点被自己的懒散坑了一笔。把一个 DeepSeek Harness 自动重构任务丢在后台想着“让 agent 自己跑会儿不就完了”转头就去开会了。两小时回来一看 Dashboard 上的 token 用量整个人都不好了——单次任务烧掉 860 万 token。DeepSeek 的单价再厚道也经不住 agent 在循环里反复读文件、反复输出推理链账单照样能把你打醒。后来我把 DeepSeek 官方 API 文档和 Harness 的配置项从头到尾捋了一遍把能控 token 消耗的开关逐个实测才总算把成本压了下来。这篇就把其中最管用的 5 个官方开关说清楚哪些是 DeepSeek API 层的参数哪些是 Harness 配置文件里的开关各自的原理、配置写法、实测效果和副作用我都写出来了。如果你正在用 Harness 这类 agent 工具跑自动化编码、批量文档处理、定时巡检或者只是想把 DeepSeek API 的调用成本整个控住这 5 个开关可以直接抄作业。按我的实测同一批任务跑下来token 账单能压到原来的四分之一甚至更低。下面先从最容易被忽略的问题讲起钱到底是从哪个环节烧掉的。1. 先把账查明白一条 Harness 任务的 Token 都去了哪1.1 普通 API 调用和 agent 任务不是同一个量级如果你只调过普通 API对 token 的感觉大概率是一问一答几千 token。但 Harness 这类 agent 框架的工作方式是“多轮循环”模型读任务 → 决定调哪个工具 → 工具返回结果 → 模型再读结果 → 再调下一个工具。每一轮都是一次完整的模型请求而每次请求携带的不是这一轮的增量而是从 system prompt 开始的整个会话快照。这就造成一个很多人没意识到的事实随着任务推进单次请求的输入 token 会一路涨直到撞上上下文窗口上限。第 1 轮可能只要 8K token跑到第 30 轮时同样的任务单次请求可能已经涨到 50K 甚至更多。而且这些输入 token 是按输入单价计费的不是免费赠送。1.2 Harness 每一轮到底往请求里塞了什么我手头这个版本的 DeepSeek Harness单次请求由四块组成system prompt包含行为约束和 skill 触发规则。如果你挂了 15 个 skill每个 skill 的说明按 200-500 token 算这部分就要 5000 到 9000 token。工具 schemafile_read、bash、file_edit这类工具的 JSON Schema 定义。一个工具几百 token挂四五个工具又是两三千 token。会话历史前面所有轮次的 user/assistant 消息、工具调用与工具结果原样保留。最新输入当前这一步的指令和观察结果。问题最严重的是第三块。很多 harness 对工具输出不做截断一个file_read把整个 3000 行源文件读回来这些内容就作为一条工具结果消息塞进历史。后面每一轮这 3000 行都要重新发送一次。你跑了 20 轮这 3000 行就被计费了 20 遍而且每次都是全量重发。这块才是 token 消耗的真正大头不是你以为的“模型思考”。1.3 用 usage 字段做一次“查账”不要只看 total_tokens那会把问题糊住。DeepSeek API 是 OpenAI 兼容格式非流式响应里直接能拿到拆解数字。我习惯写个最小的脚本去查from openai import OpenAI client OpenAI( api_keysk-你的-key, base_urlhttps://api.deepseek.com/v1 ) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 列出当前目录的 TODO 注释分布}], streamFalse ) print(prompt tokens:, resp.usage.prompt_tokens) print(completion tokens:, resp.usage.completion_tokens) print(cache hit tokens:, resp.usage.prompt_cache_hit_tokens) print(cache miss tokens:, resp.usage.prompt_cache_miss_tokens) print(total tokens:, resp.usage.total_tokens)注意最后两个字段这是后面第三个开关能不能生效的关键证据。我第一次跑演示任务时看到的是一串非常难看的数字指标数值prompt_tokens8126completion_tokens2894total_tokens11020prompt_cache_hit_tokens0prompt_cache_miss_tokens8126prompt 占大头、缓存完全没有命中这就是“烧 token”的原始画像。后面五个开关逐个来拧。2. 开关一模型降级把 deepseek-reasoner 换成 deepseek-chat2.1 两个官方模型的计费逻辑差异DeepSeek 官方目前主要提供两个模型deepseek-chat和deepseek-reasoner。很多人在 Harness 配置里图省事直接填了 reasoner觉得“推理模型能力强”结果账单一路走高。这两个模型的 API 单价差异其实不是重点真正的重点是输出量。reasoner 会在给出最终答案之前先产出一大段内部思维链CoT这段内容会作为输出 token 计费跟你最终看到的答案一样贵。同一道“分析项目里三处内存泄漏并给出修复方案”的题我实测过模型completion tokens相对倍数deepseek-chat21481xdeepseek-reasoner15,732约 7.3x看到这个倍数你就明白为什么 agent 任务要慎用 reasoner。普通问答差几倍还能忍Harness 里一个任务要跑几十轮每一轮都要先生成一大段“思考过程”这个差距会被滚成雪球。2.2 为什么 reasoner 的思维链“烧”得最隐蔽reasoner 的 CoT 对用户是隐形的你只看到“思考中...”然后 final answer 那一层才会出结果。但计费不看显隐性只看实际输出的字符量。DeepSeek 文档里写得很清楚reasoning_content需要单独取出但它产生的 token 已经记在账单上了。我判断要不要用 reasoner标准很简单任务里有没有“需要模型自己推演多种可能分支”的成分。如果只是“读文件、找 TODO、按模板改代码”这种执行型任务reasoner 的优势完全发挥不出来反而白白多付好几倍的输出 token。2.3 Harness 里怎么改模型以我手头这个版本的配置为例字段名在不同版本可能不同但基本逻辑是一样的provider: base_url: https://api.deepseek.com/v1 default_model: deepseek-chat reasoner_model: deepseek-reasoner切完之后建议立刻跑一个最小任务验证。这里有个很容易踩的坑有人把控制台上的“模型展示名”直接填进配置比如填“DeepSeek-V3”而不是 API 模型 iddeepseek-chatharness 会直接报 model not found。API 请求里认的是模型 id不是展示名。2.4 什么场景值得继续用 reasoner我的经验是三个场景值得切回去一是代码架构层面的多模块影响面分析二是涉及竞态条件、并发安全的推理三是需要从模糊需求里推断出明确方案的场景。这些任务一次多花几万 token 是值得的因为用 chat 可能要反复试十几轮最后还不一定对。降级不是死规则是把模型能力对齐到任务复杂度。3. 开关二历史消息裁剪与自动压缩堵住上下文膨胀的漏点3.1 会话历史为什么是最大的漏上一节提到工具返回的完整文件内容会一直躺在历史里。Harness 默认不会替你清理它假设“上下文越多模型越好干活”。但对 token 账单来说这恰恰是最凶的一头怪兽。我跑过一个改 8 个文件的批处理任务。第 30 轮时单次请求的输入 token 已经涨到 52,000其中大半是早期读过的文件内容。任务后半段模型每走一步都在为前面已经读过的 5000 行代码重复计费。这种情况就像水桶底部漏了个洞你一边往里加水水一边在流走。3.2 开两个配置项trim 和 compact正常的 harness 都有历史管理开关我用的版本这两个参数最关键token_policy: trim_history: true compact_threshold: 32768 max_context_tokens: 49152trim_history: true表示允许裁剪历史。compact_threshold表示当上下文逼近这个值时harness 会把较早的历史消息压缩成一段摘要原始消息移出上下文。max_context_tokens是硬顶超过这个值直接丢弃最早的消息。3.3 阈值怎么定才不被“二次收割”压缩不是免费的生成摘要本身也要消耗一次 completion tokens。所以阈值不能拍脑袋往低了设。我的经验公式是先查当前模型实际的上下文长度。DeepSeek 不同模型、不同版本的上下文支持有差异配置前以 API 文档为准。把max_context_tokens设为模型上下文上限的 60% 左右留出工具返回和本次输出的空间。把compact_threshold设为max_context_tokens的 70% 左右。举个例子如果模型上下文上限是 64K那max_context_tokens设 40K 前后compact_threshold设 28K-30K。千万别把阈值设成 4K 这种极端值否则任务刚聊几句就压缩一次压缩本身的消耗比省下来的还多妥妥的“二次收割”。3.4 实测效果和副作用同一批任务不开压缩时第 30 轮单次请求输入 52K开了压缩和裁剪后在 26K 附近稳定住了总 token 消耗降了大约 40%。副作用也得说清楚压缩摘要会丢失早期文件的部分细节。如果后续某一步需要精确引用第 3 轮读过的某个文件的方法名模型可能只记得“大概有个函数”于是又得重新读文件。我的对策是把关键文件路径单独固定在“常驻上下文”里或者在压缩前给关键内容打标记让压缩逻辑尽量保留这些片段。4. 开关三让请求稳定命中官方 Context Caching输入价格差一个量级4.1 DeepSeek 官方缓存的计费机制DeepSeek 官方有上下文硬盘缓存Context Caching机制。同一个账号在同一段时间内如果多次请求的前缀完全一致后续请求里命中缓存的那部分输入 token会按明显低于未命中的价格计费。这个差价量级很大我实测下来命中后的输入成本大约只有完全未命中的十分之一左右。这不是什么偏门玩法是官方计费规则。你需要做的只是让你的请求前缀尽可能稳定。很多人的成本高企其实就是白花花的输入 token 全都走了贵价通道。4.2 命中缓存的第一性条件前缀一致缓存命中的核心是“前缀哈希一致”。通俗说就是连续请求的 messages 数组开头几段要一模一样你把 system prompt 最先发出去的部分叫做前缀它一旦含有不稳定内容命中就凉了。最容易破坏前缀稳定性的东西有三个一是把当前时间戳拼在 system prompt 尾部二是在会话开始就把随机 request id 塞进第一条消息三是 skill 加载顺序每次都不一样。这三个坑我都踩过尤其是一看似无害实际对缓存命中率的杀伤力最大。4.3 在 Harness 里固定前缀的做法我把 harness 的 prompt 模板改成了固定的拼接顺序第一层system prompt内容完全固定。第二层工具 schema按工具名排序后固定拼接顺序永远一致。第三层历史对话按时间追加。第四层最新的一条 user 消息所有动态内容时间、路径、随机数都放这里。关键规则就一句动态信息永远不要在 system prompt 里出现。时间、路径、随机数全部扔到最后一条消息里。我改完这个拼接顺序后同一批任务的缓存命中率从不到 20% 提升到 83%效果非常直观。token_policy: cache_priority: true stable_prompt_prefix: true dynamic_content_placement: tail4.4 怎么确认真的命中了缓存继续看 usage 字段。命中率高的时候应该是这种样子指标数值prompt_cache_hit_tokens42,310prompt_cache_miss_tokens8,120缓存命中率83.9%如果这个数字长期是 0说明你的请求前缀稳定性有问题。按上面的拼接顺序检查 prompt 模板重点看有没有时间戳、随机数被拼到开头。还有几个细节缓存不跨账号也不跨 API key缓存有效期有限长时间不发请求前缀会被淘汰多个并行任务如果共享同一套前缀反而能一起把命中率养高。这些官方文档里都写了只是绝大多数人没注意。5. 开关四工具调用装上半径限制器堵住 agent 空转的死循环5.1 最贵的不是思考是“空转”做过 agent 任务的人一定见过这个场景模型想读一个文件路径写错了工具返回报错它不修正路径反而换一个更离谱的路径再试一次。或者调一个 bash 命令失败它开始翻来覆去尝试各种 flag每次尝试都是一整轮完整请求而这一整轮请求的输入 token 是整个历史长度。这种“空转”没有任何有效产出但每一轮都在按全量 prompt 计费。工具用得越多工具返回的报错信息越长空转的代价就越离谱。我见过最夸张的一次一个重试死循环贡献了整任务的 60% 以上 token 消耗。5.2 三个配置项直接封死我用的版本里三个开关全部打开之后效果立竿见影tool_policy: max_tool_calls_per_round: 8 max_consecutive_tool_calls: 12 auto_retry: false allowed_tools: - bash - file_read - file_edit - search working_directory: ./repo/srcmax_tool_calls_per_round: 8单轮决策里最多允许模型调 8 次工具到顶后强制交回控制权。max_consecutive_tool_calls: 12连续工具调用的总上限防止模型一股脑地疯狂调用。auto_retry: false关闭失败自动重试。消息失败后不再原样重发模型会直接进入决策层。5.3 白名单和工作目录也是省钱利器allowed_tools限制模型能用的工具类型。一个前端改版任务根本不需要让它访问系统全局目录。working_directory: ./repo/src把活动半径限制在当前项目内既省 token 又减少误操作的风险。还有一个容易被忽略的点很多 harness 的file_read工具支持只读文件头部若干字节比如read_head_bytes: 4000。能用 grep / glob 拿到的信息就别让模型读整个文件。一次少读几十行几十轮下来就是几万 token。能用search工具精确定位关键行就不要用file_read全量拉取。5.4 限制前后的实测对比同一个重构任务我跑了两次状态工具调用次数请求轮次总 token限制前4731约 320 万限制后139约 140 万总 token 降了约 55%。这里有个很重要的经验限制工具不会让模型变笨反而会让它更专注手头的活。前提是allowed_tools必须覆盖任务真实需要的工具否则模型会一直报 unavailable tool反而制造新的空转这一步要按任务类型反复调整。6. 开关五锁死输出长度和采样参数从生成侧逼模型少说废话6.1 max_tokens 和 temperature 为什么会影响账单max_tokens是硬顶直接限制每次响应的输出 token 上限。有人把它设成 32K觉得“反正模型不一定输出那么多”。但一旦模型进入某种重复输出状态这个上限会变成最贵的保险丝——它允许模型一次性生成几万 token 的废话再停下来账单直接炸。temperature不直接决定 token 数但它决定“试错倾向”。温度偏高时模型更发散容易在一个问题上绕来绕去多走好几轮工具调用间接拉高 total tokens。DeepSeek API 的temperature默认值是 1.0对 agent 任务来说偏高我跑下来 0.2 附近最舒服。6.2 我用的生成参数generation: max_tokens: 4096 temperature: 0.2 top_p: 0.9如果任务是“提取某个函数的空指针风险”这种短答案场景max_tokens可以直接压到 1024。设置上限不是限制模型思考是防止最坏情况下的天量输出。真正的思考应该在工具调用和代码分析上而不是在生成废话上。6.3 关掉 verbose 输出删掉“详细一点”的 prompt很多 harness 有 verbose/debug 模式。日志打印本身不烧 token但不少实现会把调试日志也塞进工具结果作为 context 传给下一轮这个必须关。你以为在“看日志”其实是把日志当输入又喂了一遍模型。同样的坑在 system prompt 里也有。如果你写了“回答尽量详细注明每一步理由”agent 会非常忠实地执行——每次工具调用间隙都给你输出上千字的计划说明这是纯浪费。agent 输出要的是“结论 关键依据”不是论文。6.4 五个开关的乘法效应这几个开关不是独立省钱的。模型降级把单轮输出成本砍下来上下文压缩和缓存命中把输入成本压到最低工具限制减少了请求轮次输出锁止避免了异常长尾。它们合起来是乘法不是加法。我拿同一批任务跑了两遍对照状态总 token相对账单基线reasoner 完整历史 无缓存 无工具限制 verbose约 860 万100%全开chat 压缩 缓存 工具限制 输出锁止约 210 万约 25% 左右注意全开状态下总 token 降了 75% 不说命中的输入 token 还走打折价所以真实账单降幅比 token 数字降幅更明显。这也是为什么我一直强调把缓存命中单独算一笔账。7. 一份能直接抄的配置与常见问题排查7.1 完整配置清单把上面所有配置合在一起长这样。字段名以你的 harness 版本为准核心逻辑一致provider: base_url: https://api.deepseek.com/v1 default_model: deepseek-chat reasoner_model: deepseek-reasoner token_policy: max_context_tokens: 49152 trim_history: true compact_threshold: 32768 cache_priority: true stable_prompt_prefix: true dynamic_content_placement: tail tool_policy: max_tool_calls_per_round: 8 max_consecutive_tool_calls: 12 auto_retry: false allowed_tools: - bash - file_read - file_edit - search working_directory: ./repo/src read_head_bytes: 4000 generation: max_tokens: 4096 temperature: 0.2 top_p: 0.97.2 几个容易踩的误区很多人看完前面的开关回去一配发现还是没省多少麻烦基本都出在这几个误解上误解一以为官方缓存是 API 自动全开的。其实需要请求前缀足够稳定才会命中prompt 模板里随便加个时间戳就前功尽弃。误解二模型支持 64K就把max_context_tokens设成 64K。这等于告诉 agent 可以无限堆历史上下文膨胀问题只会更严重。误解三max_tokens越大越好。它是上限不是目标长度设成超大值后遇到重复输出故障时账单会很酸爽。误解四把temperature调成 0 以为最省。实际上 0 会让模型更容易卡在同一个错误决策上工具重试反而变多。0.2 附近是我跑 agent 任务的甜点区。误解五只看 total_tokens不看 cache hit 和 cache miss。没有拆解数据你根本不知道下一步该调哪个开关。7.3 五个开关都开了但账单没降这样查按优先级看三个数症状可能原因检查点prompt_cache_miss_tokens 长期占比高请求前缀不稳定system prompt 里有没有时间戳/随机数completion_tokens 占比异常高模型没降级或输出上限没锁确认配置里的 default_model 生效请求轮次很多工具限制没生效检查 auto_retry 是否还开着allowed_tools 是否过宽如果 usage 数据里根本看不到prompt_cache_hit_tokens字段先确认你的 SDK 或请求方式是否支持这个字段返回有些分支版本的客户端会把未知字段吞掉不是没命中是没显示。7.4 顺手提醒一句别把登录报错和 token 计费混淆有些人在接入 Harness 时遇到类似 “login fail / token exchange failed: token endpoint returned status 403 forbidden: country” 的报错。这种是账号登录认证层面的事情通常和服务商对请求来源的限制有关跟你本文调的 token 计费完全是两码事。遇到这种报错要先查账号状态和请求环境不要去怀疑刚才的压缩配置或缓存配置。两类问题的排查路径完全不同混在一起只会浪费时间。我自己把五个开关用到现在大概一个月了最值的一件事就是把默认模型从 reasoner 换成了 chat以及让缓存命中率稳定在 70% 以上。工具限制建议在你对任务流程足够熟悉之后再收紧刚上手就锁死工具反而会因为缺工具被模型反复报错。核心就一句话先开开关再盯着 usage 的几个数字跑真实任务账单自然会教你把参数调到合适的位置。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。