Skip to content

Ridhi Dua

Case study

Legal & Compliance Search & Discovery

Turning a Contract Audit Into a Search Query

Close-up of a hand signing a paper contract at a desk.
Photo by Scott Graham on Unsplash

A semantic search layer over 510 commercial contracts finds the clause that matters and cites the exact sentence it came from.

Problem

An audit request lands on a Friday

A compliance team is told to produce every vendor and licensing agreement with a Most Favored Nation clause, an Audit Rights provision, or an uncapped indemnity, ahead of a regulator’s information request. The portfolio runs to several hundred contracts. None are tagged by clause type.

A keyword search for “audit” finds the word. It does not find the sentence that grants the right, thirty pages into an addendum.

Approach

Search the clause, not the file

The fix is an index built for clauses, not files. Every contract is split into passages and embedded, then indexed in Qdrant. A query like “audit rights” or “change of control trigger” retrieves the passages closest in meaning, including ones that never use those exact words. (Technically: dense vector retrieval with all-MiniLM-L6-v2 embeddings.)

Each match is then re-scored sentence by sentence against the query, so the one sentence doing the work gets highlighted, not the paragraph around it. (Technically: cross-encoder reranking with bge-reranker-v2-m3.)

A retrieval-grounded chat sits on the same index. Ask “which of these agreements cap liability below $1M?” and the answer cites the passages it came from, not a model’s general memory of contract law.

How it works

Query to citation, in four hops


The chat model never answers from memory alone, and every result links back to the source PDF.

In practice

What the reviewer sees

A reviewer searching the audit rights question doesn’t get a document list. They get the clause, in context, with the sentence that matters marked.

MASTER_SERVICES_AGREEMENT_2019.pdf, p. 14, §9.2

Vendor shall maintain accurate books and records relating to this Agreement, and Client, or its designated independent auditor, may inspect and audit such records upon thirty (30) days’ written notice, no more than once per calendar year, at Client’s expense, during Vendor’s normal business hours.

The same mechanism runs on the categories compliance teams ask for most:

  • ›Audit Rights
  • ›Change of Control
  • ›Most Favored Nation
  • ›Cap on Liability
  • ›Anti-Assignment
  • ›IP Ownership Assignment

Outcome

One query, not one file at a time

A portfolio of 500 contracts at 10 minutes of manual review each runs to roughly 80 hours per sweep. Clause search cuts that to the time it takes to read the results. (Illustrative estimate, not a measured client result.)

The harder win is what happens next time. A new regulation naming a clause type the portfolio was never tagged for doesn’t mean opening every file again. It means writing one query, with every result citing the sentence it came from.

Evidence

What isn’t solved yet

Engineering note

Latency scales with chunk count, not query complexity. The sentence-level highlighter calls the reranker once per sentence, in sequence. At the default top_k of 10, with 15 to 25 sentences per chunk, one search can mean 150 to 250 round trips to the inference API before a result renders. Batching that call is next on the project’s own roadmap, not a hidden defect.

The corpus is worth naming plainly too. CUAD is a public research dataset of historical commercial contracts, standing in here for a firm’s live matter files. Moving this from illustration to production means pointing the same architecture at a real, access-controlled repository, with the audit trail that implies.

Let’s talk about your problem.

Book a consultation