上一篇《别在业务代码里裸调大模型》把大模型装进了 Spring Cloud。后台问得最多的是同一句话问它公司内部的事它就一本正经地胡说八道怎么破这篇就解决它。先说结论不是模型不行是你喂饭的方式不对。一、把文档直接塞进 Prompt是新手必踩的第一个坑最直觉的方案用户提问把相关文档全文拼进 Prompt 一起发给模型。Demo 一跑效果惊艳上生产四种死法装不下——一套产品手册几百页再大的上下文窗口也塞不进去太贵——输入 token 按量计费每问一句都重发整本手册月底账单让你怀疑人生太慢——模型先读完五万字才开始答题首字延迟几十秒用户早跑了不更新——文档今天刚改模型根本不知道这就是幻觉的根源。二、RAG 一句话让模型开卷考试不许背全书只发三页相关资料。离线把文档切片、向量化、存进向量库在线把用户问题向量化捞出最相关的几段连同问题一起交给模型让它照着资料作答。本篇打通左半场文档入库下一篇讲右半场检索与生成。文档 → 切片 → Embedding → 向量库 问题 → Embedding ↓ 相似度检索 相关片段 问题 → 大模型 → 答案三、三步把文档灌进知识库Spring AI Redis第 1 步依赖和配置复制就能用dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tika-document-reader/artifactId !-- PDF/Word/Markdown 通吃 -- /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-redis/artifactId /dependencyspring: ai: openai: api-key: ${LLM_API_KEY} base-url: ${LLM_BASE_URL} # 国产兼容模型换地址即可 embedding: options: model: text-embedding-3-small vectorstore: redis: index: knowledge-index prefix: doc:向量库用 Redis Stack普通 Redis 不支持向量索引Docker 一行起docker run -d --name redis-stack -p 6379:6379 redis/redis-stack:latest第 2 步入库流水线核心就十几行Service public class KnowledgeIngestService { private final VectorStore vectorStore; public KnowledgeIngestService(VectorStore vectorStore) { this.vectorStore vectorStore; } public int ingest(String fileUrl, String docName, String tenantId) { // 1. 加载Tika 自动识别 PDF/Word/Markdown 并抽取文本 ListDocument rawDocs new TikaDocumentReader(fileUrl).get(); // 2. 切片600 token 一片相邻片重叠 100防止语义被拦腰斩断 TokenTextSplitter splitter TokenTextSplitter.builder() .chunkSize(600).chunkOverlap(100).build(); // 3. 打元数据来源、租户、更新时间——下期权限过滤全靠它 ListDocument chunks splitter.apply(rawDocs).stream() .map(d - Document.builder().text(d.getText()) .metadata(Map.of(source, docName, tenantId, tenantId, updatedAt, LocalDate.now().toString())) .build()) .toList(); // 4. 向量化 入库一步到位 vectorStore.add(chunks); return chunks.size(); } }提醒一句入库是离线批处理别挂在用户请求链路里。文档上传后丢给 MQ 或异步线程池否则 Embedding 批处理能把接口拖死。第 3 步先验证检索再谈生成GetMapping(/search) public ListString search(RequestParam String q) { SearchRequest request SearchRequest.builder() .query(q) .topK(4) // 召回最相关的 4 片 .similarityThreshold(0.7) // 相似度门槛滤掉牛头不对马嘴的 .build(); return vectorStore.similaritySearch(request).stream() .map(d - d.getText() 【来源 d.getMetadata().get(source) 】) .toList(); }拿十几个真实业务问题打一遍检索结果不对模型再强也白搭。这半场验收通过再进下一篇的生成环节。四、切片的三个坑我替你踩过了别按字数硬切。每 500 字一刀代码被腰斩、表格被劈成两半向量化出来的全是残次语义。正确姿势先按标题/章节结构切再用长度兜底。一定要留重叠。相邻两片保留 10%~20% 重叠否则正好从一句话中间切开两片都读不懂。metadata 第一天就要打全。来源、租户、密级、更新时间……很多人上线后才发现没法做权限过滤只能全量重建。下一篇的多租户隔离靠的就是今天打进去的tenantId。五、Embedding 和向量库各给你一句话结论Embedding 两条纪律一个知识库固定一个 Embedding 模型换模型 全量重新入库文档更新只重算变化的切片用内容哈希判增量别无脑全量重建。向量库一句话选型百万级以内 Redis 足够你们本来就有要做 SQL 级权限过滤上 pgvector真到千万级再请出 Milvus。别为了简历优化架构。六、写在最后下一篇是 RAG 的灵魂怎么把召回片段拼成 Prompt、怎么让模型不知道就说不知道、怎么给答案挂引用溯源以及最容易出数据泄露事故的多租户权限过滤——A 公司员工绝不能搜出 B 公司的文档。如果这篇帮你少踩了坑点赞 收藏就是最大的鼓励。评论区聊聊你们知识库的量级几百份还是几万份文档我按评论区的规模决定下一篇选型讲多深。系列导航一别在业务代码里裸调大模型 → 二RAG 文档入库本篇→ 三检索增强与多租户权限每周四更新关注不迷路。运行环境JDK 17 Spring Boot 3.3 Spring AI 1.0.x Redis Stack代码实测可跑。
阅读完成 · 觉得有帮助?