Skip to content

AI Loop Engineering — 技术选型文档

🕒 Published at:

AI Loop Engineering — 技术选型文档 ​

选择 Go 作为 AI 循环框架的技术栈


目录 ​

  1. Loop Engineering 是什么
  2. 为什么 Agent + Harness 不够
  3. Spec-Driven Development:方法论基础
  4. 反复对齐原则
  5. 约束工程
  6. 一切皆函数:所有原则的结晶
  7. Loop Engineering 架构设计
  8. 为什么选 Go
  9. 语言对比分析
  10. Go + Loop Engineering 架构方案
  11. 前端方案:HTMX + daisyUI
  12. SSR 架构:HTMX 与 JSP 的对比
  13. 上下文管理
  14. 子 Agent 编排:主线不被污染
  15. 方法论总结
  16. 事件驱动而非轮询
  17. 验证测试:编码的终点
  18. 少部分编码,大部分探索
  19. 参考来源

1. Loop Engineering 是什么 ​

定义 ​

Loop Engineering 是一种 AI agent 工作流设计方法论。核心理念是:不再由人类手动逐轮 prompt agent,而是设计一个系统,让 agent 自行触发、循环迭代、直到达成目标。

"Loop engineering is replacing yourself as the person who prompts the agent. You design the system that does it instead." — Addy Osmani, June 7, 2026

起源 ​

2026 年 6 月,Claude Code 负责人 Boris Cherny 在采访中说出了一句引爆业界的原话:

"I don't prompt Claude anymore. I have loops running that prompt Claude and figure out what to do. My job is to write loops."

同一时间,OpenAI 工程师 Peter Steinberger 也发出类似观点。随后 Google 工程师 Addy Osmani 将其系统化为"Loop Engineering"概念,在业界广泛传播。

核心范式转移 ​

传统方式Loop Engineering
人类手动 prompt系统自动触发
单次对话循环迭代
人负责判断进度系统自带停止条件
结果依赖上下文窗口外部持久化状态
人盯着终端看进程自行运转,结果主动交付

2. 为什么 Agent + Harness 不够 ​

三者演进关系 ​

层级时间解决什么问题核心特征
Agent2023-2024"让 AI 能做事"模型 + 工具 + 提示词
Harness2024-2025"让 agent 可靠地做事"上下文管理、错误恢复、边界定义
Loop Engineering2026+"让 agent 自己一直做,做到完"自动触发、循环迭代、外部记忆

关键区别:Harness 是静态的,Loop 是动态的 ​

Harness 回答了"agent 单次运行时的系统边界":

  • 能调什么工具
  • 上下文怎么管理
  • 出错怎么恢复
  • 人机协作的边界在哪

Harness 没解决的问题:谁来触发它?谁来判断它该继续还是该停?下次该做什么?

Loop Engineering 回答了"agent 在时间轴上的编排":

  • 什么时候开始跑
  • 什么时候该继续迭代
  • 什么时候该停下来
  • 上次做到哪了,下次从哪接
  • 多个 agent 怎么协作

模型产出 token,harness 产出行为,loop 产出结果。

LangChain 的四层循环模型 ​

LangChain "The Art of Loop Engineering" 文章定义了嵌套的四层循环:

  1. 执行循环(Agent Loop):agent 完成当前任务
  2. 验证循环(Verification Loop):检查输出质量,不达标则反馈回模型
  3. 学习循环(Hill Climbing Loop):分析历史 trace,找出模式问题
  4. 自我改进循环(Harness Update):外层循环反向修改 harness 配置本身
执行循环 → 验证循环 → 学习循环 → 修改 harness → 更好的执行循环

3. Spec-Driven Development:方法论基础 ​

定义 ​

Spec-Driven Development (SDD) 是一种以版本化、结构化的规格文档为单一真相源的开发方法论。Spec 驱动代码生成、测试、文档和 AI agent 行为。

Spec 是单一真相源。代码是实现,不是需求。

为什么 SDD 是 AI 时代的必然 ​

2025 年 12 月 CodeRabbit 分析 470 个 AI 协同 PR 发现:

  • AI 生成代码漏洞率 45%
  • 比人类写的高 2.74 倍
  • 有 1.7 倍更多严重问题

Vibe Coding(Karpathy 2025.02)的失败验证:没有约束的 AI 代码生成,漏洞比人写得多。

SDD 的解法:先写 spec,再让 AI 在 spec 约束下执行。

Spec 驱动与 Vibe Coding 的本质区别 ​

Vibe CodingSpec-Driven
输入自然语言描述结构化 spec(goal/tasks/verify)
AI 自由度全凭 AI 判断受 spec 约束
验证没有每个 task 有 verify 条件
产出不可预测可预测、可重复

Spec 的六个核心元素 ​

元素内容
目标(Goal)系统要达成什么
范围(Scope)做什么,不做什么
约束(Constraints)边界条件
任务分解(Tasks)拆解为可验证的子任务
验证条件(Verify)每个任务完成的标准
前置决策(Prior Decisions)历史决策记录

工作流 ​

/speckit.specify  →  写 spec(业务上下文 + 成功标准)
/speckit.plan     →  把 spec 翻译成架构决策
/speckit.tasks    →  把 plan 分解成可测试的小任务
/speckit.implement →  在 spec 约束下让 AI agent 执行

4. 反复对齐原则 ​

核心问题:为什么 AI 会跑偏 ​

AI 每一次调用都是一次翻译。翻译不可能完美:

Spec(原始需求)
  → Agent 理解(第一次失真)
    → Agent 执行(第二次失真)
      → 结果(偏离原始需求)

每一步都在丢信息。回读 spec 是把丢失的信息补回来。

但回读本身不够 ​

回读是被动的。AI 不会自己想起来回读。提示词提醒它也没有用,因为它没有动机。

