news 2026/9/18 10:06:38

预算耗尽前,TaoToken 该触发哪类 Agent 压缩

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
预算耗尽前,TaoToken 该触发哪类 Agent 压缩

1. 预算烧穿那一刻,压缩不是“省字”而是调度决策

我在一个跑 40 分钟以上的 Agent 长任务里踩过一个很典型的坑:第 27 步模型开始重复确认已经定下来的目录结构,第 31 步把两轮前已经否掉的方案重新提出来,第 35 步直接抛context_length_exceeded。这不是模型变笨,是 harness 层缺少预算检查——它只知道往后追加消息,不知道在哪个水位该卸载、在哪个水位该压缩、压缩一次又要花掉多少 Token。后来我把长任务的调用入口统一收拢到 TaoToken(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_intro),用同一个 Key 在 https://taotoken.net/api 上出请求,才终于能把“预算检查”“压缩调用”“上下文回灌”三件事的 Token 账对齐到同一张表里。这篇就按 Agent 调度工程师的视角,把长任务里四类上下文机制——预算与卸载、压缩、todo-state 复述、跨会话记忆——的触发阈值、Token 开销和切换配置拆开讲清楚,最后给一份可以直接抄的阈值配置和不同压缩类型的 Token 对照。

先说结论:压缩不是等到报错才做的补救,它是一次有成本的调度动作。压缩调用本身要读一遍剩下的上下文、再写出一份更短的内容,这两头都在烧 Token。如果你的预算检查只盯着“当前上下文多长”,不盯着“压缩这次要花多少”,那大概率会出现一个尴尬场面——为了省 Token 而触发的压缩,直接把剩余预算吃掉三分之一。

所以本文所有阈值都围绕一个前提设计:预算检查与压缩调用也是 Token 消耗方,必须单独建账

2. 先把账本立起来:预算检查本身要花多少 Token

很多同学写 harness 的时候,预算检查是这么写的:每一步都把完整消息列表丢给模型,问它“现在大概占了多少 Token”。这个做法在长任务里是自杀式的,因为你每次都在为“统计”付一次全量上下文的价格。

正确的拆分是三层:

第一层是本地估算。用对应模型的 tokenizer 或者社区近似算法,对当前 transcript 做一次离线计数,误差控制在 5% 以内就够用。这一步零 API 成本。

第二层是周期性校准。每 N 步(我一般设 3 步)拿一次真实用量,和本地估算对齐,修正系数。真实用量可以从流式响应里累计input_tokens/output_tokens得到。

第三层是压缩预算预留。在总预算里切出一块固定的“压缩专用额度”,跟主任务额度分开记账。这样即使压缩调用比预期贵,也不会把主任务的推理预算吃穿。

账本字段建议至少包含这些:

{ "window_tokens": 200000, "reserve_output_tokens": 16000, "compact_budget_tokens": 12000, "compact_spent_tokens": 0, "estimate_ratio": 1.0, "last_calibrate_step": 0, "calibrate_every_steps": 3 }

window_tokens是模型窗口,reserve_output_tokens是留给最终输出的,compact_budget_tokens是这块任务允许在压缩上花掉的总额度。真正参与水位判断的可用额度是:

usable = window_tokens - reserve_output_tokens ratio = used_tokens / usable

注意used_tokens里要包含 tool 返回的原始内容。Agent 长任务里最容易被忽略的一类膨胀源就是工具输出——一次目录树、一次全量日志、一次 diff,都能瞬间把上下文推高几万 Token。这些内容不该长期驻留在 transcript 里,它们属于“卸载”的范畴,不是“压缩”的范畴。

3. 四类压缩的触发阈值怎么定

这一步是全文的核心。四类机制对应四类不同的问题,触发水位也不同,混着用就会出现“明明压缩了却还是丢失目标”的情况。

第一类:上下文预算与卸载(offload)。解决的是“工具原始输出太长”。做法是把大块内容写到外部存储(本地文件、对象存储、记忆库),transcript 里只留一个指针加一句摘要。触发水位我建议放在 0.55——也就是可用额度用掉一半多的时候就开始卸载,而不是等满了再卸。卸载的成本几乎为零,越早做越好。

