diff --git a/openclaw/knowledgebase/prd/PRD-USER-GUIDE.md b/openclaw/knowledgebase/prd/PRD-USER-GUIDE.md new file mode 100644 index 00000000..f05fa2a7 --- /dev/null +++ b/openclaw/knowledgebase/prd/PRD-USER-GUIDE.md @@ -0,0 +1,337 @@ +# Ralph PRD 创建与执行指南 + +> 如何用 prd.json 描述一个多步骤任务,让星枢自动跑完。 + +--- + +## 📋 一分钟速览 + +``` +1. 创建 prd.json(按本指南格式) +2. 放进 ~/ralph/queue/ 目录 +3. 告诉星枢:「执行这个 PRD」 +4. 星枢派 Ralph Engine 子 agent 自动跑完 +5. 完成 → Telegram 收到报告 +``` + +--- + +## 📁 PRD 文件格式 + +```json +{ + "projectName": "项目名称(中文)", + "projectType": "任务类型", + "created": "YYYY-MM-DD", + "description": "项目简要描述", + "workDir": "执行时的工作目录(绝对路径)", + "maxIterations": 10, + "userStories": [ + { + "id": "1", + "title": "任务描述(动宾结构,越具体越好)", + "passes": false, + "qualityGate": { + "type": "quality gate 类型", + "description": "如何判断完成", + "command": "验证命令(可选)", + "path": "期望文件路径(可选)" + }, + "notes": "执行备注(留空)" + } + ] +} +``` + +--- + +## 🎯 Quality Gate 类型说明 + +设计 quality gate 是 PRD 中最关键的一步。gate 决定了子 agent 如何判断 story 完成。 + +| 类型 | 适用场景 | 设计方法 | +|------|---------|---------| +| `file-exists` | 文件生成类任务 | 指定期望生成的文件路径 | +| `command-output` | 命令执行类 | 指定命令和期望输出片段 | +| `human-review` | 创意/审核类 | 指定需要人工确认的环节 | + +### 设计原则 + +**好的 quality gate 示例:** +```json +{"type": "file-exists", "path": "/Users/weishen/ralph/output/report.md"} +{"type": "command-output", "command": "wc -w /tmp/draft.md | awk '{print $1}'", "expected": "500"} +{"type": "command-output", "command": "test -f /tmp/cover.png && echo OK", "expected": "OK"} +``` + +**❌ 差的 quality gate(无法判断):** +```json +{"type": "file-exists", "description": "生成报告"} +``` +没有具体文件路径,引擎无法验证。 + +--- + +## 🛠️ 四步创建 PRD + +### Step 1:确定项目类型 + +| 类型 | 适用场景 | 示例 | +|------|---------|------| +| `research` | 信息收集、分析 | 竞品分析、市场调研 | +| `content-production` | 内容创作 | 公众号文章、视频脚本 | +| `video` | 视频制作 | B站视频、教程 | +| `system-audit` | 系统巡检、维护 | 服务器检查、日志分析 | +| `multi-step-task` | 通用多步骤任务 | 任何包含多个阶段的工作 | + +### Step 2:拆解 Stories + +**每个 story 必须满足:** +- 能在单次 LLM 调用中完成 +- 有明确的输出物(文件或命令结果) +- quality gate 可以被自动化验证 + +**拆解检查清单:** +- [ ] story 描述是一个具体的「动作+结果」 +- [ ] 有明确的 quality gate 验证方式 +- [ ] 不依赖其他 story 的输出(解耦) +- [ ] 大小适中(避免「完成整个项目」这种过大的 story) + +**好 story vs 差 story:** + +| 差 ❌ | 好 ✅ | +|-------|-------| +| 完成内容营销策略 | 使用 Last30Days 研究竞品近30天动态 | +| 写一篇文章 | 生成 1500 字公众号文章草稿,保存到 draft.md | +| 做视频 | 用 FFmpeg 将3个素材片段拼接成 3 分钟视频 | + +### Step 3:填写 quality gate + +每个 story 必须设计 quality gate: + +```json +{ + "id": "1", + "title": "使用 Last30Days 研究竞品动态", + "qualityGate": { + "type": "file-exists", + "description": "确认研究数据文件已生成", + "path": "/Users/weishen/ralph/active/campaign/research.md" + } +} +``` + +### Step 4:创建文件 + +在 `~/ralph/queue/` 创建 `prd.json`: + +```bash +mkdir -p ~/ralph/queue +# 用编辑器创建 prd.json,或让星枢帮你创建 +``` + +--- + +## 📝 PRD 示例 + +### 示例 A:公众号文章生产 + +```json +{ + "projectName": "AI 工具对比文章", + "projectType": "content-production", + "created": "2026-04-11", + "workDir": "/Users/weishen/ralph/active/ai-tools-article", + "maxIterations": 8, + "userStories": [ + { + "id": "1", + "title": "使用 Last30Days 研究 Cursor 和 Windsurf 近30天热点", + "passes": false, + "qualityGate": { + "type": "file-exists", + "description": "确认生成了原始数据文件", + "path": "/Users/weishen/ralph/active/ai-tools-article/raw_research.md" + }, + "notes": "" + }, + { + "id": "2", + "title": "生成文章大纲(标题/小标题/金句)", + "passes": false, + "qualityGate": { + "type": "file-exists", + "description": "确认大纲文件存在", + "path": "/Users/weishen/ralph/active/ai-tools-article/outline.md" + }, + "notes": "" + }, + { + "id": "3", + "title": "撰写完整文章(1500字)", + "passes": false, + "qualityGate": { + "type": "command-output", + "description": "字数 >= 1200", + "command": "wc -w /Users/weishen/ralph/active/ai-tools-article/article.md | awk '{print $1}'", + "expected": "1" + }, + "notes": "" + }, + { + "id": "4", + "title": "生成文章配图", + "passes": false, + "qualityGate": { + "type": "file-exists", + "description": "确认封面图生成", + "path": "/Users/weishen/ralph/active/ai-tools-article/cover.png" + }, + "notes": "" + }, + { + "id": "5", + "title": "人工预览确认(发布前审核)", + "passes": false, + "qualityGate": { + "type": "human-review", + "description": "人工预览文章,确认无误后手动告知星枢继续", + "notes": "" + } + } + ] +} +``` + +### 示例 B:竞品分析研究 + +```json +{ + "projectName": "Cursor vs Windsurf 竞品分析", + "projectType": "research", + "created": "2026-04-11", + "workDir": "/Users/weishen/ralph/active/cursor-vs-windsurf", + "maxIterations": 6, + "userStories": [ + { + "id": "1", + "title": "Last30Days 搜索 Cursor 近30天热点", + "passes": false, + "qualityGate": { + "type": "file-exists", + "path": "/Users/weishen/ralph/active/cursor-vs-windsurf/cursor_research.md" + }, + "notes": "" + }, + { + "id": "2", + "title": "Last30Days 搜索 Windsurf 近30天热点", + "passes": false, + "qualityGate": { + "type": "file-exists", + "path": "/Users/weishen/ralph/active/cursor-vs-windsurf/windsurf_research.md" + }, + "notes": "" + }, + { + "id": "3", + "title": "抓取两个竞品的官网更新", + "passes": false, + "qualityGate": { + "type": "file-exists", + "path": "/Users/weishen/ralph/active/cursor-vs-windsurf/official_updates.md" + }, + "notes": "" + }, + { + "id": "4", + "title": "生成对比分析报告", + "passes": false, + "qualityGate": { + "type": "command-output", + "description": "报告 >= 1000 字", + "command": "wc -w /Users/weishen/ralph/active/cursor-vs-windsurf/analysis_report.md | awk '{print $1}'", + "expected": "1" + }, + "notes": "" + }, + { + "id": "5", + "title": "保存到 Obsidian 知识库", + "passes": false, + "qualityGate": { + "type": "file-exists", + "path": "/Users/weishen/Workspace/nexus/openclaw/knowledgebase/research/cursor-vs-windsurf-2026-04.md" + }, + "notes": "" + } + ] +} +``` + +--- + +## 🚀 执行与追踪 + +### 提交 PRD 执行 + +```bash +# 把 PRD 放进队列 +mv ~/Downloads/my-prd.json ~/ralph/queue/ + +# 告诉星枢: +# 「执行 ~/ralph/queue/my-prd.json」 +``` + +### 查看执行状态 + +```bash +# 查看所有项目的状态 +ls -la ~/ralph/active/ + +# 查看某个项目的 prd.json 状态 +cat ~/ralph/active/my-project/prd.json + +# 查看执行日志 +cat ~/ralph/active/my-project/progress.txt +``` + +### 目录结构说明 + +| 目录 | 用途 | +|------|------| +| `~/ralph/queue/` | PRD 入口,放入待执行的项目 | +| `~/ralph/active/` | 正在执行的项目(从 queue 移入) | +| `~/ralph/archive/` | 已完成项目归档 | + +### human-review 类型的处理 + +当遇到 `human-review` 类型 story: +1. 子 agent 会暂停并等待 +2. 你手动检查输出物 +3. 告诉星枢:「Story #N 可以继续」 +4. 星枢更新 prd.json 继续执行 + +--- + +## ⚠️ 常见问题 + +**Q: story 太长做不完怎么办?** +A: 拆小。每个 story 应该在 5 分钟内完成。 + +**Q: quality gate 判断失败怎么办?** +A: 检查 `progress.txt` 看失败原因,修复问题后告诉星枢「重试 Story #N」。 + +**Q: Ubuntu1 和 MacMini 怎么选执行节点?** +A: 内容生产(Last30Days、图片生成、n8n)→ MacMini;系统运维(Docker、巡检)→ Ubuntu1。 + +**Q: 任务中途可以暂停吗?** +A: 可以。直接告诉星枢「暂停」,prd.json 会保留当前状态。 + +--- + +## 📂 相关文件 + +- 模板:`openclaw/knowledgebase/prd/TEMPLATE.md` +- 技术实现:`~/.openclaw/scripts/ralph_engine.py` +- 知识库目录:`openclaw/knowledgebase/prd/` diff --git a/openclaw/knowledgebase/prd/TEMPLATE.md b/openclaw/knowledgebase/prd/TEMPLATE.md new file mode 100644 index 00000000..e7cf40b3 --- /dev/null +++ b/openclaw/knowledgebase/prd/TEMPLATE.md @@ -0,0 +1,446 @@ +# PRD 模板 - 内容生产工作流(非编程任务) + +> 基于 Ralph 模式改造,适用于视频制作、文章发布、研究分析等非编程任务。 + +--- + +## 📋 prd.json - 结构化任务清单 + +```json +{ + "version": "1.0", + "projectName": "项目名称", + "projectType": "content-production | video | research | multi-step-task", + "created": "YYYY-MM-DD", + "description": "项目简要描述", + "userStories": [ + { + "id": "1", + "title": "任务描述(动宾结构,越具体越好)", + "branchName": "feature/xxx", + "passes": false, + "assignedTo": "agentId 或 human", + "qualityGate": { + "type": "file-exists | command-output | human-review | llm-judge", + "description": "如何判断此任务完成", + "command": "(可选)验证命令", + "expected": "(可选)预期输出" + }, + "notes": "执行过程中的备注/心得" + } + ], + "qualityCheckCommands": { + "description": "项目级质量检查命令(非 story 级别)" + } +} +``` + +--- + +## ✅ Quality Gate 类型说明 + +| 类型 | 适用场景 | 判断方式 | +|------|---------|---------| +| `file-exists` | 文件生成类任务 | 检查文件是否生成 | +| `command-output` | 命令执行类 | 验证命令退出码或输出 | +| `human-review` | 创意/审核类 | 需要人工确认(不可完全消除) | +| `llm-judge` | 内容质量评估 | LLM 评估输出质量 | + +--- + +## 📄 适用场景模板 + +### 场景 A:视频制作 + +```json +{ + "projectName": "AI 工具对比视频", + "projectType": "video", + "userStories": [ + { + "id": "1", + "title": "撰写 3 分钟视频脚本(AI 工具对比)", + "qualityGate": {"type": "file-exists", "description": "脚本文件存在且 > 500 字"}, + "notes": "" + }, + { + "id": "2", + "title": "收集/生成视频素材片段", + "qualityGate": {"type": "file-exists", "description": "素材文件夹存在且包含 > 3 个片段"}, + "notes": "" + }, + { + "id": "3", + "title": "FFmpeg 剪辑拼接成完整视频", + "qualityGate": {"type": "command-output", "description": "ffprobe 检查视频时长 3min±10s"}, + "notes": "" + }, + { + "id": "4", + "title": "生成封面图", + "qualityGate": {"type": "file-exists", "description": "封面图存在"}, + "notes": "" + }, + { + "id": "5", + "title": "上传到 B 站", + "qualityGate": {"type": "human-review", "description": "人工确认视频已发布"}, + "notes": "" + } + ] +} +``` + +### 场景 B:文章发布公众号 + +```json +{ + "projectName": "公众号文章 - AI 趋势分析", + "projectType": "content-production", + "userStories": [ + { + "id": "1", + "title": "使用 Last30Days 研究 AI 趋势", + "qualityGate": {"type": "file-exists", "description": "生成的研究报告存在"}, + "notes": "" + }, + { + "id": "2", + "title": "生成摘要、金句、观点提炼", + "qualityGate": {"type": "command-output", "description": "输出包含摘要+3个以上金句"}, + "notes": "" + }, + { + "id": "3", + "title": "生成文章配图", + "qualityGate": {"type": "file-exists", "description": "配图文件存在"}, + "notes": "" + }, + { + "id": "4", + "title": "排版并预览(HTML/Markdown)", + "qualityGate": {"type": "human-review", "description": "人工预览确认格式无误"}, + "notes": "" + }, + { + "id": "5", + "title": "发布到公众号", + "qualityGate": {"type": "human-review", "description": "人工确认已群发"}, + "notes": "" + } + ] +} +``` + +### 场景 C:竞品动态追踪 + +```json +{ + "projectName": "竞品分析 - Cursor vs Windsurf", + "projectType": "research", + "userStories": [ + { + "id": "1", + "title": "Last30Days 搜索两个竞品近 30 天动态", + "qualityGate": {"type": "file-exists", "description": "生成两个研究文件"}, + "notes": "" + }, + { + "id": "2", + "title": "抓取竞品官网更新页面", + "qualityGate": {"type": "file-exists", "description": "页面内容已保存"}, + "notes": "" + }, + { + "id": "3", + "title": "生成对比分析报告", + "qualityGate": {"type": "command-output", "description": "报告文件 > 1000 字"}, + "notes": "" + }, + { + "id": "4", + "title": "保存到 Obsidian 知识库", + "qualityGate": {"type": "file-exists", "description": "笔记存在于知识库"}, + "notes": "" + } + ] +} +``` + +--- + +## 🔄 Ralph 执行循环(简化版) + +不使用 Claude Code 的情况下,可通过 OpenClaw sub-agent 模拟: + +``` +每次循环: + 1. 读取 prd.json + 2. 选取 id 最小的 passes:false 的 story + 3. 生成 fresh sub-session 执行该 story + 4. 运行 quality gate 检查 + 5. 通过 → passes:true,追加 notes + 6. 重复直到全部完成 +``` + +--- + +## 📝 progress.txt 格式 + +``` +[YYYY-MM-DD HH:mm] Story #N 完成: + 心得: <执行过程中的学到的东西> + 耗时: <N 分钟> +--- +``` + +--- + +## 💡 与编程任务 PRD 的核心区别 + +| 维度 | 编程任务 PRD | 非编程任务 PRD | +|------|------------|--------------| +| 工具链 | git, npm, typecheck, test | FFmpeg, 爬虫, LLM | +| 质量门 | 自动(CI/CD) | 混合(自动+人工) | +| 人工介入 | 极低(代码审查) | 中等(创意审核) | +| Story 大小 | 极小(单次完成) | 中等(可包含创意工作) | +| 迭代速度 | 快(机器执行) | 慢(人机混合) | + +--- + +## 🦞 OpenClaw Native Ralph 架构(2026-04-11 实测验证) + +### 核心发现 + +| 问题 | 结论 | +|------|------| +| Ubuntu1 上无 skill(0个) | Skill 密集型任务 → MacMini;系统任务 → Ubuntu1 | +| sessions_spawn + node 参数 | ✅ 可跨节点派生子 agent | +| prd.json 状态机 | ✅ 落地验证通过 | +| progress.txt 追加日志 | ✅ 追加验证通过 | +| Gateway REST API | ❌ 未开启,改用 sessions_spawn | + +### 架构图 + +``` +星枢(MacMini / 主会话) + └── Ralph Engine(Python 脚本 / 星枢派生子 agent) + │ + ├── 读取 prd.json + ├── 选取 passes:false 的 story + ├── 判断 targetNode:skill密集型 → MacMini / 系统任务 → Ubuntu1 + ├── sessions_spawn(mode=run, node=目标节点) + │ └── 子 agent 执行 story + quality gate + ├── 更新 prd.json (passes:true / notes) + ├── 追加 progress.txt + └── 循环直到全部完成 → Telegram 通知 +``` + +### 节点 Skill 地图 + +| 节点 | Skill 可用性 | 适合任务类型 | +|------|------------|------------| +| MacMini (192.168.3.189) | 全部(Last30Days, n8n, OpenCode, image_generate 等) | 研究、内容生产、编码 | +| Ubuntu1 (192.168.3.47) | 无 | 系统运维、Docker、巡检 | +| Ubuntu2 (192.168.3.45) | 部分 | n8n 工作流、中间层处理 | + +### sessions_spawn 调用格式(OpenClaw Native) + +```python +# Ralph Engine 内核心调用 +sessions_spawn( + task=f"""你是 {node} 上的执行者。执行以下 story: + Story: {story_title} + Quality Gate: {qg_type} - {qg_desc} + 工作目录: {work_dir} + 目标文件: {target_path} + + 步骤: + 1. [执行命令] + 2. [quality gate 验证] + 3. [落地 marker 文件或输出] + """, + runtime="subagent", + mode="run", + node="ubuntu1 | (default MacMini)", + runTimeoutSeconds=600, + label=f"ralph-story-{story_id}" +) +``` + +### Quality Gate 落地标准(实测有效) + +```python +# ✅ 有效类型 +"type": "file-exists" # touch marker 文件 +"type": "command-output" # 命令退出码 0 +"type": "human-review" # 人工确认(不可省) + +# ⚠️ 限制 +# - Last30Days 等 skill 必须确认目标节点有装 +# - human-review 类型需要人工发送确认指令 +``` + +--- + +## 🦀 Ralph Engine 脚本(Python) + +> 路径:`~/.openclaw/scripts/ralph_engine.py` +> 运行环境:MacMini(协调层) +> 依赖:OpenClaw sessions_spawn(通过 API 或 CLI) + +```python +#!/usr/bin/env python3 +""" +Ralph Engine - OpenClaw Native +Coordinator: MacMini +Execution: 按 story 分配到对应节点 +PRD: ${WORK_DIR}/prd.json +Progress: ${WORK_DIR}/progress.txt +""" + +import json, subprocess, time, sys +from datetime import datetime + +WORK_DIR = sys.argv[1] if len(sys.argv) > 1 else "./ralph-test" +PRD_FILE = f"{WORK_DIR}/prd.json" +PROGRESS_FILE = f"{WORK_DIR}/progress.txt" + +# Skill → Node 映射 +NODE_MAP = { + "last30days": "macmini", # skill 密集型 + "n8n": "ubuntu2", + "image_generate": "macmini", + "video_generate": "macmini", + "opencode": "macmini", + "docker": "ubuntu1", # 系统任务 + "system": "ubuntu1", + "default": "macmini" +} + +def get_node_for_story(story): + """根据 story 内容判断执行节点""" + title = story.get("title", "").lower() + for key, node in NODE_MAP.items(): + if key in title: + return node + return NODE_MAP["default"] + +def spawn_story(story, work_dir): + """通过 openclaw sessions CLI 派生子 agent""" + story_id = story["id"] + title = story["title"] + qg = story.get("qualityGate", {}) + node = get_node_for_story(story) + + prompt = f"""Task: {title} +Quality Gate: {qg.get('type')} - {qg.get('description', '')} + +Work dir: {work_dir} +Output file: {qg.get('path', f'{work_dir}/story_{story_id}_out.txt')} + +Steps: +1. Execute the task +2. Run quality gate check +3. Report PASS or FAIL with details +4. Create marker file if pass: touch {work_dir}/story_{story_id}_done +""" + + # 调用 openclaw acp sessions 或者通过 CLI + cmd = [ + "openclaw", "acp", "sessions", + "--session", f"ralph-{story_id}", + "--require-existing" + ] + # 实际通过 sessions_spawn tool 调用,此处仅作架构说明 + return True # placeholder + +def main(): + prd = json.load(open(PRD_FILE)) + pending = [s for s in prd["userStories"] if not s.get("passes")] + + for story in pending: + spawn_story(story, WORK_DIR) + # 更新 prd.json + progress.txt + + print("Ralph complete") + +if __name__ == "__main__": + main() +``` + +--- + +## ⏰ 自主循环触发设计 + +### 方式一:Cron 触发(定时拉起 Ralph Engine) + +```bash +# MacMini crontab +0 2 * * * openclaw agent --task "检查 ~/ralph-queue/ 目录,有 prd.json 则启动 Ralph Engine" --agent xingshu +``` + +### 方式二:目录监听(文件触发) + +```bash +# inotifywait 或 launchd WatchPath +# 检测到 ~/ralph-queue/*.json → 自动启动 Ralph Engine +``` + +### 方式三:用户指令触发(最简单) + +``` +比利哥:开始执行 ralph prd.json +星枢 → 派生子 agent → 启动 Engine +``` + +--- + +## 📁 标准目录结构 + +``` +~/ralph/ +├── queue/ # 待执行的 prd.json 放这里 +├── active/ # 正在执行的项目 +├── archive/ # 完成的项目归档 +│ └── YYYY-MM-DD-projectName/ +│ ├── prd.json +│ ├── progress.txt +│ └── [outputs...] +└── ralph_engine.py # 执行引擎 +``` + + +--- + +## ✅ 实测验证记录(2026-04-11) + +### 测试:Ubuntu1 系统巡检 +- **结果**:3/3 stories ✅ 完成 +- **落地文件**:`sysinfo.txt`(1116B), `docker_status.txt`(835B), `audit_report.md`(2347B), `prd.json`(345B ✅ passes:true), `progress.txt`(188B ✅ 3条追加) +- **耗时**:1分43秒 + +### 关键验证点 +| 验证项 | 结果 | +|--------|------| +| prd.json passes:true 更新 | ✅ 成功 | +| progress.txt 追加日志 | ✅ 成功 | +| 跨节点 sessions_spawn | ✅ Ubuntu1 正常 | +| skill 路径(Last30Days) | ⚠️ Ubuntu1 无 skill,改用模拟 | +| 文件落地 | ✅ 实际验证 | + +### 架构修正(对比原设计) +1. **Python Ralph Engine 无法直接调用 sessions API** → 改用 "Ralph Engine as sub-agent task" +2. **skill 全在 MacMini** → 任务智能路由:系统任务→Ubuntu1/内容生产→MacMini +3. **Gateway REST API 限制** → sessions_spawn 是运行时工具,非 API + +### 最终架构(已验证) +``` +用户/星枢主会话 + └── sessions_spawn → Ralph Engine sub-agent + ├── 读取 prd.json + ├── exec 执行 story(node 本地) + ├── quality gate 检查 + ├── 更新 prd.json + progress.txt + └── 循环 → 完成后通知 +```