400-100-5265

预约演示

SAG 把 RAG 拉回数据库

2026-06-20

RAG 这两年一直很热,但真正在 Agent 场景里用过的人,大概率都遇到过一个尴尬问题:模型越来越会推理,工具调用也越来越顺手,最后卡住的地方,反而是检索。

很多 Agent 失败并不是因为模型不会想,而是第一步就拿错了材料。尤其是多跳问题,答案分散在几篇文档里,单次检索没命中,后面再怎么规划、反思、重试,也很容易沿着错误方向越走越远。

这也是 SAG(SQL-Retrieval Augmented Generation)值得单独拿出来聊的原因。它没有选择把 RAG 继续复杂化成一套重型知识图谱系统,而是往数据库方向退了一步:把文本整理成 event/entity 结构,再用 SQL 做关系扩展。看起来朴素,但在多跳检索上,效果相当直接。

一、向量 RAG 的多跳短板

传统向量 RAG 的逻辑很顺:把文本 chunk 编码成向量,问题来了,把问题也编码成向量,然后找相似度最高的几段文本。

这个方案能成为主流,原因很现实:

特点 工程价值
部署简单 向量库 embedding 模型就能跑
成本可控 离线编码、在线 ANN 检索,吞吐容易做
对非结构化文本友好 不要求先建复杂 schema
简单问答效果稳定 单文档、单事实问题通常够用

但向量检索有一个结构性弱点:它主要判断“像不像”,并不理解“谁和谁存在关系”。

比如一个问题:

A 公司收购了 B 公司,B 公司的 CTO 后来加入了 C 项目,C 项目影响了哪个产品路线?

答案可能分散在三篇文档里:

  • 一篇讲 A 收购 B;
  • 一篇讲 B 的 CTO 加入 C;
  • 一篇讲 C 项目影响某条产品路线。

单独看任意一篇,它和完整问题的语义相似度都未必高。更麻烦的是,中间文档可能只提供桥接关系,不包含最终答案。向量检索如果第一跳没有抓住正确桥,后面基本就断了。

这就是多跳检索和普通相似文本检索的区别。

普通 RAG 像是在资料库里找“最像问题的段落”;多跳 RAG 更像是在找一条证据链。前者靠相似度,后者需要关系扩展。

在 MuSiQue 这种最多需要 4 跳推理的基准上,当前较强的结构化检索方案 HippoRAG 2,Recall@2 为 49.5%。这个数字的含义很直接:只看前 2 条返回结果,一半以上的问题拿不到关键证据。

对普通问答系统来说,这可能只是回答质量下降。对 Agent 来说,问题会被放大。

Agent 通常不是检索一次就结束,而是:

流程图 - SAG 把 RAG 拉回数据库

第一步检索偏了,后面的规划也会偏。多轮之后,错误不是线性累加,而是沿着推理链扩散。

所以在 Agent 场景里,Recall@2、Recall@5 这种靠前命中率很关键。不是说 Recall@10 没价值,而是上下文窗口、延迟、token 成本、干扰信息都会限制 Agent “拿一大堆材料慢慢挑”的能力。

二、GraphRAG 的方向与代价

GraphRAG 看到了向量 RAG 的问题。它的基本思路是:从文本中抽取实体和关系,构建知识图谱,然后沿着图谱做多跳检索。

方向是合理的。多跳问题天然需要结构,图结构刚好表达实体之间的连接。

但落到工程里,图谱 RAG 的复杂度不低。

一条文本可能被拆成很多三元组:

文本信息 三元组表达
OpenAI 在 2025 年发布 GPT-5 OpenAI → 发布 → GPT-5
GPT-5 属于大语言模型 GPT-5 → 属于 → LLM
GPT-5 发布时间是 2025 年 GPT-5 → 发布时间 → 2025

这里的麻烦不在“能不能抽”,而在“能不能稳定、便宜、持续地抽”。

