第一阶段:环境与配置准备
1.1 安装必要依赖
在 apps/api 目录下,我们需要安装处理文件上传和对接 AI 模型的工具:
powershell
uv add python-multipart langchain-openai
注意 :
python-multipart是 FastAPI 处理文件上传的必需件。
1.2 更新 .env
在 .env 文件中加入你的 AI 服务密钥(以 OpenAI 为例,你也可以更换为本地模型):
env
OPENAI_API_KEY=sk-xxxx...
# 2026 年推荐使用更快速的 Embedding 模型
EMBEDDING_MODEL=text-embedding-3-small
第二阶段:编写向量生成服务
在 apps/api 下新建 services/ 文件夹,并创建 embedding.py:
python
from langchain_openai import OpenAIEmbeddings
import os
from dotenv import load_dotenv
load_dotenv()
# 初始化 Embedding 客户端
# 2026 年的 LangChain 已原生适配 Python 3.14 的并发特性
embeddings_model = OpenAIEmbeddings(
model=os.getenv("EMBEDDING_MODEL", "text-embedding-3-small")
)
async def generate_vector(text: str):
"""将文本转化为 1536 维的向量"""
# 这里会自动调用远程或本地模型进行计算
vector = await embeddings_model.aembed_query(text)
return vector
第三阶段:更新主应用文件
现在我们把所有零件组装在 apps/api/main.py 中。更新后的完整代码如下:
python
from fastapi import FastAPI, UploadFile, File, Depends, HTTPException
from contextlib import asynccontextmanager
from sqlmodel import Session, text
from typing import List
import os
# 数据库和模型导入
from database import init_db, engine, get_session
from models import User, Document
from services.embedding import generate_vector
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时执行
print("🚀 启动 KnoSphere API...")
with engine.connect() as conn:
# 激活向量扩展,这是 2026 年 RAG 系统的核心
conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector;"))
conn.commit()
init_db() # 这会创建所有表,包括 User 和 Document
print("✅ 数据库初始化完成")
yield
# 关闭时执行(如果需要清理资源)
print("👋 关闭 KnoSphere API...")
app = FastAPI(
title="KnoSphere API",
description="2026 企业级智能知识库系统",
version="1.0.0",
lifespan=lifespan
)
@app.get("/")
async def root():
return {"message": "欢迎使用 KnoSphere API - 2026 企业级智能知识库系统"}
@app.get("/health")
async def health():
return {"status": "healthy", "service": "KnoSphere API"}
@app.get("/documents")
async def list_documents(
db: Session = Depends(get_session),
limit: int = 10,
offset: int = 0
):
"""获取文档列表"""
documents = db.query(Document).offset(offset).limit(limit).all()
return {
"total": db.query(Document).count(),
"documents": [
{
"id": doc.id,
"title": doc.title,
"created_at": doc.created_at,
"content_preview": doc.content[:100] + "..." if len(doc.content) > 100 else doc.content
}
for doc in documents
]
}
@app.post("/upload")
async def upload_document(
file: UploadFile = File(...),
db: Session = Depends(get_session)
):
"""
上传文档并生成向量
支持格式:.txt, .md, .pdf, .docx
"""
# 1. 验证文件类型
allowed_extensions = {'.txt', '.md', '.pdf', '.docx'}
file_ext = os.path.splitext(file.filename)[1].lower()
if file_ext not in allowed_extensions:
raise HTTPException(
status_code=400,
detail=f"不支持的文件格式。支持格式: {', '.join(allowed_extensions)}"
)
# 2. 读取文件内容
try:
content = await file.read()
# 处理不同文件类型
if file_ext == '.pdf':
# PDF 处理 - 需要额外的依赖
try:
import PyPDF2
pdf_reader = PyPDF2.PdfReader(io.BytesIO(content))
text_content = ""
for page in pdf_reader.pages:
text_content += page.extract_text()
except ImportError:
# 如果未安装 PyPDF2,提示安装
raise HTTPException(
status_code=400,
detail="PDF 处理需要安装 PyPDF2。请运行: uv add PyPDF2"
)
elif file_ext == '.docx':
# DOCX 处理
try:
import docx
doc = docx.Document(io.BytesIO(content))
text_content = "\n".join([paragraph.text for paragraph in doc.paragraphs])
except ImportError:
raise HTTPException(
status_code=400,
detail="DOCX 处理需要安装 python-docx。请运行: uv add python-docx"
)
else:
# 文本文件处理
text_content = content.decode("utf-8")
except UnicodeDecodeError:
raise HTTPException(status_code=400, detail="文件编码错误,请使用 UTF-8 编码")
except Exception as e:
raise HTTPException(status_code=500, detail=f"文件读取失败: {str(e)}")
# 3. 检查文本长度
if len(text_content.strip()) == 0:
raise HTTPException(status_code=400, detail="文件内容为空")
# 4. 生成向量 (AI 核心步骤)
try:
vector = await generate_vector(text_content)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"向量生成失败: {str(e)}。请检查 OPENAI_API_KEY 环境变量"
)
# 5. 存储到 PostgreSQL 17
try:
new_doc = Document(
title=file.filename,
content=text_content,
embedding=vector # 存入我们之前定义的 Vector 字段
)
db.add(new_doc)
db.commit()
db.refresh(new_doc)
return {
"message": "上传成功",
"document_id": new_doc.id,
"title": new_doc.title,
"vector_dimensions": len(vector) if vector else 0,
"content_length": len(text_content)
}
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=f"数据库存储失败: {str(e)}")
# 添加缺失的导入
import io
# 如果需要添加更多文件格式处理,可以取消下面的注释并安装相应依赖
# @app.on_event("startup")
# async def check_dependencies():
# """检查可选依赖"""
# try:
# import PyPDF2
# print("✅ PyPDF2 已安装,支持 PDF 处理")
# except ImportError:
# print("⚠️ PyPDF2 未安装,PDF 文件处理将不可用")
#
# try:
# import docx
# print("✅ python-docx 已安装,支持 DOCX 处理")
# except ImportError:
# print("⚠️ python-docx 未安装,DOCX 文件处理将不可用")
if __name__ == "__main__":
import uvicorn
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
reload=True # 开发模式下自动重载
)
2026 年的核心技术细节解析
- 异步处理 (Async) :在 2026 年,FastAPI 的异步性能已经非常成熟。通过
await,系统在等待 AI 生成向量时不会阻塞,可以同时处理成百上千个用户的上传请求。 - 存算分离趋势 :虽然我们目前存入 PostgreSQL,但如果你的知识库未来达到亿级规模,只需将
Document的存储逻辑切向 Milvus 3.x 即可,架构上是完全兼容的。 - 向量压缩 :
text-embedding-3-small支持缩减维度而保持精度,这能显著降低 PostgreSQL 的索引压力。 - 生命周期管理 :使用
@asynccontextmanager替代旧的@app.on_event("startup")和@app.on_event("shutdown"),这是 FastAPI 2.0+ 的最佳实践。
第四阶段:可选依赖安装
如果你想支持更多文件格式,可以安装额外的依赖:
powershell
# 安装 PDF 处理支持
uv add PyPDF2
# 安装 DOCX 处理支持
uv add python-docx
第五阶段:测试 API
现在你可以启动 API 服务器进行测试:
powershell
# 在 apps/api 目录下运行
uv run python main.py
或者直接使用 uvicorn:
powershell
uv run uvicorn main:app --reload --host 0.0.0.0 --port 8000
测试上传接口:
bash
# 使用 curl 测试
curl -X POST "http://localhost:8000/upload" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@example.txt"
检查点:你的 AI 链路已跑通
- API 端点 :可以通过
POST /upload接收文件。 - AI 转化:文本已成功转化为高维数学向量。
- 持久化:原始文本和向量数据已安全存入 PostgreSQL。
!!!问题: 但目前只支持openai的,不支持大多数模型
- 兼容大多数模型