1. 从 environment-probing curation 到 TaoToken 写入通道:先拆 Token 账本
Microsoft 近期关于 environment-probing curation 的论文,把长期运行智能体的持久记忆问题推到了一个很工程化的位置:经验不是写完就算,写入前要有一个独立记忆智能体,以只读方式探测环境,校验这条经验是否正确、是否可复用。这个思路放到 Claude Code、Codex、CC Switch 这类编码工具里,真正容易踩坑的不是“要不要校验”,而是写入通道和校验通道的 Base URL、Key、Token 统计是否统一。很多团队的做法是主 Agent 走一个供应商,校验 Agent 走另一个供应商,最后经验库是更新了,但没人能回答这次写入消耗了多少 Token、只读探测读了多少证据、哪些记忆读取其实可以省略。
本文的目标很具体:把经验库写入通道改到 TaoToken,记忆校验再通过只读环境探测,最后输出校验后的读取结果与 Token 消耗。TaoToken 的官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=memory_curation_intro,工具配置统一使用 Base URL:https://taotoken.net/api,Key 先用占位符YOUR_API_KEY。下面不会复述论文结论,而是给出可复制的配置路径:Claude Code 走settings.json和ANTHROPIC_*,Codex 走config.toml和model_provider,CC Switch 用 Profile、Key、Base URL 三件套统一切换,再用一个本地只读脚本完成记忆校验。
2. 记忆校验的 Token 账本:写入、探测、回执、再读取
要复现 environment-probing curation 的核心动作,先把一次“经验写入”拆成五个阶段。
第一阶段是候选经验生成。主 Agent 在完成任务后,从对话、报错、修复过程中提炼出一条候选经验,例如“在本仓库升级依赖前先运行某个冒烟测试”。这一步通常由主模型完成,消耗的是任务上下文和生成候选条目的 Token。
第二阶段是只读环境探测。独立的记忆校验智能体不能直接接受候选经验,它要按照白名单读取环境证据,例如 README、依赖声明、测试文件、最近一次本地命令输出。只读意味着不修改文件、不写入数据库、不连接生产库,也不执行任何有副作用的命令。校验 Agent 的任务是回答:这条经验在当前环境中是否成立,是否具有跨任务复用价值。
第三阶段是校验回执。为了后面能自动过滤,校验结果最好强制为 JSON,例如correct、reusable、reason、suggested_fix四个字段。这样主流程不需要解析自然语言,也能把“不通过”的经验挡在持久化之前。
第四阶段是持久化。只有回执同时满足正确和可复用时,才把候选经验、证据摘要、校验回执、时间戳写入经验库。写入本身不一定调用模型,但如果在写入时做摘要压缩,就会再产生一次 Token 消耗。
第五阶段是再读取。下一轮任务读取记忆时,不能只读经验文本,还要读取校验标记和证据来源。否则一个已经被标记为“环境相关、不可复用”的经验,会在另一个项目里被错误套用。
把这五个阶段放在 TaoToken 的同一个 Base URL 下,好处是每次调用的usage字段结构一致,主 Agent 和校验 Agent 的消耗可以汇总到同一张账本里。切换模型时也不需要改业务代码,只需要改配置中的模型名。
3. 在 TaoToken 官网拿 Key:Base URL 与最小权限
先把入口固定下来。打开 TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=create_key_step,完成注册或登录。然后在控制台创建 API Key,创建页入口是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=create_key_api_keys。复制出来的 Key 不要直接写进仓库,本文统一用YOUR_API_KEY占位。
Base URL 不加任何 UTM 参数,工具配置里统一写:
https://taotoken.net/api本地环境变量可以这样设置:
export TAOTOKEN_API_KEY="YOUR_API_KEY" export TAOTOKEN_BASE_URL="https://taotoken.net/api"如果你使用 Claude Code,则还需要对应的ANTHROPIC_*变量;如果你使用 Codex,则不要在 Codex 配置里写ANTHROPIC_*。这是两套客户端,认证变量不同,混用会出现能启动但请求 401 或 404 的情况。
最小权限建议:
- 经验库写入和记忆校验使用独立 Key,方便按项目统计 Token。
- 校验 Agent 的 Key 不授予生产环境操作权限,只允许读取本地白名单文件。
- 不要把 Key 提交到 Git;用 shell 环境变量或本地未跟踪配置文件。
- 如果团队多人共用,给每个开发者单独创建 Key,便于排障。
4. Claude Code:settings.json 写 ANTHROPIC_*
Claude Code 的配置重点是settings.json和ANTHROPIC_*环境变量。可以在用户级配置或项目级配置中写入env块。下面是一个可复制的示例,模型名请按 TaoToken 控制台实际可用的模型替换:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514", "ANTHROPIC_SMALL_FAST_MODEL": "claude-3-5-haiku-20241022" } }如果你不想改settings.json,也可以只在当前终端临时导出:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY" export ANTHROPIC_MODEL="claude-sonnet-4-20250514"配置完成后,Claude Code 的请求会走 TaoToken 的 Base URL。此时你再让主 Agent 生成候选经验、让校验 Agent 读取本地证据,两个调用都会出现在同一套 Token 统计里。
Claude Code 文档入口放在这里,后面 CTA 还会再列一次:
https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=memory_validation_claudecode_doc
注意:ANTHROPIC_*只属于 Claude Code 这一类客户端。不要把它复制到 Codex 的config.toml里,Codex 不认这组变量。
5. Codex:config.toml 写 model_provider,禁止混用 ANTHROPIC_*
Codex 使用config.toml管理模型供应商。典型位置是~/.codex/config.toml。下面示例把 TaoToken 注册为一个名为taotoken的 provider,Base URL 仍然是不带 UTM 的https://taotoken.net/api:
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"然后在 shell 中提供 Key:
export TAOTOKEN_API_KEY="YOUR_API_KEY"如果你的 Codex 版本要求使用 chat completions 风格的接口,可以把wire_api按客户端文档调整为对应值。但无论怎么调,都不要把 Claude Code 的ANTHROPIC_AUTH_TOKEN写进这里。Codex 通过env_key读取TAOTOKEN_API_KEY,这是两条独立认证链。
验证思路是:先用一个最小对话请求确认 Codex 能走通,再让它执行记忆写入任务。不要让 Codex 直接连接生产数据库,也不要把校验 Agent 配置成可以写生产环境的权限。记忆校验只需要读本地文件、读测试输出、读配置快照。
6. CC Switch 三件套:Profile、Key、Base URL
如果你同时在 Claude Code、Codex、其他 CLI 之间切换,可以用 CC Switch 做统一入口。这里说的三件套是:Profile、Key、Base URL。Profile 决定当前激活哪个工具,Key 决定认证,Base URL 决定请求打到哪。示例配置如下,具体字段名请按你本地 CC Switch 版本调整:
version: 1 profiles: - name: tao-claude tool: claude-code env: ANTHROPIC_BASE_URL: "https://taotoken.net/api" ANTHROPIC_AUTH_TOKEN: "YOUR_API_KEY" ANTHROPIC_MODEL: "claude-sonnet-4-20250514" - name: tao-codex tool: codex env: TAOTOKEN_API_KEY: "YOUR_API_KEY" config_path: "~/.codex/config.toml" - name: tao-gemini tool: gemini-cli env: GEMINI_API_KEY: "YOUR_API_KEY" GEMINI_BASE_URL: "https://taotoken.net/api"切换时注意三点:
- Claude Code 的 Profile 写
ANTHROPIC_*,Codex 的 Profile 写TAOTOKEN_API_KEY,不要交叉。 - 切换后新开终端,避免旧环境变量覆盖新 Profile。
- Base URL 统一用
https://taotoken.net/api,不要在末尾随手加斜杠或/v1,除非客户端文档明确要求。
这样,记忆写入通道、记忆校验通道、再读取通道都能通过 CC Switch 切到同一组 TaoToken 配置,Token 消耗也更容易按 Profile 汇总。
7. 只读环境探测:记忆校验脚本与 JSON 回执
下面是一个可运行的 Python 示例。它做三件事:读取白名单本地文件作为证据;调用 TaoToken 的 Base URL 让校验智能体返回 JSON 回执;打印校验结果和 Token 消耗。脚本没有连接生产库,也没有 MCP 直连数据库,所有读取都在本地执行。
import json import os from pathlib import Path from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url="https://taotoken.net/api", ) READ_ONLY_FILES = ["README.md", "pyproject.toml", "tests/test_smoke.py"] def read_only_evidence(paths): evidence = {} for p in paths: path = Path(p) if not path.exists(): evidence[p] = "<missing>" continue if path.is_dir(): evidence[p] = "<dir skipped>" continue text = path.read_text(encoding="utf-8", errors="ignore") evidence[p] = text[:3000] return evidence def validate_memory(candidate, evidence): system = ( "你是独立记忆校验智能体。你只能读取给定证据,不得修改环境," "不得连接生产数据库。请判断候选经验是否正确、可复用。" "只返回 JSON。" ) user = { "candidate": candidate, "evidence": evidence, "required_schema": { "correct": "boolean", "reusable": "boolean", "reason": "string", "suggested_fix": "string", }, } resp = client.chat.completions.create( model="gpt-4.1-mini", # 按 TaoToken 控制台模型名替换 messages=[ {"role": "system", "content": system}, {"role": "user", "content": json.dumps(user, ensure_ascii=False)}, ], temperature=0, response_format={"type": "json_object"}, ) verdict = json.loads(resp.choices[0].message.content) usage = { "prompt_tokens": resp.usage.prompt_tokens, "completion_tokens": resp.usage.completion_tokens, "total_tokens": resp.usage.total_tokens, } return verdict, usage if __name__ == "__main__": candidate = "在本仓库执行升级前,先跑 pytest -q 做冒烟检查。" evidence = read_only_evidence(READ_ONLY_FILES) verdict, usage = validate_memory(candidate, evidence) print("verdict:", json.dumps(verdict, ensure_ascii=False, indent=2)) print("usage:", json.dumps(usage, ensure_ascii=False, indent=2))这个脚本把“写入前校验”变成了一个明确步骤:没有校验回执,后面的持久化就不执行。correct和reusable都为true时,才把经验写入经验库;否则只记录候选和拒绝原因,不污染持久记忆。
8. 复现输出:校验后读取结果与 Token 消耗表
运行上面的脚本后,你会得到形如下面的输出结构。数值仅表示格式,实际 Token 以 TaoToken 返回的usage为准:
{ "verdict": { "correct": true, "reusable": true, "reason": "README 与 pyproject 中的测试命令支持该经验", "suggested_fix": "" }, "usage": { "prompt_tokens": 1234, "completion_tokens": 56, "total_tokens": 1290 } }接下来是“校验后读取”。经验库可以用 JSONL 保存,每行包含候选经验、证据摘要、校验回执、写入时间。下一个任务读取时,只拼接通过校验的条目:
import json from pathlib import Path def load_valid_memory(path="memory_store.jsonl"): memories = [] for line in Path(path).read_text(encoding="utf-8").splitlines(): item = json.loads(line) verdict = item.get("verdict", {}) if verdict.get("correct") is True and verdict.get("reusable") is True: memories.append(item) return memories def build_context(memories, max_items=8): selected = memories[-max_items:] blocks = [] for item in selected: blocks.append( f"经验:{item['candidate']}\n" f"校验原因:{item['verdict'].get('reason', '')}\n" f"证据来源:{', '.join(item.get('evidence_sources', []))}" ) return "\n\n".join(blocks) if __name__ == "__main__": valid = load_valid_memory() context = build_context(valid) print(context)Token 消耗可以按阶段记录成表:
| 阶段 | 调用方 | 输入 Token 来源 | 输出 Token 来源 | 是否走 TaoToken |
|---|---|---|---|---|
| 候选经验生成 | 主 Agent | 任务上下文、最近报错 | 候选经验文本 | 是 |
| 只读环境探测 | 校验 Agent | 白名单文件截断证据 | JSON 校验回执 | 是 |
| 持久化写入 | 本地脚本 | 无模型输入 | 无模型输出 | 否 |
| 校验后读取 | 主 Agent | 已通过校验的经验 | 任务提示拼接 | 是 |
这张表的用途是定位浪费:如果只读探测的输入 Token 过高,说明证据文件截断不够或白名单太宽;如果候选经验生成的输出很长,说明主 Agent 没有先压缩再校验;如果读取阶段拼接了太多旧经验,说明读取数量上限需要收紧。
9. 排障:401、404、模型名与重复写入
401 未授权
先检查YOUR_API_KEY是否已替换。Claude Code 看ANTHROPIC_AUTH_TOKEN,Codex 看TAOTOKEN_API_KEY,CC Switch 看当前激活 Profile。不要在一个客户端里混用另一套变量名。
404 路径错误
Base URL 统一使用https://taotoken.net/api。不要在末尾随手加/v1,也不要多加斜杠。Codex 的base_url和 Claude Code 的ANTHROPIC_BASE_URL都按这个值填写。
Claude Code 可用但 Codex 不通
最常见原因是把ANTHROPIC_*写进了 Codex 配置。Codex 使用config.toml中的model_provider和env_key,不是ANTHROPIC_AUTH_TOKEN。反过来,Claude Code 也不要读TAOTOKEN_API_KEY作为主认证变量,除非你额外做了映射。
CC Switch 切换后仍旧走旧配置
环境变量优先级可能高于 Profile。切换后执行env | grep -E "ANTHROPIC|TAOTOKEN|GEMINI"检查,必要时新开终端。把旧变量清理掉再启动工具。
模型名不存在
模型名要以 TaoToken 控制台模型列表为准。Claude Code 使用ANTHROPIC_MODEL,Codex 使用config.toml中的model。不要把两个客户端的模型名硬套。
Token 消耗异常
优先检查只读证据是否做了截断,例如text[:3000];检查是否把整个仓库文件都塞进了校验请求;检查校验回执是否强制 JSON,避免自然语言长回复。如果经验重复写入,用候选经验的哈希做去重,例如sha256(candidate),写入前先查本地 JSONL。
安全边界
记忆校验 Agent 只读本地白名单文件,不连接生产库,不执行写命令。需要查询数据时,由读者在本地执行只读 SQL 或命令,再把结果作为文本证据传入校验请求。不要让 Agent 直连 Oracle 或任何生产数据库。
10. CTA:模型对话 → Coding Plan → 创建 Key → Claude Code 文档
如果你准备把经验库写入和记忆校验完整跑一遍,建议按下面顺序操作:
先到模型对话页验证 TaoToken 的模型可用性和返回结构:
https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=memory_validation_chat如果要把长期记忆校验放进日常编码流程,查看 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=memory_validation_coding_plan创建自己的 API Key,替换本文所有
YOUR_API_KEY:
https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=memory_validation_api_keysClaude Code 用户再看一遍配置文档,确认
settings.json与ANTHROPIC_*写法:
https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=memory_validation_claudecode_doc
回到最初的工程动作:把经验库写入通道改到 TaoToken,Base URL 用https://taotoken.net/api;记忆校验再通过只读环境探测执行;写入前必须有 JSON 回执;写入后只读取通过校验的条目;每个阶段都记录prompt_tokens、completion_tokens和total_tokens。这样你得到的不是一条“看起来正确”的经验,而是一条有证据来源、有校验标记、有 Token 账本的可复用记忆。