Imported from zhangsheng377/vpbuddy (
AGENTS.md). Install upstream withnpx skills add zhangsheng377/vpbuddy. Copyright stays with the author.
VPBuddy — AI 协作铁律 (必读)
适用对象: 所有 AI 协作 agent (Hermes / Claude / Codex / Copilot 等) 和人类贡献者。 维护: 张胜东 (起草: Hermes 2026-07-01) 最后更新: 2026-07-01
〇. 不可违反的 5 条铁律
铁律 1: 事实陈述必须有真命令验证
不准用 lsof 推断"没装"、不准用 ps 推断"在跑"、不准凭印象说"X 模块使用 Y 库"。
任何"X 没装 / Y 用 Z / 函数 W 调用了 V"的陈述,必须用真命令验证:
- Python 库:
python -c "import X; print(X.__file__)"或pip show X - CLI 工具:
which X+X --version - 代码路径:
grep -rn "def W" src/ - 运行状态: 真实启动一次, 看 log
来源: 2026-06-22 张胜东纠错 (Python 库是 conda env 静默装着, 不是 daemon 进程)。
铁律 2: ADR 驱动 + 1 提交 (代码 + 文档 + 部署同步)
每次架构变更必须:
- 写 1 个新 ADR (格式:
docs/decisions/00XX-主题.md), 顶部标状态 / 日期 / 作者 / 替代 / 依赖 - 同步更新
docs/design/总体架构.md状态号 (v1.20 → v1.21) + 顶部 ADR 索引 - 同步更新
docs/product-spec/VPBuddy_产品说明书.md相关章节 - 同步更新
pyproject.toml(版本号 / 依赖) +src/vpbuddy/_version.py(如版本变化) - 同步更新
README.md(如用户可见功能变化) - 1 个 commit 包含以上所有变更, 标题用
feat/fix/refactor(scope): ...格式
禁止:
- 改代码不写 ADR
- 写 ADR 不改 design/spec/README (drift)
- 跨多 commit 拆同一逻辑变更 (散)
- 把"实现"和"设计"分成两个 PR/commit
铁律 3: 代码先于文档
docs/decisions/00XX-*.md 是历史快照, 反映"当时为什么这么决定"。
真实架构在代码里。所以:
- 看 ADR 之前先
find src -name "*.py" | xargs head -30看 docstring - ADR 顶部如果标 "Superseded by 00YY", 跳到 00YY, 别读旧的
- 发现 ADR 跟代码不一致, 立刻承认+立刻修文档 (不准用旧 ADR 做架构假设)
铁律 4: 抓虚晃 — 说"let me check"必须同回合真起工具
任何"我看看 X" / "我检查下 Y" / "let me check" 的承诺, 同一回合必须起工具 (read_file / search_files / terminal)。禁止:
- "让我先看看..." 然后开始写结论
- 答应"我查一下" 然后 commit 不带证据
- 编造一个看起来合理的 API 路径
铁律 5: 真实部署驱动, 不接受"为 dev 方便"的设计
- 部署配置 (
requirements.txt/requirements-gpu.txt/pyproject.toml[gpu]extra) 是真路径 - 禁止 写"开发用 sqlite 凑合, 生产再换 postgres" 这种设计 — 部署什么就写什么
- 禁止 写"先 mock 一下, 之后接真" 超过 2 周还没接的临时代码
- 用户的 NFS / 飞牛 fnOS / GPU 服务器 是真环境, 设计必须直接 work
一. 项目目录速查
| 路径 | 用途 |
|---|---|
src/vpbuddy/ |
服务端 Python 包 (UI server / engine / storage / KB / RAG / 6 doc agent / skill 入口) |
src/tests/ |
pytest 测试 (用 conftest 控制环境) |
vpbuddy-client/ |
Tauri 桌面客户端 (Rust 后端 + Vite/JS 前端) |
vpbuddy-client/src-tauri/src/audio.rs |
跨平台音频采集 (cpal) |
vpbuddy-client/ui/ |
客户端前端 (index.html / main.js / style.css) |
ui/ |
服务端 Web UI (旧版, 客户端化后基本只参考) |
docs/decisions/00XX-*.md |
架构决策记录 (ADR), 编号严格递增 |
docs/design/总体架构.md |
总体架构 (状态号 v1.20+) |
docs/product-spec/VPBuddy_产品说明书.md |
产品说明书 (用户视角, 当前 v1.20) |
pyproject.toml |
包声明 + 依赖 (含 [gpu] / [dev] extras) |
README.md |
用户上手 (中英双语) |
data/ |
运行时数据 (会议 / KB / 上传 — gitignored) |
samples/ |
测试音频样本 (gitignored 大文件) |
二. 客户端 ↔ 服务端职责边界
| 关注点 | 客户端 (Tauri) | 服务端 (Python) |
|---|---|---|
| 音频采集 | ✓ (cpal 跨平台麦克风) | ✗ (从客户端收 wav) |
| 实时转写展示 | ✓ (SSE 推流 + 波形 + cleaned) | ✓ (funasr ASR) |
| 6 doc 生成 | ✗ | ✓ (6 sub-session) |
| demo 生成 | ✗ | ✓ (demo agent) |
| KB 检索 | ✓ (UI 输入 query) | ✓ (RAG 后端) |
| 会议状态 | ✓ (list / 选) | ✓ (持久化) |
| 录音开关 | ✓ (start_capture / stop_capture) | ✗ |
| 会议创建 | ✓ (UI 选旧 / 输入新) | ✓ (建档 + 6 doc 监听) |
数据传输: 客户端 → 服务端 = WAV (16kHz mono PCM) via HTTP multipart; 服务端 → 客户端 = SSE 实时事件流 (/api/meetings/{id}/events)。
三. 跨平台部署注意
- Linux (开发/服务端主): PipeWire / PulseAudio 内录 (
vpbuddy-client/src-tauri/src/audio.rsis_loopback_device_name走.monitor后缀名匹配, v0.8.0 真实现) - macOS (Tauri 客户端): BlackHole 需用户装,
is_loopback_device_name走名字含BlackHole/Loopback/Soundflower匹配, v0.8.0 真实现 (UI 检测缺失时显示 banner) - Windows (Tauri 客户端): WASAPI loopback v0.9.x 计划, v0.8.0 cpal 0.15.3 不暴露 cross-platform API, 当前 fallback mic + UI 强提示
is_loopback_device_name() + detect_default_loopback() + mix_two_streams() 平台分支在 vpbuddy-client/src-tauri/src/audio.rs 已实现, 详见 ADR-0032 (取代 ADR-0021 + ADR-0031 stub)。
四. 已知陷阱 (踩过)
| 坑 | 教训 | 出处 |
|---|---|---|
sqlite-vec INSERT OR REPLACE + lastrowid 产生 orphan vec row |
先查老 id → 删老 vec → 删老 doc → INSERT 新 doc → INSERT 新 vec | commit 44a701a |
| sqlite3 单连接多线程不安全 → 6 docs trigger database is locked | 加 RLock 串行化 + WAL + 30s busy_timeout |
commit 3fee650 |
| funasr 是 batch 不是 streaming, 用户说话后最长等 30s 才出字 | 客户端加 latency ticker + banner 解释 | commit 2026-06-28 |
Tauri 2.6.3 去掉 window.__TAURI__, 必须用 ESM import from @tauri-apps/api |
Vite 构建 OK, 直接 index.html 加载会失败 |
2026-06-26 |
| 飞书子 session prompt 泄露 VPBuddy 身份 | 子 agent prompt 改为"你是本次会议的助手"+ 数据隔离 | commit c412abe |
客户端 gpu.zhangshengdong.com IPv6-only 域名在 V 家网 (IPv4 单栈) 解析不到 |
LAN 直连 http://192.168.10.63:8765 |
2026-07-01 |
| Chroma 第一次 query 加载 embedding 模型 ~1s | 启动时预热 get_rag().count() |
ADR-0019 |
服务端手动 vpbuddy ui 重启 → 百炼 API key 丢失 → ASR 报 401 Unauthorized |
必须用 bash start_vpbuddy.sh 启动 (注入 DASHSCOPE_API_KEY/BAILIAN_API_KEY + MINIMAX_API_KEY) |
2026-07-12 |
WS send_frame() 失败时 capturing.store(false) 连带杀 SSE → demo 送达失败 |
SSE 独立 sse_active flag + WS 失败只 break | 2026-07-12 |
E2E 测试 test_fastapi_server.py 27 项因 RUN_E2E != 1 长期跳过,修复后全因 401/auth 失败 |
/api/status 需认证 (返回 401),fixture 健康检查改用 /healthz;加 fastapi_token fixture 向本地 server 注册拿 token;KB 测试容错 chromadb 未装 |
2026-07-18 |
E2E test_task_manager_e2e.py 3 项因 defer 行为适配失败 — running 时 submit() 返回 None 而非替换 |
MeetingTaskQueue.submit() 是 defer 模式 (running → return None, 完成后 kick),修正测试预期 |
2026-07-18 |
AIAgent(model=None) → MiniMax 报 unknown model '' (2013) |
start_vpbuddy.sh 未同步 MODEL,model=None 传到 MiniMax 为空字符串 |
改为 model=os.environ.get("MODEL", "minimax-m3") 显式 fallback (ADR-0060);start_vpbuddy.sh 新增 MODEL 同步 |
DocTaskManager.submit() 加了 should_skip_generation() 入口检查后,E2E 测试因相同 hash 被去重返回 None |
E2E 测试用独立 meeting_id 避免冲突;裸 lambda runner 不走 complete_generation 所以 hash 不变也 OK |
2026-07-18 |
旧 test_e2e_integration.py import vpbuddy 内部模块 (loopback, sub_session_controller),不是 HTTP 测试,无法从本地测试远程服务端 |
废弃旧文件 (pytest.mark.skip),重写为 test_e2e_http.py — 纯 urllib HTTP 调用远程 API,28 项,session-scoped fixture 防 429 |
2026-07-18 |
五. 工具选择速查
| 任务 | 工具 | 备注 |
|---|---|---|
| ASR | funasr paraformer-zh | 服务端 GPU, 30s batch 切片 |
| 说话人分离 | pyannote-audio | 离线下载, ModelScope 镜像 |
| LLM (chat / doc) | ollama 本地 | 默认 qwen2.5:7b |
| RAG (新, v0.6) | Chroma 嵌入式 + sentence-transformers | ADR-0019 选型, KB 隔离 by meeting_id (ADR-0020) |
| Agent 工具 (v0.6 Phase 2) | vpbuddy.tools.web_search (DDG) + vpbuddy.tools.kb_search |
纯函数, agent 通过 terminal 调 (ADR-0025, 不接 LLM function calling 协议) |
| 数据存储 | SQLite (stdlib) | 不引外部 DB 进程 |
| 客户端打包 | Tauri 2.6+ | 三平台自动 CI (Linux / macOS / Windows) |
六. 文档版本号约定
pyproject.toml[project] version: 每发版递增 (语义化版本)src/vpbuddy/_version.py__version__: CI 注入 (git describe)- 总体架构:
docs/design/总体架构.md顶部 v1.XX 状态号 - 产品说明书:
docs/product-spec/VPBuddy_产品说明书_vX.Y.md(每个 v 一份) - ADR:
docs/decisions/00XX-主题.md严格编号, 不可跳号不可复用
七. 不要做
- ❌ 用 lsof 推断 Python 包没装
- ❌ 写"为 dev 方便"的 mock 而忘了真路径
- ❌ 把"实现"和"设计"拆两个 commit
- ❌ 改代码不更新 ADR / design / spec
- ❌ 让子 agent prompt 暴露 VPBuddy 身份 / 系统内部信息
- ❌ 把旧 ADR 当现行架构看 (代码先于文档铁律)
- ❌ 切会议 / 关客户端不算会议结束 — 6 doc 完成不自动结束会议 (ADR-0022)
- ❌ 让 6 doc 写完时自动入 KB (废弃, 改手动上传, ADR-0020)
八. CI / Release 流程
- 本地
git status干净 → 改代码 + ADR + 文档 + pyproject → 1 commit git push origin main→ CI 自动跑 (lint + pytest + Tauri build 三平台)- tag 打版本:
git tag v0.6.0 && git push --tags→ 自动 release - Tauri 客户端下载 release artifacts 安装
详见根 README.md 末尾。
TL;DR: 先 ls docs/decisions/, 再 find src -name "*.py" | xargs head -30, 再真命令验证, 再写代码/改文档, 再 1 commit, 再 push。