Pattern di integrazione AI che abbiamo imparato
Dopo mesi di sviluppo con LLM, ecco i pattern che funzionano davvero in produzione e quelli che sembrano buone idee ma non lo sono.
lintedhub
redazione tecnicaPattern di integrazione AI che abbiamo imparato
Integrare LLM in produzione è diverso dal fare demo. Ecco cosa abbiamo imparato dopo mesi di trial and error.
Pattern 1: Structured Output First
Il primo errore che tutti fanno: chiedere all'LLM di generare testo libero e poi provare a parsarlo.
Non fare questo:
const response = await openai.chat.completions.create({
messages: [{ role: "user", content: "Analizza questo testo e dimmi il sentiment" }],
});
// Poi provare a parsare response.choices[0].message.content
// Buona fortuna.
Fai questo invece:
const response = await openai.chat.completions.create({
messages: [{ role: "user", content: "Analizza questo testo" }],
response_format: { type: "json_object" },
functions: [{
name: "analyze_sentiment",
parameters: {
type: "object",
properties: {
sentiment: { enum: ["positive", "negative", "neutral"] },
confidence: { type: "number", minimum: 0, maximum: 1 },
reasoning: { type: "string" }
},
required: ["sentiment", "confidence"]
}
}]
});
Structured output elimina un'intera categoria di bug.
Pattern 2: Retry con Backoff Esponenziale
Gli LLM falliscono. Rate limits, timeout, errori transienti. Non puoi ignorarlo.
async function callWithRetry<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000 + Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error("Unreachable");
}
Pattern 3: Fallback Chain
Non dipendere da un solo provider o modello.
const providers = [
{ name: "openai-gpt4", fn: callOpenAI },
{ name: "anthropic-claude", fn: callAnthropic },
{ name: "openai-gpt35", fn: callOpenAI35 }, // cheaper fallback
];
async function callLLM(prompt: string) {
for (const provider of providers) {
try {
return await provider.fn(prompt);
} catch (error) {
console.error(`${provider.name} failed, trying next...`);
continue;
}
}
throw new Error("All providers failed");
}
Pattern 4: Cache Semantico
Le stesse domande tornano. Non pagare due volte.
import { createHash } from "crypto";
function hashPrompt(prompt: string): string {
return createHash("sha256").update(prompt).digest("hex");
}
async function cachedLLMCall(prompt: string) {
const hash = hashPrompt(prompt);
const cached = await cache.get(hash);
if (cached) {
return JSON.parse(cached);
}
const result = await callLLM(prompt);
await cache.set(hash, JSON.stringify(result), { ex: 3600 });
return result;
}
Per cache semantico più avanzato, considera embedding + vector search.
Pattern 5: Prompt Template con Validazione
I prompt sono codice. Trattali come tale.
import { z } from "zod";
const ReviewPromptSchema = z.object({
code: z.string().min(1),
language: z.enum(["typescript", "python", "go"]),
context: z.string().optional(),
});
function buildReviewPrompt(input: z.infer<typeof ReviewPromptSchema>) {
const validated = ReviewPromptSchema.parse(input);
return `
Review this ${validated.language} code:
\`\`\`${validated.language}
${validated.code}
\`\`\`
${validated.context ? `Context: ${validated.context}` : ""}
Focus on:
1. Security vulnerabilities
2. Performance issues
3. Best practice violations
`;
}
Anti-Pattern: Fine-tuning Prematuro
"Il modello non fa esattamente quello che voglio, facciamo fine-tuning!"
No. Prima:
- Migliora il prompt
- Aggiungi esempi few-shot
- Usa structured output
- Considera RAG
Il fine-tuning ha senso solo quando hai provato tutto il resto e hai abbastanza dati di qualità.
Conclusione
L'integrazione AI in produzione richiede lo stesso rigore di qualsiasi altro sistema distribuito. Fallimenti, latenza variabile, costi imprevedibili: tutto va gestito esplicitamente.
I pattern qui sopra non sono esaustivi, ma coprono l'80% dei problemi che abbiamo incontrato.
Hai un progetto in mente?
Trasformiamo scelte tecniche complesse in sistemi in produzione.
Se stai valutando stack, architetture o integrazioni AI, parliamone. Niente pitch: una conversazione tecnica.
ParliamoneContinua a leggere
Tutti gli articoliEval set: il test driven development per i sistemi AI
Senza un eval set scritto, ogni modifica a un prompt è una preghiera. Ecco come costruiamo eval realistici, li mettiamo in CI e perché trattiamo i prompt come codice di produzione.
Direttive scritte: trattare i prompt come codice di produzione
Un prompt non è un messaggio in chat, è un artefatto di sistema. Come strutturiamo direttive, le versioniamo, le rivediamo in PR e perché evitiamo le "chat improvvisate" sui task seri.
MCP: collegare l'AI ai sistemi del cliente senza farsi male
Model Context Protocol è il modo serio per dare a un modello accesso a tool e dati interni. Come progettiamo server MCP custom, gestiamo permessi e teniamo l'audit trail.