<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Salmon Joy</title>
    <description>The latest articles on DEV Community by Salmon Joy (@salmonjoy).</description>
    <link>https://dev.to/salmonjoy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4166308%2Fa607206d-8f31-4a30-a0de-630ec1ef677c.png</url>
      <title>DEV Community: Salmon Joy</title>
      <link>https://dev.to/salmonjoy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salmonjoy"/>
    <language>en</language>
    <item>
      <title>Multi-hop retrieval</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Mon, 26 Oct 2026 04:54:32 +0000</pubDate>
      <link>https://dev.to/salmonjoy/multi-hop-retrieval-3l4a</link>
      <guid>https://dev.to/salmonjoy/multi-hop-retrieval-3l4a</guid>
      <description>&lt;h1&gt;
  
  
  Multi‑hop Retrieval for Enterprise Knowledge‑Driven Q&amp;amp;A
&lt;/h1&gt;

&lt;h2&gt;
  
  
  📋 Concise Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Typical Cause&lt;/th&gt;
&lt;th&gt;Immediate Remedy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Answer stops after a single paragraph&lt;/td&gt;
&lt;td&gt;Query spans multiple knowledge islands; single‑vector lookup returns only the first island&lt;/td&gt;
&lt;td&gt;Decompose into sub‑questions and chain retrieval hops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stale regulatory numbers appear in the response&lt;/td&gt;
&lt;td&gt;Context window contains cached documents, but the live value is governed by an external API&lt;/td&gt;
&lt;td&gt;Add a “live‑value” hop that calls the authoritative service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency spikes when depth &amp;gt; 3&lt;/td&gt;
&lt;td&gt;Each hop launches a separate retrieval round; network and model inference accumulate&lt;/td&gt;
&lt;td&gt;Profile per‑hop latency, enforce a cumulative budget, and consider early‑stop criteria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business rule is violated despite correct evidence&lt;/td&gt;
&lt;td&gt;Rule logic lives in deterministic code, but the LLM is asked to “reason” about it&lt;/td&gt;
&lt;td&gt;Encode the rule as executable Python (or a policy engine) and feed its result as a system prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  ⏩ Decision Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Receive user question"]
    B["Parse &amp;amp; Detect Multi‑hop Need"]
    C["Generate First Sub‑query"]
    D["Retrieve Evidence #1"]
    E["Run Deterministic Rule #1"]
    F["Iterate to Next Sub‑query"]
    G["Assemble Final Answer"]
    H["Return to User"]
    A --&amp;gt; B
    B --&amp;gt; C
    C --&amp;gt; D
    D --&amp;gt; E
    E --&amp;gt; F
    F --&amp;gt; D
    F --&amp;gt; G
    G --&amp;gt; H
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagram shows a single loop for readability; real deployments may iterate up to a configured depth limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  📐 Architecture &amp;amp; Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Core Responsibility&lt;/th&gt;
&lt;th&gt;Owner (Typical)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Front‑end API&lt;/td&gt;
&lt;td&gt;Accepts raw user query, returns streamed answer&lt;/td&gt;
&lt;td&gt;Product / Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Question Analyzer&lt;/td&gt;
&lt;td&gt;Detects whether the query requires multi‑hop processing (e.g., multiple entities, conditional clauses)&lt;/td&gt;
&lt;td&gt;NLP Engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub‑query Generator&lt;/td&gt;
&lt;td&gt;Emits a focused retrieval prompt for each hop (e.g., “What is the Basel III definition of capital requirement?”)&lt;/td&gt;
&lt;td&gt;Prompt Engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retriever&lt;/td&gt;
&lt;td&gt;Executes a vector or keyword search against the enterprise corpus; returns ranked passages&lt;/td&gt;
&lt;td&gt;Retrieval Team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence Chainer&lt;/td&gt;
&lt;td&gt;Persists retrieved passages, deduplicates, orders them, and makes them available to subsequent hops&lt;/td&gt;
&lt;td&gt;Knowledge Engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rule Engine&lt;/td&gt;
&lt;td&gt;Executes deterministic business rules or policy checks (e.g., “capital requirement must be ≥ 8 %”)&lt;/td&gt;
&lt;td&gt;Compliance / Engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live‑Value Adapter&lt;/td&gt;
&lt;td&gt;Calls external authoritative APIs for up‑to‑date numeric values (e.g., latest stress‑test factor)&lt;/td&gt;
&lt;td&gt;Integration Team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response Composer&lt;/td&gt;
&lt;td&gt;Merges chained evidence, rule outcomes, and live values into a coherent natural‑language answer; enforces stop‑criteria&lt;/td&gt;
&lt;td&gt;LLM Ops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring &amp;amp; Guardrails&lt;/td&gt;
&lt;td&gt;Tracks per‑hop latency, token usage, and compliance violations; triggers fallback if limits exceeded&lt;/td&gt;
&lt;td&gt;SRE / Observability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🧑‍💻 Teaching‑Only Python Helper (Standard Library Only)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# teaching-only: helper that decides whether to continue hopping
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;

&lt;span class="n"&gt;MAX_HOPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;           &lt;span class="c1"&gt;# illustrative ceiling; adjust per business policy
&lt;/span&gt;&lt;span class="n"&gt;MAX_LATENCY_SEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;   &lt;span class="c1"&gt;# illustrative cumulative budget; adjust per SLA
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_continue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;hop_counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;elapsed_sec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Decide if another retrieval hop is allowed.

    Parameters
    ----------
    hop_counter: int
        Number of hops already executed.
    elapsed_sec: float
        Total wall‑clock time spent on previous hops.
    evidence: List[Tuple[str, float]]
        List of (doc_id, relevance_score) collected so far.

    Returns
    -------
    bool
        True → launch next hop; False → stop and compose answer.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Hard stop on depth
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;hop_counter&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hop_counter cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hop_counter&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_HOPS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Hard stop on latency
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;elapsed_sec&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elapsed time cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elapsed_sec&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_LATENCY_SEC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Soft stop: diminishing returns (example heuristic)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# compare last two relevance scores
&lt;/span&gt;        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# stop if improvement is negligible
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_score&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;prev_score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📚 Illustrative Architectural Decision Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 1 – Choice of Retrieval Backend
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Enterprise knowledge bases are stored in heterogeneous formats (PDF, Confluence, relational tables). The team evaluated pure dense‑vector search (FAISS) versus a hybrid dense + BM25 approach (Elastic) for the first hop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Adopt a hybrid backend that first filters with BM25 on metadata (document type, confidentiality label) and then re‑ranks with dense embeddings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improves recall for sparse regulatory terms that dense models under‑represent.
&lt;/li&gt;
&lt;li&gt;Adds modest per‑hop latency due to the two‑stage pipeline; this overhead is acceptable because early hops dominate the overall latency budget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria (illustrative)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The hybrid approach must demonstrably increase recall on the internal compliance benchmark.
&lt;/li&gt;
&lt;li&gt;Per‑hop latency should remain within the organization’s acceptable latency budget as measured on a production‑size index.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ADR 2 – Handling Live Numerical Values
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Regulatory answers often need the most recent numeric factor (e.g., “latest stress‑test multiplier”). Storing such numbers in the vector store quickly becomes stale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Introduce a dedicated &lt;strong&gt;Live‑Value Adapter&lt;/strong&gt; that detects sub‑queries matching the pattern &lt;code&gt;latest *&lt;/code&gt; and triggers an HTTP call to the official regulator API. The retrieved value replaces any cached occurrence before answer composition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guarantees freshness for regulated numbers, satisfying audit requirements.
&lt;/li&gt;
&lt;li&gt;Adds external‑service latency; a circuit‑breaker will abort the live call after a short timeout and fall back to the most recent cached value with a “⚠️ may be outdated” flag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria (illustrative)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The live‑value path must return values that match the regulator API in the overwhelming majority of cases.
&lt;/li&gt;
&lt;li&gt;The fallback flag should appear only when the live call fails, and such failures should be rare enough to meet compliance expectations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✅ Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;✅ Item&lt;/th&gt;
&lt;th&gt;How to Verify&lt;/th&gt;
&lt;th&gt;Frequency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Depth‑Latency Trade‑off – cumulative latency respects SLA&lt;/td&gt;
&lt;td&gt;Automated load test that exercises the max‑depth path and records end‑to‑end time&lt;/td&gt;
&lt;td&gt;CI on every code merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evidence Freshness – no stale regulatory doc beyond an acceptable age&lt;/td&gt;
&lt;td&gt;Compare timestamps of retrieved passages against source metadata&lt;/td&gt;
&lt;td&gt;Weekly audit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rule Engine Correctness – deterministic outputs for known inputs&lt;/td&gt;
&lt;td&gt;Unit tests with exhaustive edge cases (e.g., capital = 7 % should be rejected)&lt;/td&gt;
&lt;td&gt;Nightly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live‑Value Success Rate – high success ratio for API calls&lt;/td&gt;
&lt;td&gt;Monitoring of HTTP 200 counters vs. total live‑value attempts&lt;/td&gt;
&lt;td&gt;Real‑time alert on sustained degradation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval Recall – meets internal benchmark expectations&lt;/td&gt;
&lt;td&gt;Run the benchmark suite after any index rebuild or embedding model change&lt;/td&gt;
&lt;td&gt;Per index refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security / Permissions – each hop respects document ACLs&lt;/td&gt;
&lt;td&gt;Integration test that simulates a user lacking access to a confidential doc&lt;/td&gt;
&lt;td&gt;Monthly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model Hallucination Guardrail – answer always cites at least one retrieved passage&lt;/td&gt;
&lt;td&gt;Regex check that every answer contains a citation marker (e.g., &lt;code&gt;[DocID]&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation Sync – ADRs, architecture diagram, and config files are version‑controlled&lt;/td&gt;
&lt;td&gt;Repo scan for drift between &lt;code&gt;architecture.md&lt;/code&gt; and actual code constants&lt;/td&gt;
&lt;td&gt;Every release&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  📖 References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Microsoft RAG concepts – Azure Foundry documentation on Retrieval‑Augmented Generation&lt;br&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LoRA: Low‑Rank Adaptation of Large Language Models – original paper introducing parameter‑efficient fine‑tuning&lt;br&gt;&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Query rewriting and HyDE</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Sun, 25 Oct 2026 04:54:31 +0000</pubDate>
      <link>https://dev.to/salmonjoy/query-rewriting-and-hyde-405n</link>
      <guid>https://dev.to/salmonjoy/query-rewriting-and-hyde-405n</guid>
      <description>&lt;h1&gt;
  
  
  Query Rewriting &amp;amp; HyDE in Retrieval‑Augmented Generation
&lt;/h1&gt;




&lt;h2&gt;
  
  
  Diagnosis Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Root Cause&lt;/th&gt;
&lt;th&gt;Immediate Mitigation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Low relevance but correct intent&lt;/td&gt;
&lt;td&gt;Query too terse or uses domain jargon unknown to the retriever&lt;/td&gt;
&lt;td&gt;Run an &lt;strong&gt;Intent Analyzer&lt;/strong&gt; and consider a safe rewrite (add missing qualifiers).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High relevance, unintended facts&lt;/td&gt;
&lt;td&gt;HyDE synthetic document mismatches real sources&lt;/td&gt;
&lt;td&gt;Verify HyDE output against a deterministic &lt;strong&gt;Live‑Value Resolver&lt;/strong&gt; before composition.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance flags on answer&lt;/td&gt;
&lt;td&gt;Original query contains regulated entities (e.g., ticker symbols) that were altered&lt;/td&gt;
&lt;td&gt;Preserve the exact token sequence; skip rewrite and apply rule‑based guardrails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sudden latency spikes&lt;/td&gt;
&lt;td&gt;Both rewrite and HyDE pipelines fire for every request&lt;/td&gt;
&lt;td&gt;Add a &lt;strong&gt;Decision Helper&lt;/strong&gt; that selects a single strategy per query.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated hallucinations on numeric topics&lt;/td&gt;
&lt;td&gt;Retrieval fell back to stale cache instead of live API&lt;/td&gt;
&lt;td&gt;Route numeric sub‑queries to an authoritative tool/API.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Decision Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["User query"] --&amp;gt; B["Is query domain‑critical (e.g., regulator‑required tokens)?"]
    B --&amp;gt;|yes| C["Keep original, enforce guardrails"]
    B --&amp;gt;|no| D["Is intent confidence high?"]
    D --&amp;gt;|yes| E["Use original query for retrieval"]
    D --&amp;gt;|no| F["Can a safe rewrite be generated?"]
    F --&amp;gt;|yes| G["Rewrite + retrieve"]
    F --&amp;gt;|no| H["Generate HyDE document, then retrieve"]
    C --&amp;gt; I["Retrieve + compose answer"]
    E --&amp;gt; I
    G --&amp;gt; I
    H --&amp;gt; I
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Architecture &amp;amp; Responsibilities
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Primary Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Input Handler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Normalise Unicode, enforce length limits, flag regulated identifiers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intent Analyzer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Produce a confidence indicator using a frozen‑base LLM; does not modify model weights.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rewriter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generates a longer, context‑rich query while preserving identified regulated tokens.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HyDE Generator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Constructs a short answer, embeds it as a synthetic document, and returns the embedding to the Retriever.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retriever&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performs dense/sparse search over the knowledge base; falls back to vector store if lexical match fails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live‑Value Resolver&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Calls authoritative APIs (e.g., market data) for any numeric entity detected after retrieval.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Answer Composer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Merges retrieved passages, HyDE‑generated text, and live values; applies a template that inserts guardrail checks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Guardrails (Business Rules Engine)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes deterministic code that validates compliance, rate limits, and forbidden content before the final answer is emitted.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitoring &amp;amp; Logging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Captures latency, cost, intent‑drift metrics, and flags hallucinations for human review.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Decision Helper (Python – standard library only)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# teaching‑only
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_strategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rewrite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hyde&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Choose a retrieval‑augmentation strategy.

    Rules
    -----
    1. Non‑empty, printable ASCII required.
    2. If a regulated token (ticker, SSN, etc.) is present → keep original.
    3. If the Intent Analyzer would likely indicate high confidence → original.
    4. Otherwise, attempt a safe rewrite; if rewriting fails → HyDE.

    The function never contacts external services; it only analyses the string.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. basic validation
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query must be non‑empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nf"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;126&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query must be printable ASCII&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. detect regulated tokens (very simple regex for illustration)
&lt;/span&gt;    &lt;span class="n"&gt;regulated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b([A-Z]{1,4}\d{0,2})\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# e.g., ticker XYZ or XYZ12
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;regulated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. mock intent confidence (placeholder – real system uses a frozen LLM)
&lt;/span&gt;    &lt;span class="c1"&gt;#    Here we treat the presence of a question mark as a proxy for lower confidence.
&lt;/span&gt;    &lt;span class="n"&gt;high_confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;high_confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. safe rewrite feasibility (e.g., length &amp;gt; 5 words → likely expandable)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rewrite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. fallback
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hyde&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ADR 1 – When to Apply Query Rewriting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
User queries often omit qualifiers that are essential for downstream compliance (e.g., “stock ticker XYZ price” must stay literal, while “latest mortgage rates” benefits from added temporal scope).  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Apply a &lt;em&gt;safe rewrite&lt;/em&gt; only when:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No regulated tokens are detected.
&lt;/li&gt;
&lt;li&gt;The Intent Analyzer suggests low confidence &lt;strong&gt;and&lt;/strong&gt; the query is long enough to allow meaningful expansion.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Positive&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Broader lexical match improves recall.
&lt;/li&gt;
&lt;li&gt;Enables downstream retrieval of related contextual information without manual prompt engineering.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Negative&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Potential intent drift if the rewrite injects assumptions (e.g., adding “30‑day” when the user asked for “today”).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demonstrated improvement in relevance metrics on a held‑out test set compared with the original‑only pipeline.
&lt;/li&gt;
&lt;li&gt;Human reviewers confirm that rewritten queries retain the original intent in the majority of cases.
&lt;/li&gt;
&lt;li&gt;Measured latency remains within the operational budget for the deployment environment.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ADR 2 – When to Use HyDE
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Certain domains (legal, medical, fintech) contain concise factual answers that are rarely present verbatim in the corpus, but a short synthetic answer can act as a strong anchor for retrieval.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Trigger HyDE when:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Intent Analyzer indicates low confidence &lt;strong&gt;and&lt;/strong&gt; the query is a brief factual request (single sentence, limited token count).
&lt;/li&gt;
&lt;li&gt;No regulated tokens are present.
&lt;/li&gt;
&lt;li&gt;Retrieval on the original query returns an insufficient number of high‑scoring candidates.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Positive&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synthetic document provides a dense embedding that bridges phrasing gaps.
&lt;/li&gt;
&lt;li&gt;Early relevance boost without additional external calls.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Negative&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generated text may hallucinate unsupported facts, increasing reliance on the Guardrails engine.
&lt;/li&gt;
&lt;li&gt;Additional CPU cycles for the HyDE LLM, though limited to a single forward pass on a frozen model.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relevance metrics (e.g., nDCG) show a measurable lift for HyDE‑enabled queries relative to a baseline without HyDE.
&lt;/li&gt;
&lt;li&gt;Post‑guardrail factual error rate, as verified by human auditors, remains acceptably low.
&lt;/li&gt;
&lt;li&gt;Overall system latency for the HyDE path does not exceed the limits appropriate for the target user experience.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Unit Tests&lt;/strong&gt; for &lt;code&gt;decide_strategy&lt;/code&gt; covering regulated token detection, confidence branches, rewrite eligibility, and HyDE fallback.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Integration Tests&lt;/strong&gt; that mock the Intent Analyzer and verify the correct pipeline branch executes.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Regression Suite&lt;/strong&gt;: run relevance benchmarks on a stable validation set after any LoRA update.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Compliance Audits&lt;/strong&gt;: automatically validate that every answer containing regulated identifiers passed through the Guardrails engine.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Live‑Value Validation&lt;/strong&gt;: for all numeric sub‑queries, confirm that values originate from authorized APIs (e.g., Bloomberg, Federal Reserve).
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Latency Monitoring&lt;/strong&gt;: record per‑stage latency; raise alerts if any stage exceeds the service‑level objective defined for the deployment.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Cost Tracking&lt;/strong&gt;: aggregate token usage per strategy and ensure it stays within allocated budgets.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Model Drift Review&lt;/strong&gt;: periodically compare intent confidence distributions with the latest data; adjust thresholds only after a documented evaluation.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft RAG concepts – &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LoRA: Low‑Rank Adaptation of Large Language Models – &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Two-stage retrieval and reranking</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Thu, 22 Oct 2026 04:54:29 +0000</pubDate>
      <link>https://dev.to/salmonjoy/two-stage-retrieval-and-reranking-4opa</link>
      <guid>https://dev.to/salmonjoy/two-stage-retrieval-and-reranking-4opa</guid>
      <description>&lt;h1&gt;
  
  
  Two‑Stage Retrieval &amp;amp; Reranking: A Technical Guide
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Recall first, precision second. This guide explains how to separate candidate generation from relevance refinement, how to tune the funnel, and which metrics keep the system both fast and trustworthy.&lt;/em&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  📋 Concise Diagnosis Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Root Cause&lt;/th&gt;
&lt;th&gt;First‑Stage Check&lt;/th&gt;
&lt;th&gt;Second‑Stage Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Low answer relevance (many off‑topic sentences)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Top‑N too small&lt;/strong&gt; → insufficient recall&lt;/td&gt;
&lt;td&gt;Verify vector index recall on a held‑out query set&lt;/td&gt;
&lt;td&gt;Confirm reranker model is loaded and scoring correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High latency (≈ 2 s)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Top‑N too large&lt;/strong&gt; or &lt;strong&gt;expensive reranker&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Measure index latency per query (ms)&lt;/td&gt;
&lt;td&gt;Profile reranker inference time per candidate (ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt token budget exceeded (≈ 1 500)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Top‑k too high&lt;/strong&gt; → too many tokens passed to generator&lt;/td&gt;
&lt;td&gt;Count tokens returned from index (sum of passage lengths)&lt;/td&gt;
&lt;td&gt;Count tokens after reranker cut‑off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missed regulatory clause (false‑negative)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Recall gap&lt;/strong&gt; – missing relevant doc in index&lt;/td&gt;
&lt;td&gt;Run BM25 / dense recall test against known clause IDs&lt;/td&gt;
&lt;td&gt;Ensure reranker does not drop the clause by rank&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧭 Decision Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Start: User Query"]
    B["Dense / BM25 Search → Top‑N"]
    C["Apply Filters (date, jurisdiction)"]
    D["Reranker LLM scores candidates"]
    E["Select Top‑k"]
    F["Assemble Prompt for Generator"]
    G["Generate Answer"]
    H["Return to User"]
    A --&amp;gt; B
    B --&amp;gt; C
    C --&amp;gt; D
    D --&amp;gt; E
    E --&amp;gt; F
    F --&amp;gt; G
    G --&amp;gt; H
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🏗️ Architecture &amp;amp; Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Primary Responsibility&lt;/th&gt;
&lt;th&gt;Deterministic Business Rule&lt;/th&gt;
&lt;th&gt;Typical Latency Target*&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Index Service&lt;/strong&gt; (e.g., Pinecone, Elasticsearch)&lt;/td&gt;
&lt;td&gt;Retrieve up to &lt;strong&gt;Top‑N&lt;/strong&gt; document chunks via vector similarity or BM25&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;query.metadata.source == "authoritative"&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; restrict to indices flagged &lt;code&gt;authoritative == true&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;≤ 150 ms per query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filter Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enforce compliance filters (date, jurisdiction, confidentiality)&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;doc.date &amp;lt; policy.effective_date&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; drop the document&lt;/td&gt;
&lt;td&gt;≤ 30 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Reranker&lt;/strong&gt; (LLM inference with a lightweight prompt)&lt;/td&gt;
&lt;td&gt;Score the &lt;strong&gt;Top‑N&lt;/strong&gt; candidates and produce a ranking&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;score &amp;lt; rerank.threshold&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; discard before Top‑k selection&lt;/td&gt;
&lt;td&gt;≤ 300 ms for N = 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompt Assembler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Concatenate selected &lt;strong&gt;Top‑k&lt;/strong&gt; snippets, add system prompt, enforce token budget&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;total_tokens &amp;gt; max_prompt_tokens&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; truncate lowest‑ranked snippets&lt;/td&gt;
&lt;td&gt;≤ 20 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Generator&lt;/strong&gt; (chat‑style LLM)&lt;/td&gt;
&lt;td&gt;Produce the final answer using the assembled prompt&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;generated_text&lt;/code&gt; contains any &lt;code&gt;disallowed_terms&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; flag for human review&lt;/td&gt;
&lt;td&gt;≤ 800 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitoring &amp;amp; Logging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Capture recall, precision, latency, token counts per request&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;If&lt;/em&gt; &lt;code&gt;latency &amp;gt; SLA.latency&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;precision &amp;lt; SLA.precision&lt;/code&gt; &lt;em&gt;then&lt;/em&gt; raise an alert&lt;/td&gt;
&lt;td&gt;Real‑time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Latency targets are illustrative; actual Service‑Level Agreements must be defined per deployment.  &lt;/p&gt;




&lt;h2&gt;
  
  
  🐍 Teaching‑Only Python Helper
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# teaching-only: helper to decide top‑N / top‑k based on policy constants
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;

&lt;span class="c1"&gt;# ---- Configuration (replace with env‑vars or config files in production) ----
&lt;/span&gt;&lt;span class="n"&gt;MAX_PROMPT_TOKENS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;          &lt;span class="c1"&gt;# hard limit for downstream generator
&lt;/span&gt;&lt;span class="n"&gt;MAX_LATENCY_MS&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;          &lt;span class="c1"&gt;# end‑to‑end budget
&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_TOP_N&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_TOP_K&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_funnel_sizes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;estimated_index_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;estimated_rerank_latency_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Return (top_n, top_k) that respects MAX_PROMPT_TOKENS and MAX_LATENCY_MS.
    Assertions guarantee deterministic behaviour for unit testing.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# 1️⃣ Start with defaults
&lt;/span&gt;    &lt;span class="n"&gt;top_n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_TOP_N&lt;/span&gt;
    &lt;span class="n"&gt;top_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_TOP_K&lt;/span&gt;

    &lt;span class="c1"&gt;# 2️⃣ Adjust top_n if the token budget would be exceeded even before reranking
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;estimated_index_tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_PROMPT_TOKENS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Reduce the pool size proportionally, but never below 1
&lt;/span&gt;        &lt;span class="n"&gt;top_n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MAX_PROMPT_TOKENS&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;estimated_index_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3️⃣ Adjust top_k to keep the final prompt under the token limit
&lt;/span&gt;    &lt;span class="c1"&gt;#    Assume an average snippet length of 200 tokens (empirical, not arbitrary)
&lt;/span&gt;    &lt;span class="n"&gt;avg_snippet_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="n"&gt;max_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_PROMPT_TOKENS&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;avg_snippet_len&lt;/span&gt;
    &lt;span class="n"&gt;top_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4️⃣ Ensure the overall latency budget is not violated
&lt;/span&gt;    &lt;span class="c1"&gt;#    +500 ms is a placeholder for generator inference; replace with real estimate in production
&lt;/span&gt;    &lt;span class="n"&gt;total_latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;estimated_rerank_latency_ms&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;total_latency&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_LATENCY_MS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Latency &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_latency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ms exceeds budget &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MAX_LATENCY_MS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 5️⃣ Return a deterministic tuple
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;

&lt;span class="c1"&gt;# Example (for notebooks or documentation):
# top_n, top_k = decide_funnel_sizes(estimated_index_tokens=1200,
#                                   estimated_rerank_latency_ms=250)
# print(top_n, top_k)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📜 Architectural Decision Records (ADRs)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 1 – Choosing a Dense Vector Index
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;The corpus contains roughly twelve thousand compliance paragraphs. Queries are frequently phrased in natural language, requiring semantic matching.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decision&lt;/td&gt;
&lt;td&gt;Adopt a dense vector index (e.g., Pinecone) as the primary &lt;strong&gt;first‑stage&lt;/strong&gt; retriever, supplemented by BM25 as a fallback for exact phrase matches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternatives&lt;/td&gt;
&lt;td&gt;1. Pure BM25 – deterministic but limited semantic recall.&lt;br&gt;2. Hybrid (BM25 + dense) – higher engineering cost.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consequences&lt;/td&gt;
&lt;td&gt;Improves recall for paraphrased regulatory language, but introduces vector‑search latency that must be monitored.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acceptance Criteria&lt;/td&gt;
&lt;td&gt;Target recall on a held‑out set of 200 clause queries ≥ 0.85 &lt;strong&gt;and&lt;/strong&gt; 95th‑percentile latency ≤ 150 ms on the target hardware.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  ADR 2 – Reranker Scoring Threshold
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;The reranker LLM returns a raw relevance score in the range [0, 1]. Some low‑scoring candidates may still contain useful context.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decision&lt;/td&gt;
&lt;td&gt;Introduce a configurable &lt;strong&gt;rerank.threshold&lt;/strong&gt; (default 0.60). Candidates scoring below the threshold are discarded before Top‑k selection.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternatives&lt;/td&gt;
&lt;td&gt;1. Fixed Top‑k without a score filter – risk of low‑quality snippets.&lt;br&gt;2. Dynamic, per‑query thresholds – adds complexity and non‑determinism.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consequences&lt;/td&gt;
&lt;td&gt;Guarantees a minimum relevance baseline, reduces token waste, and keeps reranker latency predictable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acceptance Criteria&lt;/td&gt;
&lt;td&gt;Target Precision@k (k = 5) on a validation set ≥ 0.78 &lt;strong&gt;and&lt;/strong&gt; token count reduction relative to raw Top‑N ≥ 30 %. The threshold may be tuned but must stay ≥ 0.55 to satisfy the precision target.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ✅ Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recall Test&lt;/strong&gt;: Run a quarterly BM25 + dense recall benchmark on a labelled query set (≥ 200 samples). Record the percentage of known relevant passages retrieved in Top‑N.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precision Test&lt;/strong&gt;: After reranking, compute Precision@k (k = 5, 10) on the same set. Verify against the targets in ADR 2.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency SLA&lt;/strong&gt;: Measure end‑to‑end latency (index → rerank → generator) under a representative load (≥ 100 QPS). Alert if the 95th‑percentile exceeds &lt;code&gt;MAX_LATENCY_MS&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Budget Audits&lt;/strong&gt;: Log &lt;code&gt;prompt_tokens_before&lt;/code&gt; and &lt;code&gt;prompt_tokens_after&lt;/code&gt;. Ensure average reduction meets the &amp;gt; 20 % target.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance Filter Validation&lt;/strong&gt;: Unit‑test all deterministic filter rules (date, jurisdiction, confidentiality) with a deterministic test harness; any failure must block deployment.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Drift Monitoring&lt;/strong&gt;: Track hallucination rate using a synthetic fact‑checking prompt. If the rate rises above 5 %, trigger a prompt‑engineering review (do &lt;strong&gt;not&lt;/strong&gt; automatically fine‑tune).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Sync&lt;/strong&gt;: Verify that any change to &lt;code&gt;MAX_PROMPT_TOKENS&lt;/code&gt;, &lt;code&gt;MAX_LATENCY_MS&lt;/code&gt;, or &lt;code&gt;rerank.threshold&lt;/code&gt; is reflected in this guide and the corresponding ADRs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup &amp;amp; Rollback&lt;/strong&gt;: Archive the exact vector index snapshot and reranker prompt version used for each production release. Enable deterministic rollback if a new release violates any acceptance criterion.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft RAG concepts&lt;/strong&gt; – Azure Foundry documentation: &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LoRA: Low‑Rank Adaptation of Large Language Models&lt;/strong&gt; – research paper: &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(The LoRA paper is cited for understanding lightweight adaptation; it is not the original RAG publication.)&lt;/em&gt;  &lt;/p&gt;




&lt;h3&gt;
  
  
  Editorial Note
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A symptom listed in the diagnosis table is a hypothesis, not proof of the root cause.
&lt;/li&gt;
&lt;li&gt;RAG does &lt;strong&gt;not&lt;/strong&gt; guarantee factual accuracy, instant compliance, or complete coverage; deterministic business rules and live‑value APIs must be used where up‑to‑date facts are required.
&lt;/li&gt;
&lt;li&gt;LoRA updates freeze the base model weights and add low‑rank matrices; they do &lt;strong&gt;not&lt;/strong&gt; inherently preserve all original behaviours—regression testing remains essential.
&lt;/li&gt;
&lt;li&gt;When a request requires a live value (e.g., a current market price), retrieve it from an authoritative API rather than a cached document.
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;End of guide.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Hybrid search: lexical + vector</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Wed, 21 Oct 2026 04:54:39 +0000</pubDate>
      <link>https://dev.to/salmonjoy/hybrid-search-lexical-vector-55li</link>
      <guid>https://dev.to/salmonjoy/hybrid-search-lexical-vector-55li</guid>
      <description>&lt;h1&gt;
  
  
  Hybrid Search in Enterprise Retrieval: Lexical + Vector Fusion
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Quick Diagnosis
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Root Cause&lt;/th&gt;
&lt;th&gt;Lexical (BM25) Impact&lt;/th&gt;
&lt;th&gt;Dense Vector Impact&lt;/th&gt;
&lt;th&gt;Immediate Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Exact phrase returns no hit&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Query terms missing in index or stop‑word removal&lt;/td&gt;
&lt;td&gt;Low recall – exact match fails&lt;/td&gt;
&lt;td&gt;Irrelevant – semantic similarity may surface loosely related docs&lt;/td&gt;
&lt;td&gt;Verify analyzer pipeline, re‑index with phrase‑aware tokenizer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Relevant documents missing despite synonyms&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Vocabulary mismatch, no semantic layer&lt;/td&gt;
&lt;td&gt;Zero score (no token overlap)&lt;/td&gt;
&lt;td&gt;May retrieve but low rank if weight is too low&lt;/td&gt;
&lt;td&gt;Increase vector weight or add synonym expansion to index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Legal compliance audit returns extra unrelated hits&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Over‑aggressive vector weighting&lt;/td&gt;
&lt;td&gt;Still deterministic for exact hits&lt;/td&gt;
&lt;td&gt;Introduces noise&lt;/td&gt;
&lt;td&gt;Reduce vector contribution, add stricter metadata filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Entity identifiers (e.g., “ACC‑12345”) are not boosted&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;No entity‑aware boosting rule&lt;/td&gt;
&lt;td&gt;Matches exact token, but lower than surrounding text&lt;/td&gt;
&lt;td&gt;Vector similarity may ignore numeric patterns&lt;/td&gt;
&lt;td&gt;Add entity boost factor in scoring function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Search latency spikes after hybrid enablement&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Unoptimized fusion step or large candidate set&lt;/td&gt;
&lt;td&gt;Fast BM25 lookup&lt;/td&gt;
&lt;td&gt;Cosine similarity on many vectors is expensive&lt;/td&gt;
&lt;td&gt;Limit candidate pool, cache embeddings, tune top‑k per branch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Decision Flow (Mermaid)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Start"]
    B["Is query short &amp;amp; exact?"]
    C["Is entity pattern detected?"]
    D["Set lexical weight"]
    E["Set vector weight"]
    F["Execute hybrid search"]
    A --&amp;gt; B
    B --&amp;gt;|Yes| D
    B --&amp;gt;|No| C
    C --&amp;gt;|Yes| D
    C --&amp;gt;|No| E
    D --&amp;gt; F
    E --&amp;gt; F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The diagram guides weight selection before the hybrid request is issued.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture &amp;amp; Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Primary Responsibility&lt;/th&gt;
&lt;th&gt;Owner (role)&lt;/th&gt;
&lt;th&gt;Key Interfaces&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lexical Index (BM25)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tokenization, posting list creation, deterministic scoring&lt;/td&gt;
&lt;td&gt;Search Index Engineer&lt;/td&gt;
&lt;td&gt;Query API, Document Ingestion Pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vector Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Embedding generation (offline), approximate nearest‑neighbor (ANN) lookup, cosine similarity&lt;/td&gt;
&lt;td&gt;ML Retrieval Engineer&lt;/td&gt;
&lt;td&gt;Embedding Service, ANN Index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fusion Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Combine BM25 score &amp;amp; vector similarity, apply entity boost, enforce metadata filters&lt;/td&gt;
&lt;td&gt;Retrieval Architect&lt;/td&gt;
&lt;td&gt;Scoring Service, Filter Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metadata Filter Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apply user‑defined constraints (date, department, product) before ranking&lt;/td&gt;
&lt;td&gt;Data Governance Lead&lt;/td&gt;
&lt;td&gt;Filter API, Access Control Layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observability Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Log latency, score distribution, drift in recall/precision&lt;/td&gt;
&lt;td&gt;SRE / Analytics&lt;/td&gt;
&lt;td&gt;Metrics Exporter, Alerting Rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Evaluation Harness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Periodic QA against labeled queries, regression detection&lt;/td&gt;
&lt;td&gt;QA Engineer&lt;/td&gt;
&lt;td&gt;Test Suite, Benchmark Dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Core Distinctions for Hybrid Retrieval
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Current Knowledge&lt;/strong&gt; – Stored in the lexical index and vector store; it reflects the state of the document corpus at ingestion time.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Values&lt;/strong&gt; – Anything that must be obtained from an authoritative system (e.g., pricing API, compliance service) should be fetched via a dedicated tool or API at query time, not from the retrieved text.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforceable Business Rules&lt;/strong&gt; – Deterministic logic such as entity boosts, mandatory metadata filters, or compliance flags must live in code that guarantees execution for every request.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tuning for Stable Behavior&lt;/strong&gt; – Adjustments to weight ratios, boost factors, or retrieval thresholds should be performed after systematic evaluation with labeled data and regression testing; they are not a substitute for the business rules above.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Python Decision Helper (standard library only)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# teaching-only: illustrative helper to choose lexical/vector weights
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_weights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;has_entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata_filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Returns a weight map for hybrid search.

    - lexical weight + vector weight must sum to 1.0.
    - entity presence pushes lexical weight up.
    - metadata filtering favours lexical precision.

    Raises:
        AssertionError: if inputs are malformed or resulting weights are out of bounds.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Basic sanity checks
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query must be a non‑empty string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;has_entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;has_entity must be bool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata_filter must be bool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Heuristic: short exact queries → strong lexical emphasis
&lt;/span&gt;    &lt;span class="n"&gt;short_exact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(what|how|why)\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Base weights
&lt;/span&gt;    &lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;
    &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;short_exact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;
        &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;has_entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# boost exact token match
&lt;/span&gt;        &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lexical&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;metadata_filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# filters favour deterministic hits
&lt;/span&gt;        &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lexical&lt;/span&gt;

    &lt;span class="c1"&gt;# Final validation
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lexical weight out of range&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vector weight out of range&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;lexical&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weights must sum to 1.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lexical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lexical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vector&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Decision Record 1 – Weighting Strategy Selection
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; – Enterprises need a reproducible way to decide the lexical‑vs‑vector ratio per query type.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt; – Adopt a rule‑based heuristic (see &lt;code&gt;decide_weights&lt;/code&gt;) that adjusts weights based on query length, presence of identifiable entities, and whether a metadata filter is active.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uncertainty&lt;/strong&gt; – Heuristics may not capture domain‑specific jargon, multilingual nuances, or evolving business terminology; the mapping could be sub‑optimal for newly introduced vocabularies.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The hybrid system must demonstrate at least the same mean average precision as the prior baseline on a held‑out validation set of enterprise queries.
&lt;/li&gt;
&lt;li&gt;95th‑percentile latency must remain within the service‑level agreement defined for the production environment.
&lt;/li&gt;
&lt;li&gt;Adjusting the vector weight upward should not cause an unacceptable drop in recall as judged by the evaluation harness.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture Decision Record 2 – Entity Boosting Policy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; – Many enterprise queries contain identifiers (account numbers, SKU codes, regulation IDs). Lexical match already surfaces them, but they can be drowned by higher‑scoring semantic hits.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt; – Introduce a deterministic boost factor applied to the BM25 score whenever a regular‑expression pattern matches a known identifier schema. The boost is applied before fusion with the vector score.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uncertainty&lt;/strong&gt; – Over‑boosting may hide newer, semantically relevant content that does not repeat the identifier verbatim.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Precision on identifier‑centric queries (top‑3 results) must meet or exceed the established baseline.
&lt;/li&gt;
&lt;li&gt;The boost should not noticeably degrade recall for queries that do not contain identifiers.
&lt;/li&gt;
&lt;li&gt;The additional computation for the boost must not materially increase average query latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Document Refresh&lt;/strong&gt; – Periodically re‑ingest updated documents and recompute embeddings using the same frozen base model.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Regression Test Suite&lt;/strong&gt; – After any index or weight change, run a representative set of labeled queries; reject changes if mean average precision degrades beyond an acceptable margin.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Metadata Schema Review&lt;/strong&gt; – Verify that filter fields (e.g., &lt;code&gt;effective_date&lt;/code&gt;, &lt;code&gt;department&lt;/code&gt;) remain aligned with governance policies; update the filter service if the schema drifts.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Observability Review&lt;/strong&gt; – Confirm that latency histograms and score distribution dashboards are healthy; set alerts for deviations from expected operational ranges.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Entity Pattern Audit&lt;/strong&gt; – Regularly validate that regular expressions cover newly introduced identifier formats; add missing patterns as needed.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Weight Tuning Cadence&lt;/strong&gt; – Conduct controlled experiments after major business cycles to recalibrate lexical/vector ratios based on fresh evaluation results.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft RAG concepts – &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LoRA: Low‑Rank Adaptation of Large Language Models – &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Managed model API vs self-hosted inference</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Thu, 15 Oct 2026 04:54:22 +0000</pubDate>
      <link>https://dev.to/salmonjoy/managed-model-api-vs-self-hosted-inference-5hlg</link>
      <guid>https://dev.to/salmonjoy/managed-model-api-vs-self-hosted-inference-5hlg</guid>
      <description>&lt;h1&gt;
  
  
  Managed Model API vs Self‑Hosted Inference
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Quick‑Diagnosis Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision Factor&lt;/th&gt;
&lt;th&gt;Managed API (Provider‑Hosted)&lt;/th&gt;
&lt;th&gt;Self‑Hosted Inference (On‑Prem / Cloud‑Owned)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational ownership&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider runs GPU fleet, scaling logic, OS patches, and health checks.&lt;/td&gt;
&lt;td&gt;Your ops team provisions hardware, runs schedulers, applies patches, and monitors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data control &amp;amp; compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data leaves your environment; you must rely on provider‑defined egress contracts.&lt;/td&gt;
&lt;td&gt;Data stays in your network; you can enforce any regulatory boundary you control.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware utilization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared capacity; batch sizes are limited by provider’s quota and pricing tier.&lt;/td&gt;
&lt;td&gt;You can size batches precisely, over‑subscribe GPUs, or reserve dedicated instances.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Prompt‑only or limited parameter tweaks (temperature, top‑p).&lt;/td&gt;
&lt;td&gt;Ability to swap model checkpoints, add adapters, change tokenizers, or run LoRA updates.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SLA defined by provider (e.g., high uptime); fail‑over is automatic.&lt;/td&gt;
&lt;td&gt;You must design redundancy (multi‑zone, active‑passive, health‑checks) yourself.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skill requirements&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimal; integration via HTTP/SDK.&lt;/td&gt;
&lt;td&gt;Requires Kubernetes, GPU driver management, model‑server knowledge (e.g., NVIDIA Triton).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency profile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on provider’s multi‑tenant queue; generally higher than a tightly tuned local stack.&lt;/td&gt;
&lt;td&gt;Can be tuned to lower latency by colocating near downstream services and controlling batch timing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total cost of ownership&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Predictable usage‑based pricing plus any data‑egress fees; no capital expense.&lt;/td&gt;
&lt;td&gt;Capital expense for GPUs plus variable OPEX (power, staffing, maintenance).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The table is a diagnostic aid. Real projects should measure latency, throughput, and cost for their specific workloads before committing.  &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Decision Flow (Mermaid)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Start"] --&amp;gt; B["Require strict data residency?"]
    B --&amp;gt;|Yes| C["Need very low latency?"]
    B --&amp;gt;|No| D["Team has GPU‑ops expertise?"]
    C --&amp;gt;|Yes| E["Choose Self‑Hosted"]
    C --&amp;gt;|No| F["Choose Managed API"]
    D --&amp;gt;|Yes| E
    D --&amp;gt;|No| F
    E --&amp;gt; G["Implement self‑hosted stack"]
    F --&amp;gt; G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagram condenses the most common trade‑offs: data residency, latency, and operational skill set.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Managed API Owner&lt;/th&gt;
&lt;th&gt;Self‑Hosted Owner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model hosting &amp;amp; hardware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider (fleet mgmt, GPU health)&lt;/td&gt;
&lt;td&gt;Internal SRE / Platform team (provisioning, driver updates)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inference service (REST / gRPC)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider (API gateway, auth)&lt;/td&gt;
&lt;td&gt;Your model server (Triton, vLLM, or custom)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling &amp;amp; autoscaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider (elastic load)&lt;/td&gt;
&lt;td&gt;Your orchestration (K8s HPA, custom scaler)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitoring &amp;amp; alerting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider (service health page)&lt;/td&gt;
&lt;td&gt;Your observability stack (Prometheus, Grafana, alerts)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security &amp;amp; access control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider IAM, API keys&lt;/td&gt;
&lt;td&gt;Zero‑trust network policy, mTLS, internal RBAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider‑defined contracts&lt;/td&gt;
&lt;td&gt;In‑house DLP, audit logs, compliance checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Versioning &amp;amp; updates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider releases new model versions&lt;/td&gt;
&lt;td&gt;Your CI/CD pipeline for model artifact promotion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost tracking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provider billing dashboard&lt;/td&gt;
&lt;td&gt;Internal chargeback tags (GPU‑hours, storage)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Decision Helper (Python, std‑lib only)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# teaching‑only example
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InferenceContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;All inputs that influence the operating model decision.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;data_residency_required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;latency_target_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;   &lt;span class="c1"&gt;# None means “no explicit target”
&lt;/span&gt;    &lt;span class="n"&gt;gpu_ops_expertise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;expected_monthly_token_volume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_inference_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InferenceContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Return the recommended operating mode: ``&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;managed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;`` or ``&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;``.
    The logic mirrors the Mermaid diagram but adds defensive checks.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Basic sanity checks – raise early if required fields are missing.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_residency_required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Residency flag must be bool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_monthly_token_volume&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Token volume cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latency_target_ms&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latency_target_ms&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Latency target must be non‑negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Decision tree
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_residency_required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Residency forces control of the stack; latency becomes secondary.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latency_target_ms&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;latency_target_ms&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Very low latency is generally only achievable with local inference.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gpu_ops_expertise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# Default to managed when none of the constraints push toward ownership.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;managed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Example (illustrative, not executed):
# ctx = InferenceContext(True, None, False, 5_000_000)
# mode = decide_inference_mode(ctx)
# print(mode)  # → "self_hosted"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The helper is deliberately simple: it does &lt;strong&gt;not&lt;/strong&gt; embed any provider‑specific pricing or SLA numbers, keeping the logic portable across clouds.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Architectural Decision Records (ADRs)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 001 – Data Residency vs Latency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A regulated financial services team processes personally identifiable information (PII) and must keep all raw data behind its firewall. The same service also requires very low response time for real‑time fraud scoring.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Deploy a self‑hosted inference stack inside the private data center, using a GPU‑accelerated model server with a LoRA‑based domain adapter.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatives Considered&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Managed API with an egress‑only contract.
&lt;/li&gt;
&lt;li&gt;Hybrid approach: Managed API for non‑PII requests, self‑hosted for PII.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Rationale&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Residency&lt;/em&gt; eliminates any cross‑border data movement. &lt;em&gt;Latency&lt;/em&gt; can be measured directly on the internal network, giving confidence that the target is met. The hybrid option introduced routing complexity without clear cost benefit.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End‑to‑end latency meets the internal target defined by the product team.
&lt;/li&gt;
&lt;li&gt;No raw data leaves the internal network, as verified by network flow logs that show no outbound traffic to provider IP ranges.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ADR 002 – Skill Availability vs Speed‑to‑Market
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
An edtech startup needs to launch an adaptive‑quiz feature within a tight schedule. The team has strong product designers but only one DevOps engineer with limited GPU experience.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Adopt a managed inference API (e.g., Azure OpenAI or AWS Bedrock) for the initial launch.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatives Considered&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build a self‑hosted stack using Kubernetes + Triton.
&lt;/li&gt;
&lt;li&gt;Contract an external GPU‑ops consultancy to set up the infrastructure.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Rationale&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The managed service removes the need for GPU driver maintenance, scaling logic, and model‑server configuration, fitting the short timeline. The consultancy option added procurement overhead and did not guarantee long‑term knowledge transfer.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature released within the planned timeline.
&lt;/li&gt;
&lt;li&gt;Integration tests pass with an acceptable failure rate as defined by the product team.
&lt;/li&gt;
&lt;li&gt;Post‑launch cost analysis shows usage within the budgeted forecast.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Latency verification&lt;/strong&gt; – Run a calibrated load test; confirm that observed latency satisfies the target defined for the project.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput capacity&lt;/strong&gt; – Ensure the system sustains the expected token volume without excessive queuing.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data‑flow audit&lt;/strong&gt; – Verify that no raw input leaves the trusted zone (self‑hosted) or that egress contracts are in place (managed).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch &amp;amp; driver updates&lt;/strong&gt; – For self‑hosted, schedule regular GPU driver refresh; for managed, monitor provider release notes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model version governance&lt;/strong&gt; – Tag each deployed checkpoint; keep a changelog linking business releases to model updates.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability&lt;/strong&gt; – Instrument request latency, error rates, and GPU utilization; set alerts on threshold breaches.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost reconciliation&lt;/strong&gt; – Reconcile monthly token usage against provider invoices; for self‑hosted, reconcile GPU‑hour billing and power consumption.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance re‑validation&lt;/strong&gt; – At each major regulatory review, confirm that the chosen operating model still satisfies jurisdictional requirements.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft – Retrieval‑augmented generation concepts. &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LoRA: Low‑Rank Adaptation of Large Language Models. &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Enterprise AI gateway</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Wed, 14 Oct 2026 04:54:39 +0000</pubDate>
      <link>https://dev.to/salmonjoy/enterprise-ai-gateway-50l1</link>
      <guid>https://dev.to/salmonjoy/enterprise-ai-gateway-50l1</guid>
      <description>&lt;h1&gt;
  
  
  Enterprise AI Gateway – Technical Guide
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A control‑plane that authenticates, routes, and governs every LLM request across an organization.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 Diagnosis Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Root Cause&lt;/th&gt;
&lt;th&gt;When a Gateway Becomes Worthwhile&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sprawl of API keys&lt;/td&gt;
&lt;td&gt;Each team provisions its own provider credentials&lt;/td&gt;
&lt;td&gt;Multiple independent consumer services and/or a mix of cloud providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unpredictable monthly LLM spend&lt;/td&gt;
&lt;td&gt;No centralized quota enforcement&lt;/td&gt;
&lt;td&gt;Organization needs centralized budgeting and cost‑center accountability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inconsistent policy enforcement (e.g., PII leakage)&lt;/td&gt;
&lt;td&gt;Policy logic duplicated in many services&lt;/td&gt;
&lt;td&gt;Regulatory or legal policies must be auditable enterprise‑wide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latent or failed model calls during peak loads&lt;/td&gt;
&lt;td&gt;No fail‑over or routing logic&lt;/td&gt;
&lt;td&gt;Strong service‑level expectations for availability and response time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difficulty onboarding a new foundation model&lt;/td&gt;
&lt;td&gt;Hard‑coded provider URLs in code&lt;/td&gt;
&lt;td&gt;A central “allow‑list” of approved models is required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🗺️ Decision Diagram
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Multiple LLM Consumers"] --&amp;gt; B["Compliance / Cost Constraints"]
    B --&amp;gt; C["Need Central Auth &amp;amp; Quotas"]
    C --&amp;gt; D["Enterprise AI Gateway"]
    D --&amp;gt; E["Implement Shared Control Plane"]
    A --&amp;gt; F["Few Consumers"]
    F --&amp;gt; G["Ad‑hoc Direct Provider Calls"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If the left‑hand path is taken, a gateway is strongly recommended. The right‑hand path may remain viable for very small deployments.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Architecture &amp;amp; Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Typical Implementation Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Verify caller identity (API‑key, JWT, mTLS).&lt;/td&gt;
&lt;td&gt;Use corporate IdP (Azure AD, Okta). Map identities → tenants → quota buckets.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quota &amp;amp; Throttling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enforce per‑team, per‑product, and per‑model limits.&lt;/td&gt;
&lt;td&gt;Token‑bucket or leaky‑bucket counters stored in a fast cache (Redis, Azure Cache).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Routing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Select provider &amp;amp; model based on policy, latency, cost, or feature set.&lt;/td&gt;
&lt;td&gt;Rule engine (e.g., JSON‑based policy) that evaluates &lt;code&gt;preferredProvider&lt;/code&gt;, &lt;code&gt;fallbackProvider&lt;/code&gt;, &lt;code&gt;region&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Policy Enforcement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apply legal/ethical guardrails (PII redaction, hate‑speech blocking, regulated exposure caps).&lt;/td&gt;
&lt;td&gt;Plug‑in filters that run before request reaches the model; can short‑circuit with a “blocked” response.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logging &amp;amp; Auditing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Capture request metadata, decisions, and outcomes for compliance dashboards.&lt;/td&gt;
&lt;td&gt;Structured logs (JSON) streamed to SIEM/Log Analytics; include request ID, caller, model, policy decisions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provider Abstraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hide vendor‑specific SDKs behind a uniform interface.&lt;/td&gt;
&lt;td&gt;Internal &lt;code&gt;ModelClient&lt;/code&gt; with methods &lt;code&gt;invoke(prompt, params)&lt;/code&gt; that internally selects Azure OpenAI, AWS Bedrock, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Detect degraded latency or error rates and transparently switch to a secondary provider.&lt;/td&gt;
&lt;td&gt;Health‑check ping; routing rule &lt;code&gt;if latency deteriorates → use fallback&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model Allow‑list&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Central catalog of approved foundation models (name, version, vendor, licensing).&lt;/td&gt;
&lt;td&gt;Single source of truth (e.g., Azure Table, DynamoDB) referenced during routing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🐍 Python Decision Helper (Standard Library Only)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Teaching‑only&lt;/strong&gt; – The snippet demonstrates how a service could decide whether to invoke the gateway or fall back to a direct provider, based solely on a configuration file.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# enterprise_ai_gateway_helper.py
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Decision helper for routing LLM requests.

- Reads a JSON config that contains:
    * `allow_list`: approved model identifiers
    * `quota_limits`: per‑tenant request caps
    * `fallback_provider`: secondary cloud vendor
- Returns a dict with routing metadata; raises AssertionError on mis‑configuration.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;

&lt;span class="n"&gt;CONFIG_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATEWAY_CONFIG&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./gateway_config.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load and validate the gateway configuration.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;CONFIG_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Basic sanity checks – deterministic assertions, not runtime heuristics.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow_list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow_list must be a list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow_list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow_list cannot be empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quota_limits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quota_limits must be a dict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fallback_provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fallback_provider required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_routing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requested_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Determine the provider and model to use.

    Parameters
    ----------
    tenant_id: str – Identifier of the calling team/product.
    requested_model: str – Model name requested by the caller.
    current_usage: int – Number of requests already made this billing period.

    Returns
    -------
    dict with keys `provider`, `model`, `via_gateway`.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Enforce allow‑list
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;requested_model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow_list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Model &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;requested_model&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not approved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Enforce quota (simple per‑tenant cap)
&lt;/span&gt;    &lt;span class="n"&gt;quota&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quota_limits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No quota defined for tenant &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;current_usage&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;quota&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tenant &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exceeded quota (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_usage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quota&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Routing decision – primary provider derived from model name convention
&lt;/span&gt;    &lt;span class="n"&gt;primary_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;azure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;requested_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aws&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# In a real deployment the health check would be dynamic; here we assume primary is healthy.
&lt;/span&gt;    &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;primary_provider&lt;/span&gt;

    &lt;span class="c1"&gt;# Example of deterministic fail‑over logic (placeholder)
&lt;/span&gt;    &lt;span class="c1"&gt;# if health_check(provider) == "unhealthy":
&lt;/span&gt;    &lt;span class="c1"&gt;#     provider = cfg["fallback_provider"]
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;requested_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;via_gateway&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# All decisions flow through the gateway
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage (for illustration only)
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Simulate a request from team 'risk‑engine' asking for 'gpt-4o-mini' with 12 prior calls.
&lt;/span&gt;    &lt;span class="n"&gt;routing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decide_routing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk-engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📄 Illustrative Architecture Decision Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 1 – Adopt Central Model Allow‑List
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Multiple engineering squads independently select foundation models. Procurement data shows several distinct model versions in production, leading to fragmented licensing and security reviews.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Introduce a &lt;strong&gt;central allow‑list&lt;/strong&gt; stored in a managed key‑value service. The gateway validates every request against this list before routing.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Positive&lt;/th&gt;
&lt;th&gt;Negative&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single source of truth for compliance and licensing.&lt;/td&gt;
&lt;td&gt;Requires coordination for model deprecation or addition.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Faster onboarding of new services (they inherit the list).&lt;/td&gt;
&lt;td&gt;Slight increase in request latency due to the lookup.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All production LLM calls should be validated by the gateway before reaching a provider.
&lt;/li&gt;
&lt;li&gt;Requests for models not present in the allow‑list are rejected with an appropriate error response.
&lt;/li&gt;
&lt;li&gt;Auditors can retrieve a read‑only JSON snapshot of the allow‑list via a dedicated API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Uncertainties&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frequency of model version churn may pressure the update process.
&lt;/li&gt;
&lt;li&gt;Impact on latency for high‑throughput micro‑services needs monitoring.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ADR 2 – Implement Provider‑Failover Policy
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
During a load test, Azure OpenAI latency spiked markedly, breaching internal availability expectations. No automatic reroute existed, leading to request timeouts.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Encode a &lt;strong&gt;fail‑over rule&lt;/strong&gt; in the gateway: if the primary provider’s recent latency exceeds an acceptable threshold, automatically route new requests to the secondary provider defined in &lt;code&gt;fallback_provider&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences&lt;/strong&gt;  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Positive&lt;/th&gt;
&lt;th&gt;Negative&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Improves resilience without code changes in downstream services.&lt;/td&gt;
&lt;td&gt;Requires reliable health‑monitoring infrastructure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enables cost optimisation by preferring lower‑priced providers when performance is acceptable.&lt;/td&gt;
&lt;td&gt;Possible model‑output variance between providers; downstream must tolerate it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health monitoring must emit latency metrics to a central store at regular intervals.
&lt;/li&gt;
&lt;li&gt;Fail‑over activation must be logged with timestamp, measured latency, and chosen provider.
&lt;/li&gt;
&lt;li&gt;After latency improves and remains within acceptable bounds for a sustained period, routing should revert to the primary provider.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Uncertainties&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How downstream services will handle subtle differences in tokenisation or response format between providers.
&lt;/li&gt;
&lt;li&gt;Potential licensing implications of dynamically switching providers mid‑request.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Authentication Review&lt;/strong&gt; – Verify token validation against the corporate IdP on a quarterly cadence.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Quota Accuracy&lt;/strong&gt; – Reconcile gateway counters with cloud billing reports each month.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Policy Coverage&lt;/strong&gt; – Run an automated test suite that injects known PII, regulated terms, and profanity; ensure the gateway blocks or redacts as expected.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Latency &amp;amp; Fail‑over Tests&lt;/strong&gt; – Simulate provider latency degradation; confirm automatic reroute and proper logging.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Allow‑list Audits&lt;/strong&gt; – Generate a weekly immutable snapshot; compare against procurement records for consistency.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Log Retention &amp;amp; Access Control&lt;/strong&gt; – Ensure logs are encrypted at rest and retained for the mandated compliance period.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Disaster Recovery Drill&lt;/strong&gt; – Power‑cycle the gateway service and verify that downstream services handle the temporary unavailability according to the defined fallback strategy.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Cost Monitoring&lt;/strong&gt; – Correlate gateway‑reported usage with cloud billing dashboards; investigate any significant variance.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft RAG concepts&lt;/strong&gt; – Retrieval‑augmented generation overview for Azure AI services. &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LoRA paper&lt;/strong&gt; – Low‑Rank Adaptation of Large Language Models. &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;This guide is intended for architects and platform engineers evaluating the trade‑offs of an Enterprise AI Gateway. Adoption decisions should be driven by measurable compliance, cost, and resilience signals rather than assumed performance gains.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Reasoning depth vs latency vs cost</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Tue, 13 Oct 2026 04:54:38 +0000</pubDate>
      <link>https://dev.to/salmonjoy/reasoning-depth-vs-latency-vs-cost-2f73</link>
      <guid>https://dev.to/salmonjoy/reasoning-depth-vs-latency-vs-cost-2f73</guid>
      <description>&lt;h1&gt;
  
  
  Reasoning Depth vs Latency vs Cost – An Escalation‑Based Design Guide
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Balancing model capability, response time, and expense by routing work through a defined escalation path.&lt;/em&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  1️⃣ Concise Diagnosis Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom 🩺&lt;/th&gt;
&lt;th&gt;Likely Primary Cause&lt;/th&gt;
&lt;th&gt;Immediate Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sub‑second latency but answers are vague or incomplete&lt;/td&gt;
&lt;td&gt;Model selected lacks sufficient reasoning depth&lt;/td&gt;
&lt;td&gt;Verify the request’s reasoning steps (chain‑of‑thought, policy nuance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency spikes above service‑level objective while cost stays low&lt;/td&gt;
&lt;td&gt;Small model forced to iterate many retries or falls back to heuristics&lt;/td&gt;
&lt;td&gt;Review token usage and number of inference calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per 1 K tokens is high but latency is acceptable&lt;/td&gt;
&lt;td&gt;Large model used for a trivially‑easy task&lt;/td&gt;
&lt;td&gt;Confirm the routing rules that map “easy” workload to a lightweight model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inconsistent policy compliance across similar requests&lt;/td&gt;
&lt;td&gt;Missing or stale retrieval context; deterministic business logic executed elsewhere&lt;/td&gt;
&lt;td&gt;Ensure retrieval component pulls the latest authoritative source; check rule engine logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frequent escalation to the biggest model&lt;/td&gt;
&lt;td&gt;Reasoning budget definition too permissive or risk‑threshold too low&lt;/td&gt;
&lt;td&gt;Re‑evaluate the thresholds that trigger escalation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2️⃣ Decision Flow (Mermaid)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Start"] --&amp;gt; B["Is request easy?"]
    B --&amp;gt;|Yes| C["Route to Small Model"]
    B --&amp;gt;|No| D["Is latency budget sufficient?"]
    D --&amp;gt;|Yes| E["Route to Medium Model"]
    D --&amp;gt;|No| F["Escalate to Large Model"]
    C --&amp;gt; G["Execute"]
    E --&amp;gt; G
    F --&amp;gt; G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Key definitions&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy request&lt;/strong&gt; – single‑lookup, no multi‑step reasoning, deterministic rule check.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency budget&lt;/strong&gt; – maximum wall‑clock time allocated for the request tier (set in the Service‑Level Objective table).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalation&lt;/strong&gt; – handing the request to a higher‑capacity model when either depth or risk exceeds the current tier’s limits.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3️⃣ Architecture &amp;amp; Responsibility Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Core Responsibility&lt;/th&gt;
&lt;th&gt;Interaction Points&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Request Router&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Classifies incoming payloads (easy vs. complex) and selects the initial model tier based on the decision flow.&lt;/td&gt;
&lt;td&gt;Consumes request metadata, consults &lt;em&gt;Reasoning Budget Engine&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reasoning Budget Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Computes a &lt;em&gt;budget&lt;/em&gt; ‑ tokens × cost × max latency – for the current tier and exposes a “budget‑exceeded” flag.&lt;/td&gt;
&lt;td&gt;Reads pricing table, latency SLA, and request complexity estimate.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost / Latency Monitor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Records actual token consumption, wall‑clock latency, and monetary cost per request; feeds back to the router for adaptive throttling.&lt;/td&gt;
&lt;td&gt;Emits metrics to observability stack; triggers alerts when SLA drift occurs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model Pool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Holds at least three model variants: &lt;br&gt;• &lt;strong&gt;Small&lt;/strong&gt; – fast, cheap, limited depth (e.g., gpt‑3.5‑turbo). &lt;br&gt;• &lt;strong&gt;Medium&lt;/strong&gt; – balanced latency and reasoning (e.g., gpt‑4‑base). &lt;br&gt;• &lt;strong&gt;Large&lt;/strong&gt; – highest depth, higher cost (e.g., gpt‑4‑32k).&lt;/td&gt;
&lt;td&gt;Exposes a uniform inference API; each model reports its token‑rate and per‑token price.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retrieval Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supplies external, up‑to‑date documents (RAG) &lt;em&gt;only&lt;/em&gt; for contexts that require factual grounding.&lt;/td&gt;
&lt;td&gt;Uses Microsoft RAG concepts; never substitutes deterministic rule evaluation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tooling / APIs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes authoritative calls (e.g., live currency rates, regulatory APIs) when a request requires live values.&lt;/td&gt;
&lt;td&gt;Invoked by the model via function‑call style prompts; results are never cached for live‑value requests.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deterministic Rule Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enforces business‑critical policies that must be 100 % correct (e.g., compliance thresholds).&lt;/td&gt;
&lt;td&gt;Runs &lt;strong&gt;outside&lt;/strong&gt; the LLM; the LLM may suggest a rule but the engine validates it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Fine‑tuning / LoRA Service&lt;/strong&gt; (optional)&lt;/td&gt;
&lt;td&gt;Trains low‑rank adapters on stable, high‑quality labeled data when prompting and retrieval are proven insufficient.&lt;/td&gt;
&lt;td&gt;Uses LoRA paper guidance; adapters are frozen after evaluation and merged for inference only when regression tests pass.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4️⃣ Python Decision Helper (Teaching‑Only)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# -*- coding: utf-8 -*-
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
decision_helper.py – map a request to the appropriate model tier.

Teaching‑only: this module illustrates the budget calculation and routing
logic; production systems should substitute the placeholder constants
with configuration values sourced from a centralized policy store.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;

&lt;span class="c1"&gt;# ---- Configuration placeholders (populate from authoritative sources) ----
&lt;/span&gt;&lt;span class="n"&gt;TOKEN_COST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# $ per token – replace with real provider price
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;MAX_LATENCY_MS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# milliseconds – replace with SLA value
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;MAX_TOKENS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# context window size – replace with model capability
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# -------------------------------------------------------------------------
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_budget_exceeded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;estimated_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;elapsed_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Return True when either cost, latency, or token‑count exceeds the limits
    defined for the given tier.  All limits are injected via the placeholder
    dictionaries above.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Cost check – expressed in dollars for the estimated token count
&lt;/span&gt;    &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;estimated_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;TOKEN_COST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Latency check – compare observed wall‑clock time with tier SLA
&lt;/span&gt;    &lt;span class="n"&gt;latency_ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elapsed_ms&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_LATENCY_MS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Token‑count sanity – avoid exceeding model context window
&lt;/span&gt;    &lt;span class="n"&gt;token_ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;estimated_tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_TOKENS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# All three conditions must hold; otherwise we need to escalate
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latency_ok&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;token_ok&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 0.0 is a placeholder ceiling
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;request_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;estimated_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_easy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Determine the model tier for a request.

    Assertions act as sanity checks for the teaching example.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;estimated_tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Token estimate must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_easy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_easy must be boolean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_time must be timezone‑aware&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 1️⃣ Easy requests start on the smallest tier
&lt;/span&gt;    &lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_easy&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# 2️⃣ Measure elapsed time so far (simulated here as zero)
&lt;/span&gt;    &lt;span class="n"&gt;elapsed_ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;total_seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3️⃣ Escalate if budget is exceeded
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;_budget_exceeded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;estimated_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elapsed_ms&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tier&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5️⃣ Architectural Decision Records (ADRs)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 001 – Use Escalation‑Based Model Selection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Our platform processes a mixture of high‑throughput lookups and low‑throughput policy analyses. Early prototypes used a single large model for simplicity, resulting in unacceptable latency for the bulk of traffic and inflated compute spend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Adopt a three‑tier escalation policy (Small → Medium → Large) governed by a &lt;em&gt;Reasoning Budget Engine&lt;/em&gt;. The router initially classifies each request as &lt;em&gt;easy&lt;/em&gt; or &lt;em&gt;complex&lt;/em&gt; based on a lightweight static analysis (token estimate, presence of chain‑of‑thought cues). If the budget is exceeded after the first inference, the system automatically re‑routes to the next tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatives Considered&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single‑model approach – rejected due to SLA violations and cost overruns.
&lt;/li&gt;
&lt;li&gt;Dynamic model scaling (on‑the‑fly parameter adjustment) – deemed too risky for compliance‑critical paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;95 % of requests complete within the latency SLA of their assigned tier.
&lt;/li&gt;
&lt;li&gt;Total compute cost per day reduces by ≥ 30 % compared with the single‑model baseline.
&lt;/li&gt;
&lt;li&gt;No increase in policy‑violation incidents after introducing escalation.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  ADR 002 – Keep Live‑Value Retrieval Outside LLM Inference
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A subset of fraud‑detection requests require the latest exchange‑rate. Early designs cached the rate in the prompt to avoid extra calls, leading to occasional compliance errors when the cache was stale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Introduce a &lt;em&gt;Tooling / APIs&lt;/em&gt; component that the LLM invokes via function‑call style prompts. The component fetches the value from the authoritative service at request time; the result is never cached for live‑value calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alternatives Considered&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre‑embedding rates in the prompt – rejected because cache invalidation complexity exceeds benefit.
&lt;/li&gt;
&lt;li&gt;Relying on the LLM’s internal knowledge – rejected; the model’s knowledge cutoff is older than required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Acceptance Criteria&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every live‑value request triggers exactly one external API call.
&lt;/li&gt;
&lt;li&gt;Auditable logs show the timestamp of the fetched value matched the request timestamp ± 5 seconds.
&lt;/li&gt;
&lt;li&gt;No compliance test failures attributable to stale data after rollout.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6️⃣ Evaluation &amp;amp; Maintenance Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Unit tests&lt;/strong&gt; for &lt;code&gt;decide_model&lt;/code&gt; covering easy/complex, budget‑exceed, and time‑edge cases.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Integration tests&lt;/strong&gt; that simulate end‑to‑end routing with mock latency and cost profiles.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Regression suite&lt;/strong&gt; for deterministic rule engine output (must remain unchanged after any LoRA update).
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Metric verification&lt;/strong&gt; – confirm that Cost / Latency Monitor reports per‑tier averages matching SLA tables.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;RAG validation&lt;/strong&gt; – sample a set of retrieval‑augmented prompts and verify factual grounding against the source documents; do not rely on RAG for policy enforcement.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;LoRA audit&lt;/strong&gt; – after any adapter training, run full‑coverage functional tests; retain the frozen base model unchanged.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Policy review cadence&lt;/strong&gt; – quarterly check that the &lt;em&gt;Reasoning Budget Engine&lt;/em&gt; thresholds still align with business risk tolerances.
&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Documentation sync&lt;/strong&gt; – ensure the decision flow diagram and ADRs reflect the current routing logic.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7️⃣ Editorial Accuracy Guidance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A symptom listed in the diagnosis table is a clue, &lt;strong&gt;not&lt;/strong&gt; proof of a root cause.  Investigate label quality, missing context, preprocessing pipelines, and intrinsic model capability before attributing errors to pre‑training.
&lt;/li&gt;
&lt;li&gt;Retrieval‑Augmented Generation (RAG) improves factual grounding but &lt;strong&gt;does not guarantee&lt;/strong&gt; correctness, completeness, or compliance.  Deterministic rule checks must remain separate and authoritative.
&lt;/li&gt;
&lt;li&gt;Low‑Rank Adaptation (LoRA) freezes the base model weights and learns low‑rank updates; this &lt;strong&gt;does not guarantee&lt;/strong&gt; that all prior behaviours are preserved.  Regression testing outside the target task is required.
&lt;/li&gt;
&lt;li&gt;Live‑value APIs must always be invoked at request time; cached or stale values are unacceptable for any compliance‑sensitive operation.
&lt;/li&gt;
&lt;li&gt;All acceptance criteria in ADRs contain measurable thresholds and acknowledge uncertainty; they are not claims of absolute performance.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8️⃣ References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft RAG concepts – Retrieval‑Augmented Generation for grounding LLM output. &lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LoRA: Low‑Rank Adaptation of Large Language Models. &lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2106.09685&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;By defining explicit escalation paths, quantifying a reasoning budget, and separating deterministic logic from probabilistic inference, teams can keep latency low, cost proportional, and capability aligned with the true difficulty of each request.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Prompting vs RAG vs fine-tuning</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Mon, 12 Oct 2026 12:26:46 +0000</pubDate>
      <link>https://dev.to/salmonjoy/prompting-vs-rag-vs-fine-tuning-1a2a</link>
      <guid>https://dev.to/salmonjoy/prompting-vs-rag-vs-fine-tuning-1a2a</guid>
      <description>&lt;h1&gt;
  
  
  Prompting vs RAG vs Fine-Tuning: Diagnose the Failure First
&lt;/h1&gt;

&lt;p&gt;A wrong answer is an observation, not a root cause. Inspect the input, source evidence, retrieval results, tool responses, and expected output before choosing an intervention. The same symptom can come from missing context, ambiguous labels, a weak base model, or a bug outside the model. The examples and architectural decisions below are hypothetical teaching examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Match the intervention to evidence
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observed issue&lt;/th&gt;
&lt;th&gt;Evidence to inspect&lt;/th&gt;
&lt;th&gt;Candidate intervention&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Instructions are unclear or the answer has the wrong style&lt;/td&gt;
&lt;td&gt;Prompt wording, examples, instruction conflicts, and task tests&lt;/td&gt;
&lt;td&gt;Improve prompting and evaluate the change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An answer needs private or changing documents&lt;/td&gt;
&lt;td&gt;Source version, access filters, retrieval coverage, and citation support&lt;/td&gt;
&lt;td&gt;Retrieve relevant documents and provide them as context through RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The answer needs a current numeric value&lt;/td&gt;
&lt;td&gt;Authoritative service, timestamp, units, and response schema&lt;/td&gt;
&lt;td&gt;Call a tool or API at request time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A rule must be enforced exactly&lt;/td&gt;
&lt;td&gt;Approved rule specification, inputs, boundary cases, and authorization&lt;/td&gt;
&lt;td&gt;Implement and test deterministic application code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A stable task pattern remains weak after baseline improvements&lt;/td&gt;
&lt;td&gt;Label quality, representative examples, model capability, and held-out results&lt;/td&gt;
&lt;td&gt;Evaluate fine-tuning against the improved baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Prompting supplies instructions and examples at inference time. RAG retrieves relevant content and adds it to the model input. Fine-tuning changes learned behavior using training examples. They are composable: a tuned model can still use prompts, retrieval, and tools. None removes the need to evaluate the complete application.&lt;/p&gt;

&lt;p&gt;Do not infer that a repetitive error came from pre-training merely because it occurs often. Check the labels, missing context, preprocessing, and task definition first. A model that cannot handle the underlying task may require a different base model rather than more prompt text or tuning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision flow
&lt;/h2&gt;

&lt;p&gt;This diagram summarizes candidate interventions after diagnosis. A symptom can lead to more than one candidate. Validate each change with task-level evaluation before adopting it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A["Inspect failure evidence"]
    B["Clarify instructions and examples"]
    C["Retrieve relevant current documents"]
    D["Query authoritative live values"]
    E["Enforce exact rules in code"]
    F["Evaluate tuning for stable patterns"]
    G["Compare results and operating costs"]
    A --&amp;gt; B
    A --&amp;gt; C
    A --&amp;gt; D
    A --&amp;gt; E
    A --&amp;gt; F
    B --&amp;gt; G
    C --&amp;gt; G
    D --&amp;gt; G
    E --&amp;gt; G
    F --&amp;gt; G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture and responsibilities
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Evaluation focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt templates&lt;/td&gt;
&lt;td&gt;Version instructions, examples, and context assembly&lt;/td&gt;
&lt;td&gt;Task success and sensitivity to phrasing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document ingestion and retrieval&lt;/td&gt;
&lt;td&gt;Maintain source versions, access filters, indexes, and relevant excerpts&lt;/td&gt;
&lt;td&gt;Coverage, freshness, ranking, and citation support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool execution&lt;/td&gt;
&lt;td&gt;Fetch authoritative values and perform authorized actions&lt;/td&gt;
&lt;td&gt;Schema, units, timestamps, errors, and authorization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic application logic&lt;/td&gt;
&lt;td&gt;Enforce explicit business rules and output constraints&lt;/td&gt;
&lt;td&gt;Boundary cases and reproducible results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training and model registry&lt;/td&gt;
&lt;td&gt;Track datasets, base versions, tuning artifacts, and evaluation evidence&lt;/td&gt;
&lt;td&gt;Target-task improvement and regressions elsewhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration and monitoring&lt;/td&gt;
&lt;td&gt;Assemble context, route requests, and record useful diagnostics&lt;/td&gt;
&lt;td&gt;End-to-end quality, cost, latency, and failure recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a hypothetical policy assistant, use retrieval to supply the applicable document version and citations. Use an API for a live rate, and code for an exact threshold calculation. The model may explain the result, but application logic must enforce any required rule. Retrieval does not guarantee a correct answer or regulatory compliance; source coverage, interpretation, and review still matter.&lt;/p&gt;

&lt;p&gt;LoRA freezes base weights and learns low-rank updates to selected weight matrices. Frozen base weights do not imply unchanged behavior when the updates are applied. Evaluate target-task quality and regressions on other tasks. Where the model and deployment support merging, LoRA updates can be merged into the base weights; runtime adapter selection is a separate deployment choice. Measure latency and cost for the actual serving configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python decision helper: teaching only
&lt;/h2&gt;

&lt;p&gt;This helper maps an already diagnosed category to a candidate intervention. It does not diagnose a model, authorize an action, or decide compliance. A real investigation may produce several categories, so the function accepts multiple findings. It uses only the Python standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;UNCLEAR_INSTRUCTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unclear_instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;DOCUMENT_GAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_gap&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;LIVE_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;live_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;EXACT_RULE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exact_rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;STABLE_TASK_GAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stable_task_gap_after_baselines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="n"&gt;INTERVENTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UNCLEAR_INSTRUCTIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_prompting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOCUMENT_GAP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_rag&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LIVE_VALUE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query_authoritative_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXACT_RULE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;implement_tested_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STABLE_TASK_GAP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_fine_tuning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;candidate_interventions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return unique candidates in the order the findings were supplied.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;findings must be a list of Finding members&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;finding&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;each finding must be a Finding member&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INTERVENTIONS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;finding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;candidate_interventions&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;candidate_interventions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOCUMENT_GAP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXACT_RULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOCUMENT_GAP&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_rag&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;implement_tested_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;candidate_interventions&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Finding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STABLE_TASK_GAP&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluate_fine_tuning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The explicit type checks remain active when Python assertions are disabled. The assertions demonstrate expected behavior; they are not input validation. Candidate names intentionally describe the next engineering step rather than promise a successful fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Illustrative architectural decision records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ADR 001: Retrieve changing policy documents
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; A hypothetical assistant must explain policy documents that change independently of model releases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Maintain a searchable source collection with versions and effective dates. Refresh it according to the application's freshness requirement, apply access filters, retrieve relevant passages, and retain citation metadata. Evaluate missing-document and conflicting-version cases. Escalate when supporting evidence is insufficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences:&lt;/strong&gt; Document updates can be delivered without retraining the model. Ingestion and retrieval add operational work and latency. A fresh index alone cannot establish that an answer is correct, complete, or compliant. Exact enforceable rules remain in tested code.&lt;/p&gt;

&lt;h3&gt;
  
  
  ADR 002: Evaluate tuning for stable classification behavior
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; A hypothetical classifier still makes a recurring error after task definition, labels, prompts, and supplied context have been checked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Compare a tuning candidate with the improved baseline using representative, disjoint evaluation data. Track the base model, training data, and tuning configuration. Include regression cases outside the target category and keep a rollback path. Consider LoRA if the chosen model and training stack support it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequences:&lt;/strong&gt; Tuning may improve stable task behavior, but improvement must be demonstrated. Training data, evaluation, and model lifecycle management add cost. Small trainable updates do not guarantee preserved general performance. Tuning is not a dependable mechanism for refreshing changing facts or enforcing exact rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluation and maintenance checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Version prompts, model configurations, data sources, and expected outputs so comparisons are reproducible.&lt;/li&gt;
&lt;li&gt;Measure end-to-end task success with representative examples; inspect individual failure cases as well as averages.&lt;/li&gt;
&lt;li&gt;For RAG, evaluate source coverage, retrieval relevance, document versions, access control, and whether citations support each factual claim.&lt;/li&gt;
&lt;li&gt;For tools, validate schemas, units, timestamps, and error states. Define when a cached result is acceptable; do not silently use stale data for a request requiring a live value.&lt;/li&gt;
&lt;li&gt;For deterministic rules, test boundary values and invalid inputs against the approved specification.&lt;/li&gt;
&lt;li&gt;For tuning, keep training and evaluation data separate and compare against the strongest practical baseline. Check regressions and drift before promotion.&lt;/li&gt;
&lt;li&gt;Measure latency and cost per successful task for the actual application. Set thresholds from its requirements rather than invented universal benchmarks.&lt;/li&gt;
&lt;li&gt;Keep diagnostic records limited to the information needed for investigation, with appropriate retention and data handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with the evidence, choose a candidate change, and measure the result. Keep retrieval, tool execution, rule enforcement, and learned task behavior accountable to their own tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primary references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation" rel="noopener noreferrer"&gt;Microsoft: Retrieval augmented generation and indexes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2106.09685" rel="noopener noreferrer"&gt;Hu et al.: LoRA: Low-Rank Adaptation of Large Language Models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Long context vs RAG</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Fri, 09 Oct 2026 05:10:36 +0000</pubDate>
      <link>https://dev.to/salmonjoy/long-context-vs-rag-2oke</link>
      <guid>https://dev.to/salmonjoy/long-context-vs-rag-2oke</guid>
      <description>&lt;h1&gt;
  
  
  Long Context Did Not Kill RAG: The Real Architecture Decision
&lt;/h1&gt;

&lt;p&gt;When I first plugged a LLM into our fintech risk engine, I thought “just dump the whole CSV, it’s only a few thousand rows”. The model froze, the API balked, and our devs started yelling about token limits. Turns out, feeding a &lt;strong&gt;5 MB PDF of credit‑card statements&lt;/strong&gt; into the prompt is like trying to read &lt;em&gt;War and Peace&lt;/em&gt; in one breath – you get the gist but miss the details, and you pay a fortune in tokens.  &lt;/p&gt;

&lt;p&gt;So I went back to the drawing board and asked: &lt;strong&gt;when does feeding the whole document actually work, and when do we need a Retrieval‑Augmented Generation (RAG) layer?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static, short, self‑contained sources&lt;/strong&gt; – e.g., a one‑page terms‑of‑service, a quiz question bank, or a syllabus snippet – can safely be shoved into the prompt. Accuracy stays high because the model sees everything at once, there’s virtually no retrieval‑noise, and provenance is simple – the prompt itself is the source. The token cost is predictable and usually cheap.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;As soon as the corpus grows beyond a few kilobytes or changes daily, the “long context” trick dies.&lt;/strong&gt; In my edutech chatbot we tried to feed a whole course catalog (200+ pages). The model started hallucinating module numbers and latency shot up. RAG saved us: we indexed each lesson, pulled only the three most relevant chunks, and the answer became spot‑on. Retrieval reduces noise because you only surface what the similarity score says is relevant, but you also introduce a new failure mode – the retriever might miss the right paragraph.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let’s break it down
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Full‑Doc&lt;/th&gt;
&lt;th&gt;RAG&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Accuracy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% recall of the text but can drown in irrelevant bits.&lt;/td&gt;
&lt;td&gt;Higher precision when the retriever is good; a poor retriever can drop critical facts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Noise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Noisy by design.&lt;/td&gt;
&lt;td&gt;Filters noise but adds risk of “retrieval hallucination”.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 token ≈ 4 characters. A 10 KB doc ≈ 2,500 tokens, eating most of the 4k limit for GPT‑4.&lt;/td&gt;
&lt;td&gt;Typically 2‑3 chunks of 200‑300 tokens each → saves &amp;gt;80% of tokens.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Access control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Must embed the whole sensitive file in every API call – not ideal for PCI‑compliant fintech data.&lt;/td&gt;
&lt;td&gt;Store docs in a secure vector store, fetch only needed vectors, keep raw file off‑chain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Freshness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Updating a static prompt means re‑sending the whole new document each time.&lt;/td&gt;
&lt;td&gt;Swap a single vector or re‑index a changed chapter in seconds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provenance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can point to line numbers directly.&lt;/td&gt;
&lt;td&gt;Provides a document ID and chunk offset, which can be logged for audit trails – actually better for compliance.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Case study 1 – Fintech
&lt;/h2&gt;

&lt;p&gt;We built a &lt;strong&gt;KYC assistant&lt;/strong&gt; that needed the latest AML regulations. Regulations update weekly, so we indexed each PDF. The assistant now answers “What’s the new threshold for cash transactions?” by pulling the exact clause, not by guessing from a stale prompt.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Case study 2 – Edutech
&lt;/h2&gt;

&lt;p&gt;Our tutoring bot used RAG to fetch only the relevant lesson from a &lt;strong&gt;300‑page physics textbook&lt;/strong&gt;. Students got answers in &lt;strong&gt;0.8 s&lt;/strong&gt; instead of the &lt;strong&gt;4‑second lag&lt;/strong&gt; we saw when we tried to push the whole PDF.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Long context didn’t kill RAG; it just reminded us that each tool has a sweet spot.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;full‑doc&lt;/strong&gt; when the source is tiny, immutable, and low‑risk.
&lt;/li&gt;
&lt;li&gt;Flip to &lt;strong&gt;RAG&lt;/strong&gt; when you need scalability, freshness, or tighter control.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What’s the biggest “long‑context disaster” you’ve survived?&lt;/strong&gt; Drop a story below – I love a good war tale!  &lt;/p&gt;

&lt;p&gt;If you are someone who loves to know the technical work and architecture design I have shared more details based on my experience on this here: &lt;a href="https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Long_context_vs_RAG.md" rel="noopener noreferrer"&gt;https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Long_context_vs_RAG.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Function calling vs free-form generation</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Thu, 08 Oct 2026 05:10:53 +0000</pubDate>
      <link>https://dev.to/salmonjoy/function-calling-vs-free-form-generation-2kgi</link>
      <guid>https://dev.to/salmonjoy/function-calling-vs-free-form-generation-2kgi</guid>
      <description>&lt;h1&gt;
  
  
  LLMs Should Decide What to Ask For, Not Secretly Execute Your Business Logic
&lt;/h1&gt;

&lt;p&gt;Last month I was knee‑deep in a fintech app that let users snap a receipt and instantly see a spending summary. The LLM was supposed to read the image, pull out numbers, and dump them into our ledger. Instead it started “doing its own business logic”: rounding oddly, applying a grandma‑style discount, even flagging a transaction as fraud on a hunch. It felt like handing a chef a pan and watching them secretly add mystery spices.&lt;/p&gt;

&lt;p&gt;The issue was clear: I was using free‑form generation as a Swiss‑army knife and letting the model decide &lt;em&gt;how&lt;/em&gt; to do the work. The result? Non‑deterministic output, audit nightmares, and a pile of “why did the AI do that?” tickets.&lt;/p&gt;

&lt;p&gt;Enter function calling. Think of it as a polite waiter: you tell the model, “If you need a number, call the &lt;code&gt;extract_amount(image)&lt;/code&gt; function and I’ll give you a float.” The model can’t magically compute inside its brain; it must ask your API for the exact piece you typed. Your service handles the heavy lifting, has auth checks, logs every request, retries on failure, and returns a deterministic result. This is exactly what OpenAI’s Function Calling and the “Tools” feature do – expose narrow, typed endpoints and keep the business logic on the server side.&lt;/p&gt;

&lt;p&gt;A quick analogy: free‑form generation is like giving a kid a 3‑D printer and saying “make me a toy.” They might print a dinosaur, a spaceship, or a banana. Function calling is like handing them a LEGO set with a clear instruction sheet – they can only build what the instructions allow, and you can count each piece as it’s added.&lt;/p&gt;

&lt;p&gt;In our fintech case we defined three tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;extract_amount(image_bytes) → float&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;record_transaction(user_id, amount, category) → bool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;check_fraud(user_id, amount) → bool&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the LLM says, “I need the amount from this receipt – call &lt;code&gt;extract_amount&lt;/code&gt;,” and we get a clean number. If the API hiccups we retry, everything is logged, and auditors can see exactly what was asked and what was returned. No hidden discounts.&lt;/p&gt;

&lt;p&gt;In edutech we built a tutoring bot that could answer math questions, but we didn’t want it to hallucinate formulas. We exposed a &lt;code&gt;solve_linear(a, b) → float&lt;/code&gt; function. The model now asks, “What’s x in 2x+3=7? Call &lt;code&gt;solve_linear&lt;/code&gt; with &lt;code&gt;a=2, b=-4&lt;/code&gt;.” The answer is always correct, traceable, and teachers can audit the logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key take‑aways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate interpretation (LLM decides &lt;em&gt;what&lt;/em&gt; to ask) from execution (your code does the &lt;em&gt;how&lt;/em&gt;).
&lt;/li&gt;
&lt;li&gt;Keep tools narrow and parameters typed – no free‑form JSON blobs.
&lt;/li&gt;
&lt;li&gt;Wire up auth, audit trails, retries, and error handling on the tool side.
&lt;/li&gt;
&lt;li&gt;Keep business logic deterministic in your code, not hidden in the model’s imagination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the next time you’re tempted to let the LLM write the whole recipe, remember: let it be the clever waiter, not the secret chef. What narrow tool would you love to add to your stack? Drop a comment and let’s swap ideas!&lt;/p&gt;

&lt;p&gt;If you are someone who loves to know the technical work and architecture design I have shared more details based on my experience on this here: &lt;a href="https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Function_calling_vs_free-form_generation.md" rel="noopener noreferrer"&gt;https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Function_calling_vs_free-form_generation.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Structured outputs as application contracts</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Wed, 07 Oct 2026 05:10:32 +0000</pubDate>
      <link>https://dev.to/salmonjoy/structured-outputs-as-application-contracts-34gd</link>
      <guid>https://dev.to/salmonjoy/structured-outputs-as-application-contracts-34gd</guid>
      <description>&lt;h1&gt;
  
  
  Your LLM Output Should Have a Contract, Not a Vibe
&lt;/h1&gt;

&lt;p&gt;So there I was, an AI engineer at a fintech startup, trying to turn a GPT‑4 chat into a credit‑score suggestion engine. The user typed “I just got a promotion, how much should I loan?” and the model spat back a paragraph that looked like poetry: “Congrats! Maybe $5‑10k could work, but keep your debt‑to‑income ratio low…” I tried to yank the numbers out with a regex like &lt;code&gt;/\$(\d+)-(\d+)k/&lt;/code&gt;. Spoiler: it broke the moment someone said “$5‑10 k” with a thin space or used “5‑10k” without the dollar sign. One mis‑typed hyphen and my downstream service crashed, mis‑classifying a safe applicant as risky. It felt like trying to catch a greased pig with a colander.&lt;/p&gt;

&lt;p&gt;That’s when I discovered the power of structured outputs as application contracts. Instead of hoping the model “gives me what I need”, I told it &lt;em&gt;exactly&lt;/em&gt; what shape the response must have – a JSON object that matches a JSON Schema and a typed TypeScript interface. The prompt became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"loan_range"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"medium"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"low"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the model can’t accidentally sprinkle a poem in there; it either obeys or says “I’m sorry, I can’t comply”. That refusal is a feature: my code checks &lt;code&gt;if (response.refusal) …&lt;/code&gt; and falls back to a safe default.&lt;/p&gt;

&lt;p&gt;Why is this better than regex? Regex is a brittle detective that looks for patterns in free text. Anything outside the pattern – extra whitespace, emojis, a different phrasing – sends it into a dead end. A schema validator, on the other hand, parses a proper data structure and instantly tells you which fields are missing or of the wrong type. It’s like checking a passport instead of eyeballing a face.&lt;/p&gt;

&lt;p&gt;In my edutech side‑project, we needed a list of quiz questions with “question”, “options”, and “answer”. By versioning the schema (&lt;code&gt;"$schema": "http://json-schema.org/draft-07/schema#", "title": "QuizV2"&lt;/code&gt;), we could roll out a new field “explanation” without breaking older clients. Downstream safety checks – e.g., “no option string longer than 200 chars” – are baked into the schema, so the LLM can’t hand us a monster answer that blows up the UI.&lt;/p&gt;

&lt;p&gt;A quick case study: after switching to structured outputs and enabling refusals, our fintech loan‑approval pipeline’s error rate dropped from 12% to under 1%. The only time we got a refusal was when the user asked for advice on illegal activity, and we gracefully returned a polite error message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; treat the LLM like a junior dev who follows a contract, not a poet who vibes with your mood. Define a JSON Schema, generate typed interfaces, validate, version, and let refusals be your safety net.&lt;/p&gt;

&lt;p&gt;Got a funny regex story or a schema win? Drop a comment – I’d love to hear how you’re taming your LLMs!&lt;/p&gt;

&lt;p&gt;If you are someone who loves to know the technical work and architecture design I have shared more details based on my experience on this here: &lt;a href="https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Structured_outputs_as_application_contracts.md" rel="noopener noreferrer"&gt;https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Structured_outputs_as_application_contracts.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
    <item>
      <title>Context engineering vs prompt engineering</title>
      <dc:creator>Salmon Joy</dc:creator>
      <pubDate>Tue, 06 Oct 2026 13:17:36 +0000</pubDate>
      <link>https://dev.to/salmonjoy/context-engineering-vs-prompt-engineering-1id</link>
      <guid>https://dev.to/salmonjoy/context-engineering-vs-prompt-engineering-1id</guid>
      <description>&lt;h1&gt;
  
  
  Prompt Engineering Is Too Small a Mental Model,&amp;nbsp;Think Context Architecture
&lt;/h1&gt;

&lt;p&gt;I was knee‑deep in a fintech app that tried to answer user questions about credit‑score changes. My first version was a classic “prompt engineering” hack:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“You are a friendly finance bot, explain the score drop in plain English.”  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It worked for the first few queries, then the answers got weird – sometimes the bot repeated the same disclaimer, other times it started spilling the policy docs verbatim. I was losing token budget fast and the model kept “remembering” the old disclaimer even after I removed it. I realized I was treating the whole prompt as a monolith, when in reality I was juggling five different pieces of context that should have their own lanes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter context architecture
&lt;/h2&gt;

&lt;p&gt;Think of an LLM conversation like a pizza kitchen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System instructions&lt;/strong&gt; – the chef’s recipe book; they stay on the board all night.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User state&lt;/strong&gt; – the current order ticket (what the customer just asked, plus any previous choices).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieved knowledge&lt;/strong&gt; – the pantry shelf you pull ingredients from (a database lookup of the user’s credit history).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool results&lt;/strong&gt; – the side‑dish the sous‑chef prepares (e.g., a risk‑score API call).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy&lt;/strong&gt; – the health‑inspection sticker you slap on the box to make sure you never serve raw chicken.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic happens in precedence. The model first looks at &lt;strong&gt;system instructions&lt;/strong&gt;, then layers &lt;strong&gt;user state&lt;/strong&gt;, then &lt;strong&gt;fetched knowledge&lt;/strong&gt;, then &lt;strong&gt;tool results&lt;/strong&gt;, and finally &lt;strong&gt;policy&lt;/strong&gt; overrides anything that would break compliance. If you drop a policy clause at the bottom of a huge prompt, it might never be seen because the model runs out of tokens before it gets there. That’s why you always put the “stable‑prefix” (&lt;strong&gt;system + policy&lt;/strong&gt;) at the front – it’s cached, cheap, and guarantees the model never forgets the rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token budget = pizza dough budget
&lt;/h2&gt;

&lt;p&gt;You only have so many tokens per request; if you waste them on stale context (like a disclaimer you already sent), you run out of room for the juicy answer.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contamination risk&lt;/strong&gt; is when old user state leaks into a new conversation – imagine the kitchen forgetting to clear the ticket and adding yesterday’s pepperoni to today’s vegan pizza. To avoid that, we clear the user state each session or use a fresh context window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stable‑prefix caching
&lt;/h2&gt;

&lt;p&gt;(OpenAI Prompt Caching) lets you store the &lt;strong&gt;system + policy&lt;/strong&gt; block once and reuse it across millions of calls. In my edutech project, we cached a 120‑token prefix that described the “tutor bot” persona and compliance rules. The cache cut latency by &lt;strong&gt;30 %&lt;/strong&gt; and saved us &lt;strong&gt;$2 K a month&lt;/strong&gt; on token spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case study: Fintech fraud‑alert bot
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“You are a compliance‑aware fraud analyst.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Policy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“Never reveal raw transaction IDs.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“My card was declined twice.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retrieved&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“Last 5 transactions: $23, $0, $0.”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“Risk engine returns confidence 0.92.”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The final prompt stayed under &lt;strong&gt;350 tokens&lt;/strong&gt;, the answer was spot‑on, and no policy leakage occurred.&lt;/p&gt;




&lt;p&gt;So the next time you’re tempted to dump a giant prompt into the model, pause and ask yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What belongs in &lt;strong&gt;system instructions&lt;/strong&gt;?
&lt;/li&gt;
&lt;li&gt;What’s the &lt;strong&gt;user state&lt;/strong&gt;?
&lt;/li&gt;
&lt;li&gt;What do I need to &lt;strong&gt;fetch&lt;/strong&gt;?
&lt;/li&gt;
&lt;li&gt;What &lt;strong&gt;tool results&lt;/strong&gt; am I adding?
&lt;/li&gt;
&lt;li&gt;What &lt;strong&gt;policy&lt;/strong&gt; must sit at the very front?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Build that context architecture, and you’ll spend less time chasing bugs and more time building cool features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What weird context mishap have you run into?&lt;/strong&gt; Drop a comment and let’s swap stories!&lt;/p&gt;

&lt;p&gt;If you are someone who loves to know the technical work and architecture design I have shared more details based on my experience on this here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Context_engineering_vs_prompt_engineering.md" rel="noopener noreferrer"&gt;https://github.com/SalmonJoy/My_guide_for_building_AI_systems/blob/main/Context_engineering_vs_prompt_engineering.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>enterprise</category>
    </item>
  </channel>
</rss>
