Files
blog-press/docs/Web/AI/RAG.md
2026-06-24 09:53:18 +08:00

211 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: RAG开发
date: 2026-06-245
---
# 一、工作流程
```text
原始文档 / 数据
【文档收集与清洗】
【文档切分Chunking
【向量化Embedding
【向量数据库存储】
用户自然语言问题
【检索系统】召回相关知识片段
【上下文组装】构建增强 Prompt
【大模型】基于知识生成回答
【引用 / 校验】
最终返回给用户(答案 + 来源)
```
# 二、实战
## 2.1 资料处理
### 2.1.1 pdf处理
  [PaddleOCR](https://aistudio.baidu.com/paddleocr)是百度飞桨PaddlePaddle团队开源的产业级 OCR光学字符识别与文档智能开发套件。
```python
JOB_URL = "https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
TOKEN = ""
MODEL = "PP-OCRv5"
FILE_URL = ""
HEADERS = {
"Authorization": f"bearer {TOKEN}",
"Content-Type": "application/json",
}
# ========== 提交 OCR 任务 ==========
payload = {
"fileUrl": FILE_URL,
"model": MODEL,
"optionalPayload": {
"useDocOrientationClassify": False,
"useDocUnwarping": False,
"useChartRecognition": False,
},
}
print("🚀 Submitting OCR job...")
resp = requests.post(JOB_URL, json=payload, headers=HEADERS)
resp.raise_for_status()
job_id = resp.json()["data"]["jobId"]
print(f"✅ Job submitted, jobId={job_id}")
# ========== 轮询任务状态 ==========
while True:
r = requests.get(f"{JOB_URL}/{job_id}", headers=HEADERS)
r.raise_for_status()
data = r.json()["data"]
state = data["state"]
if state == "pending":
print("⏳ Job status: pending")
elif state == "running":
prog = data.get("extractProgress", {})
total = prog.get("totalPages")
done = prog.get("extractedPages")
if total and done:
print(f"📄 Processing: {done}/{total} pages")
else:
print("📄 Processing...")
elif state == "done":
prog = data["extractProgress"]
print(
f"✅ Job finished | Pages: {prog['extractedPages']} | "
f"Start: {prog['startTime']} | End: {prog['endTime']}"
)
break
elif state == "failed":
print("❌ Job failed:", data.get("errorMsg", "Unknown error"))
sys.exit(1)
time.sleep(5)
# ========== 获取 OCR 结果 ==========
jsonl_url = data["resultUrl"]["jsonUrl"]
print(f"📥 Fetching result: {jsonl_url}")
resp = requests.get(jsonl_url)
resp.raise_for_status()
```
  这里只处理了url形式的文档实际开发中可以搭建一个管理页面集中处理文档资料。
  获取到的结果是按照区域划分的,还需要进一步的处理:
```python
pages = []
for line in resp.text.strip().splitlines():
if not line.strip():
continue
obj = json.loads(line)
for page in obj.get("result", {}).get("ocrResults", []):
pruned = page.get("prunedResult", {})
texts = pruned.get("rec_texts", [])
# 一页一段
page_text = "\n".join(texts)
pages.append(page_text)
# ✅ 最终文档
full_doc = "\n\n".join(pages)
```
## 2.2 向量化
  使用在线或者离线向量化模型处理:
```python
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每个 chunk 最大长度
chunk_overlap=50, # 重叠,防止切坏语义
separators=["\n\n", "\n", "。", "", "", "", "", " ", ""]
)
chunks = text_splitter.split_text(full_doc)
print(f"✅ 切分成 {len(chunks)} 个 chunk")
for i, chunk in enumerate(chunks):
print(f"\n===== Chunk {i} =====")
print(chunk)
model = SentenceTransformer("BAAI/bge-base-zh", cache_folder="./models")
embeddings = model.encode(
chunks,
normalize_embeddings=True
)
print(f"✅ 向量维度: {embeddings.shape}")
client = chromadb.PersistentClient(path="./vector_db/train_docs")
collection = client.get_or_create_collection(name="train_docs")
for i, (chunk, emb) in enumerate(zip(chunks, embeddings)):
collection.add(
ids=[str(i)],
documents=[chunk],
embeddings=[emb.tolist()]
)
print("✅ 向量库写入完成")
```
  这里使用的是`BAAI/bge-base-zh`模型,第一次会将模型下载到本地。
  将处理结果存储到chroma向量数据库中。
## 2.3 检索系统
```python
model_path = "./models/models--BAAI--bge-base-zh/snapshots/0e5f83d4895db7955e4cb9ed37ab73f7ded339b6"
model = SentenceTransformer(model_path, local_files_only=True)
client = chromadb.PersistentClient(path="./vector_db/train_docs")
collection = client.get_or_create_collection(name="train_docs")
q = "培训计划怎么制定?"
q_emb = model.encode([q], normalize_embeddings=True)
res = collection.query(
query_embeddings=q_emb.tolist(),
n_results=3
)
print("\n\n".join(res["documents"][0]))
```
::: tip
注意这里使用离线模型时的路径
:::
## 2.4 结合大模型
  常用提示词:
```python
你是专业的知识问答助手
请严格基于下方提供的参考资料回答问题
如果参考资料中不包含答案请明确说明当前资料无法回答该问题”。
不要编造推测或引入外部知识
参考资料
"""
{{context}}
"""
用户问题
{{question}}
请按以下要求回答
1. 回答简洁准确有条理
2. 必要时使用列表或分点说明
3. 避免冗余描述
```