GraphRAG 通常要处理几类问题:

  • 实体抽取:哪些词算实体;
  • 实体归一:OpenAI、Open AI、该公司是不是同一个;
  • 关系抽取:谓词怎么定义;
  • 重复合并:相似实体和关系如何去重;
  • 社区发现:大图上怎么聚类;
  • 摘要生成:如何让图结构可读、可检索;
  • 增量更新:新数据进来时如何维护旧图。

这些步骤很多都依赖 LLM。效果可以做得不错,但成本、延迟、可维护性都会上来。

HippoRAG 2 进一步证明了结构化记忆和多跳检索对 RAG 很重要。它依赖 Personalized PageRank 做图排序,在 benchmark 规模下表现不错。

但如果放到持续增长的生产数据里,全局图排序会带来很重的维护负担。数据每天写入,关系不断变化,如果每次都需要全局重建或大范围重排,系统就很难支撑高频增量。

这里有一个典型工程权衡:

方案 优势 代价 更适合的场景
向量 RAG 简单、便宜、吞吐好 多跳弱,缺少关系结构 FAQ、单文档问答、语义搜索
GraphRAG 关系表达强,多跳自然 构建和更新成本高 稳定知识库、低频更新、强结构场景
HippoRAG 2 结构化记忆能力强 全局图排序对增量不友好 benchmark、相对静态的数据集
SAG 轻量结构、SQL 扩展、增量友好 依赖 event/entity 抽取质量 Agent 记忆、多跳问答、持续写入数据底座

这张表里最关键的一点是:工程上不只看检索效果,还要看数据生命周期。

如果数据是一次性导入、很少变化,重型图谱可以接受。 如果数据每天持续写入,Agent 还要实时使用,轻量结构往往更有生命力。

三、SAG 的 event/entity 索引

SAG 的思路很有意思:它没有继续堆复杂图谱,也没有把文本拆成一堆三元组,而是给每个 chunk 加一张轻量索引卡。

一个 chunk 对应:

  • 一个 event:对该 chunk 中事项的完整摘要;
  • 多个 entity:从原始 chunk 中抽取出的人物、组织、地点、时间、产品、话题等实体。

event 保留语义上下文,entity 负责索引和连接。

这和三元组路线差异很大。

结构 表达方式 主要问题
三元组 头实体 → 关系 → 尾实体 语义被切碎,关系谓词不稳定
SAG 超边 event ↔ 多个 entities 结构较粗,但保留完整事项语义

三元组的问题在真实数据里很容易放大。同一段内容,不同模型可能抽出不同谓词:

  • 使用;
  • 基于;
  • 提出;
  • 支持;
  • 发布;
  • 参与。

谓词一旦不稳定,后续图检索和关系匹配都会受影响。尤其是跨领域数据,schema 很难统一,越想抽得精细,越容易维护不住。

SAG 把要求降低了:LLM 主要做两件事。

第一,把 chunk 总结成一个完整 event。 第二,从原文中尽可能抽取 entity。

event 像一条带上下文的事项记录,entity 像索引点。一个 event 同时连接多个 entity,在图论里更接近超边。

流程图 - SAG 把 RAG 拉回数据库

这种结构没三元组那么精细,但对 RAG 来说,精细不一定总是优势。

RAG 最后要回到原文证据。三元组太碎,容易丢上下文;event 保留了一段可读语义,entity 提供连接入口。很多时候,这比抽一堆不稳定谓词更可靠。

素材里提到一个细节值得注意:SAG 在抽取 event 时会做代词消歧,把“他”“该公司”“这个产品”替换成完整名称。这个设计很朴素,但很关键。

因为检索系统里的 event 要能独立被理解。如果 event 里全是上下文依赖的代词,向量检索、关键词检索、重排序都会被干扰。

一个更好的 event 应该像这样:

OpenAI 在 2025 年发布 GPT-5,并将 GPT-5 定位为面向开发者和企业应用的大语言模型产品。

而不是:

该公司在这一年发布了它,并将其定位为面向开发者和企业的产品。

后者对人类读连续上下文没问题,但对检索系统很不友好。

四、用 SQL 做多跳扩展

SAG 的系统分成两段:离线写入和在线检索。

