200 lines
29 KiB
Markdown
200 lines
29 KiB
Markdown
# 2026-10-08
|
||||
|
|
|
|||
|
|
## 会话技能加载 + 项目记忆去重
|
|||
|
|
|
|||
|
|
- 按用户指令加载 `session-mechanism`:四类必读已读(`00-动手前必过.md` / `rules.md` / `manifest.md` / `01-文档索引.md`)+ SKILL.md 第一屏(触发句、第 0 步加载门槛、十条禁令、自决策白名单、现状地图)。
|
|||
|
|
- 内化判据:**边界内自决策**(技术选型/实现路径/命名/调参/部署/排查/版本/兼容降级/文档技术内容);**只提报三类**(功能语义分叉/红线门禁/超边界:花钱·对外承诺·要凭据)。
|
|||
|
|
- 项目 `MEMORY.md` 去重重组为 v4(17,841 → 17,315 B):新增 §0 两条指针(工作台 AI 通路 `docs/AI链路-本地CLI接入.md`、技能侧 WeKnora 调用);§2.1 补 09-29 AI 通路四条硬红线+两段流程模型来源;§4.2/§4.3 降级为「存根+硬红线」;清历史流水。
|
|||
|
|
|
|||
|
|
### 未决
|
|||
|
|
- ⚠️ `MEMORY.md` 体积仍会被注入截断(阈值约 10–12 KB)。解法二选一:① 维持单文件(细节自动可见,但注入截断)② 拆专题文件(不截断,但细节失去自动注入)。**无客观优劣 ⇒ 待用户定**。
|
|||
|
|
|
|||
|
|
## 工作台「更新榜单数据」按钮排查(功能正常,是可见性问题)
|
|||
|
|
|
|||
|
|
- 现象:用户点击后「没有会话执行」。
|
|||
|
|
- 取证(四处读数):宿主库 `automations` 有该 once 任务(ACTIVE、`next_run_at` 已过期、`model=hy4-preview`、`skills=["mcn-data-insight"]`);`automation_runs.status=IN_PROGRESS` + `automation_runtime_state.running=1`(⚠️ `running_conversation_id=null` 是常态,不代表没起会话);`sessions` 已建后台会话 `8a085794…`(bg=1,10:07:23);会话 jsonl 283 KB 且 mtime 持续更新(10:14),工具调用 30 Bash/14 Read/4 Write ⇒ **任务真的在跑**。`/api/dsh/ranking-update` 返回 `files=104`、`lastUpdateAt` 10:13:51 ⇒ 数据已在落盘。
|
|||
|
|
- 真因两条(都与抓取逻辑无关):① 会话 `cwd = …\mcn-work-shop` ⇒ 落在侧边栏 **mcn-work-shop 空间分组**,不在用户当前空间,需切组才可见(这是设计,非 bug);② 工作台服务作为会话后台任务**被回收** ⇒ 前端轮询 `/api/run/status` 持续抛错。
|
|||
|
|
- 修复:`public/data-pages.js` `updateRankingData()` 轮询加失败计数 —— 连续 3 次查询失败即提示「工作台服务已断开,任务仍在后台执行」并结束轮询(原逻辑静默 `continue` 到 15 分钟超时,用户零感知)。
|
|||
|
|
- ⚠️ **排查方法论沉淀**:判「后台任务有没有在执行」的正确取證链 = `automations` → `automation_runs` → `automation_runtime_state` → `sessions` → 会话 jsonl 的 mtime/大小。⛔ 别只看 `running_conversation_id`(常为 null,会误判成没执行)。
|
|||
|
|
|
|||
|
|
## 工作台目录统一改名 `mcn-work-shop` → `mcn-workshop`
|
|||
|
|
|
|||
|
|
- 动因(用户):「分组已改为 mcn-workshop,需要全部替换;执行会话任务时需要按分组名称显示在会话列表」。
|
|||
|
|
🔑 **机制**:WorkBuddy 侧边栏空间分组名 = 会话 `cwd` 的 **basename** ⇒ **只改字符串无效,必须真改名目录**。
|
|||
|
|
- 执行五步:① 停服务释放句柄(否则 rename 必 `WinError 5`)→ ② `mv mcn-work-shop mcn-workshop`(成功)→ ③ 临时脚本全仓替换 **`mcn-work-shop`→`mcn-workshop`:37 文件 / 121 处**;⛔ 按**沿革句规矩跳过** `.workbuddy/memory/YYYY-MM-DD.md`(16 个历史日志保留当时目录名史实)→ ④ 修 2 处被替换改坏语义的注释(`server.js` L1265 / L1269,原「旧 mcn-workshop/新建 mcn-workshop」被换成同词,已补回三代路径)→ ⑤ 重启验证:`app.js`/`data-pages.js` 200,`data-pages.js` 含 `pollFail` 修复。
|
|||
|
|
- ⚠️ **事实澄清(易踩)**:`D:\AI技能\mcn-workshop` **不是工作台**,是 09-01 路径拼接 bug 留下的**垃圾目录**(3 个 0 字节文件 + `outputs`)。工作台本体一直在仓库内 `…\V1.0\mcn-workshop`。sessions 表取证:该垃圾目录下**零会话**;未删除会话中仅 1 条 mcn-work 相关,cwd 仍是旧 `…\mcn-work-shop`。
|
|||
|
|
- 净效果:新建后台会话 cwd = `…\V1.0\mcn-workshop` ⇒ 侧边栏分组显示 **`mcn-workshop`** ✅
|
|||
|
|
- 残留:`project/…/subskills/mcn-data-insight/scripts/__pycache__/*.pyc`(二进制缓存含旧串,会自行重生成,无需处理)。
|
|||
|
|
|
|||
|
|
### 追加澄清(用户真实意图,⛔ 别再理解成"目录改名")
|
|||
|
|
- 用户要的不是改目录名,而是:**工作台提交 WorkBuddy 定时任务后,产生的 AI 会话应归属哪个「空间分组」**。
|
|||
|
|
- 机制:分组名 = 会话 `cwd` 的**目录名**;工作台侧由 `server.js` 的 `SESSION_CWD`(当前 = 工作台自身目录)决定 ⇒ **改目录名只是让分组名变成 `mcn-workshop` 的手段**,不是目的本身。
|
|||
|
|
- ⚠️ **存量不掉头**:10:07 那条榜单更新任务 cwd 仍是旧 `…\mcn-work-shop` ⇒ 显示在**旧**分组;改名后**新建**的任务才落到 `mcn-workshop`。清理用的 `SESSION_CWD_PATTERN='%mcn-work%'` 覆盖新旧三代,不受影响。
|
|||
|
|
- 待用户定(功能语义分叉):① 维持工作台专属分组 ② 归入用户当前主项目分组 ③ 自定义独立分组(需目录真实存在且在 workspaces 登记,08-27 即此法)。可选项:把 `SESSION_CWD` 提升为 `config.json` 可配字段,换分组只改配置不动代码。
|
|||
|
|
|
|||
|
|
## 后台任务进度可见(用户:「我需要看到 才知道执行是否正常」)
|
|||
|
|
|
|||
|
|
- 真需求:不是分组放哪,而是**在工作台内直接看到执行状态**,判断在跑还是卡住、做了什么。
|
|||
|
|
- 后端 `server.js` `/api/run/status` 增强:automation → 关联它拉起的后台会话(`sessions.is_background_automation=1` 且创建时间落在任务创建 −15s~+300s)→ 读该会话 jsonl **尾部 256 KB** → 新增字段
|
|||
|
|
`elapsedMs` / `sessionId` / `sessionTitle` / `lastAction`(最近一段文本,截断 160 字)/ `toolCalls`(按工具名计数)/ `updatedAgoMs` / `stalled`(>90 s 无新输出)/ `logBytes`。
|
|||
|
|
- ⭐ 会话日志路径换算(可复用):cwd → projects 目录名 = **盘符小写 + 分隔符全转 `-`**(`escapeCwdForProjects()`);基目录 `<workbuddy>/projects/<转义名>/<sessionId>.jsonl`。
|
|||
|
|
- ⚠️ `stalled` 只在 `state=running` 时有意义(已完成任务日志当然不再写入,会恒 true)。
|
|||
|
|
- 前端新增 `window.TaskProgress`(实现在 `public/app.js`,样式 `style.css` 的 `.tp-*`):右下角常驻面板 = 状态/已运行时长/工具调用/最近动作/停滞警告。**四处轮询点全接入**:`app.js executeTask`、`data-pages.js` 的榜单更新/批量更新账号/视频解析。终态保留 8 秒自动收起,运行超时则保留供继续观察。
|
|||
|
|
- 验证:三文件 `node --check` 全过;服务起来后 `app.js` 含 6 处、`data-pages.js` 含 9 处 `TaskProgress`,`style.css` 含 `.tp-panel`;状态接口返回完整进度字段。
|
|||
|
|
|
|||
|
|
### ✅ 分组归属定案:就用 `mcn-workshop` 文件夹对应的分组(已实测)
|
|||
|
|
- 用户拍板:任务会话归到 **`mcn-workshop` 文件夹对应的那个分组**。
|
|||
|
|
- 实测(提交轻量自检任务取证):新会话 `cwd = …\V1.0\mcn-workshop` ✅;对照 10:07 那条旧榜单任务仍是 `…\mcn-work-shop`(**两者在侧边栏分属不同分组**,属正常存量,不用管)。
|
|||
|
|
- 结论:**不需要再改代码** —— `SESSION_CWD = ROOT`,目录改名后自动生效。自检任务已删排期。
|
|||
|
|
- ⚠️ 认知要点:侧边栏分组按 **完整 cwd** 聚合,不是按文件夹名合并 ⇒ 同名不同路径会是两个分组。
|
|||
|
|
|
|||
|
|
### ⚠️ 更正(12:2x):分组靠 cwd **命中已打开的工作区**,光改目录名不够
|
|||
|
|
- 上一条只对了一半:目录改名后会话 cwd 是**仓库内** `…\V1.0\mcn-workshop`,**不是用户的工作区** ⇒ 仍显示在「**未分组任务**」区域(用户实测反馈)。
|
|||
|
|
- 用户纠正:`D:\AI技能\mcn-workshop` **才是那个工作区**。我此前仅凭目录里只有 3 个 0 字节垃圾文件就判它"是垃圾目录"——**没查登记表就下结论**,违反「判状态先问程序自己」。
|
|||
|
|
- 🔑 **真机制**:侧边栏分组 = 会话 cwd **命中已打开过的工作区**才显示为命名分组;没命中 ⇒ 落「未分组任务」。
|
|||
|
|
- 取证:`workspaces` 表仅 7 行且全是 `C:\Users\maidou\WorkBuddy\<时间戳>`,**不含**任何 `D:\AI技能\*` ⇒ 分组依据不是这张表,而是按会话 cwd 对已打开工作区的聚合。
|
|||
|
|
- 修法(配置化,⛔ 不写死):`load-config.js` 增 `sessionCwd`(默认 `''` = 用 ROOT)→ `server.js` `SESSION_CWD = String(CFG.sessionCwd||'').trim() || ROOT` → `config.json` 设 `"sessionCwd": "D:\\AI技能\\mcn-workshop"`。**换分组只改配置,不动代码。**
|
|||
|
|
- 实测:新会话 cwd = `D:/AI技能/mcn-workshop` ✅;任务在该工作区执行正常(done,结果"成功",73 秒)。对照 12:23 那条仍在仓库内路径 ⇒ 两组并存,旧的会随过期清理消失。
|
|||
|
|
- ✅ 13:06 **二次模拟请求复验一致**(用户指示:不测真实功能,只发模拟请求看分组):写入 `cwds=["D:\\AI技能\\mcn-workshop"]`,会话 cwd 同样命中 ⇒ 配置化改法稳定。两次自检排期均已删,会话留在目标工作区供用户肉眼确认。
|
|||
|
|
|
|||
## 提交(13:09)
|
||||
|
|
- commit **`f77735b`**:目录改名 + 121 处替换 + 任务进度面板 + 会话归属配置化 + 前端轮询缺陷修复。提交前已查:仓库内**无 API key**(`grep -rl "ck_fzpjin5c0iyo"` 空)、新目录**未被 gitignore 误伤**(`git check-ignore` 无输出)。工作区干净(0 未提交)。
|
|||
|
|
- ⚠️ **push 失败(非权限问题)**:`ssh work.alotbuy.com:222` 连接超时 —— 公司内网 git 服务器,当前网络不通。走 10800 代理也失败:Git Bash **没有 `connect` 工具**(`ProxyCommand` 用不了)。
|
|||
|
|
- 待办:回到公司网络/VPN 后跑 `git push origin main`(本地提交已就位,领先 origin 1 个)。
|
|||
|
|
|
|||
|
|
### 🔴 新远程地址实测:能连通,但**两条历史无共同祖先**(已停手,未推送)
|
|||
|
|
- 用户给新地址 `[email protected]:admin/mcn-short-video.git`(旧 `work.alotbuy.com:222` 超时)。实测 **能连通**:`ls-remote` 成功,远程 main = `e738dd1`(2026-10-07 10:48)。
|
|||
|
|
- 🔴 **`git merge-base main FETCH_HEAD` 为空** ⇒ 无共同祖先;两边各 **253** 个提交,`rev-list --left-right --count` = **253 / 253**。
|
|||
|
|
- 本地最早 2026-08-06「Full upload: MCNVideo AI project」,远程内容同源但 **hash 全不同** ⇒ 历史被重写过,是两条独立线。
|
|||
|
|
- 远程有本地没有的提交(如 10-07 那条 gitignore 补充),说明远程不等于"落后于本地"。
|
|||
|
|
- ⛔ **不能直接 push**:普通 push 必被拒(非 fast-forward);**强推会抹掉远程 253 个提交,不可逆**。
|
|||
|
|
- 待用户定:① 推到远程**新分支**(安全,推荐)② 合并两条历史(`--allow-unrelated-histories`,冲突量极大)③ 强推覆盖(⛔ 需明确授权)④ 不推,等原地址恢复。
|
|||
|
|
- ⚠️ 排查教训:换远程地址前必须先看 `merge-base`,⛔ 不能因为"地址能连通"就推。
|
|||
|
|
|
|||
## 素材库补采:批 65 收尾 + 批 66/67 完成(30 卡)
|
||||
|
|
|
|||
|
|
- 承 09-29 进度:批 65(细节专业 15 卡)已 apply 完成,细节专业 40→55。
|
|||
|
|
- **批 66(细节专业 15 卡)**:取材 31748 姜乘澜底妆 / 17511 笑笑易 / 19014 俊希做菜 / 24821 烟道逃生 / 25090 姜乘澜画眼线。✅ **本批 5 条原生即教程/实操题材**,与细节专业天然契合(不像批 65 从非专业题材硬提)。apply:接受 15/退回 0,问法改写 15 张平均 +32 字。细节专业 55→70。
|
|||
|
|
- **批 67(自嘲反差 15 卡)**:取材 26484 路之坑爹感恩宴 / 31816 直男五合一洗护 / 31970 李普不离谱 / 21500 桃气小周买饭 / 26411 老弟受难日记。含 1 张**元层面自黑**卡(31970 全家崩溃时推销泡面)。apply:接受 15/退回 0,问法改写 15 张平均 +12 字。自嘲反差 56→71。
|
|||
|
|
- 两批均走完整链路:`写 md → _tmp_bNN_spec.py 生成 spec → meta.json → build-pending → cat PROMPT_polish_v3.md + build-pending 组装 prompt → 派 doubao-seed-2-1-pro → _wNN.py 校验落盘 → apply-pending`。
|
|||
|
|
|
|||
|
|
### 本轮新踩坑
|
|||
|
|
- ⚠️ **MCP `myai-mcp-production` 登录态会过期**:批 66 拉第 4 条时报「认证失败」。解法:先 `auth_status` 确认 → `feishu_login` 重授权(拉起浏览器)→ 重试即通。**连续拉多条详情时中途要留意**。
|
|||
|
|
- ⚠️ **spec 脚本里别夹英文单词**:批 66 的 neg 句误写「等摊主 processing」,批量产出会污染语料。写完 spec 脚本前先自查。
|
|||
|
|
|
|||
|
|
### 当前缺口(修正后口径,2026-10-08 10:50)
|
|||
|
|
| 标签 | 现有 | 缺口 | 候选 |
|
|||
|
|
|:--|--:|--:|--:|
|
|||
|
|
| 食材极致 | 8 | 92 | ⛔ 0 |
|
|||
|
|
| 预见式服务 | 21 | 79 | ⛔ 2 |
|
|||
|
|
| 感官沉浸 | 59 | 41 | 14 |
|
|||
|
|
| 细节专业 | 70 | 30 | 22 |
|
|||
|
|
| 自嘲反差 | 71 | 29 | 34 |
|
|||
|
|
| 视觉冲击 | 76 | 24 | 10 |
|
|||
|
|
|
|||
|
|
达标:品质对比 110 / 氛围沉浸 106 / 反差 217 / 反常识 128 / 价值观冲击 108。
|
|||
|
|
- ⛔ **卡点未解**:`食材极致`(缺口 92)与 `预见式服务`(缺口 79)候选池近乎空,占剩余缺口一半以上。需换关键词或换捞法才能推进。
|
|||
|
|
- 暂存批累计 24 批(43–52、54–67,缺 53)。
|
|||
|
|
|
|||
|
|
## 补采续跑:批 68(感官沉浸 15 卡)/批 69(细节专业 9 卡)
|
|||
|
|
|
|||
|
|
**批 68 · 感官沉浸(33289 子杭自驾318 ×6 / 31773 萝卜乔乔英国留学回国 ×6 / 30090 姐弟双向送礼 ×3)**
|
|||
|
|
- apply 结果:**接受 15/退回 0,问法改写 15 张,平均 +19 字**。感官沉浸 59 → 74。
|
|||
|
|
- ⭐ **两条来源 0 卡,已在 md 写明判据**:`28012`(电焊工试戏)男主嘴配的「滋滋」是**谐音梗的音效**而非真实声音质感,事件主角是"身在曹营心在焊" → 归 `反常识`/`自嘲反差`;`28415`(男朋友的算计)踩碎眼镜/摔筷子/拍桌的动静是**发疯甩锅的附产品** → 归 `反差`/`价值观冲击`。
|
|||
|
|
- 感官通道分布齐全(冷/缺氧失眠/冰雹砸车/撕羊腿/热水澡/久坐腰酸 · 热瓶/苦到脸垮/中药味/红米肠/赶机喘/长途疲惫 · 中暑虚脱/猛灌水/红糖蛋滋啦)。
|
|||
|
|
|
|||
|
|
**批 69 · 细节专业(28328 海鲜蒸汽 ×4 / 37316 巧克力棒手作 ×5)= 9 卡**
|
|||
|
|
- apply 结果:**接受 9/退回 0,问法改写 9 张,平均 +20 字**。细节专业 70 → 79。
|
|||
|
|
- ⭐ **本批 3 条来源 0 卡,坚持不凑数**(沿用批 56 口径):
|
|||
|
|
- `20461`(机票骗局)—— 骗子的"专业"是**话术与骗术设计**(伪装客服、真退票取信、连环索要卡号),不落在"这一下换普通人来做就做不到位"的操作细节上 → `反差`/`反常识`。**这是细节专业最容易误判的一类:话术专业 ≠ 操作专业。**
|
|||
|
|
- `24820`(烟道脱困)—— 主角是**作死翻车与体力消耗**,片尾"专业人士、专业场地、专业操作"是**反讽** → `自嘲反差`/`难度极限`;且同账号同题材 `24821` 已在批 66 取过两卡,本条脱困手法同构,不重复入库。
|
|||
|
|
- `22163`(轮椅游渔岛)—— 倒拖轮椅过软沙滩属**体力付出** → `难度极限`;其余为情侣互坑 → `反差`/`自嘲反差`。
|
|||
|
|
- ⭐ **取批命中率下降的信号**:细节专业候选池看着有 22 条,但主队列取 5 条只有 2 条可用(命中率 40%)。后续该标签每批卡数会低于 15,属正常,不要为了凑 15 张硬塞。
|
|||
|
|
|
|||
|
|
**新增踩坑与复用做法**
|
|||
|
|
- ✅ **`_wNN.py` 用 sed 复用**(`sed -e 's/_raw68/_raw69/g' -e 's/pending_0068/pending_0069/g' -e 's/^N = 15/N = 9/' _w68.py > _w69.py`)—— 卡数变化时记得同步改 `N`。本轮连续 3 批(67/68/69)一次通过,`bad: []`。
|
|||
|
|
- ✅ **超长详情自动落盘**:`33289` 返回 88,150 字符超限 → 工具落盘到 `D:\.workbuddy\projects\d-AI技能-mcn-short-video\<sessionId>\tool-results\*.txt`,用 Read 直接读(该文件只有 117 行,一次读完)。
|
|||
|
|
- ⚠️ 派模型改用「让 Agent 自己 Read prompt 文件 → 自己 Write 落盘 `_rawNN.txt`」——比让模型把 JSON 回吐到对话再手工落盘更省上下文,连续 3 批稳定。
|
|||
|
|
|
|||
|
|
**当前缺口(批 69 后)**:自嘲反差 29(候选 34)|感官沉浸 26(候选 14)|视觉冲击 24(候选 10)|细节专业 21(候选 22)。食材极致 92/预见式服务 79 仍挂起(用户 2026-10-08 决策:先不处理)。
|
|||
|
|
|
|||
|
|
## 批 70(自嘲反差 15 卡)· 本轮第 5 批 → 复核点
|
|||
|
|
|
|||
|
|
**结果**:接受 15/退回 0,问法改写 15 张,平均 **+27 字**(前几批 +19/+20,本批问法增厚更充分)。自嘲反差 71→**86**(缺口 14)。
|
|||
|
|
**来源**:35376 唐轩乌龙×6 | 35301 丁浩普信男×6 | 28146 妈妈硬核推理×3。**5 条视频里 2 条 0 卡**(33593、21923)。
|
|||
|
|
|
|||
|
|
**⭐ 自嘲反差口径新增形态「姿态过载」**(本批确立):
|
|||
|
|
- 定义:主角自己把一件小事升格到远超其体量的规格,且全程一本正经(妈妈把女儿回家晚做成刑侦审讯:北风4级/100米/11分37秒 vs 6点12分39秒)。
|
|||
|
|
- 判据仍落回一句话:**笑点落在主角自己身上**。妈妈是主角、推理的荒谬感由她自己一本正经地制造 → 收。
|
|||
|
|
- ⛔ 反向凡尔赛揭晓(语数英 100/98/100 + 兑现平板)→ 笑点在预期被颠覆 → `反常识`;儿子 O 型嘴石化 → 笑点落在旁观者受击 → `反差`(世界参差)。均不收。
|
|||
|
|
|
|||
|
|
**两条 0 卡判据(写入 meta)**:
|
|||
|
|
- **33593(张开父子的下场)**:家族护短复仇爽剧,爽点落在反派父子被制裁上,主角阵营全程降维打击,无一处笑点落在自己身上 → `反差`/`价值观冲击`。其「悲痛段落硬塞洗面奶口播」虽属元层面自黑,但批 67 已收同构卡(C1 全家崩溃时推销泡面)→ 不重复入库。
|
|||
|
|
- **21923(消防设施瘫痪的代价)**:真实事件改编的沉重社会悲剧(烟花引火→消防栓被锁→接头拧不上→母亲丧生→儿子一夜白头),全片无笑点 → `价值观冲击`。
|
|||
|
|
- ⭐ **通用判据沉淀**:**沉重社会悲剧类一律不进自嘲反差**;**元层面自黑要查是否已收同构卡**(批 67 已占一类)。
|
|||
|
|
|
|||
|
|
**其他弃卡判据**:35376「你那算盘珠子都崩我脸上了」是吐槽他人 → `反差`;「我没吃过我妈包的包子」与「我妈不会做饭」是同一场乌龙的两端 → 分作「立 flag」与「揭盅」两卡,不合并(同批 67 B2/B3/B4 细分做法)。35301 防晒植入段属商业植入;丽丽怒骂并入 B4 不单列。
|
|||
|
|
|
|||
|
|
**本轮 5 批(66–70)合计 69 卡**:66=15 | 67=15(自嘲反差)| 68=15(感官沉浸)| 69=9(细节专业,不凑数)| 70=15(自嘲反差)。
|
|||
|
|
**当前缺口(批 70 后)**:感官沉浸 **26**(候选 14)→ 视觉冲击 24(10)→ 细节专业 21(22)→ 自嘲反差 14(34)。食材极致 92/预见式服务 79 挂起。
|
|||
|
|
**体检**:`5_tag_coverage.py` 卡片总数 1017(源文件 69 个),12 维无自造标签;⛔ 零覆盖仅 `难度极限`(用户决策不处理),⚠️ 偏少仅 `食材极致`(8,挂起)。
|
|||
|
|
|
|||
|
|
**复核抽查**:批 70 卡 6(哭着嚼坚果上供)润色生效——台词前置 + 破折号拍点(「我以后再也不养小仓鼠了,我对不起你」——唐轩把相框平放在桌上…),锁定 4 字段零改动,无编造。spec 回写 sim=3/neg=2、tag 单一、src 3 个,全部符合。
|
|||
|
|
|
|||
|
|
**⭐ 入库状态核查(用户问「素材都同步到 wekonra 了吗」→ 答案:没有,两层原因)**
|
|||
|
|
- **流程层**:按暂存模式,补采只落 `batches/pending_import/`,统一入库必须跑 `13_import_pending.py --run`。截至批 70,**27 批 397 卡全部堆在暂存区,一条都没进库**(`13_import_pending.py --help` 盘点:27 批/397 卡/异常 0)。`batches/*.md` 41 批(早期跑过 `2_import_batch.py` 的)是唯一进过库的部分。
|
|||
|
|
- **环境层**:`WeKnora-app` 容器 **Exited (127)**,最后一条日志停在 **2026-09-29 23:53**(health 200)→ 31607 端口不通,连"库里现有多少条"都查不了。同项目其余容器(frontend 24719 / docreader / postgres / redis)都在跑。**整个 10-08 的补采从未连过库。**
|
|||
|
|
- **部署信息**:镜像 `wechatopenai/weknora-app:latest`,restart `unless-stopped`,compose 工作目录标签 `/home/maidou/weknora`(WSL 路径,本机 `docker ps -a` 可见)。拉起命令 `docker start WeKnora-app`;若仍 127 需查 compose 的 command/entrypoint。
|
|||
|
|
- **回炉链路同样未完成**:「删旧条目 + 重导 + 检索终验」都还没做;回炉批 31–33 也未跑完。
|
|||
|
|
- ⚠️ 排查口诀补充:**问「同步了吗」时先查两处**——① `13_import_pending.py --help` 看暂存盘点 ② `docker ps -a` 看 WeKnora-app 是否 Up。两者都要看,只查一处会误判。
|
|||
|
|
|
|||
|
|
**⭐ 规则核对:入库前必须补全 question(用户 2026-10-08 追问「是否遵循」→ 核查 27 批结论)**
|
|||
|
|
- **规则依据(能查到的最强出处)**:RUNBOOK §步骤 6「写 spec.json(检索问法)」=流水线必经步骤;**真正的动机在 RUNBOOK 红线**:「追加相似问不重建索引(`POST /faq/entries/{id}/similar-questions` 返回 200 但向量分数按位不变)→ **要改问法只能删 + 重导**」。所以「入库前补全」不是形式要求,而是**事后补的代价=整批删+重导**。
|
|||
|
|
- ⚠️ **未找到该规则的原始对话出处**:`conversation_search` 两次 0 命中,本地 memory / RUNBOOK 也没有「入库前要补全 question」这句原话。**已按「规范 + 红线」等价认定,未擅自当作既有明文规则引用。**
|
|||
|
|
- **核查结论(27 批全量)**:全部有 spec.json、`std` 全部非空 → **形式上 100% 遵循**。但有 **2 批偏离现行规范**:
|
|||
|
|
| 批 | 偏离 | 范围 |
|
|||
|
|
|:--|:--|:--|
|
|||
|
|
| **43** | `neg=3` 条(现行应为 2),且内容是**关键词短语**(「白酒带货 / 餐厅推荐 / 商务礼仪培训」)不是问句 | 15/15 卡 |
|
|||
|
|
| **48** | `sim=2` 条(现行应为 3) | 15/15 卡 |
|
|||
|
|
其余 25 批:sim=3(批 47 起)或 sim=6(批 44/45/46,合旧规范)/neg=2,全部合规。
|
|||
|
|
- ⚠️ **文档与执行脱节(待用户裁定)**:RUNBOOK §步骤 6 明文写 **sim「口语问法 4–6 条」**,但**批 47 起实际统一为 3 条**(`_wNN.py` 校验也写死 `!= 3`)。要么改文档、要么把 sim 补回 ≥4 条。
|
|||
|
|
- ⭐ **核查脚本口诀**:`glob('batches/pending_import/batch_*.spec.json')` 逐批 `Counter(len(x['sim']))` + `Counter(len(x['neg']))` 打分布表,一眼看出条数偏离;**别用 md 的 ```text 计数 //2 算卡数**(会算成一半,以 spec 长度为准)。
|
|||
|
|
|
|||
|
|
**⭐ Docker WeKnora 启动失败排查(2026-10-08 · 已修复)**
|
|||
|
|
- **根因(不是应用崩溃,是容器 init 前的 bind mount 失败)**:`docker inspect WeKnora-app` 的 `.State.Error` 给出原文——
|
|||
|
|
`OCI runtime create failed: runc create failed: ... error mounting "/run/desktop/mnt/host/wsl/docker-desktop-bind-mounts/Ubuntu-24.04/4f4eee8c…" to rootfs at "/app/config/config.yaml": not a directory: Are you trying to mount a directory onto a file (or vice-versa)?`
|
|||
|
|
- **链路**:compose 写 `./config/config.yaml:/app/config/config.yaml`(文件→文件,写法正确,源文件 `/home/maidou/weknora/config/config.yaml` 确实存在且是 6545 B 的文件)→ 但 **Docker Desktop 的 bind-mount 代理层**(WSL 9P 中转,路径被哈希成 `4f4eee8c…`)把源**识别成了目录** → 挂载失败 → 容器连 init 都没进 → **Exit 127**(entrypoint `./scripts/docker-entrypoint.sh` 根本没执行)。
|
|||
|
|
- **时间线**:StartedAt 09-28 01:45,FinishedAt **10-08 02:51** —— 正常跑了 10 天,今天凌晨有一次重启尝试(Docker Desktop/WSL 层变动)时代理层状态不对而失败。restart `unless-stopped` 不会救「启动失败」,所以一直停在 Exited。
|
|||
|
|
- ✅ **修复:`docker start WeKnora-app` 一次即恢复**(`Up (healthy)`,31607 通)→ 属**代理层临时状态问题**,重试可解。复发时的升级路径:重启 Docker Desktop → `docker compose up -d` 重建容器(会换新的代理哈希)。治本方向:单文件 bind mount 跨 WSL 本就脆弱,可改 `docker cp` 或 volume。
|
|||
|
|
- ⭐ **排查口诀:容器 Exited(127) 先看 `docker inspect --format '{{.State.Error}}'`**,不要只看 `docker logs`(日志只到上次正常运行,看不出启动失败原因)。本次日志最后一条停在 09-29 23:53 health 200,完全看不出问题,是 inspect 的 State.Error 直接给出根因。
|
|||
|
|
|
|||
|
|
**库内实测(服务恢复后)**
|
|||
|
|
- FAQ 总数 **631**(分页抖动,去重拉取 624)。**问法 100% 齐全**:无 std 0 / 无 sim 0 / 无 neg 0。
|
|||
|
|
- sim 条数分布 `{5:312, 6:222, 3:46, 2:30, 4:14}`、neg `{2:542, 3:82}` —— 历史口径混着(旧 5/6 条、现 3 条、少量 2 条)。
|
|||
|
|
- 库内 tag_name 分布:反差 172/反常识 117/价值观冲击 93/视觉冲击 67/自嘲反差 44/细节专业 32/感官沉浸 26/氛围沉浸 24/品质对比 19/预见式服务 19/食材极致 9/难度极限 2 → **与本地统计一致,即已入库 = 早期 41 批;暂存 27 批 397 卡确实未进。**
|
|||
|
|
- ⚠️ **接口结构坑**:FAQ 列表返回是 **`data.data`**(`{data:{total,page,page_size,data:[...]}}`)两层嵌套,只取一层会得到空列表;条目标签字段是 **`tag_name`**(不是 `tag`/`tags`);`page_size=total` 一次拉全会返回空 → 必须分页 100 逐页 + 按 id 去重。
|
|||
|
|
|
|||
**⭐⭐ 27 批 397 卡统一入库完成(2026-10-08 · `13_import_pending.py --run`)**
|
||||
|
|
- **结果**:成功 27 批 [43–70 除 53] / 失败 0。**库内 631 → 1028,增量 397 == 暂存卡数**,完全对上(判据用库内增量,不用 SUMMARY 的 success 数)。问法完整性:无 std 0/无 sim 0/无 neg 0。
|
|||
|
|
- 导入后 tag:反差 224 / 反常识 132 / 品质对比 109 / 价值观冲击 108 / 氛围沉浸 105 / 自嘲反差 85 / 细节专业 79 / 视觉冲击 76 / 感官沉浸 70 / 预见式服务 22 / 食材极致 9 / 难度极限 2。
|
|||
|
|
- ⚠️ 注意:**库内 tag 数与本地 `5_tag_coverage.py` 统计不同**(例:感官沉浸本地 74 vs 库内 70)—— 库内按 spec 的单值 `tag`(每卡主标签),本地按卡片事件标签字段(含辅标签计数)。**两者口径不同,不要互相校验。**
|
|||
|
|
|
|||
|
|
**🔴 新踩坑(重要,会静默导致整批导入失败):spec.json 的 `card` 字段必须是「标题行」,不是卡片全文**
|
|||
|
|
- **现象**:首次 `--run` 成功 13 批 [43–47,50–58],失败 14 批 [48,49,59–70],报错 `✗ spec 与 md 对不上:[整张卡片全文]`。
|
|||
|
|
- **根因**:`2_import_batch.py` L40–48 的比对是
|
|||
|
|
`cards={}` → `t = b.splitlines()[0].replace("### ","").strip()` → `cards[t] = b.strip()` → `miss = [s["card"] for s in spec if s["card"] not in cards]`
|
|||
|
|
⚠️ **`cards` 是 dict,`in` 判的是 key(=标题行),不是 value** → 所以 **spec 的 `card` 必须等于「去 `### ` 前缀后的标题行」**,放全文必然 miss。
|
|||
|
|
- **我犯的错**:`_tmp_bNN_spec.py` 用 `CARD_RE` 提整张卡塞进 `card`(且带 `### `)→ 批 66–70(及此前 59–65、48、49)全部中招。对比成功的批 58:`card` = `"20829-1|凌晨三点半看完球…"`(仅标题)。
|
|||
|
|
- **修复**:对 14 批执行 `sp['card'] = blocks[i].splitlines()[0].replace('### ','').strip()` 后重跑 → 27/27 成功。
|
|||
|
|
- ⭐ **更新铁律表述**(旧的「card 禁带 `### ` 前缀」不够精确,易误解成"全文去前缀"):**`card` = 标题行本身(去 `### `、strip),不含正文字段。**
|
|||
|
|
- ⭐ **排查口诀**:报「spec 与 md 对不上」时,**不要读那一大坨报错文本**(它把整卡打印出来,看不出差异),直接复现 L40–48 的两行逻辑比对 `spec[0]['card']` 与 `cards` 的 key。
|
|||
|
|
- ⚠️ **apply-pending 不会修 card**:`10_polish_batch.py` L412–413 只回写 `sp["std"]/["sim"]/["neg"]`,**不动 `card`**(标题润色前后不变,所以不修是对的)。**card 的正确性全在生成 spec 那一刻**,写错只能事后修。
|
|||
|
|
|
|||
|
|
**导入后的遗留项**
|
|||
|
|
- 批 48 的 `sim=2`(少 1 条)**已随导入进库** → 按红线「改问法只能删+重导」,若要补须删该批 15 条重导。**未处理,待用户定夺。**
|
|||
|
|
- 批 43 的 `neg=3`(且是关键词短语)—— **neg 不入索引**(RUNBOOK §步骤6),对召回无影响,可不处理。
|
|||
|
|
- 回炉链路仍未完成:删旧条目(按 `polish_plan.json` 冻结的 526 id)+ 重导 + 检索终验。
|
|||
|
|
|
|||
**新增踩坑**
|
||||
|
|
- ⚠️ `_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` 为准**。
|