Grounded contract counsel
Lex
Answers only what the documents support
A document-grounded research chatbot over a contract set. Lex retrieves passages by embedding similarity, answers strictly from what it retrieved, and attaches a citation to every claim.
Part I
What makes it special
- 1
It declines rather than guesses
When no retrieved passage reaches the answer floor of 0.38, Lex stops before generation and says the documents do not support an answer. The refusal shows the best scores it did find and quotes each contract’s own note on what it leaves out.1
lex/agent.py · refusal“These documents do not support an answer to this, so I am not going to give one.” - 2
Every claim names its clause
Answers cite as
[MSA clause 7.2]beside the sentence they support, and the demo sets each one as a margin note quoting the clause. An audit then checks every citation against the index: a clause that does not exist is flagged, and an answer with no valid citation is withheld.2lex/agent.py · citation audit“An uncited answer from a grounded assistant is worse than no answer.” - 3
Retrieval you can read
No framework and no vector database. The contracts are split on their own clause numbering, one chunk per sub-clause, so a proviso stays with the clause it qualifies. Similarity is one numpy matrix product, and every search returns its raw scores for you to see.3
README · architecture“One chunk, one locator, one citation.” - 4
It corrects its own wrong guess
Ask
fetch_clausefor a clause that is not there and it returnsClauseNotFoundwith the list that is. In the third question Lex guesses DPA clause 11.2, reads the miss, and searches for the text instead of guessing again.4lex/agent.py · system prompt“…read the list of available clauses it returns and search again instead of guessing a second time.”
Part II - on the docket
Inside the demo
3 questions over the same two contracts.
- No. 1Terminate mid-SOW?One clause, and the proviso in its second half reverses the answer.
- No. 2Governing law in Singapore?Outside the corpus: nothing clears the floor, so Lex refuses and shows the scores.
- No. 3Cap vs. breach noticeSpans both documents, and a guessed clause locator comes back not-found mid-run.
Part III - apparatus
Under the hood
How Lex is built
- Stack
- OpenAI SDK · Python
- Pattern
- Embedding retrieval + citation-constrained generation
Why this architecture
A hand-built RAG pipeline keeps retrieval inspectable: you can see the chunker, the index, the similarity scores and the exact passages that reached the model. No framework hides the step that is most likely to be the reason an answer is wrong.
Tools
search_corpusread-onlyRetrieve the most relevant document passages for a query, with scores.fetch_clauseread-onlyFetch the full text of a numbered clause from a named document.
Real source
agents/lex-counsel/agents/lex-counsel/lex/agent.py
- openai
- numpy
Before you go in
Watch for The question the corpus cannot answer. Lex returns an explicit "not supported by these documents" rather than a confident paraphrase: the behaviour that makes RAG trustworthy.
Take a look inside