离线阶段:

  1. 文档切成 chunk;
  2. 每个 chunk 提取 event;
  3. 每个 chunk 提取多个 entity;
  4. event、entity、chunk 关系写入 MySQL;
  5. event 和 entity 相关文本写入 Elasticsearch,支持向量检索和全文检索。

一个容易被忽略的设计是:event-entity 关系本身也有描述文本,也可以有自己的 embedding。

同一个实体在不同 event 中角色可能完全不同:

entity 关系描述
OpenAI 发布 GPT-5 的公司
OpenAI Sam Altman 参与管理的公司
OpenAI 影响开发者生态的模型平台

如果只存一个实体名“OpenAI”,召回会非常粗。 如果把实体在事件中的角色也编码进去,实体召回就更接近真实语义。

在线阶段,SAG 走两条路径。

结构化召回

问题进来后,LLM 先识别关键实体。系统用这些实体去索引中找相近实体,再通过 SQL JOIN 找到关联 event 和 chunk。

示意 SQL 大概是这样的:

-- 示意代码:根据候选实体扩展到关联 event
SELECT
    e.id AS event_id,
    e.summary AS event_summary,
    c.id AS chunk_id,
    c.content AS chunk_content
FROM entity_candidates ec
JOIN event_entity_rel r
    ON ec.entity_id = r.entity_id
JOIN events e
    ON r.event_id = e.id
JOIN chunks c
    ON e.chunk_id = c.id
WHERE ec.query_id = :query_id
ORDER BY ec.score DESC, r.weight DESC
LIMIT 100;

这里的核心不是 SQL 多复杂,而是数据结构允许这么查。

只要 event 和 entity 的多对多关系在数据库里,关系扩展就可以通过 JOIN 完成,不需要全局图排序。

语义召回

同时,系统会直接用问题向量去检索语义接近的 event。

这条路径补的是另一类情况:用户问题本身已经和某些 event 很接近,没必要绕实体扩展。

结构化召回和语义召回是互补的:

路径 擅长 不擅长
结构化召回 沿实体关系找多跳线索 实体识别错误时会受影响
语义召回 直接命中语义相近事项 对隐含关系和桥接证据较弱

消融实验也能说明问题。纯语义路径的 Recall@5 只有 56.2%,加入少量结构化事项候选后,可以提升到 80.0%。

查询时扩展

SAG 的多跳能力来自查询时扩展。

系统先找到一批 event,然后反查这些 event 关联的 entity,再用这些 entity 找新的 event。每一轮只引入之前没有出现过的新内容。

流程图 - SAG 把 RAG 拉回数据库

这就是 SAG 工程上比较克制的地方。

它没有要求系统维护一张全局可推理图,也没有让 LLM 在线临时构建复杂关系网络,而是把多跳检索压回数据库里的局部扩展。

说白了,就是 JOIN。

这不是贬低。很多生产系统里,最稳定的方案往往就是把问题整理成数据库能处理的形状。

五、性能提升来自结构

SAG 在 HotpotQA、2WikiMultiHop、MuSiQue 三个多跳基准上做了对比。相同 embedding 模型 BGE-Large-EN-v1.5 和 LLM Qwen3.6-Flash 配置下,结果很明确:

指标 SAG HippoRAG 2 差值
平均 Recall@2 79.3% 68.2% 11.1 pp
MuSiQue Recall@2 64.1% 49.5% 14.6 pp
MuSiQue Recall@5 80.04% 65.1% 左右 明显领先

MuSiQue 是更能体现差异的数据集,因为它最多需要 4 跳推理,而且每条推理链都不能随便跳过。SAG 在这里优势突出,说明 event/entity 索引确实更适合复杂关联问题。

这里还有两组对比很有参考价值。

第一组是超边和三元组。

结构 MuSiQue Recall@5
三元组 77.16%
SAG 超边 80.04%

更简单的结构效果反而更好。原因不难理解:三元组保留的语义更碎,向量检索时容易匹配到关键词重合但关系无关的片段。event 把多个实体压在一个完整事项里,多跳扩展时连接更密,误差传播更少。

