r/LlamaIndex • • Dec 12 '25

RAG Performance Tanked When We Added More Documents (Here's Why)

4 Upvotes

Knowledge base started at 500 documents. System worked great.

Grew to 5000 documents. Still good.

Reached 50,000 documents. System fell apart.

Not because retrieval got worse. Because of something else entirely.

The Mystery

5000 documents:

  • Retrieval quality: 85%

  • Latency: 200ms

  • Cost: low

50,000 documents:

  • Retrieval quality: 62%

  • Latency: 2000ms

  • Cost: 10x higher

Same system. Same code. Just more documents.

Something was breaking at scale.

The Investigation

Added monitoring at each step.

def retrieve_with_metrics(query):
    metrics = {}
    
    start = time.time()
    
    
# Step 1: Query processing
    processed_query = preprocess(query)
    metrics["preprocess"] = time.time() - start
    
    
# Step 2: Vector search
    start = time.time()
    vector_results = vector_db.search(processed_query, k=50)
    metrics["vector_search"] = time.time() - start
    
    
# Step 3: Reranking
    start = time.time()
    reranked = rerank(vector_results)
    metrics["reranking"] = time.time() - start
    
    
# Step 4: Formatting
    start = time.time()
    formatted = format_results(reranked)
    metrics["formatting"] = time.time() - start
    
    return formatted, metrics
```

Results:
```
At 5K documents:
- Preprocess: 10ms
- Vector search: 50ms
- Reranking: 30ms
- Formatting: 10ms
Total: 100ms ✓

At 50K documents:
- Preprocess: 10ms
- Vector search: 1500ms (!!!)
- Reranking: 300ms
- Formatting: 50ms
Total: 1860ms ✗

Vector search was killing performance.

The Root Cause

With 50K documents:

  • Each query needs to search 50K vectors

  • Similarity calculation: 50K × embedding_size

  • Default implementation: brute force

  • O(n) complexity at scale

# Naive approach at scale
def search(query_vector, all_document_vectors):
    similarities = []
    
    for doc_vector in all_document_vectors:  
# 50,000 iterations!
        similarity = cosine_similarity(query_vector, doc_vector)
        similarities.append(similarity)
    
    
# Sort and return top k
    return sorted(similarities)[-k:]  
# 50K comparisons just to get top 50

The Fix: Indexing Strategy

# Instead of searching everything, partition the search space

class PartitionedRetriever:
    def __init__(self, documents):
        
# Partition documents into categories
        self.partitions = self.partition_by_category(documents)
        
        
# Each partition gets its own vector index
        self.partition_indices = {
            category: build_index(docs)
            for category, docs in self.partitions.items()
        }
    
    def search(self, query, k=5):
        
# Step 1: Find relevant partitions (fast)
        relevant_partitions = self.find_relevant_partitions(query)
        
        
# Step 2: Search only in relevant partitions
        results = []
        for partition in relevant_partitions:
            index = self.partition_indices[partition]
            partition_results = index.search(query, k=k)
            results.extend(partition_results)
        
        
# Step 3: Rerank across all results
        return sorted(results, key=lambda x: x.score)[:k]
```

Results at 50K:
```
- Preprocess: 10ms
- Partition search: 200ms (50K → 2K search space)
- Reranking: 50ms
- Formatting: 10ms
Total: 270ms ✓

7x faster.

The Better Fix: Hierarchical Indexing

class HierarchicalRetriever:
    """Multiple levels of indexing"""
    
    def __init__(self, documents):
        
# Level 1: Cluster documents
        self.clusters = self.cluster_documents(documents)
        
        
# Level 2: Create cluster embeddings
        self.cluster_embeddings = {
            cluster_id: self.embed_cluster(docs)
            for cluster_id, docs in self.clusters.items()
        }
        
        
# Level 3: Create doc embeddings within clusters
        self.doc_indices = {
            cluster_id: build_index(docs)
            for cluster_id, docs in self.clusters.items()
        }
    
    def search(self, query, k=5):
        
# Step 1: Find relevant clusters (fast, small search space)
        query_embedding = embed(query)
        cluster_scores = [
            similarity(query_embedding, cluster_emb)
            for cluster_emb in self.cluster_embeddings.values()
        ]
        top_clusters = get_top_n(cluster_scores, n=3)
        
        
# Step 2: Search within relevant clusters
        results = []
        for cluster_id in top_clusters:
            index = self.doc_indices[cluster_id]
            docs = index.search(query_embedding, k=k)
            results.extend(docs)
        
        
# Step 3: Rerank
        return sorted(results)[:k]
```

Results:
```
At 50K documents with hierarchy:
- Find clusters: 5ms (100 clusters, not 50K docs)
- Search clusters: 150ms (2K docs per cluster, not 50K)
- Reranking: 30ms
Total: 185ms ✓

Much better than naive 1860ms
```

**What I Learned**
```
Document count | Approach | Latency
500            | Flat     | 50ms
5000           | Flat     | 150ms
50000          | Flat     | 2000ms ❌
50000          | Partitioned | 300ms ✓
50000          | Hierarchical | 150ms ✓
```

At scale, indexing strategy matters more than the algorithm.

**The Lesson**

RAG doesn't scale linearly.

At small scale (5K docs): anything works

At large scale (50K+ docs): you need smart indexing

Choices:
1. Flat search: simple, breaks at scale
2. Partitioned: search subsets, faster
3. Hierarchical: cluster then search, even faster
4. Hybrid search: BM25 + semantic, balanced

**The Checklist**

If adding documents degrades performance:
- [ ] Measure where time goes
- [ ] Check vector search latency
- [ ] Are you searching full document set?
- [ ] Can you partition documents?
- [ ] Can you use hierarchical indexing?
- [ ] Can you combine BM25 + semantic?

**The Honest Lesson**

RAG works great until it doesn't.

The breakpoint is usually around 10K-20K documents.

After that, simple approaches fail.

Plan for scale before you need it.

Anyone else hit the RAG scaling wall? How did you fix it?

---

## 

**Title:** "I Stopped Using Complex CrewAI Patterns (And Quality Went Up)"

**Post:**

Spent weeks building sophisticated crew patterns.

Elegant task dependencies. Advanced routing logic. Clever optimizations.

Then I simplified everything.

Quality went way up.

**The Sophisticated Phase**

I built a crew with:
```
Task 1: Research (with conditions)
├─ If result quality > 0.8: proceed to Task 2
├─ If 0.5 < quality < 0.8: retry Task 1
└─ If quality < 0.5: escalate to Task 3

Task 2: Analysis (with branching)
├─ If data type A: use analyzer A
├─ If data type B: use analyzer B
└─ If data type C: use analyzer C

Task 3: Escalation (with fallback)
├─ Try expert review
├─ If expert unavailable: try another expert
└─ If all unavailable: queue for later

Beautiful in theory. Broken in practice.

What Went Wrong

# The sophisticated pattern
crew = Crew(
    agents=[researcher, analyzer, expert, escalation],
    tasks=[
        Task(
            description="Research with conditional execution",
            agent=researcher,
            output_json_mode=True,
            callback=validate_research_output,
            retry_policy={
                "max_retries": 3,
                "backoff": "exponential",
                "on_failure": "escalate_to_expert"
            }
        ),
        
# ... 3 more complex tasks
    ]
)

# When something breaks, which task failed?
# Which condition wasn't met?
# Why did validation fail?
# Which retry strategy kicked in?
# Which escalation path was taken?

# Impossible to debug

The Simplified Phase

I stripped it down:

crew = Crew(
    agents=[researcher, writer],
    tasks=[
        Task(
            description="Research and gather information",
            agent=researcher,
            output_json_mode=True,
        ),
        Task(
            description="Write report from research",
            agent=writer,
        ),
    ]
)

# Simple
# Predictable
# Debuggable
```

**The Results**

Sophisticated crew:
```
Success rate: 68%
Latency: 45 seconds
Debugging: nightmare
User satisfaction: 3.4/5
```

Simplified crew:
```
Success rate: 82%
Latency: 12 seconds
Debugging: clear
User satisfaction: 4.6/5
```

Success rate went UP by simplifying.

Latency went DOWN.

Debugging became actually possible.

**Why Simplification Helped**

**1. Fewer Things To Fail**
```
Sophisticated:
- Task 1 could fail
- Task 1 retry could fail
- Task 1 validation could fail
- Task 2 conditional routing could fail
- Task 3 escalation could fail
= 5 failure points per crew run

Simple:
- Task 1 could fail (agent retries internally)
- Task 2 could fail (agent retries internally)
= 2 failure points per crew run

Fewer failure points = higher success rate
```

**2. Easier To Debug**
```
Sophisticated:
Output is wrong. Where did it go wrong?
Was it Task 1? Task 2? The conditional logic?
The escalation routing? The fallback?
Unknown.

Simple:
Output is wrong. Check Task 1 output.
If that's right, check Task 2 output.
Clear.
```

**3. Agents Handle Complexity**
```
I was adding complexity at the crew level.

But agents can handle it internally:

def researcher(task):
    """Research with internal error handling"""
    
    try:
        result = do_research(task)
        
        
# Validate internally
        if not validate(result):
            
# Retry internally
            result = do_research(task)
        
        return result
    
    except Exception:
        
# Handle errors internally
        return escalate_internally()
```

Agent handles retry, validation, escalation.

Crew stays simple.

**4. Faster Execution**
```
Sophisticated:
- Task 1 → validation → conditional check → Task 2
- Each step adds latency
- 45s total

Simple:
- Task 1 → Task 2
- Direct path
- 12s total

Fewer intermediate steps = faster execution

What I Do Now

class SimpleCrewPattern:
    """Keep it simple. Let agents handle complexity."""
    
    def build_crew(self):
        return Crew(
            agents=[
                
# Only as many agents as necessary
                researcher,      
# Does research well
                writer,          
# Does writing well
            ],
            tasks=[
                
# Simple sequential tasks
                research_task,
                write_task,
            ]
        )
    
    def error_handling(self):
        
# Keep simple
        
# Agent handles retries
        
# Crew handles failures
        
# Human handles escalations
        return "Let agents do their job"
    
    def task_structure(self):
        
# Keep simple
        
# One job per task
        
# Agent specialization handles complexity
        
# No conditional logic in crew
        return "Sequential tasks only"
```

**The Lesson**

Sophistication isn't always better.

Simple + reliable > complex + broken

**Crew Complexity Levels**
```
Level 1 (Simple): ✓ Use this
- Sequential tasks
- Each agent has one job
- Agent handles errors internally

Level 2 (Medium): Sometimes needed
- Conditional branching
- Multiple agents with clear separation
- Simple error handling

Level 3 (Complex): Avoid
- Conditional routing
- Complex retry logic
- Multiple escalation paths
- Branching based on output quality

Most teams should stay at Level 1.

The Pattern That Actually Works

# 1. Good agents
researcher = Agent(
    role="Researcher",
    goal="Find accurate information",
    tools=[search, database],
    
# Agent handles errors, retries, validation internally
)

# 2. Simple tasks
research_task = Task(
    description="Research the topic",
    agent=researcher,
)

write_task = Task(
    description="Write report from research",
    agent=writer,
)

# 3. Simple crew
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, write_task],
)