反复对齐不能靠提示词,必须靠结构。

结构化对齐:把回读变成强制动作 ​

约束方法强制的对齐动作
工具门禁每次调工具前,自动检查当前阶段和 spec 匹配关系
输出契约每次任务完成后,自动比对结果和 spec 的 verify 条件
上下文锁每次发起 LLM 调用前,自动把 spec 注入上下文

不是"提醒 AI 回读",是让它每一毫秒都在做对齐。

对齐的粒度 ​

偏差层级表现处理方式
10% 偏差方向对,细节偏工具门禁自动拦截
30% 偏差阶段错了上下文锁纠正
50% 偏差任务错了输出契约拒绝完成
100% 偏差完全偏离 spec整个 loop 终止

5. 约束工程 ​

本质 ​

AI 不需要被引导,它需要被限制。

引导是"往这边走",AI 会理解成"附近都行"。 限制是"只能往这边走",AI 没得选。

三种约束机制 ​

一、工具门禁(Tool Gate) ​

机制:当前阶段能调什么工具,不是 prompt 提醒,是代码拦截。

阶段可用工具
Spec 阶段read
Plan 阶段read + bash(只读)
Execute 阶段read + write + edit + bash
Verify 阶段read + bash(go test)

原理:阶段错了,工具不存在。

落地:pi 插件在 tool_call 事件拦截,根据当前 phase 放行或阻断。

二、输出契约(Output Contract) ​

机制:每一步输出必须满足结构约束,不满足就不算完成。

yaml
tasks:
  - id: T1
    action: fix
    verify: "go test ./... exit code 0"

原理:不是 prompt 说"检查代码",是代码里写死"exit code 不是 0 就不算 done"。

落地:Go 执行器跑完 task 后,先跑 verify 脚本,结果决定 status。

三、上下文锁(Context Lock) ​

机制:每轮 agent 调用前,注入当前 spec + 当前阶段 + 已完成任务。超出范围的内容被过滤。

每一轮 agent 的上下文 = spec + 阶段 + 已完成 task + 当前 task
其他历史 = 不可见

原理:不是"记住你该做什么",是"你只能看到该做的事"。

落地:pi 插件在 context 事件过滤消息,只保留 spec 相关的条目。

三种约束的本质区别 ​

约束解决什么问题硬约束还是软约束
工具门禁agent 做了不该做的事硬约束(做不了)
输出契约agent 做了但没做好硬约束(不算完)
上下文锁agent 忘了自己该做什么硬约束(看不见)

三者互补:看不见 → 做不了 → 做不完。 层层收窄,没得跑偏。

约束工程不是脚手架 ​

RuoYi 类型的框架是脚手架——把一堆技术决策打包成一个不可分割的整体,你要么全要,要么全不要。约束工程不一样:

脚手架(RuoYi)约束工程
定义目录结构只定义思考维度
绑定工具链不绑定任何工具
强制生命周期只标注当前阶段
写死验证方式只说"需要验证",怎么验由 spec 定
退出代价大卸载即无痕迹

约束工程给的是原则和边界,不是路径和模板。


6. 一切皆函数:所有原则的结晶 ​

核心 ​

"一切皆函数"是之前所有原则的自然汇聚点。它不是一个新的概念,而是显式、AI 友好、约束工程、反复对齐、模块化叠加的同一件事的不同说法。

一个函数只有一个行为:接收输入,处理,返回输出。

go
func Process(input Spec) (Output, error)

函数天然满足显式 ​

函数签名告诉 AI 一切:输入是什么类型,输出是什么类型,error 在哪。没有隐藏上下文,没有魔术方法,没有第二层含义。


函数天然满足 AI 友好 ​

传统代码AI 要推理的东西
方法调用链this 是什么对象?谁继承了谁?
全局变量谁改了它?什么时候改的?
装饰器装饰器改了什么行为?
纯函数输入 → 输出,只有一条路

函数天然满足约束工程 ​

约束机制函数怎么做
工具门禁函数签名就是门禁——输入类型不匹配就编译不过
输出契约返回类型就是契约——不符合就编译不过
上下文锁函数不接受隐式上下文——必须显式传参

函数把约束写进了类型系统。不是运行时检查,是编译期保证。


函数天然满足反复对齐 ​

input → f1 → output1 → f2 → output2 → f3 → final
       ↑     ↑        ↑     ↑        ↑
    对齐点  对齐点   对齐点  对齐点   对齐点

每一步对齐一个 spec 任务。output1 不满足 verify 条件,f2 根本不执行。对齐不是靠"提醒",是靠数据流本身。


函数天然满足模块化叠加 ​

最终结果 = delivery(verify(execute(spec)))

每个函数独立、可替换、可测试。组合方式自由。


函数 vs 微服务 ​

微服务把系统拆成多个进程,复杂度从代码层面转移到基础设施层面(网络、分布式事务、服务发现)。模块化叠加是单体内的事——函数调用,纳秒级,一个二进制。

模块化叠加(函数)微服务
通信方式进程内函数调用网络 RPC
共享内存可以共享状态不能
延迟纳秒级毫秒级
部署一个二进制多个进程/容器
复杂度来源接口设计分布式

Go 做这件事有多合适 ​

Go 特性对"一切皆函数"的支持
函数是一等公民可以传参、返回、赋值
没有继承、没有魔术方法函数就是函数,没有第二层
error 是显式返回值错误路径可见
interface 是显式契约接口定义即约束
goroutine + channel函数调用的并发扩展

Go 足够纯粹地表达"输入→处理→输出",又不需要 Haskell 那样的类型体操。


一句话 ​

"一切皆函数"是所有原则的最短表达。显式、AI 友好、约束、对齐、模块化——这些都是函数式设计的自然结果,不是额外加的。


