从零搭建本地知识库问答系统
1. 为什么我建议你从本地知识库开始这两年大模型火得不行但很多人上手 LangChain 时第一反应都是去调各种在线 API。说实话这条路对新手并不友好——既要处理网络问题又要担心调用额度折腾半天可能连一个完整的流程都没跑通。我自己的经验是先搭一个本地知识库问答系统反而更容易理解 LangChain 的核心逻辑。原因很简单本地跑数据可控报错也直观改起来方便。等你把整套链路摸熟了再去接线上模型基本就是换一个模型名的事。这篇文章我会用最直白的方式带你从零开始用 Python 搭一个能回答你本地文档问题的系统。代码不多但每一步我都会解释清楚在干什么。2. 准备工作装什么、怎么装开始之前先把环境准备好。我用的是 Python 3.10理论上 3.9 以上都行。你需要装下面这几个库pip install langchain langchain-community chromadb sentence-transformers这里简单说一下每个库的用途langchain核心框架负责把各个组件串起来。langchain-community社区贡献的集成比如文档加载器。chromadb本地向量数据库用来存文档的向量表示。sentence-transformers本地 embedding 模型把文字变成向量。装完之后建议先跑一句python -c import langchain确认没报错再继续往下走。3. 核心思路三步走在写代码之前我想先让你脑子里有个整体框架。本地知识库问答系统本质上就三步加载文档把你本地的 txt、pdf、markdown 文件读进来。切分并向量化文档太长直接丢给模型肯定不行所以要切成小块每块转成向量存进向量库。检索并回答用户提问时先从向量库里找出最相关的几块内容再把这些内容连同问题一起交给大模型生成答案。这三步对应 LangChain 里的三个核心组件Loader、VectorStore和Chain。理解了这条线后面看代码就不会晕。4. 动手写代码加载文档先写第一步加载本地文档。这里我用的是 txt 文件你也可以换成 PDF 或 Word只要换对应的 Loader 就行。from langchain_community.document_loaders import TextLoader loader TextLoader(knowledge_base.txt, encodingutf-8) documents loader.load() print(f加载了 {len(documents)} 个文档)这里有个小坑要提醒你文件编码一定要指定 utf-8不然中文文档很容易报编码错误。我第一次跑的时候就栽在这上面折腾了十分钟才发现是编码问题。5. 切分文档为什么不能整篇丢进去文档加载进来之后下一步是切分。你可能觉得奇怪为什么不能直接把整篇文档丢给模型原因有两个大模型的上下文窗口有限文档太长会超出限制。检索的时候小块内容比整篇文档更容易命中用户的问题。LangChain 里最常用的切分工具是RecursiveCharacterTextSplitter它会尽量按段落、句子来切避免把一句话拦腰截断。from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ] ) chunks splitter.split_documents(documents) print(f切分成了 {len(chunks)} 个块)这里的chunk_size是每块的最大字符数chunk_overlap是块与块之间的重叠长度。重叠的作用是防止切分时把关键信息正好切没。这两个参数没有绝对标准我建议你先按 500 和 50 跑一遍再根据效果调整。6. 向量化并存入本地库切分完之后要把每一块文字转成向量存进 Chroma。这里我用的是sentence-transformers提供的本地模型好处是不用联网数据也不会外传。from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma embeddings HuggingFaceEmbeddings(model_nameparaphrase-multilingual-MiniLM-L12-v2) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) print(向量库已保存到 ./chroma_db)这个模型是支持中文的体积也不大第一次运行时会自动下载之后就能离线使用了。如果你机器配置不错也可以换更大的模型效果会更好但速度会慢一些。7. 搭建问答链路最后一步把检索和回答串起来。这里我用的是 LangChain 的RetrievalQA它会自动完成「检索相关文档块 → 拼进提示词 → 调用模型生成答案」这一整套流程。from langchain.chains import RetrievalQA from langchain_community.llms import Ollama 本地模型用 Ollama 跑 Llama 3 llm Ollama(modelllama3, base_urlhttp://localhost:11434) qa_chain RetrievalQA.from_chain_type( llmllm, retrievervectorstore.as_retriever(search_kwargs{k: 3}), return_source_documentsTrue ) question 这份文档里提到了哪些关键概念 result qa_chain.invoke({query: question}) print(回答, result[result])这里我用了 Ollama 来跑本地大模型如果你还没装可以去 Ollama 官网下载然后执行ollama pull llama3拉取模型。当然你也可以换成 OpenAI 的 API只要把llm换成对应的对象就行其他代码不用动。跑通之后你会看到模型基于你本地文档给出的回答。这时候可以多试几个问题感受一下检索效果。如果回答不理想优先调整chunk_size和检索的k值。8. 几个我踩过的坑最后分享几个实战中容易遇到的问题帮你少走弯路编码问题读文件一定要指定encodingutf-8否则中文必报错。切分参数chunk_size太小上下文不完整太大检索精度下降。建议从 500 开始调。首次运行慢embedding 模型第一次要下载耐心等一会儿之后就快了。Ollama 没启动如果报连接错误先确认ollama serve在跑。这套流程跑通之后你可以试着把文档换成自己的技术手册、读书笔记甚至公司内部资料一个能用的本地知识库问答系统就搭好了。后面想接线上模型、加 Web 界面都是在这个基础上扩展的事。