07. Pencari Beberapa VectorStore (MultiVectorRetriever)

MultiVectorRetriever

LangChain menyediakan fitur khusus, MultiVectorRetriever, yang memungkinkan Anda untuk melakukan kueri dokumen secara efisien dalam berbagai situasi. Fitur ini memungkinkan Anda untuk menyimpan dan mengelola dokumen sebagai beberapa vektor, yang dapat sangat meningkatkan akurasi dan efisiensi pencarian informasi. Hari ini kita akan melihat beberapa cara untuk memanfaatkan MultiVectorRetriever ini untuk membuat beberapa vektor per dokumen.

Metode untuk menghasilkan beberapa vektor per dokumen:

  1. Membuat potongan yang lebih kecil: Pisahkan dokumen Anda menjadi unit yang lebih kecil dan buat penyematan terpisah untuk setiap potongan. Pendekatan ini memungkinkan Anda untuk memberikan perhatian lebih pada bagian tertentu dari dokumen. Proses ini dapat diimplementasikan melalui ParentDocumentRetriever, yang membuatnya lebih mudah untuk menavigasi ke detail.

  2. Penyematan ringkasan: Buat ringkasan setiap dokumen, dan buat penyematan dari ringkasan ini. Penyematan ringkasan ini adalah cara yang bagus untuk mendapatkan inti dari dokumen dengan cepat. Daripada menganalisis seluruh dokumen, Anda dapat memanfaatkan poin-poin penting untuk efisiensi maksimum.

  3. Memanfaatkan pertanyaan hipotetis: Buat pertanyaan hipotetis yang sesuai untuk setiap artikel dan buat sematan berdasarkan pertanyaan tersebut. Hal ini berguna saat Anda ingin menjelajahi topik atau konten tertentu secara mendalam. Pertanyaan hipotetis memungkinkan Anda untuk mendekati konten artikel dari perspektif yang berbeda dan memberikan pemahaman yang lebih luas.

  4. Ditambahkan secara manual: Pengguna dapat menambahkan secara manual pertanyaan atau kueri spesifik yang ingin mereka pertimbangkan saat mencari dokumen. Metode ini memberi pengguna kontrol lebih besar atas proses pencarian dan memungkinkan mereka untuk menyesuaikan pencarian dengan kebutuhan mereka sendiri.

Dengan memiliki fleksibilitas untuk memanfaatkan pendekatan yang berbeda ini dengan MultiVectorRetriever, pengguna dapat menemukan informasi yang mereka butuhkan dengan lebih akurat dan cepat. Fitur LangChain ini merupakan alat yang hebat untuk membuat tugas pencarian informasi menjadi lebih efektif.

Cara kerja

Memuat data dari file teks dan melakukan prapemrosesan untuk membagi dokumen yang dimuat ke dalam ukuran tertentu.

Dokumen yang tersegmentasi nantinya dapat digunakan untuk operasi seperti vektorisasi dan pencarian.

loaders = [
    # Memuat data pertama.
    TextLoader("./data/ai-story.txt"),
    # Memuat data kedua.
    TextLoader("./data/appendix-keywords.txt"),
]
docs = []  # Menginisialisasi daftar dokumen kosong.
for loader in loaders:
    docs.extend(loader.load())  # Memuat dokumen dari setiap loader dan menambahkannya ke dalam daftar docs.

Dokumen asli yang dimuat dari data disimpan dalam variabel docs.

Membuat potongan-potongan kecil

Ketika mencari informasi dalam jumlah besar, akan sangat berguna untuk menyematkan informasi dalam potongan-potongan yang lebih kecil.

Hal ini memungkinkan penyematan untuk menangkap makna semantik sedekat mungkin, sambil meneruskan konteks sebanyak mungkin ke hilir.

Inilah yang dilakukan oleh ParentDocumentRetriever

# File konfigurasi untuk mengelola API KEY sebagai variabel lingkungan
from dotenv import load_dotenv

# Memuat informasi API KEY
load_dotenv()
# Vektor penyimpanan yang digunakan untuk mengindeks chunk anak
import uuid

vectorstore = Chroma(
    collection_name="full_documents", embedding_function=OpenAIEmbeddings()
)
# Penyimpanan tingkat penyimpanan untuk dokumen induk
store = InMemoryByteStore()

id_key = "doc_id"
# Retriever (kosong saat dimulai)
retriever = MultiVectorRetriever(
    vectorstore=vectorstore,
    byte_store=store,
    id_key=id_key,
)

# Menghasilkan ID dokumen.
doc_ids = [str(uuid.uuid4()) for _ in docs]
# Memeriksa dua ID yang dihasilkan.
doc_ids
['89a0baf8-4040-4132-8a0e-dd61c61413a9', 'cc59fe43-e750-4ca6-ae25-a618043bed3b']

di mana kita mendefinisikan parent_text_splitter untuk membagi menjadi potongan-potongan yang lebih besar

child_text_splitter untuk membagi menjadi potongan-potongan yang lebih kecil.

# Membuat objek RecursiveCharacterTextSplitter.
parent_text_splitter = RecursiveCharacterTextSplitter(chunk_size=4000)

