
用 DeepSeek Harness 做开发辅助第一个月账单出来的时候我差点以为 API Key 被人盗刷了。聊了几个小时的天改了几十个文件Token 用量却比我预估的高了好几倍。后来我把配置一条一条翻出来看才发现问题不在模型而在 Harness 默认的那套“高能耗”设置。这篇文章不聊宏观概念只讲怎么用 5 个官方开关把 Token 消耗压下来把账单控制在看得懂的范围内。适合正在用 DeepSeek Harness 做编码、写脚本、跑 Agent 工作流的开发者也适合准备把 Harness 部署到团队环境、但又担心 API 成本失控的运维同学。1. 先搞清楚你的 Token 到底烧在哪了1.1 Token 不是字数是颗粒度许多刚开始用 DeepSeek Harness 的朋友都有同一个错觉Token 就是汉字数量。我输入的是一段自然语言模型返回的是中文那 1000 Token 差不多就对应 1000 个字。实际完全不是这样。Token 是模型内部对文本做的切分结果英文一个单词可能被切成 1 到 3 个 Token中文一个汉字大约对应 1 到 2 个 Token代码、符号、空格、缩进、换行全都要消耗。更麻烦的是不同模型的切分规则不完全一样同样一段文字在 DeepSeek 的编码表里和在别的模型里Token 数可能有明显差异。我举一个实际例子一段 200 字的 Python 代码里面混杂了缩进、括号、中文注释可能轻松超过 400 Token。你以为你让模型改的是 200 字的文件实际上背后的计费单位是这个数的两倍还多。理解了这一点你再看账单就不会太惊讶也会明白为什么省 Token 的第一步不是少说话而是搞清楚一次请求到底发出去多少东西。下面这张表可以帮你建立基本感觉文本片段估算 Token说明“hello world”约 2英文单词通常 1 个 Token“你好”约 2中文单字通常 1 到 2 个 Token含缩进的 50 行 Python 代码约 400 以上缩进、符号、注释都计入1.2 Harness 的“输入”远比你想的多为什么同样的对话在网页版和 Harness 里的 Token 消耗不一样因为 Harness 不只是聊天窗口它是一套把 DeepSeek 接进本地命令行、IDE、Agent 工作流的“驱动器”。你让它读文件它会把文件内容塞进上下文你让它调用 Skill它会把 Skill 定义和返回结果塞进上下文你让它访问工具工具的返回 JSON 也会被完整塞进去。云端模型看到的内容是一个巨大的请求包包里面至少有四部分系统提示词固定的一部分通常几千 Token工具定义Harness 注册的所有工具描述可能几千 Token会话历史前面所有轮次的对话以及每次工具调用的输入输出当前指令你真正想让模型做的事情。这四部分加起来才是每次请求的真实输入量。所以你每一次点击发送成本都不只是你最后打的那句话。默认配置下这个输入量很容易突破几万 Token。你在网页版对话时输入就是你刚打的问题在 Harness 里输入是整包物品。这个区别决定了 Harness 的费用天然会比普通聊天高。1.3 消耗占比的观察我调参前统计过我自己的账单某次会话总消耗 72K Token其中历史上下文重复发送占了约 61%系统提示词和工具定义占了约 17%模型输出占了约 15%工具调用返回结果占了约 7%。也就是说真正的“有效输出”只占很小一块大头都在上下文重复发送上。这让我明确了操作方向不是让模型少回答而是让 Harness 少把旧内容一遍遍发上去。为了直观我整理了一张实际记录下来的两种会话形态对比表会话形态输入 Token约输出 Token约总消耗约长会话 30 轮窗口 32K未清理58K8K66K短会话 6 轮窗口 16K及时清理14K5K19K同样完成一个功能的开发后者只花了前者的三分之一。差距主要来自历史上下文的重复发送。所以下面的几个开关大多都在围绕“怎么少发旧内容”做文章。2. 官方开关一、二、三把上下文和输出勒紧2.1 开关一限制上下文窗口context_windowHarness 的默认上下文窗口通常会顶到模型支持的上限因为工具希望你能体验“超长上下文”的便利。但对于大多数编码任务超长上下文其实是一种浪费。窗口越大Harness 能在上下文里塞的内容越多每次请求携带的输入也就越多。你并不会因为窗口大而得到更聪明的回答只会得到更贵的账单。我建议普通编码场景把上下文窗口设在 16K命令行问答场景甚至可以设到 8K。配置项名称一般是 context_window 或 --context-size。以 JSON 配置为例{ context_window: 16384 }需要说明的是限制窗口并不是“只保留最后 16K 的内容”更准确的说法是Harness 会在请求发出前把将要发送的上下文控制在窗口内。超出部分可能被丢弃或被截断。设置窗口的真正价值在于它给整个会话设下了一个明确的成本天花板防止会话因为被喂入大量文件内容而悄悄膨胀到几十 K。尤其当你用 Harness 做代码仓库级别的 Agent 任务时Harness 可能会扫描目录、读取多个文件如果窗口没有限制一次扫描可能就把几百 K 文本全部塞进请求。这里的关键操作习惯是及时清理会话。我见过很多人一整天不关 Harness 窗口让会话累积到几百轮每次回复前光是把历史重新发送一遍就要烧掉几万 Token。我的做法是当一个会话解决完一个完整任务就执行 /clear 或 /compact。/compact 尤其好用它让模型把之前的讨论压成一段摘要用摘要替代完整的原始历史后续请求的输入量能下降一个量级。但注意摘要本身也占 Token所以不要每两句话就压缩一次通常一个长任务压缩一到两次就够了。2.2 开关二锁死单次回复的最大 Tokenmax_tokens第二个开关是 max_tokens限制模型单次输出的上限。这可能是最直观、也最容易被忽略的开关。默认值很大导致模型有足够空间“说废话”。尤其当你在 Harness 里没有明确要求简洁时DeepSeek 很容易生成额外解释、补充说明、示例代码和总结段落。我的建议是日常任务配置 1024代码生成类任务可以临时提高到 2048。例如{ max_tokens: 1024 }可能有朋友担心max_tokens 设低了模型会不会回答到一半被截断确实存在这个风险。如果模型觉得回答还没写完但已经到达输出上限它会直接停止不会通知你导致回复看起来“半截”。为了减少这个问题我通常配合 temperature 一起调整。temperature 设到 0.2 左右模型会更倾向于直接输出结论而不是长篇大论地铺陈。同时在指令中明确“只给关键代码不要解释”也能让输出更紧凑。真遇到长任务比如生成一个完整的服务类文件我会临时把 max_tokens 调到 4096任务结束再调回来。不同任务类型建议使用的 max_tokens 可以参考下面这张表任务类型建议 max_tokens日常问答、翻译、改写512代码修改、报错解释1024生成完整代码文件2048 到 4096长篇文档撰写4096还有一个认知要纠正max_tokens 并不是总预算。它只限制本次回复的输出 Token不影响输入 Token。很多用户以为把 max_tokens 调低就能大幅控制成本结果发现账单还是很高原因就是他们的输入侧还堆着大量历史。所以max_tokens 要和窗口限制、历史轮次限制一起用单靠哪一个都压不住。2.3 开关三瘦身历史对话轮次history_limit第三个开关控制 Harness 在每次请求中携带多少轮历史消息。默认值一般很慷慨20 轮起步。但看过前面消耗分析你应该明白20 轮历史如果每一轮都包含工具调用的长文本累积起来非常吓人。我推荐把 history_limit 设为 5 到 8 轮。以 6 轮为例{ history_limit: 6 }为什么是 6 而不是 1因为现代编码工作流通常是一个小闭环读取文件、分析问题、提出方案、修改代码、运行测试、看报错。这六步各对应一轮或两轮对话。保留 6 轮模型能理解你刚才在做什么又不至于背上一个月前讨论的包袱。在这个开关下有两个配套选项值得打开始终保留系统提示词始终保留当前工具结果。它们确保历史轮次被压缩时模型不会丢掉最关键的工具上下文。比如刚才读取的一个文件内容如果被当作普通历史消息清理了你接下来的指令就会失去参照。这个细节很多人没注意一压缩历史后模型突然“失忆”其实不是模型问题是配置问题。不同保留轮数的效果差异也很明显保留轮数效果1 到 2 轮最省 Token但模型容易忘记刚才做了什么5 到 8 轮适合编码闭环推荐日常默认值20 轮以上上下文完整但费用近似线性上涨实操里我的经验是如果任务真的需要长期记忆不要依赖多轮历史。把关键信息写入项目目录下的 notes.md然后让 Harness 读取这个文件。这比让它从 20 轮历史里寻找信息更省 Token也更可靠。用文件代替聊天记忆是我在长期使用中觉得最实用的一招。3. 官方开关四、五让 Harness 少做无效动作3.1 开关四关掉自动补全和自动执行改成手动确认Harness 为了让你用起来更顺滑默认会开启一堆自动行为。你以为它只是在你输入时悄悄补全几行实际上每一次补全都是一次完整的模型请求。想象一下你打开一个 1000 行的代码文件Harness 每当你敲一个字符就尝试补全一次每次补全都要把整个文件内容作为输入发出去那一个小时的编码时间Token 消耗会比正常问答高出好几个数量级。这个数字一点都不夸张我见过有人在 IDE 里连着用 Harness 写了一个下午服务端后台的请求记录里全是密密麻麻的补全请求。我强烈建议把 auto_complete 和 auto_execute 设为 false。不同版本叫法不一样但思路是一致的{ auto_complete: false, auto_execute: false }关闭之后Harness 不会在你写完一行代码时立刻弹出补全建议也不会在看到日志里出现关键字时自动调用工具。所有动作都需要你按快捷键或输入命令触发。刚开始可能觉得少了点“智能感”但当你查看服务端请求记录时会发现请求数量明显减少。我做过一个实测同样是调试一个接口异常的任务自动模式触发了 27 次模型调用手动模式只触发 9 次。自动模式里有大量调用是在尝试猜测用户意图它试图自动搜索相关文档、自动读取代码、自动生成修复方案但其中一半是无效猜测。关闭自动行为本质上是把猜测权从模型手里收回来交给你自己。你比模型更清楚你想干什么省下来的不只是 Token还有时间。更有意思的是有些 Harness 版本在没有人工确认的情况下会自动调用执行类工具。这种自动执行不仅费 Token还有安全风险。代码改动一旦自动执行可能会在项目里留下你没注意到的副作用。手动确认模式同时解决了成本和风险两个问题属于那种关了才会觉得真香的开关。3.2 开关五打开提示词缓存Prompt Caching第五个开关是提示词缓存。DeepSeek API 支持基于前缀的缓存机制。简单来说服务端会把常见前缀的计算结果暂存下来当你下一次请求携带相同前缀时命中的那部分输入可以按更低的缓存价计费。因为 Harness 每次请求都会包含系统提示词、Skill 定义、开头若干轮历史这些内容恰好构成了一个高度稳定的前缀非常适合吃缓存红利。打开方式很简单{ prompt_cache: true }但很多人打开后发现效果不明显问题通常出在“前缀不稳定”上。缓存命中的前提是前缀完全一致哪怕你在系统提示词尾部多了一个空格缓存都可能失效。所以使用缓存有几个铁律系统提示词和 Skill 定义设置好后不要频繁改动用户消息尽量放在固定位置不要穿插到系统提示词中间不要在会话途中频繁 /clear因为每开一个新会话前缀就要从零开始重新积累。这里还有一个很容易踩的坑为了解决历史过长的问题有些用户喜欢在每次请求前手动修改历史消息比如删掉中间几轮或者重新排列顺序。这会让前缀出现断层缓存命中率断崖式下降。正确的做法是要么保持完整历史的固定顺序让它积累成一个稳定前缀要么干脆开启新会话让前缀从简短的固定内容开始。缓存的实际收益在长会话里最明显。你开着一个会话连续工作一小时系统提示词和前面历史会被发送很多次如果每次都命中缓存输入费用会大幅下降。我自己的账单在打开缓存后长会话场景的输入费用大约下降三到五成。注意缓存并不是所有请求都能命中当你发出一条全新的用户指令时新的用户指令本身不会被缓存但前面的固定部分可以。这部分固定部分通常占输入量的 70% 以上所以收益并不小。3.3 补充两个和开关等效的官方能力说完 5 个开关我还想再强调两个不属于“开关”但同样能压账单的官方能力。第一个是模型选择。DeepSeek Harness 通常允许你在 deepseek-chat 和 deepseek-reasoner 之间切换。reasoner 模型在推理时会产生内部思考过程这些思考过程同样计入 Token。如果你只是做代码格式化、翻译、写注释用 reasoner 简直是拿大炮打蚊子。我的配置里默认模型就是 deepseek-chat只有遇到复杂的架构设计、算法推导、疑难 bug 定位时才手动切换。你可以把这条写进团队规范里任何人跑 Harness 前先确认模型类型能省出一笔很可观的费用。第二个是批量处理任务。比如你手上有 10 个 markdown 文件需要统一改格式不要开 10 个会话、发 10 次请求。你把 10 个文件名一次性丢给 Harness让它在一个会话里逐个处理。这样系统提示词和工具定义只需要发送一次后续处理都能复用同一份上下文。批量处理省掉的是重复的固定开销10 个独立请求的固定开销是 10 份1 个批量请求只需要 1 份。4. Token 与登录态的经典问题排查前几节讲的是计费 Token 的控制这一节说一说和 Token 相关的另一类问题登录 Token 失效、刷新失败。这类问题不算配置问题但如果你遇到会直接影响 Harness 能否正常使用消耗的虽然不是 API 费用但却是实实在在的时间成本。4.1 “sign-in could not be completed”和“token exchange failed”Harness 登录时本质上是用一个临时授权码向认证服务换取访问 Token。这个过程在日志里体现为 token exchange。如果这一步失败你会看到 “sign-in could not be completed” 或 “token exchange failed”。我的排查步骤是先看完整报错确认是不是网络层面的瞬时错误。如果是网络抖动导致的稍等几十秒重试可能就好了。检查账号是否在其它设备上重新登录过。如果是本地旧的登录会话可能已经被服务端判为失效这时直接重新登录。清理本地凭证文件。DeepSeek Harness 的凭证一般存在 ~/.deepseek-harness 目录下的 auth 文件里。删除前可以备份然后重新执行登录命令。这套流程能解决九成以上的登录失败问题。不要为了保留登录状态去手动改凭证文件几乎只会把事情搞得更糟。4.2 “invalid refresh_token”和 access token could not be refreshed访问 Token 是短期的过期后 Harness 会尝试用 refresh_token 换新的。当你看到类似 “failed to refresh token: 400 bad request: invalid refresh_token” 的报错十有八九是本地保存的刷新凭证已经不合法了。常见诱因有两个。第一多端登录互相顶替。你在电脑上登录了 Harness之后又在手机上用同一个账号登录老设备的刷新凭证会被撤销下次续签就会失败。第二本地凭证文件被同步工具弄坏了。比如你把它放在云盘同步目录里同步时出现冲突文件内容变成空字符串那 refresh_token 自然就是 invalid 的。处理方式也很直接删除本地凭证文件重新登录。不要试图通过修改 JWT 内容来续期JWT 的签名是服务端验证的本地改任何一个字符都会报错。我见过有人反复尝试在 JSON 里补全 refresh_token 字段结果每次都是同样的报错因为服务端根本不认本地拼出来的值。4.3 JWT 与 Token 续签的几个认知我经常看到有人把“登录 Token 失效”归结为工具 Bug这里想替工具说句公道话。JWT 的设计初衷就是无状态、自包含。服务端签发的 Token 里写好了过期时间到期之前服务端在没有额外黑名单机制的情况下无法强制让某个 Token 失效。Harness 在实际登录中采用的通常是 OAuth 流程短期访问 Token 加长期刷新 Token。访问 Token 丢掉没关系刷新 Token 还在就能续如果刷新 Token 也丢了就只能重新登录。如果你是自己写脚本调用 Harness 的 API续签逻辑要注意三点Token 不要硬编码在脚本或仓库里尽量用环境变量或系统钥匙串续签前检查 Token 的过期时间快过期了才发请求续签失败不要死循环重试连续失败基本说明凭证已经废弃该走人工登录流程了。这套经验放在任何 OAuth 客户端上都适用。4.4 常见报错速查表报错关键词可能原因处理建议sign-in could not be completed登录流程中断、授权码无效清凭证后重新登录token exchange failed换 Token 时网络或服务端异常检查账号授权状态重试登录token endpoint returned 403服务端拒绝 Token 交换检查账号权限和授权范围重新登录invalid refresh_token: empty string本地刷新凭证损坏删除凭证文件重新登录access token could not be refreshed刷新 Token 过期或账号已退出重新执行登录流程403 forbidden凭据权限不足检查账号是否有对应服务权限实际排查时建议按顺序先看完整报错再检查凭证文件最后重新登录。不要在同一会话里反复点击登录那样只会产生更多的失败请求。5. 直接可抄的配置样板与实测效果5.1 一份适合普通编码场景的 Harness 配置把前 5 个开关落成一份配置我的日常配置长这样。文件位置在不同版本略有差异但大多是 ~/.deepseek-harness/config.json 或项目根目录的 .harness.yaml。JSON 版{ model: deepseek-chat, context_window: 16384, max_tokens: 1024, history_limit: 6, auto_complete: false, auto_execute: false, prompt_cache: true, temperature: 0.2 }YAML 版model: deepseek-chat context_window: 16384 max_tokens: 1024 history_limit: 6 auto_complete: false auto_execute: false prompt_cache: true temperature: 0.2这份配置的核心思想可以归结为一句话默认用便宜模型、短窗口、短输出、少历史、无自动动作、开缓存。你不需要完全照抄但可以先复制这份然后根据自己手头任务的类型微调。如果你是在团队内网服务器上统一部署 Harness建议由管理员在共享配置里预设这些值并禁止普通用户覆盖关键的成本项否则团队里只要有一个人开着自动补全写一天代码账单就会很难看。5.2 实测下来能省多少我在一个中型前端项目上做过调整前后的对比。调整前使用默认配置完成“新增一个列表页、包含接口联调和空态处理”这个任务累计消耗大约 68K Token。调整后使用上面的配置同样任务消耗大约 21K Token。下降幅度接近 70%。其中关闭自动补全贡献最大其次是收紧历史轮次和限制上下文窗口。缓存的效果更多体现在连续工作一小时的场景里单独看单次任务不明显但叠加下来很可观。配置状态会话总消耗约模型调用次数约完成情况默认配置68K27完成上述配置21K9完成质量无明显损失第三列模型调用次数也很说明问题默认配置下 Harness 做了大量试探性工作调了 27 次模型手动确认模式下只调了 9 次。模型调用次数直接和账单正相关所以你也可以通过观察统计接口里的请求次数来判断配置调整的效果。如果你的 Harness 版本自带 usage 或 metrics 面板优先看它如果没有可以临时在代理层记录一下请求体大小也能估算出个大概。5.3 三个我踩过的坑最后聊几个我在调整配置时踩过的坑给后来者提个醒。第一个坑是“频繁清理会话缓存反而失效”。我一开始以为 /clear 是省钱大招所以每几轮就清一次。结果缓存命中率掉到几乎为零因为每次新会话都要从头积累前缀。后来我改成同一个任务尽量保持一个会话任务结束才清场。清场前如果担心丢失上下文用 /compact 先压缩一份摘要而不是直接 /clear。第二个坑是“多会话并行账单翻倍”。有一段时间我同时开着三个 Harness 窗口一个写前端、一个改接口、一个写运维脚本。表面上是三线并发其实每个窗口都在独立发送系统提示词、工具定义和历史上下文。后来我强制自己单会话串行或者把同类任务合并到同一个会话总消耗立刻降下来了。第三个坑是“上下文窗口调太小触发反复重试”。有一次我为了省钱把窗口设成 4096结果 Harness 读取一个比较大的配置文件时内容被截断工具请求失败后自动重试重试时又因为窗口太小继续失败来回折腾了七八轮费用反而比不设窗口还高。解决方法是不要在让 Harness 扫描大文件时把窗口压得过低如果文件太大先用正则或 grep 把关键片段提取出来再丢给模型。用小的输入片段配合合理的窗口才是真正的省。调 DeepSeek Harness 的参数本质上是在跟“自己”做对抗。工具默认配置追求的是省事、智能、反应快而这些目标天然都会增加 Token 消耗。我调了这 5 个开关之后最大的感受是模型质量并没有下降回答反而更干脆了因为我限制了它的发挥空间它就只能挑重点讲。省 Token 这件事功夫不在省钱本身而在帮模型减少无效动作。我用过的最小成本方案就是上面这份配置加一条习惯每次开工先想清楚这个会话要解决什么问题解决完立刻清场。这条习惯比任何参数都管用。