Tüm Ürünler
Search
Belge Merkezi

ApsaraDB RDS:Use ApsaraDB RDS for PostgreSQL to create a RAG application

Son Güncelleme:Oct 03, 2026

ApsaraDB RDS for PostgreSQL, vektör depolamayı tam metin arama ile birleştirerek geri alım artırılmış üretim (RAG) uygulamaları için yetkin bir vektör veritabanı sağlar. Bu kılavuz, tek bir PostgreSQL örneğinde çok yollu geri alım, sonuç birleştirme ve soru-cevap üretiminin nasıl birlikte çalıştığını göstermek amacıyla bir bilet sohbet botu oluşturma sürecini adım adım anlatır.

Bu kılavuzu tamamladıktan sonra şunları anlayacaksınız:

  • Bir RAG işlem hattı için belgelerin nasıl alınacağı ve yapılandırılacağı

  • Dört geri alım yönteminin her birinin nasıl çalıştığı ve hangisinin ne zaman kullanılacağı

  • Karşılıklı sıra birleşimi (RRF) algoritması ve bce-reranker-base_v1 modeli kullanılarak sonuçların nasıl birleştirilip yeniden sıralanacağı

Nasıl çalışır

Bilet sohbet botu işlem hattı dört aşamadan oluşur:

  1. Veri işleme — Kaynak belgeleri (yardım dokümanları, bilgi tabanları, geçmiş biletler) parçalara ayırın ve gömme (embedding) oluşturun. Her ikisini de RDS örneğinde saklayın.

  2. Çok yollu geri alım — Kullanıcı sorularına karşı dört paralel arama çalıştırın: belge anahtar kelime tabanlı, içerik anahtar kelime tabanlı, BM25 tabanlı ve gömme tabanlı.

  3. Sonuç birleştirme — RRF algoritması ve bce-reranker-base_v1 modelini kullanarak dört yolun tümünden gelen sonuçları birleştirin ve yeniden sıralayın.

  4. Soru-cevap analizi — Geri alım ilkelerini değerlendirmek ve karşılaştırmak amacıyla test sırasında soru-cevap çiftlerini puanlayın.

Ön koşullar

Başlamadan önce şunlara sahip olduğunuzdan emin olun:

  • Bir ApsaraDB RDS for PostgreSQL örneği

  • Uzantıları yüklemek için ayrıcalıklı bir veritabanı hesabı

  • Bir Alibaba Cloud Model Studio hesabı ve API anahtarı (metin gömme modeli için). Bkz. API anahtarı alma

  • RDS örneğinin bulunduğu sanal özel bulut (VPC) için yapılandırılmış bir NAT ağ geçidi; böylece örnek harici modellere erişebilir. Bkz. Vektör oluşturmak için rds_embedding uzantısını kullanma

Veri işleme

Kaynak verileri edinme

RAG uygulamanızın amacına göre veri toplayın. Bu kılavuzdaki bilet sohbet botu üç kaynak kullanır:

  • Yardım dokümantasyonu

  • Bilgi tabanı makaleleri

  • Geçmiş destek biletleri

Belgeleri segmentlere ayırma ve gömme oluşturma

Gömme oluşturmadan önce belgeleri parçalara ayırın. Yardım belgelerini HTML hiyerarşisine (H1, H2) göre segmentlere ayırmak için LangChain HTMLHeaderTextSplitter sınıfını kullanın. Geri alım hassasiyeti ve kapsama alanı arasında denge kurmak için parça boyutunu ve örtüşmeyi yapılandırın. Bölücü seçeneklerinin tam listesi için bkz. LangChain metin bölücüler.

Markdown belgeleri için, MarkdownHeaderTextSplitter öğesini başlık işaretleriyle (örneğin # ve ##) hiyerarşik bölme için kullanın.

Verileri saklama

İşlenen verileri iki temel tabloda saklayın: document ve embedding.

Tetikleyici oluşturma SQL deyimleri

document tablosu, belge düzeyindeki meta verileri ve tam metin eşleştirme için kullanılan anahtar kelimeleri saklar.

Sütun Tür Açıklama
id bigint Birincil anahtar, otomatik artan
title varchar(255) Belge başlığı (benzersiz — güncellemede yinelemeleri önlemek için kullanılır)
url varchar(255) Kaynak URL
key_word varchar(255) Tam metin eşleştirme için anahtar kelimeler
tag varchar(255) Kaynak etiketi (örn. direct, aone); tsvector ağırlığını kontrol eder
created timestamp Oluşturma zamanı
modified timestamp Son değiştirilme zamanı
key_word_tsvector tsvector key_word değerinden oluşturulan ağırlıklı tsvector; anahtar kelime tabanlı geri alımda kullanılır
product_name varchar(255) Filtreleme için ürün adı

Dizinler:

Dizin Tür Amaç
document_pkey btree (id) Birincil anahtar
document_title_key btree (title), UNIQUE Yinelemeleri önleme — belgeler başlığa göre güncellenir
document_product_name_key btree (product_name) Ürün kapsamalı filtreleme
document_key_word_tsvector_gin GIN (key_word_tsvector) Hızlı anahtar kelime eşleştirme

Tetikleyici: trigger_update_tsvector INSERT veya UPDATE işlemlerinde çalışır ve key_word_tsvector değerini otomatik olarak yeniden oluşturur.

Tetikleyici, tag sütununa göre A–D ağırlıkları atar; böylece anahtar kelime tabanlı geri alımda direct belgeleri aone belgelerinden daha yüksek sırada yer alır. A, B, C, D ağırlıkları azalan öncelik sırasına göre verilmiştir:

CREATE OR REPLACE FUNCTION update_tsvector()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
        IF NEW.tag = 'direct' THEN
            NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'A');
        ELSIF NEW.tag = 'aone' THEN
            NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'B');
        ELSIF NEW.tag IS NOT NULL THEN
            NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'C');
        ELSE
            NEW.key_word_tsvector := setweight(to_tsvector('jiebacfg', NEW.key_word), 'D');
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION

