Appearance
第十二阶段:Docker 安装与 FastAPI 问答接口
进入项目 4:分布式 RAG 服务。第一步:把项目 1 的知识库问答做成 HTTP 接口。
一、为什么要做成接口
之前的问答脚本只能在终端里运行,只有你自己能用。做成接口以后,任何程序都能通过 HTTP 请求来调用它:网页、手机 App、其他服务,用什么语言写的都可以。
这也是后面装进 Docker、做成分布式服务的前提:先把功能变成一个服务,才谈得上打包、扩容、排队。
二、安装 Docker Desktop
下一阶段要用 Docker,这一阶段先装好:
- 从官网下载 Docker Desktop for Windows,安装时选 Per-user installation,后端用 WSL 2;
- 启动后,窗口左下角显示 Engine running,说明引擎已经在运行;
- 在终端里验证:
bash
docker run hello-world看到 Hello from Docker! 就说明装好了。
三、安装 FastAPI
bash
pip install fastapi uvicornFastAPI 是写接口的框架,uvicorn 是运行接口的服务器。
四、代码 12_api.py
提示
model_name里的“这里填你的 Embedding 模型名”是占位文字。LM Studio 只加载了一个 Embedding 模型时,照这样写也能运行;想写规范一点,可以换成 LM Studio 里显示的模型名。
python
import os
from dotenv import load_dotenv
from fastapi import FastAPI
from pydantic import BaseModel
from openai import OpenAI
from llama_index.core import StorageContext, load_index_from_storage, Settings
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
load_dotenv()
# 启动时只加载一次索引(复用项目 1 的 kb_storage),不要每次请求都加载
Settings.embed_model = OpenAILikeEmbedding(
model_name="这里填你的 Embedding 模型名",
api_base="http://localhost:1234/v1", api_key="<redacted>")
index = load_index_from_storage(StorageContext.from_defaults(persist_dir="kb_storage"))
retriever = index.as_retriever(similarity_top_k=3)
llm = OpenAI(api_key=<redacted>("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL"))
app = FastAPI(title="知识库问答服务")
# 请求体格式:{"question": "..."},FastAPI 会自动校验
class AskRequest(BaseModel):
question: str
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/ask")
def ask(req: AskRequest):
nodes = retriever.retrieve(req.question)
context = "\n\n".join(n.get_content() for n in nodes)
resp = llm.chat.completions.create(
model=os.getenv("LLM_MODEL"),
messages=[
{"role": "system", "content": "根据资料回答,资料里没有就说不知道。\n资料:\n" + context},
{"role": "user", "content": req.question},
])
return {"answer": resp.choices[0].message.content,
"sources": [round(n.score, 3) for n in nodes]}代码讲解:
- 启动时只加载一次索引:
load_index_from_storage写在函数外面,服务启动时执行一次。如果写进/ask里面,每个请求都要重新加载,会非常慢。 - pydantic 的
BaseModel:AskRequest规定请求体必须是{"question": "..."}的形式。FastAPI 会自动校验,格式不对就直接返回 422 错误,不用自己写判断。 - 两个接口:
GET /health:健康检查,返回{"status": "ok"}。以后 Docker 和 K8s 会靠它判断服务是否还活着。POST /ask:检索、拼资料、调用 LLM,返回回答和每条资料的相似度分数(sources)。
五、启动
bash
uvicorn 12_api:app --port 800012_api:app 的意思是:12_api.py 文件里名为 app 的对象。
文件名以数字开头报错怎么办:Python 的模块名一般不应该以数字开头。如果 uvicorn 报导入错误,把文件改成字母开头的名字,比如 api12.py,再运行 uvicorn api12:app --port 8000。
六、用 /docs 测试
FastAPI 会自动生成测试页面。打开 http://localhost:8000/docs,展开 POST /ask,点 Try it out,填入问题后点 Execute。
实测结果:
- 返回 200;
- 正确回答了折叠键盘的蓝牙配对步骤;
sources是[0.643, 0.563, 0.418],即检索到的 3 段资料的相似度分数,第一段最相关。
七、.gitignore
运行后会生成 __pycache__/(Python 的缓存文件),已经加入 .gitignore,不会提交。
下一阶段预告
第十三阶段:把这个服务装进 Docker 容器,并用 Qdrant 向量数据库替换本地的索引文件 kb_storage。
👉 下一阶段:第十三阶段:Qdrant 向量数据库