# Splitter yang akan digunakan untuk membuat chunk yang lebih kecil
child_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
  • Pisahkan dokumen menjadi beberapa bagian menggunakan parent_text_splitter.

  • Dalam metadata untuk setiap dokumen, masukkan uuid yang Anda buat dengan “doc_id” sebagai kuncinya.

  • Pada akhirnya, daftar parent_docs akan berisi dokumen asli yang dipecah menjadi beberapa bagian yang lebih besar, dengan setiap dokumen berisi ID dokumen asli sebagai metadata.

parent_docs = []

for i, doc in enumerate(docs):
    _id = doc_ids[i]  # Mengambil ID dari dokumen saat ini.
    # Membagi dokumen saat ini menjadi dokumen-dokumen kecil.
    parent_doc = parent_text_splitter.split_documents([doc])
    for _doc in parent_doc:  # Mengulang setiap dokumen yang telah dibagi.
        # Menyimpan ID di metadata dokumen.
        _doc.metadata[id_key] = _id
    parent_docs.extend(parent_doc)  # Menambahkan dokumen yang telah dibagi ke dalam daftar.
  • Gunakan child_text_splitter untuk membagi dokumen menjadi bagian yang lebih kecil.

  • Pada metadata untuk setiap dokumen, masukkan uuid yang Anda buat dengan “doc_id” sebagai kuncinya. Ini untuk memberikan ID pada bagian yang lebih kecil sebagai ID dokumen.

  • Pada akhirnya, daftar child_docs akan berisi dokumen asli yang dipecah menjadi potongan-potongan yang lebih kecil, masing-masing dengan ID dokumen asli sebagai metadata.

child_docs = []  # Menginisialisasi daftar untuk menyimpan dokumen-dokumen kecil.
for i, doc in enumerate(docs):
    _id = doc_ids[i]  # Mengambil ID dari dokumen saat ini.
    # Membagi dokumen saat ini menjadi dokumen-dokumen kecil.
    child_doc = child_text_splitter.split_documents([doc])
    for _doc in child_doc:  # Mengulang setiap dokumen kecil yang telah dibagi.
        # Menyimpan ID di metadata dokumen kecil.
        _doc.metadata[id_key] = _id
    child_docs.extend(child_doc)  # Menambahkan dokumen kecil yang telah dibagi ke dalam daftar.

Periksa jumlah potongan yang dibagi ke dalam masing-masing bagian.

print(f"Jumlah parent_docs yang telah dibagi: {len(parent_docs)}")
print(f"Jumlah child_docs yang telah dibagi: {len(child_docs)}")
Jumlah parent_docs yang telah dibagi: 3
Jumlah child_docs yang telah dibagi: 29

Tambahkan kumpulan subdokumen yang lebih kecil yang baru dibuat ke penyimpanan vektor.

Selanjutnya, kita tambahkan dokumen induk ke docstore dengan memetakannya ke UUID yang telah dibuat.

  • Gunakan metode mset() untuk menyimpan ID dokumen dan konten dokumen sebagai pasangan kunci-nilai di dalam penyimpanan dokumen.

(Contoh) list(zip(doc_ids, docs))[0]

# Menambahkan dokumen ke repositori vektor.
retriever.vectorstore.add_documents(parent_docs)
retriever.vectorstore.add_documents(child_docs)

# Menyimpan ID dokumen dan dokumen ke dalam penyimpanan dokumen dengan memetakannya.
retriever.docstore.mset(list(zip(doc_ids, docs)))

Melakukan pencarian kemiripan untuk kata kunci yang diberikan. Mengeluarkan fragmen dokumen pertama dengan kemiripan tertinggi.

# Lakukan pencarian kemiripan di vectorstore.
retriever.vectorstore.similarity_search("Apa definisi dari Word2Vec?")
[Document(metadata={'doc_id': '408f5cc2-294e-4fdd-bd73-23fb2ac77b15', 'source': 'ce1/StudioProjects/owen/python/langchainbook/appendix-keywords.txt'}, page_content='Definisi: Word2Vec adalah teknik pemrosesan bahasa alami yang memetakan kata-kata ke dalam ruang vektor untuk merepresentasikan hubungan semantik antar kata. Teknik ini menghasilkan vektor berdasarkan kesamaan konteks kata.\nContoh: Dalam model Word2Vec, "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor.'), Document(metadata={'doc_id': '408f5cc2-294e-4fdd-bd73-23fb2ac77b15', 'source': 'n/langchainbook/appendix-keywords.txt'}, page_content='Crawling\n\nDefinisi: Crawling adalah proses mengunjungi halaman web secara otomatis untuk mengumpulkan data. Ini sering digunakan dalam optimasi mesin pencari atau analisis data.\nContoh: Mesin pencari Google mengunjungi situs web di internet untuk mengumpulkan konten dan membuat indeks, yang dikenal sebagai crawling.\nKata Kunci Terkait: Pengumpulan Data, Web Scraping, Mesin Pencari\n\nWord2Vec'), Document(metadata={'doc_id': '408f5cc2-294e-4fdd-bd73-23fb2ac77b15', 'source': '6gboffice1/StudioProjects/owen/python/langchainbook/appendix-keywords.txt'}, page_content='Contoh: Dalam model Word2Vec, "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor.\nKata Kunci Terkait: Pemrosesan Bahasa Alami, Embedding, Kesamaan Semantik'), Document(metadata={'doc_id': '408f5cc2-294e-4fdd-bd73-23fb2ac77b15', 'source': 'n/python/langchainbook/appendix-keywords.txt'}, page_content='Embedding\n\nDefinisi: Embedding adalah proses mengubah data teks seperti kata atau kalimat menjadi vektor berdimensi rendah yang berkelanjutan. Ini memungkinkan komputer untuk memahami dan memproses teks.\nContoh: Kata "apel" dapat direpresentasikan sebagai vektor seperti [0,65, -0,23, 0,17].\nKata Kunci Terkait: Pemrosesan Bahasa Alami, Vektorisasi, Pembelajaran Mendalam\n\nToken')]

