1,377
社区成员
发帖
与我相关
我的任务
分享
假设一家制造企业有5000份技术文档。
员工问:
“某型号设备出现E103报警应该怎么处理?”
即使大模型掌握大量通用知识,也不一定看过这家企业自己的设备说明书。
比较直接的方案是:
把相关说明书找到,然后交给模型阅读。
这其实就是RAG最核心的思想。
flowchart LR
A[用户问题] --> B[知识检索]
B --> C[找到相关文档]
C --> D[问题+文档]
D --> E[大语言模型]
E --> F[答案]
典型RAG包含五个核心组件。
负责加载:
长文档不能直接全部交给模型,因此需要切成较小的Chunk。
例如:
一份100页PDF
↓
Chunk 001
Chunk 002
Chunk 003
...
Chunk 560
Embedding会将文本转换成向量。
例如:
"NX草图如何添加尺寸约束?"
→
[0.13, -0.21, 0.87, ..., 0.34]
含义相似的文本,在向量空间中的距离通常也更加接近。
负责保存Embedding。
常见方案包括:
FAISS
Milvus
Qdrant
Chroma
Elasticsearch
最后将检索结果作为上下文,让模型生成答案。
flowchart TD
A[PDF/Word/数据库] --> B[数据清洗]
B --> C[文本切块]
C --> D[Embedding]
D --> E[(Vector DB)]
F[用户问题] --> G[Query Embedding]
G --> H[相似度检索]
E --> H
H --> I[Top-K文档]
I --> J[Prompt构造]
F --> J
J --> K[LLM]
K --> L[最终答案]
这里实际上分成两个阶段:
文档 → 切块 → Embedding → 数据库
通常只需要在文档发生变化时重新执行。
用户问题 → 检索 → LLM → 回答
每次用户提问都会执行。
下面用伪代码表示整个过程:
def rag(question):
# 1. 将问题向量化
query_vector = embedding(question)
# 2. 搜索知识库
documents = vector_db.search(
query_vector,
top_k=5
)
# 3. 拼接上下文
context = "\n".join(documents)
# 4. 构造Prompt
prompt = f"""
请根据以下资料回答问题。
资料:
{context}
问题:
{question}
"""
# 5. 调用大模型
answer = llm(prompt)
return answer
真正的工程系统当然会更加复杂,但核心思路基本如此。
很多人第一次搭建RAG,会遇到一个问题:
系统明明检索到了资料,模型为什么还是回答不好?
原因往往并不在LLM。
一段文本中包含太多信息,语义不够集中。
上下文被切得过碎。
例如:
Chunk1:该设备最大转速为
Chunk2:12000rpm。
单独检索Chunk1就失去了核心信息。
检索1条可能遗漏信息。
检索30条又可能把大量噪声送给模型。
医学、法律、机械制造等领域具有大量专业术语,通用Embedding模型未必表现最佳。
一个高质量RAG系统需要不断优化:
flowchart LR
A[Query] --> B[Query Rewrite]
B --> C[Hybrid Search]
C --> D[Reranker]
D --> E[Context Compression]
E --> F[LLM]
F --> G[Answer]
可以增加:
因此,RAG真正的技术门槛往往不是“调用一次Embedding API”,而是:
怎样构建一条高质量的知识检索流水线。
RAG最大的意义,是把大模型从:
“依靠自己记忆回答”
转变成:
“先查询真实资料,再组织答案”。
对于企业知识库、智能客服、科研助手、法律助手和工业知识问答而言,RAG依然是非常重要的大模型知识协同方案。