CREATE TRIGGER trigger_update_tsvector
BEFORE INSERT OR UPDATE ON document
FOR EACH ROW
EXECUTE FUNCTION update_tsvector();
CREATE TRIGGER

Tetikleyici oluşturma SQL deyimleri

embedding tablosu, belge parçalarını ve bunların vektör temsillerini saklar.

Sütun Tür Açıklama
id bigint Birincil anahtar, otomatik artan
doc_id integer document.id için yabancı anahtar
content_chunk text Segmentasyondan sonraki metin parçası
content_embedding vector(1536) content_chunk değerinden oluşturulan gömme
created timestamp Oluşturma zamanı
modified timestamp Son değiştirilme zamanı
ts_vector_extra tsvector content_chunk değerinden oluşturulan tsvector; içerik anahtar kelime tabanlı geri alımda kullanılır

Dizinler:

Dizin Tür Amaç
embedding_pkey btree (id) Birincil anahtar
embedding_doc_id_key btree (doc_id) Belge birleştirme araması
embedding_content_embedding_idx HNSW (content_embedding, vector_cosine_ops), m=16, ef_construction=64 Yaklaşık en yakın komşu (ANN) vektör araması
embedding_rumidx RUM (ts_vector_extra) Sıralama ile hızlı tam metin araması

Tetikleyici: embedding_tsvector_update INSERT veya UPDATE işlemlerinde ts_vector_extra değerini yeniden oluşturur:

CREATE TRIGGER embedding_tsvector_update
BEFORE INSERT OR UPDATE ON embedding
FOR EACH ROW
EXECUTE PROCEDURE tsvector_update_trigger('ts_vector_extra','public.jiebacfg','content_chunk');

Çok yollu geri alım

Her geri alım yönteminin ne zaman kullanılacağı

Farklı geri alım yöntemleri farklı sorgu özelliklerine uygundur. Kullanım durumunuz için doğru stratejiyi seçmek üzere bu tabloyu kullanın:

Yöntem En uygun olduğu durumlar Sınırlamalar
Belge anahtar kelime tabanlı geri alım Bilinen ürün anahtar kelimeleri veya etiketlerle eşleşen sorgular; kesin terimler için hızlı ve hassas Anlamsal bağlamı kaçırır; yazım hatalarında veya eş anlamlılarda başarısız olur
İçerik anahtar kelime tabanlı geri alım Belge gövde metnini hedefleyen sorgular; hızlı tam metin sıralaması için RUM dizininden yararlanır Anahtar kelime eşleştirmeyle aynı sınırlamalara sahiptir
BM25 tabanlı geri alım Terim sıklığı ve belge düzeyindeki önemin önemli olduğu sorgular; ts_rank'i tamamlar Tamamen istatistiksel; anlamsal anlayış yoktur
Gömme tabanlı geri alım Doğal dilde ifade edilen sorgular; eş anlamlıları ve farklı ifadeleri yönetir Gömme modeli gerektirir; kesin anahtar kelime eşleşmelerini kaçırabilir

Çoğu RAG uygulaması için dört yöntemin tümünü birleştirin ve sonuçları RRF algoritması kullanarak birleştirin. Bu, tek bir yöntemden daha iyi bir geri alım sağlar.

Belge anahtar kelime tabanlı geri alım

Belge anahtar kelime tabanlı geri alım, kullanıcı sorularını document tablosunda saklanan anahtar kelimelerle eşleştirir ve benzerliğe göre en iyi N belgeyi döndürür.

Adım 1: Belge anahtar kelimelerini ağırlıklı tsvector değerleri olarak dizinleyin.

Anahtar kelimeleri segmentlere ayırmak için to_tsvector ve ağırlık atamak için setweight kullanın. Çince kelime segmentasyonu uzantıları pg_jieba ve zhparser Çince metni işler. Kurulum talimatları için bkz. Uzantıları yönetme.

SELECT setweight(to_tsvector('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库'), 'A');
                                   setweight
-------------------------------------------------------------------------------
 'postgresql':1A '世界':3A '先进':5A '关系':8A '型':9A '开源':7A '数据库':10A

Adım 2: Kullanıcı sorusunu bir tsquery'e dönüştürün ve anahtar kelimelerle eşleştirin.

SELECT
    id,
    title,
    url,
    key_word,
    ts_rank(
        key_word_tsvector,
        to_tsquery(replace(text(plainto_tsquery('jiebacfg', '%s')), '&', '|'))
    ) AS score
FROM
    public.document
WHERE
    key_word_tsvector @@ to_tsquery(replace(text(plainto_tsquery('jiebacfg', '%s')), '&', '|'))
    AND product_name = '%s'
ORDER BY
    score DESC
LIMIT 1;

Temel işlevler:

to_tsquery bir soruyu tsquery değerine dönüştürür:

SELECT to_tsquery('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库');
                                   to_tsquery
--------------------------------------------------------------------------------
 'postgresql' <2> '世界' <2> '先进' <2> '开源' <-> '关系' <-> '型' <-> '数据库'

