Bangun agen RAG korektif dengan menggunakan IBM Granite dan Tavily

Penulis

Jobit Varughese

Technical Content Writer

IBM

Model bahasa besar (LLM) luar biasa kuat, tetapi pengetahuan mereka terbatas pada kumpulan data pelatihan mereka. Ketika menjawab pertanyaan, terutama tentang informasi yang spesifik, berkembang, atau berpemilik, LLM dapat berhalusinasi atau memberikan jawaban yang umum dan tidak relevan. Retrieval augmented generation (RAG) membantu dengan mengambil informasi yang relevan untuk LLM dari sumber data eksternal.

Namun, tidak semua RAG diciptakan sama. Corrective retrieval augmented generation (cRAG) tidak hanya dibangun di atas RAG yang lebih tradisional, tetapi juga merupakan peningkatan yang signifikan. Metode ini dirancang untuk menjadi lebih kuat dengan mengevaluasi kualitas dan relevansi hasil yang diambil. Jika konteksnya lemah, tidak relevan, atau berasal dari sumber yang tidak dapat dipercaya, cRAG berusaha mencari informasi yang lebih baik melalui tindakan korektif atau secara eksplisit menolak untuk menjawab, alih-alih mengarang jawaban. Teknik ini membuat sistem cRAG lebih dapat diandalkan dan dipercaya untuk aplikasi penting seperti menjawab pertanyaan terkait polis.

Diagram Dokumen yang Relevan

Dalam tutorial ini, Anda akan belajar bagaimana membangun sistem korektif RAG (CRag) yang kuat dengan menggunakan model IBM® Granite pada Watsonx dan LangChain. Kerangka kerja serupa seperti LlamaIndex atau LangGraph juga dapat digunakan untuk membangun aliran RAG yang kompleks dengan node yang berbeda. Teknik seperti penyempurnaan dapat lebih meningkatkan kinerja LLM spesifik untuk RAG khusus domain. LLM seperti yang ada di OpenAI (misalnya, model GPT seperti ChatGPT) juga merupakan pilihan populer untuk agen semacam itu, meskipun tutorial ini berfokus pada IBM Granite.

Di sini, kita akan berfokus pada contoh penggunaan: menjawab pertanyaan tentang dokumen polis asuransi tertentu (PDF). Tutorial ini akan memandu Anda dalam menerapkan algoritma RAG canggih yang:

  • Mengambil informasi dari dokumen PDF Anda sendiri.

  • Jika dokumen internal tidak cukup untuk menghasilkan jawaban, agen dapat menggunakan pencarian web eksternal (Tavily) sebagai cadangan.

  • Agen dengan cerdas menyaring hasil eksternal yang tidak relevan sehingga jawabannya disesuaikan dengan kebijakan pribadi.

  • Agen akan memberikan tanggapan yang jelas dan terbatas dengan informasi parsial jika tersedia, atau penolakan yang jelas jika konteksnya tidak ada.

Contoh penggunaan: Membangun agen kueri polis asuransi yang andal

Tutorial ini merupakan demonstrasi pembuatan agen kueri polis asuransi yang dirancang untuk menganalisis dokumen polis (brosur PDF) dan menjawab pertanyaan pengguna secara akurat. Kami menggunakan model IBM Granite dan LangChain untuk membangun agen dengan langkah-langkah pengambilan dan verifikasi yang kuat yang memastikan jawaban berkualitas tinggi dengan sumber terbatas.

Mari kita pahami bagaimana prinsip-prinsip utama RAG yang andal berlaku dalam contoh penggunaan kami.

Penerapan prinsip-prinsip utama

Basis pengetahuan internal (PDF): Sumber kebenaran utama agen adalah PDF polis asuransi yang Anda berikan. Ini mengubah dokumen ini menjadi penyimpanan vektor yang dapat dicari.

Cadangan pencarian eksternal (Tavily): Jika basis pengetahuan internal tidak memiliki informasi yang cukup, agen dapat berkonsultasi dengan sumber web eksternal melalui Tavily. Tavily adalah mesin pencari yang dibangun khusus untuk agen AI dan LLM yang menghasilkan pengambilan real-time yang lebih cepat melalui antarmuka pemrograman aplikasi (API) untuk aplikasi berbasis RAG.

Penilaian konteks: Evaluator pengambilan berbasis LLM (bertindak sebagai penilai) akan memberikan skor untuk relevansi item yang diambil dari PDF internal Anda sekaligus memastikan bahwa hanya item berkualitas tinggi yang diambil yang disertakan.

Penulisan ulang kueri: Untuk pencarian web, agen dapat menulis ulang kueri pengguna untuk meningkatkan peluang menemukan informasi eksternal yang relevan.

Verifikasi sumber: Pemeriksaan yang didukung LLM mengevaluasi apakah hasil pencarian web eksternal relevan dengan polis asuransi swasta, menyaring informasi umum, atau detail tentang program kesehatan masyarakat (seperti Medi-Cal). Fungsi ini mencegah dibuatnya jawaban yang menyesatkan dan memungkinkan koreksi diri, sehingga membantu penyempurnaan pengetahuan.

Pembuatan yang dibatasi: Prompt terakhir pada LLM secara tegas menginstruksikan untuk hanya menggunakan konteks yang disediakan, memberikan jawaban yang tepat, menyatakan ketika informasi tidak tersedia, atau memberikan jawaban parsial dengan batasan yang tegas. Fungsi ini meningkatkan kemampuan beradaptasi dan keandalan respons yang dihasilkan.

Prasyarat

Anda memerlukan akun IBM Cloud untuk membuat proyek watsonx.ai . Pastikan Anda memiliki akses ke Kunci API watsonx dan ID Proyek Anda. Anda juga memerlukan kunci API untuk Tavily AI untuk kemampuan pencarian web.

Langkah-langkah

Langkah 1. Siapkan lingkungan Anda

Meskipun terdapat pilihan beberapa alat, tutorial ini akan memandu Anda untuk menyiapkan akun IBM menggunakan Jupyter Notebook.

  1. Masuk ke watsonx.ai dengan menggunakan akun IBM Cloud Anda.
  2. Buat proyek watsonx.ai. Anda bisa mendapatkan ID proyek dari dalam proyek Anda. Klik tab Kelola. Kemudian, salin ID proyek dari bagian Detail di halaman Umum. Anda memerlukan ID ini untuk tutorial ini.
  3. Buat Jupyter Notebook.

Langkah ini akan membuka lingkungan notebook tempat Anda dapat menyalin kode dari tutorial ini. Sebagai alternatif, Anda dapat mengunduh notebook ini ke sistem lokal Anda dan mengunggahnya ke proyek watsonx.ai Anda sebagai aset. Untuk melihat tutorial Granite lainnya, kunjungi Komunitas IBM Granite. Tutorial ini juga tersedia di Github.

Langkah 2. Siapkan layanan waktu proses watsonx.ai dan kunci API

  1. Buat instans layanan watsonx.ai Runtime (pilih paket Lite, yang merupakan instans gratis).
  2. Buat Kunci antarmuka pemrograman aplikasi (API).
  3. Kaitkan layanan watsonx.ai Runtime ke proyek yang Anda buat di watsonx.ai.

Langkah 3. Penginstalan paket

Untuk bekerja dengan kerangka kerja LangChain dan mengintegrasikan IBM WatsonXLLM, kita perlu menginstal beberapa pustaka penting. Mari kita mulai dengan menginstal paket yang diperlukan. Kumpulan ini mencakup langchain untuk kerangka kerja RAG, langchain-ibm untuk integrasi watsonx, faiss-cpu untuk penyimpanan vektor yang efisien, PyPDF2 untuk memproses PDF, transformator kalimat untuk mendapatkan penanaman dan permintaan untuk panggilan API web. Pustaka ini penting untuk menerapkan machine learning dan solusi NLP.

# Install Libraries
!pip install langchain langchain-ibm faiss-cpu PyPDF2 sentence-transformers requests

Catatan: Tidak diperlukan GPU, tetapi eksekusi dapat lebih lambat pada sistem berbasis CPU. Langkah ini akan membuka lingkungan notebook tempat Anda dapat menyalin kode dari tutorial ini. Tutorial ini juga tersedia di GitHub.

Langkah 4. Impor perpustakaan yang diperlukan

Selanjutnya, impor semua modul yang diperlukan dan berikan kunci API Anda dengan aman untuk watsonx dan Tavily, bersama dengan ID Proyek watsonx Anda.

# Import required libraries

import os
import io
import getpass
from PyPDF2 import PdfReader
from langchain_ibm import WatsonxLLM
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.schema import Document
import requests
from botocore.client import Config
import ibm_boto3
from langchain.prompts import PromptTemplate
from langchain.tools import BaseTool

# Watsonx
WML_URL = "https://us-south.ml.cloud.ibm.com"
WML_API_KEY = getpass.getpass(" Enter Watsonx API Key: ")
PROJECT_ID = input(" Enter Watsonx Project ID: ")

# Tavily
TAVILY_API_KEY = getpass.getpass(" Enter Tavily API Key: ")