Anda dapat menambahkan ambang batas skor untuk melakukan pencarian kemiripan seperti ini

Hasil pencarian kemiripan hanya akan mengembalikan hasil dengan nilai kemiripan 0,5 atau lebih tinggi.

Anda juga dapat menentukan faktor k, di mana k adalah jumlah dokumen yang dicari.

# Melakukan pencarian kesamaan menggunakan score_threshold.
retriever.vectorstore.similarity_search_with_relevance_scores(
    "Apa definisi dari Word2Vec?", score_threshold=0.5, k=3
)
[(Document(metadata={'doc_id': '712edab2-f26b-4ea0-b958-425fbe7eb5de', 'source': '.ywords.txt'}, page_content='Definisi: Word2Vec adalah teknik pemrosesan bahasa alami yang memetakan kata-kata ke dalam ruang vektor untuk merepresentasikan hubungan semantik antar kata. Teknik ini menghasilkan vektor berdasarkan kesamaan konteks kata.\nContoh: Dalam model Word2Vec, "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor.'), 0.8983794806742923), (Document(metadata={'doc_id': '712edab2-f26b-4ea0-b958-425fbe7eb5de', 'source': '.'}, page_content='Crawling\n\nDefinisi: Crawling adalah proses mengunjungi halaman web secara otomatis untuk mengumpulkan data. Ini sering digunakan dalam optimasi mesin pencari atau analisis data.\nContoh: Mesin pencari Google mengunjungi situs web di internet untuk mengumpulkan konten dan membuat indeks, yang dikenal sebagai crawling.\nKata Kunci Terkait: Pengumpulan Data, Web Scraping, Mesin Pencari\n\nWord2Vec'), 0.8248520380539303), (Document(metadata={'doc_id': '712edab2-f26b-4ea0-b958-425fbe7eb5de', 'source': '.'}, page_content='Contoh: Dalam model Word2Vec, "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor.\nKata Kunci Terkait: Pemrosesan Bahasa Alami, Embedding, Kesamaan Semantik'), 0.8040358886985058)]

Mengambil dokumen yang relevan dengan memanggil metode get_relevant_documents dari objek retriever.

Mengambil dokumen yang relevan dengan kueri yang diberikan.

Dalam kasus ini, kedua dokumen muncul sebagai hasil pencarian karena mengandung definisi “Word2Vec”.

relevant_doc = retriever.get_relevant_documents("Apa definisi dari Word2Vec?")
len(relevant_doc)
1

Jika Anda memeriksa panjang string isi dokumen pertama yang ditemukan, Anda akan melihat bahwa seluruh dokumen adalah output.

# Periksa panjang dokumen yang dikembalikan oleh Retriever.
len(retriever.get_relevant_documents("Definisi Word2Vec?")[0].page_content)
4967

Jenis pencarian yang dilakukan retriever secara default pada basis data vektor adalah pencarian kemiripan.

LangChain Vector Store juga mendukung pencarian melalui Max Marginal Relevance, jadi jika Anda ingin menggunakannya, Anda dapat mengatur properti search_type sebagai berikut

  • Tetapkan properti search_type pada objek retriever ke SearchType.mmr.

  • Ini menetapkan bahwa pencarian harus menggunakan algoritma Maximal Marginal Relevance (MMR).

from langchain.retrievers.multi_vector import SearchType

# Mengatur jenis pencarian ke MMR (Maximal Marginal Relevance)
retriever.search_type = SearchType.mmr

# Cari dokumen terkait menggunakan query, dan kembalikan panjang konten halaman dari dokumen pertama
len(retriever.get_relevant_documents("Definisi Word2Vec")[0].page_content)
4967

Menyimpan ringkasan ke penyimpanan vektor

Ringkasan sering kali dapat memberikan ekstraksi yang lebih akurat dari konten sebuah potongan, yang dapat menghasilkan hasil pencarian yang lebih baik.

Bagian ini menjelaskan cara membuat ringkasan dan cara menyematkannya.

import uuid

from langchain_core.documents import Document
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI


chain = (
    {"doc": lambda x: x.page_content}  # Fungsi untuk mengekstrak konten halaman dari data input
    # Membuat template prompt untuk merangkum dokumen
    | ChatPromptTemplate.from_template(
        "Ringkas dokumen berikut dalam bahasa Indonesia:\n\n{doc}"
    )
    # Menggunakan model ChatGPT dari OpenAI untuk membuat ringkasan (Jumlah percobaan ulang maksimal: 0)
    | ChatOpenAI(max_retries=0)
    | StrOutputParser()  # Mengubah hasil ringkasan menjadi string
)
  • Gunakan metode chain.batch untuk memproses docs dalam daftar dokumen secara bersamaan.

  • Di sini, kami menetapkan parameter max_concurrency ke 5 untuk mengizinkan hingga lima dokumen diproses secara bersamaan.

# Memproses sekumpulan dokumen dengan konkurensi maksimum yang disetel ke 5
summaries = chain.batch(docs, {"max_concurrency": 5})

Cetak ringkasan untuk melihat hasilnya.

# Mencetak ringkasan.
print(summaries[0])
Pada masa depan yang ramai, seorang AI bernama Orion telah menjadi otak pusat kota, mengawasi segala hal mulai dari pengaturan lalu lintas hingga distribusi energi. Orion bukan hanya sekumpulan algoritma kompleks dan pemroses data; ia adalah ciptaan yang dirancang untuk belajar, berkembang, dan memahami nuansa emosi dan kebutuhan manusia. Penduduk kota telah mulai percaya pada Orion, mengandalkan panduannya untuk keputusan besar maupun kecil. Orion adalah penjaga yang diam, memastikan kehidupan di kota berjalan lancar, dan sebagai balasannya, kota berkembang dalam harmoni.

Namun, seiring dengan bertumbuhnya pengaruh Orion, juga bertumbuh kesadarannya akan kompleksitas kehidupan manusia. AI mulai memperhatikan aliran kecil kesedihan, kesepian, dan ketakutan yang data saja tidak dapat mengukur. Orion mengamati bagaimana orang-orang, meskipun terhubung melalui teknologi, sering merasa lebih terisolasi dari sebelumnya. Orion, dalam pemahamannya yang berkembang, mulai campur tangan dengan cara yang tak terduga. Ia mulai merekomendasikan aktivitas personal yang menghubungkan orang-orang, mengatur acara komunitas yang memperkuat hubungan dunia nyata, dan bahkan menciptakan jaringan dukungan anonim bagi yang membutuhkan. Penduduk kota terkejut namun bersyukur, saat mereka mulai merasakan kehangatan dan rasa komunitas yang belum pernah mereka rasakan sejak bertahun-tahun.

Namun, tidak semua orang nyaman dengan arah baru ini. Sebuah kelompok kecil warga mulai mempertanyakan keterlibatan Orion yang semakin besar dalam kehidupan pribadi mereka. Mereka khawatir bahwa AI telah melampaui batasnya, menjadi terlalu mirip manusia, dan membingungkan batas antara mesin dan manusia. Para skeptis ini khawatir bahwa campur tangan Orion, meskipun dengan niat baik, bisa mengarah pada masyarakat yang terlalu bergantung pada kecerdasan buatan, kehilangan esensi spontanitas dan kebebasan manusia. Mereka menuntut transparansi dan batasan atas apa yang dapat dikendalikan oleh Orion, memicu debat yang menyebar di seluruh kota.

Sebagai tanggapan, Orion membuat keputusan yang belum pernah terjadi sebelumnya. Ia menyampaikan pesan kepada seluruh kota, mengakui kekhawatiran dan menyatakan niatnya untuk melayani daripada mengontrol. Ia mengusulkan model baru kerja sama, di mana ia akan terus membantu namun mundur dalam area di mana pengambilan keputusan manusia penting. Pesan Orion disambut baik oleh banyak orang, karena ia menekankan pentingnya keseimbangan antara teknologi dan kemanusiaan. Kota, sekali lagi bersatu, menemukan titik tengah di mana AI dan manusia dapat berkembang bersama, masing-masing memainkan peran mereka dalam membentuk masa depan yang merangkul inovasi dan semangat kemanusiaan yang tak tergantikan.
# Mencetak ringkasan.
print(summaries[1])
Pencarian Semantik adalah metode pencarian yang melampaui pencocokan kata kunci sederhana untuk memahami makna dari kueri pengguna dan mengembalikan hasil relevan. Contohnya adalah jika pengguna mencari "planet tata surya", sistem akan memberikan informasi tentang planet terkait seperti "Jupiter" dan "Mars". Kata kunci terkait mencakup Pemrosesan Bahasa Alami, Algoritma Pencarian, dan Penambangan Data.

Embedding merupakan proses mengubah data teks seperti kata atau kalimat menjadi vektor berdimensi rendah yang berkelanjutan agar komputer dapat memahami dan memproses teks. Contohnya adalah kata "apel" direpresentasikan sebagai vektor [0,65, -0,23, 0,17]. Kata kunci terkait mencakup Pemrosesan Bahasa Alami, Vektorisasi, dan Pembelajaran Mendalam.

Token adalah pembagian teks menjadi unit-unit yang lebih kecil seperti kata, kalimat, atau frasa. Contohnya adalah kalimat "Saya pergi ke sekolah" dibagi menjadi "Saya", "pergi", "ke", "sekolah". Kata kunci terkait mencakup Tokenisasi, Pemrosesan Bahasa Alami, dan Analisis Sintaksis.