第二组是 embedding 模型鲁棒性。

HippoRAG 2 原论文使用更强的 NV-Embed-v2,在 MuSiQue 上 Recall@5 达到 74.6%。但换成 BGE-Large-EN-v1.5 后,下降到 65.1%,损失接近 10 个百分点。

SAG 在 BGE-Large-EN-v1.5 下达到 80.0%,换成 NV-Embed-v2 后提升到 81.7%,变化不大。

这个结果说明,SAG 的收益主要来自索引结构和检索算法,而不是单纯依赖更强的 embedding 模型硬拉。

这点对生产环境挺重要。

因为模型升级并不总是免费的。更强 embedding 往往意味着更高成本、更慢写入、更复杂部署。一个检索架构如果必须绑定顶级 embedding 才能跑出效果,落地空间会被压缩。

SAG 的结构鲁棒性,降低了底层模型选择压力。

六、生产环境里的现实价值

Benchmark 好看是一回事,生产环境能不能跑是另一回事。

SAG 适合规模化,主要靠几个工程特性。

chunk 天然并发

每个 chunk 的 event/entity 抽取可以独立进行。写入侧可以批量并发,不需要像全局图构建那样强依赖整体状态。

这对大规模数据处理很友好。尤其是企业知识库、用户记忆、工单、文档、邮件这类数据,新增频率高,批处理和流式写入都需要考虑。

实体复用靠 SQL

SAG 没有做特别重的 entity resolution。入库前做简单字符串归一,再通过 SQL 查重,同名同类型实体直接复用。

听起来有点粗糙,但符合它的设计定位:entity 是索引点,event 才承载主要语义。

如果把实体归一做得过重,系统会重新回到图谱工程那套复杂流程。SAG 的取舍是接受一定实体噪声,用 event 的语义完整性兜底。

关系都是局部的

新数据进来,只需要:

  1. 切 chunk;
  2. 抽 event;
  3. 抽 entity;
  4. 写入 event/entity/chunk 关系;
  5. 更新索引。

不需要重建全局图,也不需要跑全局 PageRank。

这就是它和重型 GraphRAG 的分界线。

GraphRAG 更像是在维护一套知识地图。 SAG 更像是在给每条数据加可 JOIN 的语义索引。

Zleap AI 团队提到,SAG 已经在 5 亿级数据规模的生产环境中稳定运行,在线检索延迟保持在秒级以内。这个量级至少说明,它不是只能停留在论文里的玩具方案。

同时团队提供了 Wikipedia Demo: https://wiki.zleap.com

Demo 支持快速模式和高精度模式。快速模式省掉 LLM 精排,更关注响应速度;高精度模式增加 LLM 重排序,更关注召回质量和最终证据排序。

七、为什么它适合 Agent

Agent 和普通 RAG 问答的最大差异,是检索会进入任务链路。

普通问答系统常见模式是:

流程图 - SAG 把 RAG 拉回数据库

Agent 更常见的是:

流程图 - SAG 把 RAG 拉回数据库

检索准确率会直接影响整条链路的稳定性。

如果第一次查错,Agent 会基于错误材料规划下一步。 如果第一次没查到,Agent 可能会换一个错误方向继续查。 如果每次都返回太多上下文,LLM 又会被噪声拖慢,甚至被无关信息带偏。

所以对 Agent 来说,更好的检索不是“尽量多给”,而是“尽早给对”。

SAG 的价值也在这里:

  • Recall@2 提升,意味着更早拿到关键证据;
  • 多跳扩展,意味着能沿实体关系继续找线索;
  • event 保留上下文,减少碎片证据造成的误判;
  • SQL 增量写入,适合持续增长的记忆和知识库;
  • 快速/高精度模式,可以按场景在延迟和准确率之间切换。

Agent 记忆也是一个很适合 SAG 的场景。

长期记忆并不是一堆孤立文本。同一个用户、项目、偏好、任务,会在不同时间反复出现。新的记忆可能补充旧记忆,也可能修正旧记忆。

纯向量记忆更像是在找相似片段。但 Agent 真正需要的是知道:

  • 哪些是历史背景;
  • 哪些是当前状态;
  • 哪些实体持续出现;
  • 哪些事项之间存在时间顺序;
  • 哪些旧结论已经被新事件覆盖。

SAG 的 event/entity 结构天然能承载这类信息。只要在 SQL 表里补上时间、来源、版本、状态字段,它就可以变成一种可持续更新的 Agent 记忆索引。

一个简化 schema 可以长这样:

-- 示意代码:SAG 风格的记忆表结构
CREATE TABLE events (
    id BIGINT PRIMARY KEY,
    chunk_id BIGINT NOT NULL,
    summary TEXT NOT NULL,
    occurred_at DATETIME,
    source_type VARCHAR(64),
    status VARCHAR(32),
    embedding_id VARCHAR(128),
    created_at DATETIME NOT NULL
);

CREATE TABLE entities (
    id BIGINT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(64) NOT NULL,
    normalized_name VARCHAR(255) NOT NULL,
    created_at DATETIME NOT NULL,
    UNIQUE KEY uk_entity (normalized_name, type)
);

CREATE TABLE event_entity_rel (
    event_id BIGINT NOT NULL,
    entity_id BIGINT NOT NULL,
    role_description TEXT,
    weight FLOAT DEFAULT 1.0,
    PRIMARY KEY (event_id, entity_id)
);

这个结构不复杂,但它能回答很多纯向量库不好回答的问题:

  • 某个用户最近提到过哪些项目;
  • 某个项目的状态在过去一个月怎么变化;
  • 某个产品决策关联了哪些人、会议和文档;
  • 某个偏好是长期稳定的,还是最近刚出现的。

这类查询如果只靠向量检索,往往会变成“看起来相关”的文本堆叠。放到关系表里,很多问题反而简单了。

八、边界也要看清楚

SAG 很实用,但也不是所有 RAG 场景都该上这套结构。

如果你的场景只是简单 FAQ、单文档问答、政策条款检索,传统向量 RAG 可能已经够了。SAG 的离线抽取、event/entity 存储、SQL 扩展都会引入额外复杂度。

如果你的数据本身已经有很强 schema,比如 ERP、CRM、订单、库存、权限系统,直接 Text-to-SQL 或结构化查询可能更合适。没必要先把结构化数据转成文本,再抽 event/entity。

如果你的业务对实体消歧要求极高,比如医疗、法律、金融风控,SAG 的轻量实体归一可能不够,需要更严格的主数据管理、别名体系和审核流程。

比较合理的判断是:

场景 是否适合 SAG
多文档多跳问答 很适合
Agent 长期记忆 很适合
企业知识库持续增量写入 适合
简单 FAQ 不一定需要
强结构业务数据库查询 优先考虑原生结构化查询
高精度实体主数据场景 需要补充更强实体治理

SAG 的工程意义,在于它找到了一条中间路线。

向量 RAG 太弱,GraphRAG 太重。SAG 没有试图把所有知识都整理成完美图谱,而是把每个 chunk 变成一个带实体索引的事项,再用数据库完成局部关系扩展。

这条路线的判断很务实: RAG 不一定需要一张昂贵的大图,但需要数据之间能被连接。 Agent 不一定需要一次拿回很多上下文,但需要尽早拿到正确证据。 生产系统不一定追求最精细的知识表示,但必须支持持续写入、持续更新、持续查询。

从这个角度看,SAG 真正带来的变化并不是“又一个 RAG 变体”,而是把 RAG 的核心问题往前推了一层:

数据进入 Agent 系统时,应该被组织成什么样?

SAG 给出的答案很明确:用 event 保留完整语义,用 entity 建立连接点,用 SQL 做多跳扩展。它没有把系统设计得很炫,但刚好抓住了 Agent 数据底座最现实的几个矛盾:准确率、增量更新、查询延迟和工程可维护性。[DONE]

创作声明:本内容包含AI辅助创作,观点仅供参考。