知识库搭建增加kafka+minio+mysql异步解析上传文件到chroma
一. 注意的坑
-
大文件 OOM:PDFBox 千万别 loadPDF(file.getBytes()),要流式读取;MinIO 下载也别整读内存。
-
幂等:Kafka at-least-once 会重复投递,消费者用 fileId 做去重(Redis SETNX 或查状态),否则同一文件入库两次。
-
Chroma 幂等:vectorStore.add() 最好能按 fileId 标识切片(metadata 或 Document id),重复消费时覆盖而非重复插入------具体 API 需要在 Spring AI 2.0 里确认。
-
消息堆积:大文件解析慢,消费者加并发、必要时拆 topic,别让大文件拖垮队列。
-
失败可观测:死信 topic + 状态 FAILED + 错误信息,否则文件"静默丢失"很难排查。
二. 落地顺序建议
-
先起 MinIO + Kafka 环境,引入依赖,跑通「存 MinIO → 发 Kafka → 消费打印日志」。
-
把解析/切片/入库逻辑从 Controller 迁到 Consumer。
-
加状态追踪 + 轮询接口,前端改异步。
-
最后补幂等、重试、死信、大文件分片等加固项。
(
-
起 MinIO + Kafka + MySQL,引入依赖,MinioService 流式上传/下载跑通。
-
建 ingest_task 表 + JPA 实体/仓库/Service。
-
改造 UploadController:存 MinIO → 插表 → 发 Kafka;PdfService 改流式。
-
写 DocumentConsumer 消费编排,手动 ack + 幂等 + 重试 + 死信。
-
加状态查询接口,前端 index.html 改为「上传 → 拿 fileId → 轮询状态」。
-
最后补大文件压测、死信监控、失败重投工具。
)
三. 落地建议
- PdfService 要加 InputStream 重载:现在它是 readPdf(MultipartFile),内部 Loader.loadPDF(file.getBytes()) 整读内存,大文件会 OOM。改成
readPdf(InputStream) 流式解析,MultipartFile.getInputStream() 和 minioService.download() 都能复用。
-
application.yml 的上传大小限制要调大:现在是 max-file-size: 20MB,既然要"大文件",按实际需求调,比如 500MB。
-
"先中转后演进"的预留:MinioService 里先把 presignedUrl() 方法留好,UploadController 的存储调用抽象在 MinioService 内部------以后切预签名直传时,Controller
只多一个 POST /presign 接口,消费链路完全不动。
- 幂等要双重保证:DB 层用 uk_file_id 唯一键 + 消费前 isSuccess 判断;Chroma 侧给切片打 fileId metadata,若底层 API 支持按 id 覆盖则更好(Spring AI 2.0 的
VectorStore.add 具体幂等能力需验证)。
- 环境依赖:MinIO、Kafka、MySQL 三个中间件要先起起来;Ollama + Chroma 沿用现状。
四. 防止Claude Code卡住,对应的prompt优化
不要继续大范围分析项目,也不要重新设计架构。
连接信息已经确认:
MinIO:
Kafka:
localhost:9092
MySQL:
localhost:3306
username=root
password=root
现在直接开始第 1 步开发:
-
检查 pom.xml 和 application.yml
-
配置 MinIO、Kafka、MySQL
-
检查并实现 MinioService
-
不要安装或下载 MinIO
-
不要修改 Docker 中已经运行的 MinIO
-
不要重新设计现有 RAG 架构
请边检查边修改代码。
每完成一个小步骤就运行编译/测试验证,不要花几分钟继续思考整个项目。
如果发现配置有问题,直接修复并继续。
现在开始实际编码。
五. MinIo
docker inspect minio | grep -E 'MINIO_ROOT_USER|MINIO_ROOT_PASSWORD'
"MINIO_ROOT_USER=admin",
"MINIO_ROOT_PASSWORD=admin123456",
"MINIO_ROOT_USER_FILE=access_key",
"MINIO_ROOT_PASSWORD_FILE=secret_key",
服务器
│
┌───────────┴───────────┐
│ │
9000 9001
│ │
↓ ↓
MinIO API MinIO Console
│
Docker
│
minio
六. Kafka总结
- 为啥Producer和Consumer的key和value都需要序列化?

