| 方案 | 一句话概括 | 更新成本 | 实时性 | 适合场景 |
|---|---|---|---|---|
| 微调 | 把私域数据重新训一遍 | 高 | 差 | 知识库稳定、文风要求极高 |
| RAG | 临时把相关知识塞给模型 | 低 | 好 | 知识高频迭代、客服/法规/医疗 |
| RAG+微调 | 先微调打底,再 RAG 补新 | 极高 | 中 | 头部企业才玩得起 |
一、LLM 的「专业盲区」
flowchart LR
A[索引阶段] --> B[检索阶段]
A1[加载文档] --> A2[文本分段] --> A3[Embedding] --> A4[写向量库]
B1[用户提问] --> B2[转向量] --> B3[TopK 召回] --> B4[拼接上下文 --> LLM]
二、RAG 的 2 个阶段
如何让大模型听懂你的专业黑话------RAG 与向量搜索全景解析
2.1 索引阶段(离线)
-
文档加载
LangChain4j 内置 10+
DocumentLoader:本地、S3、GitHub、网页抓取... -
分段
按段落 / 句子 / token 切,重叠 20% 保语义连贯;每段 ≤ 模型最大窗口的 1/2。
-
向量化
调用嵌入模型(text-embedding-v3、ada-002 等)→ 1024/1536 维向量。
-
写库
向量数据库:Pinecone、Weaviate、Qdrant、ES8.x、MongoDB Atlas 等。
2.2 检索阶段(在线)
-
用户问题 → 同一嵌入模型 → 向量。
-
余弦相似度取 TopK(K=4~10)。
-
把原始文本片段当上下文,连同问题一起喂给 LLM。
-
LLM 生成带出处、带时间戳的最终答案。
三、向量搜索的 4 种相似度度量
| 名称 | 公式 | 特点 |
|-----------|-------------------------|---------------|---|------------|
| 余弦相似度 | cosθ = A·B / (‖A‖*‖B‖) | 只关注方向,最常用 |
| 欧氏距离 | √Σ(ai-bi)² | 方向+绝对距离 |
| 点积 | Σ(ai*bi) | 未归一化,受模长影响大 |
| 曼哈顿距离 | Σ | ai-bi | | 计算快,适合高维稀疏 |
生产经验:余弦 0.8 以上的片段再送 LLM,可过滤 60% 噪声。
四、LangChain4j 一站式实现(Java 代码)
4.1 加依赖
<!--大模型-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<!--PDF 解析-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
</dependency>
<!--向量存储-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-pinecone</artifactId>
</dependency>
4.2 写配置
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
community:
dashscope:
embedding-model:
api-key: ${DASH_SCOPE_API_KEY}
model-name: text-embedding-v3 # 1024 维
4.3 索引管道(一次运行,永久生效)
@Component
public class Indexer {
@Autowired EmbeddingModel embeddingModel;
public void build() {
List<Document> docs = FileSystemDocumentLoader.loadDocumentsRecursively(
"E:/knowledge", // 放 PDF/MD/TXT
new ApachePdfBoxDocumentParser()
);
PineconeEmbeddingStore store = PineconeEmbeddingStore.builder()
.apiKey(System.getenv("PINECONE_API_KEY"))
.index("hospital-index")
.nameSpace("outpatient")
.createIndex(PineconeServerlessIndexConfig.builder()
.cloud("AWS")
.region("us-east-1")
.dimension(1024)
.build())
.build();
EmbeddingStoreIngestor.ingest(docs, store); // 一键分段+向量化+写库
}
}
4.4 检索 + 问答(在线)
@AiService(wiringMode = EXPLICIT,
chatModel = "qwenChatModel",
contentRetriever = "hospitalRetriever")
public interface MedicalAgent {
String chat(@UserMessage String question);
}
@Configuration
public class RagConfig {
@Bean
ContentRetriever hospitalRetriever(EmbeddingModel em,
EmbeddingStore<TextSegment> store) {
return EmbeddingStoreContentRetriever.builder()
.embeddingModel(em)
.embeddingStore(store)
.maxResults(4) // Top4 片段
.minScore(0.8) // 余弦阈值
.build();
}
}
五、效果 & 调优秘籍
| 参数 | 推荐值 | 备注 |
|---|---|---|
| 分段大小 | 300~600 token | 看模型窗口,留 50% 余量 |
| 重叠 | 30~50 token | 平衡连贯 vs 冗余 |
| TopK | 4~10 | 过多 >10 易超 token 上限 |
| 余弦阈值 | 0.75~0.85 | 医疗/法律建议 ≥0.8 |
| 嵌入模型 | text-embedding-v3 / ada-002 | 中文用阿里,英文用 OpenAI |
六、常见坑 & 排查清单
-
PDF 是扫描图 → 先用 OCR(Tesseract/腾讯云 OCR)再丢给解析器。
-
Table 表格丢失 → 用
ApacheTikaDocumentParser或Camelot先抽表。 -
召回为空 → 检查分段是否过碎 / 向量维度是否不一致 / 索引空间写错。
-
答案幻觉 → 把
minScore调高 + 在提示词里加"若上下文无法回答,请明确拒绝"。
七、一句话总结
把私域数据切成块 → 变成向量 → 放数据库 → 用户问题实时找最像的块 → 塞给 LLM → 秒级生成专业答案。
RAG 不是银弹,却是 90% 企业让大模型"说人话、说行话"的最短路径。