
1. 401 先出现PAST-Bench 的 Episode 流水线需要独立模型入口在 PAST-Bench 的 26 个场景里跑到第 3 个 Episode 时我遇到的第一个硬错误不是记忆召回失败而是401 invalid_api_key。为了把模型入口和记忆实验解耦我先把 Key 统一到 TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_intro 。Base URL 只填https://taotoken.net/apiKey 用占位符YOUR_API_KEY。这样前台 Agent 循环、后台复盘、Episode 重跑都走同一个模型入口Token 消耗才有办法对照。PAST-Bench 的特殊之处在于它不像单轮问答那样每次只测一次模型输出。它把任务拆成 26 个场景、204 个跨会话 Episode早期 Episode 给 Agent 留下偏好、流程或修正后续 Episode 会清空当前上下文再分别观察 Memory、Procedural Reuse、Information Gathering 和 Update 四类能力。每组实验还会关掉持久化能力重跑一次用来把模型本身的能力和历史经验带来的增益拆开。对开发者来说这意味着 Token 消耗不再是“一次请求花多少”而是“一条 Episode 链上前台循环和后台复盘各花多少”。我这次的目标不是复现某个排行榜名次而是得到三份可核对材料每个 Episode 的完整日志包括 turn 数、工具调用、结束原因记忆写入与检索记录确认 Agent 是否真的经历了“写入、检索、应用”Token 消耗对照把前台 Agent Loop 与后台 Review、Compaction、Skill 提取分开记账。只要模型入口不统一这三份材料就很难横向比较。比如前台走一个供应商后台复盘走另一个供应商最后看到的“总 Token 下降”可能只是路由变化而不是记忆策略变好。把 Base URL 固定为https://taotoken.net/api之后至少模型入口这一层是稳定的剩下的变量才是 Episode 结构、记忆读写策略和持久化开关。如果你也要搭同样的验证环境可以先在 TaoToken 官网领取 Keyhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_key 。拿到 Key 后不要写进仓库放到本地环境变量或工具自己的配置里再用下面的日志结构逐步替换成你的场景。2. 把 26 场景 204 Episode 拆成三条日志流PAST-Bench 的 Episode 不是简单的“多轮聊天”。它至少包含三种时间尺度单次 Episode 内的前台循环模型推理、工具调用、观察回填、继续推理跨 Episode 的记忆持久化事实写入、技能创建、会话归档、检索命中Episode 之后的异步复盘压缩历史、提炼经验、更新长期记忆或技能文件。如果只保存一份聊天记录后面根本分不清哪些 Token 花在当前任务哪些花在“让下一次任务更聪明”。所以我建议把日志拆成三条流episode.jsonl、memory.jsonl、review.jsonl。它们可以放在同一个运行目录下但字段职责要分开。runs/ pastbench-2026-08-12/ episodes.jsonl memory.jsonl review.jsonl token_summary.csv config.snapshot.jsonepisodes.jsonl记录前台循环。每一行是一个 turn而不是一个 Episode。因为 PAST-Bench 里同一个 Episode 可能包含多次工具调用和多次模型请求按 turn 记录才能看到上下文是怎么膨胀的。{ episode_id: scene-07-ep-013, scene: 7, episode_index: 13, phase: foreground, turn: 4, model: claude-sonnet-4-5-20250929, input_tokens: 8123, output_tokens: 932, cached_tokens: 2048, tool_calls: 3, tool_names: [read_file, search_memory, write_file], stop_reason: tool_use, duration_ms: 18400 }memory.jsonl记录记忆侧动作。这里最重要的是把“写入”和“检索”都留痕并且带上后续是否被使用的证据。否则你只知道系统存了东西不知道它有没有在下一轮真正进入模型上下文。{ event: memory_write, episode_id: scene-07-ep-013, key: pref:package-manager, value: prefer-pnpm, source_turn: 3, confidence: 0.82 }{ event: memory_read, episode_id: scene-07-ep-014, query: package manager preference, hits: [ {key: pref:package-manager, score: 0.91} ], used_in_prompt: true, prompt_section: working_memory }review.jsonl记录后台复盘。很多自进化 Agent 的“额外 Token”就在这里它可能读历史 Rollout、提取稳定事实、合并冲突、创建 Skill或者更新会话摘要。这些动作不一定发生在用户等待的请求里但会真实消耗 Token也会影响下一次 Episode 的上下文。{ event: background_review, episode_id: scene-07-ep-013, input_rollouts: 12, created_skills: [skill:retry-with-backoff], updated_facts: [pref:package-manager], input_tokens: 15200, output_tokens: 1800, duration_ms: 52100 }这三条日志流建好之后PAST-Bench 的 26 个场景才不是黑盒。你可以按scene聚合也可以按episode_index看同一场景内记忆是否逐渐生效还可以把持久化关闭组的日志与开启组并排比较。最关键的是Token 消耗终于能落到“前台第几轮”和“后台第几次复盘”上而不是只看一个总数。3. Claude Code、Codex、CC Switch 的 Base URL 配置不能混用把 Key 领回来之后最容易踩的坑不是模型名而是把不同工具的配置字段混在一起。Claude Code 读ANTHROPIC_*Codex 读自己的config.tomlCC Switch 是切换层。它们可以指向同一个 Base URL但环境变量不能互相套用。3.1 Claude Codesettings.json 里写 ANTHROPIC_*Claude Code 的配置入口通常是用户目录下的settings.json。如果要把模型入口切到 TaoTokenBase URL 填https://taotoken.net/apiKey 用YOUR_API_KEY占位。不要把 Key 提交到 Git。{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: claude-sonnet-4-5-20250929, ANTHROPIC_SMALL_FAST_MODEL: claude-haiku-4-5-20251001 } }有些版本也接受ANTHROPIC_API_KEY。二选一即可不要同时填两个不同值。配置完成后在本地终端验证claude --version claude -p 只回复 ok如果出现401先检查ANTHROPIC_AUTH_TOKEN是否真的来自 TaoToken 控制台如果出现404检查 Base URL 是不是被误写成了完整接口路径。ANTHROPIC_BASE_URL一般填到域名和/api这一层由客户端自己拼接后续路径。Claude Code 更细的配置说明可以参考 TaoToken 的 Claude Code 文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_claude_doc 。里面会把 Base URL、Key 和模型入口讲得更清楚。3.2 Codexconfig.toml 不要出现 ANTHROPIC_*Codex 不读ANTHROPIC_BASE_URL。如果你把 Claude Code 的ANTHROPIC_*复制到 Codex它不会报“字段不存在”更可能表现为请求发不出去或模型入口仍然走旧配置。Codex 的正确做法是声明一个自定义 provider再把 Base URL 和环境变量名写进去。model gpt-5.1-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat然后在本地终端设置环境变量export TAOTOKEN_API_KEYYOUR_API_KEY如果你的 Codex 版本要求 Responses API请按工具文档调整wire_api字段但无论怎么改Base URL 仍然是https://taotoken.net/api环境变量名仍然是TAOTOKEN_API_KEY不要写成ANTHROPIC_AUTH_TOKEN。这样前台 Agent Loop 和后台 Review 才能共用同一个入口。3.3 CC Switch 三件套供应商、模型映射、生效配置CC Switch 的价值在于频繁切换配置。验证 PAST-Bench 时你可能需要在“持久化开启组”和“持久化关闭组”之间切换模型入口也可能需要临时换回其他供应商做对照。这时别手改多个文件用三件套管理供应商配置记录 provider id、Base URL、Key 环境变量名模型映射记录默认模型、快速模型、后台复盘模型生效配置把当前选中项写入 Claude Code 或 Codex 实际读取的位置。一个可维护的供应商片段可以长这样{ providers: [ { id: taotoken, name: TaoToken, baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, models: { default: claude-sonnet-4-5-20250929, fast: claude-haiku-4-5-20251001 } } ], activeProvider: taotoken }如果你的 CC Switch 版本字段名不同按语义映射即可供应商 id 对应 providerBase URL 对应https://taotoken.net/apiKey 环境变量对应TAOTOKEN_API_KEY默认模型对应你实际要跑的模型名。切换完成后用一条最小请求验证当前入口而不是直接开 204 个 Episode。4. 用一次 curl 确认 /api 与 /api/v1 的拼接关系在批量跑 Episode 之前先用 curl 做一次最小连通性检查。很多404不是 Key 的问题而是路径拼接问题有人把 Base URL 写成https://taotoken.net/api/v1客户端又拼了一次/v1最终得到/api/v1/v1/chat/completions。下面的命令只在你本地终端执行不要把生产库连接串塞进 Agent 环境export TAOTOKEN_API_KEYYOUR_API_KEY curl -sS https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { model: gpt-5.1-codex, messages: [ {role: user, content: 只回复pong} ], max_tokens: 8 }如果你用的是 Claude Code 这类 Anthropic 协议客户端实际拼接的可能是/v1/messages所以ANTHROPIC_BASE_URL仍然只填https://taotoken.net/api。如果客户端要求 OpenAI 兼容路径完整 URL 才会出现/api/v1/chat/completions。判断规则很简单Base URL 是根接口路径由客户端拼不要把完整接口路径写进 Base URL。常见错误可以按下面顺序排查401 invalid_api_keyKey 没设置、复制时带了空格、环境变量未导出404 not foundBase URL 多写了/v1或模型名在当前入口不存在429 too many requests并发 Episode 太高先降到 1 到 2 并发保留重试日志context_length_exceeded前台 Working Memory 太长检查 Compaction 是否发生或者检索条数是否过多。处理完连通性之后再跑一个dry-runEpisode只跑 1 个场景、2 个 Episode确认episodes.jsonl、memory.jsonl、review.jsonl都有数据。不要一上来就全量跑 204 个 Episode否则失败后很难判断是模型入口、记忆策略还是日志结构的问题。5. Token 对照表前台循环和后台复盘要分开记账PAST-Bench 的 Token 消耗之所以容易看错是因为它天然包含多次 Episode。一个自进化 Agent 可能在第一个 Episode 花很多 Token 写入记忆和创建 Skill后面几个 Episode 因为检索命中而减少探索。如果你只看总 Token会误以为“越跑越贵”或“越跑越便宜”实际上前台和后台的曲线可能完全不同。我建议至少记录下面这些字段字段说明episode_id场景与 Episode 编号phaseforeground / review / compactioninput_tokens本次请求输入output_tokens本次请求输出cached_tokens缓存命中部分如工具支持memory_reads本次检索次数memory_hits命中条数memory_writes本次写入条数skill_created是否创建技能stop_reason结束原因duration_ms耗时然后用一个本地脚本把 JSONL 汇总成 CSV。脚本只读本地日志不连接任何生产库import json import csv from collections import defaultdict from pathlib import Path run_dir Path(runs/pastbench-2026-08-12) summary defaultdict(lambda: { input_tokens: 0, output_tokens: 0, requests: 0, memory_reads: 0, memory_writes: 0, }) for line in (run_dir / episodes.jsonl).read_text(encodingutf-8).splitlines(): row json.loads(line) key (row[episode_id], row[phase]) summary[key][input_tokens] row.get(input_tokens, 0) summary[key][output_tokens] row.get(output_tokens, 0) summary[key][requests] 1 for line in (run_dir / memory.jsonl).read_text(encodingutf-8).splitlines(): row json.loads(line) key (row[episode_id], foreground) if row[event] memory_read: summary[key][memory_reads] 1 elif row[event] memory_write: summary[key][memory_writes] 1 with (run_dir / token_summary.csv).open(w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([ episode_id, phase, requests, input_tokens, output_tokens, memory_reads, memory_writes ]) for (episode_id, phase), row in sorted(summary.items()): writer.writerow([ episode_id, phase, row[requests], row[input_tokens], row[output_tokens], row[memory_reads], row[memory_writes] ])跑完以后你会得到类似这样的对照思路阶段调用次数输入 Token输出 Token记忆读取记忆写入scene-01-ep-01 前台632,4004,10002scene-01-ep-01 后台复盘115,2001,80001scene-01-ep-02 前台418,9002,70030scene-01-ep-02 后台复盘19,8001,20000如果第二个 Episode 的前台输入明显下降同时memory_reads和used_in_prompttrue增加说明记忆检索可能真的减少了重复探索。如果前台 Token 下降但后台复盘 Token 暴涨总成本未必更低这就是自进化 Agent 需要单独观察“学到的东西是否值得”的原因。对于 PAST-Bench 的四类能力你还可以分开统计Memory看跨 Episode 的事实命中率与前台 Token 变化Procedural Reuse看 Skill 创建次数与后续复用次数Information Gathering看检索轮数是否减少工具调用是否更集中Update看旧记忆被修正后后续 Episode 是否还引用过期事实。这些指标比单个总分更能解释 Token 为什么变化。6. 记忆写入/检索记录判断增益不是看总分PAST-Bench 之所以要检查 Memory 写入、Skill 创建、Session Search 和后续读取是因为“总分提升”不一定等于“记忆机制生效”。有可能是模型本身在第二个 Episode 表现更好也有可能是日志里根本没有检索命中。为了排除这种误判我建议把每个 Episode 的记忆路径写成可查询事件。一个完整的记忆链路至少包含四个事件{event: memory_candidate, episode_id: scene-07-ep-013, key: fact:api-timeout, value: 30s, reason: user_correction} {event: memory_write, episode_id: scene-07-ep-013, key: fact:api-timeout, value: 30s, confidence: 0.9} {event: memory_read, episode_id: scene-07-ep-014, query: api timeout, hits: [{key: fact:api-timeout, score: 0.88}], used_in_prompt: true} {event: memory_applied, episode_id: scene-07-ep-014, turn: 2, evidence: tool_call.arguments.timeout 30}最后一条memory_applied很重要。很多系统只记录“检索到了”但没法证明模型真的按记忆执行。你可以用工具调用参数、最终文件内容或 Episode 结束状态作为证据。没有这条证据memory_reads只能说明检索层工作不能说明 Agent 用上了历史经验。检查清单可以这样设计每个memory_write是否有明确的来源 turn每个memory_read是否记录 query、score 和是否进入 prompt每个命中记忆是否在后续工具调用或最终输出中有可验证证据冲突记忆是否被 Update 事件覆盖而不是同时留在检索结果里持久化关闭组是否确实没有memory_write和跨 Episodememory_read。如果你发现“检索次数很多但应用证据为零”大概率是检索结果进入了上下文却没有被模型用于决策或者被更近的历史挤压掉了。这时不要急着加更多记忆而是先检查 Working Memory 的装配顺序系统指令、当前任务、近期 turn、检索记忆分别占了多少 Token。PAST-Bench 测的是跨会话记忆不是“存得越多越好”。7. 持久化开关对照组如何跑出可解释的增益PAST-Bench 的每组实验都会关掉持久化能力重跑一次这是整个验证里最有价值的设计之一。因为它把“模型本身能力”和“历史经验增益”拆开了。你也应该为自己跑的 26 个场景建立两组目录runs/ pastbench-persistent-on/ episodes.jsonl memory.jsonl review.jsonl token_summary.csv pastbench-persistent-off/ episodes.jsonl memory.jsonl review.jsonl token_summary.csv两组之间只允许一个变量不同持久化开关。模型入口都走https://taotoken.net/apiKey 都来自同一个 TaoToken 控制台Episode 顺序、场景数量、并发度和超时设置保持一致。否则你比较的就不是记忆增益而是环境噪声。在关闭组里memory.jsonl仍然可以存在但应该只记录“未启用持久化跳过写入/检索”这类事件在开启组里才是真正的写入、检索、应用链路。跑完后按场景聚合成对照表场景持久化完成 Episode前台 Token后台 Token记忆应用次数scene-07off8142,00000scene-07on8121,50026,4005scene-12off898,70000scene-12on8102,30031,2001这张表能直接告诉你两件事开启持久化后前台省下的 Token 是否覆盖后台复盘开销记忆应用次数少的场景是否反而增加了总成本。对于 Update 类场景你还应该检查旧记忆是否被覆盖。如果开启持久化后仍然后续 Episode 引用了已被修正的事实那么问题不在 Token而在写入合并策略。当需要反复切换供应商或配置时用 CC Switch 管好三件套别在 Claude Code 和 Codex 之间复制环境变量。Claude Code 的ANTHROPIC_BASE_URL可以指向https://taotoken.net/apiCodex 的config.toml里则要用自己的model_provider和env_key。两者可以共享同一个 Key但不能共享字段名。配置稳定后PAST-Bench 的 Episode 日志才有可比性。如果你还没有开始搭环境可以直接从 TaoToken 官网进入https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_env 。先领 Key再把 Base URL 写到对应工具的模型入口然后跑一个 2 Episode 的小样本。小样本能跑通三条日志流再扩到 26 个场景。8. 文末 CTA模型对话、Coding Plan、API Keys、Claude Code 文档如果你只想先确认模型入口是否可用可以打开模型对话页面直接用 TaoToken 的 Key 做一次最小请求https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_chat 。这一步不需要改代码适合在配置 Claude Code 或 Codex 之前确认 Key、Base URL 和模型名。如果你准备长期跑 PAST-Bench 这类多 Episode 验证建议看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_plan 。它会比临时 Key 更适合高频前台循环和后台复盘并存的场景。Key 管理和创建入口在 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_keys 。创建后把 Key 放到本地环境变量例如TAOTOKEN_API_KEY再让 Claude Code、Codex 或你的 Episode Runner 读取。不要把 Key 写进episodes.jsonl也不要把生产库连接串交给 Agent。Claude Code 的配置细节可以参考https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentpastbench_doc 。记住三件事Claude Code 用settings.json和ANTHROPIC_*Codex 用config.tomlBase URL 统一填https://taotoken.net/api不要带 UTM也不要带/v1。回到 PAST-Bench。26 个场景、204 个跨会话 Episode 真正要验证的不是某一次回答看起来多聪明而是 Agent 能不能把早期 Episode 里的偏好、流程和修正稳定地带到后续任务里。要证明这一点你需要 Episode 日志、记忆写入/检索记录和 Token 消耗对照。TaoToken 在这里只做 Key 入口和统一 Base URL不替你做记忆策略也不改变 Harness 结构。把入口固定下来把日志拆开把持久化开关跑成对照组你才能判断一次“自进化”到底是模型变强了还是运行时真的记住了。