> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lighton.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Revue de Conformite des NDA

> Automatisez la revue de conformite des NDA entrants en executant des controles juridiques configurables sur les contrats charges et en proposant des reformulations issues de NDA precedemment signes, via la recherche agentique et les Chat Completions structurees de Paradigm.

<Note>
  **Derniere mise a jour : Avril 2026** — L'API Paradigm evolue rapidement. Consultez toujours la [derniere reference API](/fr/developer-resources/api-fundamentals/quick-guide) et privilegiez les cookbooks les plus recents.
</Note>

## Presentation

Les equipes juridiques consacrent des heures a la revue des NDA entrants au regard de leur politique interne — verifier que la responsabilite est correctement plafonnee, que les exceptions de communication existent, que la clause de restitution des informations contient les bonnes exceptions. Ce cookbook montre comment construire un pipeline qui charge un NDA dans Paradigm, execute un ensemble configurable de controles juridiques, et pour chaque controle en echec propose une reformulation issue d'un NDA deja signe (ou, a defaut, d'un modele par defaut).

Le pattern se generalise a tout workflow de revue contractuelle : MSA, contrats fournisseurs, DPA, contrats de travail. Partout ou un controle de politique et une proposition de correction feraient gagner du temps au relecteur.

<Tip>
  Cet exemple est inspire d'un workflow de production utilise par un gestionnaire d'actifs francais pour la revue des NDA issus de processus M\&A. Les quatre controles presentes ici correspondent aux regles de conformite reelles du client — vous pouvez les remplacer par les votres en editant une simple liste Python.
</Tip>

## Demo

Decouvrez le pipeline revisant un NDA d'exemple, echouant sur deux controles sur quatre, et proposant des reformulations extraites d'une reference precedemment signee :

<iframe className="w-full aspect-video rounded-xl" src="https://drive.google.com/file/d/1tVlz-5SX1-R5bA_bBGjzx6ngCQtI4NCa/preview" allow="autoplay" />

## Fonctionnement

1. L'utilisateur charge un NDA entrant, plus zero a plusieurs NDA de reference deja signes.
2. Chaque document est charge dans Paradigm et indexe via embedding.
3. Le co-contractant (Target Company) est extrait de chaque document et sert a apparier le NDA entrant avec la reference la plus proche.
4. Quatre controles de conformite sont executes sur le NDA entrant. Chaque controle est un petit arbre de questions juridiques oui/non — chaque question est resolue en combinant une Document Search agentique (pour localiser la clause) et une Chat Completion structuree (pour classifier la clause et renvoyer la citation exacte).
5. Pour chaque controle en echec, le meme flux d'extraction est applique au NDA de reference apparie pour proposer une reformulation. Si aucune reference n'a ete appariee, un modele par defaut est utilise a la place.
6. Les resultats sont compiles dans un rapport JSON avec, pour chaque controle, le statut, les citations extraites et la reformulation proposee.

<img src="https://mintcdn.com/lighton/R6TNsY-FLG4JV2qJ/images/use-cases/nda-review/architecture.png?fit=max&auto=format&n=R6TNsY-FLG4JV2qJ&q=85&s=80710a0a8249e7ccdb7594f9119b02c9" alt="Pipeline de revue de conformite NDA — diagramme d'architecture montrant le chargement et embedding, l'identification du co-contractant, l'evaluation des quatre controles, la reformulation et le rapport JSON" className="rounded-lg" width="3585" height="3234" data-path="images/use-cases/nda-review/architecture.png" />

## Prerequis

