[CASE STUDY 09][IN DEVELOPMENT]

Agentic RAG Document Research Agent

A multi-tenant research assistant that answers questions over a team's documents and the web with inline citations, and has a second model verify each answer. On a 110-case benchmark against my first version, the rebuild answered more accurately, 95.3% against 91.1% on content checks, reached first token in half the time and cost 39% less per turn.

Role
AI & Full-Stack Engineer — end to end
Timeline
Sep 2026 – Present
Status
In development
Stack
Next.js 16, TypeScript, LangGraph +5
Agentic RAG turn: a question passes admission checks; a rules router sets the route first, then on a document turn search runs in code, fusing dense and keyword results and reranking them; the LangGraph agent answers from them and is told to cite each claim; the answer streams first, its citations are checked and sources follow, a separate model checks groundedness and a badge shows the result; delegated research, under the Deep agents toggle, takes a separate path of journalled branches that a restart resumes

* ONE TURN, END TO END

Agentic RAG: One turn, end to end

[AT A GLANCE]

OWNED
End to end: the agent runtime, retrieval and indexing, answer verification, durable research, the streaming chat client and the benchmark harness
PRODUCT
Multi-tenant workspaces with Google and GitHub sign-in, invites, an audit log and data purge; Team $49/mo (2,000 turns, 10 seats) and Scale $299/mo (20,000 turns, 50 seats) plans wired to Stripe
MEASURED BY
A 110-case benchmark with known answers across facts, synthesis, refusals, reasoning, faults and citations, run through the app's real chat route
STATUS
Pre-launch: benchmarked on a five-document test corpus, with no customers yet
NOT MINE
The models and services: chat models from several providers, Cohere embeddings and reranking, Qdrant, MongoDB, AWS S3, LangGraph's MongoDB checkpointer, Deep Agents for the research branches, Tavily web search, and TypeSafe's Jev decision model as the verifier

[STACK]

  • Next.js 16
  • TypeScript
  • LangGraph
  • LangChain
  • Qdrant
  • Cohere Rerank
  • MongoDB
  • LangSmith

[01] The problem

Sourced-looking is not sourced

Teams want answers from their own documents, with each claim traceable to its source. Document assistants fail quietly in two ways: answers that look cited but are not supported, and refusals of questions the documents can answer. My first version took 11.5 s to its first token at the median, and its quality was judged by reading answers one at a time, which had already missed an unindexed document for days.

[02] The constraints

What dependable RAG had to survive

  1. Unreliable providers are the operating condition

    Most model routes run on free tiers, so quotas, refused keys and dead routes are routine. The runtime has to fail over in seconds, not minutes, and a quota failure must never read as a quality regression in the benchmark.

  2. The benchmark has to exercise the real route

    Guardrails, citation rewriting and streaming all sit behind the chat route, and each had produced a defect invisible one layer below. Every case runs through that route, and deterministic checks on the stored answer decide pass or fail.

  3. Verification cannot hold the answer back

    A second model checking every answer adds a round trip. The answer streams first, its sources follow, and the grounded badge arrives when the check completes; offline, a check takes a median of 0.49 s.

[03] The approach

How it was built

I scored my first version and the rebuild side by side on the same 110 cases, audited the harness, fixed fifteen of its defects and scored both again. The rebuilt runtime retrieves in code before the agent's first call, routes turns with rules, has a separate model verify each answer against its evidence and checkpoints only the turns that delegate research.

[KEY DECISIONS]

  1. [01]Scored my first version and the rebuild on the same 110 cases, then audited the harness, fixed fifteen defects and scored both again.
  2. [02]Ran search in code before the agent's first call: dense and BM25 results fused with reciprocal rank fusion, then reranked with Cohere.
  3. [03]Routed turns with rules, which beat a model router on intent accuracy at no added cost.
  4. [04]Verified groundedness with a separate model, with the chat-model judge as an automatic fallback.
  5. [05]Put a deadline on every provider and chain, so a dead or hung provider costs seconds, not minutes.

[04] The trade-offs

What each measured change cost

  1. [01]

    Retrieve in code before the agent's first call

    Instead of
    Make the model call the search tool first
    What it cost
    When a model rather than the rules router picks the route, a greeting triggers a wasted search.
    What it bought
    With the turn plan, agent calls fell from 2.19 to 1.15 a turn and median latency from 10.0 s to 5.7 s on the same 110 cases.
  2. [02]

    Route turns with rules, not a model

    Instead of
    A model-based intent router on every turn
    What it cost
    Rules are maintained by hand as new kinds of question appear, and the model was better at spotting multi-hop questions, 89.1% against 76.4%.
    What it bought
    Rules scored 93.6% intent accuracy against the model's 84.5%, which sent plain document questions to the web, at no added latency or cost.
  3. [03]

    A separate model verifies groundedness

    Instead of
    Let a chat model from the answering chain judge its own answers
    What it cost
    An early-access dependency; when it is unavailable, the chat-model judge takes over automatically.
    What it bought
    In three runs it passed none of 28 planted errors; the chat-model judge passed 8 in each of its two runs. A check costs about $0.00002.
  4. [04]

    Checkpoint delegated research turns only

    Instead of
    A workflow engine such as Temporal, or a checkpoint on every turn
    What it cost
    Up to 1.9 s added to each delegated turn in a stubbed test, after checkpoint writes were cut from 111 to 4 a turn.
    What it bought
    In a crash test with a shortened lease, a research turn killed mid-run was answered 53.6 s later with no one asking again; without checkpoints it was never answered.

