
最近越来越多朋友私信问我,怎么用 LangChain 搭一个能读自己文档、还能对接模型回答问题的机器人?
📌 不用开服务器、也不用接 OpenAI 付费 API,我们可以用 FastAPI + LangChain + 本地模型,部署一个 属于自己的知识问答助手!
而且,我还整理了这类项目中最容易踩坑的报错合集,比如:
ImportError: cannot import name ... from langchainAttributeError: 'NoneType' object has no attribute 'run'这篇文章,就从 0 到 1 带你搭一个属于自己的私有智能助手系统,还能优雅处理 LangChain 那些常见的“更新地狱”问题🔥
LangChain 可以让大模型调用外部工具、结合数据库、处理文档、读网页…… FastAPI 是轻量级 Web 框架,用它做 API 接口,完美适配 LangChain 项目 🧩
技术组件 | 用途 | 优势 |
|---|---|---|
FastAPI | 提供 RESTful 接口 | 快速开发、异步支持、自动文档生成 |
LangChain | 构建 LLM 应用框架 | 支持链式调用、丰富模块、文档解析 |
FAISS / Chroma | 文档向量检索 | 本地私有知识库搭建神器 🔍 |
llm-chatbot/
├── app/
│ ├── main.py # FastAPI 主应用
│ └── qa_chain.py # LangChain 问答逻辑
├── docs/ # 私有文档目录
├── requirements.txtpip install fastapi uvicorn langchain openai chromadb小心💥:LangChain 更新频率非常高,请务必锁版本!
langchain==0.1.14
chromadb==0.4.24我们在 qa_chain.py 中封装核心功能:文档加载 → 向量存储 → 检索问答 💬
import os;
from langchain.document_loaders import DirectoryLoader;
from langchain.embeddings import OpenAIEmbeddings;
from langchain.vectorstores import Chroma;
loader = new DirectoryLoader("docs", "pdf");
documents = loader.load();
db = new Chroma(documents, new OpenAIEmbeddings());⚠️ 小心:Chroma 的向量存储路径默认写在
.chromadb文件夹中,不可删除!
from langchain.chains import RetrievalQA;
from langchain.chat_models import ChatOpenAI;
retriever = db.asRetriever();
llm = new ChatOpenAI("gpt-3.5-turbo");
qa_chain = new RetrievalQA(llm, retriever);在 main.py 中创建异步接口,接收问题,返回答案 📡
from fastapi import FastAPI, Request;
from qa_chain import qa_chain;
app = new FastAPI();
@app.post("/ask")
async def ask_question(request: Request):
json = await request.json();
query = json["question"];
answer = qa_chain.run(query);
return { "answer": answer };运行服务:
uvicorn app.main:app --reloadImportError: cannot import name 'XYZ' from 'langchain'原因: LangChain 模块频繁调整路径 🚧 解决办法:
dir(langchain) 调试模块结构AttributeError: 'NoneType' object has no attribute 'run'原因: QA链未初始化或加载失败 💥 解决办法:
assert qa_chain is not None : "QA Chain 初始化失败";from fastapi.security import APIKeyHeader;
api_key_header = new APIKeyHeader("X-API-Key");
@app.post("/ask")
async def ask(q: Request, key: str = Depends(api_key_header)):
if key != "your-secret-key":
raise HTTPException(403, "权限不足");使用 FastAPI UploadFile,支持前端上传 PDF、TXT、Markdown 并实时入库 ✨
🎯 至此,我们就完成了一个拥有如下能力的本地问答机器人:
它可以应用在企业知识库、教程助手、简历问答、产品文档 Q&A 等多个场景中!💼