--- name: kb-workflow description: 当收到"添加到知识库 + 链接" 或"保存到知识库 + 链接"时使用 --- # KB Workflow ## 触发条件 | 触发词 | 行为 | 示例 | |--------|------|------| | `添加到知识库` + 链接 | 添加到知识库并处理 | "添加到知识库 https://www.bilibili.com/video/BVxxx" | | `保存到知识库` + 链接 | 同上 | "保存到知识库 https://www.bilibili.com/video/BVxxx" | --- ## 状态机定义 工作流是一个严格的状态机,每个状态有明确的前置条件和后置条件: | 状态 | 前置条件 | 执行动作 | 成功后进入 | 失败处理 | |------|---------|---------|-----------|---------| | `init` | 用户触发 + URL 有效 | 创建 state.json,检查环境变量 | `link_parse` | 报错退出 | | `link_parse` | state.json 存在 | 解析链接,提取平台和ID | `metadata` | 记录错误,最多重试1次 | | `metadata` | platform, content_id 已知 | 提取元数据 | `content` | 记录错误,最多重试1次 | | `content` | 元数据文件存在 | 下载内容/字幕 | `analyze` 或 `whisper` | 根据错误类型处理 | | `whisper` | 视频已下载,无官方字幕 | 语音识别转文字 | `analyze` | 尝试 OCR 降级 | | `analyze` | 有文本内容(字幕/识别结果/文章) | AI 深度分析 | `archive` | **流程失败,报错退出** | | `archive` | 分析报告存在 | 归档 + Git 提交 | `done` | 记录错误,可手动处理 | | `done` | - | 汇报完成 | - | - | ### 状态判断流程图 ``` 用户发送链接 ↓ ┌─────────────────────────────────────┐ │ Step 0: 环境变量检查 │ │ 缺少必需变量 → 报错退出 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 1: 链接解析 (link_parse) │ │ 输出: platform, content_type, id │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 2: 元数据提取 (metadata) │ │ 输出: title, author, etc. │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ content_type 判断 │ ├─────────────────────────────────────┤ │ video/zvideo → Step 3a (视频处理) │ │ article/zhuanlan/question → Step 3b │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 3a: 视频处理 │ │ 有官方字幕? → 是 → Step 5 │ │ → 否 → Step 4 (Whisper) │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 3b: 文章处理 │ │ 提取文字 → 直接进入 Step 5 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 4: Whisper 语音识别 (可选) │ │ 无字幕时执行,生成 text/json/srt │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 5: 深度分析 (analyze) │ │ ⚠️ 必须成功,否则流程失败 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ Step 6: 归档 (archive) │ │ 复制到归档目录 + Git 提交 │ └─────────────────────────────────────┘ ↓ 完成 ``` --- ## 环境变量清单 ### 必需变量(缺失则报错退出) | 变量名 | 用途 | 示例 | |--------|------|------| | `AI_API_KEY` | AI API 密钥 | `your-api-key` | | `AI_PROVIDER` | AI 提供商 | `zhipu` / `openai` / `minimax` | | `AI_MODEL` | 模型名称 | `glm-5` / `gpt-4` | | `AI_BASE_URL` | API 端点 | `https://open.bigmodel.cn/api/coding/paas/v4` | ### 可选变量 | 变量名 | 用途 | 用途说明 | |--------|------|---------| | `BILIBILI_COOKIE` | B站登录态 | 下载会员视频 | | `ZHIHU_COOKIE` | 知乎登录态 | 访问专栏等 | | `HF_TOKEN` | HuggingFace Token | 说话者分离功能 | | `KB_ARCHIVE_PATH` | 归档目录 | 默认 `~/work/zq/30.资源/AI分析` | | `KB_GIT_ROOT` | Git 仓库根目录 | 默认 `~/work/zq` | | `KB_GIT_USER` | Git 提交用户名 | 归档时使用 | | `KB_GIT_EMAIL` | Git 提交邮箱 | 归档时使用 | ### 配置方法 ```bash # 创建专用配置文件 cat > ~/.kb_env << 'EOF' export AI_API_KEY="your-api-key" export AI_PROVIDER="zhipu" export AI_MODEL="glm-5" export AI_BASE_URL="https://open.bigmodel.cn/api/coding/paas/v4" export BILIBILI_COOKIE="SESSDATA=xxx; bili_jct=xxx" export KB_ARCHIVE_PATH="$HOME/work/zq/30.资源/AI分析" export KB_GIT_ROOT="$HOME/work/zq" EOF # 在 ~/.bashrc 中添加 [ -f ~/.kb_env ] && source ~/.kb_env ``` --- ## 步骤详解 ### Step 0: 环境变量检查 **前置条件:** 无 **执行命令:** ```bash # 加载环境变量 if [ -f ~/.kb_env ]; then source ~/.kb_env; fi # 检查必需变量 for var in AI_API_KEY AI_PROVIDER AI_MODEL AI_BASE_URL; do if [ -z "${!var}" ]; then echo "❌ 错误:$var 未设置" exit 1 fi done echo "✅ 环境变量检查通过" ``` **成功标准:** - 所有必需变量已设置 - 输出 "✅ 环境变量检查通过" **失败处理:** - 缺少任何必需变量 → 报错退出,提示用户配置 **输出示例:** ``` ✅ 环境变量检查通过 AI_PROVIDER: zhipu AI_MODEL: glm-5 ``` **错误示例:** ``` ❌ 错误:AI_API_KEY 未设置 请配置以下环境变量: - AI_API_KEY - AI_PROVIDER - AI_MODEL - AI_BASE_URL ``` --- ### Step 1: 链接解析 **前置条件:** - 环境变量检查通过 - URL 格式有效 **执行命令:** ```bash # 获取目录路径 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py --pending # 解析链接 python3 ~/.openclaw/skills/kb-link-parser/link-parser.py --url "[URL]" ``` **成功标准:** - 返回 JSON 包含 `success: true` - 包含字段:`platform`, `content_type`, `content_id` - 生成文件:`pending/{platform}_{id}.link.json` **失败处理:** - 不支持的平台 → 报错退出,告知用户支持的平台 - URL 无效 → 报错退出,请用户提供正确链接 **输出示例:** ```json { "success": true, "platform": "bilibili", "content_type": "video", "content_id": "BV1xx411c7mD", "output_file": "pending/bilibili_BV1xx411c7mD.link.json" } ``` **错误示例:** ```json { "success": false, "error": "不支持的平台: example.com", "supported_platforms": ["bilibili.com", "zhihu.com", "youtube.com"] } ``` --- ### Step 2: 元数据提取 **前置条件:** - Step 1 完成 - `platform`, `content_type`, `content_id` 已知 **执行命令:** ```bash # 获取目录路径 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py --metadata # 根据平台选择命令 # B站视频 python3 ~/.openclaw/skills/kb-bilibili-metadata/bilibili_metadata.py \ --id "[BV号]" --type video \ --output "metadata/bilibili_[BV号].meta.json" # B站专栏 python3 ~/.openclaw/skills/kb-bilibili-metadata/bilibili_metadata.py \ --id "[cv号]" --type article \ --output "metadata/bilibili_cv[cv号].meta.json" # 知乎问答 python3 ~/.openclaw/skills/kb-zhihu-metadata/zhihu_metadata.py \ --id "[问题ID]" --type question \ --output "metadata/zhihu_[ID].meta.json" # 知乎视频 python3 ~/.openclaw/skills/kb-zhihu-metadata/zhihu_metadata.py \ --id "[视频ID]" --type zvideo \ --output "metadata/zhihu_[ID].meta.json" ``` **成功标准:** - 返回 JSON 包含 `success: true` - 包含字段:`platform`, `content_id`, `title` - 生成文件:`metadata/{platform}_{id}.meta.json` **失败处理:** - 网络错误 → 重试1次 - 内容不存在 → 报错退出 - 需要登录 → 提示配置 Cookie **输出示例:** ```json { "success": true, "platform": "bilibili", "content_id": "BV1xx411c7mD", "content_type": "video", "title": "视频标题", "author": "UP主名字", "duration": "10:30", "output_file": "metadata/bilibili_BV1xx411c7mD.meta.json" } ``` **错误示例:** ```json { "success": false, "error": "视频不存在或已被删除", "content_id": "BV1xx411c7mD" } ``` --- ### Step 3a: 视频内容下载 **前置条件:** - Step 2 完成 - `content_type` 为 `video` 或 `zvideo` **执行命令:** ```bash # 获取目录路径 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py --content_downloads # B站视频 - 优先尝试字幕 python3 ~/.openclaw/skills/kb-bilibili-content/bilibili_content.py \ --id "[BV号]" --type subtitle-download \ --output "content/downloads/" # 检查是否有官方字幕 # 如果 has_subtitle=true → 进入 Step 5 # 如果 has_subtitle=false → 下载视频,进入 Step 4 ``` **成功标准:** - 返回 JSON 包含 `success: true` - `has_subtitle=true`: 有字幕文件 - `has_subtitle=false`: 视频文件下载成功 **失败处理:** - 403 禁止访问 → 检查 BILIBILI_COOKIE 配置 - 网络超时 → 重试1次 - 会员视频 → 提示需要配置 Cookie **输出示例(有字幕):** ```json { "success": true, "type": "subtitle", "has_subtitle": true, "subtitle_file": "content/downloads/bilibili_BV1xx411c7mD.srt", "message": "官方字幕下载成功" } ``` **输出示例(无字幕):** ```json { "success": true, "type": "subtitle", "has_subtitle": false, "message": "无官方字幕,需要下载视频进行语音识别" } ``` **错误示例:** ```json { "success": false, "error": "403 Forbidden - 可能需要会员权限", "suggestion": "请配置 BILIBILI_COOKIE 环境变量" } ``` --- ### Step 3b: 文章内容提取 **前置条件:** - Step 2 完成 - `content_type` 为 `article`、`zhuanlan` 或 `question` **执行命令:** ```bash # B站专栏 python3 ~/.openclaw/skills/kb-bilibili-content/bilibili_content.py \ --id "[cv号]" --type article \ --output "content/" # 知乎专栏 python3 ~/.openclaw/skills/kb-zhihu-content/zhihu_content.py \ --type article-from-media \ --output "content/" ``` **成功标准:** - 返回 JSON 包含 `success: true` - 包含字段:`filepath`, `content_length` - 跳过 Step 4,直接进入 Step 5 **输出示例:** ```json { "success": true, "type": "article", "filepath": "content/bilibili_cv43780186.txt", "content_length": 5234, "message": "文章内容提取成功" } ``` --- ### Step 4: Whisper 语音识别 **前置条件:** - Step 3a 完成 - `has_subtitle=false` - 视频文件已下载 **执行命令:** ```bash # 获取目录路径 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py --content # 普通识别 python3 ~/.openclaw/skills/kb-whisper/whisper.py \ --input "content/downloads/bilibili_BV1xx411c7mD.mp4" \ --model base \ --output "content/" # 带说话者分离(需要 HF_TOKEN) if [ -n "$HF_TOKEN" ]; then python3 ~/.openclaw/skills/kb-whisper-diarization/whisper_diarization.py \ --input "content/downloads/bilibili_BV1xx411c7mD.mp4" \ --model base --diarize \ --output "content/" fi ``` **成功标准:** - 返回 JSON 包含 `success: true` - 生成文件:`.json`, `.txt`, `.srt` **失败处理:** - 模型未下载 → 提示下载模型 - 内存不足 → 尝试更小的模型 - Whisper 失败 → 尝试 OCR 降级 **输出示例:** ```json { "success": true, "input_file": "content/downloads/bilibili_BV1xx411c7mD.mp4", "model": "base", "output_files": { "json": "content/bilibili_BV1xx411c7mD.json", "txt": "content/bilibili_BV1xx411c7mD.txt", "srt": "content/bilibili_BV1xx411c7mD.srt" }, "duration_seconds": 630 } ``` --- ### Step 5: 深度分析 **前置条件:** - 有文本内容(字幕/识别结果/文章) - 元数据文件存在 **执行命令:** ```bash # 获取目录路径 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py --analyzed # 分析视频 AI_API_KEY="$AI_API_KEY" AI_PROVIDER="zhipu" AI_MODEL="glm-5" \ python3 -u ~/.openclaw/skills/kb-deep-analyzer/deep_analyzer.py \ --metadata "metadata/bilibili_BV1xx411c7mD.meta.json" \ --content "content/bilibili_BV1xx411c7mD.json" \ --output "analyzed/bilibili_BV1xx411c7mD.md" \ --type video \ --provider zhipu --model glm-5 # 分析文章 AI_API_KEY="$AI_API_KEY" AI_PROVIDER="zhipu" AI_MODEL="glm-5" \ python3 -u ~/.openclaw/skills/kb-deep-analyzer/deep_analyzer.py \ --metadata "metadata/xxx.meta.json" \ --content "content/xxx.txt" \ --output "analyzed/xxx.md" \ --type article \ --provider zhipu --model glm-5 ``` **成功标准:** - 返回 JSON 包含 `success: true` - 生成分析报告文件 **失败处理:** - ⚠️ **深度分析失败 = 整个流程失败** - API 调用失败 → 记录错误,**终止流程** - **禁止**使用预设模板或降级内容 **输出示例:** ```json { "success": true, "output_file": "analyzed/bilibili_BV1xx411c7mD.md", "model": "glm-5", "provider": "zhipu" } ``` **错误示例:** ```json { "success": false, "error": "AI API 调用失败: rate limit exceeded", "message": "深度分析失败,整个流程终止" } ``` --- ### Step 6: 归档 **前置条件:** - Step 5 完成 - 分析报告文件存在 **执行命令:** ```bash # 归档 python3 ~/.openclaw/skills/kb-workflow/kb_workflow.py \ --archive-file "analyzed/bilibili_BV1xx411c7mD.md" # 如果配置了 Git,会自动提交 ``` **成功标准:** - 文件复制到归档目录 - Git 提交成功(如果配置) **失败处理:** - 归档失败 → 记录错误,文件仍可用 - Git 失败 → 不影响主流程 **输出示例:** ```json { "success": true, "archive_path": "~/work/zq/30.资源/AI分析/2026-03-13/bilibili_BV1xx411c7mD.md", "git_commit": "abc1234" } ``` --- ## 目录结构 ``` ~/work/knowledge-base/ # 知识库根目录 ├── pending/ # 待处理链接 │ └── {platform}_{id}.link.json ├── metadata/ # 元数据 │ └── {platform}_{id}.meta.json ├── content/ # 内容 │ ├── downloads/ # 视频下载 │ │ └── {platform}_{id}.mp4 │ ├── {platform}_{id}.txt # 文本内容 │ └── {platform}_{id}.json # Whisper 结果 └── analyzed/ # 深度分析报告 └── {platform}_{id}.md ~/work/zq/30.资源/AI分析/ # 归档目录 └── YYYY-MM-DD/ └── {platform}_{id}.md ``` --- ## 子技能清单 | 步骤 | 子技能 | 命令 | |------|--------|------| | 1 | kb-link-parser | `--url "[URL]"` | | 2 | kb-bilibili-metadata | `--id "[ID]" --type video --output "[PATH]"` | | 2 | kb-zhihu-metadata | `--id "[ID]" --type question --output "[PATH]"` | | 3a | kb-bilibili-content | `--id "[ID]" --type subtitle-download --output "[PATH]"` | | 3a | kb-bilibili-content | `--id "[ID]" --type video --output "[PATH]"` | | 3b | kb-bilibili-content | `--id "[ID]" --type article --output "[PATH]"` | | 3b | kb-zhihu-content | `--type article-from-media --output "[PATH]"` | | 4 | kb-whisper | `--input "[VIDEO]" --model base --output "[PATH]"` | | 4 | kb-whisper-diarization | `--input "[VIDEO]" --model base --diarize --output "[PATH]"` | | 5 | kb-deep-analyzer | `--metadata "[META]" --content "[CONTENT]" --output "[OUT]" --type video` | --- ## 端到端示例 ### 示例 1: B站视频(有官方字幕) **输入:** `添加到知识库 https://www.bilibili.com/video/BV1xx411c7mD` ``` Step 0: ✅ 环境变量检查通过 Step 1: ✅ 链接解析 → bilibili, video, BV1xx411c7mD Step 2: ✅ 元数据提取 → 标题: "xxx", 作者: "xxx" Step 3a: ✅ 字幕下载 → has_subtitle=true, bilibili_BV1xx411c7mD.srt Step 4: ⏭️ 跳过(有官方字幕) Step 5: ✅ 深度分析 → bilibili_BV1xx411c7mD.md Step 6: ✅ 归档 → ~/work/zq/30.资源/AI分析/2026-03-13/ ``` ### 示例 2: B站视频(无官方字幕) **输入:** `添加到知识库 https://www.bilibili.com/video/BV1yy411c7mE` ``` Step 0: ✅ 环境变量检查通过 Step 1: ✅ 链接解析 → bilibili, video, BV1yy411c7mE Step 2: ✅ 元数据提取 → 标题: "xxx", 时长: "15:30" Step 3a: ⚠️ 无官方字幕 → 下载视频 Step 3a: ✅ 视频下载 → bilibili_BV1yy411c7mE.mp4 Step 4: ✅ Whisper 识别 → bilibili_BV1yy411c7mE.json/txt/srt Step 5: ✅ 深度分析 → bilibili_BV1yy411c7mE.md Step 6: ✅ 归档 ``` ### 示例 3: 403 下载失败 **输入:** `添加到知识库 https://www.bilibili.com/video/BV1zz411c7mF` ``` Step 0: ✅ 环境变量检查通过 Step 1: ✅ 链接解析 Step 2: ✅ 元数据提取 Step 3a: ❌ 403 Forbidden → 可能需要会员权限 → 请配置 BILIBILI_COOKIE 环境变量 → 流程暂停,等待用户处理 ``` --- ## 常见错误处理 ### 错误 1: 环境变量未设置 **症状:** `❌ 错误:AI_API_KEY 未设置` **解决:** ```bash echo 'export AI_API_KEY="your-key"' >> ~/.kb_env source ~/.kb_env ``` ### 错误 2: 403 下载失败 **症状:** B站视频下载返回 403 **解决:** 1. 获取 B站 Cookie(F12 → Network → Copy Cookie) 2. 配置环境变量: ```bash echo 'export BILIBILI_COOKIE="SESSDATA=xxx; bili_jct=xxx"' >> ~/.kb_env source ~/.kb_env ``` ### 错误 3: 深度分析失败 **症状:** `success: false` from kb-deep-analyzer **处理:** - **整个流程终止** - 检查 AI_API_KEY 是否有效 - 检查 AI_BASE_URL 是否正确 - 检查模型配额是否用尽 ### 错误 4: Whisper 模型未下载 **症状:** `Model file not found` **解决:** ```bash cd ~/whisper.cpp ./models/download-ggml-model.sh base ``` --- ## 状态管理(断点续传) > ⚠️ 此功能需要完成 P3 实现 ```bash # 初始化状态 python3 kb_workflow.py --init-state "[URL]" # 查询当前状态 python3 kb_workflow.py --get-state "[URL]" # 推进到下一步 python3 kb_workflow.py --advance-step "[URL]" "metadata" # 记录错误 python3 kb_workflow.py --record-error "[URL]" "403 Forbidden" # 获取恢复指令 python3 kb_workflow.py --resume "[URL]" ``` --- ## ⚠️ 严格失败处理原则 1. **深度分析不可跳过**:kb-deep-analyzer 是必须成功的步骤 2. **失败即终止**:如果深度分析返回 `success: false`,必须立即停止 3. **禁止降级处理**:不能使用预设模板或简单摘要"假装成功" 4. **每次执行都要使用 AI**:必须有真实的 AI API 调用