
先说结论这个粗糙版AI知识库我用了大概三周把过去两年攒下的工作笔记、技术文档、碎片灵感全塞了进去现在它已经能在我写方案、查旧资料、甚至复盘项目的时候帮我节省大量时间。虽然不是企业级那种漂亮的知识中台但作为一个纯个人知识库它完全满足了我的需求而且整个搭建过程只用了一个周末。如果你也攒了一堆Markdown笔记、PDF、网页剪藏每次找东西都翻得头疼想用AI把它们变成可对话的侧大脑那这篇文章应该能给你一套立刻能抄的作业。我尽量不讲虚的只讲我这个粗糙版是怎么从零搭起来的踩了哪些坑以及为什么我觉得对普通人来说粗糙反而比完美更合适。1. 为什么是粗糙版我们到底需要什么样的AI知识库1.1 从一次找资料的崩溃开始起因是上个月要写一份关于RAG应用方案的复盘报告需要在十几个分散的笔记文件里找之前记录的一个关键参数。我把Obsidian、OneNote、本地文件夹全翻了一遍最后打开一个叫临时记录2023.docx的文件发现里面躺着一句参考qwen embedding 1024维效果还行。那一刻真的很崩溃——我明明写了但和没写一样因为搜不到。后来我试过用Windows自带的搜索、Everything、甚至是Obsidian的全文搜索都不够用。因为很多内容我记得大概意思但记不住关键词比如我想找关于数据库字段设计的一个坑我脑子里没有精确的词搜索框无能为力。那段时间正好在折腾AI手边有大模型API就想搞一个能理解语义的检索工具。说白了就是把那些文本扔进去以后可以用自然语言问我在数据库字段设计上踩过什么坑然后它把相关笔记找出来给我看。1.2 粗糙版的三个原则够用、可维护、能落地我见过很多知识库项目上来就是分布式矢量数据库、Kubernetes集群、Dify流水线全套折腾两周还没开始往里放第一篇文章。这不适合个人。我的粗糙版定了三条军规够用不追求实时大规模索引几百个文件、几十万字级别的量普通脚本就能处理。可维护所有内容还是普通文件随时可以手工编辑AI层只是叠加在文件之上的一个语义搜索引擎。能落地用最少的组件一个Python脚本、一个向量数据库、一个API跑通后能真正长期用而不是Demo完就吃灰。这三个原则贯穿了我后面所有的选择。所以我的知识库长得很朴素一个文件夹放所有原始文档一个Python脚本负责索引和启动问答再无其他。2. 选型思路不装Dify、不搞K8s用文件加脚本搭出RAG2.1 为什么我没有选All-in-One平台其实一开始我也看过Dify、FastGPT这类开源知识库平台界面漂亮还带工作流编排看起来挺香。但琢磨了两天后我放弃了原因有三太重Dify要起Docker、挂数据库、配置模型供应商一套下来我的小服务器内存都快爆了而我实际要放到知识库里的内容并不算多。数据绑架知识库的价值在数据如果我把所有内容都倒进某个平台以后想换工具就得整体迁移很麻烦。而如果我坚持用文件即数据无论AI工具怎么换我的知识资产是永久的。心智负担这类平台有太多概念数据集、分段模式、召回测试、工作流对我来说是过度设计。我只想要一个函数ask_knowledge_base(问题) - 答案。所以绕了一圈之后我还是回到了最朴素的RAG结构文档 → 切片 → 向量化 → 向量数据库 → 查询时检索 → 把命中片段塞给大模型 → 输出带引用的回答。这套东西在概念上不难难的是每一环的参数和细节而这正好是可以手工控制的地方。2.2 最终方案Markdown文件 Chroma向量库 大模型API我的具体选型是这样的存储层一个knowledge_base/目录里面全部是Markdown文件可以是笔记、文档、甚至网页剪藏后转成的文本。向量数据库Chroma。这是个轻量级向量数据库支持Python直接操作数据落盘可以存在本地目录不依赖独立服务对我这种个人使用场景非常合适。Embedding模型文本转向量用的国内大模型平台的通用文本向量API具体名称不写了各家都有类似产品一次可以批量处理几百条文本返回的向量维度通常是1024等具体按服务商文档来。大模型API用的也是国内大模型的对话接口负责最后的组织答案环节。有人会问为什么不直接用本地模型比如用Ollama跑Embedding和对话我的回答是个人电脑跑大模型输出质量还不稳定尤其是中文的理解能力和商业API差距明显另外API按量计费个人查询量很小一个月几块钱完全能接受。粗糙版的第一原则是够用而不是免费。2.3 目录结构与命名规范知识库的数据库schema这个细节很多人都忽略但我认为是知识库能否长期用得下去的命根子。我把knowledge_base/按主题分了几类目录knowledge_base/ ├── work/ # 工作相关项目复盘、会议结论、方案草稿 ├── tech/ # 技术代码笔记、架构设计、工具用法 ├── life/ # 生活健康、读书笔记、杂项经验 └── temp/ # 临时还没归类的剪藏每个文件命名尽量用主题_描述_日期.md的格式例如数据库字段设计复盘_整型陷阱_202403.md。这样做不是为了给AI看AI靠内容检索不靠文件名而是为了给自己看——万一哪天AI方案挂了我还能靠目录结构手动找文件。粗糙不等于放弃管理轻量的规范反而能省掉很多麻烦。3. 搭建过程从零到能问答的完整步骤3.1 环境准备Python和需要装的东西我的电脑是Windows直接用Python 3.10。先建虚拟环境避免依赖污染python -m venv kbenv kbenv\Scripts\activate # Linux/macOS 用 source kbenv/bin/activate pip install chromadbChroma是这次的主要依赖。另外需要一个能兼容的HTTP客户端来调用API我习惯用requests也可以直接上openai库改造一下因为很多国内API兼容OpenAI格式。不知道版本有没有坑我当时直接pip安装的最新版如果你遇到某些函数参数变化建议看官方文档如果不折腾版本固定装chromadb0.4.x也行核心用法基本一致。3.2 文档切块别小看这一步它决定了回答质量这一步是RAG灵魂一开始我根本没在意直接把整篇文档扔给向量模型结果检索效果奇差。后来才明白向量模型一次处理文本有限定长度而且一篇长文做成一个向量查询时和提问相关的细节早就被稀释了。我采用的切块策略是按标题和段落切先按行读取Markdown遇到#、##这种标题就开启新块每块内再按段落合并。这样能尽量保证每个块是一个语义完整的单元。控制块大小单个文本块控制在200~500字上下具体根据文档内容调整。太短缺上下文太长又稀释重点。增加overlap相邻块之间重叠一两句话50字左右避免切断了本来连续的语义。比如某一段被切成两块后半块的开头重复一下前半块的结尾。保留元信息每一块都记录来源文件路径和标题生成一个文档对象存到Chroma的metadata里。这样回答时能定位到具体文件。切块这步没有标准答案完全取决于你的文档风格。如果你大部分是短小的碎片笔记不切也行如果是长篇报告那就必须切。我最后写了一个不到一百行的chunk_text.py来统一处理。3.3 向量化与存储把文本变成可检索的坐标切好的块可以直接送向量模型。注意这里的向量化其实就是把一个文本字符串变成一串数字坐标使得语义相近的文本坐标也相近。我选择每批次最多100条然后调用APIimport requests def get_embeddings(texts): # 这里替换为自己的服务商API接口 resp requests.post( https://api.example.com/v1/embeddings, headers{Authorization: Bearer your-key}, json{model: text-embedding-model, input: texts} ) resp.raise_for_status() return resp.json()[data] # 每项是 {embedding: [...]}拿到向量后存进Chromaimport chromadb client chromadb.PersistentClient(path./vector_store) collection client.get_or_create_collection( my_kb, metadata{hnsw:space: cosine} ) # ids需要用字符串集合这里我用 文件路径#块序号 作为主键 collection.add( idsids, embeddingsembeddings, documentstext_chunks, metadatasmetas )重点讲两个选择距离函数用了cosine。因为切出来的块长度不一欧氏距离会被文本长度干扰cosine只关心方向对检索更合适。Chroma的默认也是cosine的参数开法。数据落本地目录。PersistentClient会生成一个vector_store文件夹里面是SQLite存储这意味着索引完一次以后可以直接复用不用每次重新算向量。3.4 问答接口让知识库回答问题时系统是这么跑的查询流程是这样的你输入一个问题 → 先把问题转成一个向量 → 去Chroma里找出最相似的N个块一般是5-10个→ 把这几个块的文本连同问题一起发给大模型 → 模型基于这些上下文组织成一段回答并标记来源。这一步是真正有AI感的地方也是整个系统最核心的价值点。用代码表示def ask_kb(question, n_results5): emb get_embeddings([question])[0][embedding] hits collection.query( query_embeddings[emb], n_resultsn_results ) context \n\n.join(hits[documents][0]) sources hits[metadatas][0] prompt f请根据下面的资料回答问题。如果资料不足以回答直接说不知道。 资料内容 --- {context} --- 问题{question} 请用简洁的中文回答并在最后列出参考来源文件名。 answer call_llm(prompt) return answer, sources这样出来的答案就不是大模型凭空瞎编的而是有你的笔记内容作为依据。这个吃自己的数据的过程就是Retrieval-Augmented GenerationRAG虽然我这套很粗糙但完整体验了把大模型变成个人知识库问答助手的链路。4. 实测效果它真的比百度好用吗4.1 三类问题的表现事实查询、经验检索、闲聊式提问我把知识库里一些典型问题拿来测结果分成三类事实查询比如我在数据库设计上记录过哪些坑这种只需要召回片段然后列出来的效果几乎是最好的。它能准确找到相关块的标题和内容再让大模型提炼一下得出的答案基本等于把笔记重读了一遍。经验检索比如Refile类型导致的性能问题原因是什么这种问题涉及模糊语义关键词可能都不完全重合但向量检索能根据性能这种语义关系召回相关内容。效果也不错只是偶尔会夹带不相关的内容需要我自己扫一眼过滤。闲聊式提问比如我最近做项目好累怎么办这种和知识库内容毫无关系的问题系统可能会从生活笔记里召回一些关于休息建议的块然后给出一个沾边但不痛不痒的回答。我后来在代码里加了一个判断如果召回的相似度分数低于某个阈值就直接回答知识库中没有相关内容请换个问法。这能避免不少尴尬。4.2 翻车现场检索失败和幻觉问题不可能全是好消息。实际使用中最常见两类翻车检索召回错块比如问TLS握手为什么慢结果系统召回的是握手礼仪的生活笔记。问题在于切块后的向量没有携带文档类型标签跨领域歧义没法解决。我的解决办法是在元信息里加上目录级别查询时先按tech目录过滤再按相似度排序。这比让模型自己判断要靠谱得多。幻觉这是RAG最大的坑。即使上下文里有相关内容大模型有时也会把不同笔记的内容缝合到一起生成看似合理但其实不存在的细节。比如它会把A笔记的字段类型写进B笔记的表格里。我的应对方式是prompt里反复强调如果原文没有提到的细节不要自己补充同时要求回答末尾附上参考来源这样我至少可以人工验证。老实说目前的粗糙版并不能完全杜绝幻觉只能最大限度降低。4.3 粗糙版的性能杂谈多慢、多菜、多省心速度方面因为向量检索是本地完成的很快基本毫秒级。主要耗时在网络请求一次问答通常3~6秒取决于大模型响应速度。同比直接问机器人多了检索环节但答案更有料这个延迟完全可以接受。菜的地方也有对扫描版PDF完全无能为力因为那是图像得先OCR我懒得搞直接跳过把PDF里的关键段落手工复制成文本。另外老文档格式混乱比如带表格的excel切块时容易把表格内容切碎召回后语义不通。我自己优先把重要内容转成Markdown再入知识库其他格式不强求。省心是真的省心索引一次后就基本不用再管新增文档时跑一下脚本增量索引三分钟搞定。我现在已经连续用了三周没有任何系统崩溃或数据损坏的情况。Chroma这种本地数据库对个人单机场景来说非常稳定。5. 这次踩过的坑给想复制方案的人提个醒5.1 编码与乱码问题第一批文档入知识库我直接把Word复制成txt导入结果查询时总出现乱码尤其是中文引号和破折号。原因是有些文件是GBK编码而Python默认按UTF-8读取导致解析出的文本一堆替换符。后来我在读取文件时做了编码检测with open(path, r, encodingutf-8) as f: text f.read() # 如果读到异常降级为 gb2312 尝试对于已经乱掉的文件没有好办法得重新导出成UTF-8。所以建议所有源文件统一用Markdown格式Markdown本质是纯文本编码清晰不依赖任何软件这是知识库的护城河。5.2 切块参数怎么调我刚说的200~500字、overlap 50这些不是拍脑袋是从测试中对比出来的。我当时做了个小实验同一个文档分别用100、200、500、1000字的块去索引然后拿10个问题去查询看召回质量。结论是碎片化笔记切200字左右长文章切500字左右最均衡。切太少检索容易丢失上下文切太多向量相似度会被整体主题带偏细节丢失。overlap我只是顺带设置了50字效果没法精确量化但至少没有坏处。5.3 API成本控制与缓存大模型的问答API是按token计费的embedding虽然便宜但索引整库时量一大也是一笔小开销。我的节省方法是只索引新增文件用文件修改时间作为标记如果文件没变化就不重新算向量。这样日常新增几条笔记成本几乎为零。回答时限制上下文长度不要一股脑把召回的块全塞给模型我设置了只取召回Top5块并且限制每个块不超过500字这样上下文总量控制在3000字内单次问答的花费可以忽略不计。问题缓存把相同问题重复查时使用历史结果。我还没做这点但如果你要频繁用可以考虑存一个question-answer映射到SQLite里既省成本又加速。5.4 隐私与安全什么内容别放进去因为是个人知识库很多人会想把所有东西都塞进去包括身份证号、银行卡、私密日记。这里要泼冷水哪怕用的是本地向量库最终的答案还是要送给大模型API去生成所以敏感信息等于变相发送给了第三方服务商。我在代码里特意加了一道隐私拦截检测到包含身份证号、手机号、银行账号等规律特征的段落时不采集这个块查询时如果问题涉及敏感词直接拒绝回答。粗糙版可以菜但底线不能丢。另外如果你真的有大段隐私内容又想让AI检索可以考虑用本地推理服务比如Ollama但效果会弱一些。权衡下我还是选择API方案。6. 从粗糙到顺手下一步我打算怎么升级6.1 用Obsidian做日常入口我试过热门的Obsidian知识库搭建方案确实好看插件也多。但对我这种粗糙版用户来说Obsidian可以当API知识库的前端笔记本来的条目落盘成Markdown同时触发我的Python脚本去增量更新Chroma索引。这样我只需要在Obsidian里写笔记AI知识库自动同步不用每次跑命令行。做法也不复杂Obsidian有类似保存时执行命令的社区插件我没折腾既然能用就行。6.2 让知识库参与写作和复盘下一步我想做一个小工具写周报时自动从知识库里找出这周写过的笔记片段按照工作、学习、问题三类生成总结周报草稿。再往后等沉淀几个月的数据可以做一个项目复盘助手——输入项目名让知识库取出所有相关笔记自动梳理时间线、关键决策和踩过的坑导出成一份复盘报告。这应该会比我手工翻笔记高效得多。6.3 粗糙版的极限与升级信号这个粗糙版什么时候需要升级我的判断标准有三个检索越来越慢比如数据量超过5万条块SQLite和内存可能扛不住那就可以考虑换专业的向量数据库或者加一层缓存。需要多人协作/多端访问那就必须把服务部署到云端可能真得上Dify这类平台了。对准确率要求变高比如要拿它做企业技术客服那就得做rerank对召回结果进行精排、召回策略、权限控制等这已经完全超出个人知识库范畴了。在那之前我这个粗糙版已经足够应付日常使用。知识库的核心从来不是工具多先进而是你有没有值得放进去的内容以及你愿不愿意持续往里写。如果你也经常感觉知识散落却找不到可以从今天起花一个小时把最近的一个月笔记整理进一个干净文件夹然后切块、索引、跑通问答。粗糙不可怕可怕的是永远停留在我应该搞一个知识库的念头里。先跑起来后面慢慢细化就好。