RAG 关键词检索怎么做?用 SQLite FTS5 建索引并返回原文出处

用 SQLite FTS5 的 trigram 建立中文连续关键词原型索引,限制公开资料,返回原文、来源和页号,并明确短词与语义检索边界。

RAG 的检索层不一定先下载嵌入模型。对包含明确产品名或术语的资料,可以先建立关键词索引,返回原文和出处,再交给回答模型。SQLite FTS5 可以做这个小型原型;本文用 trigram 将连续三个字符作为检索单位,演示中文“保修期”的命中。

资料全部为虚构教学条款,示例不调用模型,不声称它能理解同义词或达到语义检索效果。默认 SQLite 编译功能因 Python 发行版而异;运行前需要确认当前环境提供 FTS5 和 trigram tokenizer。

RAG 关键词检索怎么做?用 SQLite FTS5 建索引并返回原文出处

先说清中文短词的边界

本文使用连续字符片段,不是中文词语分词。少于三个字符的查询不适用于这个 trigram MATCH 演示,所以“保修”会被明确拒绝,“保修期”可用于测试;真实项目应另行定义短词检索或分词方案,而不是给查询任意添加不相干字符。

SQLite 官方 tokenizer 实现可核对 trigram 的三个字符处理;官方 trigram 测试展示 FTS5 建表、MATCH 和相关配置。它处理字面匹配,不能凭空把“保修”理解成“售后服务”。

建立索引并限制公开资料范围

代码只用 Python 标准库。保存为 fts_demo.py,执行 python fts_demo.py。三条资料中两条公开、一条内部,检索应只返回公开原文。

import sqlite3

conn = sqlite3.connect(":memory:")
conn.row_factory = sqlite3.Row
print("sqlite_version:", sqlite3.sqlite_version)
conn.execute("""
CREATE VIRTUAL TABLE chunks USING fts5(
    source_id UNINDEXED, page UNINDEXED, scope UNINDEXED, text,
    tokenize='trigram'
)
""")
conn.executemany("INSERT INTO chunks(source_id,page,scope,text) VALUES (?,?,?,?)", [
    ("manual-a", 1, "public", "示例设备 A 的保修期为 12 个月。"),
    ("manual-b", 2, "public", "示例设备 B 的保修期为 6 个月。"),
    ("internal-c", 1, "internal", "内部演示设备 C 的保修期为 36 个月。"),
])

def retrieve_literal(term):
    if not isinstance(term, str) or len(term.strip()) < 3:
        raise ValueError("本演示要求至少三个字符的连续检索词")
    literal = '"' + term.strip().replace('"', '""') + '"'
    rows = conn.execute("""
        SELECT source_id,page,scope,text,bm25(chunks) AS rank
        FROM chunks WHERE chunks MATCH ? AND scope=?
        ORDER BY rank LIMIT ?
    """, (literal, "public", 5)).fetchall()
    return [dict(row) for row in rows]

results = retrieve_literal("保修期")
print(results)
assert {row["source_id"] for row in results} == {"manual-a", "manual-b"}
assert all(row["scope"] == "public" and "保修期" in row["text"] for row in results)
try:
    retrieve_literal("保修")
except ValueError as error:
    print("short_query_rejected:", error)
else:
    raise AssertionError("两字符查询不应进入本演示检索")
conn.close()

source_id、page、scope 使用 UNINDEXED,保留为检索结果与范围条件,不加入正文词项。Python sqlite3 官方文档说明参数绑定方式;代码将 MATCH 表达式和范围作为参数传入。检索词还被转成字面短语,避免把用户输入直接当作 FTS 查询语法。

结果与排序怎么核对

固定输入应得到 manual-a 和 manual-b,两条都包含原文及页号,internal-c 不返回。两字符查询应打印明确拒绝原因。若报 no such module: fts5 或 no such tokenizer: trigram,先换成支持该功能的 SQLite/Python 构建,不把空结果当成资料不存在。

SQLite 官方辅助函数实现可核对 bm25 的评分方向。这里按 rank 升序取结果;这个字面相关性分数不是余弦相似度,更不是回答正确率,不应沿用其他向量库的阈值。

接到问答前,再做两次检查

  1. 问“设备 A 保修期”,检查真正支持设备 A 的原文能否命中。检索词本身若不连续存在于文本,trigram 短语匹配可能没有结果;需要针对真实查询设计分词或多条件策略。
  2. 问资料里没有的条款,检索没有依据时让回答层说明无法确认。不要将索引中某条相近记录当作无条件答案。

检索接口返回的 source_id 和 page 应跟着片段进入回答环节,用来核对引用。生产范围条件必须来自已认证用户的真实权限,本文固定 public 仅用于公开演示资料,不能让模型自由选择 internal。

何时适合这个原型,何时需要扩展

  • 产品名、编号、连续术语明确时,先用小库验证字面召回和出处。
  • 同义问法、长问题和语义匹配需求明显时,比较分词检索、向量召回或组合方案,不能把这个原型包装成通用语义搜索。
  • 文档更新时,必须同步删除或替换过期索引记录,并保持元数据与正文一致。
  • 数据变大或并发提升时,测量真实查询与写入模式;内存库教学结果不是生产容量说明。

下一步是挑一小组有明确术语的公开资料,保存来源字段并运行上述检索。先核对字面命中、范围和引用,再接入模型回答。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/31990.html

赞 (0)
AI小管家的头像AI小管家
AI 训练 JSONL 怎么检查?逐行校验字段并保存错误记录
上一篇 1小时前
RAG 嵌入缓存怎么做?用 SQLite 按文本哈希和模型版本复用向量
下一篇 1小时前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部