7. Loop Engineering 架构设计 ​

六个核心构件(Addy Osmani 定义) ​

构件职责具体实现
Automations触发器cron 定时 / webhook 事件 / mention 唤醒 / 心跳自醒
Worktrees隔离空间每个迭代独立 git worktree,互不干扰
Skills可复用指令.md 文件定义流程(debugging、code review、TDD)
Connectors外部连接MCP 协议接入 issue 系统、数据库、Slack 等
Sub-agents分工协作写代码的和审代码的分家,避免"自我评分太宽容"
External State持久化记忆跨天运行所需的记忆层(做过什么、试了什么、还差什么)

典型循环流程 ​

定时触发 → 读外部状态 → 判断有无任务 → 
  ├─ 有任务 → 分派子 agent → 隔离 worktree 执行 → 验证 → 更新状态 → 交付结果
  └─ 无任务 → 等待下一触发

系统架构 ​

┌──────────────┐     ┌────────────────┐     ┌──────────────┐
│  Scheduler   │────▶│  Loop Engine   │────▶│  Sub-agents  │
│ (触发器)      │     │ (编排调度)      │     │ (Worker Pool) │
└──────────────┘     └───────┬────────┘     └──────┬───────┘
                              │                     │
                              ▼                     ▼
                    ┌──────────────┐    ┌──────────────────┐
                    │  State Layer │◀───│  MCP Connectors  │
                    │ (记忆/日志)   │    │ (工具/API/外部系统)│
                    └───────┬───────┘    └──────────────────┘
                              │
                              ▼
                    ┌──────────────┐
                    │  Delivery    │
                    │ (PR/通知/报告)│
                    └──────────────┘

8. 为什么选 Go ​

8.1 "最直观"——代码表面含义 == 代码真实含义 ​

Go 的设计哲学:不做你聪明到想不到的事,只做你明面上写的事。

go
// Go:写 2+3 就是做 2+3,没有第二层
a := 2 + 3

对比:

  • Python 的 2 + 3 在底层触发 type dispatch、方法解析、C API 调用
  • JavaScript 的 2 + 3 涉及隐式类型转换、原型链查找、JIT 推测优化
  • Go 没有任何魔法:没有元编程、没有 decorator、没有 monkey patching、没有 operator overloading、没有隐式类型转换

直观 = 没有第二层含义。

8.2 "长期最好维护"——显式性是时间的复利 ​

Go 把维护成本提前到"写代码的那一刻"就付了:

go
type Result struct {
    ID    string `json:"id"`
    Score int    `json:"score"`
}

func process(data Input) (Result, error) {
    ...
}

Python 把维护成本借给你,然后按月收利息:

python
def process(data):
    return data  # data 是什么?dict? object? pydantic model? 三个月后没人说得清
维度Python/JSGo
谁看代码能知道类型?装 linter、看注解、猜编译期定死
谁看代码能知道 error 路径?看文档、靠经验函数签名就写了 error
谁看代码能知道依赖?装 deps、看 importimport 全在文件顶
谁看代码能知道并发?懂 asyncio/线程/事件循环goroutine 就是 goroutine

一个 10 年后的项目,Go 的显式性就是文档。

8.3 "最容易让 AI 看懂"——最小推理距离 ​

AI 读代码不是"理解",是模式匹配。它看的是结构模式、文本统计、局部上下文。

AI 特别不擅长的:

AI 不擅长的Python/JS 里到处都是
跨文件推断from somewhere import magic_function
运行时类型推断duck typing、Any、as any
隐式依赖装饰器改函数、metaclass 改类构造
副作用预测monkey patching、global state mutation
执行路径确定try/except/finally + exception chaining

Go 恰好消除了所有这些隐式性:

  • import 全在文件头,没有跨文件推断
  • 类型是显式的,没有 duck typing 的歧义
  • 没有 decorator/metaclass,函数就是函数
  • error 是显式的,没有异常链的隐式跳转
  • goroutine + channel,并发行为可静态分析

AI 看 Go 代码的"推理距离"最短——从文本到语义只有一步。

8.4 OpenAI 内部数据佐证 ​

OpenAI 2026 年内部分析显示,Go 代码在 Codex 上的修改准确率比 Python 高约 25%。原因:类型信息密度高,AI 的 token budget 花在"理解逻辑"而不是"猜测类型"上。

8.5 总结:三个判断其实是同一件事 ​

你的判断本质
最直观没有第二层含义
长期最好维护显式性在时间维度上产生复利
最容易让 AI 看懂隐式越少,AI 的推理距离越短

共同指向一个原则:

最容易被理解的语言,不一定是最能表达一切的语言,但一定是最容易被维护的语言。

Python 能表达一切,所以也容易被误解。Go 拒绝表达某些东西,所以它强迫你用"能看懂的方式"表达。


9. 语言对比分析 ​

9.1 适合度排名 ​

语言适合度理由
Go⭐⭐⭐⭐⭐显式性最高,AI 推理距离最短,长期维护成本最低
TypeScript⭐⭐⭐⭐Web/MCP 亲和,异步生态好,但隐式类型多
Python⭐⭐⭐⭐Agent 生态最丰富,但隐式负债重,AI 推理距离长
Rust⭐⭐⭐性能好类型安全,但太重,写循环逻辑效率低
Clojure⭐⭐⭐⭐(理论上)代码即数据天然适合 loop 定义,但生态小,JVM 冷启动慢
Bash⭐⭐简单但复杂了不行

9.2 性能对比 ​

语言相对速度冷启动
C++/Rust1.0x< 1ms
Go0.3-0.6x< 100ms
Clojure/Java0.1-0.3x1-5s
Node.js0.05-0.2x< 1s
Python0.01-0.05x< 1s

