Salta al contenuto principale

Costruire una Pipeline di Elaborazione Documenti AI su AWS

Indice dei contenuti
Una pipeline serverless di elaborazione documenti su AWS che usa LLM per estrarre dati strutturati da documenti non strutturati — fatture, contratti, report — su larga scala. Nessun cluster GPU richiesto.

Le compagnie assicurative elaborano milioni di documenti ogni anno: verbali di polizia, cartelle cliniche, fatture, preventivi di riparazione. Tradizionalmente, operatori umani leggono ogni documento, lo classificano, ne estraggono i campi rilevanti e inseriscono i dati nel sistema dei sinistri. Questo è lento, costoso e soggetto a errori.

In questo articolo descrivo l’architettura di una pipeline di elaborazione documenti in produzione che ho contribuito a costruire. Il sistema ingestisce documenti di sinistro, estrae testo usando LLM con capacità visiva, raggruppa e classifica le sezioni del documento, estrae dati strutturati e genera embedding vettoriali per la ricerca semantica. Tutto su un’architettura AWS completamente serverless senza costi di infrastruttura idle.

Lo Spazio del Problema
#

Un tipico sinistro assicurativo arriva come archivio ZIP contenente più documenti: un verbale di polizia, certificati medici, preventivi di riparazione, fotografie, corrispondenza. Ogni documento deve essere:

  1. Analizzato in testo leggibile dalla macchina
  2. Classificato per tipo (verbale di polizia, referto medico, fattura, ecc.)
  3. Strutturato estraendo campi specifici per tipo di documento
  4. Indicizzato per ricerca semantica
  5. Riassunto per dare al responsabile del caso una panoramica

Panoramica dell’Architettura
#

L’architettura segue un pattern event-driven, completamente serverless:

Upload ZIP → S3 → EventBridge → Step Functions → [Pipeline Lambda] → DynamoDB + Aurora
                                              Servizio Sinistri (ECS) ← ALB ← Utenti

I componenti chiave:

  • S3: riceve upload ZIP tramite URL pre-firmati
  • EventBridge: attiva la pipeline quando arriva un file
  • Step Functions: orchestra il workflow di elaborazione multi-fase
  • Lambda: esegue ogni fase (stateless, parallelo)
  • DynamoDB: traccia lo stato e archivia i risultati di estrazione
  • Aurora PostgreSQL: archivia gli embedding vettoriali per RAG

La Pipeline Step Functions
#

Il cuore del sistema è una macchina a stati AWS Step Functions che orchestra l’elaborazione dei documenti attraverso una fase lineare seguita da due rami paralleli.

Fase Lineare: Analisi ed Estrazione Testo
#

Stage 1: Start — Valida lo ZIP, estrae i file, crea record di tracciamento in DynamoDB. Gestisce anche la deduplicazione.

Stage 2: Split — Ogni documento viene convertito in PDF (se è un DOCX), poi suddiviso in pagine singole salvate come immagini PNG.

Stage 3: Parse — Qui entra in gioco l’AI. Ogni immagine di pagina viene inviata a Claude 3.5 Sonnet (via Amazon Bedrock) per l’estrazione del testo basata su visione. L’LLM legge l’immagine e produce testo Markdown pulito.

processor.py
def parse_page(image_bytes: bytes, page_number: int) -> str:
    bedrock = boto3.client("bedrock-runtime")

    response = bedrock.invoke_model(
        modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
        body=json.dumps({
            "anthropic_version": "bedrock-2023-05-31",
            "max_tokens": 4096,
            "messages": [{
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": base64.b64encode(image_bytes).decode(),
                        },
                    },
                    {
                        "type": "text",
                        "text": "Estrai tutto il testo da questa pagina del documento. "
                                "Preserva la struttura usando la formattazione Markdown. "
                                "Includi tabelle, intestazioni e qualsiasi testo scritto a mano.",
                    },
                ],
            }],
        }),
    )

    result = json.loads(response["body"].read())
    return result["content"][0]["text"]

Perché Claude 3.5 Sonnet invece di Amazon Textract? Gli LLM visivi gestiscono documenti reali (timbri, scrittura a mano, layout misti) significativamente meglio dell’OCR tradizionale. E l’output è già Markdown strutturato.