第二类:压缩(compaction)。解决的是“历史对话太啰嗦”。把前 N 轮的消息合并成一份结构化摘要。触发水位放 0.70。这里有个关键点:压缩一定要产出结构化内容,不要产出自由散文。自由散文的摘要里,模型最容易丢的就是“已经否决的方案”和“硬约束”,而这两样恰恰是长任务跑偏的主要来源。

结构化摘要的 schema 建议固定为五段:

goal: 当前任务的最终目标(一句话) constraints: 不可违反的硬约束(列表) decisions: 已确认的决策 + 被否决的方案及原因 artifacts: 已产出的文件路径 / 函数名 / 接口签名 open: 未决问题和下一步待办

第三类:todo-state 复述(restate)。解决的是“目标漂移”。做法是不做内容压缩,而是周期性把当前目标、已完成项、待办项、验收条件重新回灌到上下文尾部。触发水位放 0.75,并且每 K 步强制执行一次,不管水位。我一般 K 取 8。复述内容的 Token 非常小,通常几百个,但对缓解目标丢失的效果立竿见影。

第四类:跨会话记忆(memory)。解决的是“任务跨进程 / 跨天重启后从零开始”。做法是把长尾事实写入外部记忆库,需要时按查询召回。写入触发水位 0.55(和卸载同步做),召回触发水位 0.75。

把四类放在一张表里对照:

机制解决的问题触发水位回灌 Token(约)单次调用开销
卸载 offload工具输出膨胀0.5550~200接近 0(本地写入)
压缩 compact历史对话啰嗦0.701.5k~3k读全量 + 写摘要
todo 复述目标漂移0.75 / 每 8 步300~600接近 0(本地拼装)
记忆召回跨会话断点0.75300~800单次检索 + 注入
硬停 hard stop兜底0.88中止并落盘

再给一份不同压缩类型的 Token 对照。测试场景是一个已经跑到约 120k Token 的编码类长任务,输出预留 16k,可用额度 184k:

压缩类型回灌 Token(约)压缩调用开销(约)保留度适用水位
不压缩全量回灌120k0100%仅作基线
自由文本摘要2.5k~4k读 120k / 写 3k中,约束易丢0.70
结构化摘要1.2k~2k读 120k / 写 1.5k0.70
todo-state 复述300~600读 120k / 写 0.4k目标保真,细节不保0.75
卸载 + 指针50~200本地写入内容可回溯0.55
记忆写入 + 按需召回300~800写 1k / 召回 0.6k长尾事实可检索0.55 写入 / 0.75 召回

这张表的意义在于:压缩类型不同,Token 量级差一个数量级。用自由文本摘要去处理工具输出,等于花高价买了一个还不一定记得住的结果;用卸载去处理历史决策,又等于什么都没压缩,因为决策本来就不该被卸载掉。

阈值配置可以直接落成一份 JSON:

{ "budget": { "window_tokens": 200000, "reserve_output_tokens": 16000, "compact_budget_tokens": 12000 }, "triggers": { "offload_ratio": 0.55, "compact_ratio": 0.70, "restate_ratio": 0.75, "memory_recall_ratio": 0.75, "hard_stop_ratio": 0.88, "restate_every_steps": 8 }, "compact_schema": [ "goal", "constraints", "decisions", "artifacts", "open" ] }

4. 把 Base URL 切到 TaoToken:Claude Code / Codex / CC Switch

阈值配好之后,下一步是让压缩调用真的走同一条链路。如果你在同一个长任务里混用了多个供应商,压缩调用的 Token 就不在同一个账本上,前面做的预算对齐全白费。

先去 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_key 拿到 Key,然后在 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_keys 创建一把长期 Key。后面所有配置里的YOUR_API_KEY都换成它。

Claude Code:用 settings.json 或 ANTHROPIC_环境变量。*

~/.claude/settings.json

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-5", "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5" } }

如果你更喜欢 shell 层注入:

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY" export ANTHROPIC_MODEL="claude-sonnet-4-5" export ANTHROPIC_SMALL_FAST_MODEL="claude-haiku-4-5"

ANTHROPIC_SMALL_FAST_MODEL建议单独指向一个便宜的小模型。todo-state 复述、轻量分类、摘要拼接这类低智力密度调用可以走它,能明显压低压缩总开销。

Codex:用 config.toml,不要套 ANTHROPIC_*。

~/.codex/config.toml

model = "gpt-5-codex" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "responses"

Key 单独放环境变量,不要写进 toml:

