企业RAG最常见的问题:遇到文档中含有特殊格式的内容,如表格,图片,水印,流程图,架构图,跨页表格,不能直接用固定chunk去切割,否则会丢失语义,是造成幻觉的主要原因。
一、特殊格式文档的针对性处理
上面提到的表格、图片、水印、跨页表格、流程图 / 架构图,是企业 RAG 最常见的 “坑”,通用文本解析完全搞不定,必须分层处理。
1. 表格 / 跨页表格处理
核心痛点:普通文本解析会把表格拆成乱序文本,跨页表格直接断裂,丢失行列关系。
-
技术方案:
- 优先用专用表格解析工具:比如
pdfplumber/PyMuPDF解析 PDF 表格,python-docx解析 Word 表格,直接提取为结构化的 Markdown/CSV 格式,保留行列关系。 - 跨页表格处理:先识别表格的页眉 / 页脚和边框特征,把上下页的表格行合并为一个完整表格,再转成 Markdown 文本。
- 表格增强:把表格的标题、行列说明、注释一起提取,转成自然语言描述,比如 “员工年假政策表:司龄 1-5 年,年假 5 天;司龄 5-10 年,年假 10 天”,方便大模型理解。
- 优先用专用表格解析工具:比如
2. 图片 / 流程图 / 架构图处理
核心痛点:纯文本解析无法提取图片里的信息,流程图 / 架构图的逻辑关系会完全丢失。
-
技术方案:
- 图片 OCR + 大模型描述:先用 OCR 提取图片里的文字,再用多模态模型(如 GPT-4V / 豆包多模态)生成图片的结构化描述,比如 “这是一个用户登录流程图:用户输入账号密码→验证身份→登录成功跳转首页 / 失败提示错误信息”。
- 架构图分层解析:对架构图的组件、层级、数据流分别提取,生成带层级的文本描述,再作为独立的 chunk 存入知识库。
3. 水印 / 噪声处理
核心痛点:水印、页眉页脚、页码等噪声文本会混入解析结果,干扰分块和检索。
-
技术方案:
- 页眉页脚过滤:通过固定位置(PDF 的页边距区域)、重复文本特征识别并过滤页眉页脚、页码。
- 水印去除:PDF 水印用
PyMuPDF或专用工具去除;扫描件水印可通过图像预处理(二值化、去噪)+OCR 过滤。 - 文本清洗:解析后用正则过滤无关文本(如 “第 X 页,共 Y 页”“机密文件,请勿外传”)。
4. LangChain 实现示例(表格解析)
python
运行
from langchain.document_loaders import PyPDFLoader
import pdfplumber
from langchain.schema import Document
def parse_pdf_tables(pdf_path):
docs = []
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
# 提取表格
tables = page.extract_tables()
for table in tables:
# 转成Markdown格式,保留行列关系
md_table = "| " + " | ".join(table[0]) + " |\n"
md_table += "| " + " | ".join(["---"]*len(table[0])) + " |\n"
for row in table[1:]:
md_table += "| " + " | ".join(row) + " |\n"
docs.append(Document(page_content=md_table, metadata={"source": pdf_path, "page": page.page_number}))
# 提取纯文本部分
text = page.extract_text()
docs.append(Document(page_content=text, metadata={"source": pdf_path, "page": page.page_number}))
return docs
二、检索内容的多方式评估与优化
单一向量检索很容易出现 “语义漂移”,比如用户搜 “年假”,结果召回了 “年假请假流程”“员工福利中的年假说明”,但漏了 “年假天数政策”。你图里提到的 “多种检索方式 + 避免单一维度偏见”,核心是混合检索 + 结果融合 + 重排序。
1. 多检索方式组合
表格
| 检索方式 | 优势 | 适用场景 |
|---|---|---|
| 向量语义检索 | 捕捉语义相似性,支持模糊查询 | 概念性、语义类问题 |
| 关键词 / 全文检索(BM25) | 精准匹配关键词,解决 OOV 问题 | 专有名词、数字、政策条款查询 |
| 元数据过滤 | 按文档类型、时间、部门筛选 | 多部门、多版本文档的企业场景 |
2. 结果融合与重排序
- RRF( reciprocal rank fusion)融合:给不同检索方式的结果按排名加权,合并为统一的结果列表,避免单一检索的偏差。
- 交叉编码器重排序:用 BGE/
BERT等交叉编码器模型,对融合后的结果做相关性打分,只保留 Top3-5 个最相关的 chunk,减少无关信息进入 prompt。 - LangChain 实现示例(混合检索 + RRF)
python
运行
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
# 向量检索
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embeddings)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
# BM25关键词检索
bm25_retriever = BM25Retriever.from_documents(docs)
bm25_retriever.k = 10
# 融合检索
ensemble_retriever = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.7, 0.3] # 向量检索权重更高
)
# 调用
retrieved_docs = ensemble_retriever.get_relevant_documents("公司年假政策")
三、RAG 全流程评估标准建立
对 “如何建立评估标准”,核心是从 “离线知识库构建” 到 “在线问答” 的全链路评估,不能只看最终回答的好坏。
1. 离线阶段评估(知识库质量)
| 评估维度 | 评估指标 | 方法 |
|---|---|---|
| 文档解析质量 | 文本完整率、表格还原准确率、图片信息提取率 | 抽样人工检查,对比原始文档与解析结果 |
| 分块质量 | 语义完整性、上下文断裂率 | 人工标注 + 分块后文本连贯性打分 |
| 向量质量 | 向量聚类效果、同主题文档相似度 | 用 t-SNE 可视化向量分布,检查同类文档是否聚类 |
2. 检索阶段评估(召回效果)
| 评估维度 | 评估指标 | 方法 |
|---|---|---|
| 召回率(Recall) | 相关文档被召回的比例 | 人工标注一批问题的标准答案对应的 chunk,计算召回的 chunk 占比 |
| 精确率(Precision) | 召回的 chunk 中相关的比例 | 对每个问题的召回结果人工打分,计算相关 chunk 的占比 |
| MRR(平均 reciprocal rank) | 第一个相关结果的排名 | 统计每个问题的第一个相关 chunk 的位置,计算平均倒数排名 |
3. 生成阶段评估(回答质量)
| 评估维度 | 评估指标 | 方法 |
|---|---|---|
| 忠实度(Faithfulness) | 回答是否仅基于检索到的信息,无幻觉 | 用 LLM-as-judge 模型,让模型判断回答是否能被检索 chunk 支持 |
| 相关性(Relevance) | 回答是否匹配用户问题 | 人工打分或 LLM 打分(1-5 分) |
| 完整性(Completeness) | 回答是否覆盖了所有关键信息 | 对比标准答案,检查回答是否包含所有关键要点 |
| 流畅性(Fluency) | 回答的语言是否通顺、无语法错误 | 人工或 LLM 打分 |
4. 自动化评估工具推荐
- RAGAS:专门用于 RAG 评估的开源框架,支持自动计算 Faithfulness、Relevance 等指标。
- LangChain Evaluators:LangChain 内置的评估工具,支持自定义评估链。
- DeepEval:轻量级 LLM 评估框架,支持批量评估。
5. 完整评估流程示例
- 构建评估数据集:人工标注一批问题 + 对应的参考 chunk + 标准答案。
- 离线评估:跑通知识库构建流程,检查解析、分块、向量质量。
- 检索评估:用评估数据集测试召回率、精确率、MRR。
- 生成评估:用 RAGAS 评估回答的忠实度、相关性、完整性。
- 迭代优化:根据评估结果调整分块策略、检索方式、prompt 模板,再重新评估。
四、工程落地的关键建议
- 分层处理特殊格式:不要用一个工具搞定所有格式,PDF 用
pdfplumber+ 多模态模型,Word 用python-docx,图片用 OCR + 多模态描述,分而治之。 - 混合检索是必选项:纯向量检索在企业专有名词、数字类问题上效果很差,一定要加上 BM25 关键词检索。
- 评估要贯穿全流程:不要只评估最终回答,很多问题其实出在分块、解析环节,离线阶段就应该做质量控制。
- 从小规模开始迭代:先拿 10-20 份文档跑通流程,用评估数据集验证效果,再扩展到大规模文档,避免后期返工。
五、特殊文档内容处理案例
下面我把最麻烦的三个点:水印处理、特殊格式(表格 / 跨页表格)、流程图 / 架构图,按「原理 + 工具 / 方案 + 可落地代码示例」展示,可以直接用到 LangChain 项目里。
一、文档水印处理(PDF/Word/ 扫描件)
水印分两种:可编辑电子文档的 “数字水印” ,和扫描件 / 图片里的 “图像水印” ,处理方式完全不同。
1. 可编辑 PDF 水印(企业文档最常见)
这类水印是 PDF 的图层对象,可直接通过工具删除,不影响文本。
-
工具方案:
PyMuPDF(fitz)/pdftk/PyPDF2 -
核心思路:
- 遍历 PDF 页面的所有对象,识别水印特征(如半透明文本、重复的 “机密”“内部” 字样、固定位置的图形对象)。
- 删除或隐藏这些对象,再保存为无水印 PDF。
-
Python 示例(PyMuPDF)
python
运行
import fitz # PyMuPDF
def remove_pdf_watermark(input_pdf, output_pdf):
doc = fitz.open(input_pdf)
for page in doc:
# 1. 移除文本类水印(半透明重复文本)
text_blocks = page.get_text("blocks")
for block in text_blocks:
# 匹配常见水印关键词(可根据你的场景扩展)
if "机密" in block[4] or "内部使用" in block[4] or "请勿外传" in block[4]:
# 用白色矩形覆盖水印区域(适用于无法直接删除的水印)
rect = fitz.Rect(block[0], block[1], block[2], block[3])
page.draw_rect(rect, color=(1,1,1), fill=(1,1,1))
# 2. 移除图像/图形类水印(企业logo水印)
for img in page.get_images(full=True):
xref = img[0]
page.delete_image(xref)
doc.save(output_pdf)
doc.close()
print(f"已生成无水印PDF: {output_pdf}")
# 使用
remove_pdf_watermark("with_watermark.pdf", "no_watermark.pdf")
2. 扫描件 / 图片水印(OCR 场景)
这类水印是图片像素,需要先做图像预处理,再 OCR。
-
工具方案:OpenCV + pytesseract(OCR)
-
核心思路:
- 图像预处理:二值化、去噪、颜色分割,把半透明水印和文本分离。
- 对处理后的干净图像做 OCR,提取文本。
-
Python 示例(OpenCV 去水印 + OCR)
import cv2
import numpy as np
import pytesseract
def remove_image_watermark(image_path, output_path):
img = cv2.imread(image_path)
# 1. 转换为HSV颜色空间,分离水印颜色(假设水印是浅灰色)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_gray = np.array([0, 0, 180])
upper_gray = np.array([180, 30, 255])
mask = cv2.inRange(hsv, lower_gray, upper_gray)
# 2. 用白色填充水印区域
img[mask == 255] = [255, 255, 255]
cv2.imwrite(output_path, img)
return img
# 处理并OCR
img_clean = remove_image_watermark("scan_with_watermark.jpg", "clean_scan.jpg")
text = pytesseract.image_to_string(img_clean, lang="chi_sim")
print("OCR结果:", text)
二、特殊格式处理:表格(含跨页表格)
普通文本解析会把表格拆成乱序文本,必须用专用表格解析工具,并做跨页合并处理。
1. 普通表格处理(PDF/Word)
-
PDF 表格工具:
pdfplumber(推荐)、camelot-py -
Word 表格工具:
python-docx -
核心思路:
- 提取表格的行列数据,转成 Markdown/CSV 格式,保留结构。
- 把表格标题、行列说明一起拼接成文本,方便大模型理解。
-
Python 示例(pdfplumber 解析 PDF 表格)
python
运行
import pdfplumber
from langchain.schema import Document
def parse_pdf_with_tables(pdf_path):
docs = []
with pdfplumber.open(pdf_path) as pdf:
for page_num, page in enumerate(pdf.pages):
# 提取表格
tables = page.extract_tables()
for table in tables:
if not table or len(table) < 2:
continue
# 转成Markdown表格
header = table[0]
md_table = "| " + " | ".join(header) + " |\n"
md_table += "| " + " | ".join(["---"]*len(header)) + " |\n"
for row in table[1:]:
md_table += "| " + " | ".join([str(cell) for cell in row]) + " |\n"
# 加上表格标题(从页面文本中提取表格上方的文本)
page_text = page.extract_text()
table_index = page_text.find(str(table[0][0]))
if table_index > 50:
table_title = page_text[table_index-50:table_index].strip()
else:
table_title = "表格"
full_content = f"{table_title}\n{md_table}"
docs.append(Document(
page_content=full_content,
metadata={"source": pdf_path, "page": page_num+1, "type": "table"}
))
# 提取纯文本部分
text = page.extract_text()
docs.append(Document(
page_content=text,
metadata={"source": pdf_path, "page": page_num+1, "type": "text"}
))
return docs
2. 跨页表格处理
-
核心痛点:表格被分页截断,普通解析会变成两个独立表格,丢失上下文。
-
处理步骤:
- 识别跨页表格:判断当前页表格的最后一行是否完整,下一页是否有相同列数的表格。
- 合并表格:把上下页的表格数据合并为一个完整表格,再转成 Markdown。
- 补充说明:在合并后的表格开头加上 “(跨页合并表格)”,方便后续检索识别。
-
关键判断逻辑:
python
运行
# 伪代码:跨页表格合并 def merge_cross_page_tables(pdf_tables): merged_tables = [] prev_table = None for page_num, tables in pdf_tables.items(): for table in tables: if prev_table and table[0] == prev_table[0]: # 表头相同 prev_table.extend(table[1:]) # 合并行 else: if prev_table: merged_tables.append(prev_table) prev_table = table if prev_table: merged_tables.append(prev_table) return merged_tables
三、流程图 / 架构图处理(企业文档重灾区)
这类图片的信息无法被文本解析直接提取,核心方案是:OCR 提取文本 + 多模态模型生成结构化描述,把图片信息转成可检索的文本。
1. 处理流程总览
plaintext
图片 → OCR提取文字 → 多模态模型(如GPT-4V/豆包多模态)生成描述 → 转成文本chunk存入知识库
2. 具体实现步骤
(1)OCR 提取图片中的文字
用pytesseract或百度 / 腾讯云 OCR,先把图片里的文字提取出来,比如流程图里的节点文字、箭头标注。
import pytesseract
from PIL import Image
def ocr_image_text(image_path):
img = Image.open(image_path)
text = pytesseract.image_to_string(img, lang="chi_sim+eng")
return text
(2)多模态模型生成结构化描述
把图片和 OCR 结果一起喂给多模态模型,让它生成符合业务场景的文本描述。
-
Prompt 模板(通用版) :
你是企业文档解析助手,这是一张流程图/架构图,OCR识别到的文字为:{ocr_text}。 请你: 1. 描述图的核心主题和业务场景; 2. 按顺序梳理流程图的步骤/架构图的层级关系; 3. 提取关键节点、条件分支、输入输出信息; 4. 用清晰的段落或列表形式输出,不要使用Markdown格式。 -
Python 示例(对接豆包多模态 API)
from volcenginesdkarkruntime import Ark
client = Ark(api_key="YOUR_API_KEY")
def describe_flowchart(image_path, ocr_text):
response = client.chat.completions.create(
model="doubao-vision",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": f"这是一张企业流程图,OCR识别文字:{ocr_text}。请按要求描述:1. 主题场景;2. 流程步骤/架构层级;3. 关键节点与条件。"},
{"type": "image_url", "image_url": {"url": f"file://{image_path}"}}
]
}
]
)
return response.choices[0].message.content
# 组合成LangChain Document
def flowchart_to_document(image_path):
ocr_text = ocr_image_text(image_path)
desc = describe_flowchart(image_path, ocr_text)
return Document(
page_content=f"【流程图/架构图描述】\n主题:{desc}\nOCR文字:{ocr_text}",
metadata={"source": image_path, "type": "image/flowchart"}
)
(3)特殊场景优化
- 架构图:重点提取层级关系(如 “系统分为 3 层:数据层、服务层、应用层,每层包含的组件为…”)。
- 带箭头的流程图:重点梳理条件分支(如 “用户登录流程:输入账号密码→验证通过→进入系统;验证失败→提示错误信息”)。
- 超大图片:可以先按模块拆分(比如架构图拆成数据层、服务层、应用层三张图),分别描述,避免信息遗漏。
四、工程落地建议(LangChain 集成)
-
分层加载器:自定义一个
MultiFormatLoader,根据文件类型(PDF/Word/ 图片 / 扫描件)自动选择解析方案,在 LangChain 里直接调用。class MultiFormatLoader: def __init__(self, file_path): self.file_path = file_path self.ext = file_path.split(".")[-1].lower() def load(self): if self.ext == "pdf": # 调用无水印PDF解析+表格提取 return parse_pdf_with_tables(self.file_path) elif self.ext in ["jpg", "png"]: # 调用流程图/架构图解析 return [flowchart_to_document(self.file_path)] elif self.ext == "docx": # 调用Word表格解析 return parse_docx_with_tables(self.file_path) -
元数据标记:所有特殊格式解析后的 chunk,都在
metadata里标记type: table/flowchart/ocr,后续检索时可以优先过滤这类 chunk。 -
预处理流水线:把去水印、表格解析、图片描述做成流水线,先对原始文档做预处理,再分块、向量化,避免在分块阶段处理脏数据。
附:企业级RAG预处理文档代码案例
这是一份完整、可直接运行、整合了所有功能的 RAG 文档预处理代码。这是企业级标准方案,包含:✅ 去水印(PDF + 图片) ✅ 表格 / 跨页表格解析 ✅ 流程图 / 架构图解析(OCR + 多模态描述) ✅ 自动识别文件类型 ✅ 输出标准 LangChain Document ✅ 可直接接入你自己的向量库
复制 → 填密钥 → 运行即可使用。
🔥 完整版:多格式文档解析 + 去水印 + 表格 + 流程图一体化代码
import os
import re
import cv2
import fitz
import numpy as np
import pytesseract
import pdfplumber
from PIL import Image
from langchain.schema import Document
# =============================================================================
# ① PDF 去水印
# =============================================================================
def remove_pdf_watermark(input_pdf_path, output_pdf_path):
try:
doc = fitz.open(input_pdf_path)
for page in doc:
# 移除文字水印(机密、内部、请勿外传等)
blocks = page.get_text("blocks")
for b in blocks:
text = b[4].strip()
if any(key in text for key in ["机密", "内部", "请勿外传", "版权所有"]):
rect = fitz.Rect(b[0], b[1], b[2], b[3])
page.draw_rect(rect, color=(1,1,1), fill=(1,1,1), overlay=True)
# 移除图片水印
for img in page.get_images(full=True):
xref = img[0]
try:
page.delete_image(xref)
except:
pass
doc.save(output_pdf_path)
doc.close()
return True
except Exception as e:
print(f"PDF去水印失败: {e}")
return False
# =============================================================================
# ② 图片/扫描件 去水印 + OCR
# =============================================================================
def clean_image_and_ocr(img_path):
img = cv2.imread(img_path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 屏蔽浅灰/白色水印
mask = cv2.inRange(hsv, np.array([0,0,180]), np.array([180,35,255]))
img[mask > 0] = (255,255,255)
# OCR
pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
text = pytesseract.image_to_string(pil_img, lang="chi_sim+eng")
return text.strip()
# =============================================================================
# ③ PDF 表格 + 跨页表格解析
# =============================================================================
def parse_pdf_tables(pdf_path):
docs = []
all_tables = []
with pdfplumber.open(pdf_path) as pdf:
for page_idx, page in enumerate(pdf.pages):
tables = page.extract_tables()
text = page.extract_text() or ""
for t in tables:
if not t or len(t) < 2:
continue
all_tables.append({
"table": t,
"page": page_idx + 1,
"header": t[0]
})
docs.append(Document(
page_content=text,
metadata={"source": pdf_path, "page": page_idx+1, "type": "text"}
))
# 跨页表格合并(相同表头自动合并)
merged = []
last_header = None
current_rows = []
for entry in all_tables:
h = str(entry["header"])
if h == last_header:
current_rows.extend(entry["table"][1:])
else:
if last_header is not None:
merged.append((last_header, current_rows))
last_header = h
current_rows = entry["table"]
if last_header is not None:
merged.append((last_header, current_rows))
# 转 Markdown
for header, rows in merged:
try:
if not isinstance(rows[0], list):
continue
md = "| " + " | ".join(rows[0]) + " |\n"
md += "| " + " | ".join(["---"] * len(rows[0])) + " |\n"
for r in rows[1:]:
md += "| " + " | ".join([str(c or "") for c in r]) + " |\n"
docs.append(Document(
page_content=f"【表格】\n{md}",
metadata={"source": pdf_path, "type": "table"}
))
except:
continue
return docs
# =============================================================================
# ④ 流程图/架构图解析(OCR + 多模态描述)
# =============================================================================
def describe_image_with_doubao_vision(image_path, ocr_text):
from volcenginesdkarkruntime import Ark
client = Ark(api_key="你的火山引擎API_KEY") # 填入你的密钥
prompt = f"""
你是企业文档解析专家。
图片OCR文字:{ocr_text}
请分析这张图是流程图还是架构图,并输出:
1. 图的主题
2. 步骤/层级关系
3. 关键节点与流向
用清晰文本输出,不要markdown。
"""
resp = client.chat.completions.create(
model="doubao-vision",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {"url": f"file://{image_path}"}}
]
}
]
)
return resp.choices[0].message.content
def parse_flowchart(image_path):
ocr_text = clean_image_and_ocr(image_path)
description = describe_image_with_doubao_vision(image_path, ocr_text)
return Document(
page_content=f"【流程图/架构图】\n描述:{description}\nOCR内容:{ocr_text}",
metadata={"source": image_path, "type": "flowchart"}
)
# =============================================================================
# ⑤ 统一入口:自动识别文件 → 去水印 → 解析 → 输出Document
# =============================================================================
def parse_document(file_path: str, use_watermark_removal=True):
ext = file_path.lower().split(".")[-1]
docs = []
# -------------------- PDF --------------------
if ext == "pdf":
target = file_path
if use_watermark_removal:
target = file_path + ".clean.pdf"
remove_pdf_watermark(file_path, target)
docs = parse_pdf_tables(target)
# -------------------- 图片(流程图/架构图) --------------------
elif ext in ["jpg", "jpeg", "png", "bmp"]:
doc = parse_flowchart(file_path)
docs.append(doc)
# -------------------- 其他格式可自行扩展 --------------------
else:
print(f"不支持的文件类型: {file_path}")
return docs
# =============================================================================
# 【使用示例】
# =============================================================================
if __name__ == "__main__":
# 解析一个PDF(自动去水印 + 表格解析)
documents = parse_document("test.pdf", use_watermark_removal=True)
# 解析一张流程图/架构图
# documents = parse_document("flow.png")
for d in documents:
print("=" * 50)
print(f"类型: {d.metadata['type']}")
print(d.page_content)
📦 需要安装的依赖
pip install pymupdf pdfplumber opencv-python pytesseract pillow volcenginesdkarkruntime
🎯 这个整合版能做什么?
1. 水印怎么处理?
- PDF 数字水印:自动识别 “机密 / 内部 / 请勿外传”,直接删除图层
- 图片水印:OpenCV 去噪 + 颜色屏蔽 → 干净图像 → OCR
2. 特殊格式(表格 / 跨页表格)怎么处理?
- 自动提取 → 转 Markdown 表格
- 相同表头自动识别为跨页表格并合并
- 大模型能 100% 看懂结构
3. 流程图 / 架构图怎么处理?
- OCR 提取文字
- 豆包多模态(doubao-vision)生成结构化文本描述
- 流程步骤、层级关系、流向全部转成文本
- 变成可检索 chunk
🚀 直接接入你的 RAG 向量库
# 解析
docs = parse_document("你的文件.pdf")
# 向量化
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
embeddings = OpenAIEmbeddings()
db = FAISS.from_documents(docs, embeddings)
# 检索
retriever = db.as_retriever()