Stage 4: Page Checker — Implementa la logica di retry: raccoglie i risultati da tutte le chiamate di parsing, identifica i fallimenti, e ri-dispatcha le pagine fallite fino a 3 volte.

extractor.py
def check_pages(document_id: str, page_results: list[dict]) -> dict:
    successful = [p for p in page_results if p["status"] == "success"]
    failed = [p for p in page_results if p["status"] == "error"]

    retryable = [p for p in failed if p.get("retry_count", 0) < MAX_RETRIES]

    if retryable:
        for page in retryable:
            page["retry_count"] = page.get("retry_count", 0) + 1
        return {"status": "retry", "pages": retryable}

    return {
        "status": "success",
        "parsed_pages": len(successful),
        "failed_pages": len(failed),
    }

Ramo Superiore: Pipeline di Embedding
#

Crea embedding vettoriali per la ricerca semantica. I chunk del documento vengono embeddati usando text-embedding-ada-002 di OpenAI e archiviati in Aurora PostgreSQL con l’estensione pgvector.

Questo alimenta un’interfaccia RAG dove i responsabili dei casi possono fare domande tipo “Qual era il costo stimato delle riparazioni?” e ottenere risposte ancorate ai documenti reali.

Ramo Inferiore: Pipeline di Classificazione ed Estrazione
#

Clusterizzazione: Identifica range di pagine consecutive che appartengono allo stesso argomento. Usiamo Gemini 2.0 Flash per questo perché è veloce, economico e funziona bene per il ragionamento di classificazione.

Classificazione: Ogni cluster viene etichettato con un tipo di documento (verbale di polizia, certificato medico, fattura, preventivo riparazione, ecc.).

Estrazione: In base all’etichetta di classificazione, vengono estratti campi specifici. Un verbale di polizia ottiene targa, nome conducente, data e luogo. Un referto medico ottiene diagnosi, trattamento e medico.

La Strategia Multi-Modello
#

Una delle decisioni architetturali più interessanti è stata usare tre diversi provider LLM, ognuno selezionato per un compito specifico:

CompitoModelloPerché
Estrazione testo (OCR)Claude 3.5 Sonnet (Bedrock)Migliori capacità visive per documenti complessi
Embeddingtext-embedding-ada-002 (OpenAI)Embedding di alta qualità a costi contenuti
Clusterizzazione/ClassificazioneGemini 2.0 Flash (Vertex AI)Veloce ed economico per compiti di ragionamento

Tutte le chiamate LLM passano attraverso un servizio gateway interno che astrae le differenze tra provider. Questo approccio multi-modello ci permette di ottimizzare per costo e qualità per compito invece di essere vincolati a un singolo provider.

Performance e Costi
#

Alcuni numeri dalla produzione:

  • Tempo di elaborazione: un documento di 30 pagine richiede circa 3-5 minuti end-to-end
  • Throughput: il sistema gestisce 500+ documenti per ora nei periodi di punta
  • Costo per documento: circa EUR 0.15-0.30, a seconda del numero di pagine
  • Costo infrastruttura a riposo: quasi zero (serverless)

Lezioni Imparate
#

Gli LLM visivi sono pronti per la produzione per l’OCR. Claude 3.5 Sonnet gestisce documenti assicurativi reali (timbri, scrittura a mano, scansioni di bassa qualità, lingue miste) molto meglio dell’OCR tradizionale.

Step Functions è lo strumento giusto per le pipeline documentali. La logica di retry integrata, gli stati Map paralleli, la gestione degli errori e il debug visivo rendono Step Functions ideale per l’elaborazione multi-fase.

Il retry non è opzionale. Le API LLM falliscono più spesso delle API tradizionali. Il pattern Page Checker (fino a 3 tentativi per pagina) è ciò che rende la pipeline abbastanza affidabile per la produzione.

Batch invece di real-time quando puoi. Elaborare gli upload ogni 10 minuti invece di immediatamente ha semplificato significativamente l’architettura. Per l’elaborazione dei sinistri assicurativi, qualche minuto di latenza è perfettamente accettabile.

Articoli correlati