---
title: Ten model calls per contract review, zero external APIs
description: "Walk through the SIE contract-review-agent example: a multi-agent contract reviewer on the OpenAI Agents SDK with every model call served locally."
canonical_url: https://superlinked.com/blog/contract-review-agent
last_updated: 2026-08-10
---

*This article walks through [contract-review-agent](https://github.com/superlinked/sie/tree/main/examples/contract-review-agent), a workable example from the open-source [SIE repo](https://github.com/superlinked/sie) on GitHub: a multi-agent contract reviewer built on the OpenAI Agents SDK, with every model call served locally. SIE is Superlinked's self-hosted inference engine, one cluster that serves embedding, reranking, OCR, vision, entity-extraction, and generation models behind three primitives (extract, encode, score). The example is a complete project you can clone and run against real SEC-filed contracts. Built by Superlinked.*

Count the model calls in a serious contract review agent. Triage to decide what kind of document arrived. Vision to read the signature page. OCR for the scanned exhibit. Embeddings to find relevant clauses, a reranker to order them, entity extraction to pull parties and dates, text-to-SQL to check the obligations database, a reasoning model to assess clause risk, an orchestrator to run the whole show, and a safety guardrail watching everything.

That's ten. In most stacks, that's also four or five vendor accounts, a pile of API keys, per-token bills arriving from companies that now hold fragments of your contracts, and four status pages to watch during an outage.

The contract-review-agent example in the SIE repo makes a different bet: every one of those ten calls is served by one SIE cluster through native APIs (local by default; `SIE_CLUSTER_URL` can point at a managed cluster). The agent framework is the OpenAI Agents SDK, but there's no OpenAI API anywhere in the request path.

## The two-agent split

The design decision worth stealing here is the separation of investigation from synthesis.

An Investigator agent (Qwen/Qwen3.6-27B with a 64K context window) does the actual work through seven tools. It classifies the document, reads the signature page with a vision model, runs OCR, searches clauses via embeddings and reranking, extracts entities, and queries an SQLite obligations database through text-to-SQL. The critical property: it can only assert facts it gathered through tool calls. No tool call, no claim.

A separate Synthesizer agent takes the Investigator's findings and formats them into a strict `ContractReview` JSON schema. Splitting the roles prevents the failure mode where a model starts emitting the output schema halfway through gathering evidence and fills the gaps with plausible fiction. Investigation and formatting are different jobs; the example treats them as different agents.

## The model catalog

Each role maps to a model sized for the task, all listed in `config.yaml`:

Qwen3.5-4B handles triage, vision, clause-risk reasoning, and text-to-SQL. LightOnOCR-2-1B does OCR. BAAI/bge-m3 provides dense embeddings; Qwen3-Reranker-4B reorders retrieved clauses. GLiNER large-v2.1 extracts entities without training, and ibm-granite/granite-guardian-3.0-2b runs as the safety guardrail. The 27B orchestrator wants an H100 or RTX PRO 6000; the 4B models run on far less.

Swapping any of these is a config edit, not a code change. And if a model is unavailable, the run degrades gracefully: the ledger records what was skipped instead of the whole review failing.

The sizing logic rewards attention. Nobody needs 27B parameters to decide whether a document is an NDA or a supply agreement; a 4B model triages in a fraction of the time and cost. Meanwhile the orchestrator, the one model that has to plan across all seven tools and a 64K context, gets the big weights. Right-sizing per role is the cost story most single-model architectures never get to tell.

Binding the Agents SDK to the cluster takes one adapter:

```python
Agent(
    name="Risk Analyst",
    model=SIENativeModel(
        "Qwen/Qwen3.5-4B",
        sie_client,
        provision_timeout_s=900,
    ),
)
```

That `SIENativeModel` wraps `SIEAsyncClient.generate` and builds strict JSON schemas for constrained generation, so the Agents SDK works exactly as documented while every token is produced on your own GPUs.

## Guardrails that are actually guardrails

Two constraints in the example deserve mention because they're the kind of thing production teams add after an incident, and this repo has them on day one. Text-to-SQL is SELECT-only; the agent can query the obligations database but structurally cannot write to it. And no generated code executes, ever. No Python sandboxes, no shell. The agent's power is bounded by its seven tools, and the tools are bounded by design.

Meanwhile the observability layer captures per-model latency, data volume, and throughput, so you can see which of the ten models is your bottleneck rather than guessing.

## Real contracts, one command away

The default corpus is CUAD: 510 real commercial contracts from SEC filings, licensed CC BY 4.0. A fetch script pulls the ~18MB archive, parses it, seeds the SQLite obligations database, and renders a page image so the vision and OCR paths have something real to chew on.

```bash
docker run -d --gpus all -p 8080:8080 \
  -v sie-hf-cache:/app/.cache/huggingface \
  ghcr.io/superlinked/sie-server:latest-cuda12-default
cd examples/contract-review-agent && uv sync --frozen
uv run fetch-contracts
uv run review
```

No GPU handy for the corpus fetch? `uv run make-sample` generates synthetic contracts offline.

## Why this matters beyond contracts

Contract review is the demo, but the pattern is the product: one cluster, one client, many specialized models, each doing the job it's actually good at. The alternative (one giant general model for everything, or a spiderweb of vendor APIs) costs more and tells you less about where your latency and errors live.

If your organization has documents it can't send to third parties, this example is the closest thing to a working blueprint you'll find. Clone it, point it at the CUAD corpus, and read the review it produces. Then read the ledger and see all ten models that produced it.

**Try it on GitHub:** [superlinked/sie/examples/contract-review-agent](https://github.com/superlinked/sie/tree/main/examples/contract-review-agent)
