Open In Colab GitHub Repository

RAG menggunakan Pencarian Hibrida dengan Milvus dan LlamaIndex

Pencarian hibrida memanfaatkan kekuatan pencarian semantik dan pencocokan kata kunci untuk memberikan hasil yang lebih akurat dan relevan secara kontekstual. Dengan menggabungkan keunggulan pencarian semantik dan pencocokan kata kunci, pencarian hibrida sangat efektif dalam tugas-tugas pencarian informasi yang kompleks.

Buku catatan ini mendemonstrasikan cara menggunakan Milvus untuk pencarian hibrida di pipeline LlamaIndex RAG. Kita akan mulai dengan pencarian hibrida default yang direkomendasikan (semantik + BM25) dan kemudian mengeksplorasi metode-metode penyematan jarang alternatif lainnya dan kustomisasi perangking hibrida.

Prasyarat

Instal dependensi

Sebelum memulai, pastikan Anda telah menginstal dependensi berikut ini:

$ pip install llama-index-vector-stores-milvus
$ pip install llama-index-embeddings-openai
$ pip install llama-index-llms-openai

Jika Anda menggunakan Google Colab, Anda mungkin perlu memulai ulang runtime (Navigasikan ke menu "Runtime" di bagian atas antarmuka, dan pilih "Mulai ulang sesi" dari menu tarik-turun).

Menyiapkan akun

Tutorial ini menggunakan OpenAI untuk penyematan teks dan pembuatan jawaban. Anda perlu menyiapkan kunci API OpenAI.

import openai

openai.api_key = "sk-"

Untuk menggunakan penyimpanan vektor Milvus, tentukan server Milvus Anda URI (dan secara opsional dengan TOKEN). Untuk memulai server Milvus, Anda dapat mengatur server Milvus dengan mengikuti panduan instalasi Milvus atau mencoba Zilliz Cloud secara gratis.

Pencarian teks lengkap saat ini didukung di Milvus Standalone, Milvus Distributed, dan Zilliz Cloud, tetapi belum di Milvus Lite (direncanakan untuk implementasi di masa mendatang). Hubungi support@zilliz.com untuk informasi lebih lanjut.

URI = "http://localhost:19530"
# TOKEN = ""

Memuat data contoh

Jalankan perintah berikut untuk mengunduh dokumen contoh ke dalam direktori "data/paul_graham":

$ mkdir -p 'data/paul_graham/'
$ wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'

Kemudian gunakan SimpleDirectoryReaderLoad untuk memuat esai "What I Worked On" oleh Paul Graham:

from llama_index.core import SimpleDirectoryReader

documents = SimpleDirectoryReader("./data/paul_graham/").load_data()

# Let's take a look at the first document
print("Example document:\n", documents[0])
Example document:
 Doc ID: f9cece8c-9022-46d8-9d0e-f29d70e1dbbe
Text: What I Worked On  February 2021  Before college the two main
things I worked on, outside of school, were writing and programming. I
didn't write essays. I wrote what beginning writers were supposed to
write then, and probably still are: short stories. My stories were
awful. They had hardly any plot, just characters with strong feelings,
which I ...

Pencarian Gabungan dengan BM25

Bagian ini menunjukkan cara melakukan pencarian gabungan menggunakan BM25. Untuk memulai, kita akan menginisialisasi MilvusVectorStore dan membuat indeks untuk dokumen contoh. Konfigurasi default yang digunakan:

  • Penyematan padat dari model penyematan default ( text-embedding-ada-002 milik OpenAI)
  • BM25 untuk pencarian teks lengkap jika enable_sparse bernilai True
  • RRFRanker dengan k = 60 untuk menggabungkan hasil jika pencarian hibrida diaktifkan
# Create an index over the documnts
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.core import StorageContext, VectorStoreIndex


vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,  # vector dimension depends on the embedding model
    enable_sparse=True,  # enable the default full-text search using BM25
    overwrite=True,  # drop the collection if it already exists
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
2025-04-17 03:38:16,645 [DEBUG][_create_connection]: Created new connection using: cf0f4df74b18418bb89ec512063c1244 (async_milvus_client.py:547)
Sparse embedding function is not provided, using default.
Default sparse embedding function: BM25BuiltInFunction(input_field_names='text', output_field_names='sparse_embedding').

Berikut adalah informasi lebih lanjut tentang argumen untuk mengonfigurasi bidang padat dan bidang jarang di MilvusVectorStore:

bidang padat

  • enable_dense (bool): Bendera boolean untuk mengaktifkan atau menonaktifkan penyematan padat. Nilai defaultnya adalah True (Benar).
  • dim (int, optional): Dimensi vektor penyematan untuk koleksi.
  • embedding_field (str, optional): Nama bidang penyematan padat untuk koleksi, nilai defaultnya adalah DEFAULT_EMBEDDING_KEY.
  • index_config (dict, optional): Konfigurasi yang digunakan untuk membangun indeks embedding padat. Defaultnya adalah Tidak Ada.
  • search_config (dict, optional): Konfigurasi yang digunakan untuk mencari indeks padat Milvus. Perhatikan bahwa ini harus kompatibel dengan jenis indeks yang ditentukan oleh index_config. Setelan default untuk Tidak Ada.
  • similarity_metric (str, optional): Metrik kemiripan yang digunakan untuk penyematan padat, saat ini mendukung IP, COSINE, dan L2.