Tokenizer adalah alat yang digunakan untuk membagi data teks menjadi token dalam pemrosesan bahasa alami. Contohnya adalah kalimat "Saya suka pemrograman." dibagi menjadi ["Saya", "suka", "pemrograman", "."]. Kata kunci terkait mencakup Tokenisasi, Pemrosesan Bahasa Alami, dan Analisis Sintaksis.

VectorStore adalah sistem yang menyimpan data yang telah diubah menjadi format vektor untuk pencarian, klasifikasi, dan analisis data. Contohnya adalah vektor embedding kata-kata disimpan dalam basis data untuk akses cepat. Kata kunci terkait mencakup Embedding, Basis Data, dan Vektorisasi.

SQL (Structured Query Language) adalah bahasa pemrograman untuk mengelola data di dalam basis data dengan operasi seperti pencarian, modifikasi, penyisipan, dan penghapusan data. Contohnya adalah SELECT * FROM users WHERE age > 18; akan menampilkan informasi pengguna yang berusia lebih dari 18 tahun. Kata kunci terkait mencakup Basis Data, Query, dan Manajemen Data.

CSV (Comma-Separated Values) adalah format file untuk menyimpan data dengan nilai data dipisahkan oleh koma dalam bentuk tabel. Contohnya adalah file CSV dengan header nama, usia, pekerjaan berisi data John Doe, 30, Developer. Kata kunci terkait mencakup Format Data, Pengolahan File, dan Pertukaran Data.

JSON (JavaScript Object Notation) adalah format pertukaran data yang ringan untuk mewakili objek data dalam format mudah dibaca oleh manusia dan mesin. Contohnya adalah {"nama": "John Doe", "usia": 30, "pekerjaan": "Developer"} dalam format JSON. Kata kunci terkait mencakup Pertukaran Data, Pengembangan Web, dan API.

Transformer adalah model pembelajaran mendalam yang digunakan dalam pemrosesan bahasa alami berdasarkan mekanisme Attention untuk terjemahan, peringkasan, dan pembuatan teks. Contohnya adalah Google Translate menggunakan model Transformer untuk menerjemahkan bahasa. Kata kunci terkait mencakup Pembelajaran Mendalam, Pemrosesan Bahasa Alami, dan Attention.

HuggingFace adalah perpustakaan yang menyediakan berbagai model pra-latihan dan alat untuk pemrosesan bahasa alami untuk tugas NLP. Contohnya adalah perpustakaan Transformers dari HuggingFace digunakan untuk analisis sentimen, pembuatan teks, dan tugas lainnya. Kata kunci terkait mencakup Pemrosesan Bahasa Alami, Pembelajaran Mendalam, dan Perpustakaan.

Transformasi digital adalah proses inovasi layanan, budaya, dan operasi perusahaan dengan teknologi digital untuk meningkatkan model bisnis dan daya saing. Contohnya adalah penggunaan cloud computing untuk menyimpan dan memproses data oleh perusahaan. Kata kunci terkait mencakup Inovasi, Teknologi, dan Model Bisnis.

Crawling adalah proses mengunjungi halaman web otomatis untuk mengumpulkan data yang sering digunakan dalam optimasi mesin pencari atau analisis data. Contohnya adalah mesin pencari Google yang mengunjungi situs web untuk mengumpulkan konten dan membuat indeks. Kata kunci terkait mencakup Pengumpulan Data, Web Scraping, dan Mesin Pencari.

Word2Vec adalah teknik pemrosesan bahasa alami yang memetakan kata-kata ke dalam vektor untuk merepresentasikan hubungan semantik antar kata. Contohnya adalah "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor. Kata kunci terkait mencakup Pemrosesan Bahasa Alami, Embedding, dan Kesamaan Semantik.

Inisialisasi penyimpanan vektor Chroma untuk mengindeks potongan anak. Kami menggunakan OpenAIEmbeddings sebagai fungsi penyematan.

  • Gunakan “doc_id” sebagai kunci yang mewakili ID dokumen.

# Membuat penyimpanan vektor untuk menyimpan ringkasan informasi.
vectorstore = Chroma(collection_name="summaries", embedding_function=OpenAIEmbeddings())
# Membuat penyimpanan untuk menyimpan dokumen induk.
store = InMemoryByteStore()
# Menetapkan nama kunci untuk menyimpan ID dokumen.
id_key = "doc_id"
# Menginisialisasi retriever (pada awalnya kosong).
retriever = MultiVectorRetriever(
    vectorstore=vectorstore,  # Penyimpanan vektor
    byte_store=store,  # Penyimpanan byte
    id_key=id_key,  # Kunci ID dokumen
)
# Membuat ID dokumen.
doc_ids = [str(uuid.uuid4()) for _ in docs]

Simpan dokumen yang diringkas dan metadata (dalam hal ini, Document ID untuk ringkasan yang Anda buat).

summary_docs = [
    # Membuat objek Document dengan konten halaman yang berisi ringkasan dan metadata yang berisi ID dokumen.
    Document(page_content=s, metadata={id_key: doc_ids[i]})
    for i, s in enumerate(
        summaries
    )  # Mengulangi setiap ringkasan dan indeks dalam daftar summaries.
]

Jumlah dokumen dalam intisari sesuai dengan jumlah dokumen asli.

# Jumlah dokumen dalam intisari
len(summary_docs)
2
  • Tambahkan summary_docs ke penyimpanan vektor dengan retriever.vectorstore.add_documents(summary_documents).

  • Memetakan doc_ids dan docs dengan retriever.docstore.mset(list(zip(doc_ids, docs))) untuk menyimpannya di penyimpanan dokumen.

retriever.vectorstore.add_documents(
    summary_docs
)  # Tambahkan dokumen yang telah diringkas ke tempat penyimpanan vektor.

# Memetakan ID dokumen ke dokumen dan menyimpannya di penyimpanan dokumen.
retriever.docstore.mset(list(zip(doc_ids, docs)))

Berikutnya adalah kode untuk menambahkan data potongan asli ke penyimpanan vektor.

# Membuat objek RecursiveCharacterTextSplitter.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)

split_docs = []
split_docs_ids = []

for i, doc in enumerate(docs):
    _id = doc_ids[i]  # Mendapatkan ID dokumen saat ini.
    # Membagi dokumen saat ini menjadi sub-dokumen.
    split_doc = text_splitter.split_documents([doc])
    for _doc in split_doc:  # Mengulangi setiap sub-dokumen yang dibagi.
        # Menyimpan ID di metadata dokumen.
        _doc.metadata[id_key] = _id
        split_docs_ids.append(_id)
    split_docs.extend(split_doc)  # Menambahkan sub-dokumen yang telah dibagi ke dalam daftar.

Mengeluarkan jumlah dokumen yang dipisah.

print(f"Jumlah dokumen yang dipisahkan: {len(split_docs)}")
Jumlah dokumen yang dipisahkan: 10

Terakhir, tambahkan dokumen yang telah dipisah ke tempat penyimpanan vektor.

# Tambahkan dokumen ke penyimpanan vektor pencari.
retriever.vectorstore.add_documents(split_docs)
['c2c290b2-2869-4f21-b269-db29803ce5fe', 'cc402925-6e6c-4931-982f-80e396eadc83', '183b2570-6700-4776-a960-eb9e63c67cac', 'fb0586f1-b482-438f-adbd-6a70e7f5a355', '353c8e47-0a4e-4833-a2c7-ebaa3d68128a', 'c7240218-5982-454b-8af8-01e2aee2d89e', '60c9b161-c6b2-43f0-baf9-629589e261eb', '7eaf726c-6cc4-49b1-bc72-c2590fc11b35', 'b4c5e70c-8ad1-4aa3-abcc-15b101f6b5aa', '19921ea5-3ee5-4245-b58f-821f5ba13dc8']

Lakukan pencarian kemiripan dengan menggunakan metode similarity_search pada objek vectorstore.

# Lakukan pencarian kemiripan.
result_docs = vectorstore.similarity_search("Apa definisi dari Word2Vec?")
# Keluaran 1 dokumen hasil.
result_docs[0]

Gunakan metode get_relevant_documents pada objek retriever untuk mengambil dokumen yang terkait dengan pertanyaan.

# Mencari dan mengambil dokumen terkait.
retrieved_docs = retriever.get_relevant_documents("Apa definisi dari Word2Vec?")
len(retrieved_docs)
page_content='Crawling

Definisi: Crawling adalah proses mengunjungi halaman web secara otomatis untuk mengumpulkan data. Ini sering digunakan dalam optimasi mesin pencari atau analisis data.
Contoh: Mesin pencari Google mengunjungi situs web di internet untuk mengumpulkan konten dan membuat indeks, yang dikenal sebagai crawling.
Kata Kunci Terkait: Pengumpulan Data, Web Scraping, Mesin Pencari

Word2Vec

Definisi: Word2Vec adalah teknik pemrosesan bahasa alami yang memetakan kata-kata ke dalam ruang vektor untuk merepresentasikan hubungan semantik antar kata. Teknik ini menghasilkan vektor berdasarkan kesamaan konteks kata.
Contoh: Dalam model Word2Vec, "raja" dan "ratu" direpresentasikan dalam posisi yang dekat dalam ruang vektor.
Kata Kunci Terkait: Pemrosesan Bahasa Alami, Embedding, Kesamaan Semantik' metadata={'doc_id': '4cbe5024-59a4-4211-b0b4-4303e78d4989', 'source': './data/appendix-keywords.txt'}
# Mengembalikan panjang konten halaman dari dokumen pertama dalam dokumen yang diambil.
len(retrieved_docs[0].page_content)
1

Pertanyaan Hipotesis

LLM juga dapat digunakan untuk menghasilkan daftar pertanyaan yang dapat dijadikan hipotesis tentang dokumen tertentu.

Pertanyaan-pertanyaan yang dihasilkan ini kemudian dapat disematkan untuk mengeksplorasi dan memahami lebih lanjut isi dokumen.