<2> kelimeler arasındaki mesafeyi gösterir. <-> bitişik kelimeleri gösterir. 是 ve 的 gibi durdurma kelimeleri otomatik olarak kaldırılır. & VE anlamına gelir, | VEYA anlamına gelir ve ! DEĞİL anlamına gelir.

Kullanıcı girdisi geçersiz operatörler içerebileceğinde to_tsquery yerine plainto_tsquery kullanın:

SELECT to_tsquery('jiebacfg','日志|&堆积');
ERROR:  syntax error in tsquery: "日志|&堆积"

SELECT plainto_tsquery('jiebacfg','日志|&堆积');
 plainto_tsquery
-----------------
 '日志' & '堆积'

VEYA eşleştirmesi için & işaretini | ile değiştirmek amacıyla plainto_tsquery sonucunu bir dizeye dönüştürmek için text işlevini, ardından replace işlevini kullanın:

-- Use the plainto_tsquery function.
SELECT plainto_tsquery('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库');
                          plainto_tsquery
--------------------------------------------------------------------
 'postgresql' & '世界' & '先进' & '开源' & '关系' & '型' & '数据库'

-- Use the plainto_tsquery, text, and replace functions.
SELECT replace(text(plainto_tsquery('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库')), '&', '|');
                            replace
--------------------------------------------------------------------
 'postgresql' | '世界' | '先进' | '开源' | '关系' | '型' | '数据库'

-- Use the to_tsquery, plainto_tsquery, text, and replace functions.
SELECT to_tsquery(replace(text(plainto_tsquery('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库')), '&', '|'));
                           to_tsquery
--------------------------------------------------------------------
 'postgresql' | '世界' | '先进' | '开源' | '关系' | '型' | '数据库'

Alana özgü ifadelerin segmentasyonunu iyileştirmek için pg_jieba sözlüğüne özel terimler ekleyin:

-- Automatically add 关系型 to custom dictionary 0 with a weight of 100000.
INSERT INTO jieba_user_dict VALUES ('关系型',0,100000);

-- Load custom dictionary 0. The first 0 is the dictionary sequence number; the second 0 loads the default dictionary.
SELECT jieba_load_user_dict(0,0);
 jieba_load_user_dict
----------------------

-- Convert a user question into a tsquery value.
SELECT to_tsquery(replace(text(plainto_tsquery('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库')), '&', '|'));
                           to_tsquery
--------------------------------------------------------------------
 'postgresql' | '世界' | '先进' | '开源' | '关系型' | '数据库'

关系型 terimini sözlüğe eklemeden önce, terim '关系' & '型' şeklinde ayrışır. Ekledikten sonra sözlük, bileşik terimi '关系型' tek bir belirteç olarak döndürür.

Operatörler ve puanlama:

Bir tsvector'un bir tsquery ile eşleşip eşleşmediğini kontrol etmek için @@ kullanın. Ağırlık eşleştirmesi sonuçları etkiler:

SELECT to_tsvector('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库') @@ to_tsquery('jiebacfg', 'postgresql:A');
 ?column?
----------
 f

SELECT setweight(to_tsvector('jiebacfg', 'PostgreSQL是世界上先进的开源关系型数据库'),'A') @@ to_tsquery('jiebacfg', 'postgresql:A');
 ?column?
----------
 t

Sorgu, A ağırlığına sahip postgresql arar. Tsvector'a ağırlık atanmadığından ilk ifade false döndürür. setweight uygulandıktan sonra eşleşme başarılı olur.

Bir tsvector'un bir tsquery ile ne kadar iyi eşleştiğini puanlamak için ts_rank kullanın:

WITH sentence AS (
    SELECT 'PostgreSQL是世界上先进的开源关系型数据库' AS content
    UNION ALL
    SELECT 'MySQL是应用广泛的开源关系数据库'
    UNION ALL
    SELECT 'MySQL在全球非常流行'
)
SELECT content,
       ts_rank(to_tsvector('jiebacfg', content), to_tsquery('jiebacfg', 'postgresql | 开源')) AS score
FROM sentence
WHERE to_tsvector('jiebacfg', content) @@ to_tsquery('jiebacfg', 'postgresql | 开源')
ORDER BY score DESC;

                  content                   |    score
--------------------------------------------+-------------
 PostgreSQL是世界上先进的开源关系型数据库 |  0.06079271
 MySQL是应用广泛的开源关系数据库          | 0.030396355

İlk cümle hem postgresql hem de 开源 ile eşleşir ve yalnızca 开源 ile eşleşen ikinci cümleden daha yüksek puan alır. Üçüncü cümle hiçbir terimle eşleşmediği için @@ tarafından filtrelenir.

Segmentasyon hatalarını yönetme:

Kelime segmentasyonu başarısız olursa veya girdi beklenmeyen karakterler içerirse, anahtar kelime eşleştirmesi sonuç döndürmeyebilir. Yedek olarak bulanık eşleştirme için pg_bigm uzantısını kullanın:

WITH sentence AS (
    SELECT 'PostgreSQL是世界上先进的开源关系型数据库' AS content
    UNION ALL
    SELECT 'MySQL是应用广泛的开源关系数据库'
    UNION ALL
    SELECT 'MySQL在全球非常流行'
)
SELECT
    content,
    bigm_similarity(content, 'postgres | 开源产品') AS score
FROM
    sentence
ORDER BY
    score DESC;

                  content                   |   score
--------------------------------------------+------------
  PostgreSQL是世界上先进的开源关系型数据库 | 0.23076923
  MySQL是应用广泛的开源关系数据库          | 0.05263158
  MySQL在全球非常流行                      |        0.0