print(" Credentials loaded.")

os membantu bekerja dengan sistem operasi.

io memungkinkan untuk bekerja dengan aliran data.

getpass menggunakan cara yang aman untuk menangkap informasi sensitif seperti kunci API dan tidak menampilkan input ke layar.

PyPDF2.PdfReader memungkinkan ekstraksi konten dari PDF.

langchain_ibm.WatsonxLLM memungkinkan kita untuk menggunakan IBM Watsonx Granite LLM dengan mudah dalam kerangka kerja LangChain.

langchain.embeddings.HuggingFaceEmbeddings mengambil model HuggingFace dan menghasilkan penanaman tekstual yang penting untuk pencarian semantik.

langchain.vectorstores.FAISS adalah sebuah pustaka untuk penyimpanan vektor yang efisien dan pencarian kemiripan yang memungkinkan kita untuk membuat indeks vektor dan mengajukan kueri.

langchain.text_splitter.RecursiveCharacterTextSplitter membantu membagi konstituen teks yang besar menjadi potongan kecil yang diperlukan untuk memproses dokumen yang tidak muat dalam memori.

langchain.schema.Document menunjukkan unit teks yang berubah-ubah dengan metadata terkait yang menjadikannya sebuah fondasi dalam langchain.

requests digunakan untuk membuat permintaan HTTP secara eksternal ke API.

botocore.client.Config adalah kelas konfigurasi yang digunakan untuk menentukan pengaturan konfigurasi untuk klien AWS/IBM Cloud Object Storage.

ibm_boto3 adalah IBM Cloud Object Storage SDK untuk Python yang membantu berinteraksi dengan cloud object storage.

langchain.prompts.PromptTemplate menawarkan cara untuk membuat prompt terstruktur yang dapat digunakan kembali untuk model bahasa.

langchain.tools.BaseTool adalah kelas dasar tempat Anda membuat alat khusus yang dapat diberikan kepada agen LangChain untuk digunakan.

Langkah ini menyiapkan semua alat dan modul yang kita butuhkan untuk memproses teks, membuat penanaman, menyimpannya dalam basis data vektor, dan berinteraksi dengan IBM watsonx LLM. Ini menetapkan semua bagian yang diperlukan untuk membuat sistem RAG dunia nyata, yang mampu mencari sumber, menanyakan, dan mencari berbagai jenis data.

Langkah 5. Muat dan proses PDF dari IBM Cloud Object Storage

Dalam langkah ini, kami akan memuat PDF polis asuransi dari IBM Cloud Object Storage. Kode membaca PDF, membaca konten teks, dan membagi teks menjadi potongan yang lebih kecil dan dapat dikelola. Potongan ini diubah menjadi penanaman numerik dan disimpan dalam penyimpanan vektor FAISS yang mempersiapkan kita untuk pencarian kesamaan semantik pada lain waktu dalam konteks lokal untuk mengoptimalkan hasil pengambilan.

import os, types
import pandas as pd
from botocore.client import Config
import ibm_boto3

def __iter__(self): return 0

cos_client = ibm_boto3.client(service_name='s3',
ibm_api_key_id='YOUR_IBM_API_KEY',
ibm_auth_endpoint="https://iam.cloud.ibm.com/identity/token",
config=Config(signature_version='oauth'),
endpoint_url='https://s3.direct.us-south.cloud-object-storage.appdomain.cloud')

bucket = 'YOUR_BUCKET_NAME'
object_key = 'YOUR_OBJECT_KEY'

streaming_body_2 = cos_client.get_object(Bucket=bucket, Key=object_key)['Body']
pdf_bytes = io.BytesIO(streaming_body_2.read())

reader = PdfReader(pdf_bytes)
text = ""
for page in reader.pages:
extracted = page.extract_text()
if extracted:
text += extracted

print(f" Extracted {len(text)} characters from PDF.")
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_text(text)
print(f" Split into {len(chunks)} chunks.")

embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vectorstore = FAISS.from_texts(chunks, embeddings)

print(f" Created FAISS index.")

ibm_boto3.klien memungkinkan klien untuk berinteraksi dengan IBM Cloud Object Storage.

Bucket adalah nama bucket cloud object storage yang berisi PDF.

object_key adalah nama PDF di bucket cloud object storage.

cos_client.get_object(...).read() mengambil konten file PDF dalam cloud object storage sebagai byte.

io.BytesIO mengubah byte mentah PDF menjadi aliran biner dalam memori dalam format yang dapat digunakan oleh PdfReader.

PdfReader membuat objek yang dapat mengurai dan mengekstraksi teks dari PDF.

page.extract_text() mengekstraksi teks dari satu halaman dalam PDF.

RecursiveCharacterTextSplitter dikonfigurasikan untuk membagi teks yang diekstrak menjadi potongan berisi 500 karakter dengan 50 karakter yang tumpang tindih, oleh karena itu semuanya tetap dalam konteks.

splitter.split_text(text) menjalankan pemisahan semua halaman teks PDF menjadi potongan yang lebih kecil.

HuggingFaceEmbeddings memuat model transformator kalimat yang telah dilatih sebelumnya untuk mengubah potongan teks menjadi representasi vektor yang padat.

FAISS.from_texts(chunks, embeddings) membangun indeks FAISS dalam memori yang memungkinkan potongan teks dapat dicari berdasarkan kemiripan semantiknya.

Langkah ini menangani pengindeksan penuh dokumen PDF dari cloud ke teks yang siap LLM dan pengindeksan yang nyaman untuk pengambilan secara real-time.

Langkah 6. Inisialisasi LLM dan alat

Dalam langkah ini, Anda akan mengonfigurasi IBM Granite LLM untuk mendorong penalaran agen Anda dan mengintegrasikannya dengan fungsi pencarian web Tavily. Parameter LLM diatur untuk respons yang faktual dan stabil.

llm = WatsonxLLM(
model_id="ibm/granite-3-2b-instruct",
url=WML_URL,
apikey=WML_API_KEY,
project_id=PROJECT_ID,
params={
"max_new_tokens": 300, # ~2-3 paragraphs, good for corrective RAG
"temperature": 0.2, # low temperature = more factual, stable answers
}
)

print(" Watsonx Granite LLM ready.")
class TavilySearch(BaseTool):
name: str = "tavily_search"
description: str = "Search the web using Tavily for extra info."

def _run(self, query: str):
response = requests.post(
"https://api.tavily.com/search",
json={"api_key": TAVILY_API_KEY, "query": query}
)
response.raise_for_status()
return response.json()['results'][0]['content']


tavily_tool = TavilySearch()

WatsonXLLM membuat instans pembungkus LLM untuk IBM watsonx yang memungkinkan interaksi dengan model Granite.

model_id="ibm/granite-3-2b-instruct" adalah model IBM Granite (model instruksi parameter 2,7 miliar) yang dirancang untuk tugas AI generatif berbasis instruksi.

class TavilySearch(BaseTool) mendefinisikan alat LangChain khusus untuk melakukan pencarian web dengan menggunakan API Tavily.

tavily_tool = TavilySearch() membuat sebuah contoh yang dapat dieksekusi dari alat pencarian Tavily khusus.

Ketika kita menginisialisasi watsonxLLM, nilai url, apikey, dan project_id dari kredensial yang telah kita siapkan sebelumnya akan diteruskan untuk mengautentikasi dan menyambungkan ke layanan. Parameternya, seperti "max_new_token": 300, membatasi panjang respons dan "temperature": 0.2 mengontrol kreativitas output, mendukung hasil yang lebih deterministik.

Definisi kelas TavilySearch mencakup deskripsi fungsinya. Logikanya terdapat di dalam metode def _run(self, query: str). Dalam metode ini, kami membuat permintaan HTTP POST ke titik akhir API Tavily, termasuk TAVILY_API_KEY dan kueri pencarian dalam muatan JSON. Kami kemudian memverifikasi apakah ada kesalahan HTTP dengan response.raise_for_status() dan mengurai respons JSON untuk mengakses cuplikan konten dari hasil pencarian pertama.

Langkah ini menyiapkan model bahasa untuk pembuatan teks dan menyertakan alat pencarian web eksternal sebagai cara untuk menambah pengetahuan model bahasa.

Langkah 7. Tentukan templat prompt dan fungsi pembantu

Langkah ini mendefinisikan berbagai templat prompt yang memandu perilaku LLM pada berbagai tahap proses RAG. Pendekatan ini mencakup prompt untuk menilai relevansi potongan dokumen internal, menulis ulang kueri pengguna untuk pencarian web yang lebih baik dan prompt penting untuk memverifikasi sumber hasil pencarian web. Fungsi pembantu untuk menilai potongan dan mengambilnya dari penyimpanan vektor juga ditentukan.

# Define Prompt Templates and Helper Functions

# Prompt for scoring the relevance of retrieved chunks
scoring_prompt_template = PromptTemplate.from_template(
"""
You are an evaluator. Score the relevance of the context chunk to the given insurance question.

Question: "{query}"

Context:
\"\"\"
{chunk}
\"\"\"

Respond only in this format:
Score: <0-5>
Reason: <one line reason>
"""
)