由于kafka的broker端存的是byte\[\],而不是java对象。
生产者:
Producer:
Java对象
↓
Serializer
↓
byte\[\]
↓
Kafka
消费者:
Kafka
↓
byte\[\]
↓
Deserializer
↓
Java对象
- auto-offset-reset: earliest含义?
这个配置和消费者第一次读取 Kafka 消息时从哪里开始读有关。
如果这个消费者组没有找到已经提交的 offset,那么从最早的消息开始消费。
消息:
Kafka:
0 PDF-A
1 PDF-B
2 PDF-C
3 PDF-D
4 PDF-E
七. Chroma / Milvus / PGVector 这三种向量库的区别和联系
- 三种向量库对比
| Chroma | Milvus | pgvector | |
|---|---|---|---|
| 本质 | AI/RAG 向量数据库 | 专业、高性能向量数据库 | PostgreSQL 扩展 |
| 上手难度 | ⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| 小型 RAG | 非常适合 | 可以 | 适合 |
| 大规模向量 | 一般/可扩展 | 非常强 | 中大型可用 |
| 分布式 | 支持云/服务化部署 | 强项 | PostgreSQL 集群能力为主 |
| 业务数据 JOIN | 一般 | 不是强项 | 非常强 |
| SQL | 不以 SQL 为核心 | 自己的查询 API | 标准 SQL |
| 事务/ACID | 不以此为核心 | 不以此为核心 | PostgreSQL 原生能力 |
| Java 后端 | 可以 | 很好 | 很好 |
| RAG 学习 | 非常推荐 | 推荐 | 推荐 |
| 企业业务系统 | 看场景 | 大规模 AI 场景 | 业务数据+向量一体化 |
- 各自特点与适用场景
Chroma
-
一个命令装好就能跑,API 极简,内置持久化(默认 SQLite)。
-
适合:原型验证、demo、个人项目、小团队 MVP,数据量不大但想快速上线。
-
缺点:不是为高并发/海量数据设计的,规模上去了通常要换。
PGVector
- 最大优势是**"向量 + 关系数据"一体化**:你不需要再维护一个独立的向量库,业务数据和向量数据在同一张表、同一个事务里。例如 SELECT * FROM docs ORDER BY
embedding <=> :q LIMIT 5。
-
适合:已经用 PostgreSQL 的团队、需要强一致性和复杂过滤(向量 + 结构化条件混合查询)的场景。
-
缺点:性能天花板受单机 PG 限制,海量向量规模(亿级)不如专用分布式库。
Milvus
-
功能最全、性能最强:多索引类型、分区、数据分片、流式/批式写入、GPU 加速等。
-
适合:数据量亿级、高并发 QPS、需要水平扩展的生产级系统(如大型知识库、电商以图搜图、推荐系统)。
- 选型建议
-
快速起步 / 原型 → Chroma
-
已经有 PostgreSQL / 想少维护一套系统 → PGVector
-
海量数据 + 高并发 + 生产级 → Milvus
一个常见的演进路径是:先用 Chroma 或 PGVector 跑通 → 数据量和 QPS 上来了 → 迁移到 Milvus。
第一种: Chroma
Chroma
↓
专门帮你保存:
vector
text
metadata
Java开发规范.pdf:
切成:
chunk1
chunk2
chunk3
...
chunk100
Embedding:
chunk1 → 0.12, 0.38, ...
chunk2 → 0.25, 0.11, ...
Kafka消费者如何提交offset?
转成向量:query → 0.13, 0.39, ...
Chroma 找最相似的:
chunk17
chunk31
chunk72
然后交给 LLM。
Chroma 官方目前也支持 metadata filtering、dense/sparse/hybrid search 等能力。
第二种:Milvus:专业的向量数据库
官方文档现在把 Milvus 的部署从本地原型一直覆盖到 Kubernetes 大规模分布式系统,并支持 HNSW、IVF、DiskANN 等多种索引和大规模扩展。
比如:
100万向量
↓
1000万向量
↓
1亿向量
↓
10亿向量
这种情况下,Milvus 的优势越来越明显。
架构可能变成:

它本身就是围绕向量检索设计的。
第三种: pgvector
pgvector 和前两个最大的区别是:
它不是一个独立的向量数据库产品,而是 PostgreSQL 的一个扩展。
例如:CREATE EXTENSION vector;
然后:
CREATE TABLE document_chunk (
id BIGSERIAL PRIMARY KEY,
content TEXT,
embedding VECTOR(1536)
);
于是 PostgreSQL 就可以直接存:
普通数据
向量
pgvector 支持精确搜索和近似最近邻搜索,并支持 HNSW、IVFFlat 等索引;同时你还能继续使用 PostgreSQL 的 JOIN、事务、备份等能力。
pgvector 最大的优势:
业务数据和向量可以放一起
比如:
document
id
name
category
tenant_id
created_at
然后:
document_chunk
id
document_id
content
embedding
那么你可以直接:
SELECT *
FROM document_chunk
WHERE tenant_id = 100
ORDER BY embedding <=> '...'
LIMIT 10;
甚至:
文档
↓
JOIN
↓
用户权限
↓
分类
↓
向量相似度
这对企业知识库特别有意义。
pgvector 官方也明确支持和 PostgreSQL 全文搜索一起实现 hybrid search。