Automatisez la verification multi-documents en extrayant et recoupant des champs a travers des documents charges, grace aux APIs Document Search et Chat Completions de Paradigm.
Use this file to discover all available pages before exploring further.
Derniere mise a jour : Avril 2026 — L’API Paradigm evolue rapidement. Consultez toujours la derniere reference API et privilegiez les cookbooks les plus recents.
Verifier la coherence des informations entre plusieurs documents lies — formulaires de marches publics, contrats, releves bancaires, declarations d’identite — est un travail fastidieux, source d’erreurs et couteux lorsqu’il est realise manuellement. Ce cookbook montre comment construire un pipeline de verification automatise qui charge des documents dans Paradigm, extrait des champs specifiques via Document Search, et les recoupe grace a Chat Completions avec des prompts structures.Ce pattern s’applique a tout workflow de verification multi-documents : audits de conformite, traitement de sinistres d’assurance, demandes de prets, integration de fournisseurs, et plus encore.
Cet exemple est base sur un cas d’usage reel en production pour la verification de formulaires de marches publics francais (DC4). Le pattern se generalise a tout scenario ou vous devez verifier la coherence entre plusieurs documents.
L’utilisateur charge un ensemble de documents lies (ex. : un formulaire, un contrat, un RIB, une declaration).
Les documents sont ingeres dans Paradigm via l’API Upload Sessions.
Pour chaque controle, des champs specifiques sont extraits des documents concernes via Document Search.
Les champs extraits sont compares via Chat Completions avec un prompt systeme structure qui gere la correspondance approximative (fautes, differences de format, abreviations).
Chaque controle retourne un resultat structure : is_correct, les valeurs comparees, et une explication de la decision.
Tous les resultats sont compiles dans un rapport de verification.
Les documents doivent etre charges dans Paradigm avant de pouvoir etre interroges. L’API Upload Sessions gere le pipeline d’ingestion — vous creez une session, chargez les fichiers, puis fermez la session pour declencher l’embedding.
def create_upload_session(self) -> dict: """Cree une nouvelle session de chargement pour l'ingestion de documents.""" response = requests.post( f"{self.base_url}/api/v2/upload-sessions", headers=self.headers, json={"pipeline": "v2.2.1"} ) response.raise_for_status() return response.json()def upload_file(self, session_id: str, file_path: str) -> dict: """Charge un fichier dans une session existante.""" with open(file_path, "rb") as f: response = requests.post( f"{self.base_url}/api/v2/upload-sessions/{session_id}/files", headers={"Authorization": f"Bearer {self.api_key}"}, files={"file": f} ) response.raise_for_status() return response.json()def close_upload_session(self, session_id: str) -> dict: """Ferme la session pour declencher l'embedding des documents.""" response = requests.post( f"{self.base_url}/api/v2/upload-sessions/{session_id}/close", headers=self.headers ) response.raise_for_status() return response.json()
Les documents doivent etre entierement indexes avant de pouvoir etre interroges. Le temps d’indexation depend de la taille et de la complexite du document — en general quelques secondes a quelques minutes.
Etape 3 : Extraire des champs avec Document Search
Une fois les documents indexes, utilisez Document Search pour extraire des champs specifiques. Le parametre query est une question en langage naturel — Paradigm recherche dans le document et retourne le contenu pertinent.
def search_document( self, file_ids: list[str], query: str, tool: str = "DocumentSearch") -> dict: """Extrait des informations specifiques des documents charges. Args: file_ids: identifiants Paradigm des fichiers a interroger. query: question en langage naturel decrivant ce qu'il faut extraire. tool: "DocumentSearch" pour le texte, "VisionDocumentSearch" pour les docs scannes. """ payload = { "model": "alfred-4.2", "query": query, "file_ids": file_ids, "tool": tool } response = requests.post( f"{self.base_url}/api/v2/chat/document-search", headers=self.headers, json=payload, timeout=150 ) response.raise_for_status() return response.json()
Exemples de requetes d’extraction :
# Extraire le nom de l'acheteur d'un formulaireresult = client.search_document( file_ids=[form_file_id], query="Quel est le nom du pouvoir adjudicateur ?")# Extraire le numero de reference du marche d'un avis de marcheresult = client.search_document( file_ids=[tender_notice_id], query="Quel est le numero de reference du marche ?")# Extraire les coordonnees bancaires d'un document scanneresult = client.search_document( file_ids=[bank_doc_id], query="Quel est le numero IBAN ?", tool="VisionDocumentSearch" # Utiliser la vision pour les documents scannes)
Etape 4 : Recouper les champs avec Chat Completions
C’est le coeur du pipeline de verification. Apres avoir extrait le meme champ de deux documents differents, utilisez Chat Completions avec un prompt systeme structure pour les comparer. Le prompt gere les imperfections du monde reel : fautes de frappe, differences de formatage, abreviations, accents manquants.
def cross_reference(self, query: str) -> dict: """Compare les valeurs extraites via correspondance approximative par LLM. Retourne une reponse JSON structuree avec : - is_correct: bool — si les valeurs correspondent - compare_values: dict — les valeurs comparees - details: str — explication du resultat de la comparaison """ system_prompt = """You are a document verification assistant. Your role is to comparedata extracted from different documents and determine if they match.Rules for comparison:- Names: ignore case, accents, and minor spelling variations. "JEAN-PIERRE DUPONT" matches "Jean-Pierre Dupont" matches "Jean Pierre Dupont".- Addresses: compare street, postal code, and city separately. Minor differences in formatting are acceptable.- Phone numbers: ignore spaces, dots, and country prefixes. "01 23 45 67 89" matches "+33 1 23 45 67 89" matches "0123456789".- Emails: case-insensitive comparison.Always respond in valid JSON with this exact structure:{ "is_correct": true/false, "compare_values": {"document_1": "...", "document_2": "..."}, "details": "Explanation of why the values match or don't match."}""" payload = { "model": "alfred-4.2", "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": query} ], "max_tokens": 500, "temperature": 0.1 } response = requests.post( f"{self.base_url}/api/v2/chat/completions", headers=self.headers, json=payload, timeout=150 ) response.raise_for_status() data = response.json() return data["choices"][0]["message"]["content"]
Le prompt systeme ci-dessus est essentiel pour gerer les donnees reelles. Adaptez les regles de correspondance approximative a votre domaine. Par exemple, pour la verification de documents financiers, vous pourriez vouloir une correspondance stricte sur les montants mais approximative sur les noms d’entreprise.
Chaque controle est une fonction qui extrait un champ de deux documents et les compare. Voici le pattern — repetez-le pour chaque champ a verifier.
import jsondef verify_buyer_name(client: ParadigmClient, form_id: str, tender_id: str) -> dict: """Verifie que le nom de l'acheteur correspond entre le formulaire et l'avis de marche.""" # Etape A : extraction du document 1 form_result = client.search_document( file_ids=[form_id], query="What is the full name of the public buyer?" ) # Etape B : extraction du document 2 tender_result = client.search_document( file_ids=[tender_id], query="What is the full name of the public buyer?" ) # Etape C : recoupement comparison = client.cross_reference( f"Compare these buyer names:\n" f"Document 1 (form): {form_result['answer']}\n" f"Document 2 (tender notice): {tender_result['answer']}" ) return { "check": "buyer_name", "result": json.loads(comparison) }
Compilez tous les resultats dans un rapport structure. L’exemple ci-dessous genere un resume simple — en production, vous pourriez generer un PDF ou ecrire en base de donnees.
def generate_report(results: list[dict]) -> dict: """Compile les resultats de verification dans un rapport de synthese.""" passed = [r for r in results if r["result"]["is_correct"]] failed = [r for r in results if not r["result"]["is_correct"]] report = { "total_checks": len(results), "passed": len(passed), "failed": len(failed), "status": "VALID" if len(failed) == 0 else "INVALID", "details": { "passed_checks": [r["check"] for r in passed], "failed_checks": [ { "check": r["check"], "reason": r["result"]["details"], "values": r["result"]["compare_values"] } for r in failed ] } } return report
Utilisez VisionDocumentSearch pour les documents scannes — le DocumentSearch standard fonctionne pour les PDF natifs, mais les documents scannes et les images necessitent l’outil vision pour une extraction fiable.
Gardez les requetes d’extraction specifiques — “Quel est l’IBAN ?” fonctionne mieux que “Extraire toutes les informations bancaires.” Un champ par requete donne des resultats plus fiables.
Adaptez le prompt systeme a votre domaine — les regles de correspondance approximative doivent refleter vos exigences metier. Les donnees financieres peuvent necessiter une correspondance exacte ; les noms et adresses necessitent generalement une correspondance approximative.
Executez les controles en parallele — chaque controle est independant, utilisez le threading pour les traiter simultanement. Ajoutez un leger delai entre les lots si vous atteignez les limites de debit.
Journalisez les resultats intermediaires — quand un controle echoue, avoir les valeurs brutes extraites des deux documents facilite grandement le debogage.