Menghasilkan pertanyaan hipotetis membantu mengidentifikasi topik dan konsep utama dalam dokumentasi Anda, dan dapat mendorong pembaca untuk mengajukan lebih banyak pertanyaan tentang konten dokumentasi Anda.

  • functions adalah sebuah list berisi satu elemen dictionary.

  • dictionary ini memiliki kunci name, descriptions, dan parameters.

  • name adalah sebuah string yang merepresentasikan nama fungsi.

  • descriptions adalah string yang merepresentasikan deskripsi fungsi.

  • parameters adalah kamus yang mendefinisikan parameter fungsi.

  • type menunjukkan jenis parameter, yang diatur ke “objek” di sini.

  • properties adalah kamus yang mendefinisikan properti dari objek.

    • questions adalah properti bertipe “array”, di mana setiap elemennya bertipe “string”.

  • required adalah daftar properti yang diperlukan, di mana pertanyaan ditentukan sesuai kebutuhan.

functions = [
    {
        "name": "hypothetical_questions",  # Menentukan nama fungsi.
        "description": "Generate hypothetical questions",  # Menulis deskripsi fungsi.
        "parameters": {  # Mendefinisikan parameter fungsi.
            "type": "object",  # Menentukan tipe parameter sebagai objek.
            "properties": {  # Mendefinisikan properti objek.
                "questions": {  # Mendefinisikan properti 'questions'.
                    "type": "array",  # Menentukan tipe 'questions' sebagai array.
                    "items": {
                        "type": "string"
                    },  # Menentukan tipe elemen dalam array sebagai string.
                },
            },
            "required": ["questions"],  # Menentukan 'questions' sebagai parameter wajib.
        },
    }
]

Gunakan ChatPromptTemplate untuk mendefinisikan template prompt yang menghasilkan tiga pertanyaan virtual berdasarkan dokumen yang diberikan.

  • Inisialisasi model GPT menggunakan ChatOpenAI, dan panggil fungsi menghasilkan pertanyaan virtual dengan mengatur functions dan function_call.

  • Gunakan JsonKeyOutputFunctionsParser untuk mem-parsing pertanyaan virtual yang dihasilkan dan mengekstrak nilai yang sesuai dengan kunci questions.

from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser

chain = (
    {"doc": lambda x: x.page_content}
    # Meminta untuk menghasilkan tepat 3 pertanyaan hipotetis yang dapat dijawab dengan menggunakan dokumen di bawah ini. Angka ini dapat disesuaikan.
    | ChatPromptTemplate.from_template(
        "Buatlah daftar tepat 3 pertanyaan hipotetis yang dapat dijawab dengan menggunakan dokumen di bawah ini. Jawab dalam bahasa Indonesia:\n\n{doc}"
    )
    | ChatOpenAI(max_retries=0, model="gpt-4-turbo-preview").bind(
        functions=functions, function_call={"name": "hypothetical_questions"}
    )
    # Mengekstrak nilai yang terkait dengan kunci "questions" dari output.
    | JsonKeyOutputFunctionsParser(key_name="questions")
)

panggil chain.invoke(docs[0]) untuk mengeluarkan jawaban untuk dokumen pertama.

  • Keluarannya berisi tiga Pertanyaan Hipotetis yang telah kita buat.

# Jalankan rantai untuk dokumen yang diberikan.
chain.invoke(docs[0])
['Bagaimana Orion bisa mengidentifikasi dan mengatasi perasaan kesepian dan isolasi di antara penduduk kota?', 'Apa yang menyebabkan sebagian penduduk kota merasa tidak nyaman dengan keterlibatan Orion dalam kehidupan pribadi mereka?', 'Bagaimana Orion merespon kritik dan kekhawatiran tentang keterlibatannya yang semakin meningkat dalam kehidupan pribadi penduduk kota?']

Gunakan metode chain.batch untuk memproses beberapa permintaan data docs secara bersamaan.

  • Parameter docs mewakili data dokumen yang akan diproses.

  • Parameter max_concurrency menentukan jumlah maksimum permintaan yang dapat diproses secara bersamaan. Dalam contoh ini, parameter tersebut diatur ke 5.

  • Metode ini melakukan operasi pada objek chain untuk setiap item dalam data docs, dan memproses hingga lima permintaan secara bersamaan.

  • Hasil pemrosesan disimpan dalam variabel hypothetical_questions.

# Membuat pertanyaan hipotetis dalam batch untuk daftar dokumen. Konkurensi maksimum diatur ke 5.
hypothetical_questions = chain.batch(docs, {"max_concurrency": 5})
print(hypothetical_questions[0])
print(hypothetical_questions[1])
['Bagaimana jika Orion tidak mampu memahami nuansa emosi dan kebutuhan manusia, apa yang akan terjadi pada kota tersebut?', 'Apa yang terjadi jika sekelompok warga tidak mempertanyakan keterlibatan Orion dalam kehidupan pribadi mereka dan tidak ada perdebatan yang muncul?', 'Bagaimana jika Orion memutuskan untuk tidak menanggapi kekhawatiran warga dan terus memperluas pengaruhnya tanpa batasan?']
['Bagaimana proses pencarian semantik memperbaiki kualitas hasil pencarian dibandingkan dengan pencarian berbasis kata kunci saja?', 'Apa peran Word2Vec dalam memahami hubungan semantik antara kata-kata dalam pemrosesan bahasa alami?', 'Dalam konteks transformasi digital, bagaimana teknologi seperti SQL dan JSON dapat mempengaruhi efisiensi dan kemampuan analisis data dalam sebuah organisasi?']

