Agent 长任务总丢目标?TaoToken Key 跑通预算、压缩与 todo-state 复述 📅 发布时间:2026/9/18 5:15:37 👁 浏览次数: 1. Agent 长任务跑飞时先把 TaoToken Key 和 Base URL 接进调用链当 Agent harness 跑到第 30 轮突然把“修复订单幂等”改成“重写登录页”或者请求直接返回 context_length_exceeded、工具输出被截断、todo 列表被挤出窗口先别急着换模型。长任务丢目标通常不是模型智力问题而是上下文预算、卸载、压缩、todo-state 复述和跨会话记忆没有形成闭环。把这条调用链接到 TaoToken 后可以先用同一套 Key 和 Base URL 做可观测压降先到 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentintro 拿 Key再把 Base URL 配成 https://taotoken.net/api接入你现有的 Agent 调用链。下面从预算表、压缩日志、todo-state 模板到 Claude Code / Codex / CC Switch 配置给一套可跟做的落地步骤。先配置环境变量。Key 用 YOUR_API_KEY 占位不要把真实 Key 写进代码仓库export TAOTOKEN_API_KEYYOUR_API_KEY export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你的 Agent 调用链基于 OpenAI 兼容 SDK可以直接这样初始化import os from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlhttps://taotoken.net/api, ) resp client.chat.completions.create( modelYOUR_MODEL_ID, messages[ {role: system, content: 你是长任务 Agent。每轮先复述 TODO State再执行下一步。}, {role: user, content: 读取 TODO State只输出下一步动作。}, ], max_tokens256, ) print(resp.choices[0].message.content)模型 ID 从 TaoToken 的模型对话页选择不要硬编码不确定的模型名。裸 curl 调试可以用curl -sS $TAOTOKEN_BASE_URL/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: YOUR_MODEL_ID, messages: [ {role: system, content: 你是长任务 Agent。}, {role: user, content: 只输出 OK} ], max_tokens: 16 }能返回 OK说明 Key、Base URL、模型路由至少通了。接下来才是上下文工程。2. 上下文预算控制表先量化哪几段在吃 Token长任务上下文不是一块铁板。它至少包括system prompt、工具描述、历史对话、工具原始输出、todo-state、跨会话记忆、当前用户输入。真正导致目标丢失的往往不是当前输入太长而是历史工具输出和旧对话把 todo-state 挤到窗口边缘。先在调用链外层加一个预算对象。下面是一份可以直接落到 YAML / JSON 配置里的预算控制表配置项作用建议起始值观测指标model_context_window当前模型窗口按模型填写请求前校验max_input_tokens输入硬上限窗口的 60%超过即触发卸载reserve_output_tokens输出预留窗口的 20%防止输出被截断tool_output_max_tokens单次工具输出截断2000工具返回长度分布history_keep_turns保留最近对话轮数8旧步骤重复率compress_trigger_ratio压缩触发比例0.75压缩次数 / 请求数unload_policy卸载策略tool_output_summary卸载后 token 降幅todo_state_every_turnstodo 复述间隔2目标漂移率memory_write_policy写记忆条件on_goal_change_or_blocker跨会话恢复成功率落地配置示例context_budget: model_context_window: 128000 max_input_tokens: 76800 reserve_output_tokens: 25600 tool_output_max_tokens: 2000 history_keep_turns: 8 compress_trigger_ratio: 0.75 unload_policy: tool_output_summary todo_state_every_turns: 2 memory_write_policy: on_goal_change_or_blocker在每次请求前计算预算def estimate_tokens(text: str) - int: # 粗略估算中文约 1 字 1 token英文约 4 字符 1 token zh sum(1 for ch in text if \u4e00 ch \u9fff) other len(text) - zh return zh max(other // 4, 1) def assert_budget(messages, budget): input_tokens sum(estimate_tokens(m[content]) for m in messages) if input_tokens budget[max_input_tokens]: raise RuntimeError(finput too large: {input_tokens}) return input_tokens预算不是越紧越好。太紧会让 Agent 频繁压缩反而丢失事实。建议先记录一周日志再按 P95 输入 token 调整。想直接拿 Key 做一轮对照可以从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentbudget_setup 进入控制台创建独立 Key避免和线上生产 Key 混用。3. 压缩与卸载把工具输出从“全文回灌”改成“结构化摘要”上下文溢出最容易被忽略的来源是工具输出。文件内容、日志、网页正文、SQL 结果、测试输出如果每次都全文塞回消息列表几轮就能吃满窗口。压缩不是让模型随便总结而是固定字段抽干目标、事实、待办、阻塞、下一步。压缩提示词模板你是一个上下文压缩器。只保留 1. 当前目标与验收标准 2. 已确认的事实、文件路径、函数名、配置项 3. 未完成的子任务和阻塞项 4. 下一步动作 丢弃寒暄、重复日志、已解决错误的完整堆栈、与目标无关的探索。 输出 JSON {goal:,acceptance:,facts:[],todos:[],blockers:[],next_action:}卸载策略可以分三层工具输出超过 tool_output_max_tokens 时先截断尾部再调压缩器生成结构化摘要。历史对话超过 history_keep_turns 时只保留最近 N 轮原文更早内容合并成 facts 和 todos。todo-state 永远不参与压缩每轮复述时重新注入保证目标在窗口中心。压缩前后 token / 请求日志对照可以这样记录轮次输入策略输入 token输出 token请求数目标保持备注1原始全量152309201否第 9 轮开始重复旧日志2仅截断工具输出98008801部分仍丢失验收标准3截断 结构化压缩62008701是todo 列表稳定4压缩 todo 复述59009101是目标漂移下降5压缩 todo 跨会话记忆51008501是可跨会话恢复这些数字不是固定答案而是让你先建立对照基线。可以用一个本地脚本解析 traceimport json def rough_tokens(text: str) - int: zh sum(1 for ch in text if \u4e00 ch \u9fff) return zh max((len(text) - zh) // 4, 1) def load_metrics(path: str): rows [] with open(path, r, encodingutf-8) as f: for line in f: item json.loads(line) rows.append({ turn: item[turn], strategy: item[strategy], input_tokens: rough_tokens(item[input]), output_tokens: rough_tokens(item[output]), requests: item.get(requests, 1), goal_aligned: item.get(goal_aligned, False), }) return rows for row in load_metrics(agent_trace.jsonl): print(row)关键看三个指标输入 token 是否随轮次线性增长、请求数是否因压缩重试翻倍、目标保持是否在压缩后下降。如果压缩后输入降了但目标保持也降说明压缩丢掉了验收标准需要把 acceptance 字段设为不可丢弃。4. todo-state 复述模板每两轮强制把目标拉回窗口中心todo-state 不是普通 TODO 列表而是 Agent 每轮行动前的“目标对齐检查”。它应该短、稳定、可复述。建议固定字段# TODO State - 目标不可变... - 验收标准... - 当前子目标... - 已完成... - 未完成... - 阻塞项... - 下一步动作只输出一个... - 本轮禁止偏移检查本轮输出是否仍服务于目标是/否 - 需要卸载... - 需要写入跨会话记忆...把它注入每轮请求TODO_STATE_TEMPLATE # TODO State - 目标不可变{goal} - 验收标准{acceptance} - 当前子目标{subgoal} - 已完成{done} - 未完成{pending} - 阻塞项{blockers} - 下一步动作{next_action} - 本轮禁止偏移检查本轮输出是否仍服务于目标{aligned} def build_messages(goal, acceptance, state, user_input): todo_state TODO_STATE_TEMPLATE.format( goalgoal, acceptanceacceptance, subgoalstate.get(subgoal, ), done, .join(state.get(done, [])), pending, .join(state.get(pending, [])), blockers, .join(state.get(blockers, [])), next_actionstate.get(next_action, ), aligned是/否, ) return [ {role: system, content: 你是长任务 Agent。每轮先复述 TODO State再执行下一步。}, {role: user, content: f{todo_state}\n\n用户输入{user_input}}, ]每两轮复述一次或者在以下事件后立即复述工具调用连续失败、目标被修改、压缩触发、跨会话恢复。复述不是让模型抄一遍而是让它在生成行动前先做一致性判断。如果模型输出“本轮禁止偏移检查否”就停止执行回到目标对齐。5. 跨会话记忆把长期状态搬出聊天窗口本地执行 SQL/命令上下文窗口再大也不适合存长期状态。跨会话记忆只存三类目标、事实、阻塞。其他内容可以丢。最小实现用本地 SQLite 即可。下面命令由读者在本地执行不要让 Agent 直连生产库或 Oraclesqlite3 agent_memory.db CREATE TABLE IF NOT EXISTS memory(id INTEGER PRIMARY KEY, scope TEXT, key TEXT, value TEXT, updated_at TEXT); sqlite3 agent_memory.db INSERT INTO memory(scope,key,value,updated_at) VALUES(session,goal,修复订单幂等,datetime(now)); sqlite3 agent_memory.db INSERT INTO memory(scope,key,value,updated_at) VALUES(session,blocker,等待退款状态机确认,datetime(now)); sqlite3 agent_memory.db SELECT key,value FROM memory WHERE scopesession;在 Python 里读写import sqlite3 from datetime import datetime def save_memory(db_path, scope, key, value): with sqlite3.connect(db_path) as conn: conn.execute( INSERT INTO memory(scope,key,value,updated_at) VALUES(?,?,?,?), (scope, key, value, datetime.utcnow().isoformat()), ) def load_memory(db_path, scope): with sqlite3.connect(db_path) as conn: rows conn.execute( SELECT key,value FROM memory WHERE scope? ORDER BY updated_at DESC, (scope,), ).fetchall() return {k: v for k, v in rows}跨会话恢复时只把目标、验收标准、未完成项、阻塞项注入上下文不要把所有历史原文拉回来。这样即使换了会话Agent 也能从记忆里恢复方向。6. Claude Code、Codex、CC Switch 接入 TaoToken 的三套配置现有 Agent 调用链切供应商时最怕把 Claude Code 的环境变量套到 Codex 上。下面分开写。Claude Code 用 settings.json / ANTHROPIC_*{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_CLAUDE_MODEL_ID, ANTHROPIC_SMALL_FAST_MODEL: YOUR_SMALL_MODEL_ID } }Codex 用 config.toml不要写 ANTHROPIC_*model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatCC Switch 三件套可以直接按表填字段填写值ProviderTaoTokenBase URLhttps://taotoken.net/apiAPI KeyYOUR_API_KEYModel从模型对话页选择配置完成后先跑一个最小请求验证 Key 和 Base URL再接入长任务 harness。需要新 Key 时从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcc_switch 进入控制台创建不要复用测试 Key 到生产 Agent。7. 可复现排查压缩前后 token/请求日志对照与预算告警当长任务再次丢目标按下面顺序排查现象可能原因检查项处理第 N 轮重复旧步骤历史消息未卸载history_keep_turns降到 6-8工具输出占满窗口工具返回未截断tool_output_max_tokens截断并结构化摘要目标被挤出todo-state 未复述todo_state_every_turns每 2 轮强制复述跨会话恢复后失忆记忆未落盘memory_write_policy目标/阻塞变更时写入token 消耗突增压缩未触发compress_trigger_ratio0.75 触发压缩请求数翻倍压缩后重试日志 requests 字段合并重试缓存摘要建议每次请求记录一行 JSONL{turn:12,strategy:compresstodounload,input_tokens:6120,output_tokens:880,requests:1,goal_aligned:true}对比压缩前后日志时重点不是看单次 token 最低而是看“输入 token 是否随轮次平稳、目标保持是否稳定、请求数是否可控”。如果压缩把 acceptance 字段丢掉短期 token 会下降长期会因返工把总消耗拉更高。8. CTA模型对话 → Coding Plan → 创建 Key → Claude Code 文档如果你已经有一个长任务 Agent建议按这个顺序接入 TaoToken先到模型对话页选模型https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchat_cta需要 Coding 场景时看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_plan_cta创建独立 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keys_ctaClaude Code 接入细节看文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_code_doc_cta最后再给一个最小闭环把 Base URL 固定为 https://taotoken.net/apiKey 用 YOUR_API_KEY预算表、todo-state 模板、压缩日志和跨会话记忆都落到本地文件。这样长任务即使跑到几十轮也能在每次请求前看清哪些上下文在消耗 Token哪些该卸载哪些必须复述。更多入口可以从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentfinal_cta 进入。