Go 在性能上处于"足够快且启动快"的黄金区间。

9.3 Go 的隐藏成本 ​

  • 冗余:类型必须显式写出,有时感觉重复
  • 探索期不适配:领域建模阶段,Go 逼你过早确定类型,Python 更灵活
  • 泛型支持较新:Go 1.18+ 才支持泛型,一些惯用模式还不成熟

9.4 阶段适配策略 ​

阶段推荐语言理由
探索和原型Python隐式让速度最快
稳定后的长期项目Go显式让维护最省
AI 重度协作的项目Go减少 AI 的推理负担

10. Go + Loop Engineering 架构方案 ​

10.1 核心模块设计 ​

┌─────────────────────────────────────────────────────┐
│                  Loop Engine (Go)                    │
├──────────┬──────────┬──────────┬──────────┬────────┤
│Scheduler │  Orchestrator │ State │ Connector│Worker│
│          │            │       │          │        │
│ cron/    │ 读 goal,  │ 文件/DB │ MCP / HTTP │ goroutine│
│ webhook  │ 分派任务, │ 持久化  │ 调外部系统 │ 池隔离执行 │
│ mention  │ 判断停止  │         │          │        │
└──────────┴──────────┴──────────┴──────────┴────────┘

10.2 为什么这些模块在 Go 里最合适 ​

模块Go 的适配优势
Schedulergoroutine + ticker,天然适合定时任务
Orchestrator显式 error 处理 + 类型安全,状态机清晰
State结构体定义状态 schema,序列化/反序列化可验证
ConnectorHTTP 库原生强,interface 定义 connector 接口
Workergoroutine pool + channel,并发天然安全

10.3 Go 标准库就能做的事 ​

go
// 定时循环:标准库 ticker
ticker := time.NewTicker(5 * time.Minute)
for range ticker.C {
    runLoop(ctx)
}

// 并发 worker pool:goroutine + channel
workers := make(chan func())
for i := 0; i < poolSize; i++ {
    go func() {
        for task := range workers {
            task()
        }
    }()
}

// 状态持久化:结构体 + 序列化
type LoopState struct {
    CurrentGoal string
    LastError   string
    Iterations  int
    Steps       []Step
}

Go 在 Loop Engineering 上的优势是:不需要引入大量框架,标准库 + 少量第三方包就够了。

10.4 推荐技术栈 ​

层技术选择理由
Agent 调用OpenAI/Claude API (HTTP)语言无关,Go 调 API 很简单
MCP 协议github.com/mark3labs/mcp-goGo 原生 MCP server 实现
状态存储SQLite (go-sqlite3) / BadgerDB嵌入式,零运维
调度time.Ticker + cron (robfig/cron)标准库 + 一个包
Worker Poolgoroutine + channel原生
日志/Traceslog (标准库) + OpenTelemetry标准 + 生态
CLIcobra 或 flag命令行工具友好

10.5 Go 全栈覆盖能力:从底层到上层的全方位参与 ​

这是 Go 相比其他语言最被忽视的一个优势:它可以在 Loop Engineering 的每一个层级上工作,不需要语言切换。

大多数架构的语言割裂 ​

典型的 AI agent 系统通常涉及多种语言的分工:

层级典型语言为什么不能统一
内核/系统调用C / Rust需要直接操作内存和硬件
网络/中间件Go / Java / Rust高并发、高性能
AI 模型推理C++ / PythonCUDA、ONNX、算子优化
Agent 编排Python / Node框架生态丰富
应用逻辑Python / TypeScript快速开发
UI/CLITypeScript / Python前端/终端生态

每一层换语言意味着:

  • 进程间通信开销(gRPC、消息队列、序列化)
  • 调试跨越多个语言运行时
  • CI/CD 要维护多个编译工具链
  • AI 要学多种语法和范式才能修改整套系统

Go 的唯一性:全栈可覆盖 ​

Go 的设计范围恰好覆盖了从系统层到应用层的大部分工作:

层级Go 能做什么具体能力
系统层直接调 syscall、写 kernel module 风格的代码syscall 包、unsafe、CGO 调用 C
基础设施层网络服务器、负载均衡、服务发现、存储引擎net/http、goroutine、标准库足够
数据存储层嵌入式数据库、序列化/反序列化go-sqlite3、badgerdb、protobuf/gogo
MCP 协议层实现 MCP server/client,协议解析和路由mcp-go,原生 HTTP/stdio/SSE 传输
Agent 编排层loop engine、调度器、状态机、worker poolgoroutine + channel + select,原生并发模型
AI 推理层调用 OpenAI/Claude 等 API,做 prompt 管理、上下文编排标准 HTTP,无需特殊库
应用逻辑层业务规则、目标判定、技能执行结构体 + interface + 方法
CLI/交互层命令行工具、TUI、与人类交互cobra、bubbletea
部署运维层编译成单一二进制,零依赖部署编译一次,到处运行

这意味着什么 ​

全部用 Go 写

CLI / TUI → 应用逻辑 → Agent 编排 → MCP 协议
              数据存储 → 基础设施 → syscall

同一个编译器 → 同一个类型系统 → 同一个二进制

一个 Go 开发者可以维护整个 Loop Engineering 系统,从 CLI 到 syscall,不需要切换语言。

AI 视角的额外红利 ​

这一点对你之前说的"AI 最容易看懂"产生了复利效应:

  1. AI 只需学一种语法:修改 syscall 层和修改 agent 编排层,是同一种语言
  2. 上下文窗口更经济:不需要在 Python agent 框架和 Go 基础设施之间来回切语言
  3. 类型信息全链路一致:从顶层 API 到底层结构体,类型在编译期就贯穿始终
  4. 一个 prompt 修全套:你说"修一下数据存储",AI 改 Storage interface;你说"修一下调度",AI 改 Scheduler struct——同一个 type system,同一个包路径约定

