20. Agent 创建流程:Scaffold-First 架构
核心原则:先建骨架,再填内容。 Agent 目录必须先通过 AgentScaffold 父类创建,后续的 Hunt/Digest 才能往里面写文件。
20.1 Create 流程(五阶段严格串行)
当 Innovator 需要创建一个全新的 Agent 时,严格按照以下五个阶段串行执行:
Scaffold → Hunt → Digest → Evolve → Execute
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
创建骨架 调研写入 消化提炼 验证测试 执行任务
阶段 1: Scaffold(脚手架创建骨架)
由引擎硬编码执行,不依赖 LLM。
当 Innovator 输出 [CALL: meta_creator] 时,agent-chat.js 中的 executeMetaCreator() 函数直接调用 AgentScaffold.create(),在 data/agents/{agent_name}/ 下生成完整的标准目录结构:
data/agents/{agent_name}/
├── agent.md ← 身份定义
├── soul.md ← 灵魂人格
├── identity.md ← 标识信息
├── user.md ← 用户关系
├── tools.md ← 工具权限
├── heartbeat.md ← 心跳任务
├── config.json ← 配置(含 cli.toolPolicy)
├── .claude/skills/
│ └── main_skill/
│ └── SKILL.md ← 核心技能(初始为空壳)
├── memory/
│ ├── short-term/
│ ├── long-term/
│ ├── sessions/
│ └── daily/
├── knowledge/ ← Digest 阶段写入 knowhow/benchmark
├── workspace/ ← 自治工作区
│ ├── code/
│ ├── data/
│ └── assets/
├── train/ ← Hunt 阶段写入的调研和训练数据
└── logs/
阶段 2: Hunt(知识狩猎)
执行型子 Agent,有完整工具权限。
meta_hunt 在新建 Agent 的目录下运行,将调研结果写入该 Agent 的 train/ 目录:
data/agents/{agent_name}/train/
├── knowhow.md ← 方法论调研
├── toplist.md ← 标杆案例
├── agent_profile.md ← Agent 人格画像(思维、风格、工具、心跳、用户关系)
└── crawl/ ← 爬取数据
├── source_01.md
└── source_02.md
阶段 3: Digest(知识消化)
执行型子 Agent,读取 train/ 的调研数据,提炼输出到 knowledge/ 和 SKILL.md,并基于 agent_profile 生成定制化 Bootstrap 文件。
输入: train/knowhow.md + train/toplist.md + train/agent_profile.md + train/crawl/
输出:
├── knowledge/knowhow.md ← 精炼后的方法论
├── knowledge/benchmark.md ← 评分标准(≥5个维度)
├── .claude/skills/main_skill/SKILL.md ← 基于方法论生成的核心技能
├── agent.md ← 身份定义、职责、规则(基于 agent_profile)
├── soul.md ← 思维方式、沟通风格、价值观
├── tools.md ← 工具权限和文件操作范围
├── heartbeat.md ← 自检频率和质量监控规则
└── user.md ← 与用户/上级的关系定义
阶段 4: Evolve(验证进化)
用测试用例验证新 Agent 的输出质量,对照 knowledge/benchmark.md 评分。
阶段 5: Execute(执行用户任务)
Agent 已创建并验证通过,直接调用执行用户最初的需求。
20.2 meta_creator 引擎级拦截
为什么不让 Claude 子进程执行 meta_creator?
| 方案 | 可靠性 | 问题 |
|---|---|---|
| Claude 拼 curl 命令调 scaffold API | ⚠️ 低 | LLM 可能拼错 JSON、遗漏字段、URL 写错 |
| Claude 用 Write 工具手动建目录 | ❌ 极低 | 会漏掉标准子目录、忘记写 config.json |
| 引擎硬编码执行 AgentScaffold | ✅ 100% | 代码确定性执行,不依赖 LLM |
实现位置
server/routes/agent-chat.js 中的子 Agent 调度循环:
// ═══ 硬编码拦截: meta_creator → 直接调用 AgentScaffold 父类 ═══
if (call.agent === 'meta_creator') {
res = await executeMetaCreator(call.task, agentId, convId, sendSSE, callId);
} else {
res = await agentManager.callAgent(call.agent, call.task, { ... });
}
executeMetaCreator 执行逻辑
- 解析参数 — 从 Innovator 的任务文本提取 agent_name、display_name、domain
- 调用 AgentScaffold.create() — 生成完整目录结构 + bootstrap 文件
- 写入初始 SKILL.md — 基于任务描述生成空壳 SKILL.md(后续由 Digest 填充)
- 返回结构化结果 — 包含创建的目录列表,供 Innovator Reflect 验证
20.3 子 Agent 工作目录
问题
所有子 Agent 的 Claude CLI 进程之前都运行在项目根目录 lemonboss/,导致:
- Claude CLI 读不到
.claude/skills/下的 l1/l2 知识文件 - Hunt 的输出写到错误的位置
解决方案
agent-manager.js 的动态 Agent 发现逻辑现在会计算正确的工作目录:
// 独立 Agent → 运行在 Agent 自己的目录下
agentConfig.workDir = agentDir; // data/agents/{agentName}/
// Scoped Skill → 运行在所属 Agent 的目录下
const ownerAgentDir = path.dirname(path.dirname(path.dirname(foundPath)));
agentConfig.workDir = ownerAgentDir; // data/agents/innovator-001/
_runViaProtocol() 优先使用 agent-specific workDir:
const effectiveWorkDir = agent.workDir || this.workDir;
效果
- meta_hunt 运行在
data/agents/innovator-001/,自动读取全部 18 个 SKILL.md 作为知识上下文 - 新创建的 Agent 运行时能读取自己目录下的
.claude/skills/
路径约定(⚠️ 关键)
由于 meta_hunt/meta_digest 等子 Agent 运行在 data/agents/innovator-001/ 目录下,
所有指向其它 Agent 的路径都必须使用 ../{agent_name}/ 格式(上一级的兄弟目录):
正确: ../{agent_name}/train/knowhow.md
错误: data/agents/{agent_name}/train/knowhow.md ← 会变成嵌套路径!
错误: train/knowhow.md ← 会写到 innovator-001 自己的目录
目录结构关系:
data/agents/
├── innovator-001/ ← 子 Agent CLI 的 CWD
│ ├── .claude/skills/ ← l1/l2 知识文件
│ └── workspace/ ← innovator 自己的工作区
├── poetry_writer/ ← ../ poetry_writer/ 可以访问到
│ ├── train/ ← Hunt 写入这里
│ ├── knowledge/ ← Digest 写入这里
│ └── .claude/skills/ ← Digest 生成 SKILL.md 到这里
└── other_agent/
20.4 l1/l2 Skill 角色定位
当前架构(执行型,v1)
l1/l2 SKILL.md 文件作为知识手册,被 Claude CLI 进程自动读取。 meta_hunt 等执行型 Agent 参考这些知识,直接使用原生工具(Bash、Read、Write)执行任务。
meta_hunt (执行型, 有工具权限)
├── 参考 l2-web-research/SKILL.md → 了解搜索方法
├── 参考 l1-web-fetch/SKILL.md → 了解爬取方法
└── 直接用 Bash curl 执行搜索和爬取
未来架构(递归编排型,v2)
每个 l1/l2 作为独立子 Agent 通过 [CALL:] 调度:
meta_hunt (编排型, 无工具)
├── [CALL: l2-web-research] → 独立 CLI 进程
│ ├── [CALL: l1-search-engine] → 独立 CLI 进程
│ └── [CALL: l1-web-fetch] → 独立 CLI 进程
└── [CALL: l1-text-transform] → 独立 CLI 进程
v2 需要 agentManager.callAgent() 支持递归 [CALL:] 解析,并加入 maxDepth 防止死循环。
20.5 数据流向图
用户: "帮我创建一个写诗的 Agent"
│
▼
Innovator (--tools "", 纯文本编排)
│
├── [CALL: meta_creator] ──▶ 引擎硬编码 ──▶ AgentScaffold.create()
│ 创建 data/agents/poetry_writer/ (模板 Bootstrap)
│
├── [CALL: meta_hunt] ──▶ Claude CLI (cwd: innovator-001/)
│ 读取 .claude/skills/l1-*/l2-* 知识
│ 用 Bash/curl 搜索调研
│ 写入 data/agents/poetry_writer/train/
│ └── knowhow.md + toplist.md + agent_profile.md
│
├── [CALL: meta_digest] ──▶ Claude CLI (cwd: innovator-001/)
│ 读取 train/ (knowhow + toplist + agent_profile)
│ 提炼写入 knowledge/knowhow.md + benchmark.md
│ 生成 .claude/skills/main_skill/SKILL.md
│ 生成 Bootstrap: agent.md, soul.md, tools.md,
│ heartbeat.md, user.md
│
├── [CALL: meta_evolving] ──▶ Claude CLI (cwd: poetry_writer/)
│ 运行测试用例
│ 对照 benchmark 评分
│
└── [CALL: poetry_writer] ──▶ Claude CLI (cwd: poetry_writer/)
执行用户的原始需求