本目录是“基于大模型的私有知识库问答系统”后端当前后端实现。
cmd/api: API 入口cmd/worker: Worker 入口internal/platform: 配置、数据库连接、HTTP 响应、中间件、鉴权、本地文件存储internal/account: 注册、登录、刷新令牌、退出登录、当前用户信息、修改密码internal/chat: 会话创建、列表、详情、删除;普通聊天与知识库 RAG SSE 聊天internal/kb: 知识库 CRUD、文档上传、文档列表/详情/删除、重建索引任务创建internal/task: 统一任务模型、任务创建与状态推进internal/worker: 异步任务消费执行器internal/admin: 管理端路由占位migrations: Goose 迁移 SQL
- 复制环境变量模板
cp backend/.env.example backend/.env说明:
- 默认
DATABASE_DSN已经和compose.dev.yaml里的 PostgreSQL 配置对齐 - 当前默认宿主机端口为
55432 - 如果你不改端口、用户名、密码和数据库名,那么可以直接使用默认值
- 现在 API/Worker 会自动读取
backend/.env和backend/.env.local,不需要手动source .env
- 至少确认以下配置
DATABASE_DSNAUTH_JWT_SECRETDEEPSEEK_API_KEYAI_EMBEDDING_PROVIDERSTORAGE_PROVIDERSTORAGE_BUCKETSTORAGE_LOCAL_ROOT
embedding 相关说明:
- 默认
AI_EMBEDDING_PROVIDER=local_hash,不依赖额外远程服务,适合本地开发和课程演示 - 如果你有可用的 OpenAI 兼容 embedding 服务,可改成:
AI_EMBEDDING_PROVIDER=openai_compatibleAI_EMBEDDING_BASE_URL=<你的 embedding base url>AI_EMBEDDING_API_KEY=<你的 embedding key>
- 当前聊天仍然使用 DeepSeek Chat Completions;embedding provider 与聊天 provider 可以分开配置
- 准备 PostgreSQL 15+,推荐直接用仓库内的开发容器
Podman Compose:
cd backend
podman-compose -f compose.dev.yaml up -dDocker Compose:
cd backend
docker compose -f compose.dev.yaml up -d说明:
- 容器镜像已内置
pgvector - migration 会负责创建
pgcrypto、vector扩展 - 默认上传文件会保存在
backend/data/storage,目录会自动创建
- 执行数据库迁移
cd backend
./scripts/migrate-up.sh如果你更习惯 make:
cd backend
make db-up
make migrate-upAPI:
cd backend
./scripts/run-api.shWorker:
cd backend
./scripts/run-worker.sh如果你更习惯 make:
cd backend
make run-api
make run-workercd backend
GOCACHE=/tmp/go-build go test ./...- 聊天接口:
POST /api/v1/sessions/{sessionId}/messages - 返回类型:
text/event-stream - 当前已接入 provider:
DeepSeek - 当前支持场景:
- 会话未绑定知识库时的通用聊天
- 会话绑定知识库时的 RAG 聊天
- 历史消息自动截取最近若干条拼接到上下文
- 命中知识库时基于
pgvector检索 chunk,assistant 消息会保存引用 - 未命中知识库时自动回退为通用回答,并在 SSE
meta.grounded=false中标记 - 用户消息和 assistant 消息落库
- 已支持
POST /sessions/{sessionId}/messages/{messageId}/regenerate - 已支持
POST /sessions/{sessionId}/stream/stop
- 当前限制:
regenerate采用覆盖式更新,不保留回答版本历史stream/stop会终止当前会话正在生成的流;若成功中断,不会把不完整答案落库
建议至少补齐以下环境变量:
DEEPSEEK_API_KEYAI_DEFAULT_CHAT_MODELAI_CHAT_TIMEOUTAI_MAX_HISTORY_MESSAGESAI_SSE_HEARTBEAT_INTERVALAI_EMBEDDING_PROVIDERAI_RAG_MAX_CONTEXT_CHUNKS
下面示例展示“注册 -> 登录 -> 创建普通会话 -> 发起流式聊天”的最短链路。
- 注册
curl -X POST http://127.0.0.1:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "demo_user",
"email": "[email protected]",
"password": "StrongPass123!"
}'- 登录并保存
access_token
curl -X POST http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"account": "demo_user",
"password": "StrongPass123!"
}'登录成功后,从返回 JSON 的 data.access_token 中取出令牌。
- 创建一个不绑定知识库的普通会话
curl -X POST http://127.0.0.1:8080/api/v1/sessions \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "DeepSeek Curl Smoke",
"model": "deepseek-chat"
}'创建成功后,从返回 JSON 的 data.session_id 中取出会话 ID。
- 发起 SSE 聊天
curl -N -X POST http://127.0.0.1:8080/api/v1/sessions/<session_id>/messages \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"content": "你好,请用三句话做一个简短的自我介绍。"
}'预期返回示例:
event: meta
data: {"message_id":"uuid","grounded":false,"model":"deepseek-chat"}
event: delta
data: {"content":"你好"}
event: delta
data: {"content":"!我是 DeepSeek ..."}
event: done
data: {"finish_reason":"stop"}
- 可选:回查会话详情,确认消息已经落库
curl http://127.0.0.1:8080/api/v1/sessions/<session_id> \
-H "Authorization: Bearer <access_token>"- 若要测试知识库会话下的 RAG 聊天,最短顺序是:
- 创建知识库
- 上传
txt/md/docx - 等待 worker 将文档状态处理为
available - 创建带
knowledge_base_id的会话 - 调用
POST /api/v1/sessions/{sessionId}/messages
- SSE 的
meta.grounded:true表示命中了知识库上下文false表示知识库未命中,当前回答已回退为通用回答
- 回查
GET /api/v1/sessions/{sessionId}时,assistant 消息的citations字段会返回引用文档信息
POST /api/v1/sessions/{sessionId}/messages/{messageId}/regenerate- 返回类型也是
text/event-stream - 会基于原用户问题重新检索并生成回答
meta.message_id会等于原 assistant 消息 ID- 成功后会直接覆盖原 assistant 消息内容、token 用量和
citations
- 返回类型也是
POST /api/v1/sessions/{sessionId}/stream/stop- 返回 JSON:
{"code":0,"message":"ok","data":{"stopped":true|false}} stopped=true表示当前确实中断了一个活跃流stopped=false表示当前会话没有正在运行的流
- 返回 JSON:
- 同一会话同一时刻只允许一个活跃生成任务
- 若在已有流未结束时再次调用发送消息或重生成,会返回
409
- 若在已有流未结束时再次调用发送消息或重生成,会返回
- 上传接口:
POST /api/v1/knowledge-bases/{kbId}/documents - 请求格式:
multipart/form-data,字段名固定为file - 上传大小上限默认
20 MiB,可通过STORAGE_MAX_UPLOAD_BYTES调整 - 当前允许上传的 MIME / 扩展名:
text/plain/.txttext/markdown/.md/.markdownapplication/vnd.openxmlformats-officedocument.wordprocessingml.document/.docxapplication/pdf/.pdf
- 当前 worker 已实现:
document_ingestknowledge_base_reindexresource_cleanup
- 当前 ingest 已实现的文本提取:
txtmarkdowndocxpdf(带可提取文本层的 PDF)
- 当前 embedding 行为:
- 默认使用本地
local_hashembedding,把文档 chunk 和查询统一映射到1536维向量,适合本地开发与演示 - 若你配置了
AI_EMBEDDING_PROVIDER=openai_compatible,worker 和 RAG 查询都会改用远程 embedding 服务
- 默认使用本地
- 当前限制:
- 扫描件或纯图片型
pdf若不包含可提取文本层,worker 会将该文档任务标记为failed - 当前仍未实现 OCR,因此这类 PDF 无法入库
- 扫描件或纯图片型
- 为扫描件 PDF 接入 OCR
- 若有真实 embedding 服务,切换
AI_EMBEDDING_PROVIDER=openai_compatible - 完成管理员的用户、任务、系统参数、配额和审计接口
- 继续补 quota / audit 统计落库