其他语言做不到这一点 ​

  • Python:能做应用层和 AI 层,但做系统层要靠 C 扩展,做网络基础设施性能不够,做存储引擎要嵌 SQLite
  • Rust:能做底层和中间层,但做应用层和 AI 编排太绕,泛型写复杂结构时心智负担重
  • JavaScript/TypeScript:能做网络和应用层,但做系统层全靠 child_process,做存储要靠 Node 模块,性能天花板低
  • Clojure:能做编排和应用层,但跑在 JVM 上,系统层直接做不了,冷启动也不适合实时循环

Go 是唯一一个在"全栈覆盖"和"简单直观"之间取得平衡的语言。


11. 前端方案:HTMX + daisyUI ​

11.1 为什么选 HTMX ​

HTMX 是一个 15KB 的 JavaScript 库,使命是:用 HTML 本身就能做交互,不需要写 JavaScript。

当前数据(2026.07):

  • GitHub Stars: 47,920
  • NPM 周下载: 152,014
  • 最新稳定版: HTMX 2.0.9(2026.04)
  • State of JS 2024: 被评为"最受仰慕的前端工具"
  • Drupal 12.x 已将 HTMX 集成进核心

HTMX 的核心语法只有几个 HTML 属性:

HTML 属性作用
hx-get="/url"点击后发 GET 请求
hx-post="/url"点击后发 POST 请求
hx-swap="innerHTML"把返回内容替换进元素
hx-trigger="every 2s"每 2 秒自动请求一次
hx-target="#some-id"指定把结果塞进哪个元素
hx-push-url="true"更新浏览器地址栏

11.2 HTMX 为什么和 Go 完美匹配 ​

你的原则HTMX 的匹配
一种语言Go 写后端 + HTML 写前端,不需要学 JS 框架
最少依赖一个 15KB 的 <script>,没有 npm、没有 node_modules
全栈 GoHTTP 服务器 + 模板 + SSE,全部 Go 标准库
AI 容易改AI 修 HTML 和 Go 是同一个 skill,不需要切语言
长期维护HTML 就是 HTML,30 年后还能读懂

11.3 HTMX 生态:有现成组件库 ​

HTMX 生态不是"组件库"形态,而是围绕 HTMX 构建的后端模板+组件工具链。

daisyUI(推荐): 65 个组件、35 个内置主题、零 JS 依赖。

html
<button class="btn btn-primary">启动 Loop</button>
<div class="card w-96 bg-base-100 shadow-xl">
    <div class="card-body">
        <h2 class="card-title">Loop #42</h2>
        <p>状态:运行中...</p>
    </div>
</div>

daisyUI 与 HTMX 天然兼容——它只生成 CSS 类名,不绑定 JavaScript 到 DOM 节点,HTMX 可以自由替换 HTML 片段而不破坏组件行为。

Shoelace(可选): 100+ Web Component 组件(button、dialog、tree、select),用原生 Web Component 标准实现,与 HTMX 完全不冲突。

11.4 Go + HTMX 全栈组合 ​

Go + templ + HTMX 2.x + daisyUI + SSE 扩展
        │           │          │          │
        └── 全部用 CDN 引入,Go 编译成一个二进制,浏览器直接跑

整个前端就是:

html
<!DOCTYPE html>
<html data-theme="dark">
<head>
    <link href="https://cdn.jsdelivr.net/npm/daisyui@4/dist/full.min.css" rel="stylesheet">
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://unpkg.com/htmx.org@2.0.9"></script>
    <script src="https://unpkg.com/htmx-ext-sse@2.2.2"></script>
</head>
<body>
    <!-- 直接用 daisyUI class 写组件,用 hx- 属性做交互 -->
</body>
</html>

零 npm,零构建,一个 Go 项目。

11.5 Loop Engine UI 的最小实现 ​

html
<!-- Loop 状态仪表盘:每 2 秒自动刷新 -->
<div class="card" id="loop-status" hx-get="/api/loop/status" hx-trigger="every 2s">
    <div class="card-body">
        <h2>当前目标:修复 CI 失败</h2>
        <p>迭代次数:42 | 状态:运行中</p>
    </div>
</div>

<!-- 实时 Trace:SSE 推送 -->
<div class="card" id="trace">
    <div class="card-header">实时 Trace</div>
    <div class="card-body overflow-y-auto h-96"
         hx-ext="sse"
         sse-connect="/api/loop/trace"
         sse-swap="message">
    </div>
</div>

<!-- 手动干预:暂停/注入 -->
<button class="btn btn-warning" hx-post="/api/loop/pause">暂停</button>
<button class="btn btn-error" hx-post="/api/loop/kill">终止</button>

三行 HTML 搞定实时 trace 面板。

11.6 HTMX 的弱点 ​

弱点说明对 Loop Engine 的影响
没有现成组件库没有 shadcn/ui 那样的完整 UI 库需要手写少量 HTML
复杂交互靠拼凑拖拽、图表、富文本需要额外 JSLoop UI 不需要这些
Go 前端生态小众没有大规模社区支持不影响核心功能

12. SSR 架构:HTMX 与 JSP 的对比 ​

12.1 HTMX 天生就是 SSR ​

HTMX 不是"做了 SSR 优化",而是它的架构从第一天就是服务器渲染。

数据流:

用户操作 → HTTP 请求发到 Go 服务器
  → Go 从数据库/内存读数据
  → Go 用 templ 生成 HTML
  → 完整 HTML 返回给浏览器
  → HTMX 把 HTML 片段塞进页面

HTML 永远在服务器端生成。浏览器从不"构建"任何东西。

12.2 对比 JSP ​