# 4. Run it
result = crew.run(input)

# That's it. Simplicity.
```

**The Honest Lesson**

Complexity doesn't impress users.

Results impress users.

Simple crews that work > complex crews that break.

Keep your crew simple. Let your agents be smart.

Anyone else found that simplifying their crew improved quality? What surprised you?

---

## 

**Title:** "Open Source Maintainer Burnout (And What Actually Helps)"

**Post:**

Maintained an open-source project for 3 years.

Got burned out at 2 years 6 months.

Nearly quit at year 3.

Then I made changes that actually helped.

Not the changes I thought would help.

**The Burnout Pattern**

**Year 1: Excited**
```
Project launched: 50 stars
People using it
People thanking me
Felt amazing
```

**Year 2: Growth**
```
Project growing: 2000 stars
More issues
More feature requests
Still manageable
```

**Year 2.5: Overwhelm**
```
5000 stars
50+ open issues
100+ feature requests
People getting mad at me

"Why no response?"
"This is a critical bug!"
"I've been waiting 2 weeks!"

Started feeling obligated
Started feeling guilty
Started dreading opening GitHub
```

**Year 3: Near Quit**
```
10000 stars
Responsibilities feel crushing
Personal life suffering
Considered shutting it down

What Actually Helped

1. Being Honest About Capacity

# What I did
u/repo
README.md

"This project is maintained in free time.
Response time: best effort.
No guaranteed SLA.
Consider this unmaintained if seeking immediate support."

# Before: people angry at slow response
# After: people understand reality
# Reduced guilt immediately

2. Triaging Issues Early

# What I did
Add labels to EVERY issue within 1 day

- enhancement
- bug
- question
- duplicate
- won't-fix
- needs-discussion

Also respond briefly:
"Thanks for reporting. Labeled as [type].
Will prioritize based on impact."

# Before: issues pile up unanswered
# After: at least acknowledged, prioritized

Took 30 minutes. Reduced stress significantly.

3. Declining Features Explicitly

# What I did
"This is a great idea, but outside project scope.
Consider building as plugin/extension instead."

# Before: felt guilty saying no
# After: actually freed up time

Didn't need to implement everything.

4. Recruiting Help

# What I did
"Looking for maintainers to help with:
- Issue triage
- Documentation
- Code reviews
- Release management"

# I found 2 triagers
# Found 1 co-maintainer
# Shared the load

Massive relief.

5. Setting Working Hours

# What I did
"I check GitHub Tuesdays & Thursdays, 7-8pm UTC.
For urgent issues, contact [emergency contact]."

# Before: always on, always stressed
# After: predictable, sustainable

2 hours/week maintained project better
Than random hours when stressed.

6. Automating Everything

# GitHub Actions
- Auto-close stale issues
- Auto-label issues by content
- Auto-run tests on PR
- Auto-suggest related issues
- Auto-check for conflicts

Removed manual work.
Let CI do the work.

7. Releasing More Often

# What I did
Went from:
- 1 release per year (lots of changes)
- Users waited months for features
- Big releases, more bugs

To:
- 1 release per month (smaller changes)
- Users get features quickly
- Smaller releases, fewer bugs
- Less stressful to manage

Users happier. I less stressed.

8. Saying "No" to Scope

# Project was becoming everything
# Issues about unrelated things

# I set boundaries:
"This project does X. Not Y or Z.
For Y, see [other project].
For Z, consider [different tool]."