export TAOTOKEN_API_KEY="YOUR_API_KEY"

这里强调一遍:Claude Code 用ANTHROPIC_*,Codex 用config.toml+env_key,两套体系不能互相套用。把ANTHROPIC_BASE_URL写到 Codex 的配置里,或者反过来,只会得到一堆 401 和连接超时。

CC Switch:记住三件套 = 供应商名 + Base URL + API Key。

CC Switch 在切换 Claude Code 供应商时,实际改的就是三个字段:

供应商名: taotoken Base URL: https://taotoken.net/api API Key: YOUR_API_KEY

切完之后一定做两件事:一是重启终端里已有的 Claude Code 会话,环境变量是进程级缓存的;二是跑一次/status或等价命令确认当前生效的 Base URL。多供应商并存时最容易出的问题就是“配置改了但没生效”,长任务跑到一半才发现压缩调用打到了旧地址。

切换到 TaoToken 之后,建议把官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_switch 上的模型列表和文档对照一遍,确认你要用的压缩模型和目标模型都在可用范围内。

5. 压缩后目标丢失的排障顺序

压缩触发之后,最常见的三类异常和对应的排查顺序如下。

症状一:压缩后立刻重复之前的动作。大概率是结构化摘要里decisions字段丢了。检查方法:把压缩产出的摘要单独打印出来,数一下里面有没有“被否决的方案”。如果只有结论没有过程,模型就会重新走一遍已经被否掉的路。修法是让压缩调用产出的 schema 强制包含decisions,并且要求每条决策后面必须跟一句否决理由。

症状二:压缩后整体跑偏,开始做任务目标之外的事。这是 todo-state 没有复述的典型表现。压缩只保留内容,不保留“我们现在在干什么”。修法是把复述频率提高到每 5 步一次,并且把goal字段放在 transcript 最末尾——模型对上下文尾部的注意力最强。

症状三:压缩调用本身就超预算。表现为压缩之后剩余额度比压缩之前还紧张。原因是压缩调用没有被单独记账。修法是把compact_budget_tokens从主预算里切出来,压缩调用前先检查这块额度还剩多少,超了就直接降级到 todo-state 复述,不做全量摘要。

症状四:跨会话恢复后重新探索目录结构。说明记忆写入做了,但召回没做,或者召回索引对不上。检查方法:看恢复后的第一轮请求里有没有注入记忆召回结果。修法是给记忆库加一个按artifact path的索引,恢复时用任务名做一次定向召回,而不是泛召回。

症状五:直接抛context_length_exceeded如果阈值都配了还报这个错,通常是本地估算系数偏了。把estimate_ratio往上调 0.05 再跑一轮,或者把calibrate_every_steps从 3 改到 1,先确认估算和真实用量对齐。

排障的时候有一个通用原则:先看压缩产出的内容,再看触发水位,最后看配置链路。绝大多数“压缩没用”的案例,问题都出在压缩产物质量上,而不是阈值上。

6. 把压缩闸门接进 harness 主循环

阈值配置和供应商配置都准备好之后,最后一步是把它接进主循环。下面是一个本地执行的守卫函数示例,逻辑是“先校准、再判断、再决定动作、最后记账”:

BUDGET = { "window_tokens": 200_000, "reserve_output_tokens": 16_000, "compact_budget_tokens": 12_000, "compact_spent_tokens": 0, "calibrate_every_steps": 3, "restate_every_steps": 8, } def guard(used_tokens: int, step: int, compact_cost_estimate: int): usable = BUDGET["window_tokens"] - BUDGET["reserve_output_tokens"] ratio = used_tokens / usable remain_compact = BUDGET["compact_budget_tokens"] - BUDGET["compact_spent_tokens"] # 硬停兜底 if ratio >= 0.88: return {"action": "hard_stop", "reason": "budget_exhausted"} # 目标复述:低水位也按步数强制触发 if ratio >= 0.75 or step % BUDGET["restate_every_steps"] == 0: return {"action": "restate_todo"} # 压缩:额度不够就降级 if ratio >= 0.70: if remain_compact >= compact_cost_estimate: BUDGET["compact_spent_tokens"] += compact_cost_estimate return {"action": "compact_structured"} return {"action": "restate_todo", "reason": "compact_budget_low"} # 卸载:最早触发,成本最低 if ratio >= 0.55: return {"action": "offload_tool_output"} return {"action": "continue"}