sparse field

  • enable_sparse (bool): Bendera boolean untuk mengaktifkan atau menonaktifkan penyematan jarang. Defaultnya adalah False.
  • sparse_embedding_field (str): Nama bidang penyematan jarang, defaultnya adalah DEFAULT_SPARSE_EMBEDDING_KEY.
  • sparse_embedding_function (Union[BaseSparseEmbeddingFunction, BaseMilvusBuiltInFunction], optional): Jika enable_sparse bernilai True, objek ini harus disediakan untuk mengonversi teks ke sematan jarang. Jika Tidak Ada, fungsi penyematan jarang default (BM25BuiltInFunction) akan digunakan, atau gunakan BGEM3SparseEmbedding jika koleksi yang ada tidak memiliki fungsi bawaan.
  • sparse_index_config (dict, optional): Konfigurasi yang digunakan untuk membangun indeks sematan jarang. Defaultnya adalah Tidak Ada.

Untuk mengaktifkan pencarian hibrida selama tahap kueri, setel vector_store_query_mode ke "hibrida". Ini akan menggabungkan dan memberi peringkat ulang hasil pencarian dari pencarian semantik dan pencarian teks lengkap. Mari kita uji dengan contoh kueri: "Apa yang dipelajari penulis di Viaweb?":

import textwrap

query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(response), 100))
The author learned about retail, the importance of user feedback, and the significance of growth
rate as the ultimate test of a startup at Viaweb.

Menyesuaikan penganalisis teks

Penganalisis memainkan peran penting dalam pencarian teks lengkap dengan memecah kalimat menjadi token dan melakukan pemrosesan leksikal, seperti stemming dan penghilangan kata berimbuhan. Penganalisis biasanya bersifat spesifik untuk bahasa tertentu. Untuk lebih jelasnya, lihat Panduan Penganalisis Milvus.

Milvus mendukung dua jenis penganalisis: Penganalisis bawaan dan Penganalisis Khusus. Secara default, jika enable_sparse diatur ke True, MilvusVectorStore menggunakan BM25BuiltInFunction dengan konfigurasi default, menggunakan penganalisis bawaan standar yang menandai teks berdasarkan tanda baca.

Untuk menggunakan penganalisis yang berbeda atau menyesuaikan yang sudah ada, Anda dapat memberikan nilai pada argumen analyzer_params saat membuat BM25BuiltInFunction. Kemudian, tetapkan fungsi ini sebagai sparse_embedding_function di MilvusVectorStore.

from llama_index.vector_stores.milvus.utils import BM25BuiltInFunction

bm25_function = BM25BuiltInFunction(
    analyzer_params={
        "tokenizer": "standard",
        "filter": [
            "lowercase",  # Built-in filter
            {"type": "length", "max": 40},  # Custom cap size of a single token
            {"type": "stop", "stop_words": ["of", "to"]},  # Custom stopwords
        ],
    },
    enable_match=True,
)

vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    enable_sparse=True,
    sparse_embedding_function=bm25_function,  # BM25 with custom analyzer
    overwrite=True,
)
2025-04-17 03:38:48,085 [DEBUG][_create_connection]: Created new connection using: 61afd81600cb46ee89f887f16bcbfe55 (async_milvus_client.py:547)

Pencarian Hibrida dengan Penyematan Jarang Lainnya

Selain menggabungkan pencarian semantik dengan BM25, Milvus juga mendukung pencarian hibrida menggunakan fungsi sematan jarang seperti BGE-M3. Contoh berikut ini menggunakan BGEM3SparseEmbeddingFunction bawaan untuk menghasilkan sematan jarang.

Pertama, kita perlu menginstal paket FlagEmbedding:

$ pip install -q FlagEmbedding

Kemudian mari kita buat penyimpanan vektor dan indeks menggunakan model OpenAI bawaan untuk embedding densen dan BGE-M3 bawaan untuk embedding jarang:

from llama_index.vector_stores.milvus.utils import BGEM3SparseEmbeddingFunction

vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    enable_sparse=True,
    sparse_embedding_function=BGEM3SparseEmbeddingFunction(),
    overwrite=True,
)

storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 68871.99it/s]
2025-04-17 03:39:02,074 [DEBUG][_create_connection]: Created new connection using: ff4886e2f8da44e08304b748d9ac9b51 (async_milvus_client.py:547)
Chunks: 100%|██████████| 1/1 [00:00<00:00,  1.07it/s]

Sekarang mari kita lakukan kueri penelusuran hibrida dengan contoh pertanyaan:

query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb??")
print(textwrap.fill(str(response), 100))
Chunks: 100%|██████████| 1/1 [00:00<00:00, 17.29it/s]