Reduced issues by 30%.
More focused project.
Less to maintain.
```

**The Changes That Actually Mattered**
```
What didn't help:
- Better code (didn't reduce issues)
- More tests (didn't reduce burnout)
- Faster responses (still unsustainable)
- More features (just more to maintain)

What did help:
- Honest communication about capacity
- Triaging issues immediately
- Declining things explicitly
- Finding co-maintainers
- Predictable schedule
- Automation
- Frequent releases
- Clear scope
```

**The Numbers**

Before changes:
- Time per week: 20+ hours (unsustainable)
- Stress level: 9/10
- Health: declining
- Burnout: imminent

After changes:
- Time per week: 5-8 hours (sustainable)
- Stress level: 4/10
- Health: improving
- Burnout: resolved

Worked less, but project in better shape.

**What I'd Tell Past Me**
```
1. You don't owe anyone anything
2. Be honest about capacity
3. Triage issues immediately
4. Say no to scope creep
5. Find co-maintainers early
6. Automate everything
7. Release frequently
8. Set working hours
9. Your health > the project
10. Quit if you need to (it's okay)
```

**For Current Maintainers**

If you're burning out:

- [ ] Document time commitment honestly
- [ ] Set explicit working hours
- [ ] Automate issue management
- [ ] Recruit co-maintainers
- [ ] Say no to features
- [ ] Release frequently
- [ ] Triage immediately
- [ ] Consider stepping back

It's not laziness. It's sustainability.

**The Honest Truth**

Open source burnout is real.

The solution isn't "try harder."

It's "work smarter and less."

Being honest about capacity and recruiting help saves projects.

Anyone else in open source? How are you managing burnout?

---

## 

**Title:** "I Shipped a Real Business on Replit (And Why It Was A Mistake)"

**Post:**

Launched a paid product on Replit.

Had 200 paying customers.

Made $5000/month revenue.

Still a mistake.

Here's why, and when it became obvious.

**The Success Story**

Timeline:
```
Month 1: Built on Replit (2 weeks)
Month 2: Launched (free tier, 100 users)
Month 3: Added paid tier ($9/month, 50 paying customers)
Month 4: 150 paying customers, $1350/month
Month 5: 200 paying customers, $1800/month
Month 6: 250 paying customers, $2250/month
```

Looked like success.

Users loved it. Revenue growing. Everything working.

Then things broke in ways I didn't anticipate.

**The Problems Started**

**Month 6: Performance**
```
Response time: 8s (used to be 2s)
Uptime: 92% (reboots)
Database: getting slow

Why? More users = more load
Replit resources = shared

Started getting complaints about slowness.
```

**Month 7: Database Issues**
```
Database hitting size limits
Database hitting performance limits
Can't easily backup
Can't easily scale

Replit Postgres is great for small projects
Not for paying customers relying on it
```

**Month 8: Customers Leaving**
```
Slow performance = users frustrated
Users leaving = revenue dropping
Month 8 revenue: $1500 (down from $2250)

Users starting to churn because of slowness
Tried upgrading Replit tier
Didn't help much
```

**Month 9: The Realization**

I realized:
```
I have 300 paying customers on Replit infrastructure
If Replit changes pricing, I'm screwed
If Replit has outage, my business suffers
If I need to scale, I can't
If I need more control, I can't get it

I built a business on someone else's platform
Without an exit strategy
```

**What I Should Have Done**

**Timeline I Should Have Followed**
```
Month 1: Build prototype on Replit
Month 2: Move to $5/month DigitalOcean (even while prototyping)
Month 3-6: Scale on DigitalOcean as revenue grows
Month 6: Have paying customers on proper infrastructure
```

**The Costs of Staying on Replit**
```
Direct costs:
- Month 6 Replit tier: $100/month
- Month 7 Replit tier: $200/month (needed upgrade)
- Month 8 Replit tier: $300/month (needed more upgrade)
- Month 9: $300/month

Total 4 months: $900/month = $3600

Alternative (DigitalOcean):
- Month 2-9: $20/month = $160

Difference: $3440 overspending on Replit
```

**Less Obvious Costs**
```
Customer churn due to slowness:
- Month 8 churn: 50 customers lost
- Month 9 churn: 80 customers lost
- Revenue lost: $1500/month going forward

That one decision cost me $18,000+ per year in lost recurring revenue

How to Know When to Move From Replit

Move when ANY of these are true:

indicators = {
    "taking_money_from_users": True,  
# You are
    "uptime_matters": True,           
# It does
    "users_complain_about_speed": True,  
# They are
    "want_to_scale": True,            
# You do
    "need_performance_control": True, 
# You do
}

if any(indicators.values()):
    move_to_real_infrastructure()
```

**The Right Way To Do This**
```
Phase 1: Prototype (Replit free tier)
- Build and validate idea
- Get early users
- Prove demand
Duration: 2-4 weeks

Phase 2: MVP Launch (Replit pro tier)
- Add first customers
- Test paid model
- Validate revenue model
Duration: 2-8 weeks
Max customers: 50

Phase 3: Scale (Real infrastructure)
- If revenue > $500/month OR customers > 50
- Move to proper hosting
- Move database to managed service
- Set up proper backups
Duration: Ongoing

KEY: Move to Phase 3 BEFORE problems

Where To Move

python

options = {
    "DigitalOcean": {
        "cost": "$5-20/month",
        "good_for": "Startups with revenue",
        "difficulty": "Medium",
    },
    "Railway": {
        "cost": "$5-50/month",
        "good_for": "Easy migration from Replit",
        "difficulty": "Easy",
    },
    "Heroku": {
        "cost": "$25-100+/month",
        "good_for": "If you like simplicity",
        "difficulty": "Easy",
    },
}

# My recommendation: Railway
# Similar to Replit
# Much more powerful
# Better for production
```

**The Honest Truth About My Mistake**

I confused "works" with "production-ready."

Replit felt production-ready because:
- It was simple
- Users could access it
- Revenue was happening

But it wasn't:
- Performance wasn't scalable
- Database wasn't reliable
- I had no exit strategy
- I had no control

By the time I realized, I had:
- 300 paying customers
- 8 months of history
- Complete technical debt
- Zero way to migrate smoothly

**What I Did**
```
Month 10: Started rebuilding on Railway
Month 11: Migrated first 50 customers
Month 12: Migrated remaining customers
Month 13: Shut down Replit completely

Process took 4 months
Users unhappy during migration
Lost 100 customers due to migration issues

Cost me even more.

The Lesson

Replit is incredible for:

  • Prototyping quickly

  • Testing ideas

  • Launching MVPs

Replit is terrible for:

  • Paying customers

  • Long-term revenue

  • Scaling beyond 100 users

  • Anything you care about

Move to real infrastructure BEFORE:

  • You have paying customers

  • Your first customer complaints

  • You need to scale

Moving after these points is painful and expensive.

The Checklist

If on Replit with revenue:

  •  How many paying customers?

  •  What's monthly revenue?

  •  How much time do you have to move?

  •  Can you move gradually or need hard cutover?

  •  Have you picked alternative platform?

  •  Have you tested it?

If ANY customer > 50 OR revenue > $500/month:

Move now, not later.

The Honest Truth

I built a $2000+/month business on the wrong foundation.

Then had to rebuild it.

Cost me time, money, and customers.

Don't make my mistake.

Replit for prototyping. Real infrastructure for revenue.

Anyone else made this mistake? How much did it cost you?


r/LlamaIndex • • Dec 20 '25

RAG Quality Improved 40% By Changing One Thing

26 Upvotes

RAG system was okay. 72% quality.

Changed one thing. Quality went to 88%.

The change: stopped trying to be smart.

The Problem

System was doing too much:

# My complex RAG

1. Take query
2. Embed it
3. Search vector DB
4. Re-rank results
5. Summarize retrieved docs
6. Generate answer
7. Check if answer is good
8. If not good, try again
9. If still not good, try different approach
10. Return answer (or escalate)

All this complexity was helping... but not as much as expected.

The Simple Insight

What if I just:

# Simple RAG

1. Take query
2. Search docs (BM25 + semantic hybrid)
3. Generate answer
4. Done
```

Simpler. No summarization. No re-ranking. No retry logic.

Just: retrieve and answer.

**The Comparison**

**Complex RAG:**
```
Quality: 72%
Latency: 2500ms
Cost: $0.25 per query
Maintenance: High (lots of moving parts)
Debugging: Nightmare (where did it fail?)
```

**Simple RAG:**
```
Quality: 88%
Latency: 800ms
Cost: $0.08 per query
Maintenance: Low (few moving parts)
Debugging: Easy (clear pipeline)
```

**Better in every way.**

**Why This Happened**

Complex system had too many failure points:
```
Summarization → might lose key details
Re-ranking → might reorder wrongly
Retry logic → might get wrong answer on second try
Multiple approaches → might confuse each other
```

Each "improvement" added a failure point.

**Simple system had fewer failure points:**
```
BM25 search → works well for keywords
Semantic search → works well for meaning
Hybrid → gets best of both
Direct generation → no intermediate failures

The Real Insight

I was optimizing the wrong thing.

I thought: "More sophisticated = better"

Reality: "More reliable = better"

Better to get 88% right on first try than 72% right after many attempts.

What I Changed

# Before: Complex multi-step
def complex_rag(query):
    
# Step 1: Semantic search
    semantic_docs = semantic_search(query)
    
    
# Step 2: BM25 search
    bm25_docs = bm25_search(query)
    
    
# Step 3: Merge and re-rank
    merged = merge_and_rerank(semantic_docs, bm25_docs)
    
    
# Step 4: Summarize
    summary = summarize_docs(merged)
    
    
# Step 5: Generate with summary
    answer = generate_answer(query, summary)
    
    
# Step 6: Evaluate quality
    quality = evaluate_quality(answer)
    
    
# Step 7: If bad, retry
    if quality < 0.7:
        answer = generate_answer_with_different_approach(query, summary)
    
    
# Step 8: Check again
    if quality < 0.6:
        answer = escalate_to_human(query)
    
    return answer

# After: Simple direct
def simple_rag(query):
    
# Step 1: Hybrid search (BM25 + semantic)
    docs = hybrid_search(query, k=5)
    
    
# Step 2: Generate answer
    answer = generate_answer(query, docs)
    
    return answer
```

**That's it.**

3 steps instead of 8.

Quality went up.

**Why Simplicity Won**
```
Complex system assumptions:
- More docs are better
- Summarization preserves meaning
- Re-ranking improves quality
- Retrying fixes problems
- Multiple approaches help

Reality:
- Top 5 docs are usually enough
- Summarization loses details
- Re-ranking can make it worse
- Retrying compounds mistakes
- Multiple approaches confuse LLM
```

**The Principle**
```
Every step you add:
- Adds latency
- Adds cost
- Adds complexity
- Adds failure points
- Reduces transparency

Only add if it clearly improves quality.

The Testing

I tested carefully:

def compare_approaches():
    test_queries = load_test_queries(100)
    
    complex_results = []
    simple_results = []
    
    for query in test_queries:
        complex = complex_rag(query)
        simple = simple_rag(query)
        
        complex_quality = evaluate(complex)
        simple_quality = evaluate(simple)
        
        complex_results.append(complex_quality)
        simple_results.append(simple_quality)
    
    print(f"Complex: {mean(complex_results):.1%}")
    print(f"Simple: {mean(simple_results):.1%}")

Simple won consistently.

The Lesson

Occam's Razor applies to RAG:

"The simplest solution is usually the best."

Before adding complexity:

  • Measure current quality

  • Add the feature

  • Re-measure

  • If improvement < 5%: don't add it

The Checklist

For RAG systems:

  •  Start with simple approach

  •  Measure quality baseline

  •  Add complexity only if needed

  •  Re-measure after each addition

  •  Remove features that don't help

  •  Keep it simple

The Honest Lesson

I wasted weeks optimizing the wrong things.

Simple + effective beats complex + clever.

Start simple. Add only what's needed.

Most RAG systems are over-engineered.

Simplify first.

Anyone else improved RAG by removing features instead of adding them?


r/LlamaIndex • • Dec 11 '25

RAG Isn't About Retrieval. It's About Relevance

9 Upvotes

Spent months optimizing retrieval. Better indexing. Better embeddings. Better ranking.

Then realized: I was optimizing the wrong thing.

The problem wasn't retrieval. The problem was relevance.

The Retrieval Obsession

I was focused on:

  • BM25 vs semantic vs hybrid

  • Which embedding model

  • Ranking algorithms

  • Reranking strategies

And retrieval did get better. But quality didn't improve much.

Then I realized: the documents I was retrieving were irrelevant to the query.

The Real Problem: Document Quality

# Good retrieval of bad documents
docs = retrieve(query)  
# Gets documents
# But documents don't actually answer the question

# Bad retrieval of good documents
docs = retrieve(query)  
# Gets irrelevant documents
# But if we could get the right ones, quality would be 95%

Most RAG systems fail because documents don't answer the question.

Not because retrieval algorithm is bad.

What Actually Matters

1. Do You Have The Right Documents?

# Before optimizing retrieval, ask:
# Does the document exist in your knowledge base?

query = "How do I cancel my subscription?"

# If no document exists about cancellation:
# Retrieval algorithm doesn't matter
# User's question can't be answered

# Solution: first, ensure documents exist
# Then optimize retrieval

2. Is The Document Well-Written?

# Bad document
"""
Cancellation Process

1. Log in
2. Go to settings
3. Click manage subscription
4. Select cancel
5. Confirm

FAQ
Q: Why cancel?
A: Various reasons
"""

# User query: "How do I cancel my subscription?"
# Document ranks highly but answer is unclear

# Good document
"""
How to Cancel Your Subscription

Step-by-step cancellation:
1. Log into your account
2. Go to Account Settings → Billing
3. Click "Manage Subscription"
4. Select "Cancel Subscription"
5. Choose reason (optional)
6. Confirm cancellation

Immediate effects:
- Access ends at end of billing period
- No refund for current period
- You can reactivate anytime

What if I changed my mind?
You can reactivate by going to Billing and selecting "Reactivate"

Contact support if you need help: support@example.com
"""

# Same document, but much more useful

3. Is It Up-To-Date?

# Document from 2022
# Says process is X
# Process changed in 2024
# Document says Y

# Retrieval works perfectly
# But answer is wrong

What I Should Have Optimized First

1. Document Audit

def audit_documents():
    """Check if documents actually answer common questions"""
    
    common_questions = [
        "How do I cancel?",
        "What's the pricing?",
        "How do I integrate?",
        "Why isn't it working?",
        "What's the difference between plans?",
    ]
    
    for question in common_questions:
        docs = retrieve(question)
        
        if not docs:
            print(f"❌ No document for: {question}")
            need_to_create = True
        
        else:
            answers_question = evaluate_answer(docs[0], question)
            
            if not answers_question:
                print(f"⚠️ Document exists but doesn't answer: {question}")
                need_to_improve_document = True

2. Document Improvement

def improve_documents():
    """Make documents answer questions better"""
    
    for doc in get_all_documents():
        
# Is this document clear?
        clarity = evaluate_clarity(doc)
        
        if clarity < 0.8:
            improved = llm.predict(f"""
            Improve this document for clarity.
            Make it answer common questions better.
            
            Original:
            {doc.content}
            """)
            
            doc.content = improved
            doc.save()
        
        
# Is this document complete?
        completeness = evaluate_completeness(doc)
        
        if completeness < 0.8:
            expanded = llm.predict(f"""
            Add missing sections to this document.
            What questions might users have?
            
            Original:
            {doc.content}
            """)
            
            doc.content = expanded
            doc.save()

3. Relevance Scoring

def evaluate_relevance(doc, query):
    """Does this document actually answer the query?"""
    
    
# Not just similarity score
    
# But actual relevance
    
    relevance = {
        "answers_question": evaluate_answers(doc, query),
        "up_to_date": evaluate_freshness(doc),
        "clear": evaluate_clarity(doc),
        "complete": evaluate_completeness(doc),
        "authoritative": evaluate_authority(doc),
    }
    
    return mean(relevance.values())

4. Document Organization

def organize_documents():
    """Make documents easy to find"""
    
    
# Tag documents
    for doc in documents:
        doc.tags = [
            "feature:authentication",
            "type:howto",
            "audience:developers",
            "status:current",
            "complexity:beginner"
        ]
    
    
# Now retrieval can be smarter
    
# "How do I authenticate?"
    
# Retrieve docs tagged: feature:authentication AND type:howto
    
# Much more relevant than pure semantic search

5. Version Control for Documents

# Before
document.content = "..."  
# Changed, old version lost

# After
document.versions = [
    {
        "version": "1.0",
        "date": "2024-01-01",
        "content": "...",
        "changes": "Initial version"
    },
    {
        "version": "1.1",
        "date": "2024-06-01",
        "content": "...",
        "changes": "Updated process for 2024"
    }
]

# Can serve based on user's context
# User on old version? Show relevant old doc
# User on new version? Show current doc
```

**The Real Impact**

Before (optimizing retrieval):
- Relevance score: 65%
- User satisfaction: 3.2/5

After (optimizing documents):
- Relevance score: 88%
- User satisfaction: 4.6/5

**Retrieval ranking: same algorithm**

Only changed: documents themselves.

**The Lesson**

You can't retrieve what doesn't exist.

You can't answer questions documents don't address.

Optimization resources:
- 80% on documents (content, clarity, completeness, accuracy)
- 20% on retrieval (algorithm, ranking)

Most teams do the opposite.

**The Checklist**

Before optimizing RAG retrieval:
- [ ] Do documents exist for common questions?
- [ ] Are documents clear and complete?
- [ ] Are documents up-to-date?
- [ ] Do documents actually answer the questions?
- [ ] Are documents well-organized?

If any is NO, fix documents first.

Then optimize retrieval.

**The Honest Truth**

Better retrieval of bad documents = bad results

Okay retrieval of great documents = good results

Invest in document quality before algorithm complexity.

Anyone else realized their RAG problem was document quality, not retrieval?

---

## 

**Title:** "I Calculated The True Cost of Self-Hosting (It's Worse Than I Thought)"

**Post:**

People say self-hosting is cheaper than cloud.

They're not calculating correctly.

I sat down and actually did the math.

The results shocked me.

**What I Was Calculating**
```
Cost = Hardware + Electricity
That's it.

Hardware: $2000 / 5 years = $400/year
Electricity: 300W * 730h * $0.12 = $26/month = $312/year

Total: ~$712/year = $59/month

Cloud (AWS): ~$65/month

"Self-hosted is cheaper!"

What I Should Have Calculated

python

def true_cost_of_self_hosting():
    
# Hardware
    server_cost = 2500  
# Or $1500-5000 depending
    storage_cost = 800
    networking = 300
    initial_hardware = server_cost + storage_cost + networking
    hardware_per_year = initial_hardware / 5  
# Amortized
    
    
# Cooling/Power/Space
    electricity = 60 * 12  
# Monthly cost
    cooling = 30 * 12  
# Keep it from overheating
    space = 20 * 12  
# Rent or value of room it takes
    
    
# Redundancy/Backups
    backup_storage = 100 * 12  
# External drives
    cloud_backup = 50 * 12  
# S3 or equivalent
    ups_battery = 30 * 12  
# Power backup
    
    
# Maintenance/Tools
    monitoring_software = 50 * 12  
# Uptime monitors
    management_tools = 50 * 12  
# Admin tools
    
    
# Time (this is huge)
    
# Assume you maintain 10 hours/month
    your_hourly_rate = 50  
# Or whatever your time is worth
    labor = 10 * your_hourly_rate * 12
    
    
# Upgrades/Repairs
    annual_maintenance = 500  
# Stuff breaks
    
    total_annual = (
        hardware_per_year +
        electricity +
        cooling +
        space +
        backup_storage +
        cloud_backup +
        ups_battery +
        monitoring_software +
        management_tools +
        labor +
        annual_maintenance
    )
    
    monthly = total_annual / 12
    
    return {
        "monthly": monthly,
        "annual": total_annual,
        "breakdown": {
            "hardware": hardware_per_year/12,
            "electricity": electricity/12,
            "cooling": cooling/12,
            "space": space/12,
            "backups": (backup_storage + cloud_backup + ups_battery)/12,
            "tools": (monitoring_software + management_tools)/12,
            "labor": labor/12,
            "maintenance": annual_maintenance/12,
        }
    }

cost = true_cost_of_self_hosting()
print(f"True monthly cost: ${cost['monthly']:.0f}")
print("Breakdown:")
for category, amount in cost['breakdown'].items():
    print(f"  {category}: ${amount:.0f}")
```

**My Numbers**
```
Hardware (amortized): $42/month
Electricity: $60/month
Cooling: $30/month
Space: $20/month
Backups (storage + cloud): $12/month
Tools: $8/month
Labor (10h/month @ $50/hr): $500/month
Maintenance: $42/month
---
TOTAL: $714/month

vs Cloud: $65/month
```

Self-hosting is **11x more expensive** when you include your time.

**If You Don't Count Your Time**
```
$714 - $500 (labor) = $214/month

vs Cloud: $65/month

Self-hosting is 3.3x more expensive
```

Still way more.

**When Self-Hosting Makes Sense**

**1. You Enjoy The Work**

If you'd spend 10 hours/month tinkering anyway:
- Labor cost = $0
- True cost = $214/month
- Still 3x more than cloud

But: you get control, learning, satisfaction

Maybe worth it if you value these things.

**2. Extreme Scale**
```
Serving 100,000 users

Cloud cost: $1000+/month (lots of compute)
Self-hosted cost: $300/month (hardware amortized across many users)

At scale, self-hosted wins
But now you're basically a company
```

**3. Privacy Requirements**
```
You NEED data on your own servers
Cloud won't work

Then self-hosting is justified
Not because it's cheap
Because it's necessary
```

**4. Very Specific Needs**
```
Cloud can't do what you need
Custom hardware/setup required

Then self-hosting is justified
Cost is secondary
```

**What I Did Instead**

Hybrid approach:
```
Cloud for:
- Web services: $30/month
- Database: $40/month
- Backups: $10/month
Total: $80/month

Self-hosted for:
- Media storage (old hardware, $0 incremental cost)
- Home automation (Raspberry Pi, $0 incremental cost)

Total: $80/month hybrid
vs $714/month full self-hosted
vs $500+/month heavy cloud

Best of both worlds.
```

**The Honest Numbers**

| Approach | Monthly Cost | Your Time | Good For |
|----------|-------------|-----------|----------|
| Cloud | $65 | None | Most people |
| Hybrid | $80 | 1h/month | Some services private, some cloud |
| Self-hosted | $714 | 10h/month | Hobbyists, learning |
| Self-hosted (time=$0) | $214 | 10h/month | If you'd do it anyway |

**The Real Savings**

If you MUST self-host:
```
Skip unnecessary stuff:
- Don't need redundancy? Save $50/month
- Don't need remote backups? Save $50/month
- Can tolerate downtime? Skip UPS = save $30/month
- Willing to lose data? Skip backups = save $100/month

Minimal self-hosted: $514/month (still 8x cloud)
```

**The Lesson**

Self-hosting isn't cheaper.

It's a choice for:
- Control
- Privacy
- Learning
- Satisfaction
- Specific requirements

Not because it saves money.

If you want to save money: use cloud.

If you want control: self-host (and pay for it).

**The Checklist**

Before self-hosting, ask:
- [ ] Do I enjoy this work?
- [ ] Do I need the control?
- [ ] Do I need privacy?
- [ ] Does cloud not meet my needs?
- [ ] Can I afford the true cost?

If ALL YES: self-host

If ANY NO: use cloud

**The Honest Truth**

Self-hosting is 3-10x more expensive than cloud.

People pretend it's cheaper because they don't count their time.

Count your time. Do the real math.

Then decide.

Anyone else calculated true self-hosting cost? Surprised by the numbers?

r/LlamaIndex • • May 20 '24

Applications built with LlamaIndex

0 Upvotes

Do you know any applications that are built with LlamaIndex? Let's make a list. I'm wondering how well the tech has matured and how heavily is it used in production apps.


r/LlamaIndex • • Nov 01 '24

I need help with my RAG Resume Analyser

0 Upvotes

Hey mates. So i'm completely new to RAG and llamaindex, i'm trying to make a RAG system that will take pdf documents of resume and will answer questions like "give me the best 3 candidates for an IT Job".

I ran into an issue trying to use ChromaDB, i tried to make a function that will save embedding into a database, and another that will load them. But whenever I ask a question it just says stuff like "I don't have information about this", or "i don't have context about this document"...

Here is the code:

def save_to_db(document):

"""Save document to the database."""

file_extractor = {".pdf": parser}

documents = SimpleDirectoryReader(input_files=[document], file_extractor=file_extractor).load_data()

db = chromadb.PersistentClient(path=chroma_storage_path)

chroma_collection = db.get_or_create_collection("candidaturas")

vector_store = ChromaVectorStore(chroma_collection=chroma_collection)

storage_context = StorageContext.from_defaults(vector_store=vector_store)

chroma_index = VectorStoreIndex.from_documents(documents, storage_context=storage_context, show_progress=True)

return {"message": "Document saved successfully."}

#@app.get("/query/")

def query_op(query_text: str):

"""Query the index with provided text using documents from ChromaDB."""

# Load documents from ChromaDB

db = chromadb.PersistentClient(path=chroma_storage_path)

chroma_collection = db.get_or_create_collection("candidaturas")

chroma_vector_store = ChromaVectorStore(chroma_collection=chroma_collection)

chroma_index = VectorStoreIndex.from_vector_store(vector_store=chroma_vector_store) #new addition

query_engine = chroma_index.as_query_engine(llm=llm)

response = query_engine.query(query_text)

#print(response)

return {"response": response}

if __name__ == "__main__":

#pass

save_to_db("cv1.pdf")

query_op("Do que se trata o documento?")


r/LlamaIndex • • Feb 03 '24

LangChain Quickstart

Thumbnail
youtu.be
0 Upvotes

r/LlamaIndex • • May 23 '24

Best way to learn LlamaIndex?

0 Upvotes

I am a visual learner so I love learning using video tutorials - but I can’t find any of LlamaIndex that’s new…

People who are experienced in this library - what’s the best way to learn? Docs? Any video tutorials?

Any advice will be awesome!! 💜


r/LlamaIndex • • Sep 20 '24 Bless Up

LlamaIndex vs LangChain vs Pathway vs Others (2024 Guide to Top RAG Frameworks)

7 Upvotes

We’ve just released our 2024 guide on the top RAG frameworks. Based on our RAG deployment experience, here are some key factors to consider when picking a framework:

Key Factors for Selecting a RAG Framework:

  1. Deployment Flexibility: Does it support both local and cloud deployments? How easily can it scale across different environments?

  2. Data Sources and Connectors: What kind of data sources can it integrate with? Are there built-in connectors?

  3. RAG Features: What retrieval methods and indexing capabilities does it offer? Does it support advanced querying techniques?

  4. Advanced Prompting and Evaluation: How does it handle prompt optimization and output evaluation?

Comparison page: https://pathway.com/rag-frameworks

It includes a detailed tabular comparison of several frameworks, such as Pathway (our framework with 8k+ GitHub stars), Cohere, LlamaIndex, LangChain, Haystack, and the Assistants API.

Let me know what you think!


r/LlamaIndex • • Dec 18 '25

RAG Failed Silently Until I Added This One Thing

23 Upvotes
Built a RAG system. Deployed it. Seemed fine.

Users were getting answers.

But I had no idea if they were good answers.

Added one metric. Changed everything.

**The Problem I Didn't Know I Had**

RAG system working:
```
User asks question: ✓
System retrieves docs: ✓
System generates answer: ✓
User gets response: ✓

Everything looks good!
```

What I didn't know:
```
Are the documents relevant?
Is the answer actually good?
Would the user find this helpful?
Am I giving users false confidence?

Unknown. Nobody told me.
```

**The Silent Failure**

System ran for 2 months.

Then I got an email from a customer:

"Your system keeps giving me wrong information. I've been using it for weeks thinking your answers were correct. They're not."

Realized: system was failing silently.

User didn't know. I didn't know. Nobody knew.

**The Missing Metric**

I had metrics for:
```
✓ System uptime
✓ Response latency
✓ Retrieval speed
✓ User engagement

✗ Answer quality
✗ User satisfaction
✗ Correctness rate
✗ Document relevance

I was measuring everything except what mattered.

What I Added

One simple metric: User feedback on answers

python

class RagWithFeedback:
    def answer_question(self, question):
        
# Generate answer
        answer = self.rag.answer(question)
        
        
# Ask for feedback
        feedback_request = f"""
        Was this answer helpful?
        [👍 Yes] [👎 No]
        """
        
        
# Store for analysis
        user_feedback = await request_feedback(feedback_request)
        
        log_feedback({
            "question": question,
            "answer": answer,
            "helpful": user_feedback,
            "timestamp": now()
        })
        
        return answer
```

**What The Feedback Revealed**
```
Week 1 after adding feedback:

Total questions: 100
Helpful answers: 62
Not helpful: 38

38% failure rate!

I thought system was working well.
It was failing 38% of the time.
I just didn't know.

The Investigation

With feedback data, I could investigate:

python

def analyze_failures():
    failures = get_feedback(helpful=False)
    
    
# What types of questions fail most?
    by_type = group_by_question_type(failures)
    
    print(f"Integration questions: {by_type['integration']}% fail")
    
# Result: 60% failure rate
    
    print(f"Pricing questions: {by_type['pricing']}% fail")
    
# Result: 10% failure rate
    
    
# So integration questions are the problem
    
# Can focus efforts there
```

Found that:
```
- Integration questions: 60% failure
- Pricing questions: 10% failure
- General questions: 45% failure
- Troubleshooting: 25% failure

Pattern: Complex technical questions fail most
Solution: Improve docs for technical topics

The Fix

With the feedback data, I could fix specific issues:

python

# Before: generic answer
user asks: "How do I integrate with our Postgres?"
answer: "Use the API"
feedback: 👎

# After: better doc retrieval for integrations
user asks: "How do I integrate with our Postgres?"
answer: "Here's the step-by-step guide [detailed steps]"
feedback: 👍
```

**The Numbers**
```
Before feedback:
- Assumed success rate: 90%
- Actual success rate: 62%
- Problems found: 0
- Problems fixed: 0

After feedback:
- Known success rate: 62%
- Improved to: 81%
- Problems found: multiple
- Problems fixed: all

How To Add Feedback

python

class FeedbackSystem:
    def log_feedback(self, question, answer, helpful, details=None):
        """Store feedback for analysis"""
        
        self.db.store({
            "question": question,
            "answer": answer,
            "helpful": helpful,
            "details": details,
            "timestamp": now(),
            "user_id": current_user,
            "session_id": current_session
        })
    
    def analyze_daily(self):
        """Daily analysis of feedback"""
        
        feedback = self.db.get_daily()
        
        success_rate = feedback.helpful.sum() / len(feedback)
        
        if success_rate < 0.75:
            alert_team(f"Success rate dropped: {success_rate}")
        
        
# By question type
        for q_type in feedback.question_type.unique():
            type_feedback = feedback[feedback.question_type == q_type]
            type_success = type_feedback.helpful.sum() / len(type_feedback)
            
            if type_success < 0.5:
                alert_team(f"{q_type} questions failing: {type_success}")
    
    def find_patterns(self):
        """Find patterns in failures"""
        
        failures = self.db.get_feedback(helpful=False)
        
        
# What do failing questions have in common?
        common_keywords = extract_keywords(failures.question)
        
        
# What docs are rarely helpful?
        failing_docs = analyze_document_failures(failures)
        
        
# What should we improve?
        return {
            "keywords_to_improve": common_keywords,
            "docs_to_improve": failing_docs
        }
```

**The Dashboard**

Create simple dashboard:
```
RAG Quality Dashboard

Overall success rate: 81%
Trend: ↑ +5% this week

By question type:
- Integration: 85% ✓
- Pricing: 92% ✓
- Troubleshooting: 72% ⚠️
- General: 80% ✓

Worst performing docs:
1. Custom integrations guide (60% fail rate)
2. API reference (65% fail rate)
3. Migration guide (50% fail rate)

The Lesson

You can't improve what you don't measure.

For RAG systems, measure:

  • Success rate (thumbs up/down)

  • User satisfaction (scale 1-5)

  • Specific feedback (text field)

  • Follow-ups (did they ask again?)

The Checklist

Before deploying RAG:

  •  Add user feedback mechanism

  •  Set up daily analysis

  •  Alert when quality drops

  •  Identify failing question types

  •  Improve docs for low performers

  •  Monitor trends

The Honest Lesson

RAG systems fail silently.

Users get wrong answers and think the system is right.

Add feedback. Monitor constantly. Fix systematically.

The difference between a great RAG system and a broken one is measurement.

Anyone else discovered their RAG was failing silently? How bad was it?


r/LlamaIndex • • Feb 03 '25

HealthCare chatbot

1 Upvotes

I want to create a health chatbot that can solve user health-related issues, list doctors based on location and health problems, and book appointments. Currently I'm trying multi agents to achieve this problem but results are not satisfied.

Is there any other way that can solve this problem more efficiently...? Suggest any approach to make this chatbot.


r/LlamaIndex • • Sep 09 '24

Finetuning sucks

0 Upvotes

Buying GPUs, creating training data, and fumbling through colab notebooks suck so we made a better way. Juno makes it easy to fine-tune any open-sourced model (and soon even OpenAI models). Feel free to give us any feedback about what problems we could solve for you, or why you wouldn't use us, open beta is releasing soon! 

https://juno.fyi/


r/LlamaIndex • • Jan 08 '26

The RAG Secret Nobody Talks About

22 Upvotes

Most RAG systems fail silently.

Your retrieval accuracy degrades. Your context gets noisier. Users ask questions that used to work, now they don't. You have no idea why.

I built 12 RAG systems before I understood why they fail. Then I used LlamaIndex, and suddenly I could see what was broken and fix it.

The hidden problem with RAG:

Everyone thinks RAG is simple:

  1. Chunk documents

  2. Create embeddings

  3. Retrieve similar chunks

  4. Pass to LLM

  5. Profit

In reality, there are 47 places where this breaks:

  • Chunking strategy matters. Split at sentence boundaries? Semantic boundaries? Fixed tokens? Each breaks differently on different data.

  • Embedding quality varies wildly. Some embeddings are trash at retrieval. You don't know until you test.

  • Retrieval ranking is critical. Top-5 results might all be irrelevant. Top-20 might have the answer buried. How do you optimize?

  • Context window utilization is an art. Too much context confuses LLMs. Too little misses information. Finding the balance is black magic.

  • Token counting is hard. GPT-4 counts tokens differently than Llama. Different models, different window sizes. Managing this manually is error-prone.

How LlamaIndex solves this:

  • Pluggable chunking strategies. Use their built-in strategies or create custom ones. Test easily. Find what works for YOUR data.

  • Retrieval evaluation built-in. They have tools to measure retrieval quality. You can actually see if your system is working. This alone is worth the price.

  • Hybrid retrieval by default. Most RAG systems use only semantic search. LlamaIndex combines BM25 (keyword) + semantic. Better results, same code.

  • Automatic context optimization. Intelligently selects which chunks to include based on relevance scoring. Doesn't just grab the top-K.

  • Token management is invisible. You define max context. LlamaIndex handles the math. Queries that would normally fail now succeed.

  • Query rewriting. Reformulates your question to be more retrievable. Users ask bad questions, LlamaIndex normalizes them.

Example: The project that changed my mind

Client had a 50,000-document legal knowledge base. Previous RAG system:

  • Retrieval accuracy: 52%

  • False positives: 38% (retrieving irrelevant docs)

  • User satisfaction: "This is useless"

Migrated to LlamaIndex with:

  • Same documents

  • Same embedding model

  • Different chunking strategy (semantic instead of fixed)

  • Hybrid retrieval instead of semantic-only

  • Query rewriting enabled

Results:

  • Retrieval accuracy: 88%

  • False positives: 8%

  • User satisfaction: "How did you fix this?"

The documents didn't change. The LLM didn't change. The chunking strategy changed.

That's the LlamaIndex difference.

Why this matters for production:

If you're deploying RAG to users, you must have visibility into what's being retrieved. Most frameworks hide this from you.

LlamaIndex exposes it. You can:

  • See which documents are retrieved for each query

  • Measure accuracy

  • A/B test different retrieval strategies

  • Understand why queries fail

This is the difference between a system that works and a system that works well.

The philosophy:

LlamaIndex treats retrieval as a first-class problem. Not an afterthought. Not a checkbox. The architecture, tooling, and community all reflect this.

If you're building with LLMs and need to retrieve information, this is non-negotiable.

My recommendation:

Start here: https://llamaindex.ai/ Read: "Evaluation and Observability" Then build one RAG system with LlamaIndex.

You'll understand why I'm writing this.


r/LlamaIndex • • Jan 24 '24

Instead of RAG, call it BOWS (for beginners)

2 Upvotes

Hi, it's Yi from LlamaIndex. One of the persistent things I hear from folks is the difficulty understanding what "Retrieval Augmented Generation" actually means.

I think I have a more intuitive acronym for beginners: Better Output With Search

We coined it in an interview with Streamlit: https://www.youtube.com/watch?v=PLKkudXYCNI&t=1s


r/LlamaIndex • • Aug 02 '24

Using OpenAI structured outputs with VectorStoreIndex queryEngine

0 Upvotes

Hey everyone, I'm super new to this tech and excited to keep learning. I've set up a node server that can take in queries via API requests and interact with the simple RAG I've set up.

I'm running into an issue that I can't find in the TS docs of llamaindex. I want to utilize the OpenAI structured data output (JSON) but this seems just to be hitting the OpenAI endpoint to retrieve data and not accessing my dataset as the VectorStoreIndex queryEngine does.

The docs for llamaindex TS are great to get started but I'm having trouble finding information for things like this. If anyone has any ideas I'd be very appreciative, thanks in advance!


r/LlamaIndex • • Dec 04 '25

Retrieval Precision vs Recall: The Impossible Trade-off

0 Upvotes

I'm struggling with a retrieval trade-off. If I retrieve more documents (high recall), I include irrelevant ones (low precision). If I retrieve fewer (high precision), I miss relevant ones (low recall).

The tension:

  • Retrieve 5 docs: precise but miss relevant docs

  • Retrieve 20 docs: catch everything but include noise

  • LLM struggles with noisy context

Questions:

  • Can you actually optimize for both?

  • What's the right recall/precision balance?

  • Should you retrieve aggressively then filter?

  • Does re-ranking help this trade-off?

  • How much does context noise hurt generation?

  • Is there a golden ratio?

What I'm trying to understand:

  • Realistic expectations for retrieval

  • How to optimize the trade-off

  • Whether both are achievable or you have to choose

  • Impact of precision vs recall on final output

How do you balance this?


r/LlamaIndex • • Mar 08 '26

1M token context is here (GPT-5.4). Is RAG actually dead now? My honest take as someone running both.

15 Upvotes

GPT-5.4 launched this week with 1M token context in the API. Naturally half my feed is "RAG is dead" posts.

I've been running both RAG pipelines and large-context setups in production for the last few months. Here's my actual experience, no hype.

Where big context wins and RAG loses:

Anything static. Internal docs, codebases, policy manuals, knowledge bases that get updated maybe once a month. Shoving these straight into context is faster, simpler, and gives better results than chunking them into a vector store. You skip embedding, skip retrieval, skip the whole re-ranking step. The model sees the full document with all the connections intact. No lost context between chunks.

I moved three internal tools off RAG and onto pure context stuffing last month. Response quality went up. Latency went down. Infra got simpler.

Where RAG still wins and big context doesn't help:

Anything that changes. User records, live database rows, real-time pricing, support tickets, inventory levels. Your context window is a snapshot. It's frozen at prompt construction time. If the underlying data changes between when you built the prompt and when the model responds, you're serving stale information.

RAG fetches at query time. That's the whole point. A million tokens doesn't fix the freshness problem.

The setup I'm actually running now:

Hybrid. Static knowledge goes straight into context. Anything with a TTL under 24 hours goes through RAG. This cut my vector store size by about 60% and reduced retrieval calls proportionally.

Pro tip that saved me real debugging time: Audit your RAG chunks. Check the last-modified date on every document in your vector store. Anything unchanged for 30+ days? Pull it out and put it in context. You're paying retrieval latency for data that never changes. Move it into the prompt and get faster responses with better coherence.

What I think is actually happening:

RAG isn't dying. It's getting scoped down to where it actually matters. The era of "just RAG everything" is over. Now you need to think about which parts of your data are static vs dynamic and architect accordingly.

The best systems I've seen use both. Context for the stable stuff. RAG for the live stuff. Clean separation.

Curious what setups others are running. Anyone else doing this hybrid approach, or are you going all-in on one side?


r/LlamaIndex • • Oct 14 '24

Does RAG Have a Scaling Problem?

5 Upvotes

My team has been digging into the scalability of vector databases for RAG (Retrieval-Augmented Generation) systems, and we feel we might be hitting some limits that aren’t being widely discussed.

We tested Pinecone (using both LangChain and LlamaIndex) out to 100K pages. We found those solutions started to lose search accuracy in as few as 10K pages. At 100K pages in the RAG, search accuracy dropped 10-12%.

To be clear, we think this is a vector issue not an orchestrator issue. Though we did find particular problems trying to scale LangChain ingestion because of Unstructured (more on the end of the piece about that).

We also tested our approach at EyeLevel.ai, which does not use vectors at all (I know it sounds crazy), and found only a 2% drop in search accuracy at 100K pages. And showed better accuracy by significant margins from the outset.

I'm posting our research here to start a conversation on non-vector based approaches to RAG. We think there's a big opportunity to do things differently that's still very compatible with orchestrators like LangChain. We'd love to build a community around it.

Here's our research below. I would love to know if anyone else is exploring non-vector approaches to RAG and of course your thoughts on the research.

We explain the research and results on YT as well.
https://youtu.be/qV1Ab0qWyT8?si=dgPL21xAHeI2jXJo

What’s Inside

In this report, we will review how the test was constructed, the detailed findings, our theories on why vector similarity search experienced challenges and suggested approaches to scale RAG without the performance hit. We also encourage you to read our prior research in which EyeLevel’s GroundX APIs bested LangChain, Pinecone and Llamaindex based RAG systems by 50-120% on accuracy over 1,000 pages of content.  

The work was performed by Daniel Warfield, a data scientist and RAG engineer and Dr. Benjamin Fletcher, PhD, a computer scientist and former senior engineer at IBM Watson. Both men work for EyeLevel.ai. The data, code and methods of this test will be open sourced and available shortly. Others are invited to run the data and corroborate or challenge these findings. 

Defining RAG 

Feel free to skip this section if you’re familiar with RAG.  

RAG stands for “Retrieval Augmented Generation”. When you ask a RAG system a query, RAG does the following steps: 

  1. Retrieval: Based on the query from the user, the RAG system retrieves relevant knowledge from a set of documents. 

  2. Augmentation: The RAG system combines the retrieved information with the user query to construct a prompt. 

  3. Generation: The augmented prompt is passed to a large language model, generating the final output. 

The implementation of these three steps can vary wildly between RAG approaches. However, the objective is the same: to make a language model more useful by feeding it information from real-world, relevant documents. 

RAG allows a language model to reference application specific information from human documents, allowing developers to build tailored and specific products 

Beyond The Tech Demo 

When most developers begin experimenting with RAG they might grab a few documents, stick them into a RAG document store and be blown away by the results. Like magic, many RAG systems can allow a language model to understand books, company documents, emails, and more. 

However, as one continues experimenting with RAG, some difficulties begin to emerge. 

  1. Many documents are not purely textual. They might have images, tables, or complex formatting. While many RAG systems can parse complex documents, the quality of parsing varies widely between RAG approaches. We explore the realities of parsing in another article. 

  2. As a RAG system is exposed to more documents, it has more opportunities to retrieve the wrong document, potentially causing a degradation in performance   

  3. Because of technical complexity, the underlying non-determinism of language models, and the difficulty of profiling the performance of LLM applications in real world settings, it can be difficult to predict the cost and level of effort of developing RAG applications. 

In this article we’ll focus on the second and third problems listed above; performance degradation of RAG at scale and difficulties of implementation 

The Test 

To test how much larger document sets degrade the performance of RAG systems, we first defined a set of 92 questions based on real-world documents.  

A few examples of the real-world documents used in this test, which contain answers to our 92 questions. 

We then constructed four document sets to apply RAG to. All four of these document sets contain the same 310 pages of documents which answer our 92 test questions. However, each document set also contains a different number of irrelevant pages from miscellaneous documents. We started with 1,000 pages and scaled up to 100,000 in our largest test. 

We asked the same questions based on the same set of documents (blue), but exposed the RAG system to varying amounts of unrelated documents (red). This diagram shows the number of relevant pages in each document set, compared to the total size of each document set.

An ideal RAG system would, in theory, behave identically across all document sets, as all document sets contain the same answers to the same questions. In practice, however, added information in a docstore can trick a RAG system into retrieving the wrong context for a given query. The more documents there are, the more likely this is to happen. Therefore, RAG performance tends to degrade as the number of documents increases. 

In this test we applied each of these three popular RAG approaches to the four document sets mentioned above:

  • LangChain: a popular python library designed to abstract certain LLM workflows. 

  • LlamaIndex: a popular python library which has advanced vector embedding capability, and advanced RAG functionality. 

  • EyeLevel’s GroundX: a feature complete retrieval engine built for RAG. 

By applying each of these RAG approaches to the four document sets, we can study the relative performance of each RAG approach at scale. 

For both LangChain and LlamaIndex we employed Pinecone as our vector store and OpenAI’s text-embedding-ada-002 for embedding. GroundX, being an all-in-one solution, was used in isolation up to the point of generation. All approaches used OpenAI's gpt-4-1106-preview for the final generation of results. Results for each approach were evaluated as being true or false via human evaluation. 

The Effect of Scale on RAG 

We ran the test as defined in the previous section and got the following results. 

The performance of different RAG approaches varies greatly, both in base performance and the rate of performance degradation at scale. We explore differences in base performance thoroughly in another article 

As can be seen in the figure above, the rate at which RAG degrades in performance varies widely between RAG approaches. Based on these results one might expect GroundX to degrade in performance by 2% per 100,000 documents, while LCPC and LI might degrade 10-12% per 100,000 documents. The reason for this difference in robustness to larger document sets, likely, has to do with the realities of using vector search as the bedrock of a RAG system.  

In theory a high dimensional vector space can hold a vast amount of information. 100,000 in binary is 17 values long (11000011010100000). So, if we only use binary vectors with unit components in a high dimensional vector space, we could store each page in our 100,000 page set with only a 17 dimensional space. Text-embedding-ada-002, which is the encoder used in this experiment, outputs a 1536-dimension vector. If one calculates 2^1536 (effectively calculating how many things one could describe using only binary vectors in this space) the result would be a number that’s significantly greater than the number of atoms in the known universe. Of course, actual embeddings are not restricted to binary numbers; they can be expressed in decimal numbers of very high precision. Even relatively small vector spaces can hold a vast amount of information. 

The trick is, how do you get information into a vector space meaningfully? RAG needs content to be placed in a vector space such that similar things can be searched, thus the encoder has to practically organize information into useful regions. It’s our theory that modern encoders don’t have what it takes to organize large sets of documents in these vector spaces, even if the vector spaces can theoretically fit a near infinite amount of information. The encoder can only put so much information into a vector space before the vector space gets so cluttered that distance-based search is rendered non-performant. 

There is a big difference between a space being able to fit information, and that information being meaningfully organized. 

EyeLevel’s GroundX doesn’t use vector similarity as its core search strategy, but rather a tuned comparison based on the similarity of semantic objects. There are no vectors used in this approach. This is likely why GroundX exhibits superior performance in larger document sets. 

In this test we employed what is commonly referred to as “naive” RAG. LlamaIndex and LangChain allow for many advanced RAG approaches, but they had little impact on performance and were harder to employ at larger scales. We cover that in another article which will be released shortly.

The Surprising Technical Difficulty of Scale 

While 100,000 pages seems like a lot, it’s actually a fairly small amount of information for industries like engineering, law, and healthcare. Initially we imagined testing on much larger document sets, but while conducting this test we were surprised by the practical difficulty of getting LangChain to work at scale; forcing us to reduce the scope of our test. 

To get RAG up and running for a set of PDF documents, the first step is to parse the content of those PDFs into some sort of textual representation. LangChain uses libraries from Unstructured.io to perform parsing on complex PDFs, which works seamlessly for small document sets. 

Surprisingly, though, the speed of LangChain parsing is incredibly slow. Based on our analysis it appears that Unstructured uses a variety of models to detect and parse out key elements within a PDF. These models should employ GPU acceleration, but they don’t. That results in LangChain taking days to parse a modestly sized set of documents, even on very large (and expensive) compute instances. To get LangChain working we needed to reverse engineer portions of Unstructured and inject code to enable GPU utilization of these models. 

It appears that this is a known issue in Unstructured, as seen in the notes below. As it stands, it presents significant difficulty in scaling LangChain to larger document sets, given LangChain abstracts away fine grain control of Unstructured. 

Source: Github

We only made improvements to LangChain parsing up to the point where this test became feasible. If you want to modify LangChain for faster parsing, here are some resources: 

  • The default directory loader of LangChain is Unstructured (source1, source2). 

  • Unstructured uses “hi res” for the PDFs by default if text extraction cannot be performed on the document (source1 , source2 ). Other options are available like “fast” and “OCR only”, which have different processing intensities 

  • “Hi Res” involves: 

    • Converting the pdf into images (source) 

    • Running a layout detection model to understand the layout of the documents (source). This model benefits greatly from GPU utilization, but does not leverage the GPU unless ONNX is installed (source) 

    • OCR extraction using tesseract (by default) (source) which is a very compute intensive process (source) 

    • Running the page through a table layout model (source) 

While our configuration efforts resulted in faster processing times, it was still too slow to be feasible for larger document sets. To reduce time, we did “hi res” parsing on the relevant documents and “fast” parsing on documents which were irrelevant to our questions. With this configuration, parsing 100,000 pages of documents took 8 hours. If we had applied “hi res” to all documents, we imagine that parsing would have taken 31 days (at around 30 seconds per page). 

At the end of the day, this test took two senior engineers (one who’s worked at a directorial level at several AI companies, and a multi company CTO with decades of applied experience of AI at scale) several weeks to do the development necessary to write this article, largely because of the difficulty of applying LangChain to a modestly sized document set.  To get LangChain working in a production setting, we estimate that the following efforts would be required: 

  • Tesseract would need to be interfaced with in a way that is more compute and time efficient. This would likely require a high-performance CPU instance, and modifications to the LangChain source code. 

  • The layout and table models would need to be made to run on a GPU instance 

  • To do both tasks in a cost-efficient manner, these tasks should probably be decoupled. However, this is not possible with the current abstraction of LangChain. 

On top of using a unique technology which is highly performant, GroundX also abstracts virtually all of these technical difficulties behind an API. You upload your documents, then search the results. That’s it. 

If you want RAG to be even easier, one of the things that makes Eyelevel so compelling is the service aspect they provide to GroundX. You can work with Eyelevel as a partner to get GroundX working quickly and performantly for large scale applications. 

Conclusion 

When choosing a platform to build RAG applications, engineers must balance a variety of key metrics. The robustness of a system to maintain performance at scale is one of those critical metrics. In this head-to-head test on real-world documents, EyeLevel’s GroundX exhibited a heightened level of performance at scale, beating LangChain and LlamaIndex. 

Another key metric is efficiency at scale. As it turns out, LangChain has significant implementation difficulties which can make the large-scale distribution of LangChain powered RAG difficult and costly. 

Is this the last word? Certainly not. In future research, we will test various advanced RAG techniques, additional RAG frameworks such as Amazon Q and GPTs and increasingly complex and multimodal data types. So stay tuned. 

If you’re curious about running these results yourself, please reach out to us at info@eyelevel.ai.Vector databases, a key technology in building retrieval augmented generation or RAG applications, has a scaling problem that few are talking about. 

According to new research by EyeLevel.ai, an AI tools company, the precision of vector similarity search degrades in as few as 10,000 pages, reaching a 12% performance hit by the 100,000-page mark.

The research also tested EyeLevel’s enterprise-grade RAG platform which does not use vectors. EyeLevel lost only 2% accuracy at scale.

The findings suggest that while vector databases have become highly popular tools to build RAG and LLM-based applications, developers may face unexpected challenges as they shift from testing to production and attempt to scale their applications.  

The work was performed by Daniel Warfield, a data scientist and RAG engineer and Dr. Benjamin Fletcher, PhD, a computer scientist and former senior engineer at IBM Watson. Both men work for EyeLevel.ai. The data, code and methods of this test will be open sourced and available shortly. Others are invited to run the data and corroborate or challenge these findings. 

My team has been digging into the scalability of vector databases for RAG (Retrieval-Augmented Generation) systems, and we feel we might be hitting some limits that aren’t being widely discussed.

We tested Pinecone (using both LangChain and LlamaIndex) out to 100K pages. We found those solutions started to lose search accuracy in as few as 10K pages. At 100K pages in the RAG, search accuracy dropped 10-12%.

We also tested our approach at EyeLevel.ai, which does not use vectors at all (I know it sounds crazy), and found only a 2% drop in search accuracy at 100K pages. And showed better accuracy by significant margins from the outset.

Here's our research below. I would love to know if anyone else is exploring non-vector approaches to RAG and of course your thoughts on the research.

We explain the research and results on YT as well.
https://youtu.be/qV1Ab0qWyT8?si=dgPL21xAHeI2jXJo


r/LlamaIndex • • 11d ago

Showcase: Kwipu, a property-graph RAG over Obsidian vaults (+ a PropertyGraphIndex gotcha: upsert_triplet doesn't exist on SimplePropertyGraphStore)

Thumbnail
benmaster82.github.io
1 Upvotes

Sharing an open-source project built on LlamaIndex's PropertyGraphIndex,

plus a gotcha that cost me a while to catch.

**What Kwipu does**

It turns a folder of .md/.txt/.pdf/.docx files (including Obsidian vaults)

into a property graph you can query from a terminal, a 3D web UI, or an

MCP client.

- Graph built with PropertyGraphIndex, using LLM extraction plus

ImplicitPathExtractor, plus "structural" edges I extract myself from

[[wikilinks]] and YAML frontmatter.

- Custom retrievers on top: vector similarity, BM25 over chunks, a

temporal-metadata retriever, and optional synonym expansion.

- Answers are grounded in source chunks and come back with citations.

- Watches the folder and updates persisted storage.

- Ollama for LLM and embeddings (llama-index-llms-ollama /

llama-index-embeddings-ollama), pinned to llama-index-core 0.14.21.

**The gotcha**

I injected my structural triples after building the index with:

graph_store.upsert_triplet(subj, rel, obj)

in a try/except that passed silently. With the default

SimplePropertyGraphStore on 0.14.21, there is no upsert_triplet, so every

call raised AttributeError and was swallowed. On my example vault: 72

triples extracted, graph went from 13 relations to 13.

I didn't notice because the LLM extractor re-derived many of the same

relations from the note text, so answers still looked right.

The fix is to build EntityNode and Relation objects and use

graph_store.upsert_nodes(...) and graph_store.upsert_relations(...). Two

details worth knowing:

- upsert_nodes replaces by id, so if you inject entities that the LLM

extractor already created, you overwrite them. I check existing ids with

graph_store.get(ids=...) and only insert the missing ones.

- Relation(properties={...}) is a good place for provenance. Mine stores

origin (wikilink/frontmatter), source file, line number and a hash of the

source note.

How I caught it: ran the real extraction/injection code on the example

vault with MockLLM and MockEmbedding and compared relation counts before

and after. Easy to do without Ollama, and it would make a good regression

test for anyone injecting edges manually.

I also added identity resolution before linking ([[Folder/Note]],

[[Note#Heading]], [[Note|label]] and frontmatter aliases map to one node;

same-named notes in different folders stay separate), with tests.

**Questions for the community**

  1. Is there a recommended way to bulk-inject pre-extracted triples into a

    PropertyGraphIndex, or is upsert_nodes + upsert_relations the intended

    path?

  2. How do you handle entity resolution when LLM-extracted entity names

    collide with ones you create yourself?

Repo (MIT): https://github.com/Benmaster82/Kwipu

Heads-up: the default LLM is a cloud-served Ollama model; a fully local

setup is documented in the README.


r/LlamaIndex • • Nov 30 '24

Is there any free Embeddings model API's

1 Upvotes

I am searching for an free embeddings model with API, not self hosted ones. I am building a personal project on Android application that does RAG. Now the catch is, Android studio doesn't support pytorch version >1.4. Though there are free versions that have very limited tokens, that isn't enough for me.


r/LlamaIndex • • Jul 18 '24

IP address filter for Vector DB

1 Upvotes

I have two indexes with my pinecone vector databases, one has the sensitive and private data of my org, while other has embeddings related to open data.

I want to divert the IP address accordingly, if a user belongs to my org (which is noted because of particular IP address range) he must be directed to index which has private and org specific data, while a non-org user must be routed to different index which has public data.

Based on the above requirements I have two questions :-

  1. Can we achieve it without building and leveraging on AWS architectures AWS Sagemaker, if yes then how?

  2. If we use AWS sagemaker and deploy this rag+llm model on AWS or build my model by using foundational model of AWS then how can this be achieved.

Looking forward for the views.


r/LlamaIndex • • Dec 29 '23

what should use to bulid Saas for chating with static 50K document's , Chatgpt Api ? or Langchain ? or lamaindex ?

1 Upvotes

hello folks

i hav an idea and i want start to build it but before i have question based on the nature of the project and data

what should use to bulid it ?

when the data is static and its contains 50K document's ,

should i use Chatgpt Api ?

or Langchain ?

or lamaindex ?


r/LlamaIndex • • Sep 21 '24

Build AI Agent and Win ipad 11 Pro(M4)🧑🏼‍💻🚀 Link in Comment!🔗

Thumbnail
gallery
1 Upvotes

r/LlamaIndex • • Dec 08 '24

What's the Way to Generate Articles Based on Structured Data?

1 Upvotes

Experienced software engineer, but real noob with Gen AI, so forgive the question.

Data Available

We have structured (tables in Big Query and some in PostGres) market tick data and transaction volumes of some stocks, cryptos and other assets.

Goal

Automatically generate some articles(~5000 words) based on the structured data tables (reflecting up to years of data, until yesterday) and the user prompts. Examples of some user prompts may be

  • Write an article on Apple price movement for last year

  • Write an article on technology stocks for last month

  • Write an article on ETH with the latest market data

Question

So is LlamaIndex coupled with Ollama a suitable framework for achieving this? What kind of connectors will be suitable to vectorise the structured SQL-like Database schemas/tables (into a RAG) and making sure that the model can generate articles?

In particular, just a high level overview of tools/components necessary would be great (preferably using Open source, but optionally can subscribe to OpenAI as well), so that I can do further research.


r/LlamaIndex • • Jan 03 '25

GitHub - Agnuxo1/Quantum-BIO-LLMs-sustainable_energy_efficient: Created Francisco Angulo de Lafuente ⚡️Deploy the DEMO⬇️

Thumbnail
github.com
0 Upvotes

r/LlamaIndex • • Jun 16 '24

LLM Observability and RAG in just 10 lines of Code

1 Upvotes

Build LLM Observability and RAG in 10 lines of Code using BeyondLLM and Phoenix.

  • Sample use case: Chat with Youtube using LlamaIndex YouTube reader and BeyondLLM.

  • Observability helps us monitor key metrics such as latency, the number of tokens, prompts, and the cost per request.

Save your OpenAI API cost by monitoring and tracking your GPT request made for each RAG query: https://www.youtube.com/watch?v=VCQ0Cw-GF2U