Loop+Harness 拆解:清华自进化 Agent 论文的工程化落地与 TaoToken 接入实践
1. 从一次“越跑越笨”的 Agent 说起Loop 与 Harness 到底在解决什么如果你最近在折腾编码类 Agent大概率遇到过这种场景同一个项目第一轮对话它能把重构任务拆得明明白白第二轮换个文件就又开始犯低级错误第三轮甚至把之前已经修好的接口又改回去了。你明明感觉它“应该学到点什么”但实际表现是每一轮都在从零推理经验像沙子一样从指缝漏走。这不是模型不够强而是绝大多数 Agent 产品还停留在“预训练 固定提示词 静态工具”的模式。模型上线那一刻能力就冻结了交互产生的轨迹用完即弃。清华和 Frontis.AI 联合发布的那篇《Self-Improving Agents in the Era of Experience》把这个矛盾讲得很透经验时代的核心逻辑是反过来的——Agent 的价值不再取决于预训练数据集有多大而取决于部署运行过程中持续生成的交互经验能不能被提炼、沉淀、再反哺回系统本身。这篇论文里有两个词反复出现也是整个自进化体系的骨架Loop和Harness。Loop 是循环但它不是简单的“思考-行动-观察”任务闭环。论文把 Agent 的演进分成三代第一代是任务闭环任务结束循环终止记忆清空第二代是跨任务复用引入持久记忆和技能库但框架全靠人工配置上线后不会自己更新第三代是运行时系统把 Harness 本身变成可被 Agent 修改和进化的对象。三代演进的核心变化就是循环从“任务内闭环”扩展成了“跨任务、跨部署的持续进化循环”。Harness 则是这个循环的载体。一个部署后的智能体系统由四部分决定基座模型、可变的状态化 Harness、用户侧目标与反馈、环境侧工具与执行状态。模型权重更新一次要数天和数百万美元而 Harness 的状态在部署期间可以被快速检查、修改和治理。它直接决定了模型能看到什么、能做什么、能捕获什么证据、哪些交互能变成可复用的经验。所以这篇不是纯论文解读我想从工程落地视角把它拆开Loop 怎么配、Harness 怎么校验、自进化和元进化的流程怎么用可复制的配置片段跑起来以及怎么通过统一的 Key/API 通道完成一次端到端验证。适合谁看有后端基础、正在做 Agent 应用开发、想让自己的 Agent 从“一次性工具”变成“越用越强”的工程师。下面所有配置和脚本都可以直接抄。2. TaoToken 前置统一 Key/API 通道怎么接进自进化 Loop在讲 Loop 和 Harness 的具体配置之前得先把“通道”这件事说清楚。自进化 Agent 的一个核心特征是它会在运行过程中频繁调用模型——提炼经验要调、生成技能要调、校验轨迹要调、元层调度还要调。如果每个环节都散落在不同的 Key、不同的 Base URL、不同的计费口径上Harness 的状态治理根本无从谈起因为你连“这一轮进化消耗了多少、走了哪个模型”都追踪不了。我试过把模型调用统一到一个入口Harness 的日志和归因才真正可读。TaoToken 在这里扮演的就是这个统一通道的角色一个 Key 覆盖多种模型Base URL 固定调用格式兼容主流 SDK。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址后面不加任何 UTM 参数直接写进配置里就行。为什么自进化场景特别需要这个因为论文里把进化分成两条路径快速路径是在 Harness 层面更新技能和记忆便宜、快速、可逆慢速路径是把累积经验内化到模型参数昂贵、缓慢、几乎不可逆。工程落地时99% 的迭代都发生在快速路径上——也就是反复调用模型来提炼技能、压缩记忆、校验轨迹。这条路径的调用频次极高如果通道不统一成本和质量都没法归因。具体到操作你需要先拿到 Key。进入控制台创建 API Key地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。创建完之后把 Base URL 和 Key 写进环境变量后面所有脚本都从这里读export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-你的key这里有个坑要提前说Base URL 结尾不要带斜杠也不要自己拼/v1SDK 会按标准路径去拼。我见过有人写成https://taotoken.net/api/v1/结果 404排查半天以为是 Key 的问题。另外如果你用的是 OpenAI 兼容的 SDKbase_url直接填上面那个地址即可。模型选择上自进化 Loop 里不同环节对模型的要求不一样。提炼技能、生成结构化 JSON 这种任务用响应快、指令遵循好的模型就够元层调度、复杂轨迹归因这种需要长上下文推理的再上更强的模型。TaoToken 的好处是同一个 Key 可以切换 Model IDHarness 里只需要改一个字段不用换通道。模型对话的入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 可以先在那里试一下不同模型对同一段轨迹的提炼效果再决定 Loop 里用哪个。如果你打算长期跑编码类 Agent 或者让 Agent 自己做元进化调度调用量会比较大可以看下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 里面有完整的参数说明和错误码对照排障的时候比猜要快得多。把通道统一之后Harness 才能在每个 Loop 结束时把“这一轮用了哪个模型、消耗多少、产出了什么技能、记忆有没有更新”这些信息写进结构化日志。没有这一步后面的自进化验证就是空中楼阁。3. 可复制配置Loop 循环片段与 Harness 校验脚本这一节是全文的核心直接给可复制的配置。我把它拆成三块Loop 的循环配置、Harness 的状态文件、以及校验脚本。三块拼起来就是一个最小可运行的自进化闭环。先说 Loop。论文里把进化路径分成 Skills、记忆、环境、参数固化、元进化五层工程落地时不需要一次全上先从 Skills 和记忆这两层做起因为它们都在 Harness 层面可逆、便宜、好调试。下面这个loop_config.json定义了一个 Loop 的完整流程{ loop_id: self-evolve-coding-agent, base_url: https://taotoken.net/api, model_id: claude-sonnet-4-5, max_iterations: 8, stages: [ { name: interact, description: 与用户/环境交互产生轨迹, capture: [user_input, tool_calls, tool_results, final_output] }, { name: extract, description: 从轨迹中提炼有效经验, prompt_template: 从以下轨迹中提炼可复用的操作步骤输出 JSON{trace}, output_schema: { skill_name: string, steps: array, preconditions: array, failure_signals: array } }, { name: validate, description: Harness 校验提炼结果, checks: [schema_valid, no_secret_leak, step_executable] }, { name: commit, description: 写入技能库或记忆存储, target: harness_state.json, rollback_on_fail: true } ], harness: { state_file: ./harness_state.json, skill_dir: ./skills, memory_dir: ./memory, log_file: ./loop_trace.jsonl } }这个配置里几个关键点值得展开。stages的顺序就是 Loop 的执行顺序交互产生轨迹、提炼经验、Harness 校验、提交到状态文件。rollback_on_fail是快速路径可逆性的体现——校验不过就回滚不会污染技能库。output_schema强制提炼结果结构化这是后面 Harness 能做自动校验的前提。然后是 Harness 的状态文件harness_state.json它记录当前 Agent 的“能力底座”{ version: 0.1.0, updated_at: 2026-01-15T10:30:00Z, skills: [ { name: fix-typescript-import-order, steps: [读取 tsconfig, 按 paths 排序 import, 运行 tsc --noEmit], preconditions: [项目使用 TypeScript, 存在 tsconfig.json], failure_signals: [tsc 报 TS2307], hit_count: 0, last_used: null } ], memory: { user_preferences: {}, failure_lessons: [] }, evolution_log: [] }注意hit_count和last_used这两个字段。论文里提到技能库要能“淘汰长期闲置冗余技能”这两个字段就是淘汰策略的依据。Harness 每次使用技能后更新它们元层调度时根据命中率决定保留还是清理。接下来是 Harness 校验脚本harness_validate.py这是整个闭环里最容易被忽略但最重要的一环import json import os import re from jsonschema import validate, ValidationError SKILL_SCHEMA { type: object, required: [skill_name, steps, preconditions, failure_signals], properties: { skill_name: {type: string, minLength: 3}, steps: {type: array, minItems: 1}, preconditions: {type: array}, failure_signals: {type: array} } } SECRET_PATTERN re.compile(r(sk-[A-Za-z0-9]{16,}|AKIA[0-9A-Z]{16})) def check_schema(skill): try: validate(instanceskill, schemaSKILL_SCHEMA) return True, schema_ok except ValidationError as e: return False, fschema_fail: {e.message} def check_secret_leak(skill): raw json.dumps(skill, ensure_asciiFalse) if SECRET_PATTERN.search(raw): return False, secret_leak_detected return True, no_secret def check_step_executable(skill): for step in skill[steps]: if not isinstance(step, str) or len(step.strip()) 4: return False, fstep_too_short: {step} return True, steps_ok def validate_skill(skill): results [] for fn in (check_schema, check_secret_leak, check_step_executable): ok, msg fn(skill) results.append({check: fn.__name__, pass: ok, msg: msg}) if not ok: break return all(r[pass] for r in results), results if __name__ __main__: with open(./pending_skill.json, r, encodingutf-8) as f: skill json.load(f) ok, detail validate_skill(skill) print(json.dumps({pass: ok, detail: detail}, ensure_asciiFalse, indent2)) if not ok: os._exit(1)这个脚本做了三件事schema 校验、密钥泄露检测、步骤可执行性检查。密钥泄露检测这条特别重要论文里提到的“技能供应链攻击”和“记忆投毒”很多都是从提炼环节把敏感信息写进技能库开始的。Harness 作为经验进化的核心载体必须在提交前把这道关。把这三块拼起来一个最小的自进化 Loop 就跑起来了交互产生轨迹 → 调模型提炼技能 → Harness 校验 → 通过则写入harness_state.json不通过则回滚。整个过程都在快速路径上可逆、可观测、可归因。4. 验证请求跑一次端到端自进化并看结果配置写完了得实际跑一次才知道对不对。这一节给一个完整的端到端验证流程从发请求到看结果每一步都有可复制的命令。先准备一个待提炼的轨迹文件trace.json模拟一次真实的编码交互{ user_input: 帮我修复 src/utils/date.ts 里的时区转换错误, tool_calls: [ {tool: read_file, args: {path: src/utils/date.ts}}, {tool: run_test, args: {cmd: npm test -- date.spec.ts}} ], tool_results: [ {tool: read_file, output: export function toLocal(d: Date) { return d.toISOString(); }}, {tool: run_test, output: FAIL: expected 2026-01-15T10:00:0008:00, got 2026-01-15T02:00:00Z} ], final_output: 将 toISOString 替换为 toLocaleString 并传入 timeZone 参数 }然后写一个调用脚本run_loop.py把轨迹发给模型提炼技能import json import os from openai import OpenAI client OpenAI( base_urlos.environ[TAOTOKEN_BASE_URL], api_keyos.environ[TAOTOKEN_API_KEY] ) with open(./trace.json, r, encodingutf-8) as f: trace json.load(f) prompt f从以下轨迹中提炼可复用的操作步骤严格输出 JSON字段为 skill_name, steps, preconditions, failure_signals。 轨迹{json.dumps(trace, ensure_asciiFalse)} resp client.chat.completions.create( modelclaude-sonnet-4-5, messages[{role: user, content: prompt}], response_format{type: json_object} ) skill json.loads(resp.choices[0].message.content) with open(./pending_skill.json, w, encodingutf-8) as f: json.dump(skill, f, ensure_asciiFalse, indent2) print(json.dumps(skill, ensure_asciiFalse, indent2))跑之前确认环境变量已经导出然后执行python run_loop.py正常的话你会看到类似这样的输出{ skill_name: fix-timezone-conversion, steps: [ 读取目标文件确认当前时间转换实现, 运行相关测试定位失败断言, 将 toISOString 替换为带 timeZone 参数的 toLocaleString, 重新运行测试确认通过 ], preconditions: [项目使用 TypeScript, 存在对应测试文件], failure_signals: [测试断言时区偏移不匹配] }拿到pending_skill.json之后跑 Harness 校验python harness_validate.py校验通过会输出pass: true然后就可以提交到状态文件。提交这一步建议单独写个小脚本把 pending 技能合并进harness_state.json同时更新evolution_logimport json from datetime import datetime, timezone with open(./pending_skill.json, r, encodingutf-8) as f: skill json.load(f) with open(./harness_state.json, r, encodingutf-8) as f: state json.load(f) skill[hit_count] 0 skill[last_used] None state[skills].append(skill) state[updated_at] datetime.now(timezone.utc).isoformat() state[evolution_log].append({ action: add_skill, skill_name: skill[skill_name], at: state[updated_at] }) with open(./harness_state.json, w, encodingutf-8) as f: json.dump(state, f, ensure_asciiFalse, indent2) print(committed:, skill[skill_name])到这里一次完整的自进化循环就跑完了轨迹 → 提炼 → 校验 → 提交。你可以再跑一次run_loop.py换一个类似的时区问题轨迹观察模型提炼出的技能是否和已有的fix-timezone-conversion重复。如果重复说明 Harness 需要一个去重策略如果互补说明技能库在正向增长。这就是论文里说的“正向泛化增益”的工程化观测方式。想验证模型在不同任务上的提炼质量可以到模型对话页面手动试几段轨迹https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。把同一段轨迹发给不同模型对比输出的steps粒度和failure_signals准确度再决定 Loop 里固定用哪个 Model ID。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth自进化 Loop 跑不起来90% 的问题集中在四类报错上。这一节按真实报错逐个拆每个都给定位方法和修复动作。401 Unauthorized。这个最常见但原因不止一种。先确认TAOTOKEN_API_KEY有没有正确导出echo $TAOTOKEN_API_KEY看是不是空。如果 Key 没问题检查 Base URL 是不是写成了https://taotoken.net/api/带尾斜杠或者自己拼了/v1。SDK 会按标准路径拼多一段就 401 或 404。还有一种情况是 Key 创建后没复制完整前后有空格用export的时候被截断。修复方式重新到控制台复制一次地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 粘贴时注意不要带换行。local proxy failed。这个报错通常出现在你本地配了某些网络层SDK 请求被拦截。先检查环境变量里有没有HTTP_PROXY、HTTPS_PROXY、ALL_PROXY有的话临时 unset 掉再跑。另外确认base_url是https://taotoken.net/api不要写成http。如果是在容器里跑检查容器的 DNS 和出网策略curl -I https://taotoken.net/api看能不能通。这个报错和 Key 无关纯粹是请求没发出去。reading choices of undefined。这是 OpenAI SDK 的典型报错意思是resp.choices是 undefined通常发生在resp本身是错误响应的时候。根因一般是模型名写错了或者response_format不被该模型支持。先确认model字段填的是有效的 Model ID可以在模型对话页面确认https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。如果模型不支持json_object格式去掉response_format改成在 prompt 里强调“只输出 JSON”然后在代码里做一次json.loads的容错。OAuth 相关报错。如果你用的是 Claude Code 或者 Codex 这类带 OAuth 流程的工具报错信息里出现OAuth token expired或invalid_grant说明本地缓存的凭证过期了。这类工具通常把凭证存在~/.config或~/.codex/auth.json下。以 Codex 为例auth.json里需要同时配好三件套Base URL、Key、Model ID。Base URL 填https://taotoken.net/apiKey 填控制台创建的 KeyModel ID 填你要用的模型。三个字段缺一个都会走到 OAuth 回退逻辑然后失败。Claude Code 的配置类似在 settings 里把ANTHROPIC_BASE_URL指向统一通道ANTHROPIC_API_KEY填 Key模型名按文档填。接入文档里有完整的字段对照https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。排障的时候有个通用技巧把 SDK 的日志级别调到 debug看实际发出的请求 URL 和 header。很多问题看一眼真实请求就清楚了比猜快得多。另外Harness 的loop_trace.jsonl里记录了每一轮的模型调用和结果出问题时先看这个日志能快速定位是提炼环节挂了还是校验环节挂了。6. 语义一致 CTA把自进化 Loop 接到你的工程里写到这里Loop 和 Harness 的协作机制、可复制配置、端到端验证、常见报错都过了一遍。回到论文本身它最有价值的地方不是提出了多少新概念而是把“Agent 怎么越用越强”这件事拆成了可工程化的层次快速路径改 Harness慢速路径改参数元层决定谁来改。工程落地时先把快速路径跑通也就是技能和记忆这两层投入产出比最高。如果你要接着往下做几个方向可以选。想先把模型调用通道统一、把 Key 和 Base URL 配好直接去控制台创建 Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。想对照完整参数和错误码把 Harness 校验脚本写得更健壮看接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。想先手动试几段轨迹、对比不同模型的提炼质量再决定 Loop 里用哪个 Model ID去模型对话页面https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。如果你打算长期跑编码类 Agent、让元层自己做调度和归因调用量会上来可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。最后留一个我踩过的坑Harness 的状态文件一定要纳入版本管理每次提交技能都打一个 commit。自进化最怕的不是不进化而是进化错了方向还不自知。有了版本历史回滚就是一条git revert的事这比任何安全审计都实在。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →