新增 mcn-workshop/docs/会话任务链路-待优化项.md:4 项待优化(任务模型浮动/面板跳转入口/任务权限/旧会话归位)+红线+已修历史。 同步:项目 MEMORY.md 权威源表加该文档指针,工作台红线补 workspace_scope 一条。 理由:只写进当天日志的规矩换会话读不到,必须落到工作台文档与长期记忆。
39 KiB
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、lastUpdateAt10:13:51 ⇒ 数据已在落盘。 - 真因两条(都与抓取逻辑无关):① 会话
cwd = …\mcn-work-shop⇒ 落在侧边栏 mcn-work-shop 空间分组,不在用户当前空间,需切组才可见(这是设计,非 bug);② 工作台服务作为会话后台任务被回收 ⇒ 前端轮询/api/run/status持续抛错。 - 修复:
public/data-pages.jsupdateRankingData()轮询加失败计数 —— 连续 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.jsL1265 / L1269,原「旧 mcn-workshop/新建 mcn-workshop」被换成同词,已补回三代路径)→ ⑤ 重启验证:app.js/data-pages.js200,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)。
- ⭐ 会话日志路径换算(可复用):cwd → projects 目录名 = 盘符小写 + 分隔符全转
- 前端新增
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.jsSESSION_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,⛔ 不能因为"地址能连通"就推。
合并两条历史并完成同步(15:4x)
- 合并
admin/main(两条独立历史、无共同祖先):冲突 20 文件 47 块。- 40 块自动:规则①一边为空 → 取非空(纯新增,取并集);规则②ours 含
mcn-workshop且 theirs 含mcn-work-shop→ 取 ours(目录改名,本地最新)。 - 7 块人工(全在
MEMORY.md):本地 v4 精简版覆盖远程 v3,远程的详细条目在 RUNBOOK/技能文档均有指针 ⇒ 取本地。 - ⚠️ 脚本坑:冲突标记正则必须写
\r?\n(工作区是 CRLF),第一版漏了导致 0 匹配。
- 40 块自动:规则①一边为空 → 取非空(纯新增,取并集);规则②ours 含
- ⭐⭐ 合并的隐藏副作用(换线合并必查):远程那条线的工作台目录仍是旧名 ⇒ 合并后旧目录
mcn-work-shop被整个带回,两套代码并存。- 取证三步:①
diff -rq显示旧目录零独有文件;②server.js报 2672 行差异,实为行尾差异(旧 CRLF / 新 LF),diff --strip-trailing-cr后仅 206 行;③ 其中旧目录独有的 40 行全是本地已升级掉的旧代码(旧版凭据解析 / 旧状态接口 / 写死的会话目录)⇒ 远程无本地缺失的实质改动。 - 结论:安全删除,已
git rm -r -f(合并暂存态需-f)。
- 取证三步:①
- 推送:
git push admin main= 快进e738dd1..67317c4(合并后远程变成本地祖先,不是强推)。本地与 admin 已完全一致(rev-list --left-right --count=0 / 0)。 - ⚠️ 旧 origin(
work.alotbuy.com:222)仍 ahead 256,网络不通未推。
旧远程清理(16:1x,用户:「旧的远程没用了」)
- 处理三步:①
git remote set-url origin指向[email protected]:admin/mcn-short-video.git——保留默认远程名 origin,脚本与命令习惯不用改;② 删除冗余别名admin(与 origin 同址);③ 删除随旧远程留下的本地分支admin-main(= e738dd1,是 main 的祖先,零独有内容)。 - 验证:只剩 origin 一个远程;本地与 origin 完全一致(
0 / 0)。 - 📌 远程口径(本项目现行):
[email protected]: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⇒ 落「未分组任务」。
- 走正规 automation 工具创建的任务:
- ❌ 排除的假因:改 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',否则会话一律落「未分组任务」。
会话任务链路审计(用户:「看看哪些需要调整」)
已修:4 个轮询点口径统一(此前只有榜单更新一处有容错)。
- 轮询点 =
app.js executeTask(通用 AI 任务)/data-pages的榜单更新、批量更新账号、视频解析。 - 原先 3 处是
catch(e){continue},服务被回收时静默空转 15~35 分钟才超时 ⇒ 用户只看到按钮转圈。现均为「连续 3 次查询失败 → 提示服务断开 → 结束轮询」。
已确认健康(无需改):
- 写宿主
automations表仅 2 处(createOnceAutomation约 L409、/api/run约 L880),均已带workspace_scope。 submit-review-tasks.cjs、check-run-status.cjs走 HTTP 接口/只读,不直接写库 ⇒ 自动被修复覆盖。- 技能挂载(
skills_json)、浏览器锁约束、会话清理(SESSION_CWD_PATTERN='%mcn-work%'仍覆盖新 cwd)均正常。
待用户定(各有权衡):
1、任务模型浮动:model_id 取 sessions 最近活跃手动会话的 model,与 config.ai.cli.model(deepseek-v4.1-flash)无关 ⇒ 同一任务换次数可能换模型,产出不稳定。建议加 taskModel 配置(留空=跟随现状,填了=固定)。
2、进度面板缺「打开会话」入口:能看状态但跳不进会话。
3、任务权限恒为 fullAccess(可写文件/执行命令):是否收紧取决于任务类型。
4、修复前创建的旧会话仍 playground=1:改库可归位,但需重启 WorkBuddy 才生效。
素材库补采:批 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/*.md41 批(早期跑过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,restartunless-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.pyL40–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.pyL412–413 只回写sp["std"]/["sim"]/["neg"],不动card(标题润色前后不变,所以不修是对的)。card 的正确性全在生成 spec 那一刻,写错只能事后修。
导入后的遗留项
- 批 48 的
sim=2(少 1 条)已随导入进库 → 按红线「改问法只能删+重导」,若要补须删该批 15 条重导。未处理,待用户定夺。 - 批 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_search0 次 ≠ 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为准。