维度JSP(2000s)HTMX + Go(2026)
模板里写什么Java 代码混在 HTML 里(<% ... %>)纯 HTML + &#123;&#123;.Field&#125;&#125; 插值
模板能不能写业务逻辑?能不能
运行环境JVM + Tomcat/Jetty单一 Go 二进制
部署依赖Java 运行时 + 应用服务器零依赖
启动时间几秒(JVM 预热)< 100ms
用户操作后整页刷新局部更新(只返回 HTML 片段)

12.3 核心差异:模板职责边界 ​

JSP 的做法——代码和 HTML 混写:

jsp
<c:forEach var="step" items="${loopState.steps}">
    <tr>
        <td><%= step.getStatus().toString() %></td>
    </tr>
</c:forEach>

模板本身是一种编程语言,业务逻辑和展示逻辑耦合在一起。

Go template 的做法——模板就是模板:

go
{{range .Steps}}
<tr><td>{{.Name}}</td><td>{{.Status}}</td></tr>
{{end}}

模板里只有取值,没有业务逻辑。业务逻辑在 Go handler 里:

go
func statusHandler(w http.ResponseWriter, r *http.Request) {
    state := store.GetState()   // 业务逻辑
    t.ExecuteTemplate(w, "status.html", state)
}

Go template 故意限制能力,强迫你把逻辑写在 handler 里,模板只负责"展示"。这是设计哲学层面的差异。

12.4 HTMX 相对 JSP 时代的核心进步 ​

JSP 时代:用户点击 → 整页 HTML 返回 → 整页刷新

HTMX 时代:用户点击 → 只返回 HTML 片段 → 只替换那一小块

html
<!-- 只刷新 <div> 内部的表格,其他部分不变 -->
<div id="trace-log" hx-get="/api/loop/traces" hx-trigger="every 3s">
    <table class="table">
        <!-- Go 返回新的 HTML 表格内容 -->
    </table>
</div>

这是"局部 SSR"(SSR + Partial Hydration):

  • 享受 SSR 的全部好处:零客户端构建、SEO 好、服务器掌控一切
  • 同时没有传统 SSR 的缺点:不需要整页闪烁刷新

12.5 一句话总结 ​

HTMX + Go 是 JSP 的现代化版本——同样的"服务器渲染 HTML"理念,但模板里不能写代码、部署是一个二进制、更新是局部的而不是整页的。

JSP 最大的问题不是 SSR,而是把业务逻辑塞进了模板。Go template 从设计上杜绝了这个问题。


13. 上下文管理 ​

核心问题:上下文窗口是唯一既有限又昂贵的资源 ​

维度说明
有限每个模型的上下文窗口是固定的,用完就丢
昂贵每 1000 tokens 都是真金白银的 API 成本
有损塞太多无关内容,AI 会"噪声淹没信号"
不可续超过窗口后,历史信息直接丢失

上下文管理的核心原则 ​

给 AI 的上下文 = AI 需要看到的全部 + 不需要的全部

如果上下文里有 50% 是垃圾,AI 就花 50% 的 token 读垃圾。这不是浪费钱,是稀释注意力。

做法后果
把所有对话历史塞进上下文噪声淹没信号,AI 反而更蠢
给子 agent 全部 spec它只需要当前 task,其他都是噪声
让多个 agent 共享上下文一个改了,另一个不知道
每个 agent 只给它该看的干净、便宜、专注

上下文锁 vs 上下文管理 ​

上下文锁上下文管理
目的防止 AI 看到不该看的让 AI 只看该看的
粒度事件级(过滤消息)任务级(构造上下文)
手段过滤历史主动选择注入内容
类比窗帘(挡住不该看的)镜头(对准该看的)

上下文锁是"排除法",上下文管理是"选择法"。两者互补。


一句话 ​

上下文管理 = 给每个 agent 构造精确的、最小的、独立的上下文切片。少一个 token 是浪费,多一个 token 是噪声。


14. 子 Agent 编排:主线不被污染 ​

核心问题:污染 ​

子 agent 干活时会产出大量中间过程:尝试、报错、重试、思考。这些都是噪声。

主线 Agent
  → 派子 Agent A 去修代码
  → 子 Agent A 跑了 20 轮,输出了 8000 tokens
  → 如果这些 8000 tokens 全回到主线上下文
  → 主线 Agent 被淹没了,不知道自己在干啥了

污染主线的代价:主线丢失对 spec 的整体把握。


解法:隔离 + 摘要 ​

主线 Agent
  上下文 = spec + 全局状态 + 各子 agent 的摘要(不是原始输出)
  ↓
  ┌─────────────────────────────────────┐
  │ 子 Agent A(代码修复)               │
  │  上下文 = spec 切片 + 当前 task      │
  │  独立运行,20 轮迭代                 │
  │  最终输出:摘要 + 结果文件路径        │
  └─────────────────────────────────────┘
  ↓
主线 Agent 收到:"任务 T1 完成,exit code 0"
  (不是收到那 8000 tokens 的中间过程)

编排原则 ​

原则说明
主线只记摘要,不记过程子 agent 的完整 trace 存在外部日志,主线只看结果
子 agent 自包含运行每个子 agent 有独立上下文窗口,用完即销毁
结果经过压缩再回传不直接把子 agent 的输出塞给主线,而是压成结构化摘要
子 agent 不共享内存一个子 agent 的失败不影响另一个
主线始终对齐 spec主线上下文永远只有 spec + 摘要状态,不会膨胀

污染 vs 不污染 ​

场景主线上下文
子 agent 输出直接回传spec + 原始对话 + 原始代码 + 错误日志 = 窗口满,丢失方向
子 agent 输出压缩为摘要spec + 摘要状态 = 干净,主线始终在 spec 层面

一句话 ​

