|

LlamaIndex ‘legal-kb’: Agentic Retrieval over Index v2 with retrieve, find, read, and grep Tools

📄

LlamaIndex has revealed legal-kb, a public reference utility on GitHub. It is described as a data base for authorized paperwork, powered by LlamaIndex Index v2 (the LlamaParse Platform). The venture demonstrates a sample the crew calls a Retrieval Harness for agentic retrieval.

The method differs from single-shot retrieval. Instead of 1 embedding search per question, an agent is given filesystem-style instruments. It can then crawl a big, evolving data base to resolve a process. The instruments mirror operations engineers already know: semantic and key phrase search, regex grep, file search, and learn.

legal-kb is a working TanStack Start net app, not a library. You check in, create a venture, add information, and chat with an agent. Each venture is mirrored as a managed LlamaCloud Index v2. Uploaded information are parsed and listed robotically within the background. The chat agent then queries that index stay throughout every flip.

The Retrieval Harness, in plain phrases

The harness gives a persistent knowledge pipeline over your paperwork. It connects to a knowledge supply, indexes it, and retains it up to date. On high of that pipeline, it exposes a set of instruments to the agent.

Those instruments are intentionally near filesystem operations. An agent can listing information, learn a file, grep inside a file, or run hybrid search. Because the instruments are generic, you possibly can plug the harness into your personal brokers.

The 4 agent instruments

The agent in src/lib/agent.ts is given 4 instruments. Each maps to an Index v2 retrieval API. The desk beneath lists them as applied.

Tool Backing API Key parameters What it does
retrieve beta.retrieval.retrieve question, top_k, score_threshold, rerank_top_n, file_name, file_version Runs hybrid semantic search; optionally available reranking; returns chunks plus citations
discoverFiles beta.retrieval.discover file_name, file_name_contains Searches information by precise identify or substring; paginates robotically
learnFile beta.retrieval.learn file_id, offset, max_length Reads uncooked file content material, with offset and size home windows
grepFile beta.retrieval.grep file_id, sample, context_chars, restrict Matches a sample in a single file; returns character positions

The system immediate enforces an order. The agent should name discoverFiles first to ascertain the doc stock. It then narrows with retrieve, and confirms precise wording with learnFile or grepFile earlier than citing.

How it really works underneath the hood

Uploads observe a transparent pipeline in src/lib/information.ts. Bytes are pushed to the venture’s LlamaCloud supply listing. A File and VentureFile row are written to PostgreSQL through Prisma. An index sync is triggered however not awaited; the UI polls standing till prepared.

Versioning is scoped to the (venture, filename) pair. Re-uploading nda.pdf to the identical venture produces v1, v2, v3 facet by facet. The retrieval layer filters on the model metadata discipline. This offers model management over the data base itself.

The agent makes use of the ToolLoopAgent from Vercel AI SDK 6. You choose OpenAI or Anthropic per flip and convey your personal keys. Reasoning is streamed: Claude fashions use prolonged considering; OpenAI reasoning fashions use a medium reasoning effort.

Here is a condensed however trustworthy view of the retrieve device and the agent.

import { LlamaCloud } from '@llamaindex/llama-cloud'
import { device, ToolLoopAgent } from 'ai'
import { z } from 'zod'
import { makeCitationId } from './citations'

// One device closure per index. Wraps Index v2 retrieval APIs.
operate createLlamaParseTools(apiKey: string, projectId: string, indexId: string) {
  const shopper = new LlamaCloud({ apiKey })

  const retrieve = device({
    description: 'Run a semantic retrieval question in opposition to an index.',
    inputSchema: z.object({
      question: z.string(),
      top_k: z.quantity().nullable(),
      score_threshold: z.quantity().nullable(),
      rerank_top_n: z.quantity().nullable(),   // set to allow reranking
      file_name: z.string().nullable(),      // metadata filter
      file_version: z.quantity().nullable(),
    }),
    execute: async ({ question, top_k, score_threshold, rerank_top_n, file_name }) => {
      const custom_filters = file_name
        ? { file_name: { operator: 'eq' as const, worth: file_name } }
        : undefined

      const response = await shopper.beta.retrieval.retrieve({
        index_id: indexId,
        project_id: projectId,
        question,
        top_k,
        score_threshold,
        rerank: rerank_top_n != null ? { enabled: true, top_n: rerank_top_n } : undefined,
        custom_filters,
      })

      // Return a model-readable listing plus citations that drive the UI chips.
      const citations = response.outcomes.map((r) => ({
        id: makeCitationId(),                    // e.g. "c7f2qa"
        fileName: r.metadata?.file_name,
        rating: r.rerank_score ?? r.rating ?? null,
        preview: r.content material.slice(0, 500),
      }))
      const formatted = response.outcomes
        .map((r, i) => `### Result #${i + 1}nn${r.content material.slice(0, 600)}`)
        .be part of('nn---nn')
      return { formatted, citations }
    },
  })

  // discoverFiles / learnFile / grepFile observe the identical form, backed by
  // shopper.beta.retrieval.discover / .learn / .grep
  return { retrieve /* , discoverFiles, learnFile, grepFile */ }
}

