LangChain4j RAG从原理到实战
LangChain4j RAG从原理到实战(医疗智答助手版)
只会“调用大模型”还不够,真正可落地的 AI 助手必须具备外部知识访问能力,而 RAG 正是把“知识库”接入“对话系统”的关键能力。
⚡ 快速参考
- LangChain4j 文档:https://docs.langchain4j.dev
- Embedding Stores 集成:https://docs.langchain4j.dev/integrations/embedding-stores/
- Pinecone 官网:https://www.pinecone.io/
📚 学习目标
- 理解 RAG 的核心价值与适用场景
- 掌握 RAG 两阶段流程:索引(Indexing)与检索(Retrieval)
- 掌握 LangChain4j 的文档加载、解析、分割与向量化
- 学会用 Pinecone 作为生产可用向量数据库
- 在 AIService 中接入
ContentRetriever实现知识增强问答
一、什么是 RAG,为什么要用
1.1 RAG 的本质
RAG(Retrieval-Augmented Generation,检索增强生成)本质上是:
先从外部知识库检索相关内容,再把检索结果和用户问题一起交给大模型生成答案。
1.1.1 解决了哪些问题
- 大模型参数不是实时更新,难覆盖最新知识
- 纯模型回答容易“幻觉”
- 企业私有知识无法直接被公有模型内化
- 直接把整份文档喂给模型成本高、延迟高
常见应用场景
- 企业客服知识库问答
- 医疗、法律、金融等专业问答
- 内部制度、产品文档、FAQ 检索问答
- 频繁更新知识的实时问答系统
二、RAG 常见检索方法
2.1 关键词检索 vs 向量检索
- 关键词检索:按词项匹配和频次排序,适合精确术语检索
- 向量检索(语义检索):把文本映射为向量,按相似度匹配语义
- 混合检索:关键词 + 向量,通常效果更稳
2.1.1 相似度的理解
向量检索会计算查询向量与文档向量的相似度(如余弦相似度),分数越高,相关性越强。
三、RAG 的两阶段流程
3.1 索引阶段(离线/预处理)
索引阶段目标:把原始知识变成“可检索”的向量索引。
流程:
- 加载文档(Loader)
- 解析文档(Parser)
- 切分文档(Splitter)
- 片段向量化(Embedding)
- 向量写入数据库(EmbeddingStore)
3.1.1 为什么必须切分文本
- LLM 上下文窗口有限,整库无法直接输入
- 输入越长,时延和成本越高
- 无关上下文越多,幻觉风险越高
- 合理分块能提升召回精度与答案可控性
3.2 检索阶段(在线)
检索阶段目标:根据用户问题召回高相关片段并增强回答。
流程:
- 将用户问题向量化
- 在向量库相似度检索
- 过滤低分片段(
minScore) - 将片段 + 问题交给 LLM 生成答案
四、LangChain4j 中的 RAG 关键组件
4.1 文档加载器(Document Loader)
常见加载器包括:
ClassPathDocumentLoaderUrlDocumentLoaderAmazonS3DocumentLoaderAzureBlobStorageDocumentLoaderGitHubDocumentLoaderGoogleCloudStorageDocumentLoaderSeleniumDocumentLoaderTencentCosDocumentLoader
4.1.1 本地快速验证示例
Documentdocument=FileSystemDocumentLoader.loadDocument("E:/knowledge/人工智能.md");4.2 文档解析器(Document Parser)
常见解析器:
ApachePdfBoxDocumentParser:PDFApachePoiDocumentParser:DOC/DOCX/PPT/PPTX/XLS/XLSXApacheTikaDocumentParser:自动识别并解析多格式
4.2.1 解析器选型建议
- 格式单一:用专用解析器(更轻)
- 格式复杂:用 Tika(更通用)
4.3 文档分割器(Document Splitter)
常见分割器:
DocumentByLineSplitterDocumentBySentenceSplitterDocumentByWordSplitterDocumentByCharacterSplitterDocumentByRegexSplitterDocumentSplitters.recursive(...)
默认常见策略:片段不超过约300 token,并设置一定 overlap(如30 token)保证上下文连贯。
4.3.1 参数调优经验
chunk size小:命中更细,可能上下文不足chunk size大:上下文更完整,可能引入噪声overlap过小:信息断裂overlap过大:冗余与成本上升
常用起步建议:
chunk size:400~800 tokenoverlap:30~50 token
五、从 InMemory 到 Pinecone:生产化向量存储
5.1 为什么不用 InMemoryEmbeddingStore 上生产
- 进程重启数据丢失
- 扩容后数据难共享
- 难支撑大规模检索和治理
5.2 集成 Pinecone
依赖示例:
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-pinecone</artifactId></dependency>配置向量存储:
@BeanpublicEmbeddingStore<TextSegment>embeddingStore(){returnPineconeEmbeddingStore.builder().apiKey(System.getenv("PINECONE_API_KEY")).index("med-assistant-index").nameSpace("med-assistant-namespace").createIndex(PineconeServerlessIndexConfig.builder().cloud("AWS").region("us-east-1").dimension(embeddingModel.dimension()).build()).build();}六、知识入库与检索代码实战
6.1 批量上传知识库
Documentdocument1=FileSystemDocumentLoader.loadDocument("E:/knowledge/医院信息.md");Documentdocument2=FileSystemDocumentLoader.loadDocument("E:/knowledge/科室信息.md");Documentdocument3=FileSystemDocumentLoader.loadDocument("E:/knowledge/神经内科.md");List<Document>documents=Arrays.asList(document1,document2,document3);EmbeddingStoreIngestor.builder().embeddingStore(embeddingStore).embeddingModel(embeddingModel).build().ingest(documents);6.2 相似度检索示例
EmbeddingqueryEmbedding=embeddingModel.embed("你最喜欢的运动是什么?").content();EmbeddingSearchRequestsearchRequest=EmbeddingSearchRequest.builder().queryEmbedding(queryEmbedding).maxResults(1)// .minScore(0.8).build();EmbeddingSearchResult<TextSegment>searchResult=embeddingStore.search(searchRequest);EmbeddingMatch<TextSegment>embeddingMatch=searchResult.matches().get(0);System.out.println(embeddingMatch.score());System.out.println(embeddingMatch.embedded().text());七、把 RAG 接入 AIService(医疗智答助手)
7.1 配置ContentRetriever
@BeanContentRetrievercontentRetrieverMedAssistantPinecone(){returnEmbeddingStoreContentRetriever.builder().embeddingModel(embeddingModel).embeddingStore(embeddingStore).maxResults(1).minScore(0.8).build();}7.2 在 Agent 中启用
@AiService(wiringMode=EXPLICIT,chatModel="qwenChatModel",chatMemoryProvider="chatMemoryProviderMedAssistant",tools="appointmentTools",contentRetriever="contentRetrieverMedAssistantPinecone")这样用户提问时,系统会先检索知识库,再让模型基于检索内容回答,实现“有依据”的问答。
八、RAG 调参与踩坑清单
8.1 检索参数
maxResults:太小易漏召回,太大易引噪minScore:太高查不到,太低不相关
8.2 分块参数
- 先固定模型和向量库,再调
chunk size/overlap - 以真实问答集做 A/B 测试,不要只看单条样例
8.3 工程实践建议
- 建立“数据清洗 -> 入库 -> 评测”闭环
- 为每次知识库更新做版本标记
- 保留召回结果日志,便于诊断“答非所问”
九、小结
RAG 在 LangChain4j 中并不复杂,关键是把链路打通并持续调优:
- 文档可读(Loader/Parser)
- 片段可检(Splitter/Embedding)
- 检索可控(Retriever 参数)
- 回答可依(检索结果 + LLM 生成)
对医疗智答助手这类场景而言,RAG 能显著提升回答的专业性、可追溯性和稳定性,是从“能聊”走向“能用”的关键一步。
