1. TaoToken 发 Key 后,ReAct 长任务为什么先崩在上下文
如果你已经在 TaoToken 官网(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_intro)拿到 API Key,并且把 Claude Code 的ANTHROPIC_BASE_URL指向https://taotoken.net/api,那么接下来最容易踩的坑往往不是模型选型,而是 ReAct 长任务跑到二三十轮之后,Agent 开始忽略最初设定的规则。典型症状:第 1 轮明确要求“错误变量统一命名为 err、函数不超过 50 行、变量用 camelCase”,第 10 轮还遵守,第 30 轮开始生成snake_case,第 40 轮连错误处理风格都混了。你去看日志,模型没有报错,工具调用也成功,但输出质量就是持续下滑。
这不是模型突然变笨,而是 ReAct 循环的“只进不出”结构在作祟。ReAct 定义了「Thought → Action → Observation」的闭环:模型先思考,再调用工具,然后读取工具返回结果。这个循环解决了“让 LLM 动手做事”的问题,却没有规定“做完之后旧信息怎么处理”。每一轮 TAO 都会往上下文里追加新内容,Observation 尤其占空间,一次文件读取、一次测试输出、一次编译日志,轻轻松松就是几千 Token。上下文窗口再大,也扛不住几十轮这样堆。
所以,TaoToken 发 Key 只是让模型能稳定调用,真正的长任务稳定性要看上下文管理。本文给出一套可复现的做法:用 Structured Note-Taking 把历史“卸载”到上下文窗口之外,让 Agent 只保留当前决策真正需要的信息。文末会给出四类笔记模板和 Token 走势对照,你可以直接套到自己的 Claude Code、Codex 或 CC Switch 工作流里。
1.1 先区分:ReAct 解决行动,Context Engineering 解决信息供给
ReAct 关注“下一步做什么”,Context Engineering 关注“模型此刻看到什么”。两者不是替代关系。没有 ReAct,Agent 无法调用工具;没有 Context Engineering,Agent 能在短任务里跑通,但在长任务里会慢性退化。退化路径通常是这样:
- Observation 越积越多,有用信号被稀释;
- 系统指令被从开头挤到中间,模型对它的注意力下降;
- 失败调用和错误日志留在历史里,污染后续推理;
- Thought 冗余积累,消耗 Token 预算却不提供新信息。
这四步合起来,就是“Agent 用久了越来越差”的根因。
2. 先把钥匙接对:Claude Code、Codex、CC Switch 的 TaoToken 配置
在讲笔记外置之前,先把 TaoToken 接进常用工具。入口是 TaoToken 官网(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_config),在控制台创建 API Key,然后统一把 Base URL 设为:
https://taotoken.net/apiKey 在配置里先用占位符YOUR_API_KEY,不要把真实 Key 提交到 Git。
2.1 Claude Code:settings.json 与 ANTHROPIC_*
Claude Code 推荐在~/.claude/settings.json或项目级.claude/settings.json里写入环境变量:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY" } }如果你的 Claude Code 版本使用ANTHROPIC_API_KEY,也可以按本地文档替换字段名,但核心不变:Base URL 指向 TaoToken 的 API 地址。保存后重启 Claude Code,让它重新读取配置。
2.2 Codex:config.toml 不要混用 ANTHROPIC_*
Codex 使用 TOML 配置,路径通常是~/.codex/config.toml。它的 provider 配置和 Claude Code 完全不同,千万不要把ANTHROPIC_*写进 Codex 的配置里。一个最小化示例如下:
# ~/.codex/config.toml model_provider = "taotoken" model = "YOUR_MODEL_ID" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY"然后在 shell 里设置:
export TAOTOKEN_API_KEY="YOUR_API_KEY"如果你使用的 Codex 版本字段名不同,以本地config.toml的 provider 说明为准,但必须保证两件事:base_url 是https://taotoken.net/api,且不要出现ANTHROPIC_*。
2.3 CC Switch 三件套:供应商、模型、密钥
CC Switch 用来在多个供应商之间切换。接入 TaoToken 时,把它当成三件套来配置:
- 供应商(Provider):新增一个 TaoToken;
- 模型(Model):填入你在 TaoToken 控制台可用的模型 ID;
- 密钥(API Key):填入
YOUR_API_KEY。
Base URL 一栏填https://taotoken.net/api。配置完后,先跑一个短对话验证连通,再进入长任务。短对话都失败,就不要急着上 ReAct。
3. ReAct 的 Token 走势:无笔记 vs 有笔记的对照
要理解 Structured Note-Taking 的价值,先看 Token 走势。下面是一个 50 轮代码重构任务的估算。假设每轮 TAO 产生:Thought 约 200 Token,Action 约 150 Token,Observation 约 1,200 Token。无笔记时,所有内容都留在上下文里;有笔记时,每 3 轮把 Observation 和旧 Thought 卸载到外部笔记,上下文只保留系统提示、最近 2 轮原始对话、四类笔记摘要和当前任务状态。
| 轮次 | 无笔记累计 Token | 有笔记活跃 Token | 外置笔记 Token |
|---|---|---|---|
| 0 | 1,500 | 1,500 | 0 |
| 10 | 18,000 | 4,500 | 6,000 |
| 20 | 36,000 | 6,200 | 12,000 |
| 30 | 58,000 | 7,800 | 19,000 |
| 40 | 82,000 | 9,100 | 26,000 |
| 50 | 108,000 | 10,500 | 33,000 |
这张表不是精确基准,而是一个工程估算模型。它要说明的是:无笔记时,上下文活跃 Token 随轮次线性膨胀;有笔记时,活跃 Token 被压在一个相对平缓的区间,外置笔记虽然也在增长,但它不在上下文窗口里,只在需要时按需读取。
3.1 为什么 Observation 是最大污染源
Observation 是工具返回结果,它天然不可控。读一个文件可能返回 3,000 Token,跑一次测试可能返回 2,000 Token,一次编译错误日志可能返回 1,500 Token。这些内容在当轮有用,但下一轮就不一定需要完整保留。无笔记时,它们全部留在历史里,把系统指令和关键决策挤到中间。模型对中间位置内容的注意力本来就弱,规则漂移就发生了。
3.2 错误轨迹污染比想象中更隐蔽
工具调用失败、超时、格式解析错误都是常态。ReAct 的容错机制会让 Agent 重试,但失败的 Thought 和错误 Observation 也留在历史里。一旦一条错误信息进入上下文,它可能影响后面多轮推理。你以为 Agent 在重新尝试,实际上它在被之前的错误轨迹带偏。把错误日志卸载到笔记的“发现”或“问题”区,只把结论放回上下文,可以显著减少这种污染。
4. Structured Note-Taking 的四个抽屉:可复制模板
Structured Note-Taking 的核心动作是:把关键信息主动写到上下文窗口之外,需要时再读回来。不要只写一个notes.md,按用途拆成四个抽屉,Agent 找信息更快,人排查也更清晰。
推荐目录结构:
project/ .agent/ notes/ progress.md decisions.md findings.md strategy.md state.json4.1 进度笔记(Progress Notes)
记录已经完成什么、还没做什么。它回答“任务走到哪了”。
# Progress Notes ## 已完成 - [x] auth_service.go 认证逻辑重构 - [x] 移除 session 依赖 - [x] 补充 JWT 单元测试 ## 进行中 - [ ] order_service.go 拆分订单校验逻辑 ## 待处理 - [ ] payment_service.go 错误处理统一 - [ ] 全量回归测试4.2 决策笔记(Decision Notes)
记录为什么这样选,避免后续 Agent 推翻已经过论证的方案。
# Decision Notes ## D-001 选择 JWT 而非 Session - 原因:服务无状态,需要水平扩展 - 影响:auth_service 不再写本地 session - 状态:已确认 ## D-002 错误变量统一命名为 err - 原因:团队规范,便于 grep - 例外:导出错误使用 ErrXxx - 状态:已确认4.3 发现笔记(Finding Notes)
记录过程中发现的重要事实、冗余调用、隐藏依赖。
# Finding Notes ## F-001 payment_service 重复调用 auth_service - 现象:每个请求调用 3 次认证 - 影响:延迟增加,日志重复 - 建议:合并为一次调用并缓存结果 ## F-002 order_service 存在未处理 panic - 位置:order_service.go:142 - 触发条件:空订单 ID - 建议:增加校验并返回错误4.4 策略笔记(Strategy Notes)
记录下一步怎么做,让 Agent 在上下文重置后能快速恢复执行方向。
# Strategy Notes ## 当前优先级 1. 修复 payment_service 冗余认证调用 2. 处理 order_service 的 panic 3. 统一 error handling 风格 4. 跑回归测试 ## 约束 - 不改变对外 API - 每个 PR 不超过 300 行4.5 写入触发条件
不要每轮都写,也不要等上下文满了才写。推荐两个触发条件:
- 每 3 轮 TAO 循环后,强制写一次进度和发现;
- 当上下文活跃 Token 超过预算的 60% 时,触发一次全量整理。
写入时只写结论,不写原始日志。原始日志可以留在.agent/logs/里,但不要自动塞回上下文。
5. 把笔记接回 ReAct:每轮上下文重组算法
笔记写完之后,关键是“怎么读回来”。每轮调用 LLM 之前,不要直接把全部历史拼进去,而是重组上下文。一个可用的结构如下:
def build_context(system_prompt, recent_turns, notes, task_state): return f""" {system_prompt} ## 当前任务状态 {task_state} ## 进度摘要 {notes["progress"][-400:]} ## 关键决策 {notes["decisions"][-400:]} ## 重要发现 {notes["findings"][-400:]} ## 下一步策略 {notes["strategy"][-400:]} ## 最近原始对话 {recent_turns} """这里的recent_turns只保留最近 2 轮原始 TAO。更早的内容已经被压缩成上面四个摘要。调用时把build_context的结果作为新的输入,而不是把整个history列表直接丢进去。
5.1 上下文预算分配表
以 32K 上下文窗口为例,可以这样分配:
| 区域 | 预算 | 说明 |
|---|---|---|
| System Prompt | 2,000 | 角色、原则、工具使用规则 |
| 当前任务状态 | 500 | 当前文件、阶段、约束 |
| 四类笔记摘要 | 1,600 | 每类 400 Token 左右 |
| 最近 2 轮原始 TAO | 3,000 | 保留最新细节 |
| 工具定义 | 1,500 | 只保留必要工具 |
| 输出预留 | 4,000 | 给模型回答和工具调用 |
| 缓冲 | 19,400 | 应对突发长 Observation |
如果某一轮 Observation 特别长,不要直接塞进上下文,先写入外置笔记,再在上下文里放一句摘要:“已读取 order_service.go,发现 3 个问题,详见 Finding Notes F-003。”
5.2 读取策略:按需读取,不全量加载
笔记文件可能越来越大,不要每次把四个文件全部读进来。可以按当前阶段选择:
- 刚进入任务:读 progress + strategy;
- 做技术选型:读 decisions;
- 排查 bug:读 findings;
- 上下文重置后:读 progress + strategy,再按需读 findings。
如果笔记超过 2,000 Token,先让模型做一次摘要,再放进上下文。
6. 实战:50 轮代码重构任务的 Token 走势与修复动作
假设你在用 Claude Code 做 Go 代码重构,任务包括认证、订单、支付三个服务。第 1 轮系统指令要求:变量用 camelCase、错误变量用 err、函数不超过 50 行。前 10 轮顺利,第 20 轮开始偶尔出现snake_case,第 30 轮错误处理风格混用。用 Token 走势看:
- 无笔记:第 10 轮 18K,第 20 轮 36K,第 30 轮 58K,第 40 轮 82K,第 50 轮 108K。系统指令早已被挤出开头。
- 有笔记:第 10 轮活跃 4.5K,第 20 轮 6.2K,第 30 轮 7.8K,第 40 轮 9.1K,第 50 轮 10.5K。外置笔记增长到 33K,但不在上下文里。
修复动作:
- 把前 20 轮的 Observation 全部卸载到
.agent/notes/findings.md,上下文只留“已读取文件清单 + 关键发现编号”; - 把 Thought 压缩成决策和策略,不再保留完整推理过程;
- 把失败的工具调用日志移到
.agent/logs/errors.log,只在发现笔记里保留“某接口曾超时,已重试成功”; - 每 3 轮重新注入一次系统指令摘要,放在用户消息结尾,利用近因效应。
执行后,第 50 轮的活跃 Token 从 108K 降到 10.5K 左右,Agent 对命名规范的遵守度明显回升。
6.1 一个可复制的扫描脚本
下面的脚本可以帮你统计本地笔记和日志的体积,判断哪些内容不该留在上下文里:
#!/usr/bin/env bash NOTES_DIR=".agent/notes" LOGS_DIR=".agent/logs" echo "== notes tokens estimate ==" for f in "$NOTES_DIR"/*.md; do [ -f "$f" ] || continue chars=$(wc -c < "$f") echo "$f: ~$((chars / 4)) tokens" done echo "== logs size ==" du -sh "$LOGS_DIR" 2>/dev/null || echo "no logs dir"这个脚本只做本地统计,不连接任何生产库,也不调用外部 API。你可以按项目实际情况调整路径。
7. 常见反模式与排障清单
7.1 反模式一:笔记只写不读
Agent 把笔记写得很勤,但每轮上下文重组时没有读回来。结果是笔记在磁盘上,Agent 还是“失忆”。修复:在build_context里固定加入四类笔记摘要,并限制每类 400 Token。
7.2 反模式二:笔记变成第二个上下文
把原始日志、完整文件内容、全部工具返回都写进笔记,然后每次全量读回。这等于把上下文膨胀从内存搬到了磁盘,但读回来时又膨胀了一次。修复:笔记只写结论、决策、发现和下一步,原始内容另存日志,按需读取。
7.3 反模式三:系统指令只放开头
系统指令一直放在开头,随着上下文增长被挤到中间。修复:每 5 到 10 轮在用户消息结尾重新放一段“当前必须遵守的规则摘要”,利用近因效应。
7.4 反模式四:工具定义过多
工具定义本身占 Token,功能重叠的工具还会让模型选错。修复:每个阶段只保留必要工具,工具描述写清“适用场景”和“不适用场景”。
7.5 排障清单
- 上下文活跃 Token 是否超过预算 60%?
- 最近 3 轮是否包含超过 2,000 Token 的 Observation?
- 系统指令是否还在开头 20% 的位置?
- 笔记摘要是否每轮都读回?
- 失败调用日志是否还在上下文里?
- 工具定义是否超过 1,500 Token?
如果以上任何一项为“是”,先做一次笔记外置和上下文重组,再继续跑长任务。
8. 把长任务记忆外置固化到你的工作流
TaoToken 发 Key 之后,Claude Code、Codex、CC Switch 都只是入口。真正决定 ReAct 长任务稳定性的,是每一轮 TAO 之后你有没有做信息卸载。Structured Note-Taking 不复杂:四个抽屉、两个触发条件、一个每轮重组函数。把它固化到项目里,Agent 就不会在第 30 轮忘记第 1 轮的规则。
如果你还没有 Key,可以先从 TaoToken 官网(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_cta)进入控制台创建。下面这条路径按顺序走一遍:
先和模型对话,验证基础连通:
https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_chat需要长期跑 Coding 任务,看 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_coding创建 API Key,填到 Claude Code、Codex 或 CC Switch:
https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_keysClaude Code 的具体接入文档:
https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=react_notes_claudecode
Base URL 始终是:
https://taotoken.net/apiKey 占位符:
YOUR_API_KEY把这两个值配好,再把四类笔记模板放进.agent/notes/,你的 ReAct 长任务就从“跑到一半开始漂移”变成“上下文重置后还能接着干”。