export operate constructAgent(mannequin, apiKey: string, projectId: string, indexId: string) {
  return new ToolLoopAgent({
    mannequin,
    instruments: createLlamaParseTools(apiKey, projectId, indexId),
    directions:
      'Always name discoverFiles first, floor each reply within the paperwork, ' +
      'and cite ids inline as `cite:<id>`.',
  })
}

Answers carry visible citations. Each retrieved chunk will get a brief id, resembling cite:c7f2qa. The agent references that id inline, and the UI renders a clickable quotation chip. Clicking it opens the supply web page screenshot with bounding-box rectangles over the cited textual content.

Naive RAG vs the agentic Retrieval Harness

The harness is a unique execution mannequin from single-shot RAG. The comparability beneath focuses on conduct.

Dimension Naive / single-shot RAG Agentic Retrieval Harness (Index v2)
Retrieval circulation One vector search per question Multi-step device loop: discover → retrieve → learn/grep
Search modes Vector similarity solely Hybrid semantic search, key phrase, and regex grep
Context Fixed top-k chunks Agent reads full information or home windows on demand
Freshness Static index Persistent pipeline with sync and versioning
Precision management Mostly hidden top_k, score_threshold, rerank_top_n uncovered
Citations Chunk ids Visual citations with web page screenshots and bboxes
Best match Short query answering Long-horizon doc duties

Use instances, with examples

The design targets domains the place brokers navigate massive doc units. Legal and fintech are the acknowledged examples.

  • Consider a contract query: ‘What discover is required to terminate the MSA?’ The agent lists information, runs retrieve, then greps the precise clause. It solutions with a quotation to the particular web page.
  • Consider due diligence throughout an information room: An agent can discoverFiles by identify, then learnFile every candidate. It cross-checks clauses and not using a human opening each PDF.
  • Consider a versioned coverage base: Because retrieve accepts a file_version filter, an agent can question a selected model. This helps change monitoring over time.

Reference implementation

</div>
<div><div class=”fn”>Mutual_NDA.pdf<span class=”ver”>v2</span></div><div class=”meta”>parsed · listed · prepared</div></div>
</div>
<div class=”file” data-fn=”MSA_Acme_Vendor.pdf”>
<div class=”doc”>📄</div>
<div><div class=”fn”>MSA_Acme_Vendor.pdf<span class=”ver”>v1</span></div><div class=”meta”>parsed · listed · prepared</div></div>
</div>
<div class=”file” data-fn=”Employment_Agreement.pdf”>
<div class=”doc”>📄</div>
<div><div class=”fn”>Employment_Agreement.pdf<span class=”ver”>v1</span></div><div class=”meta”>parsed · listed · prepared</div></div>
</div>
<div class=”instruments”>
<h2>Agent Tools</h2>
<div class=”device”><code>retrieve</code> hybrid semantic search</div>
<div class=”device”><code>discoverFiles</code> file search by identify</div>
<div class=”device”><code>learnFile</code> learn uncooked content material</div>
<div class=”device”><code>grepFile</code> regex sample match</div>
</div>
</div>

<div class=”important”>
<div class=”chips” id=”chips”></div>
<div class=”feed” id=”feed”>
<div class=”empty” id=”empty”>Pick a query above, or sort your personal. The agent all the time calls <code>discoverFiles</code> first to ascertain the doc stock, then narrows with <code>retrieve</code>, then confirms precise wording with <code>learnFile</code> or <code>grepFile</code> earlier than citing.</div>
</div>
<div class=”composer”>
<enter id=”q” placeholder=”Ask about termination, non-compete, fee phrases…” autocomplete=”off”>
<button id=”go”>Run</button>
</div>
</div>
</div>

<div class=”ftr”>
<div>Interactive demo · <b>Marktechpost</b> — modeled on run-llama/legal-kb (Index v2 / LlamaParse Platform)</div>
<div><a href=”https://github.com/run-llama/legal-kb” goal=”_blank” rel=”noopener”>github.com/run-llama/legal-kb ↗</a></div>
</div>

