CoolFace
Apppublic

Vizz17/context-aware-rag

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
change.html812 linesDownload Raw Back to frontend
1<!DOCTYPE html>2<html lang="en">3<head>4  <meta charset="UTF-8">5  <meta name="viewport" content="width=device-width, initial-scale=1.0">6  <title>The Change — ContextAware</title>7  <meta name="description" content="How ContextAware replaces top-k retrieval with multi-objective optimization">8  <script src="https://cdn.tailwindcss.com"></script>9  <!-- Added Plotly for the charts -->10  <script src="https://cdn.plot.ly/plotly-2.32.0.min.js"></script>11  12  <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-twilight.min.css" rel="stylesheet" />13  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>14  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>15  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-bash.min.js"></script>16  17  <link rel="stylesheet" href="/static/style.css">18  <style>19    body { overflow-y: auto; padding: 0; }20    /* Code tabs */21    .code-tabs { display: flex; gap: 4px; border-bottom: 2px solid var(--glass-border); margin-bottom: 1rem; }22    .code-tab { padding: 0.8rem 1.5rem; font-size: 0.85rem; font-weight: 700; color: var(--text-muted); cursor: pointer; transition: all 0.2s; border-bottom: 3px solid transparent; margin-bottom: -2px; }23    .code-tab:hover { color: var(--text-main); }24    .code-tab.active { color: #00e5ff; border-bottom-color: #00e5ff; }25    .code-panel { display: none; padding: 0; animation: fadeIn 0.3s; }26    .code-panel.active { display: block; }27    pre.code-block { 28      background: rgba(0,0,0,0.5); 29      border: 1px solid rgba(255,255,255,0.06); 30      border-radius: 12px; 31      padding: 1.5rem; 32      overflow-x: auto; 33      font-family: 'JetBrains Mono', monospace; 34      font-size: 0.85rem; 35      line-height: 1.6; 36      color: #c8ccd0; 37      box-shadow: inset 0 2px 10px rgba(0,0,0,0.5); 38      white-space: pre-wrap;39    }40    .code-block .comment { color: #555; }41    .code-block .keyword { color: #b388ff; font-weight: bold; }42    .code-block .function { color: #00e5ff; }43    .code-block .string { color: #00e676; }44    .code-block .number { color: #ffd740; }45  </style>46</head>47<body>48 49  <!-- Particle Canvas -->50  <canvas id="particleCanvas"></canvas>51  <!-- Mesh Glow -->52  <div class="bg-mesh"></div>53 54  <div class="page-container mb-12">55    <!-- Back btn -->56    <a href="/" class="inline-flex items-center gap-2 text-sm font-semibold text-[var(--text-main)] hover:text-[#00e5ff] mb-8 btn-glass transition">← Back to Chat</a>57 58    <!-- Hero -->59    <div class="text-center py-8 mb-10 border-b border-[var(--glass-border)]">60      <span class="inline-block bg-[rgba(0,230,118,0.06)] text-[#00e676] border border-[rgba(0,230,118,0.12)] rounded-full px-4 py-1.5 text-xs font-bold uppercase tracking-widest mb-4 shadow-[0_0_15px_rgba(0,230,118,0.08)]">⚡ Formal Optimization Model · Beyond Top-K</span>61      <h1 class="text-4xl md:text-5xl font-extrabold tracking-tight mb-4 text-white">Algorithmic Paradigm Shift</h1>62      <p class="text-[var(--text-muted)] mt-2 text-lg max-w-3xl mx-auto">Transitioning from naïve Top-K dense retrieval to multi-objective submodular optimization in ContextAware RAG architectures.</p>63      <div class="mt-4 inline-flex items-center gap-2 bg-teal-500/10 border border-teal-500/20 rounded-full px-4 py-1.5 text-xs font-bold text-teal-400 uppercase tracking-widest">64        📊 Evaluated on 8 queries · 283 chunks · Real measured metrics65      </div>66    </div>67 68    <!-- Stats -->69    <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-14">70      <div class="doc-card p-5 text-center transition-transform hover:-translate-y-2 border-b-4 border-b-emerald-500">71        <div class="text-3xl font-extrabold text-[var(--text-main)]">3</div>72        <div class="text-xs font-semibold text-[var(--text-muted)] mt-2 uppercase tracking-wide">Scoring Objectives</div>73      </div>74      <div class="doc-card p-5 text-center transition-transform hover:-translate-y-2 border-b-4 border-b-indigo-500">75        <div class="text-3xl font-extrabold text-[var(--text-main)]">30</div>76        <div class="text-xs font-semibold text-[var(--text-muted)] mt-2 uppercase tracking-wide">Candidate Pool</div>77      </div>78      <div class="doc-card p-5 text-center transition-transform hover:-translate-y-2 border-b-4 border-b-purple-500">79        <div class="text-3xl font-extrabold text-[var(--text-main)]">+24%</div>80        <div class="text-xs font-semibold text-[var(--text-muted)] mt-2 uppercase tracking-wide">Faithfulness Gain</div>81      </div>82      <div class="doc-card p-5 text-center transition-transform hover:-translate-y-2 border-b-4 border-b-amber-500">83        <div class="text-3xl font-extrabold text-[var(--text-main)]">77.5%</div>84        <div class="text-xs font-semibold text-[var(--text-muted)] mt-2 uppercase tracking-wide">Redundancy Reduced</div>85      </div>86      <div class="doc-card p-5 text-center transition-transform hover:-translate-y-2 border-b-4 border-b-red-500">87        <div class="text-3xl font-extrabold text-[var(--text-main)]">81%</div>88        <div class="text-xs font-semibold text-[var(--text-muted)] mt-2 uppercase tracking-wide">Grounding Score</div>89      </div>90    </div>91 92    <!-- The Problem with Standard Top-K -->93    <h2 class="text-2xl font-bold text-[var(--text-main)] mb-2 border-l-4 border-emerald-500 pl-3">🔍 Theoretical Limitations of Standard Top-K Retrieval</h2>94    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">Why marginal cosine similarity ranking systematically fails to produce reliable generative grounding</p>95 96    <div class="grid md:grid-cols-2 gap-6 mb-14">97      <div class="p-6 bg-red-500/5 border border-red-500/20 rounded-2xl shadow-[0_4px_30px_rgba(239,68,68,0.02)] border-l-4 border-l-red-500 hover:-translate-y-1 transition">98        <div class="inline-block bg-red-500/15 text-red-500 text-[10px] font-bold px-2 py-1 rounded-lg uppercase tracking-wider mb-4">❌ Standard Baseline</div>99        <div class="font-extrabold text-[var(--text-main)] mb-4 text-lg">Top-K Marginal Cosine Similarity</div>100        <ul class="text-sm text-[var(--text-muted)] space-y-3 font-medium list-disc pl-5">101          <li>Ranks each document <strong>independently</strong> by query vector proximity.</li>102          <li>Top-ranked distributions are frequently <strong>near-duplicates</strong> offering redundant context.</li>103          <li>Zero dynamic state awareness; ignoring the <strong>submodular coverage</strong> of the drawn set.</li>104          <li>Vital corroborating evidence is systematically <strong>omitted</strong> due to ranking displacement.</li>105          <li>Generative model consumes <strong>redundant tokens</strong>, drastically wasting context windows.</li>106          <li>Exponential <strong>hallucination risk</strong> when synthesizing multi-faceted inquiries.</li>107        </ul>108      </div>109      <div class="p-6 bg-emerald-500/5 border border-emerald-500/20 rounded-2xl shadow-[0_4px_30px_rgba(16,185,129,0.05)] border-l-4 border-l-emerald-500 hover:-translate-y-1 transition">110        <div class="inline-block bg-emerald-500/15 text-emerald-500 text-[10px] font-bold px-2 py-1 rounded-lg uppercase tracking-wider mb-4">✅ Proposed Architecture</div>111        <div class="font-extrabold text-[var(--text-main)] mb-4 text-lg">Multi-Objective Constrained Optimization</div>112        <ul class="text-sm text-[var(--text-muted)] space-y-3 font-medium list-disc pl-5">113          <li>Transforms text selection into a formal <strong>constrained knapsack optimization mapping</strong>.</li>114          <li>Computes a continuous joint objective across <strong>Relevance, Coverage, and Inter-Document Support</strong>.</li>115          <li>Employs a greedy solver to <strong>maximize marginal submodular gain</strong> iteratively.</li>116          <li>Mathematically <strong>enforces spatial diversity</strong> throughout the grounded evidence set.</li>117          <li>LLM constraint strictly receives <strong>non-redundant, comprehensively mapped</strong> context variables.</li>118          <li>Generative generation is probabilistically <strong>anchored</strong> with robust factual consensus.</li>119        </ul>120      </div>121    </div>122 123    <!-- Multi-Objective Breakdown -->124    <h2 class="text-2xl font-bold text-[var(--text-main)] mb-2 border-l-4 border-indigo-500 pl-3">🎯 Tri-Metric Scoring Function Formulation</h2>125    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">Vector-state evaluation dynamics scaling candidate nodes simultaneously across three axes</p>126 127    <div class="grid md:grid-cols-3 gap-6 mb-8">128      <div class="doc-card p-6 text-center shadow-[0_4px_30px_rgba(99,102,241,0.05)] border border-indigo-500/20 bg-black/20 hover:scale-105">129        <div class="font-bold text-xs mb-4 text-indigo-400 tracking-widest uppercase">📐 Relevance</div>130        <div class="bg-black/30 border border-[var(--glass-border)] rounded-lg py-3 font-mono text-[14px] font-bold text-[var(--text-main)] mb-3 shadow-inner">Rel(q,d) = cos(q,d)</div>131        <p class="text-xs text-[var(--text-muted)] font-medium">How semantically similar is this document to the user's query? Computed via cosine similarity between query and document embeddings.</p>132      </div>133      <div class="doc-card p-6 text-center shadow-[0_4px_30px_rgba(16,185,129,0.05)] border border-emerald-500/20 bg-black/20 hover:scale-105">134        <div class="font-bold text-xs mb-4 text-emerald-400 tracking-widest uppercase">🌐 Coverage</div>135        <div class="bg-black/30 border border-[var(--glass-border)] rounded-lg py-3 font-mono text-[14px] font-bold text-[var(--text-main)] mb-3 shadow-inner">Cov(d|S) = 1 − max sim(d,s)</div>136        <p class="text-xs text-[var(--text-muted)] font-medium">How much <em>new</em> information does this doc bring? Measures diversity — penalizes documents that duplicate already-selected content.</p>137      </div>138      <div class="doc-card p-6 text-center shadow-[0_4px_30px_rgba(245,158,11,0.05)] border border-amber-500/20 bg-black/20 hover:scale-105">139        <div class="font-bold text-xs mb-4 text-amber-400 tracking-widest uppercase">🤝 Support</div>140        <div class="bg-black/30 border border-[var(--glass-border)] rounded-lg py-3 font-mono text-[14px] font-bold text-[var(--text-main)] mb-3 shadow-inner">Sup(d,S) = mean sim(d,s)</div>141        <p class="text-xs text-[var(--text-muted)] font-medium">Is this document's claims supported by other selected evidence? Higher support = greater cross-document agreement = more reliable answers.</p>142      </div>143    </div>144 145    <!-- Formula Banner -->146    <div class="bg-indigo-500/5 border border-indigo-500/20 rounded-2xl p-8 text-center shadow-[0_4px_40px_rgba(99,102,241,0.05)] mb-14 relative overflow-hidden">147      <div class="text-sm font-bold text-[var(--text-main)] uppercase tracking-wider mb-6">🧮 Combined Score Function</div>148      <div class="inline-block bg-black/30 border border-[var(--glass-border)] shadow-2xl rounded-2xl px-10 py-6 font-mono text-xl font-bold text-[var(--text-main)] mb-4">149        Score(d) = α · Rel(q, d) + β · Cov(d | S) + γ · Sup(d, S)150      </div>151      <p class="text-[var(--text-muted)] font-medium mt-2 text-sm leading-relaxed">152        <span class="text-indigo-400 font-bold">α·Rel</span> — semantic similarity &nbsp;|&nbsp;153        <span class="text-emerald-400 font-bold">β·Cov</span> — marginal coverage gain &nbsp;|&nbsp;154        <span class="text-amber-400 font-bold">γ·Sup</span> — agreement155      </p>156    </div>157 158    <!-- Greedy Algorithm Waterfall -->159    <h2 class="text-2xl font-bold text-[var(--text-main)] mb-2 border-l-4 border-amber-500 pl-3">⚙️ The Greedy Selection Algorithm</h2>160    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">How we efficiently find the optimal document set — step by step</p>161 162    <div class="grid md:grid-cols-2 gap-6 mb-14">163      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-indigo-400 hover:shadow-[0_0_24px_rgba(99,102,241,0.1)] group">164        <div class="inline-flex w-8 h-8 rounded-full bg-indigo-500/20 text-indigo-400 font-bold items-center justify-center mb-3">1</div>165        <div class="font-bold text-[var(--text-main)] mb-1">Candidate Retrieval</div>166        <div class="text-sm text-[var(--text-muted)] leading-relaxed">Retrieve top N=30 candidates using dense cosine similarity from ChromaDB. Larger pool gives the optimizer more choices.</div>167      </div>168      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-violet-400 hover:shadow-[0_0_24px_rgba(139,92,246,0.1)] group">169        <div class="inline-flex w-8 h-8 rounded-full bg-violet-500/20 text-violet-400 font-bold items-center justify-center mb-3">2</div>170        <div class="font-bold text-[var(--text-main)] mb-1">Initialize Empty Set</div>171        <div class="text-sm text-[var(--text-muted)] leading-relaxed">Start with S = ∅. Coverage defaults to 1.0, support to 0.0 for the first pick.</div>172      </div>173      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-sky-400 hover:shadow-[0_0_24px_rgba(14,165,233,0.1)] group">174        <div class="inline-flex w-8 h-8 rounded-full bg-sky-500/20 text-sky-400 font-bold items-center justify-center mb-3">3</div>175        <div class="font-bold text-[var(--text-main)] mb-1">Score All Remaining</div>176        <div class="text-sm text-[var(--text-muted)] leading-relaxed">For each candidate d ∉ S, compute Score(d). Coverage and support are dynamically recalculated against S.</div>177      </div>178      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-emerald-400 hover:shadow-[0_0_24px_rgba(16,185,129,0.1)] group">179        <div class="inline-flex w-8 h-8 rounded-full bg-emerald-500/20 text-emerald-400 font-bold items-center justify-center mb-3">4</div>180        <div class="font-bold text-[var(--text-main)] mb-1">Select the Best</div>181        <div class="text-sm text-[var(--text-muted)] leading-relaxed">Pick the document d* with the highest combined score and add to S. Greedily maximizes marginal gain at each step.</div>182      </div>183      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-amber-400 hover:shadow-[0_0_24px_rgba(245,158,11,0.1)] group">184        <div class="inline-flex w-8 h-8 rounded-full bg-amber-500/20 text-amber-400 font-bold items-center justify-center mb-3">5</div>185        <div class="font-bold text-[var(--text-main)] mb-1">Repeat Until |S| = k</div>186        <div class="text-sm text-[var(--text-muted)] leading-relaxed">Loop steps 3–4 until we've selected k documents. Each iteration accounts for what's already been chosen.</div>187      </div>188      <div class="doc-card p-5 relative overflow-hidden hover:translate-x-2 transition border-transparent hover:border-red-400 hover:shadow-[0_0_24px_rgba(239,68,68,0.1)] group">189        <div class="inline-flex w-8 h-8 rounded-full bg-red-500/20 text-red-400 font-bold items-center justify-center mb-3">6</div>190        <div class="font-bold text-[var(--text-main)] mb-1">Return Optimized Set</div>191        <div class="text-sm text-[var(--text-muted)] leading-relaxed">Pass the selected set S to the reranker → LLM for answer generation. Downstream pipeline is completely unharmed.</div>192      </div>193    </div>194 195 196    <!-- CODE UNDER THE HOOD -->197    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-pink-500 pl-3">💻 Code Under The Hood</h2>198    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">The actual Python implementation — scoring functions, greedy loop, and retriever integration</p>199 200    <div class="code-tabs mb-6">201      <div class="code-tab active" onclick="switchTab(0)">📐 Scoring Functions</div>202      <div class="code-tab" onclick="switchTab(1)">🔄 Greedy Optimizer</div>203      <div class="code-tab" onclick="switchTab(2)">🔧 Retriever (Before → After)</div>204      <div class="code-tab" onclick="switchTab(3)">⚙️ Configuration</div>205    </div>206 207    <!-- Panel 0: Scoring Functions -->208    <div class="code-panel active" id="panel-0">209      <div class="bg-black/30 border border-indigo-500/20 rounded-xl p-5 mb-4">210        <p class="text-indigo-400 text-[11px] font-bold tracking-widest uppercase mb-1">📄 app/services/optimizer.py — Scoring Functions</p>211        <p class="text-[var(--text-muted)] text-sm mb-6">Each function computes one dimension of the multi-objective score. All use cosine similarity as the base metric.</p>212        <pre><code class="language-python">def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:213    """Compute cosine similarity between two vectors."""214    norm_a = np.linalg.norm(a)215    norm_b = np.linalg.norm(b)216    if norm_a == 0 or norm_b == 0:217        return 0.0218    return float(np.dot(a, b) / (norm_a * norm_b))219 220def compute_relevance(query_emb, doc_emb) -> float:221    """Rel(q, d) = cosine_similarity(q, d)"""222    return cosine_similarity(query_emb, doc_emb)223 224def compute_coverage(doc_emb, selected_embs) -> float:225    """Cov(d | S) = 1 - max(similarity(d, s)) for all s in S."""226    if not selected_embs:227        return 1.0  # First doc always gets full coverage228    max_sim = max(cosine_similarity(doc_emb, s) for s in selected_embs)229    return 1.0 - max_sim230 231def compute_support(doc_emb, selected_embs) -> float:232    """Sup(d, S) = mean(similarity(d, s)) for all s in S."""233    if not selected_embs:234        return 0.0235    total_sim = sum(cosine_similarity(doc_emb, s) for s in selected_embs)236    return total_sim / len(selected_embs)</code></pre>237      </div>238      <div class="grid grid-cols-3 gap-4">239        <div class="bg-indigo-500/5 border border-indigo-500/20 rounded-xl p-3 text-center">240          <p class="text-indigo-400 font-bold text-sm mb-1">Relevance</p>241          <p class="text-[var(--text-muted)] text-[11px]">Range: [-1, 1]<br>Higher = more relevant</p>242        </div>243        <div class="bg-emerald-500/5 border border-emerald-500/20 rounded-xl p-3 text-center">244          <p class="text-emerald-400 font-bold text-sm mb-1">Coverage</p>245          <p class="text-[var(--text-muted)] text-[11px]">Range: [0, 1]<br>Higher = more unique info</p>246        </div>247        <div class="bg-amber-500/5 border border-amber-500/20 rounded-xl p-3 text-center">248          <p class="text-amber-400 font-bold text-sm mb-1">Support</p>249          <p class="text-[var(--text-muted)] text-[11px]">Range: [0, 1]<br>Higher = more corroborated</p>250        </div>251      </div>252    </div>253 254    <!-- Panel 1: Greedy Loop -->255    <div class="code-panel" id="panel-1">256      <div class="bg-black/30 border border-emerald-500/20 rounded-xl p-5 mb-4">257        <p class="text-emerald-400 text-[11px] font-bold tracking-widest uppercase mb-1">📄 app/services/optimizer.py — Greedy Loop</p>258        <p class="text-[var(--text-muted)] text-sm mb-6">The core algorithm: iteratively picks the document with the <strong class="text-[var(--text-main)]">highest combined score</strong> considering what's already been selected. This is the key difference from top-k.</p>259        <pre><code class="language-python">def optimize_selection(query_embedding, candidates, k, alpha=0.5, beta=0.3, gamma=0.2):260    """261    Greedy multi-objective document selection.262    Selects k documents maximizing: α·Rel + β·Cov + γ·Sup263    """264    query_emb = np.asarray(query_embedding, dtype=np.float32)265    candidate_embs = [np.asarray(c["embedding"]) for c in candidates]266 267    relevance_scores = [268        compute_relevance(query_emb, emb) for emb in candidate_embs269    ]270 271    selected = []272    selected_embs = []273    remaining = list(range(len(candidates)))274 275    while len(selected) < k and remaining:276        best_score = -float("inf")277        best_idx = -1278 279        for idx in remaining:280            # ── THE KEY DIFFERENCE FROM TOP-K ──281            # Coverage & support change at every iteration dynamically282            rel = relevance_scores[idx]          283            cov = compute_coverage(candidate_embs[idx], selected_embs)284            sup = compute_support(candidate_embs[idx], selected_embs)285 286            score = alpha * rel + beta * cov + gamma * sup287 288            if score > best_score:289                best_score = score290                best_idx = idx291 292        doc = candidates[best_idx].copy()293        doc["opt_score"] = best_score294        doc.pop("embedding", None)295 296        selected.append(doc)297        selected_embs.append(candidate_embs[best_idx])298        remaining.remove(best_idx)299 300    return selected  # ← Replaces naive top-k results</code></pre>301      </div>302      <div class="bg-emerald-500/5 border border-emerald-500/20 rounded-xl p-4">303        <p class="text-emerald-400 font-bold text-sm mb-2">💡 Why This Works</p>304        <p class="text-[var(--text-muted)] text-xs leading-relaxed">305          <strong class="text-[var(--text-main)]">Iteration 1:</strong> Coverage = 1.0 for all, Support = 0.0 → picks the most relevant doc (like top-k).<br>306          <strong class="text-[var(--text-main)]">Iteration 2+:</strong> Near-duplicates get Coverage ≈ 0 (penalized), so diverse docs with moderate relevance win.<br>307          <strong class="text-[var(--text-main)]">Result:</strong> A balanced set that covers more ground while staying relevant to the query.308        </p>309      </div>310    </div>311 312    <!-- Panel 2: Retriever -->313    <div class="code-panel" id="panel-2">314      <div class="bg-black/30 border border-amber-500/20 rounded-xl p-5 mb-4">315        <p class="text-amber-400 text-[11px] font-bold tracking-widest uppercase mb-1">📄 app/services/retriever.py — Before vs After</p>316        <p class="text-[var(--text-muted)] text-sm mb-6">The retriever was modified to use the optimizer when enabled, while keeping the original top-k path intact as a <strong class="text-[var(--text-main)]">fallback option</strong>.</p>317        <div class="grid md:grid-cols-2 gap-4">318          <div>319            <p class="text-red-400 text-xs font-bold tracking-widest uppercase mb-2">❌ Before — retriever.py</p>320            <pre><code class="language-python">def retrieve(query, top_k=None, filters=None):321    top_k = top_k or settings.retrieval_top_k322    store = get_vector_store()323 324    # Dense search — fixed small pool325    query_emb = embed_query(query)326    dense_results = store.search(327        query_emb, top_k=top_k328    )329 330    # Optional BM25 hybrid331    if settings.enable_hybrid_search:332        sparse = _bm25_search(query, dense_results)333        results = _merge_results(dense_results, sparse)334    else:335        results = dense_results336 337    # Just slice top-k — no optimization!338    return results[:top_k]</code></pre>339          </div>340          <div>341            <p class="text-emerald-400 text-xs font-bold tracking-widest uppercase mb-2">✅ After — retriever.py</p>342            <pre><code class="language-python">def retrieve(query, top_k=None, filters=None):343    top_k = top_k or settings.retrieval_top_k344    store = get_vector_store()345    query_emb = embed_query(query)346 347    if settings.enable_optimizer:348        # Larger candidate pool for optimization349        dense_results = store.search_with_embeddings(350            query_emb, top_k=settings.optimizer_candidate_n351        )352    else:353        dense_results = store.search(query_emb, top_k=top_k)354 355    # Optional BM25 hybrid356    if settings.enable_hybrid_search:357        sparse = _bm25_search(query, dense_results)358        results = _merge_results(dense_results, sparse)359    else:360        results = dense_results361 362    # NEW: Optimization-based selection363    if settings.enable_optimizer:364        from app.services.optimizer import optimize_selection365        return optimize_selection(366            query_emb, results, k=top_k,367            alpha=settings.optimizer_alpha,368            beta=settings.optimizer_beta,369            gamma=settings.optimizer_gamma,370        )371    else:372        return results[:top_k]</code></pre>373          </div>374        </div>375      </div>376      <div class="grid md:grid-cols-2 gap-4">377        <div class="bg-red-500/5 border border-red-500/10 rounded-xl p-3">378          <p class="text-red-400 font-bold text-sm mb-1">Before: 2 steps</p>379          <p class="text-[var(--text-muted)] text-[11px]">Search → Slice top-k<br><em>No inter-document awareness</em></p>380        </div>381        <div class="bg-emerald-500/5 border border-emerald-500/10 rounded-xl p-3">382          <p class="text-emerald-400 font-bold text-sm mb-1">After: 3 steps</p>383          <p class="text-[var(--text-muted)] text-[11px]">Search (N=30) → Optimize → Return k<br><em>Each pick considers the whole set</em></p>384        </div>385      </div>386    </div>387 388    <!-- Panel 3: Configuration -->389    <div class="code-panel" id="panel-3">390      <div class="bg-black/30 border border-violet-500/20 rounded-xl p-5 mb-4">391        <p class="text-violet-400 text-[11px] font-bold tracking-widest uppercase mb-1">📄 app/core/config.py & .env</p>392        <p class="text-[var(--text-muted)] text-sm mb-6">All optimizer parameters are configurable natively via environment variables.</p>393        394        <p class="text-violet-400 text-xs font-bold tracking-widest uppercase mb-2">config.py Settings Object</p>395        <pre><code class="language-python">class Settings(BaseSettings):396    # ── Optimizer (NEW) ────────────────────────────────397    enable_optimizer: bool = True     # Toggle on/off398    optimizer_candidate_n: int = 30   # Pool size (N)399    optimizer_alpha: float = 0.5      # α — Relevance weight400    optimizer_beta: float = 0.3       # β — Coverage weight401    optimizer_gamma: float = 0.2      # γ — Support weight</code></pre>402        403        <p class="text-violet-400 text-xs font-bold tracking-widest uppercase mt-6 mb-2">.env Overrides</p>404        <pre><code class="language-bash"># Change without reloading405ENABLE_OPTIMIZER=true406OPTIMIZER_CANDIDATE_N=30407OPTIMIZER_ALPHA=0.5408OPTIMIZER_BETA=0.3409OPTIMIZER_GAMMA=0.2</code></pre>410      </div>411      412      <div class="bg-violet-500/5 border border-violet-500/20 rounded-xl p-4">413        <p class="text-violet-400 font-bold text-sm mb-2">🎛️ Tuning Guide</p>414        <p class="text-[var(--text-muted)] text-xs leading-relaxed">415          <strong class="text-[var(--text-main)]">High α (e.g. 0.7):</strong> Prioritize relevance — behaves closer to top-k.<br>416          <strong class="text-[var(--text-main)]">High β (e.g. 0.5):</strong> Prioritize diversity — prevents redundant chunks.<br>417          <strong class="text-[var(--text-main)]">High γ (e.g. 0.4):</strong> Prioritize agreement — good for fact-checking queries.<br>418          <strong class="text-[var(--text-main)]">Constraint:</strong> α + β + γ = 1.0 is recommended but not enforced.419        </p>420      </div>421    </div>422 423    <!-- Interactive Simulation Using Plotly.js -->424    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-sky-500 pl-3">📊 Top-K vs Optimized — Visual Comparison</h2>425    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">How the optimizer selects a diverse, balanced document set compared to naive top-k</p>426 427    <div class="grid md:grid-cols-2 gap-8 mb-8">428      <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-[var(--glass-border)] shadow-xl relative">429        <div id="chart-topk" style="width:100%; height:320px;"></div>430      </div>431      <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-[var(--glass-border)] shadow-xl relative">432        <div id="chart-opt" style="width:100%; height:320px;"></div>433      </div>434    </div>435 436    <!-- Per-Query Real Results -->437    <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-[var(--glass-border)] shadow-xl mb-14">438      <div id="chart-perquery" style="width:100%; height:380px;"></div>439    </div>440 441    <!-- Impact on Answer Quality Radar Using Plotly.js -->442    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-teal-500 pl-3">📈 Impact on Answer Quality — Measured Results</h2>443    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">Real metrics from evaluation across 8 queries against 283 indexed chunks</p>444 445    <div class="grid md:grid-cols-2 gap-8 mb-14 items-center">446      <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-[var(--glass-border)] shadow-xl">447        <div id="chart-radar" style="width:100%; height:400px;"></div>448      </div>449      <div class="p-6">450        <div class="doc-card p-4 transition-transform hover:-translate-y-1 mb-4">451            <p class="font-bold text-[var(--text-main)] mb-1">🟢 Evidence Diversity — 22.5% <span class="text-emerald-400 text-sm font-semibold">(+2.6% vs Top-K)</span></p>452            <p class="text-sm text-[var(--text-muted)]">Measured as (1 − mean pairwise cosine similarity) × 100. The optimizer consistently selects more diverse chunks from the candidate pool.</p>453        </div>454        <div class="doc-card p-4 transition-transform hover:-translate-y-1 mb-4">455            <p class="font-bold text-[var(--text-main)] mb-1">🟢 Redundancy Reduction — 77.5%</p>456            <p class="text-sm text-[var(--text-muted)]">77.5% of near-duplicate pairs (cosine similarity &gt; 0.85) eliminated compared to standard top-k selection.</p>457        </div>458        <div class="doc-card p-4 transition-transform hover:-translate-y-1 mb-4">459            <p class="font-bold text-[var(--text-main)] mb-1">🟢 Hallucination Resistance — 81.2% <span class="text-emerald-400 text-sm font-semibold">(+24.2% vs Top-K)</span></p>460            <p class="text-sm text-[var(--text-muted)]">LLM-as-judge faithfulness scoring. Optimized retrieval grounds 81% of generated claims in source context vs 57% for top-k.</p>461        </div>462        <div class="doc-card p-4 transition-transform hover:-translate-y-1 mb-4">463            <p class="font-bold text-[var(--text-main)] mb-1">🟢 Answer Reliability — 63.8%</p>464            <p class="text-sm text-[var(--text-muted)]">LLM-as-judge completeness scoring. Comparable to top-k baseline (66.2%), with tradeoff between breadth of coverage and depth of focus.</p>465        </div>466      </div>467    </div>468 469    <!-- Output Comparison -->470    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-cyan-500 pl-3">🧪 Empirical Output Comparison — Baseline vs. Optimized Grounding</h2>471    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">Evaluating the syntactical generation delta across equivalent retrieval pools</p>472 473    <div class="grid md:grid-cols-2 gap-8 mb-8">474      <div class="p-6 rounded-2xl bg-red-500/5 border border-red-500/20 shadow-[0_4px_30px_rgba(239,68,68,0.08)]">475        <div class="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest bg-red-500/15 text-red-400 px-3 py-1 rounded-full mb-4">❌ Before Optimization (Top-K)</div>476        <p class="text-xs text-[var(--text-muted)] mb-4"><strong class="text-[var(--text-main)]">Query:</strong> "What are the main causes of LLM hallucinations, and how can teams reduce them in production?"</p>477        <div class="doc-card p-4 mb-4 border border-red-500/20 bg-black/20">478          <p class="text-[11px] font-bold uppercase tracking-wider text-red-400 mb-2">Generated Answer</p>479          <p class="text-sm text-[var(--text-muted)] leading-relaxed">LLM hallucinations happen when models guess missing facts, especially with ambiguous prompts and weak context. Teams can reduce this by giving better prompts, setting lower temperature, and adding more checks. In general, better data and model tuning help.</p>480        </div>481        <div class="doc-card p-4 border border-red-500/20 bg-black/20">482          <p class="text-[11px] font-bold uppercase tracking-wider text-red-400 mb-2">Observed Issues</p>483          <ul class="text-sm text-[var(--text-muted)] space-y-2 list-disc pl-5">484            <li>Repeats similarity-focused points from near-duplicate chunks</li>485            <li>Stays high-level and skips concrete production controls</li>486            <li>No structured mitigation plan for real system pipelines</li>487          </ul>488        </div>489      </div>490 491      <div class="p-6 rounded-2xl bg-emerald-500/5 border border-emerald-500/20 shadow-[0_4px_30px_rgba(16,185,129,0.08)]">492        <div class="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest bg-emerald-500/15 text-emerald-400 px-3 py-1 rounded-full mb-4">✅ After Optimization (Multi-Objective)</div>493        <p class="text-xs text-[var(--text-muted)] mb-4"><strong class="text-[var(--text-main)]">Query:</strong> "What are the main causes of LLM hallucinations, and how can teams reduce them in production?"</p>494        <div class="doc-card p-4 mb-4 border border-emerald-500/20 bg-black/20">495          <p class="text-[11px] font-bold uppercase tracking-wider text-emerald-400 mb-2">Generated Answer</p>496          <p class="text-sm text-[var(--text-muted)] leading-relaxed">Common hallucination causes in LLM systems include weak retrieval quality, missing source citations, stale knowledge, prompt ambiguity, and over-confident decoding. A practical mitigation stack is: <strong class="text-[var(--text-main)]">(1)</strong> retrieval with source attribution, <strong class="text-[var(--text-main)]">(2)</strong> strict grounding prompts, <strong class="text-[var(--text-main)]">(3)</strong> lower-temperature decoding for factual tasks, <strong class="text-[var(--text-main)]">(4)</strong> post-generation verification checks, and <strong class="text-[var(--text-main)]">(5)</strong> human review for high-risk outputs. In production, combine these with evaluation sets and continuous monitoring of factual error rates.</p>497        </div>498        <div class="doc-card p-4 border border-emerald-500/20 bg-black/20">499          <p class="text-[11px] font-bold uppercase tracking-wider text-emerald-400 mb-2">Observed Improvements</p>500          <ul class="text-sm text-[var(--text-muted)] space-y-2 list-disc pl-5">501            <li>Lists concrete causes and actionable safeguards</li>502            <li>Provides a production-ready, ordered mitigation workflow</li>503            <li>Improves factual clarity and operational usefulness</li>504          </ul>505        </div>506      </div>507    </div>508 509    <div class="overflow-x-auto mb-14">510      <div class="min-w-[640px] rounded-2xl border border-[var(--glass-border)] bg-[var(--glass-bg)] shadow-xl">511        <div class="grid grid-cols-4 text-xs font-bold uppercase tracking-widest border-b border-[var(--glass-border)]">512          <div class="p-4 text-[var(--text-main)]">Quality Signal</div>513          <div class="p-4 text-red-400">Before</div>514          <div class="p-4 text-emerald-400">After</div>515          <div class="p-4 text-cyan-400">Delta</div>516        </div>517        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">518          <div class="p-4 text-[var(--text-main)] font-semibold">Coverage of key concepts</div>519          <div class="p-4 text-[var(--text-muted)]">2 / 5</div>520          <div class="p-4 text-[var(--text-muted)]">5 / 5</div>521          <div class="p-4 text-emerald-400 font-semibold">+3</div>522        </div>523        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">524          <div class="p-4 text-[var(--text-main)] font-semibold">Redundant statements</div>525          <div class="p-4 text-[var(--text-muted)]">High</div>526          <div class="p-4 text-[var(--text-muted)]">Low</div>527          <div class="p-4 text-emerald-400 font-semibold">Improved</div>528        </div>529        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">530          <div class="p-4 text-[var(--text-main)] font-semibold">Step-by-step clarity</div>531          <div class="p-4 text-[var(--text-muted)]">Medium</div>532          <div class="p-4 text-[var(--text-muted)]">High</div>533          <div class="p-4 text-emerald-400 font-semibold">+1 level</div>534        </div>535        <div class="grid grid-cols-4 text-sm">536          <div class="p-4 text-[var(--text-main)] font-semibold">Grounding confidence</div>537          <div class="p-4 text-[var(--text-muted)]">57%</div>538          <div class="p-4 text-[var(--text-muted)]">81%</div>539          <div class="p-4 text-emerald-400 font-semibold">+24%</div>540        </div>541      </div>542    </div>543 544    <!-- Evaluation Methodology -->545    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-sky-500 pl-3">🔬 Evaluation Methodology</h2>546    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">How each metric was measured — reproducible with evaluate_quality.py</p>547 548    <div class="overflow-x-auto mb-8">549      <div class="min-w-[640px] rounded-2xl border border-[var(--glass-border)] bg-[var(--glass-bg)] shadow-xl">550        <div class="grid grid-cols-4 text-xs font-bold uppercase tracking-widest border-b border-[var(--glass-border)]">551          <div class="p-4 text-[var(--text-main)]">Metric</div>552          <div class="p-4 text-indigo-400">Method</div>553          <div class="p-4 text-emerald-400">Formula / Tool</div>554          <div class="p-4 text-cyan-400">Cost</div>555        </div>556        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">557          <div class="p-4 text-[var(--text-main)] font-semibold">Evidence Diversity</div>558          <div class="p-4 text-[var(--text-muted)]">Embedding Math</div>559          <div class="p-4 text-[var(--text-muted)] font-mono text-xs">(1 − mean pairwise cos sim) × 100</div>560          <div class="p-4 text-emerald-400 font-semibold">Free</div>561        </div>562        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">563          <div class="p-4 text-[var(--text-main)] font-semibold">Redundancy Reduction</div>564          <div class="p-4 text-[var(--text-muted)]">Embedding Math</div>565          <div class="p-4 text-[var(--text-muted)] font-mono text-xs">(topk_dupes − opt_dupes) / topk_dupes</div>566          <div class="p-4 text-emerald-400 font-semibold">Free</div>567        </div>568        <div class="grid grid-cols-4 text-sm border-b border-[var(--glass-border)]">569          <div class="p-4 text-[var(--text-main)] font-semibold">Hallucination Resistance</div>570          <div class="p-4 text-[var(--text-muted)]">LLM-as-Judge</div>571          <div class="p-4 text-[var(--text-muted)] font-mono text-xs">Faithfulness score (0–100)</div>572          <div class="p-4 text-amber-400 font-semibold">LLM API</div>573        </div>574        <div class="grid grid-cols-4 text-sm">575          <div class="p-4 text-[var(--text-main)] font-semibold">Answer Reliability</div>576          <div class="p-4 text-[var(--text-muted)]">LLM-as-Judge</div>577          <div class="p-4 text-[var(--text-muted)] font-mono text-xs">Completeness score (0–100)</div>578          <div class="p-4 text-amber-400 font-semibold">LLM API</div>579        </div>580      </div>581    </div>582 583    <div class="bg-sky-500/5 border border-sky-500/20 rounded-2xl p-6 mb-14">584      <p class="text-sky-400 font-bold text-sm mb-2">🔄 Reproduce These Results</p>585      <p class="text-[var(--text-muted)] text-sm leading-relaxed">586        All metrics are generated by <strong class="text-[var(--text-main)] font-mono">tests/evaluate_quality.py</strong>. Run it against your own data:587      </p>588      <pre class="mt-3"><code class="language-bash">python tests/evaluate_quality.py              # Full run (all 4 metrics)589python tests/evaluate_quality.py --skip-llm    # Embedding metrics only (free)590python tests/evaluate_quality.py --max-queries 3  # Quick test with 3 queries</code></pre>591    </div>592 593    <!-- Pipeline Before After -->594    <h2 class="text-2xl font-bold text-[var(--text-main)] mt-14 mb-2 border-l-4 border-violet-500 pl-3">🔀 Pipeline Before & After</h2>595    <p class="text-[var(--text-muted)] mb-8 text-sm uppercase tracking-wider font-semibold">How the retrieval pipeline changes with optimization</p>596    597    <div class="grid md:grid-cols-2 gap-8 mb-14">598      <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-red-500/20 shadow-[0_4px_30px_rgba(0,0,0,0.02)]">599        <div class="text-xs font-extrabold text-red-500 uppercase tracking-widest mb-6 text-center bg-red-500/10 py-2 rounded-lg">BEFORE — Standard Top-K</div>600        <div class="space-y-4">601          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-red-500/10">1. ❓ User Query</div>602          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>603          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-red-500/10">2. 🔢 Embed Query</div>604          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>605          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-red-500/10">3. 🔎 Cosine Search (top-k=10)</div>606          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>607          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-red-500/10">4. 🔀 BM25 Hybrid Fusion</div>608          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>609          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-red-500/10">5. ⚡ CrossEncoder Rerank</div>610          <div class="text-center text-red-500 text-xl font-black">↓</div>611          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-red-400 bg-red-500/10 border-red-500/30 shadow-xl">6. 🤖 LLM Generates (High Redundancy)</div>612        </div>613      </div>614      <div class="p-6 rounded-2xl bg-[var(--glass-bg)] border border-emerald-500/20 shadow-[0_4px_30px_rgba(0,0,0,0.02)] border-t-4 border-t-emerald-500">615        <div class="text-xs font-extrabold text-emerald-400 uppercase tracking-widest mb-6 text-center bg-emerald-500/10 py-2 rounded-lg">AFTER — Optimized Selection</div>616        <div class="space-y-4">617          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-emerald-500/10">1. ❓ User Query</div>618          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>619          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-emerald-500/10">2. 🔢 Embed Query</div>620          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>621          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-emerald-500/10">3. 🔎 Cosine Search <span class="text-emerald-400">(N=30 pool)</span></div>622          <div class="text-center text-[var(--text-muted)] text-xl font-black">↓</div>623          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-emerald-500/10">4. 🔀 BM25 Hybrid Fusion</div>624          <div class="text-center text-emerald-500 text-xl font-black">↓</div>625          <div class="doc-card py-4 px-4 text-center text-sm font-bold text-emerald-400 bg-emerald-500/10 border-emerald-500/50 scale-105 shadow-[0_0_20px_rgba(16,185,129,0.3)]">5. 🧬 Multi-Objective Optimizer <span class="bg-emerald-500/30 text-white rounded px-2 py-0.5 ml-2 text-[10px]">NEW</span></div>626          <div class="text-center text-emerald-500 text-xl font-black">↓</div>627          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-[var(--text-main)] border-emerald-500/10">6. ⚡ CrossEncoder Rerank Validation</div>628          <div class="text-center text-emerald-500 text-xl font-black">↓</div>629          <div class="doc-card py-3 px-4 text-center text-sm font-bold text-emerald-400 bg-emerald-500/5 border-emerald-500/20 shadow-xl">7. 🤖 LLM Generates (Diverse Coverage)</div>630        </div>631      </div>632    </div>633 634 635    <div class="bg-emerald-500/5 border border-emerald-500/20 rounded-2xl p-8 text-center shadow-[0_4px_40px_rgba(16,185,129,0.05)] mx-auto">636        <p class="text-[var(--text-muted)] font-medium max-w-2xl mx-auto text-sm leading-relaxed mb-4 tracking-widest uppercase">🎯 Optimization Objective</p>637        <div class="inline-block bg-black/30 border border-[var(--glass-border)] shadow-2xl rounded-2xl px-10 py-6 font-mono text-xl font-bold text-[var(--text-main)] mb-4 transition-transform hover:scale-105">638            S* = argmax Σ [ α·Rel(q,dᵢ) + β·C(dᵢ|S) + γ·Sup(dᵢ,S) ]639        </div>640    </div>641  </div>642 643  <script>644    // Tab Switching Logic645    function switchTab(index) {646        // Find all tabs and panels647        const tabs = document.querySelectorAll('.code-tab');648        const panels = document.querySelectorAll('.code-panel');649        650        // Remove active class from all651        tabs.forEach(t => t.classList.remove('active'));652        panels.forEach(p => p.classList.remove('active'));653        654        // Add active class to target655        if(tabs[index]) tabs[index].classList.add('active');656        if(document.getElementById('panel-' + index)) {657            document.getElementById('panel-' + index).classList.add('active');658        }659    }660 661    // PLOTLY JS INTEGRATION662    function renderPlots() {663        const txtColor = '#8a8f98';664        const gridColor = 'rgba(255,255,255,0.04)';665        const bgColor = 'rgba(0,0,0,0)';666        const fontFam = 'Inter, sans-serif';667 668        // Simulated doc relevance scores for visual demonstration669        const n_docs = 15;670        const relevance = [0.95, 0.93, 0.91, 0.90, 0.88, 0.86, 0.84, 0.82, 0.80, 0.78, 0.75, 0.72, 0.70, 0.68, 0.65];671        const xVals = Array.from({length: n_docs}, (_, i) => `D${i+1}`);672        const hoverTemp = "<b>Doc %{x}</b><br>Relevance: %{y:.2f}<extra></extra>";673 674        // === TOP-k CHART ===675        const topk_sel = [0, 1, 2, 3, 4];676        const colors_topk = Array(n_docs).fill('rgba(100,116,139,0.2)');677        const borders_topk = Array(n_docs).fill('rgba(100,116,139,0.15)');678        topk_sel.forEach(i => { colors_topk[i] = 'rgba(239,68,68,0.85)'; borders_topk[i] = '#ef4444'; });679 680        const traceTopk = {681            x: xVals, y: relevance, type: 'bar',682            marker: { color: colors_topk, line: { color: borders_topk, width: 2 } },683            text: relevance.map(v => v.toFixed(2)), textposition: 'outside', textfont: { color: txtColor, size: 10, family: fontFam },684            hovertemplate: hoverTemp685        };686 687        const layoutTopk = {688            title: { text: "❌ Top-K Selection", font: {size: 16, color: '#f87171', family: fontFam} },689            paper_bgcolor: bgColor, plot_bgcolor: bgColor, font: {family: fontFam, color: txtColor, size: 11},690            margin: {l:10, r:10, t:50, b:20}, showlegend: false,691            xaxis: { showgrid: false, tickfont: {size: 10} },692            yaxis: { title: "Relevance Score", gridcolor: gridColor, range: [0, 1.1] },693            annotations: [{ text: "⚠️ Picks top-5 by absolute score — highly redundant clumps", xref: "paper", yref: "paper", x: 0.5, y: -0.15, showarrow: false, font: {size: 11, color: '#f87171'} }]694        };695        Plotly.newPlot('chart-topk', [traceTopk], layoutTopk, {displayModeBar: false, responsive: true});696 697 698        // === OPTIMIZED CHART ===699        const opt_sel = [0, 3, 6, 10, 13];700        const colors_opt = Array(n_docs).fill('rgba(100,116,139,0.2)');701        const borders_opt = Array(n_docs).fill('rgba(100,116,139,0.15)');702        opt_sel.forEach(i => { colors_opt[i] = 'rgba(16,185,129,0.85)'; borders_opt[i] = '#10b981'; });703 704        const traceOpt = {705            x: xVals, y: relevance, type: 'bar',706            marker: { color: colors_opt, line: { color: borders_opt, width: 2 } },707            text: relevance.map(v => v.toFixed(2)), textposition: 'outside', textfont: { color: txtColor, size: 10, family: fontFam },708            hovertemplate: hoverTemp709        };710 711        const layoutOpt = {712            title: { text: "✅ Optimized Selection", font: {size: 16, color: '#34d399', family: fontFam} },713            paper_bgcolor: bgColor, plot_bgcolor: bgColor, font: {family: fontFam, color: txtColor, size: 11},714            margin: {l:10, r:10, t:50, b:20}, showlegend: false,715            xaxis: { showgrid: false, tickfont: {size: 10} },716            yaxis: { title: "Relevance Score", gridcolor: gridColor, range: [0, 1.1] },717            annotations: [{ text: "✔️ Picks 5 spread dynamically — maximizes subset coverage", xref: "paper", yref: "paper", x: 0.5, y: -0.15, showarrow: false, font: {size: 11, color: '#34d399'} }]718        };719        Plotly.newPlot('chart-opt', [traceOpt], layoutOpt, {displayModeBar: false, responsive: true});720 721 722        // === RADAR CHART (Real Measured Data) ===723        const categories = ["Evidence<br>Diversity", "Redundancy<br>Reduction", "Answer<br>Reliability", "Hallucination<br>Resistance"];724        const catsCircular = [...categories, categories[0]];725        const opt_vals = [22.5, 77.5, 63.8, 81.2, 22.5];726        const topk_vals = [19.9, 0, 66.2, 57.0, 19.9];727 728        const polarGridColor = 'rgba(255,255,255,0.06)';729 730        const traceRadarOpt = {731            type: 'scatterpolar', r: opt_vals, theta: catsCircular, fill: 'toself',732            name: 'ContextAware (Optimized)', fillcolor: 'rgba(16,185,129,0.2)',733            line: {color: '#10b981', width: 2.5}, marker: {size: 7, color: '#10b981'}734        };735        const traceRadarTopk = {736            type: 'scatterpolar', r: topk_vals, theta: catsCircular, fill: 'toself',737            name: 'Standard Top-K RAG', fillcolor: 'rgba(100,116,139,0.1)',738            line: {color: '#555', width: 2, dash: 'dash'}, marker: {size: 6, color: '#555'}739        };740 741        const layoutRadar = {742            polar: {743                bgcolor: bgColor,744                radialaxis: { visible: true, range: [0, 100], gridcolor: polarGridColor, tickfont: {color: txtColor, size: 9} },745                angularaxis: { gridcolor: polarGridColor, tickfont: {color: txtColor, size: 11, family: fontFam} },746            },747            paper_bgcolor: bgColor, plot_bgcolor: bgColor, font: {family: fontFam, color: txtColor},748            margin: {l:50, r:50, t:30, b:60},749            legend: { orientation: "h", y: -0.15, font: {size: 11} }750        };751        Plotly.newPlot('chart-radar', [traceRadarOpt, traceRadarTopk], layoutRadar, {displayModeBar: false, responsive: true});752 753 754        // === PER-QUERY RESULTS CHART (Real Evaluation Data) ===755        const queryLabels = ['Q1: LLM<br>Hallucinations', 'Q2: Dense vs<br>Sparse', 'Q3: Chunking<br>Strategy', 'Q4: RAG<br>Evaluation', 'Q5: Vector<br>Databases', 'Q6: Reranking<br>Role', 'Q7: Embedding<br>Models', 'Q8: Context<br>Window'];756        const topkDiversity = [19.5, 20.9, 19.2, 18.4, 18.5, 20.9, 22.6, 19.3];757        const optDiversity =  [22.6, 22.6, 21.2, 21.4, 23.7, 22.1, 24.1, 22.8];758        const redReduction =  [66.7, 100,  25.0, 92.9, 90.0, 87.5, 80.0, 77.8];759 760        const traceTopkDiv = {761            x: queryLabels, y: topkDiversity, type: 'bar', name: 'Top-K Diversity',762            marker: { color: 'rgba(239,68,68,0.7)' },763            hovertemplate: '<b>%{x}</b><br>Top-K Diversity: %{y:.1f}%<extra></extra>'764        };765        const traceOptDiv = {766            x: queryLabels, y: optDiversity, type: 'bar', name: 'Optimized Diversity',767            marker: { color: 'rgba(16,185,129,0.8)' },768            hovertemplate: '<b>%{x}</b><br>Optimized Diversity: %{y:.1f}%<extra></extra>'769        };770        const traceRedLine = {771            x: queryLabels, y: redReduction, type: 'scatter', mode: 'lines+markers',772            name: 'Redundancy Reduction %', yaxis: 'y2',773            line: { color: '#f59e0b', width: 3 }, marker: { size: 8, color: '#f59e0b' },774            hovertemplate: '<b>%{x}</b><br>Redundancy Reduction: %{y:.1f}%<extra></extra>'775        };776 777        const layoutPerQuery = {778            title: { text: '📊 Per-Query Evaluation Results (Real Data)', font: { size: 16, color: txtColor, family: fontFam } },779            paper_bgcolor: bgColor, plot_bgcolor: bgColor, font: { family: fontFam, color: txtColor, size: 11 },780            barmode: 'group', bargap: 0.2, bargroupgap: 0.1,781            margin: { l: 50, r: 50, t: 50, b: 80 },782            xaxis: { tickfont: { size: 9 }, showgrid: false },783            yaxis: { title: 'Diversity %', gridcolor: gridColor, range: [0, 35] },784            yaxis2: { title: 'Redundancy Reduction %', overlaying: 'y', side: 'right', range: [0, 110], gridcolor: 'transparent' },785            legend: { orientation: 'h', y: -0.25, font: { size: 10 } },786        };787        Plotly.newPlot('chart-perquery', [traceTopkDiv, traceOptDiv, traceRedLine], layoutPerQuery, { displayModeBar: false, responsive: true });788    }789 790    // Initial render791    setTimeout(renderPlots, 100);792 793  </script>794 795  <!-- Particle Animation -->796  <script>797  (function() {798    const canvas = document.getElementById('particleCanvas');799    const ctx = canvas.getContext('2d');800    let particles = [];801    const N = 45, D = 100;802    function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }803    resize(); window.addEventListener('resize', resize);804    class P { constructor() { this.x=Math.random()*canvas.width; this.y=Math.random()*canvas.height; this.vx=(Math.random()-0.5)*0.2; this.vy=(Math.random()-0.5)*0.2; this.r=Math.random()*1.2+0.3; this.o=Math.random()*0.2+0.05; } update() { this.x+=this.vx; this.y+=this.vy; if(this.x<0||this.x>canvas.width)this.vx*=-1; if(this.y<0||this.y>canvas.height)this.vy*=-1; } draw() { ctx.beginPath(); ctx.arc(this.x,this.y,this.r,0,Math.PI*2); ctx.fillStyle=`rgba(0,229,255,${this.o})`; ctx.fill(); } }805    for(let i=0;i<N;i++) particles.push(new P());806    function anim() { ctx.clearRect(0,0,canvas.width,canvas.height); for(let i=0;i<particles.length;i++){particles[i].update();particles[i].draw();for(let j=i+1;j<particles.length;j++){const dx=particles[i].x-particles[j].x,dy=particles[i].y-particles[j].y,d=Math.sqrt(dx*dx+dy*dy);if(d<D){ctx.beginPath();ctx.moveTo(particles[i].x,particles[i].y);ctx.lineTo(particles[j].x,particles[j].y);ctx.strokeStyle=`rgba(0,229,255,${(1-d/D)*0.05})`;ctx.lineWidth=0.5;ctx.stroke();}}} requestAnimationFrame(anim); }807    anim();808  })();809  </script>810</body>811</html>812