实战:PostgreSQL + Milvus + Redis + MinIO 构建企业知识库
码海寻道 · 大模型、智能体与 RAG 工程组件系列第 57 篇
当知识库进入企业生产环境,通常需要把业务事实、向量索引、原始文件和缓存分开。本文给出一套组件组合和关键数据流,重点放在职责边界与一致性,而不是复制一份不可维护的 Demo。
一、四个组件分别负责什么?
PostgreSQL:用户、租户、文档、版本、任务、权限、审计 Milvus:Chunk 向量、索引和相似度检索 Redis:会话、缓存、限流、短期状态 MinIO:PDF、Word、图片和解析派生文件二、数据流
客户端 → FastAPI → MinIO ↓ PostgreSQL 文档记录 ↓ 消息队列 Worker 解析/OCR/Embedding ├── PostgreSQL:Chunk 元数据 └── Milvus:向量索引问答时:
问题 → Redis 缓存检查 → Embedding → Milvus 检索 查询链路应先从 PostgreSQL 或权限服务得到当前用户的租户、知识库、文档版本和权限版本,再生成 Milvus 过滤条件和 Redis Key。Redis 命中也必须经过权限版本校验,不能因为缓存快就绕过业务回查。 → PostgreSQL 权限/版本回查 → Prompt → LLM三、PostgreSQL 表设计
CREATETABLEdocuments(id uuidPRIMARYKEY,tenant_idtextNOTNULL,titletextNOTNULL,versionintegerNOTNULL,object_keytextNOTNULL,statustextNOTNULL,created_at timestamptzNOTNULLDEFAULTnow(),UNIQUE(tenant_id,id,version));CREATETABLEjobs(id uuidPRIMARYKEY,document_id uuidNOTNULL,stagetextNOTNULL,statustextNOTNULL,progressnumeric(5,2)NOTNULLDEFAULT0,error_codetext,updated_at timestamptzNOTNULLDEFAULTnow());Milvus 中的chunk_id、document_id和tenant_id必须能回查这些业务记录。
四、MinIO 对象 Key
tenants/{tenant_id}/documents/{document_id}/v{version}/source.pdf tenants/{tenant_id}/documents/{document_id}/v{version}/parsed.json原始文件是可重建事实,解析 JSON、缩略图和 OCR 结果是派生数据。对象下载使用短时预签名 URL,不能公开整个 Bucket。
五、Milvus Collection 设计
chunk_id:主键 document_id:业务关联 tenant_id:过滤字段 version:版本过滤 status:发布状态 embedding:向量字段写入和查询必须使用同一 Embedding 模型、维度和距离指标。模型升级时创建新版本索引并灰度切换。
Milvus 中保存的chunk_id、document_id、tenant_id、version和status只是检索副本,PostgreSQL 仍是文档状态与权限事实源。向量命中后按稳定 ID 回查,索引重建或异常恢复时可以从业务事实重新生成,而不是手工修复孤立向量。
六、Redis 缓存 Key
rag:embedding:{model_version}:{content_hash} rag:search:{tenant_id}:{kb_version}:{query_hash} rag:answer:{tenant_id}:{kb_version}:{model_version}:{query_hash}缓存不能绕过权限校验。知识库发布、权限变化和模型升级时,需要通过版本化 Key 或主动失效避免旧答案继续返回。
缓存值应带serving_version、permission_version、模型版本和生成时间,并设置合理 TTL。权限回收、文档下线或回答策略变化时,优先提升版本使旧 Key 自然失效,避免对海量 Key 做高风险通配符删除。
七、异步 Worker 流程
document.created → parse_document → split_chunks → generate_embeddings → write_milvus → verify_searchable → publish_version每一步都要幂等,记录批次、模型版本、失败原因和重试次数。只有publish_version完成后,问答检索才允许使用这批数据。
Worker 还要记录trace_id、job_id、输入对象版本和阶段状态。消息重复投递时按document_id + version + stage判断是否已完成;Milvus 批量写入部分成功时,要保留批次明细并支持补写、删除或重建,不能只凭“请求成功”标记整批完成。
八、故障处理
MinIO 成功,PostgreSQL 失败
通过上传确认任务和定时扫描发现孤儿对象,不能直接把对象 Key 当作已发布文档。
PostgreSQL 成功,Milvus 失败
文档保持index_pending,进入重试队列,不能把状态标为 ready。
Redis 故障
缓存失效后回源 PostgreSQL、Milvus 和模型服务;限流故障要有明确的保护策略。
Milvus 可搜,业务记录被删除
查询服务应以 PostgreSQL 的发布和删除状态为准,并定期扫描孤儿向量。删除先阻断新检索,再异步清理 Milvus 和缓存;清理失败要进入补偿队列并有告警,避免“数据库已删、向量仍可搜”长期存在。
检索结果回查失败时不得直接展示,后台应触发索引清理补偿。
九、部署顺序
PostgreSQL → MinIO → Redis → Milvus → API → Worker → 前端生产环境中,状态组件优先考虑托管服务、备份和恢复演练。不要只验证容器能启动,还要测试数据写入、重启和跨服务失败。
十、上线清单
- 原始文件和业务元数据职责分离;
- Milvus 记录可以回查租户、版本和权限;
- Redis Key 包含租户和版本维度;
- Worker 支持幂等、重试和补偿;
- 发布状态只在索引可搜索后切换;
- 有对象、数据库和向量索引备份;
- 观测链路包含跨组件 trace_id。
结语
PostgreSQL、Milvus、Redis 和 MinIO 组合的关键,是让每个组件承担明确职责,并用稳定 ID、版本状态和异步任务连接起来。企业知识库真正难的是一致性和治理,而不是把四个服务启动起来。
下一篇将为知识库增加 Agent 工具调用和工作流编排。
参考资料
- Milvus 官方文档
- MinIO 官方文档
- Redis 官方文档
- PostgreSQL 官方文档
本文为“码海寻道”原创技术文章。组件版本、部署模式和数据恢复策略需要结合真实环境进行压测和演练。