WeClaw_84|否决一个看起来很美的方案:五道闸门与「证伪优先」的选型方法

发布时间:2026/8/30 20:44:17
WeClaw_84|否决一个看起来很美的方案:五道闸门与「证伪优先」的选型方法 Hi带娃的我热爱AI 大模型应用落地、意识解码与 AI 开发工具链。 创业路上用技术换时间一起把 AI 变成生产力 WeClaw_84否决一个看起来很美的方案五道闸门与「证伪优先」的选型方法系列文章第 84 篇- 技术选型方法学 · 证伪优先 · 跨语料基准不可迁移 · 天花板效应 · 依赖真实账单 · 零成本取证 专栏信息《从零到一构建跨平台 AI 助手WeClaw 实战指南》专栏专栏定位面向开发者和技术决策者的实战专栏用真实案例和完整代码带你理解如何构建生产级 AI 应用本文记录一次决定不做的完整决策过程GitHub 上 40k star 的记忆层框架 Mem0与 WeClaw 自研的跨会话经验系统 EBEAC 看起来天生互补——一个有多信号检索和成熟 API一个有零 LLM 成本的自动采集。方案写完了评审提出 5 个 Critical但评审只能提问不能回答。于是我们写了 5 个探针脚本、零新增依赖、不装 mem0ai在 4 小时内拿到了否决所需的全部证据。最关键的一个数字是0.0%。‍ 作者与项目作者简介翁勇刚 WENG YONGGANG新概念龙虾-WeClaw 开发团队负责人一群专注于跨平台 AI 应用的实践者理念“再复杂的技术也能用代码讲清楚” 项目地址https://github.com/wyg5208/weclaw.git 官网地址https://weclaw.link 作者 CSDNhttps://blog.csdn.net/yweng18⭐ 欢迎 Star⭐、Fork、贡献代码 摘要本文结构概览一个看起来天生互补的集成提案 → 三视角评审提出 5 个 Critical 但无法自行裁决 → 把要不要引入翻译成五道可执行闸门 → 五道闸门的实测数据3 道明确 FAIL→ 决策不引入转向三条本地优先项 → 沉淀三条可迁移的方法论 → 诚实复盘我在这轮里犯的错。核心问题如何在不安装、不改生产代码、不投入迭代周期的前提下判断一个热门框架值不值得引入以及更难的一问——当引入方案的收益论证建立在别人的 benchmark 上时怎么验证那些数字对你的场景成立关键成果用 5 个探针脚本约 900 行零新增依赖在集成前拿到否决证据未写一行生产代码实测证伪多信号检索的收益前提英文空白分词在中文语料上的词表命中率0.0%实测发现基线天花板效应裸向量检索 Recall3 已 100%任何引擎替换都无法在该指标上证明收益量化依赖真实账单强制升级 posthog、无条件新装 qdrant-client、0.1.100实际解析到 2.0.15定位真正瓶颈175 条经验只有 24 个 distinct pattern问题在采集端不在检索端适合读者需要为项目做框架选型的技术决策者做 RAG / 记忆系统 / 检索的工程师所有面对这个开源项目好像很适合我们时想要证据的人阅读时长约 16 分钟关键词技术选型、证伪优先、Mem0、EBEAC、BM25、中文分词、RRF、依赖冲突一、一个看起来天生互补的提案WeClaw 有一套自研的跨会话经验系统 EBEACEvent-Based Experience Auto-Capture工具调用失败后重试成功的踩坑-爬坑序列会被自动记录进 SQLite ChromaDB下次遇到相似任务时语义检索召回、注入系统提示词。它的核心设计主张是zero additional LLM cost——采集与检索全程不调用大模型这是它能写进论文的地方。调研 GitHub 记忆层生态时Mem0 几乎是绕不过去的项目40k star、Apache 2.0、活跃维护LoCoMo 基准 92.5、LongMemEval 94.4。它的能力清单看起来正好补上 EBEAC 的短板维度EBEAC 现状Mem0 提供检索信号纯语义向量语义 BM25 实体多信号融合记忆演化无只增不改V3 additive pipeline容量LRU 上限 500 条无硬上限生态自研 API成熟 SDK 多 vector store 适配于是有了一份集成方案以 EBEAC 为采集端和事实源Mem0 作为检索增强层用inferFalse免 LLM 直存以保住零额外 LLM 成本的论文主张。方案写得很完整——技术栈对齐、挂载点、配置项、文件清单、回滚方案。看起来很美。二、评审提出 5 个 Critical但评审不能替代证据我们没有直接开工先做了一轮三视角并行评审完备性 / 正确性 / 影响面合并后是 5 个 Critical、9 个 Warning、5 个 Suggestion。其中三条最扎心立论自相矛盾为保住零 LLM 成本必须用inferFalse原文直存但多信号检索的收益恰恰依赖 Mem0 的 LLM 抽取管线。两个收益不能同时成立。分数尺度不可比方案打算把 Mem0 返回的 score 接进 EBEAC 的 0.55 阈值过滤但两者量纲根本不同。没有验收标准方案用 LoCoMo 92.5 做收益论证而那是英文对话记忆基准与中文工具失败经验召回是两个任务。评审做到这里就到极限了。评审能指出你没有证据但它自己也没有证据。三个子评审在inferFalse这一点上甚至给出了不同倾向——这恰恰说明纯靠阅读和推理无法裁决。所以决策变成先取证证据到位前不启动实施。三、方法学把决策翻译成五道可执行闸门关键动作是把一个模糊的要不要引入拆成五个能被脚本回答的是非问题并且按依赖关系排序——前一道不通过后面的对比就不成立。探针回答的问题闸门标准01 语料诊断语料本身有没有可提升空间去重后有效条目 ≥ 50、模板化率 ≤ 50%02 检索基线现有检索的真实水平是多少建立基线替代 LoCoMo 类比03 依赖探测引入会动到哪些既有包无强制升级、无无条件新装04 BM25 信号中文语料上词面信号存在吗空白分词 semantic R3 5%05 融合增量多信号相对纯语义能加多少R3 或 MRR 有正增量三条约束让这套探针的成本几乎为零约束一零新增依赖。全部探针只用当前 venv 已有的包。这是个意外之喜——检查后发现jieba和rank_bm25早已安装意味着多信号融合这个核心卖点可以完全不依赖 Mem0 就地验证。03 只读 PyPI 的 JSON 元数据绝不执行pip install。约束二零人工标注。沿用 WeClaw_71 建立的方法学——真值取自experiences.tool_names字段查询针对某工具的失败场景则tool_names含该工具的经验即为相关。Hit1 / Recall3 / MRR 全部脚本自动算。约束三查询分两组。这是本轮最有效的一个设计# lexical含工具名字面量 → 词面检索的主场Query(f{tool}连续失败后重试成功,tool,lexical)# semantic中文同义表述、无字面重叠 → 只能靠语义向量Query(终端指令跑不起来一直返回错误,shell,semantic)两组指标之差就是多信号融合能带来的理论上限。后面会看到这一刀切得很值。还有一个容易忽略的安全细节recall()会自增hit_count直接在生产库上跑评测会污染真实使用统计。所以所有需要实例化ExperienceStore的探针都先克隆数据shutil.copy2(EXP_DB,db_copy)# SQLite WAL 模式下的旁挂文件一并复制避免丢失未 checkpoint 的数据forsuffixin(-wal,-shm):sidePath(str(EXP_DB)suffix)ifside.exists():shutil.copy2(side,str(db_copy)suffix)四、五道闸门的实测结果数据源~/.weclaw/experiences.db175 条真实经验2026-05-30 ~ 2026-07-31。4.1 闸门 01真正的瓶颈不在检索在采集经验总数 : 175 distinct pattern : 24 ← 去重后 recall 的可选池上限 去重坍缩率 : 86.3% outcome 分布 : {success: 175} 距离触发 LRU 淘汰 : 325 条三个发现直接改写了问题定义175 条经验只有 24 个 distinctabstract_pattern。recall()管道里有一步_deduplicate_by_pattern同一 pattern 只保留一条所以检索的可选池上限就是 24 条。Top 3 patternshell 47 条 / paper_lifecycle 36 条 / wechat 32 条覆盖 65.7% 的语料。outcome全部是success意味着_filter_by_outcome目前是个空操作。距 LRU 上限还差 325 条从未触发过淘汰——方案里解除 500 条容量上限这条收益根本不是当前的瓶颈。第一道闸门就 FAIL 了而且它给出的启示比不引入 Mem0更重要真正的瓶颈在采集端。ExperienceAutoRecorder生成的经验高度模板化数字归一后重复率 36%24 个 pattern 撑不起任何检索优化的收益空间。换检索引擎解决不了语料只有 24 种花样的问题。这就像给一个只有 24 本书的图书馆升级检索系统。4.2 闸门 02基线已经触顶方案lex R3sem R3ALL H1ALL MRRA.recall()完整流水线100.0%100.0%45.8%0.701B. 裸向量检索无过滤100.0%100.0%95.8%0.979C. SQLite LIKE 词面检索0.0%0.0%0.0%0.000B 行是决定性的裸向量检索的 Recall3 已经是 100%。这叫天花板效应——当对照组满分时任何替换方案都不可能在该指标上证明收益。方案里所有提升检索精度的论证在这张表面前失去了着力点。C 行的 0.0% 起初像是脚本 bug核对源码后确认是真实行为def_sqlite_fallback_recall(self,query:str,top_k:int)-list[Experience]:kwf%{query}%# ← 把整条查询当子串匹配rowsself._db_conn.execute(SELECT * FROM experiences WHERE (trigger LIKE ? OR diagnosis LIKE ? ...),...)它把整条查询字符串当子串去匹配对任何自然语言查询必然零命中。这不是词面检索是一个早就失效的降级兵——好在它只在vector_store不可用时才触发。A 行与 B 行之间那个 50 个百分点的 H1 落差是本轮最大的意外收获它值得单独一篇见下期。4.3 闸门 03依赖的真实账单方案写的是mem0ai0.1.100。实际查询 PyPI最新版本 : 2.0.15 存在的主版本号 : [0, 1, 2] [!] 方案写 mem0ai0.1.100但 会直接解析到最新的 2.0.15 跨越了主版本边界。0.1.100会直接装上 2.x。方案中所有基于 0.1.x 行为得出的 API 设计V3 流水线、search()参数形状、inferFalse语义都未在该主版本上验证过。再看它对既有环境的影响脚本把重叠依赖分了级[强依赖] posthog7.14.0 本地 7.7.0 判定 将强制升级 [强依赖] qdrant-client1.12.0 本地 未安装 判定 将新装 [强依赖] sqlalchemy2.0.31 本地 2.0.49 判定 已满足两笔硬成本强制升级 posthogchromadb 的遥测依赖波及 EBEAC 运行时基座、无条件新装 qdrant-client即使我们打算继续用 ChromaDB。这里要诚实标注探针的能力边界它只能证伪不能证实。requires_dist没重叠 ≠ 安装不冲突传递依赖和 resolver 回溯只有真实解析才暴露。所以脚本的结论是给出下一步而不是拍板python -m pip install --dry-run --report - mem0ai # 需批准后执行 python -m venv .venv_mem0_probe # 一次性隔离环境4.4 闸门 040.0%——多信号在中文语料上退化为单信号这是全场最关键的一个探针。Mem0 的核心卖点是语义 BM25 实体多信号融合而它的 BM25 走英文分词路线。中文经验文本没有空格——那么分出来的 token 还能与查询产生词面重叠吗不需要安装 mem0ai 就能回答因为问题可以拆成纯分词层面的实验分词器平均 token 数词表大小语义查询命中词表率sem R3空结果率WS空白近似 Mem0 默认22.75170.0%0.0%50.0%REGEX\w27.85460.0%0.0%50.0%JIEBA中文分词76.972350.8%41.7%4.2%0.0% 的词表命中率意味着 BM25 对中文语义查询完全无输出。原因很朴素text.split()和re.findall(r\w)都会把整段连续 CJK 吞成一个巨型 token\w匹配 CJK而用户的查询是另一句中文两者不可能在 token 级别重叠。结论是硬的Mem0 的语义 BM25 实体三信号在中文语料上退化为纯语义单信号。方案援引的 LoCoMo 92.5 / LongMemEval 94.4 全部来自英文语料——它们不是参考值偏高的问题而是测的根本不是同一件事。顺带还测出一个尺度事实正好回答评审的第 2 个 CriticalBM25 原始分数量纲对比向量相似度的 0~1: JIEBA n192 min1.70 p509.43 max23.41BM25 分数无上限且随语料漂移把它和 0~1 的相似度混在一个 0.55 阈值里判断是没有意义的。任何融合都必须先做秩结合或分数归一。4.5 闸门 05融合的真实增量是 0前四道闸门已经把方案的收益论证拆得差不多了但还剩最后一个、也是唯一与投入产出直接相关的问题在真实语料上语义 词面融合相对纯语义到底能提升多少既然jiebarank_bm25本地就有我们直接实现了 Mem0 卖点的本地等价版——RRF 秩结合它只用排名不用分数天然免疫量纲差异RRF_K60defrrf_fuse(*ranked_lists:list[int])-list[int]:Reciprocal Rank Fusion只用排名不用分数天然免疫量纲差异。scores:dict[int,float]{}forlstinranked_lists:forrank,doc_idinenumerate(lst,start1):scores[doc_id]scores.get(doc_id,0.0)1.0/(RRF_Krank)return[docfordoc,_insorted(scores.items(),keylambdakv:-kv[1])]四路同台方案lex R3sem R3ALL H1ALL MRRp50A. 向量 only100.0%100.0%95.8%0.97939.2msB. BM25/jieba only100.0%41.7%70.8%0.7080.3msC. RRF 融合100.0%100.0%95.8%0.97236.4msD.recall()生产现状100.0%100.0%45.8%0.70137.9msC 融合 - A 纯向量 R3 0.0% H1 0.0% MRR -0.007融合相对纯语义零增量MRR 甚至微降。原因在闸门 01 里就埋好了纯语义已经触顶词面信号只是重复命中同一批经验——24 个 pattern 的语料给不出两种信号互补的机会。五、决策与替代路线五道闸门中01 / 03 / 04 明确 FAIL02 / 05 显示现有向量检索已触顶而生产排序正在损失精度。决策不引入 Mem0。但这轮取证的产出远不止一个不字。证据同时给出了一份按收益排序的本地优先项修_apply_time_decay的排序损失约 4 行无新依赖——A 与 D 之间 50 个百分点的 H1 落差改造ExperienceAutoRecorder的经验生成质量——24 个 pattern 才是真正的天花板修或移除失效的_sqlite_fallback_recall引入 Mem0 —— 当前无证据支持顺序很说明问题排在前面的三项全部是本地的、零依赖的、几十行以内的。我们原本准备用一个 40k star 的框架去解决的问题真身是自家管道里的三个小缺陷。六、三条可迁移的方法论6.1 证伪优先否决的成本远低于验证引入一个框架要真装、真接、真测成本是周期级的。而否决它往往只需要一个数字。本轮 5 个探针、约 900 行脚本、零新增依赖、零安装4 小时拿到全部否决证据。关键在于顺序先找最便宜的证伪路径。04 探针是全场性价比最高的——它没装 mem0ai只是把Mem0 的 BM25 用英文分词这个已知事实和我的语料是中文这个已知事实放到一起做了个分词实验。很多集成方案的收益前提可以在不接触该框架的情况下被证伪。6.2 别人的 benchmark 不是你的验收标准LoCoMo 92.5 是真实的、可复现的、没有夸大的。它唯一的问题是它测的是英文长对话记忆而我们要做的是中文工具失败经验召回。判断一个外部基准能不能迁移看三件事语料语言、任务形态、评测指标口径。本轮三项全不匹配而 04 探针把不匹配量化成了 0.0%。一个数字要成为你的决策依据它必须在你的数据上被重新测一遍。这也是 02 探针存在的全部理由——方案里那句精度未知无基准“随后接了个 LoCoMo 类比正确的做法是把未知变成已测”。6.3 先定位瓶颈再选工具这轮最反直觉的收获来自 01 探针我们讨论了很久哪个检索引擎更强而真正的约束是语料只有 24 种花样。顺序应该反过来先量化现状的天花板在哪再看候选工具能不能碰到那个天花板。02 探针里裸向量 R3 100% 这一行本身就宣告了提升检索精度这条收益路径不存在——不管候选是 Mem0 还是别的什么。七、诚实复盘我在这轮里犯的错方法论讲得再顺过程里的错也要记下来否则下次还犯。错误一把依赖版本记错了并且传播了。前期分析一直按chromadb 1.5.5/sentence-transformers 5.2.3陈述评审报告里也是这两个数字。03 探针实测是1.5.9 / 5.5.1。修法不只是改数字而是把脚本里写死的版本改成运行时读取print(f chromadb{current.get(chromadb)or?}与 fsentence-transformers{current.get(sentence-transformers)or?}是 EBEAC 的运行时基座)教训凡是能从环境读到的事实就不要在文档和脚本里抄一遍。抄一次就是一个会过期的副本。错误二p95 掩盖了冷启动。02 探针第一版指标表只有 p50 / p95n24 时 p95 的索引落在第 22 位正好跳过了唯一的冷启动异常点。后来补上maxms列真实数字露出来了9175.8ms——嵌入模型首次加载 9.2 秒。教训小样本下的分位数会系统性地藏住尾部异常。指标表里保留一列原始 max成本一个字段收益是不被自己的统计骗。错误三脚本写了会误导的提示。01 探针的报错分支提示用--db指定路径但那个版本压根没有 argparse。02 探针最初的结语是若 C 在 lexical 组接近满分则 BM25 收益有限——一句预设了结论的条件句而实测 C 是 0.0%。后来改成由当轮数据直接判定ifc.empty_rate0.9:print([!] LIKE 路径几乎全空_sqlite_fallback_recall 用 LIKE %整条查询% 做子串匹配)教训取证脚本的输出不该包含如果……那么……式的预判。让数据自己说话脚本只负责判定。八、总结3 个关键点证伪优先引入的验证成本是周期级的否决往往只需一个数字。优先寻找最便宜的证伪路径——很多收益前提可以在不接触该框架的前提下被推翻基准不可迁移别人的 benchmark 只在它的语料、任务、指标口径下成立。判断迁移性看语言、形态、口径三项并把不匹配量化出来先量瓶颈后选工具对照组已经满分时任何替换方案都无法在该指标上证明收益。天花板的位置决定了候选工具有没有发挥空间1 个核心公式引入决策 收益前提在我的数据上成立 × 真实依赖账单可接受 × 现有基线未触顶 三项任一为假结论即为不引入互动环节思考题如果你的项目也在用某框架的 benchmark 分数作为引入依据那个基准的语料语言和任务形态与你的场景一致吗把它在自己数据上重测一遍需要多少成本本文的 04 探针在不安装 mem0ai 的前提下证伪了它的核心收益。你手上待评估的框架有哪些收益前提可以用类似的拆解到已知事实方式提前验证讨论话题你有过准备引入一个大框架最后发现真正要修的是自家几十行代码的经历吗下期预告《时间衰减的第二层修好误杀之后它开始悄悄毁掉排序》WeClaw_72 修好了衰减在阈值前的误杀为什么 H1 还是只有 45.8%非空返回率 100% 与 Hit1 45.8% 同时成立验收指标的盲区考古层位第三层一个缺陷如何靠上一次修复的验收口径存活下来敬请期待版权声明本文为 CSDN 博主「翁勇刚」的原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接及本声明。