上一篇文章说了 Loop Engineering 的概念,以及你的 Harness 其实就是 Loop Engineering 的落地实践。
这篇文章解决一个更具体的问题:在一个已经有 Agent 系统的项目里,怎么把藏在代码里的隐式 Loop 变成显式的端到端可管理的 Loop。
先测试一下你的系统:如果有人问"你的 Agent 系统里有多少个 Loop,它们分别叫什么名字,输入输出是什么,上个月各跑了多少次",你能回答吗?
如果你不能——说明你的 Loop 是隐式的。
隐式 Loop 的问题:
显式化的目标就是解决这四个问题。
每个 Loop 需要一个唯一的名字。名字应该包含三部分信息:
| 部分 | 示例 | 含义 |
|---|---|---|
| 类型 | react / quality / learning / meta | Loop 的功能分类 |
| 领域 | rag / report / audit | Loop 服务的业务领域 |
| 版本 | v1 / v2 | Loop 的迭代版本 |
命名示例:
react-rag-v1 # RAG 场景的 ReAct 循环
quality-report-v2 # 报告生成的质量检查循环
learning-audit-v1 # 审计场景的经验提取循环
meta-engine-v1 # 自进化引擎元循环 在你的系统里,每个 Skill 就是 Loop 的载体。在 SKILL.md 里加一个 loop 字段:
---
name: react-rag-v1
loop:
type: react
domain: rag
version: v1
max_iterations: 5
timeout_ms: 30000
inputs:
- name: query
type: string
description: 用户查询
outputs:
- name: answer
type: string
description: 最终回答
error_codes:
- timeout: 超过最大迭代次数
- empty: 检索结果为空
--- 这个声明做了三件事:
有了 Loop 声明,下一步是把它们注册到你的自进化数据库里。
在现有的 evolution.db 里加一张表:
CREATE TABLE loop_registry (
id INTEGER PRIMARY KEY AUTOINCREMENT,
loop_id TEXT UNIQUE NOT NULL, -- react-rag-v1
loop_type TEXT NOT NULL, -- react | quality | learning | meta
domain TEXT NOT NULL, -- rag | report | audit
version TEXT NOT NULL DEFAULT 'v1',
config TEXT, -- JSON: 最大迭代、超时、输入输出契约
status TEXT DEFAULT 'active', -- active | paused | deprecated
created_at TEXT NOT NULL DEFAULT (datetime('now'))
); 每次一个 Skill 被调用时,先从 loop_registry 查到这个 Loop 的配置,然后用这个配置初始化执行环境。而不是像现在这样——配置散在代码里,每个 Skill 用自己的方式处理。
路由逻辑变成:
用户输入 → 识别意图
→ 查 loop_registry → 找到 react-rag-v1
→ 读取配置(最大5圈,30秒超时...)
→ 执行 Loop
→ 记录执行日志到 execution_log(带上 loop_id) 你的 execution_log 表已经有了,加一个字段就够:
ALTER TABLE execution_log ADD COLUMN loop_id TEXT; 这样每条执行记录都知道属于哪个 Loop。可以回答"上个月 react-rag-v1 跑了多少次"这样的问题。
再加一张 loop_iterations 表,记录 Loop 内部每一圈的详情:
CREATE TABLE loop_iterations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
execution_id INTEGER NOT NULL, -- 关联到 execution_log
iteration INTEGER NOT NULL, -- 第几圈(从1开始)
phase TEXT NOT NULL, -- thought | action | observation
input_tokens INTEGER DEFAULT 0,
output_tokens INTEGER DEFAULT 0,
duration_ms INTEGER DEFAULT 0,
status TEXT DEFAULT 'ok', -- ok | error | timeout
detail TEXT, -- JSON: 该圈的输入输出摘要
created_at TEXT NOT NULL DEFAULT (datetime('now'))
); 有了这张表,你可以看到每个 Loop 内部的运行细节:
SELECT loop_id, COUNT(*) as runs,
AVG(iterations) as avg_loops,
SUM(tokens) as total_tokens
FROM execution_log e
JOIN loop_iterations i ON e.id = i.execution_id
WHERE e.loop_id = 'react-rag-v1'
AND e.created_at > date('now', '-7 days')
GROUP BY e.loop_id; 这个查询告诉你:上周 react-rag-v1 跑了多少次、平均跑了几圈、总 Token 消耗。这些都是你现在看不到的。
数据有了,下一步是可视化。不需要写复杂的图表代码——把你的数据接进去就行。
最简单的仪表盘足够用,显示三个信息:
Loop 活跃度
┌──────────────────────────────────────────────┐
│ react-rag-v1 ████████░░ 85% 423次 │
│ quality-report-v2 ██████░░░░ 62% 187次 │
│ learning-audit-v1 ██░░░░░░░░ 18% 45次 │
│ meta-engine-v1 ██████░░░░ 60% 12次 │
└──────────────────────────────────────────────┘
Loop 健康度
┌──────────────────────────────────────────────┐
│ react-rag-v1 ✅ 98% 2.1s avg 3.2 │
│ quality-report-v2 ⚠️ 85% 0.8s — │
│ learning-audit-v1 ✅ 100% 4.5s — │
│ meta-engine-v1 ✅ 100% 1.2s avg 1.0 │
└──────────────────────────────────────────────┘ 每一列的含义:
| 列 | 含义 |
|---|---|
| 活跃度 | 这个 Loop 的使用频率(占总执行次数的比例) |
| 健康度 | 成功率(通过 Quality Loop 的比例) |
| 平均耗时 | 单次 Loop 的平均执行时间 |
| 平均圈数 | ReAct Loop 的平均迭代次数 |
这是最关键的闭环。自进化引擎现在被动等待数据——它分析已有的失败模式。加上 Loop 声明后,它可以做更多:
自动触发条件从"失败达到阈值"升级为:
| 触发条件 | 行为 |
|---|---|
| 成功率 < 90% | 自动收紧 Quality Loop 阈值 |
| 平均圈数 > 5 | 自动增加 max_iterations 或优化输入 |
| Token 消耗环比增长 > 30% | 告警"可能是模型版本变化" |
| Loop 连续 7 天未被调用 | 自动标记为 deprecated,等你确认后清理 |
这些规则在你的自进化引擎里已经能实现了——只需要把 loop_registry 的数据接入分析器。
loop: 字段。 最简单的版本只需要 loop_id 和 type。花 10 分钟改一个,看看效果。loop_registry 表和 loop_iterations 表。代码已经有了。bridge.py 在记录执行日志时带上 loop_id。一句话: 给你的循环一个名字。名字给它身份,身份让它可观测,可观测让它可治理,可治理让它可进化。每一步只需要很小的工作量,但每一步都让你的系统从一个"跑得动的东西"变成一个"被管理的系统"。
💬 评论