
1. 从写 Prompt 到写循环编程智能体的工作方式变了如果你最近在折腾编程智能体大概率会有一种疲惫感每开一个新会话都要把项目背景、构建命令、代码规范重新讲一遍每完成一个小任务都要手动敲下一句提示词等它返回再敲下一句。你像一个不停按按钮的人智能体只是那个按钮后面的工具。Loop Engineering循环工程想解决的正是这件事——你不再亲手写每一条 Prompt而是设计一套会自己写 Prompt、自己找活、自己检查结果的循环系统。这篇文章聚焦编程智能体场景下的 Loop Engineering 落地路径。我会从settings.json和config.toml这两个配置文件骨架出发把「写 Prompt」升级为「设计循环」并交付一套可复制的配置骨架和循环触发验证动作让你在本地跑通一次完整循环。适合已经用过 Claude Code、Codex 这类编程智能体想进一步把重复劳动交给循环的开发者。核心检索词先摆出来Loop Engineering 是什么、编程智能体循环怎么搭、settings.json 和 config.toml 怎么配、循环触发怎么验证。一个循环需要五样东西外加一个记事的地方自动化任务负责按计划触发工作树负责隔离并行技能负责固化项目知识插件和连接器负责接上你现有的工具子智能体负责让出主意的和检查的分开。第六样是记忆——一个活在单次对话之外的 markdown 文件或看板记住哪些做完了、接下来该做啥。模型在两次运行之间会把一切忘光所以记忆必须落在磁盘上而不是待在上下文里。智能体会忘但代码仓库不会。下面我按「先统一 Key再搭骨架再跑通验证」的顺序来写。所有模型调用统一走 TaoToken 的 API这样你在 Claude Code、Codex 或自建脚本之间切换时不用反复改鉴权配置。2. 前置准备用 TaoToken 统一 Key 打通模型调用Loop Engineering 的第一个现实问题是循环会高频调用模型如果每个工具、每个子智能体都配一套不同的 Key 和端点维护成本会迅速超过收益。我的做法是先用 TaoToken 把模型调用统一到一套 Key 上再让循环里的各个角色共用它。TaoToken 在这里扮演的角色是统一的模型接入层。你可以在官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 了解它的能力范围API 端点是 https://taotoken.net/api这个地址不加 UTM 参数。它支持对话模型调用也支持 Coding Plan 这类面向长期编码场景的方案具体入口我放在后面的 CTA 分流里。先拿到 Key。进入控制台创建 API Key建议按用途分名字比如loop-main、loop-verifier这样后面排查是哪个子智能体在烧 token 时一目了然。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。拿到 Key 之后先做一次最小连通性验证确认端点和鉴权没问题再往循环骨架里塞。这一步别省我见过太多人把配置写进循环之后报错信息被循环吞掉排查半天才发现是 Key 没生效。export TAOTOKEN_API_KEYsk-你的key curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-20250514, messages: [{role: user, content: 只回复 ok}], max_tokens: 16 }返回里能看到choices[0].message.content是ok说明链路通了。如果返回 401检查 Key 是否复制完整如果返回 404检查端点路径是否写成了/v1/chat/completions而不是别的变体。这一步通了后面的循环才有稳定的地基。注意循环会放大 token 消耗。先用小max_tokens和低频节奏跑通再逐步放开。你是 token 富裕户还是贫困户实际花销可能天差地别。3. 可复制配置settings.json 与 config.toml 循环骨架这一节是全文的技术核心。我把循环拆成两个配置文件settings.json管调度、记忆路径和验证开关config.toml管子智能体定义和模型参数。两者配合构成一个最小可跑的循环骨架。3.1 settings.json调度与记忆settings.json负责回答三个问题多久跑一次、状态记在哪、验证者是谁。下面是我反复在用的一份骨架你可以直接复制后改路径。{ loop: { name: nightly-refactor-loop, schedule: 0 2 * * *, maxRounds: 8, stopCondition: test/auth 下所有测试通过且 lint 干净, memoryFile: .loop/state.md, triageInbox: .loop/triage.md }, model: { provider: taotoken, baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, mainModel: claude-sonnet-4-20250514, verifierModel: claude-sonnet-4-20250514 }, worktree: { enabled: true, baseBranch: main, cleanup: true }, skills: { dir: .loop/skills, autoTrigger: true } }几个字段值得展开。schedule用标准 cron 表达式0 2 * * *表示每天凌晨两点跑一次。maxRounds是硬性刹车防止循环在无法满足停止条件时无限烧 token。stopCondition是给验证者看的不是给干活的那个模型看的——这一点后面会重点讲。memoryFile指向磁盘上的状态文件循环每一轮开始前读它结束后写它。worktree.enabled打开后每个并行子智能体会拿到独立的 git worktree物理上碰不到彼此的代码副本。skills.autoTrigger让技能在任务匹配描述时自动触发而不是每次手动$skill-name。3.2 config.toml子智能体定义config.toml定义循环里的角色分工。核心原则只有一条写代码的和检查代码的必须是两个不同的智能体最好用不同的指令必要时用不同的模型。[loop] state_file .loop/state.md log_file .loop/run.log [[agents]] name explorer description 只读探索定位相关文件和调用链不做任何修改 model claude-sonnet-4-20250514 reasoning_effort low tools [read, grep, glob] [[agents]] name implementer description 根据探索结果实现改动只改被点名的文件 model claude-sonnet-4-20250514 reasoning_effort high tools [read, write, edit, bash] [[agents]] name verifier description 对照停止条件独立验证不信任 implementer 的自我报告 model claude-sonnet-4-20250514 reasoning_effort high tools [read, bash] isolation worktreeexplorer是只读的跑得快负责探路。implementer拿高推理强度负责动手。verifier的关键在于它的指令里明确写了「不信任 implementer 的自我报告」并且用isolation worktree拿到一份干净副本避免被 implementer 的中间状态污染。写代码的模型给自己改作业时太宽容了换一个带着不同指令的第二个智能体才能逮住第一个把自己说服了的那些问题。3.3 技能文件把项目知识固化下来技能就是一个文件夹加一个SKILL.md。放在.loop/skills/下循环每轮都会读到。下面是一个最小示例。--- name: project-conventions description: 本仓库的构建、测试与提交约定任何改动前必读 --- ## 构建 使用 pnpm build不要用 npm。 ## 测试 单元测试 pnpm test:unit集成测试 pnpm test:integration。 提交前必须两者都过。 ## 约定 - 不引入新的运行时依赖除非在 PR 描述里说明理由。 - 所有对外 API 变更必须同步更新 docs/api.md。 - 之前出过一次事故直接改生产配置导致回滚所以配置改动必须走 review。那段「之前出过一次事故」就是意图债的解药。智能体每开一个新会话都是从零冷启动你意图里留的任何窟窿它都会拿一个自信满满的猜测去填。技能把这份意图写在了外面写在智能体每跑一轮都会读到的地方。没有技能循环每一轮都要把你整个项目从零重新推导一遍有了技能它才开始有点复利的味道。4. 验证请求跑通一次完整循环配置写完接下来是验证。我把它拆成三步先验证单次模型调用再验证循环触发最后验证停止条件。4.1 验证循环触发用一个最小脚本模拟循环的一轮确认它能读到配置、能调通模型、能写状态文件。import json, os, subprocess, datetime with open(settings.json) as f: cfg json.load(f) state_path cfg[loop][memoryFile] os.makedirs(os.path.dirname(state_path), exist_okTrue) round_no 1 if os.path.exists(state_path): with open(state_path) as f: content f.read() round_no content.count(## Round) 1 entry f\n## Round {round_no}\n- time: {datetime.datetime.now().isoformat()}\n- status: started\n with open(state_path, a) as f: f.write(entry) print(floop round {round_no} started, state written to {state_path})跑一次然后cat .loop/state.md应该能看到## Round 1的记录。再跑一次变成## Round 2。这说明循环的「记忆」机制在工作——它知道上一轮发生过什么而不是每次从零开始。4.2 验证停止条件由独立验证者判定这是整个循环里最容易被做错的一环。停止条件不能由干活的那个模型自己宣布必须由一个全新的、独立的验证者来判断。下面是一个验证脚本的骨架。#!/usr/bin/env bash set -e echo 运行测试 pnpm test:unit pnpm test:integration echo 运行 lint pnpm lint echo 验证通过写入状态 echo - status: verified at $(date -Iseconds) .loop/state.md这个脚本由verifier子智能体调用而不是implementer。implementer说「我做完了」只是一句声明verifier跑出来的测试结果才是证明。你给循环一个类似「test/auth 下所有测试通过且 lint 干净」的目标然后就可以走人了。4.3 验证并行隔离同时起两个子智能体确认它们各自拿到独立的 worktree互不干扰。git worktree add .loop/wt-a -b loop-a git worktree add .loop/wt-b -b loop-b git worktree list输出里应该能看到两个独立的工作目录各自待在自己的分支上却共享同一个仓库历史。一个智能体的改动物理上碰不到另一个的代码副本。用完git worktree remove清理或者靠配置里的cleanup true自动处理。5. 本篇常见错排查循环跑不起来问题往往不在模型而在几个固定的坑里。我把踩过的和读者反馈最多的列出来。报错一401 Unauthorized循环里所有模型调用都失败。最常见的原因是环境变量没传进子进程。循环调度器启动的子进程不一定继承你 shell 里的export。解决办法是在settings.json里用apiKeyEnv指定变量名并确保调度器启动时该变量已注入或者改用配置文件读取。别把 Key 硬编码进config.toml再提交到仓库。报错二循环无限跑maxRounds没生效。检查你的调度逻辑是否真的读了maxRounds字段。很多骨架示例只写了字段名没写消费它的代码。另外stopCondition如果写得太模糊比如「代码变好」验证者永远无法判定完成循环就会一直跑。停止条件必须是可验证的比如「某个测试文件通过」「某个命令返回 0」。报错三两个子智能体改同一个文件冲突不断。这是没开 worktree 隔离的典型症状。确认worktree.enabled为true并且verifier的isolation设成了worktree。工作树消除的是机械层面的碰撞但你才是那个天花板——你的审查带宽决定了你实际能跑几个而不是工具说了算。报错四技能没被触发循环每轮都在重新推导项目约定。检查SKILL.md的description字段。技能靠描述匹配来触发一段又紧凑又「无聊」的描述反而比一段花哨的更好用。如果描述写得太抽象匹配不上具体任务自动触发就会失效。报错五token 消耗远超预期。循环会放大一切包括浪费。先检查是不是每个子智能体都用了高推理强度的强模型。explorer这种只读探路的角色用低推理强度就够了。把强模型花在「第二意见值这个钱」的地方比如verifier。6. 把循环搭起来但你得继续当那个工程师循环改变的是工作的方式它并没有把你从这件事里删掉。验证仍然在你头上——一个无人值守跑着的循环同时也是一个无人值守犯着错的循环。你对代码的理解只要你放任就会烂掉。循环越快地交付出你没亲手写的代码「真实存在的东西」和「你实际搞懂的东西」之间的鸿沟就越大。所以尽管去把你的循环搭起来但别忘了直接给你的智能体写提示词同样有效。关键是找到那个对的平衡点。设计循环这件事当你带着判断力去做时它是解药当你做它是为了逃避思考时它就是助燃剂。如果你还没拿到统一的 Key先去 API Keys 页面创建一个https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的调用示例。想先验证模型对话是否正常可以用模型对话入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。如果你打算长期跑编码循环或 AgentCoding Plan 会更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。Claude Code 相关的接入说明在 https://taotoken.net/claudecode?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。把循环搭起来。但要像一个打算继续当工程师的人那样去搭它而不是像一个只负责按下开始键的人。