(3 rows)

bigm_similarity her iki dizeyi de bigramlara (ardışık karakter çiftleri) dönüştürür ve örtüşmeyi hesaplar. Sonuç 0 ile 1 arasında değişir; 1 tam eşleşme anlamına gelir. Bu yöntem, yazım hataları, kısaltmalar veya segmentasyon hataları olduğunda iyi çalışır. Daha fazla bilgi için bkz. Bulanık eşleştirme tabanlı sorgular gerçekleştirmek için pg_bigm uzantısını kullanma.

İçerik anahtar kelime tabanlı geri alım

İçerik anahtar kelime tabanlı geri alım, content_chunk metnini embedding tablosunda belge anahtar kelime tabanlı geri alım ile aynı tam metin arama yaklaşımını kullanarak arar. Belge parçaları anahtar kelime alanlarından daha uzun olduğundan, RUM uzantısı önemli bir performans avantajı sağlar.

Aşağıdaki üç sorgu planı, farklı dizin yaklaşımları kullanan aynı tam metin arama sorgusunu karşılaştırır. Hepsi 'wal日志堆积怎么办' sorgusunu kullanır.

Tam metin aramalarını çalıştırmak için RUM uzantısını kullanma

Seçenek 1: RUM dizini (önerilen)

RUM dizini, ters dizin girişleriyle birlikte kelime konumlarını ve zaman damgalarını saklar; böylece ayrı bir sıralama adımı olmadan sonuçları benzerliğe göre sıralayabilir. Sorgu süresi: 3,2 ms.

EXPLAIN ANALYZE
SELECT
    id,
    doc_id,
    content_chunk,
    ts_vector_extra <=> to_tsquery(
        REPLACE(
            TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
            '&',
            '|'
        )
    ) AS similarity
FROM
    embedding
WHERE
    ts_vector_extra @@ to_tsquery(
        REPLACE(
            TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
            '&',
            '|'
        )
    )
ORDER BY
    similarity
LIMIT
    10;
                                                                     QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=10.15..22.14 rows=10 width=521) (actual time=3.117..3.182 rows=10 loops=1)
   ->  Index Scan using embedding_rumidx on embedding  (cost=10.15..6574.53 rows=5474 width=521) (actual time=3.115..3.179 rows=10 loops=1)
         Index Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
         Order By: (ts_vector_extra <=> to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
 Planning Time: 0.296 ms
 Execution Time: 3.219 ms
(6 rows)

Sorguları hızlandırmak için yerel GIN dizinlerini kullanma

Seçenek 2: ts_vector_extra sütununda GIN dizini

GIN dizini kelime konumlarını saklamaz, bu nedenle PostgreSQL bitmap yığın taraması ve ardından bir sıralama gerçekleştirmelidir. Sorgu süresi: 14,2 ms.

EXPLAIN ANALYZE
SELECT
    id,
    doc_id,
    content_chunk,
    ts_rank(
        ts_vector_extra,
        to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
                '&',
                '|'
            )
        )
    ) AS similarity
FROM
    embedding
WHERE
    ts_vector_extra @@ to_tsquery(
        REPLACE(
            TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
            '&',
            '|'
        )
    )
ORDER BY
    similarity