The author learned about retail, the importance of user feedback, the value of growth rate in a
startup, the significance of pricing strategy, the benefits of working on things that weren't
prestigious, and the challenges and rewards of running a startup.

Menyesuaikan Fungsi Penyematan Jarang

Anda juga dapat menyesuaikan fungsi sematan jarang selama fungsi tersebut diwarisi dari BaseSparseEmbeddingFunction, termasuk metode berikut ini:

  • encode_queries: Metode ini mengubah teks menjadi daftar sematan jarang untuk kueri.
  • encode_documents: Metode ini mengubah teks menjadi daftar sematan jarang untuk dokumen.

Keluaran dari setiap metode harus mengikuti format sematan jarang, yaitu daftar kamus. Setiap kamus harus memiliki kunci (bilangan bulat) yang mewakili dimensi, dan nilai yang sesuai (float) yang mewakili besarnya penyematan dalam dimensi tersebut (misalnya, {1: 0.5, 2: 0.3}).

Sebagai contoh, berikut ini adalah implementasi fungsi penyematan jarang kustom menggunakan BGE-M3:

from FlagEmbedding import BGEM3FlagModel
from typing import List
from llama_index.vector_stores.milvus.utils import BaseSparseEmbeddingFunction


class ExampleEmbeddingFunction(BaseSparseEmbeddingFunction):
    def __init__(self):
        self.model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=False)

    def encode_queries(self, queries: List[str]):
        outputs = self.model.encode(
            queries,
            return_dense=False,
            return_sparse=True,
            return_colbert_vecs=False,
        )["lexical_weights"]
        return [self._to_standard_dict(output) for output in outputs]

    def encode_documents(self, documents: List[str]):
        outputs = self.model.encode(
            documents,
            return_dense=False,
            return_sparse=True,
            return_colbert_vecs=False,
        )["lexical_weights"]
        return [self._to_standard_dict(output) for output in outputs]

    def _to_standard_dict(self, raw_output):
        result = {}
        for k in raw_output:
            result[int(k)] = raw_output[k]
        return result

Menyesuaikan reranker hibrida

Milvus mendukung dua jenis strategi perankingan ulang: Reciprocal Rank Fusion (RRF) dan Penilaian Tertimbang. Pemeringkat default dalam pencarian hybrid MilvusVectorStore adalah RRF dengan k=60. Untuk menyesuaikan pemeringkat hibrida, ubah parameter berikut ini:

  • hybrid_ranker (str): Menentukan jenis pemeringkat yang digunakan dalam kueri penelusuran hibrida. Saat ini hanya mendukung ["RRFRanker", "WeightedRanker"]. Defaultnya adalah "RRFRanker".
  • hybrid_ranker_params (dict, optional): Parameter konfigurasi untuk pemeringkat hibrida. Struktur kamus ini tergantung pada pemeringkat spesifik yang digunakan:
    • Untuk "RRFRanker", harus menyertakan:
      • "k" (int): Parameter yang digunakan dalam Reciprocal Rank Fusion (RRF). Nilai ini digunakan untuk menghitung skor peringkat sebagai bagian dari algoritme RRF, yang menggabungkan beberapa strategi peringkat menjadi satu skor untuk meningkatkan relevansi penelusuran. Nilai defaultnya adalah 60 jika tidak ditentukan.
    • Untuk "WeightedRanker", diharapkan:
      • "bobot" (daftar mengambang): Daftar yang terdiri dari dua bobot:
        1. Bobot untuk komponen penyematan padat.
        2. Bobot untuk komponen penyematan yang jarang. Bobot ini digunakan untuk menyeimbangkan signifikansi komponen penyematan yang padat dan jarang dalam proses pengambilan hibrida. Bobot default adalah [1.0, 1.0] jika tidak ditentukan.
vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    overwrite=False,  # Use the existing collection created in the previous example
    enable_sparse=True,
    hybrid_ranker="WeightedRanker",
    hybrid_ranker_params={"weights": [1.0, 0.5]},
)
index = VectorStoreIndex.from_vector_store(vector_store)
query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(response), 100))
2025-04-17 03:44:00,419 [DEBUG][_create_connection]: Created new connection using: 09c051fb18c04f97a80f07958856587b (async_milvus_client.py:547)
Sparse embedding function is not provided, using default.
No built-in function detected, using BGEM3SparseEmbeddingFunction().
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 136622.28it/s]
Chunks: 100%|██████████| 1/1 [00:00<00:00,  1.07it/s]


The author learned several valuable lessons at Viaweb, including the importance of understanding
growth rate as the ultimate test of a startup, the significance of user feedback in shaping the
software, and the realization that web applications were the future of software development.
Additionally, the experience at Viaweb taught the author about the challenges and rewards of running
a startup, the value of simplicity in software design, and the impact of pricing strategies on
attracting customers.

Coba Milvus yang Dikelola secara Gratis

Zilliz Cloud bebas masalah, didukung oleh Milvus dan 10x lebih cepat.

Mulai
Umpan balik

Apakah halaman ini bermanfaat?