Note dal ciclo di release — Parte 8 (finale)
Rilasci la suite di regressione del post 7. Funziona. I gate slice-aware catturano bug reali. Il judge calibrato regge.
Poi il tuo lead engineering ti chiede quanto costa eseguirla su ogni PR. Fai la moltiplicazione: ~12 minuti di inferenza del judge per PR, 60 PR al giorno, quattro dimensioni × diciassette slice, e la bolletta è denaro vero. Peggio, ogni sviluppatore sta aspettando 12 minuti per un check verde su un refuso di una riga in un prompt. La velocità crolla[1], il team brontola, qualcuno propone “facciamo girare i gate solo di notte” — che è esattamente come si rinuncia a tutto ciò che i gate dovevano fare.
La soluzione non è meno test. La soluzione è testare a strati, con la maggior parte del segnale che arriva nei primi novanta secondi. Questo post è ciò che gira sotto la suite di gate: contract test sotto il secondo, uno strato smoke compatto, una flotta cost-aware e una finestra shadow di due settimane prima che qualunque nuovo gate blocchi chiunque.
Questo è il post 8, l’ultimo di questa serie. Alla fine avrai il quadro completo — dalla pipeline a quattro stadi fino alla fixture di contract test che gira su ogni commit.
Cosa significa CI per un modello linguistico personalizzato?
CI per un LLM personalizzato è il lavoro che la suite di gate non deve ripetere. Il gate misura la qualità semantica; la CI cattura tutto ciò che renderebbe insignificante il punteggio del gate prima che il gate spenda un singolo token del judge.
I contract test girano in millisecondi e verificano che i template di prompt si renderizzino ancora, che gli schemi di tool-call si parsino ancora, che gli indici di retrieval rispondano ancora, che il manifest faccia ancora riferimento a hash che esistono davvero. Sono deterministici, gratuiti e l’unica ragione per cui il resto della pipeline può permettersi di esistere. Una pull request che rompe il template di prompt dovrebbe fallire in 200 ms, non dopo 12 minuti di inferenza del judge che valuta sciocchezze.
Lo strato contract è la differenza tra una bolletta CI che scala linearmente con il volume di PR e una che non lo fa. Il runner CI di Divinci spende > 90% del suo budget judge in vera valutazione semantica, non in PR che sarebbero fallite a un controllo di schema. Quel rapporto è il numero chiave.
Perché la CI tradizionale si rompe per gli LLM — attraverso la lente del costo
I post 1 e 7 hanno coperto perché la CI deterministica fallisce per un modello generativo. La versione di quella storia di cui parla questo post è il costo di quelle quattro proprietà, non la loro esistenza.
| Proprietà degli LLM | Fallimento della CI tradizionale | Forma del costo |
|---|---|---|
| Output non deterministici | Le asserzioni di exact-match diventano flaky | I re-run amplificano il costo linearmente con il tasso di flakiness |
| Qualità multidimensionale | Un singolo booleano è poco informativo | Ogni dimensione è una chiamata al judge separata (e a pagamento) |
| Drift del provider | Un gpt-4-2024-01-01 pinnato viene ritirato silenziosamente | Burst di ricalibrazione quando un provider dismette un checkpoint |
| Effetti non locali dei prompt | Lo unit test locale non può catturare l’effetto | I cambiamenti di forma della distribuzione avvengono tra PR, non al loro interno — serve un re-run dell’intera suite, non del delta |
L’architettura CI deve rendere ciascuno di questi punti sostenibile. I contract test gestiscono le proprietà 1 e 3 a basso costo. Gli smoke test gestiscono parzialmente la proprietà 4. Solo la suite completa gestisce la proprietà 2 — e solo sulle PR che ne hanno effettivamente bisogno.
La torta a strati della CI — dal sotto-secondo ai venticinque minuti
L’architettura che rilasciamo è composta da quattro strati, ciascuno dei quali si guadagna il proprio compute catturando ciò che gli strati più economici sotto non possono. L’inquadramento slice-aware di ogni strato segue la stessa lezione resa esplicita dal postmortem Tianpan Semver Lie[4]: i segnali aggregati mentono; i segnali per slice catturano ciò che gli aggregati nascondono.
La forma del costo è il design. ~74% delle PR non spende mai un token del judge — contract o smoke è sufficiente. Le PR che raggiungono la suite completa sono quelle che hanno toccato un prompt, una configurazione di modello, un indice di retrieval o del codice di valutazione — esattamente i cambiamenti per cui la suite di gate è l’unico segnale degno di fiducia. Le release candidate sono la piccola quota che raggiunge lo Strato 4.
Contract test — il vantaggio sleale
I contract test sono la prima linea, la linea più economica e la linea che la maggior parte dei team salta perché sentono sotto la dignità di una “pipeline di valutazione AI”. Sono anche il punto in cui il 30–40% delle potenziali regressioni fallisce realmente nelle suite dei nostri clienti, prima ancora che un singolo judge sia stato chiamato.
Lo strato contract afferma cinque cose e nient’altro:
- Render del template di prompt. Ogni template viene renderizzato contro una fixture canonica senza variabili non legate, loop fuori controllo o include in stile Jinja rotti.
- Schema di tool-call. Lo schema degli argomenti di ogni tool dichiarato si parsa, lo JSONSchema è valido e il prompt renderizzato fa effettivamente riferimento a tutti gli slot richiesti.
- Integrità del manifest. Ogni SHA nel manifest di release — modello, prompt, indice di retrieval, judge, dataset — corrisponde a un artefatto che esiste nel registry. I puntatori penzolanti falliscono qui, non tre strati più avanti.
- Liveness dell’indice. L’indice di retrieval risponde a una query nota entro il budget. Un indice ricostruito che ha silenziosamente rotto il retrieval emerge qui, non in produzione.
- Denylist & budget di token. Qualunque template di prompt che abbia introdotto un token proibito, sforato il budget di token per chiamata o renderizzato oltre la context window fallisce qui. Lo scoring euristico di similarità semantica[6] è anch’esso abbastanza economico da essere eseguito allo strato contract per coprire denylist fuzzy-match dove il match letterale stringa non basta.
# Una invocazione rappresentativa di contract test — gira in circa 600 ms
divinci ci contract \
--manifest release/staging.yaml \
--check schema,template,manifest,index,denylist \
--fail-fast \
--json-out /tmp/contract-report.jsonNessuna di queste chiamate invoca un judge. Nessuna di esse è non deterministica. Nessuna costa denaro misurabile. E ognuna di esse esclude un’intera classe di alert tipo “la suite di gate ha detto che la slice medica è regredita” che avrebbero sprecato 12 minuti completi di inferenza del judge per valutare output che il modello non avrebbe mai potuto produrre correttamente in primo luogo.
Lo strato smoke — 90 secondi, ~$0,05 per PR
Se lo strato contract è il vantaggio sleale a basso costo, lo strato smoke è quello che cattura davvero le regressioni per meno del prezzo di un caffè. Da venti a trenta casi tratti dalle slice a volume più alto, valutati su completamento del task e safety soltanto, senza fedeltà, senza latenza, senza controlli grounded nel retrieval. Ogni PR esegue questo. Ci vogliono circa 90 secondi perché i casi sono raggruppati in una singola chiamata al judge con uno schema di output strutturato, e perché il judge è il judge calibrato economico — non quello full-quality usato per le release candidate.
Tracciamo quale strato ha catturato ogni fix rilasciato in un log di regressioni, e l’istogramma è stato coerente negli ultimi sei mesi nei deployment dei clienti:
Il 3% che sfugge è il motivo per cui esiste l’instant rollback del post 5. I gate non promettono zero fughe; promettono un limite superiore stretto e un recupero veloce per ciò che passa.
Dimensionamento della flotta CI — come la suite da 12 minuti resta economica
Lo strato della suite completa è dove la matematica deve tornare. Un’implementazione ingenua chiama il judge una volta per caso-per-dimensione, le esegue sequenzialmente e la bolletta scala linearmente con il numero di casi. Tre ottimizzazioni fanno la maggior parte del lavoro per mantenerla trattabile:
Embedding cache. Il fingerprint del contesto di retrieval per ogni caso del golden-dataset viene hashato; se il caso non è cambiato e l’indice di retrieval non è cambiato, l’embedding in cache regge e lo step di retrieval viene saltato. Il hit rate dopo la prima settimana stabile è costantemente sopra il 90% nei deployment dei nostri clienti.
Judge batching. Il judge calibrato viene chiamato con output strutturato, raggruppando 8–16 casi per chiamata. Il costo per token del judge resta lo stesso; l’overhead per caso cala perché il system prompt si ammortizza sul batch. La soglia per il batching sicuro è impostata dall’accordo calibrato dello stesso judge a quella dimensione di batch[2] — la misuriamo durante il passaggio settimanale di calibrazione del judge (post 7).
Riuso della KV-cache tra casi. Per i modelli in cui lo stesso system prompt e le stesse definizioni di tool aprono ogni chiamata, la KV cache per quel prefisso viene calcolata una volta per esecuzione della suite, non una volta per caso[3]. Sui deployment open-weights è semplice; sui modelli closed-API dipende dal supporto al prefix-caching del provider.
L’effetto combinato porta la suite completa più o meno ai numeri di costo mostrati nel diagramma della torta a strati sopra. Le cifre esatte sono interne, ma il rapporto è la rivendicazione pubblica: ~74% delle PR spende zero dollari del judge; ~22% spende centesimi; il restante 4% spende un paio di dollari per il segnale pre-rollout a più alta confidenza che sappiamo come produrre.
Shadow CI — accenderlo senza rompere il team
L’unico errore che abbiamo visto fare ai team più spesso è passare un nuovo gate da “off” a “blocking” il primo giorno. Le soglie sono state tarate sui dati di ieri, il tasso di falsi positivi è ignoto, e la prima volta che il gate scatta il team non ha calibrazione su se sia reale o un falso allarme. L’eval engineer in on-call viene chiamato, il gate viene disabilitato, la fiducia è andata, il progetto è morto.
La soluzione è la shadow CI: eseguire il nuovo gate non-bloccante per due settimane, postare il risultato come commento di un bot su ogni PR e rivedere il tasso di falsi positivi settimanalmente prima di passarlo a bloccante. Il runner CI di Divinci ha una flag --shadow esattamente per questo. Il commento sulla PR ha lo stesso aspetto della futura versione bloccante — stesso display di diff, stesso breakdown per slice — tranne che non blocca il merge.
divinci ci run --layer=full --shadow --duration=14d --report-as=bot-commentQuando il tasso di falsi positivi resta sotto il 5% in modo sostenuto durante la finestra, lo passiamo a bloccante. Quando non lo è, stringiamo le soglie per slice, ricalibriamo il judge e ripetiamo la shadow. In entrambi i casi il team non viene preso in imboscata da un nuovo gate che scatta il primo giorno.
Un workflow GitHub Actions che davvero compone
Il pezzo che lega la torta a strati alla tua CI esistente gira in .github/workflows/llm-ci.yaml. Gli strati sono cablati in modo che quelli economici falliscano in fretta e quelli costosi girino solo quando serve — le catene needs: e i trigger filtrati per path fanno il lavoro[5].
name: LLM CI
on:
pull_request:
paths:
- 'prompts/**'
- 'config/models.yaml'
- 'eval/**'
- 'retrieval/**'
- 'manifests/**'
jobs:
contract:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v4
- run: divinci ci contract --manifest manifests/staging.yaml --fail-fast
smoke:
needs: contract
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- run: divinci ci run --layer=smoke --post-pr-comment
env:
DIVINCI_API_KEY: ${{ secrets.DIVINCI_API_KEY }}
full:
needs: smoke
if: contains(steps.changes.outputs.paths, 'prompts/') || contains(steps.changes.outputs.paths, 'config/models.yaml')
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- run: divinci ci run --layer=full --post-pr-comment --gate
env:
DIVINCI_API_KEY: ${{ secrets.DIVINCI_API_KEY }}Tre cose da notare. Gli strati si incatenano via needs:, quindi smoke non gira su un contract rotto e full non gira su uno smoke rotto. Il job full è filtrato per path ai cambiamenti che giustificano davvero un run da 12 minuti — la correzione di un refuso nel README non innesca la suite di gate. La flag --post-pr-comment è ciò che rende il diff per slice visibile senza uscire da GitHub.
Il loop di debug delle PR fallite
L’altra metà di “il gate è scattato” è “mostrami perché”. Un output della suite di regressione tipo slice medica completamento del task scesa di 0,04 non è azionabile senza i casi che l’hanno causato. Facciamo emergere i cinque peggiori diff per slice nel commento della PR, con l’input originale, l’output di baseline, l’output candidato e la trace di reasoning del judge. Il loop di debug è pensato per durare secondi, non minuti:
# Estrai i 5 peggiori casi che hanno fatto scattare il gate della slice medica su questa PR
divinci ci diffs --pr 1247 --slice medical --dimension task_completion --top 5Questa è la stessa superficie diagnostica dell’albero a sette step del post 6, cablata nel loop di feedback della CI. L’ingegnere che ha aperto la PR vede le evidenze a livello di caso sulla PR stessa; non deve andare ad aprire una dashboard di valutazione separata.
Disciplina del version control — prompt, dataset, judge come codice
I template di prompt, i golden dataset e i prompt del judge vivono tutti nel repo, hash-pinned nel manifest di release. Il manifest è l’unico oggetto che lega la suite a uno specifico stato riproducibile:
# manifests/staging.yaml — ogni run CI hasha questo
release_id: rel-staging
model: { sha: 0c1f9…, weights: r2://models/custom-v7.2, open_weights: true }
prompt: { sha: c4a8e…, template: prompts/support/v3.4.j2 }
retrieval: { sha: b21f0…, index: r2://indices/kb-2026-04 }
judge: { sha: d8e21…, rubric: eval/rubrics/v7.yaml }
dataset: { sha: a90b1…, file: eval/datasets/golden-2026-04.jsonl }Quando un run CI pubblica un punteggio, il punteggio è taggato con quell’hash del manifest. Quando un punteggio si muove, la domanda “quale input si è mosso” ha una risposta diretta: diffa il manifest, e lo strato che ha fatto scattare ti dice quale dimensione guardare per prima. Questo è il loop che la pipeline a quattro stadi del post 1 e la ricevuta vindex del post 4 chiudono insieme: il manifest è la primitiva di audit verso cui tutti e otto questi post, in inquadrature diverse, si sono diretti.
Cosa questo non risolve
Le stesse tre limitazioni oneste che abbiamo scritto in ogni post di questa serie.
- La CI non testa ciò che non è nella suite. Per quanto astuta sia la torta a strati, le uniche regressioni che cattura sono quelle che qualche caso nel golden dataset avrebbe segnalato. Lo strato replay mitiga questo per il behaviour drift, ma le query nuove che non sono mai state viste continuano a sfuggire finché non compaiono in produzione. Il sistema deve essere accoppiato al monitoraggio di produzione.
- Le cifre di costo cambiano con il pricing dei modelli. Ogni cifra di costo in questo post dipende dai tassi di token del judge, dai tassi di embedding e dai tassi di inferenza che fluttuano trimestralmente. I rapporti — 74% / 22% / 4%, 31% / 27% / 28% / 11% / 3% — sono le rivendicazioni portanti; le cifre in dollari sono illustrative per un istante nel tempo.
- Le modifiche di checkpoint lato provider restano difficili. Quando un provider closed-API aggiorna silenziosamente il modello dietro un nome stabile, lo strato contract non può catturarlo; solo la suite di gate può, e solo dopo il fatto. Mitighiamo pinnando identificatori espliciti di checkpoint ovunque il provider lo supporti e trattando il giorno in cui un checkpoint viene annunciato come un evento scatenante per un re-baseline della suite completa. Non possiamo prevenire il problema sottostante.
Chiudendo la serie
Questo è il post 8 di 8. L’arco completo:
- Come costruire una pipeline CI/CD per LLM con Divinci AI — la pipeline a quattro stadi (Register / Gate / Roll / Observe) all’interno della quale tutto il resto è vissuto.
- 10 fallimenti di release CI/CD nei modelli linguistici personalizzati — i modi di fallimento del 2026 con nome, ciascuno mappato sullo stadio che avrebbe dovuto catturarlo.
- 12 capacità di QA e release management per LLM — la matrice di capacità e il Venn a tre campi che colloca Divinci rispetto alle alternative.
- Validare e rilasciare LM personalizzati in campi regolamentati — il deep-dive di compliance, la mappatura regolatore-a-stadio, le ricevute vindex.
- Pipeline CI/CD automatizzate per LLM con instant rollback — lo strato operativo, lo spettro di automazione, la ricevuta di auto-rollback.
- Come diagnosticare i fallimenti QA di LLM personalizzati in 7 step — l’albero decisionale diagnostico; il modello è la risposta giusta all’incirca un allarme su sette.
- Test di regressione automatizzati per LLM personalizzati nel 2026 — gate Spearman slice-aware, judge calibrati, replay di trace di produzione a circuito chiuso.
- Questo post. L’infrastruttura CI che rende trattabile tutto quanto sopra su ogni PR.
I pezzi compongono: il manifest è la primitiva di audit, i gate sono lo strato di sicurezza, l’albero diagnostico è il loop di recupero, la ricevuta vindex è l’ancora esterna, e la torta a strati è ciò che rende l’intero sistema sostenibile su ogni commit. Se il tuo processo di release di LLM personalizzati non ha questi cinque elementi insieme, il gap è ciò di cui questi otto post hanno parlato.
FAQ
Qual è il test più economico che posso eseguire su ogni commit?
Un check di render del template di prompt. Gira in millisecondi, non richiede un judge, cattura una frazione sorprendente di rotture e non costa mai un centesimo misurabile. Se non lo stai ancora eseguendo, è il singolo pezzo di CI a più alto ROI che sappiamo come raccomandare.
Quanto dovrei aspettarmi che costi una pipeline CI per un LLM personalizzato?
Centesimi per PR tipica, dollari a una cifra bassa per PR di release-candidate. Il rapporto dipende dal pricing del judge e dalla frazione di PR che toccano prompt o configurazioni del modello. La quota del 4% di release-candidate sopra è tipica; per prodotti con iterazione frequente sui prompt la quota sale e la media cresce di conseguenza.
Dovrei eseguire la suite completa su ogni commit?
No. Filtra per path alle PR che toccano prompt, configurazioni del modello, retrieval o codice di valutazione. Per tutti gli altri cambiamenti, contract + smoke è sufficiente e un’attesa di 12 minuti su un refuso nel README ti farà perdere la fiducia del team entro uno sprint. La suite completa è preziosa; spendila dove il cambiamento può plausibilmente muovere una dimensione di qualità.
Come introduco un nuovo gate senza rompere tutti?
Finestra shadow di due settimane, non bloccante. Tara le soglie sul tasso di falsi positivi osservato durante la shadow. Passa a bloccante solo quando il tasso di falsi positivi sostenuto è sotto la tua tolleranza (noi usiamo il 5%). Tutto il resto è come ottieni un gate che tutti hanno imparato a ignorare.
Qual è l’unico numero che dovrei tracciare se ne traccio uno solo?
La frazione di regressioni confermate catturate prima della produzione. L’istogramma in questo post la pone a ~97% nei deployment Divinci maturi. Il 3% che sfugge è il motivo per cui esiste l’instant rollback. Il 97% è ciò per cui esiste la suite.
Riferimenti
- DORA / Google Cloud. "Accelerate State of DevOps — CI velocity, change-failure-rate and time-to-restore-service." I baseline cross-industry che rendono "12 minuti per PR è troppo lento" un'affermazione difendibile e non un'opinione.
- Zheng et al. "Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena." arXiv:2306.05685. L'evidenza empirica che le chiamate batchate di LLM-as-judge possono preservare la calibrazione alle dimensioni di batch usate negli strati smoke e full — la ragione per cui le cifre di costo in questo post sono raggiungibili.
- Pope et al. "Efficiently Scaling Transformer Inference." arXiv:2211.05102. Le tecniche di riuso della KV-cache e di prefix-sharing citate nella sezione sul dimensionamento della flotta CI.
- Pan, Tianpan. "The Semver Lie: how a minor LLM update broke production." 29 aprile 2026. Il modo di fallimento del 2026 con nome per le suite di regressione solo-aggregate; il motivo per cui la torta a strati della CI è slice-aware da cima a fondo.
- GitHub. "GitHub Actions — chaining jobs with `needs:` and conditional execution." La primitiva contro cui lo .yaml in questo post compone.
- Zhang et al. "BERTScore: Evaluating Text Generation with BERT." arXiv:1904.09675. La metrica euristica di similarità semantica indicata come alternativa a LLM-as-judge per gli strati più economici; non è ciò che eseguiamo al gate time, ma è utile nello strato contract per il rilevamento di frasi proibite su larga scala.
Ready to Build Your Custom AI Solution?
Discover how Divinci AI can help you implement RAG systems, automate quality assurance, and streamline your AI development process.
Get Started Today