犀牛鸟 2026 研究笔记 estelledc.github.io

从 12 个案例提炼 WeKnora 贡献模式

结论先行

通读 15 个 merged PR(首批 5 案 + Phase G 新增 10 案)后,好的 WeKnora 贡献有以下共性:


1. Issue 选择模式

「够小能交付」的判断标准

从首批 5 案的实际改动规模看:

案例 文件数 净增行数 从 Issue 到合入的周期
case-1785 2 +111/-1 ~2 天
case-1633 预估 1–2 预估 ≤10 未提交
case-1725 3 +149/-0 ~1 天
case-1761 1 +3/-0 ~1 天
case-1774 11 +437/-2 ~1 天

经验值:初次贡献选 1–3 文件、+50 到 +150 行的 issue。case-1774 虽有 11 文件 +437 行,但其中 67% 是测试代码,实际业务逻辑新增约 140 行,仍属可控范围。

各栈的「安全改动区」

反面论证:暂不选作教材的 PR

case-index 中被排除的 10 个 PR 可以看到不适合新手的特征:


2. 定位模式

从现象到文件的固定步骤(综合首批 5 案提炼):

  1. 读 Issue 描述 + 截图:确认能复现、记录”什么操作 → 什么现象”
  2. 画数据流:从用户操作到最终表现,经过哪些层(UI → Store → API → Service → Repository → DB;或 Upload → docreader → docparser → chunker → 向量存储 → 检索 → LLM)
  3. 定位管线入口:噪声/错误”最早从哪一层进入”(向上游追);或”在哪一层丢失/被拦截”(向下游追)
  4. grep 关键词:用 Issue 中出现的字符串(如 DISPIMGundefinedorganizationsLoadedAt)在代码仓库全局搜索
  5. 找到目标文件后读上下文:确认函数签名、调用链、已有的 guard 条件
  6. 写最小复现脚本/手动复现:确认修改前问题确实存在
  7. 设计修复 + 验证修复后不回归
  8. 检查相关文件是否有类似遗漏(如 case-1774 需要同时查 KB 和 Agent 两个表)

各栈调试入口

前端(Vue 3 + Pinia)

Go 后端(case-1774 的测试方式)

Python docreader(case-1785 的测试方式)


3. 实现模式

PR 描述四段式

段落 内容 真实案例
What 一句话描述用户看到的现象 case-1785:”RAG 问答时 AI 回复中出现 DISPIMG("ID_xxx",1) 函数字符串”
Why 根因链(从现象到代码路径) case-1761:”fetchOrganizations() 的 TTL 缓存守卫在创建成功后 10 秒内拦截了请求”
How 修复方案 + 为什么选这个方案而非其他 case-1725:”在 docparser 层插入 HTML 表格归一化器,能转 Markdown 的转,不能转的剥离样式”
Test 怎么验证修复有效 case-1774:”新增 model_delete_test.go 覆盖删除保护的所有分支”

改动粒度统计

文件数 案例 合入速度
1 case-1761 当天
2 case-1785 次日
3 case-1725 当天
11 case-1774 当天(维护者自己提交)

结论:外部贡献者的 PR 控制在 1–3 文件 是最安全的区间。case-1774 之所以 11 文件也能当天合入,是因为作者本身是主维护者。

命名、错误处理、测试的共性规范

命名

错误处理

测试


4. 栈与目录对照(2026-06 现状)

想改什么 目录 参考案例
Excel/Word/PDF 解析噪声过滤 docreader/parser/ case-1785
OCR 输出格式归一化(HTML→Markdown) internal/infrastructure/docparser/ case-1725
PDF 扫描件强制 OCR / ingest 策略 docreader/ + knowledge_process/ case-1808
MHTML 跨语言管线 docreader/ + docparser/ case-1743
Chunk 策略 / heading breadcrumb internal/infrastructure/chunker/ case-1700
向量库复制 / ID 映射 tencentvectordb/repository.go case-1668
向量库 replica / env-store tencentvectordb/ + types/vectorstore.go case-1759
检索 API(hybrid-search POST) internal/handler/ + MCP case-1754
Web-search 可行动错误 internal/.../websearch/ case-1784
Agent QA 入口 / 权限 guard internal/application/session/ case-1772
Go API 新增校验 / 删除保护 internal/application/repository/ + service/ + handler/ case-1774
前端 Store 缓存失效 / 状态同步 frontend/src/stores/ case-1761
前端组件字段映射 / null guard frontend/src/views/ + frontend/src/stores/ case-1633
docreader 单测 docreader/tests/ case-1785
Go embed / 出站安全 internal/models/embedding/ case-1828
Agent thinking / RAG 时间线 internal/types/ + RagPipelineProgress.vue case-1773
Go 后端单测 与源文件同目录 *_test.go case-1774 · case-1700 · case-1828

