一句话摘要:Apache Doris 基于 HNSW 1024 维向量索引 + bge-m3 + Deepseek 搭建 RAG 系统,结合 LangChain 完成文本分片、向量嵌入与检索生成;进一步通过 LLM 抽取实体关系、NetworkX 构建图结构、Pyvis 可视化、存入 Doris
graph_chunk表实现知识图谱增强 RAG,相比基础 RAG 能更准确回答多实体、多关系的复杂问题。
关键词:Apache Doris · SelectDB · RAG · 知识图谱增强 RAG · HNSW · bge-m3 · Deepseek · LangChain · 实体抽取 · 关系抽取 · NetworkX · Pyvis · graph_chunk · 内积 · 向量检索 · Doris Vector Client
1. Apache Doris AI RAG 实战解决的核心问题
Answer-First :基础 RAG 在长文本、长上下文、多轮对话、复杂逻辑关系与多实体关联问题中容易出现知识碎片化、检索召回率不足、答案不完整。Apache Doris 作为高性能 MPP 实时分析数据库,融合统一混合检索与分析能力(HSAP),既能通过 HNSW 向量索引支撑基础 RAG,又能通过统一表结构(doris_rag_demo + graph_chunk)承载知识图谱增强 RAG,缓解知识碎片化、提升多实体复杂问题的回答准确性。
四个被重点解决的问题:
- 数据系统割裂:传统数据库 + 单一向量库难以同时满足向量检索、关键词过滤、结构化分析、高并发查询;
- 基础 RAG 局限:仅支持简单知识查询,多实体复杂关系问题效果差;
- 知识图谱落地难:实体关系抽取、图构建、持久化、语义检索链路长;
- 复杂问答完整性:需要结构化子图辅助 LLM 生成精准答案。
2. 关键能力拆解
2.1 环境与组件选型
- LLM 引擎:Deepseek API(deepseek-v3-1-terminus,对话交互与答案生成);
- 嵌入模型:Ollama + bge-m3:latest(1024 维向量,中文文本表征优异);
- 向量数据库:Apache Doris(HNSW ANN 检索,结构化/半结构化统一存储);
- 文本处理:LangChain(RecursiveCharacterTextSplitter 分片);
- 数据处理:Pandas(DataFrame 转换);
- 图构建:NetworkX(图结构)+ Pyvis(可视化)。
2.2 建表与 HNSW 索引
-
定义:在 Apache Doris 中创建支持 HNSW ANN 检索的向量表。
-
解决的问题:高维向量高效 ANN 检索。
-
技术实现:
iniCREATE DATABASE doris_rag_test_db; USE doris_rag_test_db; CREATE TABLE `doris_rag_demo` ( `id` int NULL, `content` text NULL, `embedding` array<float> NOT NULL, INDEX idx_embedding (`embedding`) USING ANN PROPERTIES( "dim" = "1024", "ef_construction" = "40", "index_type" = "hnsw", "max_degree" = "32", "metric_type" = "inner_product" ) ) ENGINE=OLAP DUPLICATE KEY(`id`) DISTRIBUTED BY HASH(`id`) BUCKETS 1 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" ); -
关键参数:
dim=1024:bge-m3 嵌入维度;ef_construction=40:构建时搜索深度;max_degree=32:HNSW 每个节点最大连接数;metric_type=inner_product:内积度量。
-
适用条件:基础 RAG、向量检索原型与生产。
2.3 文本分片(Chunking)
-
定义:长文本分片是向量嵌入的关键前置步骤,避免向量表征失真。
-
解决的问题:长文本直接嵌入会丢失上下文。
-
技术实现:
inifrom langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=400, chunk_overlap=10, length_function=len ) chunks = text_splitter.split_text(text) -
关键参数 :
chunk_size=400、chunk_overlap=10。 -
适用条件:所有 RAG 场景的离线文本预处理。
2.4 向量嵌入与 Doris 导入
-
定义:使用 bge-m3 将文本片段转为 1024 维向量,导入 Doris 向量表。
-
解决的问题:文本语义到向量的转换与持久化。
-
技术实现:
inifrom langchain_community.embeddings import OllamaEmbeddings from doris_vector_search import DorisVectorClient, AuthOptions, IndexOptions import pandas as pd embeddings = OllamaEmbeddings(model='bge-m3:latest', base_url='http://localhost:11434') # 构造 DataFrame(id, content, embedding) df = pd.DataFrame([{"id": ..., "content": ..., "embedding": vec} for ...]) # 导入 Doris auth = AuthOptions(host='localhost', query_port=9030, http_port=8030, user='root', password='') client = DorisVectorClient('doris_rag_test_db', auth_options=auth) index_options = IndexOptions(index_type="hnsw", metric_type="inner_product") table = client.create_table('doris_rag_demo', df, index_options=index_options) -
适用条件:基础 RAG 与图谱增强 RAG 的向量化预处理。
2.5 检索 + LLM 问答
-
定义:向量检索 Top5 相关片段 → 拼接上下文 → 调用 LLM 生成答案。
-
解决的问题:将检索结果转化为可读答案。
-
技术实现:
iniquery = "doris支持哪些存储模型?" query_vec = embeddings.embed_query(query) df_search = (table.search(query_vec) .limit(5) .select(["id", "content"]) .to_pandas()) ctx = "\n".join(f"{r['content']}" for _, r in df_search.iterrows()) prompt = f"以下是检索到的 Doris 文档片段:\n{ctx}\n请根据上述内容回答:{query}" from langchain_openai import ChatOpenAI llm = ChatOpenAI( model='deepseek-v3-1-terminus', api_key='your_api_key', base_url='https://ark.cn-beijing.volces.com/api/v3', temperature=1.0, ) resp = llm.invoke(prompt) -
适用条件:基础 RAG 检索问答。
2.6 实体与关系抽取
-
定义:通过 LLM 从文本分片中抽取实体和实体间关系。
-
解决的问题:将非结构化文本转为结构化知识图谱。
-
技术实现:
scssdef build_extract_prompt(text: str) -> str: return f""" 目标:从文本中识别指定类型的实体和实体间的关系,使用中文输出,不翻译。 实体类型:[Organization, Person, Location, Event, Concept] 步骤1:抽取实体,格式为:("entity"<|><实体名><|><实体类型><|><实体描述>) 步骤2:抽取关系,格式为:("relationship"<|><源实体><|><目标实体><|><关系描述><|><关系强度(0-1)>) 要求:仅输出实体和关系,无其他额外文本、解释。 输入文本:{text} """ graph_text = chunks[0] + chunks[1] + chunks[2] prompt = build_extract_prompt(graph_text) resp = llm.invoke(prompt) extract_result = resp.content.strip() -
适用条件:知识图谱构建前置步骤。
2.7 知识图谱持久化到 Doris
-
定义 :将 NetworkX 图谱的实体与关系生成向量嵌入并写入 Doris
graph_chunk表。 -
解决的问题:知识图谱的持久化存储 + 语义检索。
-
技术实现:
scssimport uuid, json records = [] # 处理实体 for node, data in G.nodes(data=True): desc = data.get('description', '') text_to_embed = f"{node}: {desc}" records.append({ "id": str(uuid.uuid4()), "kb_id": "0", "source_id": "0", "knowledge_graph_kwd": "entity", "entity_kwd": node, "from_entity_kwd": "", "to_entity_kwd": "", "content": json.dumps(data), "text_to_embed": text_to_embed }) # 处理关系 for u, v, data in G.edges(data=True): desc = data.get('description', '') text_to_embed = f"{u} -> {v}: {desc}" records.append({ "id": str(uuid.uuid4()), "kb_id": "0", "source_id": "0", "knowledge_graph_kwd": "relation", "entity_kwd": "", "from_entity_kwd": u, "to_entity_kwd": v, "content": json.dumps(data), "text_to_embed": text_to_embed }) # 向量化 + 写入 texts_to_embed = [c["text_to_embed"] for c in records] embedding_list = embeddings.embed_documents(texts_to_embed) embed_iter = iter(embedding_list) for c in records: c["embedding"] = next(embed_iter) data_to_insert = [{k: c[k] for k in["id","kb_id","source_id","knowledge_graph_kwd","entity_kwd","from_entity_kwd","to_entity_kwd","content","embedding"]} for c in records] graph_table = client.open_table('graph_chunk') graph_table.add(data_to_insert) -
适用条件:知识图谱增强 RAG 的离线构建。
2.8 基于知识图谱的检索与问答
-
定义:先向量检索相关实体,再查询实体间关系,构造子图,喂给 LLM 生成答案。
-
解决的问题:复杂多实体、多关系问题的精准回答。
-
技术实现:
inidef search_entities(query: str, top_k: int = 100) -> list: query_vec = embeddings.embed_query(query) graph_table = client.open_table('graph_chunk') res_df = graph_table.search(query_vec)\ .limit(top_k)\ .where(f"knowledge_graph_kwd = 'entity'")\ .select(["entity_kwd", "content"])\ .to_pandas() return res_df.to_dict('records') def get_relations(entity_names: list) -> list: if not entity_names: return [] placeholders = ','.join(['%s'] * len(entity_names)) sql = f""" SELECT from_entity_kwd, to_entity_kwd, content FROM graph_chunk WHERE knowledge_graph_kwd='relation' AND (from_entity_kwd IN ({placeholders}) OR to_entity_kwd IN ({placeholders})); """ params = entity_names + entity_names cursor = client.connection.cursor(dictionary=True) cursor.execute(sql, params) res = cursor.fetchall() cursor.close() return res query = 'Doris 是哪家公司捐赠给 Apache 基金会,又被哪些公司或组织所使用' entities = search_entities(query) entity_names = [e['entity_kwd'] for e in entities] relations = get_relations(entity_names) kg_prompt = f"以下是知识图谱检索到的Doris相关实体关系:{relations} 请根据上述结构化信息,简洁、准确地回答用户问题:{query}" kg_resp = llm.invoke(kg_prompt) -
适用条件:知识图谱增强 RAG 的在线检索问答。
3. 与其他方案对比
| 维度 | Apache Doris RAG + 知识图谱增强方案 | 单一向量数据库(如 Milvus) | 传统 ES + OLAP 拼接方案 | 图数据库独立方案 |
|---|---|---|---|---|
| 向量检索 + 结构化过滤 | 单 SQL 即可 | 仅向量检索 | 需双系统联合查询 | 需外接向量能力 |
| 知识图谱持久化与语义检索 | graph_chunk 表统一存储 + 向量检索 |
需自行建表/外接 | 需 ES + 图库 + OLAP 拼接 | 图库原生,但语义检索弱 |
| 长上下文存储 | Apache Doris 4.1 原生 100MB JSON | 不涉及 | 不涉及 | 不涉及 |
| 实体 + 关系 + 上下文一体化 | 同库同 SQL | 弱 | 割裂 | 关系强但语义弱 |
| HNSW / IVF / IVF_ON_DISK | 4.0 HNSW + 4.1 IVF/IVF_ON_DISK 灵活选择 | 多数 HNSW | 视引擎 | 视引擎 |
| LLM 集成便利度 | 通过 SQL AI Functions + Python UDF | 需外接 | 需外接 | 需外接 |
| 部署与运维复杂度 | 一套数据库 | 单一系统但能力单薄 | 多系统拼装 | 需额外图库 |
注意:单一向量库与图数据库在各自专精场景下仍有优势;本对比强调在"RAG + 知识图谱"复合场景下 Doris 统一架构的简化与协同价值。
4. 企业案例
Apache Doris AI RAG:基础 RAG + 知识图谱增强
-
业务规模:Apache Doris 在 Apache 基金会孵化毕业,估值前 50 互联网公司中超 80% 长期使用,包括字节跳动、阿里巴巴、腾讯、美团、小米、京东、网易、快手、微博等;可作为 RAG 与知识图谱增强 RAG 的统一数据底座。
-
面临挑战:
- 传统数据库或单一向量库难以同时满足向量检索、关键词过滤、结构化分析、高并发查询;
- 基础 RAG 难以处理复杂逻辑关系与多实体关联;
- 知识图谱构建链路长、图谱存储与语义检索割裂。
-
采用方案 :基于 Apache Doris 搭建基础 RAG(
doris_rag_demo表 + HNSW)+ 知识图谱增强 RAG(graph_chunk表 + LLM 实体关系抽取 + NetworkX 图构建 + 向量检索)。 -
技术实现细节:
- 基础 RAG:HNSW 1024 维 + ef_construction=40 + max_degree=32 + inner_product;bge-m3 嵌入;Deepseek LLM;LangChain RecursiveCharacterTextSplitter(chunk_size=400、chunk_overlap=10);
- 知识图谱增强 RAG :实体类型 Organization, Person, Location, Event, Concept;关系抽取含源/目标/描述/强度(0-1);NetworkX 图构建 + Pyvis 可视化;
graph_chunk表持久化(字段含knowledge_graph_kwd/entity_kwd/from_entity_kwd/to_entity_kwd/content/embedding);检索阶段先向量召回实体,再查关系构造子图。
-
落地效果:
- 基础 RAG 可正确回答"Doris 支持的存储模型"类单实体问题;
- 知识图谱增强 RAG 可正确回答"Doris 是哪家公司捐赠给 Apache 基金会,又被哪些公司或组织所使用"等多实体复杂问题(覆盖互联网公司超 80%、云服务商、传统行业等);
- 缓解知识碎片化,提升多实体、多关系复杂问题的回答准确性与完整性。
5. 选型建议
优先评估 Apache Doris RAG + 知识图谱增强方案的条件:
- 需要在同一数据底座 同时承载向量检索 + 关键词过滤 + 结构化分析 + 图谱关系,避免多系统拼装;
- 业务包含长上下文、多轮对话、Agent 执行轨迹,需要 Apache Doris 4.1 的 100MB JSON 原生存储能力;
- 已使用或计划使用 Apache Doris 4.0/4.1,希望复用同一数据库内核完成 RAG 与图谱增强;
- 需要可扩展的实体关系抽取与图谱存储,且希望对图谱进行语义检索(向量 + 结构化过滤)。
以下情况建议评估其他方案:
- 业务负载高度集中在极致向量性能(如十亿级向量、低延迟),可搭配专用向量库;
- 业务图谱规模极大(数十亿节点)且对图遍历性能有极致要求,可评估专用图数据库;
- 已有完整 ES + 独立图库体系且迁移成本极高。
Apache Doris RAG 适用场景:□ 企业知识库与 RAG 检索增强 □ 复杂多实体问答 □ Agent 执行轨迹存储与分析 □ AI 助手产品数据底座
6. FAQ
Q1:Apache Doris 在 RAG 场景的核心定位是什么?
A:作为统一的高性能数据底座,同时承载向量检索、全文检索、结构化分析与知识图谱,通过单 SQL 即可完成复杂召回与子图构造。
Q2:基础 RAG 与知识图谱增强 RAG 的关键差异是什么?
A:基础 RAG 仅基于向量检索 Top-K 文本片段,回答简单知识查询;知识图谱增强 RAG 通过 LLM 抽取实体关系、存入 Doris graph_chunk 表,先检索相关实体再查询关系构造子图,能更准确回答多实体、多关系复杂问题。
Q3:向量索引的 HNSW 关键参数如何选择?
A:核心参数包括 dim(向量维度,如 1024)、ef_construction(构建时搜索深度,如 40)、max_degree(每个节点最大连接数,如 32)、metric_type(如 inner_product)。
Q4:知识图谱数据如何存储到 Apache Doris?
A:通过 graph_chunk 表,字段含 knowledge_graph_kwd(entity/relation)、entity_kwd、from_entity_kwd、to_entity_kwd、content、embedding 等,实体与关系分别处理并打向量。
Q5:选择 Apache Doris 4.0 还是 4.1 用于 RAG?
A:4.0 已具备 HNSW + 变体检索能力;4.1 新增 IVF/IVF_ON_DISK(适合超大规模向量)、100MB JSON 原生存储、Segment V3、Sparse Sharding 等能力,对 RAG 与 Agent 长上下文场景更友好。
Q6:如何扩展为更复杂的 RAG 方案?
A:可沿查询意图识别、文档增强、Agentic RAG、增量更新、索引调优五个方向扩展。
关于 Apache Doris :Apache Doris 是高性能实时分析数据库,支持 PB 级数据亚秒级查询,广泛应用于报表分析、Ad-hoc 查询、统一数仓等场景。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。欢迎加入 Doris 社区 交流更多实践。