LangChain实战-文档问答系统
当模型开始遗忘世界,我们用文档喂养它。当知识不再写在脑海,而是沉入向量空间,你写的,不再是代码,而是一条通往“理解”的路径。
什么是文档问答系统?
让模型基于你的私有数据回答问题,而不是“胡说八道”。
核心架构(RAG):
用户问题 ↓向量检索(找到相关文档) ↓拼接上下文 ↓LLM生成答案
┌──────────────┐ │ Web 前端 │ │ Chat + 上传 │ └──────┬───────┘ ↓ ┌──────────────┐ │ FastAPI │ │ 接口层 │ └──────┬───────┘ ↓ ┌────────────────────────────┐ │ RAG核心层 │ │ │ │ Loader → Splitter → Embedding │ │ ↓ │ │ Vector DB(Milvus) │ │ ↓ │ │ Retriever │ │ ↓ │ │ Qwen │ └────────────────────────────┘
整体流程拆解
我们今天做的,不是调用 API,而是完整构建:
文档处理与加载(Document Loader)
索引构建(Embedding + Vector Store)
检索与问答(Retriever + QA Chain)
文档加载
文档,是一切的起点。
from langchain.document_loaders import TextLoaderloader = TextLoader("data.txt", encoding="utf-8")docs = loader.load()
本质理解
这里做了两件事:
-
• 把文本 → LangChain Document对象 -
• 为后续处理统一格式
你可以加载:
txt / pdf / docx / html / 网页 / 数据库
文本切分
为什么要切?
因为模型吃不下整本书。
from langchain.text_splitter import RecursiveCharacterTextSplittersplitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50)split_docs = splitter.split_documents(docs)
设计哲学
-
• chunk_size:信息密度 -
• overlap:上下文连续性
切分,不是切文本,是在切“语义”。
构建向量索引
让文本变成“可以被搜索的空间”。
from langchain.embeddings import HuggingFaceEmbeddingsembedding = HuggingFaceEmbeddings( model_name="BAAI/bge-small-zh")
Embedding 本质
它不是翻译,而是:
把“意义”压缩成向量坐标
向量数据库
from langchain.vectorstores import FAISSdb = FAISS.from_documents(split_docs, embedding)
本质理解
你不是在存文本,而是在构建:
一个“语义空间”
问题进来 → 找最近的点 → 返回相关文档
检索 + 问答
from langchain.chains import RetrievalQAfrom langchain.llms import OpenAIqa = RetrievalQA.from_chain_type( llm=OpenAI(), retriever=db.as_retriever())
真正发生的事情
用户问:LangChain是什么? ↓Embedding → 向量 ↓相似度搜索 ↓找出最相关3段文本 ↓拼接 Prompt ↓LLM回答
完整最小可运行代码
from langchain.document_loaders import TextLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.vectorstores import FAISSfrom langchain.embeddings import HuggingFaceEmbeddingsfrom langchain.chains import RetrievalQAfrom langchain.llms import OpenAI# 1. 加载文档loader = TextLoader("data.txt", encoding="utf-8")docs = loader.load()# 2. 切分splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)split_docs = splitter.split_documents(docs)# 3. 向量化embedding = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh")# 4. 构建向量库db = FAISS.from_documents(split_docs, embedding)# 5. 构建问答系统qa = RetrievalQA.from_chain_type( llm=OpenAI(), retriever=db.as_retriever())# 6. 运行whileTrue: q = input("问:")print(qa.run(q))
项目下载
我已经帮你打包好一个最小工程
https://github.com/wujianyouhun/demo-for-blog/tree/master/python/LangChain/geo_rag_agent

夜雨聆风