用23ai 原生向量引擎搭建 “文本语义检索系统”

一、场景背景与架构设计

  • 场景需求:
    企业内部存储了大量 PDF/Word 文档(产品手册、制度文件、培训资料),员工需通过自然语言提问,快速找到语义相似的文档内容,替代传统的关键词检索(精准度低、无法理解语义)。

  • 架构设计:
    采用 Oracle 23ai 原生向量引擎作为核心,整体流程简单清晰:
    文档预处理:将 PDF/Word 文档拆分为文本块(解决长文本语义割裂问题);
    向量生成:在 Oracle 数据库内调用VECTOR_EMBEDDING函数,生成文本块的嵌入向量;
    索引创建:为向量列创建 HNSW 索引(适配文本检索的高召回率需求);
    语义检索:用户输入自然语言问题,生成向量后,在数据库内执行相似检索;
    结果展示:将检索到的文本块与原文档关联,返回给用户查看。

    二、实战步骤:从 0 到 1 搭建语义检索系统

  • 步骤 1:环境准备与权限配置
    确保 Oracle 23ai 数据库已安装并启用原生向量引擎(23ai 默认开启,无需额外配置);
    创建专用 schema 与用户,授予必要权限:

    -- 创建用户
    CREATE USER vector_user IDENTIFIED BY Vector@123456;
    -- 授予连接、创建表、索引权限
    GRANT CONNECT, RESOURCE, CREATE TABLE, CREATE INDEX TO vector_user;
    -- 授予向量操作相关权限
    GRANT EXECUTE ON SYS.vector_embedding TO vector_user;
    GRANT EXECUTE ON SYS.vector_chunks TO vector_user;
  • 步骤 2:创建数据表,存储文档与向量数据
    我们需要三张表:文档基础信息表(存储原文档元数据)、文本块表(存储拆分后的文本片段)、向量映射表(存储文本块对应的嵌入向量),也可合并为一张表,这里拆分是为了提升查询效率。

    -- 1. 文档基础信息表
    CREATE TABLE doc_archives (
    doc_id NUMBER PRIMARY KEY,
    doc_name VARCHAR2(200) NOT NULL,
    doc_type VARCHAR2(50) NOT NULL, -- PDF/WORD/MD
    upload_time DATE DEFAULT SYSDATE
    );
    -- 2. 文本块表
    CREATE TABLE doc_chunks (
    chunk_id NUMBER PRIMARY KEY,
    doc_id NUMBER REFERENCES doc_archives(doc_id),
    chunk_content CLOB NOT NULL, -- 文本片段内容
    chunk_index NUMBER NOT NULL, -- 文本块在原文档中的序号
    -- 1536维文本嵌入向量(适配主流开源/商用文本嵌入模型)
    chunk_emb VECTOR(1536) FLOAT32
    );
    -- 创建文档与文本块的关联索引
    CREATE INDEX idx_chunks_doc_id ON doc_chunks(doc_id);
  • 步骤 3:文档预处理与向量生成(核心:数据库内生成向量)
    传统做法是在应用层拆分文档、调用外部 API 生成向量,再导入数据库。而 Oracle 23ai 原生向量引擎提供了 VECTOR_CHUNKS(文本分块)与VECTOR_EMBEDDING(向量生成) 两大函数,直接在数据库内完成全流程,无需外部依赖。

    3.1 文本分块:用VECTOR_CHUNKS拆分长文本

    VECTOR_CHUNKS函数可将长文本按指定长度、重叠度拆分,避免单文本块语义不完整。

    -- 示例:将ID为1的PDF文档拆分为500字/块,重叠50字
    DECLARE
    v_doc_content CLOB;
    BEGIN
    -- 模拟从原文档获取内容(实际可从文件存储读取,存入CLOB字段)
    v_doc_content := '企业数字化转型是指企业利用云计算、大数据、人工智能等新一代信息技术,对业务流程、组织架构、商业模式进行全面重构……'; -- 长文档内容
    
    -- 调用VECTOR_CHUNKS拆分文本,插入文本块表
    INSERT INTO doc_chunks (doc_id, chunk_content, chunk_index)
    SELECT 
        1 AS doc_id,
        chunk_content,
        chunk_index
    FROM TABLE(VECTOR_CHUNKS(v_doc_content, 500, 50)); -- 500字/块,重叠50字
    COMMIT;
    END;
    /

    3.2 向量生成:用VECTOR_EMBEDDING生成文本嵌入向量

    VECTOR_EMBEDDING支持调用内置 AI 模型或 外部 AI 服务(如 Ollama、OpenAI API) 生成向量,这里以调用开源文本嵌入模型all-MiniLM-L6-v2(本地部署)为例。

    -- 为已拆分的文本块生成嵌入向量
    DECLARE
    CURSOR c_chunks IS SELECT chunk_id, chunk_content FROM doc_chunks WHERE doc_id = 1;
    BEGIN
    FOR r IN c_chunks LOOP
        -- 调用VECTOR_EMBEDDING生成1536维向量,存入chunk_emb列
        UPDATE doc_chunks
        SET chunk_emb = VECTOR_EMBEDDING(
            'all-MiniLM-L6-v2', -- 嵌入模型名称
            r.chunk_content,    -- 文本块内容
            VECTOR_OUTPUT => 'FLOAT32' -- 输出精度
        )
        WHERE chunk_id = r.chunk_id;
    END LOOP;
    COMMIT;
    END;
    /

    步骤 4:创建 HNSW 索引,提升检索性能

    文本语义检索对召回率要求高,因此选择 HNSW 索引:

    -- 为文本块向量列创建HNSW索引,使用余弦距离(文本嵌入的标准相似度计算方式)
    CREATE INDEX idx_chunks_emb_hnsw ON doc_chunks
    USING VECTOR HNSW (chunk_emb VECTOR_COSINE_DISTANCE)
    WITH (
    DIMENSIONS=1536,
    M=16, -- 每个节点的最大边数
    EF_CONSTRUCTION=200 -- 索引构建候选集大小
    );

    步骤 5:语义检索:自然语言转向量,执行相似查询

    这是整个系统的核心环节:用户输入自然语言问题,先将问题生成向量,再与数据库中的文本块向量执行相似检索,返回 Top-N 个最相似的结果。

    -- 示例:用户提问“企业数字化转型的核心步骤是什么?”
    DECLARE
    v_question VARCHAR2(1000) := '

Related Posts