Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
411 lines
16 KiB
Python
411 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
"""Interactive demo of the Contextual Retrieval System
|
|
|
|
This script provides an interactive demonstration showing:
|
|
1. How chunks lose context in traditional RAG
|
|
2. How contextual retrieval solves this problem
|
|
3. Side-by-side comparison of retrieval quality
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import List
|
|
import time
|
|
from datetime import datetime
|
|
|
|
from config import Config
|
|
from contextual_chunking import ContextualChunker
|
|
from contextual_tools import ContextualKnowledgeBaseTools
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(message)s' # Simple format for demo
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def print_header(title: str, char: str = "=", width: int = 80):
|
|
"""Print a formatted header"""
|
|
logger.info(f"\n{char * width}")
|
|
logger.info(f"{title.center(width)}")
|
|
logger.info(f"{char * width}\n")
|
|
|
|
|
|
def print_section(title: str, char: str = "-", width: int = 60):
|
|
"""Print a section header"""
|
|
logger.info(f"\n{char * width}")
|
|
logger.info(f"{title}")
|
|
logger.info(f"{char * width}\n")
|
|
|
|
|
|
class ContextualRetrievalDemo:
|
|
"""Interactive demo class"""
|
|
|
|
def __init__(self):
|
|
self.config = Config.from_env()
|
|
self.documents = {}
|
|
self.contextual_kb = None
|
|
self.non_contextual_kb = None
|
|
|
|
def run(self):
|
|
"""Run the interactive demo"""
|
|
print_header("CONTEXTUAL RETRIEVAL SYSTEM - INTERACTIVE DEMO")
|
|
|
|
logger.info("Welcome! This demo will show you how contextual retrieval")
|
|
logger.info("improves RAG systems by preserving context when chunking.\n")
|
|
|
|
while True:
|
|
self.show_menu()
|
|
choice = input("\nYour choice: ").strip()
|
|
|
|
if choice == "1":
|
|
self.demo_problem()
|
|
elif choice == "2":
|
|
self.demo_solution()
|
|
elif choice == "3":
|
|
self.demo_comparison()
|
|
elif choice == "4":
|
|
self.demo_real_example()
|
|
elif choice == "5":
|
|
self.show_statistics()
|
|
elif choice == "q":
|
|
logger.info("\nThank you for using the Contextual Retrieval Demo!")
|
|
break
|
|
else:
|
|
logger.info("Invalid choice. Please try again.")
|
|
|
|
def show_menu(self):
|
|
"""Show main menu"""
|
|
print_section("MAIN MENU")
|
|
logger.info("1. Demonstrate the Context Loss Problem")
|
|
logger.info("2. Show the Contextual Retrieval Solution")
|
|
logger.info("3. Compare Search Results (Side-by-Side)")
|
|
logger.info("4. Real-World Example (Financial Report)")
|
|
logger.info("5. Show Performance Statistics")
|
|
logger.info("q. Quit")
|
|
|
|
def demo_problem(self):
|
|
"""Demonstrate the context loss problem"""
|
|
print_header("THE CONTEXT LOSS PROBLEM", char="*")
|
|
|
|
# Example document
|
|
document = """
|
|
ACME Corporation Annual Report 2023
|
|
|
|
Financial Highlights:
|
|
ACME Corporation achieved record performance in 2023. The company's revenue
|
|
grew by 15% compared to the previous year, reaching $2.5 billion. This growth
|
|
was driven by strong demand in the technology sector.
|
|
|
|
TechStart Inc. Performance:
|
|
Meanwhile, TechStart Inc. faced challenges in 2023. The company's revenue
|
|
declined by 8% due to supply chain disruptions. Management has implemented
|
|
cost-cutting measures to improve profitability.
|
|
|
|
Global Industries Update:
|
|
Global Industries maintained steady performance. The company's revenue
|
|
remained flat at $1.8 billion, but profit margins improved by 2 percentage
|
|
points through operational efficiency gains.
|
|
""".strip()
|
|
|
|
logger.info("Consider this document:\n")
|
|
logger.info("=" * 60)
|
|
logger.info(document)
|
|
logger.info("=" * 60)
|
|
|
|
logger.info("\nNow imagine we chunk this document and get:\n")
|
|
|
|
# Show problematic chunks
|
|
chunks = [
|
|
"The company's revenue grew by 15% compared to the previous year, reaching $2.5 billion.",
|
|
"The company's revenue declined by 8% due to supply chain disruptions.",
|
|
"The company's revenue remained flat at $1.8 billion, but profit margins improved."
|
|
]
|
|
|
|
for i, chunk in enumerate(chunks, 1):
|
|
logger.info(f"CHUNK {i}:")
|
|
logger.info(f" '{chunk}'")
|
|
logger.info("")
|
|
|
|
logger.info("❌ PROBLEM: All chunks say 'The company' but refer to different companies!")
|
|
logger.info("❌ A search for 'company revenue growth' might return the wrong chunk!")
|
|
logger.info("❌ Without context, we can't tell which company each chunk refers to!\n")
|
|
|
|
input("\nPress Enter to continue...")
|
|
|
|
def demo_solution(self):
|
|
"""Demonstrate the contextual retrieval solution"""
|
|
print_header("THE CONTEXTUAL RETRIEVAL SOLUTION", char="*")
|
|
|
|
logger.info("Contextual Retrieval solves this by adding context to each chunk:\n")
|
|
|
|
# Show contextualized chunks
|
|
contextual_chunks = [
|
|
{
|
|
"context": "This chunk is from ACME Corporation's 2023 annual report financial highlights section.",
|
|
"text": "The company's revenue grew by 15% compared to the previous year, reaching $2.5 billion."
|
|
},
|
|
{
|
|
"context": "This chunk discusses TechStart Inc.'s 2023 performance challenges.",
|
|
"text": "The company's revenue declined by 8% due to supply chain disruptions."
|
|
},
|
|
{
|
|
"context": "This chunk covers Global Industries' steady 2023 performance.",
|
|
"text": "The company's revenue remained flat at $1.8 billion, but profit margins improved."
|
|
}
|
|
]
|
|
|
|
for i, chunk in enumerate(contextual_chunks, 1):
|
|
logger.info(f"CONTEXTUAL CHUNK {i}:")
|
|
logger.info(f" Context: {chunk['context']}")
|
|
logger.info(f" Text: {chunk['text']}")
|
|
logger.info(f" Combined: {chunk['context']} {chunk['text']}\n")
|
|
|
|
logger.info("✅ SOLUTION: Each chunk now has context!")
|
|
logger.info("✅ Searching for 'ACME revenue growth' will correctly find chunk 1!")
|
|
logger.info("✅ The context preserves crucial information lost in traditional chunking!\n")
|
|
|
|
input("\nPress Enter to continue...")
|
|
|
|
def demo_comparison(self):
|
|
"""Run a side-by-side comparison"""
|
|
print_header("SIDE-BY-SIDE COMPARISON", char="*")
|
|
|
|
# Create test document
|
|
test_doc = """
|
|
Artificial Intelligence in Healthcare
|
|
|
|
Introduction:
|
|
Artificial intelligence is transforming healthcare delivery. Machine learning
|
|
models are being used for disease diagnosis, drug discovery, and patient care
|
|
optimization. The technology has shown remarkable results in early detection
|
|
of diseases.
|
|
|
|
Diagnostic Applications:
|
|
In radiology, AI systems can detect cancer with 95% accuracy. The systems
|
|
analyze medical images faster than human radiologists. This reduces diagnosis
|
|
time from hours to minutes.
|
|
|
|
Drug Discovery:
|
|
Pharmaceutical companies use AI to identify potential drug compounds. The
|
|
technology can predict drug interactions and side effects. This accelerates
|
|
the drug development process by years.
|
|
""".strip()
|
|
|
|
logger.info("Test Document:")
|
|
logger.info("=" * 60)
|
|
logger.info(test_doc[:300] + "..." if len(test_doc) > 300 else test_doc)
|
|
logger.info("=" * 60)
|
|
|
|
# Initialize systems
|
|
logger.info("\nInitializing systems...")
|
|
|
|
# Create contextual system
|
|
contextual_chunker = ContextualChunker(
|
|
chunking_config=self.config.chunking,
|
|
llm_config=self.config.llm,
|
|
use_contextual=True
|
|
)
|
|
self.contextual_kb = ContextualKnowledgeBaseTools(
|
|
config=self.config.knowledge_base,
|
|
use_contextual=True
|
|
)
|
|
|
|
# Create non-contextual system
|
|
non_contextual_chunker = ContextualChunker(
|
|
chunking_config=self.config.chunking,
|
|
llm_config=self.config.llm,
|
|
use_contextual=False
|
|
)
|
|
self.non_contextual_kb = ContextualKnowledgeBaseTools(
|
|
config=self.config.knowledge_base,
|
|
use_contextual=False
|
|
)
|
|
|
|
# Process document
|
|
logger.info("\nProcessing document...")
|
|
|
|
# Contextual chunks
|
|
contextual_chunks = contextual_chunker.chunk_document(
|
|
text=test_doc,
|
|
doc_id="healthcare_ai"
|
|
)
|
|
self.contextual_kb.index_contextual_chunks(contextual_chunks)
|
|
|
|
# Non-contextual chunks
|
|
non_contextual_chunks = non_contextual_chunker.chunk_document(
|
|
text=test_doc,
|
|
doc_id="healthcare_ai"
|
|
)
|
|
self.non_contextual_kb.index_contextual_chunks(non_contextual_chunks)
|
|
|
|
# Test queries
|
|
test_queries = [
|
|
"How accurate is the AI system?",
|
|
"What technology reduces diagnosis time?",
|
|
"What can the technology predict?"
|
|
]
|
|
|
|
logger.info("\nRunning comparison...")
|
|
|
|
for query in test_queries:
|
|
print_section(f"Query: {query}")
|
|
|
|
# Contextual search
|
|
contextual_results = self.contextual_kb.contextual_search(
|
|
query=query,
|
|
method="hybrid",
|
|
top_k=3
|
|
)
|
|
|
|
# Non-contextual search
|
|
non_contextual_results = self.non_contextual_kb.contextual_search(
|
|
query=query,
|
|
method="hybrid",
|
|
top_k=3
|
|
)
|
|
|
|
logger.info("CONTEXTUAL RESULTS:")
|
|
if contextual_results:
|
|
result = contextual_results[0]
|
|
logger.info(f" Score: {result.score:.4f}")
|
|
logger.info(f" Context: {result.context_text[:100]}..." if result.context_text else " Context: None")
|
|
logger.info(f" Match: {result.text[:100]}...\n")
|
|
else:
|
|
logger.info(" No results found\n")
|
|
|
|
logger.info("NON-CONTEXTUAL RESULTS:")
|
|
if non_contextual_results:
|
|
result = non_contextual_results[0]
|
|
logger.info(f" Score: {result.score:.4f}")
|
|
logger.info(f" Match: {result.text[:100]}...\n")
|
|
else:
|
|
logger.info(" No results found\n")
|
|
|
|
# Score comparison
|
|
if contextual_results and non_contextual_results:
|
|
improvement = ((contextual_results[0].score - non_contextual_results[0].score)
|
|
/ non_contextual_results[0].score * 100)
|
|
logger.info(f"📊 Score Improvement: {improvement:.1f}%\n")
|
|
|
|
input("\nPress Enter to continue...")
|
|
|
|
def demo_real_example(self):
|
|
"""Demonstrate with a real-world example"""
|
|
print_header("REAL-WORLD EXAMPLE: FINANCIAL REPORT", char="*")
|
|
|
|
# Create a realistic financial report
|
|
report = """
|
|
Q2 2023 Earnings Report - TechCorp International
|
|
|
|
Executive Summary:
|
|
TechCorp International reported strong second quarter results for 2023,
|
|
with revenue of $850 million, representing a 12% year-over-year growth.
|
|
The company's cloud services division was the primary growth driver.
|
|
|
|
Revenue Breakdown:
|
|
Cloud Services: Revenue increased by 25% to $400 million, driven by
|
|
enterprise adoption of our AI-powered analytics platform. Operating margin
|
|
improved to 35% from 30% in the prior year.
|
|
|
|
Hardware Division: Revenue declined by 5% to $300 million due to supply
|
|
chain constraints. However, the new product pipeline remains strong with
|
|
three launches planned for Q3.
|
|
|
|
Software Licensing: Revenue grew by 8% to $150 million. The company added
|
|
200 new enterprise customers during the quarter, bringing the total to
|
|
5,000 active licenses.
|
|
|
|
Competitive Analysis:
|
|
Compared to DataSoft Corp, our main competitor, we maintained market share
|
|
leadership. DataSoft reported 8% revenue growth in their latest quarter,
|
|
while our 12% growth demonstrates strong execution. Their cloud division
|
|
grew 15% compared to our 25% growth.
|
|
|
|
Future Outlook:
|
|
Management expects continued momentum in Q3 2023. The company raised
|
|
full-year guidance to $3.5 billion in revenue, representing 15% annual
|
|
growth. Investment in R&D will increase by 20% to accelerate AI
|
|
product development.
|
|
""".strip()
|
|
|
|
logger.info("Processing a realistic financial report...")
|
|
logger.info("=" * 60)
|
|
logger.info(report[:400] + "..." if len(report) > 400 else report)
|
|
logger.info("=" * 60)
|
|
|
|
# Process with contextual system
|
|
logger.info("\nGenerating contextual chunks (this may take a moment)...\n")
|
|
|
|
chunker = ContextualChunker(
|
|
chunking_config=self.config.chunking,
|
|
llm_config=self.config.llm,
|
|
use_contextual=True
|
|
)
|
|
|
|
chunks = chunker.chunk_document(
|
|
text=report,
|
|
doc_id="techcorp_q2_2023"
|
|
)
|
|
|
|
# Show examples of contextualized chunks
|
|
logger.info("Example Contextual Chunks:\n")
|
|
|
|
for chunk in chunks[:3]:
|
|
logger.info(f"Original: {chunk.text[:100]}...")
|
|
logger.info(f"Context: {chunk.context}")
|
|
logger.info("")
|
|
|
|
# Show how this helps with ambiguous queries
|
|
logger.info("Why this matters:\n")
|
|
logger.info("Query: 'What was the revenue growth?'")
|
|
logger.info(" - Without context: Could match TechCorp's 12%, Cloud's 25%, or Software's 8%")
|
|
logger.info(" - With context: Correctly identifies which growth figure you want\n")
|
|
|
|
logger.info("Query: 'How did the company perform vs competition?'")
|
|
logger.info(" - Without context: Might return DataSoft's results")
|
|
logger.info(" - With context: Returns TechCorp's performance comparison\n")
|
|
|
|
input("\nPress Enter to continue...")
|
|
|
|
def show_statistics(self):
|
|
"""Show performance statistics"""
|
|
print_header("PERFORMANCE STATISTICS", char="*")
|
|
|
|
if not self.contextual_kb:
|
|
logger.info("No searches performed yet. Run a comparison first!\n")
|
|
input("\nPress Enter to continue...")
|
|
return
|
|
|
|
# Get statistics
|
|
stats = self.contextual_kb.get_statistics()
|
|
|
|
logger.info("Search Statistics:")
|
|
logger.info(f" Total searches: {stats['search_stats']['total_searches']}")
|
|
logger.info(f" Average retrieval time: {stats['search_stats']['avg_retrieval_time']:.3f}s")
|
|
logger.info(f" Contextual searches: {stats['search_stats']['contextual_searches']}")
|
|
logger.info(f" Non-contextual searches: {stats['search_stats']['non_contextual_searches']}")
|
|
|
|
logger.info("\nIndex Statistics:")
|
|
logger.info(f" Contextual chunks indexed: {stats['index_stats']['contextual_chunks']}")
|
|
logger.info(f" Non-contextual chunks indexed: {stats['index_stats']['non_contextual_chunks']}")
|
|
|
|
logger.info("\nBased on Anthropic's Research:")
|
|
logger.info(" Standard RAG: 5.7% retrieval failure rate")
|
|
logger.info(" Contextual RAG: 2.9% failure rate (49% improvement)")
|
|
logger.info(" + Reranking: 1.9% failure rate (67% improvement)")
|
|
|
|
input("\nPress Enter to continue...")
|
|
|
|
|
|
def main():
|
|
"""Run the interactive demo"""
|
|
demo = ContextualRetrievalDemo()
|
|
demo.run()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|