# Prompt for rewriting the user's query for better web search results
rewrite_prompt_template = PromptTemplate.from_template(
"""
You are a helpful assistant. Improve the following question to be clearer for an insurance information search.
Focus on making the query more specific if possible.

Original Question: "{query}"

Rewrite it to be clearer:
"""
)

# NEW: Prompt for verifying if Tavily context is from a relevant source (private policy vs. public program)
CONTEXT_SOURCE_VERIFICATION_PROMPT = PromptTemplate.from_template(
"""
You are an expert at identifying if a piece of text is from a general, public, or unrelated source
versus a specific, private, or relevant policy document.

Read the following context and determine if it appears to discuss general information,
public health programs (like Medi-Cal, Medicaid, Medicare, NHS, government-funded programs, state-funded),
or information that is clearly *not* specific to a private insurance policy like the one
the user might be asking about (assuming the user is asking about their own private policy).

If the context explicitly mentions or heavily implies public health programs, or is too general
to be useful for a specific private policy question, respond with "NO".
Otherwise (if it seems like it *could* be from a private policy context, a general insurance guide,
or does not explicitly mention public programs), respond with "YES".

Context:
\"\"\"
Response:
"""
)


# Function to score chunks using the LLM
def score_chunks(chunks, query):
scored = []
for chunk in chunks:
prompt = scoring_prompt_template.format(query=query, chunk=chunk)
response = llm(prompt).strip()

try:
# Extract score using more robust parsing
score_line = [line for line in response.splitlines() if "Score:" in line]
if score_line:
score = int(score_line[0].replace("Score:", "").strip())
else:
score = 0 # Default to 0 if score line not found
except Exception as e:
print(f" Could not parse score for chunk: {e}. Response: {response[:50]}...")
score = 0 # Default to 0 on error

scored.append((chunk, score))
return scored

# Function to retrieve documents from FAISS vector store
def retrieve_from_vectorstore(query):
# Retrieve top 8 similar documents from your PDF content
docs = vectorstore.similarity_search(query, k=8)
return [doc.page_content for doc in docs]

print(" Prompt templates and helper functions defined.")

Langkah ini mendefinisikan berbagai templat prompt yang memandu perilaku LLM pada berbagai tahap proses RAG. Permintaan untuk memverifikasi relevansi potongan dokumen internal, menulis ulang kueri pengguna untuk pencarian web yang lebih baik dan prompt penting untuk memverifikasi bahwa sumber hasil pencarian web disertakan. Fungsi pembantu untuk menilai potongan dan mengambilnya dari penyimpanan vektor juga ditentukan.

PromptTemplate.from_template adalah fungsi utilitas dari LangChain untuk membuat templat yang dapat digunakan kembali untuk membuat prompt.

scoring_prompt_template mendefinisikan sebuah prompt yang menginstruksikan LLM untuk bertindak sebagai evaluator dan memberikan skor relevansi (0-5) ke potongan konteks tertentu berdasarkan sebuah pertanyaan.

rewrite_prompt_template mendefinisikan prompt yang memandu LLM untuk meningkatkan atau membuat pertanyaan asli pengguna lebih jelas untuk pencarian.

CONTEXT_SOURCE_VERIFICATION_PROMPT mendefinisikan prompt yang menginstruksikan LLM untuk memverifikasi apakah sepotong teks (misalnya, dari pencarian web) berasal dari konteks polis pribadi atau sumber umum atau publik.

def score_chunks(chunks, query) mendefinisikan sebuah fungsi yang mengambil daftar potongan teks dan sebuah kueri, lalu menilai relevansi setiap potongan menggunakan LLM.

def retrieve_from_vectorstore (query) mendefinisikan fungsi untuk mengambil dokumen yang paling mirip dari penyimpanan vektor FAISS.

Di dalam fungsi score_chunks, sebuah daftar skor kosong diinisialisasi. Untuk setiap potongan, scoring_prompt_template diformat dengan kueri dan potongan tertentu. Prompt yang diformat ini kemudian dikirim ke LLM dan respons disederhanakan. Fungsi ini mencoba mengekstraksi skor integer (skor biner jika disederhanakan menjadi relevan atau tidak relevan) dengan mengidentifikasi baris "Score:" dalam respons model. Potongan bersama dengan skor yang diurai atau defaultnya kemudian ditambahkan ke daftar skor. Bagian sistem ini bertindak sebagai evaluator pengambilan atau penilai.

Fungsi retrieve_from_vectorstore mengimplementasikan vectorstore.similarity_search untuk menemukan 8 potongan dokumen yang paling relevan berdasarkan kueri dan mengambil page_content dari objek Dokumen LangChain yang diambil ini.

Langkah ini membangun penopang konseptual untuk sistem RAG korektif sehingga LLM akan mengevaluasi konteks dan cara mengambil pengetahuan dari sumber pengetahuan internal dan eksternal.

Langkah 8. Terapkan logika RAG korektif

Pengambilan awal adalah fungsi yang memindai penyimpanan vektor PDF.

Penilaian konteks mengambil potongan PDF yang telah diambil untuk menilai konteks sesuai dengan relevansinya.

Kembali ke tavily jika tidak ada konteks yang cukup relevan dari PDF, kemudian mengajukan kueri kepada Tavily (pencarian web).

Verifikasi sumber adalah langkah yang didukung oleh LLM yang memeriksa apakah hasil Tavily relevan dengan polis pribadi sebelum menggunakannya. Fungsi ini mencegah jawaban yang menyesatkan dari program kesehatan masyarakat.

Penulisan ulang kueri dan pencarian tavily kedua jika masih belum ada konteks yang baik, kueri akan ditulis ulang dan pencarian Tavily dicoba lagi.

Keputusan akhir ketika ada konteks yang relevan, maka akan dikirim ke LLM dengan prompt (yang ketat) untuk membuat jawabannya. Jika tidak ada konteks yang relevan setelah semua upaya yang layak, maka penolakan yang sopan akan dikirimkan.

# Implement the Corrective RAG Logic

MIN_CONTEXT_LENGTH = 100 # Adjust this based on how much minimal context you expect for a partial answer
SIMILARITY_THRESHOLD = 3 # Only scores >= 3 used for vector store chunks

def corrective_rag(query: str, policy_context_keywords: list = None):
"""
Executes the Corrective RAG process to answer insurance queries.

Args:
query (str): The user's question.
policy_context_keywords (list, optional): Keywords related to the specific policy
(e.g., ["Super Star Health", "Care Health Insurance"]).
Used to make external searches more specific. Defaults to None.
Returns:
str: The final answer generated by the LLM or a predefined refusal.
"""
retrieved_context_pieces = [] # To store all relevant pieces found throughout the process

# Initial vector search & Scoring (from your PDF)
chunks_from_vectorstore = retrieve_from_vectorstore(query)
scored_chunks_vector = score_chunks(chunks_from_vectorstore, query)
good_chunks_vector = [chunk for chunk, score in scored_chunks_vector if score >= SIMILARITY_THRESHOLD]
retrieved_context_pieces.extend(good_chunks_vector)

current_context = "\n\n".join(retrieved_context_pieces)
print(f" Context length after initial vector scoring: {len(current_context)}")

# Prepare specific query for Tavily by optionally adding policy keywords
tavily_search_query = query
if policy_context_keywords:
tavily_search_query = f"{query} {' '.join(policy_context_keywords)}"

# Fallback: Tavily direct search (only if current context is too short from vector store)
if len(current_context) < MIN_CONTEXT_LENGTH:
print(f" Context too short from internal docs, trying Tavily direct with query: '{tavily_search_query}'...")
tavily_context_direct = tavily_tool._run(tavily_search_query)

if tavily_context_direct:
# --- NEW STEP: Verify Tavily Context Source ---
# Ask the LLM if the Tavily result seems to be from a private policy context or a public program
verification_prompt = CONTEXT_SOURCE_VERIFICATION_PROMPT.format(context=tavily_context_direct)
is_relevant_source = llm(verification_prompt).strip().upper()

if is_relevant_source == "YES":
retrieved_context_pieces.append(tavily_context_direct)
current_context = "\n\n".join(retrieved_context_pieces) # Re-combine all good context
print(f" Context length after Tavily direct (verified and added): {len(current_context)}")
else:
print(f" Tavily direct context source rejected (e.g., public program): {tavily_context_direct[:100]}...")
# Context is NOT added, so it remains short and triggers the next fallback or final refusal

# Fallback: Rewrite query + Tavily (only if context is still too short after direct Tavily)
if len(current_context) < MIN_CONTEXT_LENGTH:
print(" Context still too short, rewriting query and trying Tavily...")
rewrite_prompt = rewrite_prompt_template.format(query=query)
improved_query = llm(rewrite_prompt).strip()

# Add policy keywords to the rewritten query too
if policy_context_keywords:
improved_query = f"{improved_query} {' '.join(policy_context_keywords)}"

print(f" Rewritten query: '{improved_query}'")
tavily_context_rewritten = tavily_tool._run(improved_query)

if tavily_context_rewritten:
# --- NEW STEP: Verify Rewritten Tavily Context Source ---
verification_prompt = CONTEXT_SOURCE_VERIFICATION_PROMPT.format(context=tavily_context_rewritten)
is_relevant_source = llm(verification_prompt).strip().upper()

if is_relevant_source == "YES":
retrieved_context_pieces.append(tavily_context_rewritten)
current_context = "\n\n".join(retrieved_context_pieces) # Re-combine all good context
print(f" Context length after rewritten Tavily (verified and added): {len(current_context)}")
else:
print(f" Tavily rewritten context source rejected (e.g., public program): {tavily_context_rewritten[:100]}...")

# --- Final Decision Point ---
# Now, `current_context` holds ALL the "good" and "verified" context we managed to gather.
# The decision to call the LLM for an answer or give a hard refusal is based on `current_context`'s length.

# Final check for absolutely no good context
# This triggers only if *no* relevant internal or external context was found or verified.
if len(current_context.strip()) == 0:
print(" No good context found after all attempts. Returning absolute fallback.")
return (
"Based on the information provided, there is no clear mention of this specific detail "
"in the policy documents available."
)

# If we have *any* context (even if short), pass it to the LLM to process
# The LLM will then decide how to phrase the answer based on its prompt instructions
# (exact, partial, or full refusal if context is irrelevant or insufficient based on its own reasoning).
final_prompt = (
f"You are a careful insurance expert.\n"
f"Use ONLY the following context to answer the user's question. If the context is too short "
f"or does not contain the answer, you must indicate that.\n"
f"Context:\n```\n{current_context}\n```\n\n" # Pass the gathered context
f"User's Question: {query}\n\n" # Pass the original query for the LLM's reference
f"NEVER add new details that are not in the context word-for-word.\n"
f"If the context clearly says the answer, give it exactly as written in the context, but in prose.\n"
f"If the context does not mention the topic at all, or the answer is not in the context, say:\n"
f"\"I'm sorry, but this information is not available in the provided policy details.\"\n"
f"If the context partially mentions the topic but does not directly answer the specific question (e.g., mentions 'dental' but not 'wisdom tooth removal'), reply like this:\n"
f"\"Based on the information provided, here’s what is known: [quote relevant details from the context related to the broad topic.] "
f"There is no clear mention of the specific detail asked about.\"\n"
f"Do NOT assume. Do NOT make up extra information.\n"
f"Do NOT generate extra questions or conversational filler.\n"
f"Final Answer:"
)

return llm(final_prompt)

print(" Corrective RAG logic implemented.")

Bagian pertama dari parameter policy_context_keywords memungkinkan Anda untuk menambahkan istilah spesifik dari polis Anda (misalnya, nama, perusahaan asuransi) untuk membantu mempersempit pencarian Tavily.

MIN_CONTEXT_LENGTH mendefinisikan panjang minimum yang dapat diterima dari konteks yang diambil.

SIMILARITY_THRESHOLD mendefinisikan skor relevansi minimum yang harus dimiliki oleh sebuah potongan untuk dianggap "baik."

def corrective_rag(...) mendefinisikan fungsi utama yang mengatur seluruh alur kerja RAG korektif.

Fungsi corrective_rag dimulai dengan membuat retrieved_context_pieces untuk mengumpulkan konteks yang relevan. Pertama-tama, ia mengambil dan menilai chunks_from_vectorstore dari penyimpanan vektor PDF berdasarkan kueri, kemudian scored_chunks_vector mengevaluasi relevansinya dengan menggunakan model bahasa. Hanya good_chunks_vector yang memenuhi SIMILARITY_THRESHOLD yang disimpan. Current_context kemudian dikompilasi dari semua potongan ini.

Jika current_context kurang dari MIN_CONTEXT_LENGTH, sistem akan mencoba pencarian web. Ini membuat tavily_search_query, berpotensi menggabungkan policy_context_keywords. Pencarian langsung(tavily_context_direct) dilakukan. Yang terpenting, sebuah verification_prompt dibuat dan dikirimkan ke LLM untuk menentukan apakah hasil pencarian web(is_relevant_source) berasal dari polis pribadi dan bukan program publik. Jika YA, konteks ditambahkan.

Jika konteks tetap tidak mencukupi, sistem bersiap untuk menulis ulang kueri. Sistem menggunakan rewrite_prompt untuk mendapatkan improved_query dari LLM, lalu melakukan pencarian web kedua (tavily_context_rewritten). Konteks baru ini juga mengalami verifikasi sumber yang sama.

Terakhir, apakah len(current_context.strip()) == 0 adalah pemeriksaan terakhir. Jika tidak ada konteks relevan yang ditemukan setelah semua upaya, pesan penolakan yang telah ditentukan ditampilkan. Jika tidak, final_prompt dibuat dengan semua konteks yang telah diverifikasi dan dikirim ke model bahasa untuk menghasilkan jawaban akhir.

Seluruh fungsi corrective_rag menangani pengambilan, penilaian, dan memverifikasi fungsi RAG korektif yang telah diatur secara mendetail. Hal ini memungkinkan pembaruan basis pengetahuan dan aliran pengetahuan secara konstan dan memberikan manfaat berupa jawaban yang kuat dan sadar konteks.

Langkah 9. Uji sistem

Terakhir, jalankan fungsi corrective_rag dengan kueri sampel. Sangat penting untuk memberikan policy_context_keywords yang spesifik untuk dokumen PDF Anda. Kata kunci ini akan membantu pencarian web Tavily menjadi lebih relevan dengan polis Anda yang sebenarnya, mencegah informasi program kesehatan umum atau publik mencemari konteks Anda.

Amati pernyataan cetak untuk panjang konteks dan hasil verifikasi untuk memahami aliran informasi.

query = "How does the policy cover for In-Patient Hospitalisation?"
result = corrective_rag(query)

print("\n FINAL ANSWER:\n")
print(result)

policy_specific_keywords = ["Super Star Health", "Care Health Insurance"] mendefinisikan daftar kata kunci yang relevan dengan polis asuransi yang diunggah, membantu mempersempit hasil pencarian web.

query = "..." mendefinisikan pertanyaan khusus yang mungkin diajukan pengguna.

result = corrective_rag(query, policy_context_keywords=policy_specific_keywords) memanggil fungsi corrective_rag yang utama dan meneruskan kueri pengguna dan kata sandi khusus polis untuk memulai seluruh proses RAG.

print("\n FINAL ANSWER (...)") menampilkan tajuk yang jelas sebelum mencetak jawaban yang dihasilkan.

print(result) menghasilkan jawaban akhir yang ditampilkan oleh sistem corrective_rag.

Langkah ini menunjukkan cara menggunakan sistem RAG korektif lengkap dengan contoh kueri dan kata kunci, yang mendemonstrasikan seluruh fungsionalitas dalam skenario dunia nyata.

Poin-poin penting

RAG korektif yang diterapkan sepenuhnya mengoordinasikan basis pengetahuan PDF internal dengan layanan eksternal (Tavily) untuk mendapatkan informasi yang komprehensif untuk permintaan yang kompleks.

Sistem ini secara akurat mengevaluasi dan menyaring konteks yang diambil dengan menggunakan penilaian berbasis LLM dan verifikasi sumber penting untuk memastikan bahwa digunakan informasi yang valid dan dapat diandalkan.

Sistem ini menunjukkan kemampuan untuk meningkatkan pencarian eksternal dengan menulis ulang pertanyaan pengguna secara cerdas untuk meminta informasi yang lebih ditargetkan dan berkualitas lebih tinggi.

Dengan menggunakan pembuatan yang dibatasi, jawaban yang dapat diandalkan dan akurat secara kontekstual biasanya dihasilkan dan sistem dengan sopan menolak untuk menjawab jika tidak ada cukup informasi terverifikasi yang diketahui.

Contoh ini menunjukkan bagaimana LangChain dan IBM Granite LLM di watsonx dapat digunakan untuk mengembangkan aplikasi berbasis AI yang kuat dan dapat dipercaya di domain sensitif seperti mengajukan pertanyaan tentang polis asuransi.

Solusi terkait
Agen AI untuk bisnis

Bangun, terapkan, dan kelola asisten dan agen AI yang kuat yang mengotomatiskan alur kerja dan proses dengan AI generatif.

    Menjelajahi watsonx Orchestrate
    Solusi agen AI IBM

    Bangun masa depan bisnis Anda dengan solusi AI yang dapat Anda percaya.

    Jelajahi solusi agen AI
    Layanan AI IBM Consulting

    Layanan IBM Consulting AI membantu merancang ulang cara kerja bisnis dengan AI untuk transformasi.

    Jelajahi layanan kecerdasan buatan
    Ambil langkah selanjutnya

    Baik Anda memilih untuk menyesuaikan aplikasi dan keterampilan yang dibangun sebelumnya atau membangun dan menerapkan layanan agen khusus menggunakan studio AI, platform IBM watsonx siap membantu Anda.

    Menjelajahi watsonx Orchestrate Jelajahi watsonx.ai