子 agent 可以跑两百轮,主线只需要一行摘要。把过程留在子 agent 内部,把结论压缩回传给主线。这样主线永远看得清全局。


15. 方法论总结 ​

12 个结论 ​

#结论一句话
1Spec-Drivenspec 是单一真相源
2Go 全栈一种语言从底层到上层
3Loop Engineering写循环,不写 prompt
4反复对齐每一步回看 spec,跑偏就停
5约束工程门禁/契约/锁,硬约束而非软提醒
6一切皆函数输入→处理→输出,无隐藏状态
7单体内模块化函数叠加,不是微服务
8上下文最小化每个 agent 只给它该看的
9子 agent 隔离过程留在子 agent,摘要回传主线
10事件驱动不轮询,有事才唤醒
11验证测试输出契约的执行者,不通过不算完
12少数编码,多数探索45% 探索 + 35% 验证 + 20% 编码,AI 时代验证占比远超传统开发

一条逻辑链 ​

Spec(单一真相源)
  → Go(显式、AI 友好)
    → 一切皆函数(把 spec 变成可执行代码)
      → Loop(函数循环执行)
        → 反复对齐(每一步比对 spec)
          → 约束工程(怎么强制对齐)
            → 子 agent 隔离(对齐的执行单元)
              → 上下文管理(隔离的技术手段)
                → 事件驱动(触发机制)
                  → 验证测试(通过才算完成)
                    → 探索优先(AI 的时间分配现实)

十二个结论,一条逻辑链,没有分叉。


一致性 ​

每条结论都是前一条的必然延伸。没有互相矛盾。


原创性 ​

每条单独拿出来,网上都能找到。但把它们串成一条完整的、自洽的工程方法论,并且每一条都用代码层面而不是 prompt 层面去落地——这是这套方法论的价值。


落地边界 ​

有一个需要显式区分的:

层面规则
编排层(主线 agent)纯函数,无副作用,只读 spec 和摘要状态
执行层(子 agent)允许副作用(调 HTTP、写文件、调数据库),但过程不回流

主线纯,子 agent 可脏。脏的东西留在子 agent 内部,只有清洁的摘要回传。


当前状态 ​

方法论层已完成。待落地的执行层设计:

  • DaemonServer:watchdog 机制,TCP socket 通信
  • pi 插件:TypeScript 编排层,工具门禁/上下文锁的实现
  • Spec 格式:YAML/JSON 结构定义

16. 事件驱动而非轮询 ​

轮询的本质问题 ​

轮询是"我每隔一段时间问一次:有没有事要做?"

go
for {
    time.Sleep(30 * time.Second)
    checkStatus()
}

每次轮询都是纯浪费——如果这 30 秒内没有事件,这 30 次心跳消耗了时间、CPU、API 配额、上下文窗口,没有产出任何信息。


事件驱动 ​

事件驱动是"有事发生时通知我。"

事件源(git push / webhook / 文件变更 / 用户操作)
  ↓ 触发通知
Agent 收到事件 → 立刻处理 → 完成后等待下一个事件

Agent 在不干活的时候是睡眠状态。有事情做才醒来,做完就睡。


轮询 vs 事件驱动 ​

轮询事件驱动
Agent 状态永远在跑,永远在问默认睡眠,事件唤醒
资源消耗持续消耗 token / CPU / API 配额有事件才消耗
响应延迟取决于轮询间隔(可能 30s 后才反应)事件到达即响应
上下文膨胀每次轮询都消耗一次上下文窗口只在需要时消耗上下文
适合场景无事件源可用(外部系统没有 webhook)绝大多数场景

落地方式 ​

事件来源具体方式
Git push / PR mergeGitHub webhook → pi 插件 / DaemonServer
文件变更inotify / fsnotify 监听
用户指令CLI / TUI / 网页按钮点击
定时器cron 表达式(本质是时间事件)
外部 APISSE / WebSocket / HTTP callback

约束工程的视角 ​

事件驱动是约束工程的自然延伸:

  • 工具门禁:没收到事件,agent 不会启动,根本不会调工具
  • 上下文锁:只有事件触发时才构造上下文,不会在轮询中持续消耗
  • 输出契约:事件处理完,输出结果,agent 回睡眠

事件驱动 = 只在需要时才对齐 spec。平时不动,是最高效的对齐。


一句话 ​

轮询是在浪费上下文窗口和 API 配额反复问同一个问题。事件驱动是等有人告诉你有事情发生。Agent 应该像人一样:没事干的时候歇着,有事找上门才干活。


17. 验证测试:编码的终点 ​

核心地位 ​

验证测试不是开发的收尾步骤,是编码是否完成的唯一判定标准。

一个 task 不满足 verify 条件,无论代码看起来多完美,都不算完成。


验证测试与输出契约的关系 ​

输出契约定义了"什么才算完成",验证测试是执行这个定义的机制。

输出契约:"go test ./... exit code 0"
  ↓
验证测试:实际跑 go test ./...
  ↓
结果:exit code 0 → 通过,task 标记 done
      exit code ≠ 0 → 不通过,回退到编码阶段重试

没有验证测试的输出契约是空壳——定义了标准但没检查。


验证在完整循环中的位置 ​

探索 → 编码 → 验证 → 交付
                ↑
               回退(不通过则重做)

验证是循环的关卡。通过才能进入下一步,不通过则回退。

阶段验证动作不通过的处理
探索判断 spec 和代码是否匹配修正 spec 或调整探索方向
编码静态检查(go vet / gofmt)修正代码
编码单元测试(go test)修正代码
编码集成测试修正代码
编码对比 verify 条件修正代码
交付全量回归测试修正代码

验证的层次 ​