LIMIT
    10;
                                                                           QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=7178.59..7179.76 rows=10 width=520) (actual time=10.526..14.192 rows=10 loops=1)
   ->  Gather Merge  (cost=7178.59..7718.33 rows=4626 width=520) (actual time=10.525..14.189 rows=10 loops=1)
         Workers Planned: 2
         Workers Launched: 2
         ->  Sort  (cost=6178.57..6184.35 rows=2313 width=520) (actual time=6.879..6.880 rows=10 loops=3)
               Sort Key: (ts_rank(ts_vector_extra, to_tsquery('''wal'' | ''日志'' | ''堆积'''::text)))
               Sort Method: top-N heapsort  Memory: 37kB
               Worker 0:  Sort Method: top-N heapsort  Memory: 39kB
               Worker 1:  Sort Method: top-N heapsort  Memory: 40kB
               ->  Parallel Bitmap Heap Scan on embedding  (cost=56.47..6128.59 rows=2313 width=520) (actual time=0.567..6.367 rows=1637 loops=3)
                     Recheck Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
                     Heap Blocks: exact=1515
                     ->  Bitmap Index Scan on embedding_ts_vector_gin  (cost=0.00..55.08 rows=5551 width=0) (actual time=0.794..0.794 rows=4910 loops=1)
                           Index Cond: (ts_vector_extra @@ to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
 Planning Time: 0.291 ms
 Execution Time: 14.234 ms

to_tsvector('jiebacfg'::regconfig, content_chunk) üzerinde oluşturulan GIN dizinleri

Seçenek 3: İfade üzerinde GIN dizini (önerilmez)

to_tsvector('jiebacfg'::regconfig, content_chunk) üzerinde bir GIN dizini oluşturmak, GIN kelime konumu bilgilerini saklamadığından PostgreSQL'in ts_rank hesaplamak için eşleşen her satırda to_tsvector işlevini yeniden çalıştırması gerektiği anlamına gelir. Sorgu süresi: 1.081 ms — RUM dizininden 300 kat daha yavaş.

EXPLAIN ANALYZE
SELECT
    id,
    doc_id,
    content_chunk,
    ts_rank(
        to_tsvector('jiebacfg', content_chunk),
        to_tsquery(
            REPLACE(
                TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
                '&',
                '|'
            )
        )
    ) AS similarity
FROM
    embedding
WHERE
    to_tsvector('jiebacfg', content_chunk) @@ to_tsquery(
        REPLACE(
            TEXT(plainto_tsquery('jiebacfg', 'wal日志堆积怎么办')),
            '&',
            '|'
        )
    )
ORDER BY
    similarity
LIMIT
    10;
                                                                          QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=8253.58..8254.75 rows=10 width=521) (actual time=1079.289..1081.510 rows=10 loops=1)
   ->  Gather Merge  (cost=8253.58..8786.55 rows=4568 width=521) (actual time=1079.287..1081.508 rows=10 loops=1)
         Workers Planned: 2
         Workers Launched: 2
         ->  Sort  (cost=7253.56..7259.27 rows=2284 width=521) (actual time=1073.189..1073.191 rows=10 loops=3)
               Sort Key: (ts_rank(to_tsvector('jiebacfg'::regconfig, content_chunk), to_tsquery('''wal'' | ''日志'' | ''堆积'''::text)))
               Sort Method: top-N heapsort  Memory: 43kB
               Worker 0:  Sort Method: top-N heapsort  Memory: 42kB
               Worker 1:  Sort Method: top-N heapsort  Memory: 37kB
               ->  Parallel Bitmap Heap Scan on embedding  (cost=55.93..7204.20 rows=2284 width=521) (actual time=2.127..1072.159 rows=1637 loops=3)
                     Recheck Cond: (to_tsvector('jiebacfg'::regconfig, content_chunk) @@ to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
                     Heap Blocks: exact=1028
                     ->  Bitmap Index Scan on embedding_content_gin  (cost=0.00..54.56 rows=5481 width=0) (actual time=0.808..0.809 rows=4910 loops=1)
                           Index Cond: (to_tsvector('jiebacfg'::regconfig, content_chunk) @@ to_tsquery('''wal'' | ''日志'' | ''堆积'''::text))
 Planning Time: 0.459 ms
 Execution Time: 1081.547 ms
(16 rows)

Dizin karşılaştırma özeti:

Dizin türü Yürütme süresi Sıralama nasıl çalışır
ts_vector_extra üzerinde RUM 3,2 ms Yerleşik sıralama ile dizin taraması — sıralama adımı yok
ts_vector_extra üzerinde GIN 14,2 ms Bitmap tarama + paralel sıralama
to_tsvector(content_chunk) üzerinde GIN 1.081 ms Bitmap tarama + satır başına tsvector yeniden hesaplama + sıralama

İçerik anahtar kelime tabanlı geri alım için RUM dizinini (embedding_rumidx) kullanın. Bu yöntem, saklanan sütundaki GIN yaklaşımından 4 kat, ifade üzerindeki GIN yaklaşımından ise 300 kat daha hızlıdır.

BM25 tabanlı geri alım

BM25, belgeleri terim sıklığı (TF) ve ters belge sıklığı (IDF) temelinde puanlayan klasik bir metin eşleştirme algoritmasıdır. Yüksek TF puanı, bir kelimenin bir belgede sık geçtiğini gösterir. Yüksek IDF puanı, bir kelimenin az sayıda belgede geçtiğini ve dolayısıyla daha ayırt edici olduğunu gösterir.

BM25, geri alım kalitesini iyileştirmek için ek parametrelerle TF-IDF modelini optimize eder. Çıktısı, ts_rank tabanlı anahtar kelime geri alımını tamamlar; çünkü her ikisi de terim istatistiklerinde çalışır ancak ağırlık faktörlerini farklı şekilde değerlendirir.

Gömme tabanlı geri alım

ApsaraDB RDS for PostgreSQL, vektör depolama ve benzerlik araması için pgvector uzantısını ve metinden gömme oluşturmak için rds_embedding uzantısını destekler.

pgvector uzantısı, yaklaşık en yakın komşu (ANN) araması için iki dizinleme yöntemi destekler:

  • HNSW (Hiyerarşik Gezilebilir Küçük Dünya) — veriler eklendikçe dizini artımlı olarak oluşturur; eğitim gerekmez; daha hızlı sorgu hızı

  • IVFFlat (Düz Sıkıştırmalı Ters Dosya) — oluşturulmadan önce mevcut veriler üzerinde eğitim gerektirir; biraz daha düşük sorgu hızı

Bu kılavuz, ön eğitim olmadan çalışan ve daha hızlı geri alım sağlayan HNSW'yi kullanır. IVFFlat en iyi uygulamaları için bkz. ApsaraDB RDS for PostgreSQL üzerinde LLM odaklı özel bir sohbet botu oluşturma.

SELECT
    embedding.id,
    doc_id,
    content_chunk,
    content_embedding <=> '%s' AS similarity
FROM
    public.embedding
LEFT JOIN
    document ON document.id = embedding.doc_id
WHERE
    product_name = '%s'
ORDER BY
    similarity
LIMIT %s;

pgvector performans karşılaştırmaları için bkz. Yüksek boyutlu vektör benzerlik aramaları gerçekleştirmek için pgvector uzantısını kullanma.

Sonuç birleştirme

RRF algoritması ve bce-reranker-base_v1 modelini kullanarak dört geri alım yolunun tümünden gelen sonuçları birleştirin ve yeniden sıralayın.

RRF algoritması:

RRF, her belgeye birden fazla geri alım sistemindeki sırasına göre bir puan atar:

RRF(d) = Σ 1/(k + r_i(d))

Burada d belge, r_i(d) belgenin i. sistemdeki sırası ve k yumuşatma sabitidir (genellikle 60 olarak ayarlanır). Birden fazla sistemde yüksek sırada yer alan belgeler daha yüksek RRF puanları biriktirir; bu da tüm geri alım yollarındaki konsensüsü yansıtan birleştirilmiş bir sıralama üretir.

bce-reranker-base_v1 modeli:

bce-reranker-base_v1, Çince, İngilizce, Japonca ve Koreceyi destekleyen çapraz dilli anlamsal yeniden sıralama modelidir. Tek başına RRF'den daha doğru sıralamalar üretir, ancak çok sayıda parça işlerken daha uzun sürer.

Gecikme gereksinimlerinize bağlı olarak aşağıdaki yaklaşımlardan birini seçin:

  • Hızlı yanıtlar için yalnızca RRF kullanın veya bce-reranker-base_v1'i yalnızca en iyi RRF sonuçlarına uygulayın.

  • En yüksek doğruluk için bce-reranker-base_v1'i doğrudan birleştirilmiş sonuç kümesinde çalıştırın.

Soru-cevap analizi

Bilet sohbet botu, her içerik türünün büyük dil modeli (LLM) istemine nasıl akacağını kontrol etmek amacıyla veri kaynağına bağlı olarak farklı ilkeler uygular:

  • Bilgi tabanı içeriği — LLM işleme olmadan doğrudan kullanıcıya sağlanır

  • Yardım dokümantasyonu — Segmentlere ayrılmış HTML düzen artefaktları ve yinelenen metin içerebileceğinden LLM tarafından özetlenir ve biçimlendirilir

  • LLM yedeği — Bilgi tabanı ve dokümantasyon ilgili bir sonuç sağlayamadığında LLM doğrudan yanıt verir

  • Geçmiş biletler — Kullanıcıları tam bilete yönlendiren yalnızca bir başlık ve URL olarak sağlanır

Her yanıt, kaynak belgelere bağlantılar içerir. Yanıt sorunu tamamen çözmezse kullanıcılar daha eksiksiz bilgiler için bağlantıları takip edebilir.

Test sırasında, geri alım ilkesi etkinliğini değerlendirmek için soru-cevap çiftlerini puanlayın. En etkili geri alım yapılandırmasını belirlemek için birden fazla ilke varyantı yazın ve puanları karşılaştırın:

prompt = f\'\'\'请整理并格式化下面的内容并整理输出格式,
        {prompt_content}
        基于自己的能力做出回答,我的问题是:{question}。
        \'\'\'

DingTalk sohbet botuna bağlanma

Bir web uygulaması oluşturmak veya DingTalk sohbet botuna bağlanmak için Streamlit kullanabilirsiniz. Web uygulaması kendi kendine test ve belge yönetimi için kullanılır. DingTalk sohbet botu, tüm kullanıcıların hizmete erişmesine olanak tanır.

Bir DingTalk grubundaki her soru-cevap oturumunda, veritabanı düzeyinde yeni bir bağlantı kurulmalıdır. Sık kısa ömürlü bağlantılar zaman ve bellek tüketir. Bağlantılar hızlı bir şekilde serbest bırakılmazsa örnek bağlantı sınırına ulaşabilir. Bunu önlemek için bir bağlantı havuzu kullanın — uygulamanızda bir tane uygulayın veya ApsaraDB RDS for PostgreSQL'in yerleşik PgBouncer bağlantı havuzunu kullanın.

Örnek

Bu örnek, PostgreSQL, MySQL ve SQL Server hakkında örnek bir veri kümesi kullanarak çok yollu geri alımı gösterir. Sorgu 介绍一下postgresql şeklindedir.

Verileri hazırlama

  1. Gerekli uzantıları ayrıcalıklı bir hesap kullanarak yükleyin:

    Önemli
    • pg_jieba'yı yüklemeden önce, shared_preload_libraries parametresinin pg_jieba değerine value ekleyin. shared_preload_libraries parametresini değiştirme hakkında daha fazla bilgi için bkz. Örnek parametrelerini ayarlama.

    • Yüklenen uzantıları görüntülemek için SELECT * FROM pg_extension; deyimini yürütebilirsiniz.

    CREATE EXTENSION IF NOT EXISTS pg_jieba;
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS rum;
    CREATE EXTENSION IF NOT EXISTS rds_embedding;
  2. RDS örneğinin erişimine izin vermek için RDS örneğinin bulunduğu sanal özel bulut (VPC) için bir NAT ağ geçidi oluşturun. Daha fazla bilgi için bkz. Vektör oluşturmak için rds_embedding uzantısını kullanma.

    Not

    Varsayılan olarak bir RDS örneğine İnternet üzerinden bağlanamazsınız. Alibaba Cloud Model Studio tarafından sağlanan metin gömme modeli gibi harici bir büyük model kullandığınızda, RDS örneğinin harici modellere erişebilmesi için RDS örneğinin bulunduğu VPC için bir NAT ağ geçidi oluşturmanız gerekir.

  3. Gerekli veritabanında doc ve embed adlı test tablolarını oluşturmak ve tablolar için dizinler oluşturmak amacıyla aşağıdaki SQL deyimlerini yürütün:

    --Create the doc test table and an index for the table.
    DROP TABLE IF EXISTS doc;
    
    CREATE TABLE doc (
        id bigserial PRIMARY KEY,
        title character varying(255) UNIQUE,
        key_word character varying(255) DEFAULT \'\'
    );
    
    CREATE INDEX doc_gin ON doc
    USING GIN (to_tsvector(\'jiebacfg\', key_word));
    
    --Create the embed test table and an index for the table.
    DROP TABLE IF EXISTS embed;
    
    CREATE TABLE embed (
        id bigserial PRIMARY KEY,
        doc_id integer,
        content text,
        embedding vector(1536),
        ts_vector_extra tsvector
    );
    
    CREATE INDEX ON embed
    USING hnsw (embedding vector_cosine_ops)
    WITH (
        m = 16,
        ef_construction = 64
    );
  4. Bir tetikleyici oluşturmak için aşağıdaki SQL deyimlerini yürütün. Embed tablosundaki bir satır güncellendiğinde veya satıra veri eklendiğinde ts_vector_extra sütunu otomatik olarak güncellenir.

    -- Convert the text into a tsvector value for full-text search based on keywords.
    CREATE TRIGGER embed_tsvector_update
    BEFORE UPDATE OR INSERT
    ON embed
    FOR EACH ROW
    EXECUTE PROCEDURE tsvector_update_trigger(\'ts_vector_extra\', \'public.jiebacfg\', \'content\');
  5. Embed tablosunda her ekleme veya güncelleme yapıldığında, eklenen veya güncellenen içeriğe dayalı olarak bir gömme oluşturulup embedding sütununda saklanacak şekilde aşağıdaki SQL deyimlerini yürütün.

    Önemli

    Bu örnekte Alibaba Cloud Model Studio tarafından sağlanan metin gömme modeli kullanılır. Alibaba Cloud Model Studio'yu etkinleştirmeniz ve gerekli API anahtarını almanız gerekir. Daha fazla bilgi için bkz. API anahtarı alma.

    -- Convert the question into an embedding. Specify the api_key parameter based on your business requirements.
    CREATE OR REPLACE FUNCTION update_embedding()
    RETURNS TRIGGER AS $$
    BEGIN
        NEW.embedding := rds_embedding.get_embedding_by_model(\'dashscope\', \'sk-****\', NEW.content)::real[];
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    CREATE TRIGGER set_embedding BEFORE INSERT OR UPDATE ON embed FOR EACH ROW EXECUTE FUNCTION update_embedding();
  6. Tabloya test verilerini ekleyin.

    INSERT INTO doc(id, title, key_word) VALUES
    (1, \'PostgreSQL介绍\', \'PostgreSQL 插件\'),
    (2, \'MySQL介绍\', \'MySQL MGR\'),
    (3, \'SQL Server介绍\', \'SQL Server Microsoft\');
    
    INSERT INTO embed(doc_id, content) VALUES
    (1, \'PostgreSQL是以加州大学伯克利分校计算机系开发的POSTGRES,版本 4.2为基础的对象关系型数据库管理系统(ORDBMS)。 POSTGRES领先的许多概念在很久以后才出现在一些商业数据库系统中\'),
    (1, \'PostgreSQL是最初的伯克利代码的开源继承者。 它支持大部分SQL标准并且提供了许多现代特性:复杂查询、外键、触发器、可更新视图、事务完整性、多版本并发控制,同样,PostgreSQL可以用许多方法扩展,比如,通过增加新的:数据类型、函数、操作符、聚集函数、索引方法、过程语言\'),
    (1, \'并且,因为自由宽松的许可证,任何人都可以以任何目的免费使用、修改和分发PostgreSQL,不管是私用、商用还是学术研究目的。 \'),
    (1, \'Ganos插件和PostGIS插件不能安装在同一个Schema下\'),
    (1, \'丰富的生态系统:有大量现成的插件和扩展可供使用,比如PostGIS(地理信息处理)、TimescaleDB(时间序列数据库)、pg_stat_statements(性能监控)等,能够满足不同场景的需要\');
    
    INSERT INTO embed(doc_id, content) VALUES
    (2, \'MySQL名称的起源不明。 10多年来,我们的基本目录以及大量库和工具均采用了前缀"my"。 不过,共同创办人Monty Widenius的女儿名字也叫"My"。 时至今日,MySQL名称的起源仍是一个迷,即使对我们也一样\'),
    (2, \'MySQL软件采用双许可方式。 用户可根据GNU通用公共许可(http://www.fsf.org/licenses/)条款,将MySQL软件作为开放源码产品使用,或从MySQL AB公司购买标准的商业许可证。 关于我方许可策略的更多信息,请参见http://www.mysql.com/company/legal/licensing/。 \'),
    (2, \'组复制MySQL Group Replication(简称MGR)是MySQL官方在已有的Binlog复制框架之上,基于Paxos协议实现的一种分布式复制形态。 RDS MySQL集群系列实例支持组复制。 本文介绍如何使复制方式为组复制。 使用了组复制的MySQL集群能够基于分布式Paxos协议自我管理,具有很强的数据可靠性和数据一致性。 相比传统主备复制方式,组复制具有以下优势:数据的强一致性,数据的强可靠性,全局事务强一致性\');
    
    INSERT INTO embed(doc_id, content) VALUES
    (3, \'Microsoft SQL Server是一种关系数据库管理系统 (RDBMS)。 应用程序和工具连接到SQL Server实例或数据库,并使用Transact-SQL (T-SQL)进行通信。 \'),
    (3, \'SQL Server 2022 (16.x)在早期版本的基础上构建,旨在将SQL Server发展成一个平台,以提供开发语言、数据类型、本地或云环境以及操作系统选项。 \'),
    (3, \'SQL Server在企业级应用中广受欢迎,与其他Microsoft产品(如Excel、Power BI)无缝集成,便于数据分析\');

Çok yollu geri alımı çalıştırma

introducepostgresql sorgu metnini birden fazla yöntemle almak ve ilgili belgeleri benzerliğe göre sıralamak için aşağıdaki SQL deyimlerini yürütün.

-- The text that you want to query.
WITH query AS (
    SELECT \'介绍一下postgresql\' AS query_text
),
-- Convert the question into an embedding. Replace sk-**** with the API key obtained from Alibaba Cloud Model Studio.
query_embedding AS (
    SELECT rds_embedding.get_embedding_by_model(\'dashscope\', \'sk-****\', query.query_text)::real[]::vector AS embedding
    FROM query
),
-- Document keyword search: score by ts_rank (higher = better match).
first_method AS (
    SELECT
        id,
        title,
        ts_rank(to_tsvector(\'jiebacfg\', doc.key_word),
                to_tsquery(replace(text(plainto_tsquery(\'jiebacfg\', (SELECT query_text FROM query))), \'&\', \'|\'))) AS score,
        \'doc_key_word\' AS method
    FROM doc
    WHERE
        to_tsvector(\'jiebacfg\', doc.key_word) @@
        to_tsquery(replace(text(plainto_tsquery(\'jiebacfg\', (SELECT query_text FROM query))), \'&\', \'|\'))
    ORDER BY
        score DESC
    LIMIT 3
),
-- Content keyword search: score by RUM <=> operator (lower = better match).
second_method AS (
    SELECT
        id,
        doc_id,
        content,
        to_tsvector(\'jiebacfg\', content) <=>
        to_tsquery(replace(text(plainto_tsquery(\'jiebacfg\', (SELECT query_text FROM query))), \'&\', \'|\')) AS score,
        \'content_key_word\' AS method
    FROM embed
    WHERE
        to_tsvector(\'jiebacfg\', content) @@
        to_tsquery(replace(text(plainto_tsquery(\'jiebacfg\', (SELECT query_text FROM query))), \'&\', \'|\'))
    ORDER BY
        score
    LIMIT 3
),
-- Embedding search: score by cosine distance <=> (lower = better match).
third_method AS (
    SELECT
        embed.id,
        embed.doc_id,
        embed.content,
        embedding <=> (SELECT embedding FROM query_embedding LIMIT 1) AS score,
        \'embedding\' AS method
    FROM embed
    ORDER BY score
    LIMIT 3
)
-- Join to retrieve document titles and combine results from all three methods.
SELECT
    first_method.title,
    embed.id AS chunk_id,
    SUBSTRING(embed.content FROM 1 FOR 30),
    first_method.score,
    first_method.method
FROM first_method
LEFT JOIN embed ON first_method.id = embed.doc_id
UNION
SELECT
    doc.title,
    second_method.id AS chunk_id,
    SUBSTRING(second_method.content FROM 1 FOR 30),
    second_method.score,
    second_method.method
FROM second_method
LEFT JOIN doc ON second_method.doc_id = doc.id
UNION
SELECT
    doc.title,
    third_method.id AS chunk_id,
    SUBSTRING(third_method.content FROM 1 FOR 30),
    third_method.score,
    third_method.method
FROM third_method
LEFT JOIN doc ON third_method.doc_id = doc.id
ORDER BY method, score;

Çıktı:

     title      | chunk_id |                          substring                           |        score         |      method
----------------+----------+--------------------------------------------------------------+----------------------+------------------
 PostgreSQL介绍 |        3 | PostgreSQL是最初的伯克利代码的开源继承者。 它支持大           |   13.159472465515137 | content_key_word
 PostgreSQL介绍 |        2 | PostgreSQL是以加州大学伯克利分校计算机系开发的PO             |     16.4493408203125 | content_key_word
 PostgreSQL介绍 |        4 | 并且,因为自由宽松的许可证,任何人都可以以任何目的免费使用、 |     16.4493408203125 | content_key_word
 PostgreSQL介绍 |        6 | 丰富的生态系统:有大量现成的插件和扩展可供使用,比如Post     | 0.020264236256480217 | doc_key_word
 PostgreSQL介绍 |        5 | Ganos插件和PostGIS插件不能安装在同一个Schem                  | 0.020264236256480217 | doc_key_word
 PostgreSQL介绍 |        3 | PostgreSQL是最初的伯克利代码的开源继承者。 它支持大           | 0.020264236256480217 | doc_key_word
 PostgreSQL介绍 |        2 | PostgreSQL是以加州大学伯克利分校计算机系开发的PO             | 0.020264236256480217 | doc_key_word
 PostgreSQL介绍 |        4 | 并且,因为自由宽松的许可证,任何人都可以以任何目的免费使用、 | 0.020264236256480217 | doc_key_word
 PostgreSQL介绍 |        2 | PostgreSQL是以加州大学伯克利分校计算机系开发的PO             |   0.2546271233144539 | embedding
 PostgreSQL介绍 |        3 | PostgreSQL是最初的伯克利代码的开源继承者。 它支持大           |  0.28679098231865074 | embedding
 PostgreSQL介绍 |        6 | 丰富的生态系统:有大量现成的插件和扩展可供使用,比如Post     |  0.41783296077761967 | embedding

Üç geri alım yöntemi de PostgreSQL介绍 için sonuç döndürür; bu da anahtar kelime tabanlı, içerik tabanlı ve gömme tabanlı yaklaşımların tümünün doğru belgeyi tanımladığını doğrular.

İlgili konular

RAG'de ApsaraDB RDS for PostgreSQL en iyi uygulamaları hakkında daha fazla bilgi için aşağıdaki konulara bakın: