熟悉我的人都知道我一直有个执念研究过程应该像代码一样可追踪、可复现、可 review。去年我花了大半年时间把个人和团队的研究流程彻底重构了一遍这个内部项目代号就叫 OpenResearch。它不是某个商业软件而是一套基于 Markdown、Git 和大模型辅助的开放研究工作流。这篇文章完整记录了它的设计思路、核心工具选型、落地过程和踩坑记录适合那些正在做文献综述、技术预研、行业调研或者想搭个人知识库的读者。这里要强调一下OpenResearch 不是又一个笔记软件也不是知识管理玄学。它解决的是三个很实际的问题第一研究过程中产生的判断依据能不能随时回溯第二多人一起做调研时信息能不能无缝衔接第三大模型参与研究后哪些内容是机器生成的、哪些是人工判断的能不能一眼分清。目标很朴素让研究像开源代码一样每个 commit 都有意义。1. OpenResearch 到底要解决什么问题1.1 传统研究的暗箱问题我做过很多次技术调研最痛苦的从来不是找不到资料而是资料太多之后我忘了自己为什么做出某个判断。比如两个月前读了一篇论文当时觉得“A 方案有性能问题不能选”但等真正写方案时我只记得结论忘记了当时的实验数据和分析过程。这种“只留结论、不留路径”的研究方式其实是一种暗箱。个人研究如此团队协作更严重。你收到同事转过来的一篇文献上面写着“这篇文章很有参考价值”但你不知道他关注的是哪个点是方法、数据还是结论。没有上下文的信息往往只能重新读一遍。OpenResearch 要做的第一件事就是把暗箱打开。具体做法每个结论必须关联到支持它的原材料每个引用必须关联到具体的段落每个数据结论必须关联到处理脚本。说白了就是让研究过程的每一步都可以被追问下去。这个思路并不新学术圈的 reproducibility 已经喊了很多年但落地到个人工作流里需要一套非常轻的机制太重了没人维护。我曾经试过用一个沉重的项目管理软件来管文献结果光是状态流转就花掉大量时间三个月后整个系统就烂尾了。所以 OpenResearch 的第一原则就是“轻”。轻到什么程度打开终端一个git log就能看到整个研究的演化历史打开任意一张 Markdown 卡片五分钟内就能知道这篇材料解决了什么问题、还有什么疑问。这套机制不需要后台服务不需要复杂数据库只要一台电脑和一个 Git 仓库就能跑起来。也正因为轻它才能长期坚持下来。1.2 从“开放获取”到“开放过程”大家谈“开放研究”的时候第一反应往往是开放获取OA也就是论文免费读。但只开放论文是不够的。论文只是研究的最终输出真正的 know-how 藏在前期的调研、实验、失败尝试里。所以 OpenResearch 把重点放在“开放过程”不要求你把所有东西公之于众而是要求“自己或队友之后可以完整还原过程”。我经常说先别管别人能不能复现先解决三个月后的自己能不能复现。这套思路适合谁我觉得很明确一是经常写技术方案、行业报告的人需要引用大量外部资料二是做科研或产品预研的团队需要共享调研结论三是想用大模型辅助阅读又怕被幻觉带偏的人。如果你只是随手记日记不需要搞这么重。但如果你发现自己经常“读了一堆资料还是写不出来”OpenResearch 这套流程会很有帮助。我自己最开始也怀疑把过程记录下来会不会很费时间。后来发现真正费时间的不是记录而是“没有记录的返工”。一张卡片十分钟就能写完但如果没有卡片等写总结报告时你可能会花几个小时重新翻 PDF、找原文、回忆当时的想法。两相对比开放过程的成本低得多收益却高得多。2. 整体设计与工具选型2.1 为什么选 Markdown Git 作为底层在设计 OpenResearch 时我评估过好几类工具在线文档、Notion 类知识库、本地笔记软件最后全部放弃了底层选定了 Markdown 文件 Git 仓库。原因很简单纯文本可 diff版本可回溯格式不锁定谁都能改。在线文档虽然好看但历史版本往往只给到“某天某时有人改了”不会告诉你到底改了什么、为什么改。Git 能把每一次改动精确到行配合 commit message就是天然的研究日志。这里有个对比表是我当时做选型时候的备忘录方案可回溯粒度多端同步大模型可操作性长期维护成本Notion/在线文档页面级不精确好依赖 API 或手工导出中本地笔记软件笔记级看软件一般中Markdown Git行级 diff用 Git高纯文本低Markdown 的好处是无论以后换什么工具内容都在我手里。Git 则是把所有研究动作变成了 commit加一篇文献是一个 commit修改一个实验结论是一个 commit甚至删除一篇过时笔记也是一个 commit。这样整个研究演化过程就是清晰的时间线。我还在仓库里用了 conventional commit 规范feat表示新增文献fix表示修正错误docs表示完善记录。别小看这个动作几个月后再看 git log比任何复盘文档都管用。目录结构也是精心设计的我现在的 OpenResearch 仓库长这样research/ ├── notes/ # 研究卡片按主题分子目录 │ ├── llm-rag/ │ ├── vector-db/ │ └── eval-method/ ├── literature/ # 文献元数据和 bib 文件 │ ├── zotero.bib │ ├── reading-list.md │ └── attachments/ # 只放可公开的 PDF 注释不放全文 ├── experiments/ # 实验记录 │ └── 2025-01-08-embedding-compare/ │ ├── run.sh │ ├── params.yaml │ └── report.md ├── reports/ # 阶段性输出技术调研、周报、方案 ├── scripts/ # 自动化脚本去重、摘要、引用检查 └── templates/ # 各类模板为什么把 notes 和 literature 分开因为文献是别人的卡片是自己的。文献元数据是相对稳定的卡片则是动态生长的思考。如果混在一起更新文献信息时很容易污染自己的笔记。这个边界很重要也是多人协作时减少冲突的关键设计之一。2.2 大模型辅助模块的边界OpenResearch 从一开始就引入了大模型但我在设计上给它划了一条清晰的边界大模型只能做“助理”不能做“作者”。具体来说它可以做三件事给论文生成摘要、翻译段落、根据已有卡片起草报告初稿。但它不能直接生成结论也不能自己往 bib 里加引用。为什么这么严因为大模型的幻觉问题在专业研究里是致命的。我见过太多人用 AI 写调研报告读起来通顺但引用文献要么不存在要么张冠李戴。普通文档看不出来一旦要汇报或者写方案就很容易翻车。所以我在卡片里规定凡是 AI 生成的内容必须在文本前加[AI]标记并且说明用的是什么模型、什么提示词。没有标记的内容默认是人工写的出了问题要自己负责。我用到的工具也比较轻。日常摘要走的是本地部署的量化模型7B 级别隐私保护更好速度也够遇到长文档理解再用云端 API但只传公开论文的元数据和摘要不传未发表的实验细节。这个取舍的出发点很简单研究过程里有很多中间结论并不适合外流管住数据边界比追求模型性能更重要。如果团队里有比较敏感的数据我甚至会建议直接用本地模型跑完整流程虽然慢一点但心里踏实。2.3 目录结构与元数据约定目录定了接下来就是元数据。没有元数据文件就是一盘散沙。我在每张研究卡片和实验记录顶部都用了 YAML front matter格式类似于 Jekyll 博客--- id: 2025-01-08-llm-rag-perf title: LLM RAG 检索性能对比 type: note author: zhang date: 2025-01-08 status: draft tags: [llm, rag, evaluation] sources: - yang2024retrieval - liu2023benchmark related: - ../notes/vector-db/2025-01-02-hnsw-vs-hierarchical.md ---字段少而严格。id字段是全局唯一的用来做引用锚点status表示卡片所处的阶段sources里存的是 bib 中的引用 key所有引用必须能在literature/zotero.bib里找到。我写了一个脚本每次 commit 前检查所有卡片里的xxx是否都存在于 bib 文件中如果找不到就直接拦截。这个检查救过我好几次也逼着每个人规范引用来源。一开始我也想过要不要用数据库来管元数据毕竟字段查起来更灵活。但后来放弃了因为数据库的迁移成本太高而且一旦多人协作数据库会变成瓶颈。相比之下YAML front matter 写在文件头部任何一个文本编辑器都能改Git 也能清楚地看到字段变化。即使在移动设备上临时修改也没有任何障碍。3. 核心细节实现让研究工作流真正跑起来3.1 研究卡片的字段设计研究卡片是整个 OpenResearch 的最小单位。它可以对应一篇文献、一个实验、一个灵感甚至一个未解问题。我的原则是一张卡片只回答一个核心问题。字段设计要少而明确不然很快会变成负担。除了上面的 YAML 头卡片正文我固定分成四段关键结论用三到五句话说明这篇材料讲清楚了什么。来源与上下文它与我们正在研究的主线是什么关系。证据与分歧哪些点是数据支撑的哪些点是作者推测的有没有其他文献唱反调。待办与后续还需要补什么实验或者要跟谁确认。这四段结构看起来简单但效果很好。因为大部分人的笔记只有“摘抄”没有“转述”和“判断”。当我把阅读动作强制拆成这四步读论文的速度会慢一些但读完之后的理解深度和记忆留存度大幅提升。用这个模板一篇论文大概十分钟到二十分钟能写一张卡片比过去反复二刷三刷划算得多。我还特别建议每一张卡片都要写“它对当前研究主线的作用”哪怕只是“暂时没看出作用先放着”。这话听起来有点废话但它能逼着你不是为了收集而收集。很多人的文献库越积越多最后变成一座无人看管的知识垃圾场就是因为缺了这条上下文。OpenResearch 里的这类上下文比摘要本身更重要。3.2 文献追踪与自动去重文献管理我用了 Zotero 加 Better BibTeX 插件。Zotero 抓取网页和 PDF 元数据很方便Better BibTeX 可以一键导出带稳定引用 key 的 bib 文件。然后我写了个脚本定时把literature/zotero.bib里的条目和notes里的卡片做关联检查每篇文献至少有一张卡片每张卡片的 sources 都必须存在于 bib。这样就不会出现“引用了但是没读过”的情况。自动去重的逻辑也很简单所有文献以 DOI 或 arXiv ID 为主键没有这类 ID 的以标题规范化后的字符串作为备选主键。脚本每次导入新条目时先查主键发现重复就丢到literature/duplicates.md里而不是直接删除。人工确认后再决定合并还是保留。这个“慢一步删除”的策略非常有用因为自动工具判断不了的边界情况很多。有一次脚本把两篇标题很像但内容不同的预印本当成重复如果直接删了就麻烦大了。幸好我用了“先归档后人工确认”的机制最后发现那是同一个团队的两个阶段工作虽然标题接近但结论有差异后来我把它们都保留了下来并互相加了链接。自动化的目的不是替代人而是把人从机械劳动里解放出来所以任何涉及删除的操作都要千万小心。3.3 可复现实验记录研究过程中只要涉及实验我都会在experiments/下新建一个带日期的目录里面至少包含三样东西运行脚本、参数配置、结果报告。运行脚本必须能从零开始、一键执行参数配置里写清楚每个参数的含义和依据。结果报告不是随便贴几个输出而是包含实验目的、环境信息、结论和下一步。环境信息这里要特别注意我见过太多人记录实验只写“用了 Python 跑了一下”结果三个月后自己都装不回依赖。所以我在experiments/根目录放了一个environment.yml用 Conda 锁定 Python 版本和核心依赖。每次实验结束我会把conda env export的输出连同运行日志一起提交。虽然会让仓库变得有点大但长期看完全值得。我也踩过很多坑比如“跑通了但没记录数据清洗步骤”导致后来想复现时怎么都对不上数。现在我会在实验目录里放一个 README把整个数据链路从头到尾写一遍原始数据从哪来清洗脚本是什么特征怎么构造模型参数怎么调。这些内容不追求文笔只求准确。如果哪一步实在写不清宁可先标[TODO]也不能假装它不存在。3.4 用 MR 做交叉审阅逼出高质量结论单人使用 OpenResearch最重要的动作是 commit团队使用最重要的动作是 merge request。我在团队内定了一条规则任何卡片从draft状态变为accepted之前必须经过至少一个其他成员的 review。review 不是走过场而是回答四个问题来源是否可靠结论是否被证据支撑有没有忽略明显反例大模型生成内容是否被正确标记这个过程刚开始阻力很大大家都觉得“太慢了”。但跑了一个月之后普遍反映后续写报告省了很多时间。因为 MR 里的评论其实是在帮未来的读者排雷每次讨论都沉淀成仓库里的 commit 记录。如果哪一天结论被推翻了通过git blame能快速定位到当时是哪条证据出了问题比在群里翻聊天记录高效几百倍。审阅并不只针对大的主题报告每一张卡片都可以被评论。我自己的习惯是哪怕只是改一个字段的描述也会开一个带前缀card-review:的 MR。这样虽然 MR 数量会多一些但每个改动都是独立可追溯的。团队新人刚开始不习惯后来他们发现通过看历史 MR 就能快速了解一个专题的来龙去脉反而大大减少了“新人需要老人讲背景”的负担。4. 实操过程从零跑通一个课题4.1 初始化仓库20 分钟搭好骨架如果你现在想试试 OpenResearch不需要一开始就全套照搬。我建议从最小可用的骨架开始。命令行大概是这样的mkdir my-research cd my-research git init mkdir -p notes literature experiments reports scripts templates cp -r ~/.openresearch/templates/* templates/ git add . git commit -m chore: init OpenResearch skeleton这里templates/里放的是我维护的一套空白模板。你可以先用最简单的一个卡片模板一个实验记录模板一个 README。不要贪多。同时配置一个 pre-commit hook每次提交前自动运行引用检查和 Markdown 格式检查。我在团队里用pre-commit框架配置好之后大家不用记太多命令。初始化完成之后可以把 README 里面的内容改成你自己的研究主题列表同时约定 commit 规范。这一步虽然看起来是“仪式感”但它是后来多人协作时减少摩擦的前提。团队里每个人对“完成研究”的理解可能不一样但如果 git log 里都是统一的格式至少能让协作的起点一致。4.2 录入第一批资料从 PDF 到卡片我拿一篇最近看的论文举例。先用 Zotero 抓取元数据导出到literature/zotero.bib得到引用 key 比如yang2024retrieval。然后在notes/llm-rag/下新建文件2025-01-08-yang2024retrieval.md填入模板。关键不是复制摘要而是要写清楚这篇论文在 OpenResearch 的研究地图里处在什么位置。比如它是“主流 RAG 方法对比”的一部分还是“重排算法演进”的起点。写完卡片后如果论文里有一段特别重要的图表我会把图表的截图裁剪后放到literature/attachments/下同时在卡片里用相对路径引用。注意这里只放有授权或开放的图表不放 PDF 全文避免版权和仓库体积问题。这条规则在团队里是写进规范的第一优先级。太多人把录入理解为“把 PDF 存起来”但这恰恰是 OpenResearch 最不关心的。PDF 是别人的资料卡片才是你自己的理解。所以我的建议是录入时一定要把“我为什么读它”和“它对我有什么价值”写清楚。哪怕写得很主观也没关系主观判断总比没有判断好。而且这种主观判断恰恰是未来写报告时最能体现思考深度的内容。4.3 汇总阶段报告让结论带着证据链走收集了十几张卡片之后就可以尝试生成一份阶段报告。我的做法不是手写而是用 Python 脚本把所有相关卡片渲染成一个 Markdown 文档。脚本不算复杂核心只是读取 YAML front matter 和正文再按照主题顺序输出。但关键的一点是渲染出来的报告每个结论后面都会带上支撑卡片和未解决问题列表而不是只有一句话。举个例子如果报告里写到“在中等规模语料上基于向量的召回优于关键词召回”那么这句话旁边一定会有[evidence: yang2024retrieval, liu2023benchmark]这样的标注。如果有哪些地方还没有证据也会明确标注[open-question]。这样看报告的人不用再翻原始资料也能知道哪些结论是扎实的哪些还悬空。AI 在生成初稿时也能帮上忙但我会明确要求它只基于notes/目录里的既有卡片来写不允许自己发明新引用。生成之后我把内容放进reports/目录开一个 MR 让同事 review。这个过程其实就是在做“人机协作”的示范AI 负责把零散卡片组织成通顺的文字人负责审查每个观点是否真的有据可依。只要分工明确效率和质量都能兼顾。4.4 多人协作分支策略和冲突规避团队协作时我建议每个成员维护自己的分支并按主题创建 MR。大家尽量只修改自己负责的子目录比如小张负责notes/llm-rag/小李负责notes/vector-db/这样可以避免绝大多数冲突。万一真的冲突了也不要慌因为卡片都是小文件冲突范围通常很小手工合并或者用 VS Code 的冲突编辑器都能解决。这里有一个从实战中得到的教训绝对不要把团队的研究笔记放在一个巨大的 md 文件里。之前有同事习惯把一周的调研都写在同一篇文档里结果 MR 一开几乎每次都有冲突。后来我强行规定一天最多一个文件一个主题只对应一个目录。粒度细一点协作顺滑度会提升一个量级。除了分支策略权限设计也不能忽略。我会把main分支设为 protected不允许任何人直接 push所有变更必须走 MR。这样每个改动都会被记录在案即使某次 MR 存在问题也能很容易回滚。远程仓库我用的是自建 GitLab它对 MR 和 code review 的支持比较完整也方便在内部跑一些自动化检查。如果团队很小用 GitHub 的免费仓库也完全够用。5. 常见问题与避坑指南5.1 文件冲突和进度丢失怎么办OpenResearch 最常遇到的问题就是文件冲突。除了多人协作个人在手机和电脑之间同步时也可能因为忘记 pull 而覆盖内容。我的建议是三步频繁 commit小粒度文件同步前先git status看有没有未合并的分支。另外如果某个卡片还在修改中可以把它标记为wip这样其他人看到后会自动规避。我还遇到过一次比较大的事故有一次在误操作下执行了git reset --hard丢掉了两天的工作。后来我把远程仓库放到 GitLab并开启了 push 保护同时本地写了一个备份脚本每天凌晨自动把仓库打包上传到对象存储。这个习惯现在看起来有点笨但确实救过我一次。这里可以分享一个判断文件粒度是否合适的标准如果你每次 commit 之后经常发现要连同改十几个文件才能表达一个完整意图说明文件切得太碎了但如果你经常在一个文件里同时改了文献笔记、实验结论和待办事项说明切得太粗。我一般的原则是一个文件只服务于一个“信息实体”。比如一篇文献的卡片一个实验的运行记录一个主题的阶段性汇总。这样冲突概率和回溯难度都会保持在低位。5.2 大模型幻觉怎么防前文提过引用检查脚本这是防幻觉的第一道防线。除此之外我还有两个土办法。第一让 AI 生成内容时必须给出它参考的key没有明确引用的段落不允许直接放结论区。第二每周做一次“边界抽查”随机挑五张卡片对照原始文献看是否有过度解读。这两个办法不依赖某个更聪明的模型但非常有效。如果你用的是云端 API还要注意 prompt 里不要上传未公开的数据。我一般会在 prompt 尾部加一句“如果某个说法没有出处请直接说不知道不要推测”。虽然不能百分百避免幻觉但可以明显降低编造概率。我还发现一个细节AI 在生成摘要时如果原文本身很模糊模型经常会“脑补”得更具体甚至补充出原文没有的数字。这个现象在长文档里尤其明显。后来我在 prompt 里明确要求“只能压缩信息不能新增信息原文没有的细节一概不写”效果好了很多。但这仍然不能完全替代人工校验所以我坚持所有 AI 产出都要走 MR 审阅流程。5.3 版权、隐私和数据安全开放研究不等于什么都能公开。在团队内部我们明确了几条红线不把受版权保护的 PDF 全文传进仓库不把包含用户隐私的数据提交到远端不把未发表的核心实验细节放进 AI 辅助模块。这些红线写进 README 最显眼的位置新成员入职第一课就是读这个。如果确实需要保存敏感数据我建议用git-crypt或age对文件和字段做加密而不是把整个仓库放到私有云了事。毕竟仓库会被克隆、会被同步万一某个环节泄露加密至少能多一层保护。这个设计在 OpenResearch 里是可选的但一旦涉及真实业务数据千万别省。另外引用外部资料时要注意许可协议。很多论文虽然可以在网上免费下载但不代表你可以把 PDF 重新分发。OpenResearch 的做法是仓库里只保留元数据和自己的笔记需要看全文时通过合法渠道获取。这样既规避了版权风险也让仓库本身保持轻量。毕竟研究仓库的价值在于“理解和判断”不在于“存储原文”。5.4 别让流程绑架研究最后说一个更宏观的坑。OpenResearch 刚上线的时候我一度陷入了工具洁癖花了大量时间优化脚本和模板却忽略了真正要做的研究。后来我把原则改成了“最小必要流程”能手工完成且频率低的事情就不写脚本能十分钟录入完成的卡片不要求加一堆花哨标签能直接写结论的地方不强迫自己用复杂模板。维护成本一定要控制在每天十分钟以内。如果某一天你觉得维护流程比做研究更累那一定是流程设计出了问题。OpenResearch 的价值在于让研究过程变清晰而不是制造新的负担。我个人现在的习惯是每两周花十五分钟清理过期卡片其余时间几乎不需要额外维护。有了这个原则之后我才真正把 OpenResearch 当成了研究的一部分而不是一个额外工具。每写下一张卡片、每提交一个 commit我都在为未来的自己留下路标。工具会过时模板会调整但“每个结论都要有证据”的习惯会一直留在我身上。