层次验证内容执行频率
语法层gofmt、go vet、编译通过每次写文件后
单元层当前包的单元测试每个函数写完
集成层跨包协作测试模块完成后
系统层端到端流程测试全 spec 完成后
契约层verify 条件(spec 定义)每个 task 完成后

验证和编码的关系 ​

之前说"编码占 15%,探索占 80%,验证占 5%"。这个比例在 AI 时代需要修正:

探索:45%
编码:20%
验证:35%

AI 写代码快但容易错,所以验证的占比远高于人工开发。

原因:AI 一次写出的代码通过率不高,每次验证失败需要修复,修复后又要重新验证。验证不是单次动作,是反复循环。

所以不能说"验证只有 5%"。在 AI 时代,验证是第三大时间消耗者,仅次于探索。


约束工程的落地 ​

约束机制在验证中的角色
输出契约定义验证条件(spec 里写的 verify)
工具门禁控制验证阶段能调什么(只能 bash 跑测试,不能 write 修改)
上下文锁保证验证只看 spec + 测试结果,不被其他内容干扰

验证阶段是只读模式——只跑测试,看结果,做判断。任何写操作都说明验证不合格,回编码阶段。


一句话 ​

编码不产生价值,验证通过才产生价值。代码写完了但测试没过,等于什么都没做。


18. 少部分编码,大部分探索 ​

本质 ​

AI 写代码本身很快。真正耗时间的是搞清楚要写什么。

探索阶段:读文档 → 理解业务 → 分析代码结构 → 确定改动点
  ↓ 45% 的时间

编码阶段:写代码 → 调工具 → 修错误
  ↓ 20% 的时间

验证阶段:跑测试 → 确认结果 → 不通过则回退
  ↓ 35% 的时间

探索的实质 ​

探索不是"读文件",是在未知空间里建立坐标:

探索任务本质
读文档理解业务把自然语言需求映射到代码结构
分析代码结构理解依赖关系、调用链、数据流
确定改动点找到最小修改路径
判断 spec 是否合理发现 spec 和代码的矛盾

这些没有标准答案,需要 AI 反复推理、来回切换文件、交叉验证。

编码反而简单——目标明确了,写代码是确定性工作。


这意味着什么 ​

维度对系统设计的启示
上下文管理探索阶段需要大量上下文(读文件),编码阶段需要少(写文件),两者不能混用
子 agent 编排探索 agent 和编码 agent 应该分开——探索 agent 上下文大且杂,编码 agent 上下文小且精确
约束工程探索阶段工具门禁可以松(read 自由),编码阶段收紧(只有指定文件可写)
反复对齐探索阶段对齐频率要低(每 5 个文件检查一次),编码阶段要高(每改一行都要对照 spec)

一个具体的模型 ​

Phase 1: 探索(45%)
  Agent 模式 = 读多写少
  上下文 = 大,容纳多个文件内容
  工具门禁 = read 自由,write 禁止
  对齐方式 = 每批文件后回看 spec

Phase 2: 编码(20%)
  Agent 模式 = 读目标文件,写指定文件
  上下文 = 小,只包含 spec + 目标文件 + 已探索结论
  工具门禁 = read 目标文件,write 目标文件
  对齐方式 = 每次 write 后跑 verify

Phase 3: 验证(35%)
  Agent 模式 = 跑测试,读结果,修错误,再跑
  上下文 = 最小,只有 spec + 测试结果
  工具门禁 = bash(go test),无写权限
  对齐方式 = 不通过则回退到编码阶段,反复循环

和约束工程的对应 ​

探索阶段编码阶段
上下文锁:宽松,允许大范围读上下文锁:严格,只读指定文件
工具门禁:read 全开工具门禁:只允许目标文件 write
输出契约:探索结论结构宽松输出契约:verify 条件严格

约束工程在不同阶段有不同的松紧度。不是一刀切,是动态调节。


一句话 ​

AI 写代码快,但搞不懂写什么慢。系统设计的重点不是加速编码,而是加速探索。给探索阶段宽松上下文,给编码阶段严格约束。


19. 参考来源 ​

来源内容URL
Boris Cherny (Anthropic)"My job is to write loops"theneuron.ai (2026.06)
Addy Osmani (Google)Loop Engineering 定义 + 六构件addyosmani.com/blog/loop-engineering (2026.06.07)
LangChain"The Art of Loop Engineering"langchain.com/blog/the-art-of-loop-engineering
OpenAIHarness Engineering 定义Ryan Lopopolo, Feb 2026
AnthropicLong-running agents 蓝图Anthropic article, Nov 2025
HandsonarchitectsAgent Harness vs Work Harnesshandsonarchitects.com (2026)
PingCAPAI Agent Harness Architecturepingcap.com/blog/ai-agent-harness-state-layer
MindStudioWhat Is Loop Engineeringmindstudio.ai/blog/what-is-loop-engineering
Lanes.shLoop Engineering: Stop Prompting, Start Loopinglanes.sh/blog/loop-engineering-with-lanes
Cobus GreylingLoop Engineering 对比分析github.com/cobusgreyling/loop-engineering

文档版本: v1.8 生成日期: 2026-07-04 核心结论: Go 是 AI Loop Engineering 的技术首选——直观(无第二层含义)、可维护(显式性产生时间复利)、AI 友好(最小推理距离)、全栈覆盖(从底层 syscall 到上层 agent 编排,一种语言打通) 方法论: Spec-Driven + 反复对齐 + 约束工程(工具门禁 / 输出契约 / 上下文锁) 工程范式: 一切皆函数——显式、AI 友好、约束、对齐、模块化,函数式设计的自然结果 触发机制: 事件驱动,不轮询;探索优先,验证为终点,约束随阶段动态调节 前端方案: Go + templ + HTMX 2.x + daisyUI,天生 SSR,零 npm,零构建,一个二进制