<div class=”modal” id=”modal”>
<div class=”card”>
<div class=”ch”><div class=”t” id=”mt”>Citation</div><div class=”x” id=”mx”>✕</div></div>
<div class=”shot” id=”shot”></div>
<div class=”pv”><div class=”lab”>Retrieved chunk</div><div id=”mpv”></div></div>
</div>
</div>
</div>

<script>
(operate(){
var root=doc.getElementById(‘mtp-harness’);
// — Knowledge base (illustrative content material) —
var INTENTS=[{
key:’termination’,kw:[‘terminat’,’cancel’,’convenience’,’notice’,’end the contract’,’exit’],
file:’MSA_Acme_Vendor.pdf’,ver:1,web page:6,rating:0.912,
question:’termination rights and required discover interval’,
chunk:’Either celebration might terminate this Master Services Agreement for comfort upon thirty (30) days prior written discover. Termination for trigger is efficient instantly upon written discover of a cloth breach that continues to be uncured after fifteen (15) days.’,
grep:’terminate this Master Services Agreement for comfort upon thirty (30) days’,
reply:’The MSA permits both celebration to terminate for comfort with thirty (30) days prior written discover §CITE§. Termination for trigger is quick after an uncured materials breach of fifteen (15) days §CITE2§.’,
bbox:{x:14,y:38,w:78,h:20}
},{
key:’confidential’,kw:[‘confidential’,’nda’,’term’,’how long’,’duration’,’secret’,’disclos’],
file:’Mutual_NDA.pdf’,ver:2,web page:2,rating:0.934,
question:’confidentiality obligations and survival time period’,
chunk:’The confidentiality obligations set forth herein shall survive for a interval of three (3) years following the termination or expiration of this Agreement. Confidential Information excludes info that turns into publicly accessible by means of no fault of the receiving celebration.’,
grep:’shall survive for a interval of three (3) years following the termination’,
reply:’Confidentiality obligations survive three (3) years after termination or expiration of the NDA §CITE§. Publicly accessible info is excluded from Confidential Information §CITE2§.’,
bbox:{x:12,y:30,w:80,h:22}
},{
key:’fee’,kw:[‘payment’,’net’,’invoice’,’pay’,’fees’,’billing’,’net 45′],
file:’MSA_Acme_Vendor.pdf’,ver:1,web page:4,rating:0.897,
question:’fee phrases and invoicing schedule’,
chunk:’Vendor shall bill month-to-month in arrears. Undisputed invoices are payable inside forty-five (45) days of receipt (Net 45). Late funds accrue curiosity at 1.0% per 30 days or the utmost charge permitted by legislation, whichever is decrease.’,
grep:’payable inside forty-five (45) days of receipt (Net 45)’,
reply:’Undisputed invoices are payable Net 45, inside forty-five (45) days of receipt §CITE§. Late funds accrue 1.0% month-to-month curiosity or the authorized most §CITE2§.’,
bbox:{x:14,y:34,w:76,h:18}
},{
key:’noncompete’,kw:[‘non-compete’,’noncompete’,’compete’,’restrict’,’employ’,’12 month’],
file:’Employment_Agreement.pdf’,ver:1,web page:5,rating:0.921,
question:’non-compete restriction scope and length’,
chunk:’For twelve (12) months following the termination of employment, the Employee shall not have interaction in any enterprise that straight competes with the Company throughout the territories the place the Company actively operates.’,
grep:’For twelve (12) months following the termination of employment’,
reply:’The non-compete restricts the Employee for twelve (12) months after termination of employment §CITE§. It is proscribed to territories the place the Company actively operates §CITE2§.’,
bbox:{x:13,y:40,w:78,h:16}
},{
key:’legal responsibility’,kw:[‘liabilit’,’cap’,’damages’,’indemnif’,’limitation’],
file:’MSA_Acme_Vendor.pdf’,ver:1,web page:8,rating:0.905,
question:’limitation of legal responsibility and damages cap’,
chunk:”Each celebration’s mixture legal responsibility underneath this Agreement shall not exceed the full charges paid or payable within the twelve (12) months previous the declare. Neither celebration is responsible for oblique, incidental, or consequential damages.”,
grep:’mixture legal responsibility underneath this Agreement shall not exceed the full charges’,
reply:’Aggregate legal responsibility is capped on the charges paid or payable within the prior twelve (12) months §CITE§. Indirect, incidental, and consequential damages are excluded §CITE2§.’,
bbox:{x:12,y:36,w:80,h:20}
},{
key:’governing’,kw:[‘governing’,’law’,’jurisdiction’,’delaware’,’venue’,’court’],
file:’Mutual_NDA.pdf’,ver:2,web page:3,rating:0.888,
question:’governing legislation and jurisdiction clause’,
chunk:’This Agreement shall be ruled by and construed in accordance with the legal guidelines of the State of Delaware, with out regard to its conflict-of-laws ideas. The events consent to unique jurisdiction within the state and federal courts positioned in Delaware.’,
grep:’ruled by and construed in accordance with the legal guidelines of the State of Delaware’,
reply:’The NDA is ruled by the legal guidelines of the State of Delaware §CITE§. The events consent to unique jurisdiction in Delaware state and federal courts §CITE2§.’,
bbox:{x:13,y:32,w:78,h:18}
}];

var CHIPS=[
[‘How much notice is needed to terminate the MSA?’,’termination’],
[‘How long do confidentiality obligations last?’,’confidential’],
[‘What are the payment terms?’,’payment’],
[‘What is the non-compete duration?’,’noncompete’],
[‘What is the liability cap?’,’liability’],
[‘Which law governs the NDA?’,’governing’]
];

var feed=root.querySelector(‘#feed’), empty=root.querySelector(‘#empty’);
var enter=root.querySelector(‘#q’), go=root.querySelector(‘#go’);
var chipWrap=root.querySelector(‘#chips’);
var busy=false;

CHIPS.forEach(operate(c){
var b=doc.createElement(‘div’);b.className=’chip’;b.textContent=c[0];
b.onclick=operate(){ if(!busy){ enter.worth=c[0]; run(c[1]); } };
chipWrap.appendChild(b);
});

operate rid(){var s=’abcdef0123456789′,o=’c’;for(var i=0;i<5;i++)o+=s[Math.floor(Math.random()*s.length)];return o;}
operate esc(t){return t.change(/&/g,’&amp;’).change(/</g,’&lt;’).change(/>/g,’&gt;’);}

operate match(textual content){
var t=textual content.toLowerCase(),greatest=null,hit=0;
INTENTS.forEach(operate(it){
var c=0; it.kw.forEach(operate(ok){ if(t.indexOf(ok)>-1)c++; });
if(c>hit){hit=c;greatest=it;}
});
return greatest;
}

operate litFile(fn){
root.querySelectorAll(‘.file’).forEach(operate(f){
f.classList.toggle(‘lit’, f.getAttribute(‘data-fn’)===fn);
});
}

operate addStep(cls,label,html,delay){
return new Promise(operate(res){
setTimeout(operate(){
var s=doc.createElement(‘div’);s.className=’step’;
s.innerHTML='<div class=”bubble ‘+cls+'”>’+label+'</div>’+html;
feed.appendChild(s); ping(); res();
},delay);
});
}

var C1,C2;
operate run(driveKey){
if(busy)return; busy=true; go.disabled=true;
if(empty)empty.fashion.show=’none’;
feed.innerHTML=”;
var it = driveKey ? INTENTS.filter(operate(x){return x.key===driveKey;})[0] : match(enter.worth||”);
C1=rid(); C2=rid();

if(!it){
addStep(‘discover’,’discoverFiles’,callHTML(‘discoverFiles’,{},’3 information: Mutual_NDA.pdf (v2), MSA_Acme_Vendor.pdf (v1), Employment_Agreement.pdf (v1)’),150)
.then(operate(){ return addStep(‘ans’,’reply’,'<div class=”reply”>The listed paperwork don’t comprise sufficient info to reply that. Try termination, confidentiality, fee phrases, non-compete, legal responsibility, or governing legislation.</div>’,700); })
.then(accomplished); return;
}

litFile(it.file);

// 1) discoverFiles (all the time first)
addStep(‘discover’,’discoverFiles’,callHTML(‘discoverFiles’,{},’3 information listed · ‘+it.file+’ (v’+it.ver+’) is a candidate’),150)
// 2) retrieve (hybrid search)
.then(operate(){ return addStep(”,’retrieve’,callHTML(‘retrieve’,{question:it.question,top_k:5,rerank_top_n:3},null),820); })
.then(operate(){ return addStep(”,’outcomes’,retrieveResults(it),780); })
// 3) grep to verify precise wording
.then(operate(){ return addStep(‘grep’,’grepFile’,callHTML(‘grepFile’,{file:it.file,sample:it.grep.slice(0,32)+’…’},’1 match confirmed on p.’+it.web page),820); })
// 4) grounded reply with citations
.then(operate(){ return addStep(‘ans’,’reply’,'<div class=”reply”>’+answerHTML(it)+'</div>’,780); })
.then(accomplished);
}

operate accomplished(){ busy=false; go.disabled=false; }

operate callHTML(identify,args,notice){
var a=Object.keys(args).map(operate(ok){
var v=args[k];
var val = typeof v===’quantity’ ? ‘<span class=”n”>’+v+'</span>’ : ‘<span class=”s”>”‘+esc(String(v))+'”</span>’;
return ‘<span class=”ok”>’+ok+'</span>: ‘+val;
}).be part of(‘<span class=”dim”>, </span>’);
var line='<div class=”name”><span class=”dim”>→ device</span> ‘+identify+'(<span class=”dim”>{ </span>’+a+'<span class=”dim”> }</span>)’;
if(notice) line+='<br><span class=”dim”>✓ ‘+esc(notice)+'</span>’;
line+='</div>’;
return line;
}

operate retrieveResults(it){
var s2=(it.score-0.14).toFixed(3);
var h='<div class=”outcome”>’+
‘<div class=”rrow”><div class=”high”><span>Result #1 · ‘+it.file+’ · p.’+it.web page+'</span><span class=”rating”>rating ‘+it.rating.toFixed(3)+’ · <span class=”cid”>cite:’+C1+'</span></span></div>’+esc(it.chunk.slice(0,150))+’…</div>’+
‘<div class=”rrow”><div class=”high”><span>Result #2 · ‘+it.file+’ · p.’+it.web page+'</span><span class=”rating”>rating ‘+s2+’ · <span class=”cid”>cite:’+C2+'</span></span></div>’+esc(it.chunk.slice(120,250))+’…</div>’+
‘</div>’;
return h;
}

operate answerHTML(it){
var html=esc(it.reply)
.change(‘§CITE§’,'<span class=”citechip” data-c=”1″>cite:’+C1+'</span>’)
.change(‘§CITE2§’,'<span class=”citechip” data-c=”2″>cite:’+C2+'</span>’);
// stash for modal
root._cur=it;
return html;
}

// quotation modal
var modal=root.querySelector(‘#modal’), shot=root.querySelector(‘#shot’),
mpv=root.querySelector(‘#mpv’), mt=root.querySelector(‘#mt’);
feed.addEventListener(‘click on’,operate(e){
var chip=e.goal.closest(‘.citechip’); if(!chip)return;
var it=root._cur; if(!it)return;
mt.textContent=it.file+’ · web page ‘+it.web page+’ · v’+it.ver;
shot.innerHTML='<div fashion=”opacity:.55″>’+esc(it.chunk)+'</div>’+
‘<div class=”bbox” fashion=”left:’+it.bbox.x+’%;high:’+it.bbox.y+’%;width:’+it.bbox.w+’%;peak:’+it.bbox.h+’%”></div>’;
mpv.textContent=it.chunk;
modal.classList.add(‘on’); ping();
});
root.querySelector(‘#mx’).onclick=operate(){modal.classList.take away(‘on’);ping();};
modal.onclick=operate(e){ if(e.goal===modal){modal.classList.take away(‘on’);ping();} };

go.onclick=operate(){ run(null); };
enter.addEventListener(‘keydown’,operate(e){ if(e.key===’Enter’)run(null); });

// auto-resize for WordPress embed
operate ping(){
attempt{
var h=doc.getElementById(‘mtp-harness’).offsetHeight+40;
mother or father.postMessage({sort:’mtp-harness-height’,peak:h},’*’);
}catch(e){}
}
window.addEventListener(‘load’,ping);
window.addEventListener(‘resize’,ping);
setTimeout(ping,300);
})();
</script>
</physique>
</html>

fashion=”width:100%;peak:600px;border:0;overflow:hidden;”
scrolling=”no”
loading=”lazy”
title=”Agentic Retrieval Harness — Interactive Demo”>

Key Takeaways

  • legal-kb is a public reference app exhibiting agentic retrieval on LlamaIndex Index v2.
  • The agent will get 4 filesystem-style instruments: retrieve (hybrid search), discoverFiles, learnFile, and grepFile.
  • A persistent pipeline handles parsing, indexing, sync, and per-file model management.
  • Answers embody visible citations: web page screenshots with bounding bins over the cited textual content.
  • The stack is TanStack Start, AI SDK 6, Prisma, and WorkOS, with per-user encrypted keys.


Check out the GitHub Repo. Also, be at liberty to observe us on Twitter and don’t overlook to hitch our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

Need to companion with us for selling your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar and many others.? Connect with us

The put up LlamaIndex ‘legal-kb’: Agentic Retrieval over Index v2 with retrieve, find, read, and grep Tools appeared first on MarkTechPost.

Similar Posts