diff --git a/.workbuddy/memory/2026-10-08.md b/.workbuddy/memory/2026-10-08.md index 57c9894..db313fc 100644 --- a/.workbuddy/memory/2026-10-08.md +++ b/.workbuddy/memory/2026-10-08.md @@ -89,6 +89,27 @@ - 验证:只剩 origin 一个远程;本地与 origin 完全一致(`0 / 0`)。 - 📌 **远程口径(本项目现行)**:`git@ssh.alotbuy.com:admin/mcn-short-video.git`(旧 `work.alotbuy.com:222` 已废弃)。 +### 🔴🔴 再修正:后台任务会话**不进「空间」分组**(这才是真机制,前两轮都猜错了) +- 现象:cwd 已改成 `D:\AI技能\mcn-workshop`,会话仍落在「**未分组任务**」。 +- 取证(sessions 表):`group_id` / `group_title` **全为 null**;`project_id` 也全 null ⇒ 分组不靠这三个字段。 +- ⭐ 真因:**侧边栏是「空间区」与「任务区」两套**—— + - **手动会话**(`is_background_automation` 为 0/null)→ 按 cwd 聚合成**空间分组**(如 mcn-short-video、vibe-video-analysis); + - **后台任务会话**(`is_background_automation=1`)→ 一律进**任务区**,与 cwd 无关。 + - 工作台 `/api/run` 提交的任务会话**全是 bg=1** ⇒ **改 cwd 永远改不了它进哪个区**。 +- 想让「mcn-workshop 空间」出现在侧边栏:**在 `D:\AI技能\mcn-workshop` 手动开一个会话**(手动会话按 cwd 聚合才会生成该空间);但后台任务仍会在任务区,属产品设计。 +- ✅ 正解(已落地):看后台任务执行状态用**工作台右下角进度面板**,不必依赖侧边栏分区。 +- ⚠️ `app.asar` 里 grep「未分组」= **0 次** ⇒ 该文案在别处生成(未继续逆向)。 + +### ✅✅ 真根因并修复:`automations.workspace_scope` 漏填(不是 cwd、不是工作区登记表) +- 逆向线索:`is_playground` 赋值处 = `typeof e.space?.autoGenerated=='boolean' ? +!!e.space.autoGenerated : null` ⇒ 「空间是自动生成的」才落未分组。 +- 交叉表取证(决定性): + - 走**正规 automation 工具**创建的任务:**`workspace_scope='workspace'`(36 条)** ⇒ 会话 `is_playground=0` ⇒ 正常进工作区分组; + - **工作台直接写库**的任务(`createOnceAutomation` + `/api/run` 两处 INSERT):**`workspace_scope` 为 null(当天 5 条)** ⇒ 会话 `is_playground=1` ⇒ 落「未分组任务」。 +- ❌ 排除的假因:改 cwd(无效)、把目录登记进 `workspaces` 表(无效,该表不是决定因素;登记行已保留,无害)。 +- 🔧 修复:`server.js` 两处 `INSERT INTO automations` 增加 `workspace_scope` 列并填 `'workspace'`(`createOnceAutomation` 约 L407、`/api/run` 约 L879)。 +- 实测:新任务 `scope=workspace`、新会话 **`is_playground=0`** ✅(对照组仍是 1)。 +- 📌 **红线**:工作台凡直接写宿主 `automations` 表,必须带 `workspace_scope='workspace'`,否则会话一律落「未分组任务」。 + ## 素材库补采:批 65 收尾 + 批 66/67 完成(30 卡) - 承 09-29 进度:批 65(细节专业 15 卡)已 apply 完成,细节专业 40→55。 @@ -213,6 +234,28 @@ - 批 43 的 `neg=3`(且是关键词短语)—— **neg 不入索引**(RUNBOOK §步骤6),对召回无影响,可不处理。 - 回炉链路仍未完成:删旧条目(按 `polish_plan.json` 冻结的 526 id)+ 重导 + 检索终验。 +**⭐ 方向性判断:「现在要不要测精准率/召回率」(2026-10-08 用户问,结论待执行)** +- **结论:分拆看,不要笼统测。** + | 指标 | 该不该测 | 理由 | + |:--|:--|:--| + | **召回率(反查法 R@1/R@3)** | ⚠️ **只做回归验证**,不做优化基线 | 有 ground truth(卡自身)、能隔离「问法」变量、成本 2 分钟。但历史基线已是 R@1 34/35,问法改写实测差异在噪声内 → **测了也难再提升**,价值只剩「验证 397 卡导入后检索没坏」。 | + | **精准率** | ❌ **暂不必测** | 需人工标注「top-N 每条是否相关」,1028 条库成本极高;且分数间隔极窄(top1~top10 仅差 0.047)→ 机器判不了优劣,只能人工。已知不是瓶颈。 | + | **覆盖率**(真实需求节点 → 能否找到素材) | ✅ **该测,且是当前唯一真瓶颈** | 3/5 真实节点零命中 = 素材覆盖不足。刚导入 397 卡(631→1028),覆盖率已变,**正是重新测的时机**。 | +- ⭐⭐ **根本前提(决定一切检索指标的传导性)**:**素材召回端到端触发率 ≈ 0**,且用户已裁定这是「流程不主动召回、知识库按需被取」的**设计意图**,`hybrid_search` 0 次 ≠ bug。 + → **推论:检索指标再好,也传导不到最终产出**(优化一个几乎不被调用的函数)。所以「测检索指标」的价值**只在回归验证**,不在效果优化。 +- ⭐ **刚导入 397 卡后必做的不是指标测试,而是「入库正确性验证」**:确认新卡真能被检索到(不是精准率/召回率,是「导入成功了吗」)。 + +**⭐ 入库验证 + R@N 基线(2026-10-08 · 反查法,81 条样本)** +- **结论:R@1 = 81/81 = 100%**,27 批全部命中 → **397 卡导入成功,检索链路正常**。明细 `recall_cache/verify_import_1028.json`,脚本 `_tmp_verify_import.py`(可复用,支持 `--dry`)。 +- 抽样:27 个暂存批 × 每批首/中/尾 = 81 条,覆盖 9 个标签。查询源 = **卡片正文「极致内容」**(不在索引里,索引只有 std/sim;neg 不入索引)→ 与 std 不同源,比 18b 的「从 standard_question 提取事件」更远一步。 +- ⚠️ **这个 100% 不能当「召回质量好」的证据**:std 本就是由卡片正文改写而来,正文查自己属**同源查询,存在天花板效应**。**它只证明「入库成功 + 检索没坏」,不证明「问法有效」。** 与历史基线(18b 反查法 R@1 34/35 ≈ 97%)量级一致,属正常。真要判召回质量仍需异源测试(真实编导需求节点)。 + +**🔴 新踩坑(极具迷惑性,差点得出「召回率 0%」的错误结论)** +- **检索接口路径与参数名**:正确是 **`POST /knowledge-bases/{KB}/faq/search`**,body 用 **`query_text`**(不是 `query`),返回 **`r.get("data") or r.get("results")`(直接是列表,不是嵌套 `data.data`)**。 +- 我写成了 `/faq/search` + `query` → **HTTP 404**。 +- ⚠️ **坑的杀伤力**:404 被 `try/except` 静默吞掉 → 每条都记成「未命中」→ 输出 **R@1 = 0/81 = 0%**,看起来像「导入失败/检索全崩」。 +- ⭐ **识别口诀**:**跑完先看耗时**。81 条检索正常约 14s;若「0 命中且耗时 1s」→ 一定是异常被吞了,不是真实结果。**批量检索脚本必须让异常显式暴露(打印 err),不要静默记为未命中。** + **新增踩坑** - ⚠️ `_tmp_bNN_spec.py` 里卡片名提取必须 **`.replace("###","")`**:`head.split("|")[0].strip()` 会带 `### ` 前缀 → `assert name in Q` 报 `AssertionError: ### 吃包子吃出丧母感`。批 70 踩到一次,加 replace 后通过。 - ✅ prompt 组装字节数核对:模板 7,683 + 载荷 34,647 = 42,330(`wc -c` 可验),比批 68 记录的 15,772 大是因当时统计口径不同,**以 `wc -c` 为准**。 diff --git a/project/短视频脚本创作/V1.0/mcn-workshop/server.js b/project/短视频脚本创作/V1.0/mcn-workshop/server.js index 3f01278..2832ca5 100644 --- a/project/短视频脚本创作/V1.0/mcn-workshop/server.js +++ b/project/短视频脚本创作/V1.0/mcn-workshop/server.js @@ -404,9 +404,11 @@ function createOnceAutomation(name, prompt, skillsArr, connectorIdsArr) { const ownerUserId = uidRow ? uidRow.user_id : ''; const modelRow = db.prepare(`SELECT model FROM sessions WHERE deleted_at IS NULL AND COALESCE(is_background_automation,0)=0 AND model IS NOT NULL AND model <> '' ORDER BY COALESCE(last_activity_at, updated_at) DESC LIMIT 1`).get(); const modelId = (modelRow && modelRow.model) ? modelRow.model : 'auto'; - db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,next_run_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`) - .run(id, name, prompt, 'ACTIVE', 'once', scheduledAt, nextRunAt, '', JSON.stringify([cwd]), now, now, JSON.stringify(Array.isArray(skillsArr) ? skillsArr : []), JSON.stringify(Array.isArray(connectorIdsArr) ? connectorIdsArr : []), modelId, 'fullAccess', ownerUserId, 'confirmed'); + // 10-08 修复:必须带 workspace_scope='workspace'。走正规 automation 工具创建的任务都带该值(库里 36 条如此), + // 工作台直接写库时漏了它 ⇒ 会话被视为"自动生成的空间"、落进「未分组任务」。 + db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,next_run_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status,workspace_scope) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`) + .run(id, name, prompt, 'ACTIVE', 'once', scheduledAt, nextRunAt, '', JSON.stringify([cwd]), now, now, JSON.stringify(Array.isArray(skillsArr) ? skillsArr : []), JSON.stringify(Array.isArray(connectorIdsArr) ? connectorIdsArr : []), modelId, 'fullAccess', ownerUserId, 'confirmed', 'workspace'); return { id }; } finally { db.close(); @@ -874,9 +876,10 @@ const server = http.createServer((req, res) => { // 无手动会话记录时兜底 'auto'(自动路由)。实证:调度接受 'auto' 与具体模型 ID('deepseek-v4-pro' 曾成功) const modelRow = db.prepare(`SELECT model FROM sessions WHERE deleted_at IS NULL AND COALESCE(is_background_automation,0)=0 AND model IS NOT NULL AND model <> '' ORDER BY COALESCE(last_activity_at, updated_at) DESC LIMIT 1`).get(); const modelId = (modelRow && modelRow.model) ? modelRow.model : 'auto'; - db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,next_run_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`) - .run(id, name || '工作台任务', finalPrompt, 'ACTIVE', 'once', scheduledAt, nextRunAt, '', JSON.stringify([cwd]), now, now, JSON.stringify(skillsArr), JSON.stringify(connArr), modelId, 'fullAccess', ownerUserId, 'confirmed'); + // 10-08 修复:与 createOnceAutomation 同理,必须带 workspace_scope='workspace',否则会话落「未分组任务」 + db.prepare(`INSERT INTO automations (id,name,prompt,status,schedule_type,scheduled_at,next_run_at,rrule,cwds,created_at,updated_at,skills_json,connector_ids_json,model_id,permission_mode,owner_user_id,owner_status,workspace_scope) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`) + .run(id, name || '工作台任务', finalPrompt, 'ACTIVE', 'once', scheduledAt, nextRunAt, '', JSON.stringify([cwd]), now, now, JSON.stringify(skillsArr), JSON.stringify(connArr), modelId, 'fullAccess', ownerUserId, 'confirmed', 'workspace'); db.close(); log('已提交 AI 任务: ' + id + (name ? ' (' + name + ')' : '')); return sendJSON(200, { ok: true, id, message: '任务已提交,请在左侧会话栏查看执行' });