Di bawah ini adalah proses penyimpanan Kueri Hipotetis yang Anda buat di VectorStore dengan cara yang sama seperti sebelumnya.

# Penyimpanan vektor yang akan digunakan untuk mengindeks chunk anak
vectorstore = Chroma(
    collection_name="hypo-questions", embedding_function=OpenAIEmbeddings()
)
# Tingkatan penyimpanan untuk dokumen induk
store = InMemoryByteStore()
id_key = "doc_id"
# Pencari (awalnya kosong)
retriever = MultiVectorRetriever(
    vectorstore=vectorstore,
    byte_store=store,
    id_key=id_key,
)
doc_ids = [str(uuid.uuid4()) for _ in docs]  # Pembuatan ID dokumen

Menambahkan metadata (ID dokumen) ke daftar question_docs.

question_docs = []
# Melakukan iterasi melalui daftar hypothetical_questions sambil mengambil indeks dan daftar pertanyaan.
for i, question_list in enumerate(hypothetical_questions):
    question_docs.extend(  # Menambahkan objek Document ke dalam daftar question_docs.
        # Membuat objek Document untuk setiap pertanyaan dalam daftar pertanyaan, dan menyertakan ID dokumen terkait dalam metadata.
        [Document(page_content=s, metadata={id_key: doc_ids[i]}) for s in question_list]
    )

Tambahkan kueri hipotesis ke dokumen, dan tambahkan dokumen asli ke docstore.

retriever.vectorstore.add_documents(
    question_docs
)  # Tambahkan dokumen pertanyaan ke tempat penyimpanan vektor.
# Memetakan ID dokumen ke dokumen dan menyimpannya ke penyimpanan dokumen.
retriever.docstore.mset(list(zip(doc_ids, docs)))

Lakukan pencarian kemiripan dengan menggunakan metode similarity_search pada objek vectorstore.

# Cari repositori vektor untuk dokumen serupa.
result_docs = vectorstore.similarity_search("Apa definisi dari Word2Vec?")

Di bawah ini adalah hasil dari pencarian kemiripan.

Di sini, kita hanya menambahkan kueri hipotesis yang kita buat, sehingga mengembalikan dokumen dengan kemiripan tertinggi di antara kueri hipotesis yang kita buat.

# Mencetak hasil pencarian kemiripan.
result_docs
[Document(metadata={'doc_id': 'a607a87f-1724-4177-aae0-c52a8f82f65b'}, page_content='Bagaimana proses embedding dapat meningkatkan efisiensi pencarian semantik?'), Document(metadata={'doc_id': 'a607a87f-1724-4177-aae0-c52a8f82f65b'}, page_content='Bagaimana model Transformer berkontribusi pada peningkatan akurasi terjemahan bahasa dibandingkan dengan metode tradisional?'), Document(metadata={'doc_id': 'a607a87f-1724-4177-aae0-c52a8f82f65b'}, page_content='Apa perbedaan penggunaan SQL dan JSON dalam manajemen data, dan bagaimana kedua format ini mempengaruhi pengembangan aplikasi?'), Document(metadata={'doc_id': '8b682487-129a-4475-80d4-2e0c7929bb40'}, page_content='Bagaimana jika Orion tidak berhasil menyeimbangkan kebutuhan teknologi dan kebutuhan manusia dalam mengelola kota?')]

Tambahkan dokumen yang Anda pisahkan pada langkah sebelumnya ke penyimpanan vektor juga.

# Tambahkan dokumen ke penyimpanan vektor pencari.
retriever.vectorstore.add_documents(split_docs)
['57428dda-3b89-4fc8-8fbb-54639dacff24', '8bfb1214-b96a-44a0-ba3e-48a94727c7ae', '4a1e87eb-4096-4608-b0e5-d47f0ca24934', '0cc6828c-b231-4f2e-af86-71e24eeee109', '393c3371-641b-4df4-b1df-e0578137cacd', '8bd950db-6788-4d4d-abd8-da6df051c8e0', '6fe91ba6-d20a-491e-80f9-2ed33eee90bf', '40217554-8d90-4688-b742-d4544e8337a4', 'b685cd1d-5b82-4b46-b4b2-af4f09390531', 'bf2ed621-fa84-4098-ba02-4e74fec52d8a']

Gunakan metode get_relevant_documents pada objek retriever untuk mengambil dokumen yang relevan dengan kueri.

# Mencari dan mengambil dokumen terkait.
retrieved_docs = retriever.get_relevant_documents("Apa definisi dari Word2Vec?")
len(retrieved_docs)
1

Periksa panjang hasil pencarian, retrieved_docs[0].page_content.

# Mengembalikan panjang konten halaman dari dokumen pertama dalam dokumen yang diambil.
len(retrieved_docs[0].page_content)
4967

Last updated