* Une cle API Paradigm ([obtenir une cle](/fr/developer-resources/api-fundamentals/quick-guide))
* Python 3.10+
* Au moins un NDA a revoir (des NDA d'exemple sont fournis dans le depot GitHub)
* Optionnel : des NDA precedemment signes a utiliser comme sources de reformulation

## Endpoints API utilises

| Endpoint                                                                                | Role dans ce pipeline                                                         |
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [`POST /api/v2/files`](/fr/developer-resources/api-fundamentals/quick-guide)            | Charger un NDA (PDF ou DOCX) dans Paradigm                                    |
| [`GET /api/v2/files/{id}`](/fr/developer-resources/api-fundamentals/quick-guide)        | Attendre que le document termine son embedding                                |
| [`POST /api/v3/threads/turns`](/fr/developer-resources/api-fundamentals/quick-guide)    | Recherche documentaire agentique (RAG) pour localiser les clauses             |
| [`POST /api/v2/chat/completions`](/fr/developer-resources/api-fundamentals/quick-guide) | Classification JSON structuree via un response format base sur un JSON schema |

## Implementation etape par etape

### Etape 1 : Charger et attendre l'embedding

Contrairement aux workflows bases sur les upload sessions, les NDA sont charges en tant que fichiers uniques via `POST /api/v2/files`. Parce que Document Search requiert que le document soit pleinement embed, on interroge `GET /api/v2/files/{id}` en boucle jusqu'a ce que son statut passe a `embedded`.

```python theme={null}
def upload_and_embed(self, file_path: str) -> str:
    """Upload a single file and block until it is embedded."""
    with open(file_path, "rb") as fh:
        resp = requests.post(
            f"{self.base_url}/api/v2/files",
            headers={"Authorization": f"Bearer {self.api_key}"},
            files={"file": fh},
            timeout=120,
        )
    file_id = resp.json()["id"]

    deadline = time.time() + 180
    while time.time() < deadline:
        status = self.get_file(file_id).get("status")
        if status == "embedded":
            return str(file_id)
        if status == "fail":
            raise ParadigmError(f"Embedding failed for file {file_id}")
        time.sleep(2.0)
    raise ParadigmError(f"Timeout waiting for file {file_id} to embed")
```

### Etape 2 : Poser une question juridique oui/non

Chaque verification de conformite se reduit au meme pattern en deux etapes : d'abord une Document Search fait remonter la clause pertinente, puis une Chat Completion structuree la classifie et renvoie la citation exacte. Le JSON schema garantit un format de reponse toujours previsible.

```python theme={null}
def _ask_yes_no(client, file_id: str, question: str) -> QueryResult:
    # 1. Find the passage that discusses this topic.
    search_query = f"Dans ce document, dans quelle section se trouve la clause qui parle de : {question}"
    passage = client.ask_question(file_id, search_query)

    # 2. Classify the passage against the question and return the exact quote.
    classify_query = (
        f"Voici les informations récupérées du document NDA :\n{passage}\n\n"
        f"Extrais la phrase exacte du document qui correspond à la requête suivante "
        f"et indique si la clause est présente et affirmative. Requête : {question}"
    )
    schema = {
        "type": "object",
        "properties": {
            "extracted_text": {"type": "string"},
            "is_true": {"type": "boolean"},
        },
        "required": ["extracted_text", "is_true"],
        "additionalProperties": False,
    }
    answer = client.structured_completion(classify_query, schema=schema)
    return QueryResult(
        question=question,
        is_true=bool(answer["is_true"]),
        extracted_text=answer["extracted_text"].strip(),
    )
```

<Tip>
  Les requetes sont formulees en francais car les NDA du client sont revus par des juristes francophones qui les ont redigees ainsi a l'origine. Paradigm gere le francais nativement — traduisez-les dans votre propre langue si cela fait plus de sens pour votre equipe.
</Tip>

### Etape 3 : Utiliser `force_tool` et `response_format` pour la structure

Deux fonctionnalites Paradigm font le gros du travail. Premierement, `force_tool: "document_search"` sur l'endpoint V3 threads garantit que le modele effectue un lookup RAG sur le fichier specifie plutot que de repondre depuis sa connaissance generale :

```python theme={null}
def ask_question(self, file_id: str, question: str) -> str:
    payload = {
        "ml_model": self.model,
        "query": question,
        "force_tool": "document_search",
        "file_ids": [int(file_id)],
    }
    resp = requests.post(
        f"{self.base_url}/api/v3/threads/turns",
        headers=self._json_headers(),
        json=payload,
        timeout=180,
    )
    return _extract_v3_answer(resp.json())
```

Deuxiemement, `response_format` avec un JSON schema sur `chat/completions` garantit que la reponse de classification est un objet JSON valide et parseable — fini le parsing par regex de reponses en texte libre :

```python theme={null}
payload = {
    "model": self.model,
    "messages": [
        {"role": "system", "content": self._JSON_SYSTEM_PROMPT},
        {"role": "user", "content": query},
    ],
    "temperature": 0.1,
    "max_tokens": 800,
    "response_format": {
        "type": "json_schema",
        "json_schema": {"name": "response", "schema": schema, "strict": True},
    },
}
```

### Etape 4 : Modeliser les controles sous forme d'arbres de requetes

Chaque controle de conformite est un arbre de questions oui/non avec des regles de branchement. Garder les controles sous forme de donnees — pas de code — les rend faciles a auditer, a ajuster, ou a deleguer a une personne non-technique.

```python theme={null}
CONTROLS = [
    {
        "number": "1",
        "name": "Liability of the receiving party",
        "queries": [
            {"id": "q1", "text": "Is there a liability clause for unauthorised disclosure?"},
            {"id": "q2", "text": "Is liability capped to direct damages only?"},
            {"id": "q3", "text": "Is the NDA governed by French law?"},
        ],
        "default_templates": {
            "q2": "to indemnify the Counterparty ... against all direct claims ...",
            "q3": "This Agreement is subject to French law ...",
        },
    },
    # ... three more controls
]
```

La logique de branchement vit dans `_run_control`. Le controle 1, par exemple, se lit ainsi : "s'il existe une clause de responsabilite, alors elle doit etre plafonnee aux dommages directs ; sinon, le NDA doit etre gouverne par le droit francais."

```python theme={null}
if control["number"] == "1":
    q1 = ask("q1")
    if q1.is_true:
        q2 = ask("q2")
        if not q2.is_true:
            status, failed_qid = "FAIL", "q2"
    else:
        q3 = ask("q3")
        if not q3.is_true:
            status, failed_qid = "FAIL", "q3"
```

### Etape 5 : Extraire le co-contractant pour l'appariement

Avant d'executer les controles, on identifie la Target Company dans le NDA. Dans un contexte M\&A, jusqu'a trois parties peuvent apparaitre — la Receiving Party (l'acquereur), un Financial Advisor intermediaire, et la Target Company dont les informations sont partagees. On veut la Target Company, pas les deux autres. Un prompt soigneusement redige plus un JSON schema a un seul champ suffisent a garder la sortie propre :

```python theme={null}
schema = {
    "type": "object",
    "properties": {
        "target_company": {
            "type": "string",
            "description": (
                "Nom commercial de la société cible (Target Company). "
                "Exclure la Receiving Party et le Financial Advisor intermédiaire."
            ),
        },
    },
    "required": ["target_company"],
    "additionalProperties": False,
}
```

Une fois le co-contractant de chaque document connu, on apparie le NDA entrant avec la reference la plus proche via [`difflib.SequenceMatcher`](https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher) (un substitut leger a la similarite trigram PostgreSQL).

### Etape 6 : Reformuler les clauses en echec

Lorsqu'un controle echoue, on propose un correctif. La chaine de fallback est : "essayer d'extraire la clause equivalente du NDA de reference apparie ; si rien d'utilisable ne revient, utiliser un modele pre-redige."

```python theme={null}
def _reformulate(client, question, default_template, reference_file_id):
    if reference_file_id:
        result = _ask_yes_no(client, reference_file_id, question)
        if result.extracted_text:
            return result.extracted_text, "reference"
    return default_template.strip(), "template"
```

Cela signifie que la reformulation proposee est en general tiree d'une formulation deja acceptee par le co-contractant — beaucoup plus facile a faire accepter qu'une clause modele generique.

### Etape 7 : Compiler le rapport

Le rapport final regroupe le co-contractant, la reference appariee, et un `ControlResult` par controle (statut, requetes avec citations, reformulation proposee). Un sommaire de haut niveau rend trivial le branchement de la revue dans un check CI ou un tableau de bord.

```json theme={null}
{
  "nda_filename": "NDA - Project Kairos.docx",
  "counterparty": "Nexora Group",
  "reference": {
    "filename": "NDA - Project Kairos - Livana (Meridia AM signed).pdf",
    "counterparty": "Nexora Group"
  },
  "summary": {
    "total_controls": 4, "passed": 2, "failed": 2,
    "pass_rate": 50.0, "status": "FAIL"
  },
  "controls": [
    {
      "number": "1",
      "name": "Liability of the receiving party",
      "status": "FAIL",
      "queries": [
        {"id": "q1", "is_true": true,  "extracted_text": "You shall be responsible ..."},
        {"id": "q2", "is_true": false, "extracted_text": ""}
      ],
      "reformulation": "You shall be responsible ... for any direct damages ...",
      "reformulation_source": "reference"
    }
  ]
}
```

## Code complet

<CardGroup cols={2}>
  <Card title="Code source complet" icon="github" href="https://github.com/lightonai/cookbook-nda-review">
    Clonez le depot pour executer le pipeline complet avec les NDA d'exemple.
  </Card>

  <Card title="Reference API" icon="square-terminal" href="/fr/developer-resources/api-fundamentals/quick-guide">
    Documentation complete de l'API Paradigm.
  </Card>
</CardGroup>

## Personnalisation

| Parametre                            | Description                                                                                   | Valeur par defaut         | A ajuster si...                                                                                                  |
| ------------------------------------ | --------------------------------------------------------------------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `CONTROLS` (dans `src/pipeline.py`)  | Liste des controles de conformite, chacun avec un arbre de requetes et des modeles par defaut | 4 controles M\&A NDA      | Vous avez des exigences de politique differentes                                                                 |
| `match_reference_nda(threshold=...)` | Seuil de similarite du co-contractant                                                         | `0.5`                     | Votre bibliotheque de references contient beaucoup de quasi-doublons (augmenter) ou tres peu d'entrees (reduire) |
| `model` (dans `ParadigmClient`)      | Modele Paradigm utilise pour la recherche et la completion                                    | `alfred-ft5`              | Vous avez besoin d'arbitrages vitesse/qualite differents                                                         |
| `temperature`                        | Determinisme de la completion                                                                 | `0.1`                     | Vous voulez des reformulations plus creatives depuis le fallback modele                                          |
| Prompt systeme `_JSON_SYSTEM_PROMPT` | Instructions de langue / format de sortie                                                     | Francais, JSON uniquement | Vos documents ou votre equipe travaillent dans une autre langue                                                  |

## Ajouter votre propre controle

Chaque controle est une entree de la liste `CONTROLS`. Etapes pour en ajouter un :

1. **Definir les requetes** — une question juridique oui/non par noeud de votre arbre de decision.
2. **Ajouter la logique de branchement** dans `_run_control` — sous quelle combinaison de reponses le controle est `PASS` ou `FAIL`, et quel template de requete est utilise pour la reformulation.
3. **Rediger un modele par defaut** — la formulation fallback utilisee quand aucun NDA de reference n'est apparie.

```python theme={null}
{
    "number": "5",
    "name": "Term and termination",
    "queries": [
        {"id": "q1", "text": "Does the NDA specify a fixed duration of confidentiality?"},
    ],
    "default_templates": {
        "q1": "The obligations under this Agreement shall survive for a period of five (5) years ...",
    },
}
```

## Bonnes pratiques

1. **Gardez les controles sous forme de donnees, pas de code** — mettre le texte des requetes et les modeles dans une liste (pas disperses dans des fonctions) fait de la revue de conformite une tache que votre equipe juridique peut auditer directement. Les petits gains pour les juristes sont de gros gains pour le pipeline.
2. **Utilisez toujours `force_tool: "document_search"`** pour les recherches de clauses — cela force Paradigm a citer le document reel plutot qu'a s'appuyer sur sa connaissance generale, ce qui compte enormement pour la revue juridique.
3. **Utilisez `response_format` avec un JSON schema** pour la classification — le parsing de texte libre pour "oui/non plus citation" est fragile ; le JSON impose par schema est infaillible.
4. **Privilegiez les reformulations issues de reference plutot que les modeles** — une formulation deja acceptee par le co-contractant est bien plus facile a faire signer qu'une clause modele generique. Le fallback modele n'intervient que si aucune reference n'a ete appariee.
5. **Appariez les co-contractants, pas les noms de fichiers** — extraire la Target Company avant l'appariement permet d'utiliser un inventaire de centaines de NDA signes sans se soucier de leur nommage. Un seuil de similarite souple (0.5) pardonne les variations de nommage.
6. **Validez le co-contractant extrait** — les NDA M\&A impliquent souvent trois parties ; un extracteur bon marche soutenu par un schema, avec des regles explicites "exclure ces roles" dans le champ description, evite des re-executions couteuses.