几个实现细节值得留意。

第一,compact_cost_estimate要按“输入全量 + 输出摘要”两头估,只估输出会低估三到五倍。

第二,restate_todo的触发条件用了or,意味着它既受水位驱动也受步数驱动。这个设计是为了防止一种情况:任务在低水位区反复小步前进,走了 30 步都没触发复述,目标早就飘了。

第三,compact_budget_low的降级路径一定要有。压缩额度用完时,退回到 todo-state 复述比强行压缩安全得多——前者最多丢细节,后者可能把上下文挤出窗口。

第四,所有触发动作都要落日志。长任务出问题时,日志里的触发序列比任何事后分析都直接。

接好之后,跑一个长任务验证一下。观察指标是三个:压缩触发次数、压缩累计 Token、任务最终是否命中目标。理想状态下,压缩触发 2 到 4 次,累计压缩 Token 控制在总预算的 8% 以内,任务目标不变。

7. 一条可复现的验证路径

把上面所有内容串起来,一条完整的验证路径是:

第一步,在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_flow 拿 Key,在 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_flow_key 建一把长期 Key。

第二步,按第 4 节把 Claude Code 或 Codex 的 Base URL 统一指向 https://taotoken.net/api,确认切换生效。

第三步,把第 3 节的阈值 JSON 落进 harness 配置,把第 6 节的守卫函数接进主循环。

第四步,跑一个至少 20 步的长任务,记录每次触发的动作类型和当步 Token 用量。

第五步,对照第 3 节的 Token 对照表,看实际压缩开销落在预期区间没有。偏差超过一倍,先查估算系数,再查压缩 schema 是不是退化成自由文本了。

第六步,做一次跨会话恢复,验证记忆召回是否生效。

如果你还没决定用哪个模型来跑压缩调用,可以先到 https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_chat 对比一下各模型在长上下文场景下的表现,再决定主模型和小模型的搭配。

长任务跑得多的话,https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_plan 里的 Coding Plan 可以直接覆盖编码类工作流,配合上面的阈值配置用起来更省心;Claude Code 侧的具体接入细节在 https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=budget_compact_doc 有完整说明。

回到最开始那个坑:Agent 长任务真正难的不是模型能力,而是调度层愿不愿意把 Token 当成一种需要精算的资源。预算检查、卸载、压缩、todo-state 复述、跨会话记忆,这五件事分开看都不复杂,难的是把它们放进同一本账里,并且在正确的水位触发正确的动作。阈值配错一次,你可能要多花三倍预算才能跑完同一件事。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 10:02:03

电工手册结构化:PDF语义解析与故障诊断知识图谱构建

简介:《电工手册1768页》是一本面向电气工程初学者与一线从业电工的综合性技术参考书,系统覆盖电路理论、电气安全规范、电机与变压器、电力系统、继电保护、PLC编程、自动化控制、电气安装维护、照明设计及电线电缆选型等核心内容,有效解决实…

作者头像 李华
网站建设 2026/9/18 9:59:01

MySQL InnoDB三层B+树能存多少行?从16KB页到2000万容量推导

1. 三层B树这个问题,到底在问什么前段时间有个同事跑来问我:订单表已经1800万行,是不是该分表了?我没直接给建议,先反问他:你知道 InnoDB 一棵三层 B 树大概能承载多少数据量吗?他想了半天&…

作者头像 李华
网站建设 2026/9/18 9:58:15

基于四个视觉特征的马铃薯在线分级技术解析

简介:《基于计算机视觉的马铃薯自动检测分级》是一份PDF格式的学术文献资源,面向农业工程、计算机视觉及农产品自动化检测领域的师生与工程师,可用于课题参考、算法理解与系统设计。文档针对马铃薯采后分级问题,系统阐述了基于大小…

作者头像 李华
网站建设 2026/9/18 9:56:21

金融审批数仓:累积快照建模实战指南

简介:本资源是一份面向大数据工程师、数据仓库开发者及金融行业数据分析人员的系统性学习文档,聚焦数据仓库架构设计、建模方法论与金融审批场景落地实践。内容覆盖Dolphin Scheduler、Hive、ODS/DWD/DIM/DWS/ADS分层模型、MaxwellFlume数据采集链路&…

作者头像 李华