[05] The build

What Agentic RAG is made of

  • [01]

    Answers a reader can check

    Answers stream with inline citations to the documents and web pages they draw on, then a sources list, then a grounded badge once the verifier has checked the answer. Users pick Brief, Standard or Deep effort, switch on web search, or hand a question to parallel research agents. The client re-renders only the part of an answer that changed: in a server-side benchmark on a 12 KB answer, render work fell 25-fold.

  • [02]

    Hybrid search before the first call

    For a document question, the rules router sets the route and search runs in code: dense and BM25 results fused by reciprocal rank fusion, then reranked by Cohere, and handed to the LangGraph agent as if it had searched. Searches scoring below a relevance floor of 0.35, set from measured scores, are flagged to the model as weak evidence rather than dropped.

  • [03]

    An index that keeps the whole document

    Chunking and keyword search were reworked. On one test PDF, lines missing from the index fell from 11 to 0 and chunks citing the wrong page from 16 to 0. Keyword search over a synthetic 50,000-chunk index fell from 23.1 ms to 3.8 ms, and a conversation's own documents are now found even when they rank outside the workspace's top 120.

Agentic RAG benchmark: 110 cases with known answers go through the app's real chat route on an eval server; deterministic checks on the stored answer decide pass or fail; one external judge, on a model no arm uses, scores groundedness afterwards; runs append to a log; Run 010 sets the first version beside the rebuild, one run each on the same day and providers: answer correctness 91.1% against 95.3%, tool selection 95.0% against 98.1%, median latency 13.8 s against 7.5 s, median time to first token 11.5 s against 5.5 s, and reference cost per turn $0.00234 against $0.00142

A benchmark that runs the real route

[04]

A benchmark that runs the real route

All 110 cases go through the app's real chat route. Deterministic checks on the stored answer decide pass or fail; one external judge, on a model no arm answers with, scores groundedness afterwards; and every run is appended to a log, never overwritten. An audit of the harness fixed fifteen defects, one of which had let every arm score 100% on citations.

  • [05]

    A second model checks every answer

    A separate verifier checks each answer against its evidence, and one without evidence is marked unverified. On 42 labelled answers, it passed none of the 28 planted errors in three runs; the chat-model judge passed 8 in each of its two. In the latest run it scored 97.6%, flagging one correct answer of 14.

  • [06]

    Failover in seconds, not minutes

    Auxiliary calls have deadlines of 20 s per provider and 45 s per chain, the answering model a 30-second first-byte deadline, and refused keys are benched. With the primary provider failing, a stubbed turn now finishes in 2.1 s instead of 22.1 s; a provider that accepts a call and never answers is abandoned at the first-byte deadline; and when the verifier's credit ran out mid-benchmark, the fallback judge took over unattended.

  • [07]

    Research that survives a crash

    Delegated research runs as parallel document and web branches, journalled to MongoDB. In a crash test with a 10-second lease (production uses 45), a turn killed mid-research was answered 53.6 s after the kill, with no one asking again. Checkpoint writes per delegated turn fell from 111 to 4, and their storage from 355 KB to 15 KB.

[06] What broke

And what fixed it

  1. !01

    The primary model served none of the traffic

    The first 110-case run showed the configured primary model answered 0 of 110 turns: every call walked about a dozen failing routes before one answered, and two exhausted rerank keys cost about 10 s a search. Fixing the provider layer cut median latency by 49%, lifted task success by 4.5 points and took failed turns from 2.7% to zero.

  2. !02

    Every new conversation's first message failed

    Only the real client showed it, because the hand-run tests left the field out: the chat API rejected a null thread ID, so the first message of every new conversation returned a 400. The API now accepts one.

  3. !03

    The citation score could not fail

    An audit of the harness found citations were scored after the server had stripped invalid markers, so every arm scored 100%. Scored on what the model actually wrote, each arm carried one fabricated marker; the audit fixed fifteen harness defects in all.

[07] The result

What the benchmark measured

  • 95.3%

    Answer correctness

    * content checks, 110 cases; first version 91.1%

  • 5.5 s

    Time to first token, p50

    * first version 11.5 s; p95 18.3 s against 31.8 s

  • −39%

    Cost per turn

    * $0.00142 against $0.00234, reference prices

  • 0 / 28

    Planted errors passed

    * verifier, three runs; chat-model judge 8 / 28 twice

[HOW THESE WERE MEASURED]

Answer correctness, latency and cost come from Run 010 on 24 September 2026: my first version and the rebuild on the same 110 cases, same day and providers, one run each, over a five-document test corpus, with every token priced at one model's list rate. Task success, 101 of 110 against 97, is within noise, since three of the first version's misses were a judge's provider hanging, and groundedness, last judged in Run 005, was level. The rest come from Run 005 for the call and latency gains, Run 012 for routing, three runs over 42 labelled answers for the verifier, stubbed or synthetic benchmarks for rendering, indexing, failover and checkpoints, and one crash test on an earlier build. None of it measures real users; there are none yet.

[08] What I’d do differently

Honestly

I'd budget three runs per arm from the start. In one re-scoring, two arms two rows apart disagreed on eight rows, so a single pass cannot separate a four-row lead from noise.

Written by Faizan Amir

Role on Agentic RAG: AI & Full-Stack Engineer — end to end

Last reviewed

Need something like this built?

Next case study [01]

AI Mini-Site Builder

Read the case study →

AVAILABLE FOR SENIOR ENGINEERING WORK + REACT + NEXT.JS + NODE.JS + PYTHON + RAG + AGENTIC AI