微信扫码
添加专属顾问
我要投稿
提高企业RAG准确性的实用指南,助力非结构化数据高效检索。 核心内容: 1. 利用大上下文模型提升语义分块准确性 2. 提取与检索:数据有序化与上下文化的关键步骤 3. PDF文件处理流程及代码实践分享
从PDF文件生成的知识图谱
在我之前的博客中,我写到如何使用像Gemini Flash 2.0这样具有非常大上下文大小的新模型进行语义分块,可以显著提高从非结构化数据(如PDF)中的整体检索准确性。
在探索这一点时,我开始研究其他策略,以进一步提高响应的准确性,因为在大多数大型企业中,对不准确的容忍度几乎为零,并且应该如此。在这个追求中,我最终尝试了许多不同的东西,在这篇博客中,让我们看看最终帮助提升准确性的整体步骤。
在进入步骤之前,让我们从稍高的层面看一下整个过程,并理解为了获得更准确的结果,我们必须在以下两个方面显著做得更好:
现在,让我们看看反映当前项目状态的具体步骤。我在每个步骤中放入了一些伪代码,以使整体文章更易于理解。对于那些寻找代码级具体内容的人,可以查看我的Github仓库,我在其中发布了代码。
当 PDF 进入系统时,需要发生几件事情:它被存储、处理、分块、嵌入,并与结构化知识进行丰富。以下是整个过程的展开:
# 伪代码 save_file_to_disk(pdf) db_insert(document_record, status=”started”) queue_processing_task(pdf)
validate_pdf(pdf)
text = extract_text(pdf)
chunks = semantic_chunking(text) or fallback_chunking(text)
add_overlaps(chunks)
# 伪代码 for chunk in chunks: vector = generate_embedding(chunk.text) db_insert(embedding_record, vector)
# 伪代码 for chunk in chunks: entities, relationships = extract_knowledge(chunk.text) db_insert(entities) db_insert(relationships)
# 伪代码 if success: update_status(“completed”) else: update_status(“failed”) cleanup_partial_data()
当这些步骤完成后,我们现在拥有语义块、相应的嵌入以及在文档中找到的实体和关系,这些都在相互引用的表格中。
我们现在准备好进行下一步,即检索。
现在数据已经结构化并存储,我们需要在用户提问时有效地检索这些数据。系统处理查询,找到相关信息,并生成响应。
query = preprocess_query(query) expanded_query = expand_query(query)
query_vector = generate_embedding(expanded_query) top_chunks = vector_search(query_vector)
text_results = full_text_search(query)
merged_results = merge_and_rank(top_chunks, text_results) filtered_results = filter_low_confidence(merged_results)
# 伪代码 for result in filtered_results: entities, relationships = fetch_knowledge(result) enrich_result(result, entities, relationships)
final_answer = generate_llm_response(filtered_results)
# 伪代码 return_response(final_answer)
现在,关键来了。总体而言,检索过程对我来说大约需要 8 秒,这是不可接受的。
在追踪调用时,我发现最大响应时间来自 LLM 调用(大约 1.5 到 2 秒)。SingleStore 数据库查询始终在 600 毫秒或更短的时间内返回。切换到 Groq 进行一些 LLM 调用后,总体响应时间降至 3.5 秒。我认为如果我们进行一些并行调用而不是串行调用,这可以进一步改善,但那是另一个项目。
最后,关键来了。
鉴于我们正在使用 SingleStore,我想看看是否可以只进行一次查询来完成整个检索,这样不仅更容易管理、更新和改进,而且因为我希望从数据库获得更好的响应时间。这里的假设是 LLM 模型在不久的将来会变得更好、更快,而我无法控制这些(当然,如果你真的对延迟非常认真,可以在同一网络中部署本地 LLM)。
最后,这里是代码(为了方便,单个文件)现在执行单次检索查询。
import os
import json
import mysql.connector
from openai import OpenAI
DB\_CONFIG = {
"host": os.getenv("SINGLESTORE\_HOST", "localhost"),
"port": int(os.getenv("SINGLESTORE\_PORT", "3306")),
"user": os.getenv("SINGLESTORE\_USER", "root"),
"password": os.getenv("SINGLESTORE\_PASSWORD", ""),
"database": os.getenv("SINGLESTORE\_DATABASE", "knowledge\_graph")
}
defget\_query\_embedding(query: str) -\> list:
"""
Generate a 1536-dimensional embedding for the query using OpenAI embeddings API.
"""
client = OpenAI(api\_key=os.getenv("OPENAI\_API\_KEY"))
response = client.embeddings.create(
model="text-embedding-ada-002",
input=query
)
return response.data\[0\].embedding
defretrieve\_rag\_results(query: str) -\> list:
"""
Execute the hybrid search SQL query in SingleStore and return the top-ranked results.
"""
conn = mysql.connector.connect(\*\*DB\_CONFIG)
cursor = conn.cursor(dictionary=True)
query\_embedding = get\_query\_embedding(query)
embedding\_str = json.dumps(query\_embedding)
cursor.execute("SET @qvec = %s", (embedding\_str,))
sql\_query = """
SELECT
d.doc\_id,
d.content,
(d.embedding <\*\> @qvec) AS vector\_score,
MATCH(TABLE Document\_Embeddings) AGAINST(%s) AS text\_score,
(0.7 \* (d.embedding <\*\> @qvec) + 0.3 \* MATCH(TABLE Document\_Embeddings) AGAINST(%s)) AS combined\_score,
JSON\_AGG(DISTINCT JSON\_OBJECT(
'entity\_id', e.entity\_id,
'name', e.name,
'description', e.description,
'category', e.category
)) AS entities,
JSON\_AGG(DISTINCT JSON\_OBJECT(
'relationship\_id', r.relationship\_id,
'source\_entity\_id', r.source\_entity\_id,
'target\_entity\_id', r.target\_entity\_id,
'relation\_type', r.relation\_type
)) AS relationships
FROM Document\_Embeddings d
LEFT JOIN Relationships r ON r.doc\_id = d.doc\_id
LEFT JOIN Entities e ON e.entity\_id IN (r.source\_entity\_id, r.target\_entity\_id)
WHERE MATCH(TABLE Document\_Embeddings) AGAINST(%s)
GROUP BY d.doc\_id, d.content, d.embedding
ORDER BY combined\_score DESC
LIMIT 10;
"""
cursor.execute(sql\_query, (query, query, query))
results = cursor.fetchall()
cursor.close()
conn.close()
return results
正如你所想,进行“简单的” RAG 与你的 pdf 聊天是一回事,而在保持低延迟的同时实现超过 80% 的准确率又是另一回事。现在再加入结构化数据,你已经深入到一个项目中,这几乎成了一份全职工作 ?
我计划继续调整和改进,并为这个项目写博客,短期内,我正在寻找一些接下来要探索的想法。
提取:
检索
在许多方面,我记录这些内容是为了提醒自己在构建企业级 RAG 或 KAG 时需要考虑的企业需求。如果作为读者的你发现我做的一些事情非常幼稚,或者有其他想法可以改进我,请随时在这里或在 LinkedIn 上与我联系,以便我们可以一起合作
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-04-21
改进RAG:利用混合搜索与重排序优化检索效果(含代码示例)
2025-04-21
检索增强生成(RAG)深度教程
2025-04-21
MCP 实践:基于 MCP 架构实现知识库答疑系统
2025-04-20
谈谈RAG 的四个级别
2025-04-20
大模型能像专业分析师一样提取用户需求吗?
2025-04-19
基于Embedding分块 - 文本分块(Text Splitting),RAG不可缺失的重要环节
2025-04-19
RAG升级-基于知识图谱+deepseek打造强大的个人知识库问答机器人
2025-04-19
RAG vs. CAG vs. Fine-Tuning:如何为你的大语言模型选择最合适的“脑力升级”?
2024-10-27
2024-09-04
2024-07-18
2024-05-05
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-04-20
2025-04-19
2025-04-18
2025-04-16
2025-04-14
2025-04-13
2025-04-11
2025-04-09