5. 反模式

从被排除的 PR 提炼

反模式一:改动范围不聚焦

典型代表:#1787(32 文件 +2585/-1507)、#1769(31 文件 +2317/-147)。这类 PR 需要多个维护者同时 review,任意一个文件的问题都可能 block 整个 PR。对新贡献者来说,一个被 block 两周的 PR 比没提交 PR 更打击积极性。

反模式二:跨栈联动无分拆

典型代表:#1789(前后端联动 8 文件)、#1775(IM 集成全栈 19 文件)。正确做法是拆成后端 PR + 前端 PR 分别提交,后端先合入再开前端 PR。

反模式三:缺少测试

case-1633 虽然根因已被社区确认,但迟迟没有正式 PR 的原因之一可能是——仅修改字段映射而不加 normalize 函数的单测,维护者可能觉得不够完整。从首批 5 案数据看,所有当天合入的 PR 都有对应测试。

反模式四:只写 “fix #xxxx” 不解释根因

5 个案例中,所有快速合入的 PR 都有清晰的根因描述。维护者审核带宽有限,一个 self-explanatory 的 PR 描述能把 review 时间从 30 分钟压缩到 5 分钟。

Open Design PR #3356 的经验

这是一个已合入但属于不同仓库(Open Design)的 PR。它的改动规模偏大且跨多个模块,虽然最终合入但经历了较长的 review 周期。教训是:即使你对代码有信心,大范围改动本身就会拉长合入时间——维护者需要更多精力理解影响面。如果能拆成多个小 PR 分批提交,每个 PR 的合入速度和质量都会更好。


6. Phase G 新增模式(新增案例补充)

模式 代表案例 要点
sub-chunk metadata 继承 case-1700 二次切分后按 offset 解析最深 breadcrumb,不是整 section 共用
分页复制 ID 映射 case-1668 向量库 CopyIndices 逐页 query 时必须 remap chunk ID
GET→POST API 演进 case-1754 复杂检索 body 需要 POST;同步 MCP tool + OpenAPI
ingest 策略路由 case-1808 无 text layer 的 PDF 走强制 OCR,UI 可配置
死字段误拦清理 case-1772 删未使用的 guard 比加逻辑更安全(-109 行)
跨语言管线 E2E case-1743 Python 解析 + Go chunk 需端到端验证图片/链接
横切安全 transport case-1828 多 provider 抽 transport.go;构造期 SSRF;标杆案
Agent thinking / 时间线 case-1773 nil→explicit default;后端 log + 前端时间线同 PR
env-store 双端配置 case-1759 repository + UI 元数据;QA replica=0

完整候选与下一批:case-catalog.md Tier B(一次只写 1 案,见 case-writing-standard)。


7. 思考点

题 1:你看到一个 Issue 描述”上传 PDF 后,某些页面的表格内容丢失”。已知 WeKnora 的 PDF 解析走 docreader/parser/pdf_parser.py。你会用哪条模式定位?第一步做什么?

题 2:你想修复一个前端 bug——”删除知识库后列表没有刷新”。根据 case-1761 的模式,你会去哪个 store 文件找 TTL 缓存守卫?修复方案是什么?

题 3:一个 Issue 要求”当用户删除 Agent 时,如果该 Agent 正在被某个工作流引用,应拒绝删除”。根据 case-1774 的模式,你需要改哪几层的哪些文件?改动的顺序应该是什么?

题 4:你发现 PaddleOCR-VL 解析某些 DOCX 文件时,输出中混入了 \uf0b7(Unicode bullet)字符,影响分块质量。参考 case-1785 和 case-1725 的模式,你会在哪一层做过滤?用什么样的正则?测试用例怎么设计?

题 5:一个 PR 改了 15 个文件(前端 8 个 + 后端 7 个),reviewer 已经一周没回复。根据反模式分析,你应该怎么做才能加速合入?


8. 下一章预告

ch-bridge-1248 将把本章提炼的模式直接映射到 Issue #1248(知识库问答-点赞点踩)的实施方案上: