Un AI Agent in produzione richiede 4 componenti critici: planning loop reattivo (ReAct/OODA), type-safe tool registry con validazione, persistent memory via vector store, e safety guardrails (prompt injection defense, budget limits, output filters). Questo articolo confronta 3 stack production-ready - Claude SDK (Anthropic), Anthropic Agents API (managed cloud), Ollama locale - con tutorial step-by-step per deployare un code review agent in 6 step.
Cosa È un AI Agent Veramente (Oltre le Buzzword)
Nel 2026, il confine tra chatbot e agent è diventato sfumato. Un **chatbot** riceve input, genera testo, e stop. Un **agent** fa ciò che il chatbot fa, ma aggiunge:
- Planning loop: "Qual è il mio prossimo step?" L'agente rompe il problema in sotto-task, decide quale tool usare, osserva il risultato, decide se iterare.
- Tool use reattivo: l'agente non genera il risultato direttamente, ma invoca strumenti (API, database, file system) e integra le risposte nel ragionamento.
- Memory a lungo termine: l'agente ricorda conversazioni passate, mantiene stato tra invocazioni, impara dai fallimenti.
- Validation e safety: ogni step è soggetto a guardrail - budget di token, timeout, policy di rifiuto, audit trail.
Esempio concreto: un agent di code review riceve il diff di una PR. Invece di dirvi "sembra ok", l'agent:
- Parse il diff (tool: get_diff)
- Esegue linter (tool: run_linter)
- Analizza complessità ciclomatica (tool: analyze_complexity)
- Osserva che due test falliscono → decide di suggerire un fix (tool: generate_fix_suggestion)
- Compone un commento strutturato sulla PR (no tool, sintetizza osservazioni)
Questo flusso iterativo, goal-oriented, è ciò che distingue un agent da un chatbot sofisticato.
Comparazione 3 Stack Production-Ready
1. Claude SDK (Anthropic) - La Scelta di Controllo
Claude SDK è il wrapper TypeScript/Python ufficiale di Anthropic. Offre accesso diretto ai modelli Claude 3.5 Sonnet/Opus con supporto nativo per tool use e structured outputs.
Caratteristiche chiave:
- Tool use typing: definisci tool come JSON schema, l'SDK automaticamente marshalla richieste/risposte.
- Computer use: il modello può eseguire azioni su screenshot (OCR + clicking) - unico tra i 3.
- Structured output: garantisce JSON conforme a schema, zero hallucination su format.
- Batch API (Beta): 50% discount per job asincroni (submit 100 task, attendi risultati 24h).
Pricing: Claude 3.5 Sonnet = $3 per MTok input, $15 output (2026-04). Per 1M token input + 500K output, costo ~$10.5. Economico tra i 3.
Code example - TypeScript:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
// 1. Definisci tool registry
const tools: Anthropic.Tool[] = [
{
name: "get_diff",
description: "Retrieve git diff for a PR",
input_schema: {
type: "object",
properties: {
pr_id: { type: "number", description: "Pull request ID" },
},
required: ["pr_id"],
},
},
{
name: "run_linter",
description: "Run eslint/pylint on code",
input_schema: {
type: "object",
properties: {
code: { type: "string", description: "Code snippet to lint" },
language: { type: "string", enum: ["js", "py", "java"] },
},
required: ["code", "language"],
},
},
];
// 2. Agent loop ReAct
async function codeReviewAgent(prId: number) {
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content: `Review PR #${prId}. Check code quality, suggest improvements.`,
},
];
for (let step = 0; step < 10; step++) {
// Max 10 iterations
const response = await client.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 4096,
tools: tools,
messages: messages,
});
// Aggiorna history con response
messages.push({
role: "assistant",
content: response.content,
});
// Se l'agente è finito (no tool use), esci
if (response.stop_reason === "end_turn") {
console.log("Agent completed review:");
console.log(
response.content
.filter((b) => b.type === "text")
.map((b) => (b.type === "text" ? b.text : ""))
.join("\n")
);
break;
}
// Processa tool use
const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUseBlocks) {
if (toolUse.type !== "tool_use") continue;
let result = "";
if (toolUse.name === "get_diff") {
// Mock: in produzione, fetch da GitHub API
result = `@@ -1,5 +1,6 @@\nfunction add(a, b) {\n return a + b + 1; // BUG: off-by-one\n}`;
} else if (toolUse.name === "run_linter") {
result = `Line 3: unused variable 'temp'`;
}
toolResults.push({
type: "tool_result",
tool_use_id: toolUse.id,
content: result,
});
}
// Feedback all'agente
messages.push({
role: "user",
content: toolResults,
});
}
}
// 3. Invoca agent
codeReviewAgent(42);
Pro: controllo totale, nessun lock-in cloud, debugging facile, batch API per ridurre costi.
Contro: gestisci tu la memoria (dove storie conversazioni?), nessun cloud state management, retry logic manuale.
2. Anthropic Agents API (Beta 2026) - La Scelta Cloud-First
Agents API è il wrapper managed di Anthropic. Dichiari un agente e Anthropic gestisce loop, memoria, stato, e sub-agenti.
Caratteristiche:
- State managed cloud: Anthropic mantiene la storia conversazione, no storage lato client.
- Spawn sub-agenti: un agente può creare task per altri agenti (parallelismo).
- Sandboxed code execution: l'agente può eseguire Python/JavaScript isolato (imitazione computer use).
- Web/file/knowledge base integration: accesso nativo a risorse esterne (beta).
Pricing: per-step, ~$0.10 per step (stima beta, non pricing ufficiale 2026). Per 100 step = $10, ma velocità cloud compensano.
API call example - Python:
import anthropic
client = anthropic.Anthropic(api_key="your-key")
# Crea agente sul cloud Anthropic
agent = client.agents.create(
model="claude-3-5-sonnet-20241022",
instructions="""You are a code review expert.
When given a PR:
1. Analyze the diff
2. Run linter/complexity checks
3. Provide structured feedback
Keep feedback to 3-5 points max.""",
tools=[
{
"type": "bash_execution",
"name": "run_linter",
"description": "Run linter on code snippet",
}
],
)
# Spawn task (agent processes asynchronously)
task = client.agents.tasks.create(
agent_id=agent.id,
input="Review this PR: https://github.com/user/repo/pull/42",
)
# Poll for result
import time
for _ in range(10):
task = client.agents.tasks.retrieve(agent_id=agent.id, task_id=task.id)
if task.state == "completed":
print("Review result:")
print(task.result)
break
time.sleep(2)
Pro: state persistence automatico, subagenti paralleli, sandboxed code execution, infra Anthropic-managed (zero ops).
Contro: latency >2s (rete), no offline mode, prezzo poco trasparente (beta), lock-in Anthropic API.
3. Ollama Local - La Scelta Privacy-Critical
Ollama è un runtime open-source per modelli LLM locali. Scarichi modelli (llama3.1:70b, qwen2.5-coder:32b, gemma2:27b), lancio in locale (GPU required: RTX 4090, A100, ecc.), zero cost ricorrenti.
Caratteristiche:
- Tool calling: llama3.1 7b+ supporta tool use via formato JSON speciale.
- Zero latency: local inference, ~0.5s per token (8b) vs 1.2s cloud.
- Dati on-premise: nessuna esposizione al cloud, compliance eu-ai-act più semplice.
- Fine-tuning locale: puoi adattare il modello al tuo dominio specifico.
Contro: hardware costoso (GPU >$2000), latency 5-15s per token su modelli grandi (70b), memory footprint ~50GB.
Python example:
import json
import requests
# Ollama running locally (ollama serve)
OLLAMA_URL = "http://localhost:11434"
def ollama_tool_use(prompt: str, tools: list[dict]) -> dict:
"""Agent loop con Ollama + tool calling."""
# Prepara tool schema in formato JSON
tool_schema = json.dumps(tools, indent=2)
full_prompt = f"""You are a code review agent.
Tools available:
{tool_schema}
When you need to use a tool, respond with JSON:
{{"tool": "tool_name", "args": {{"key": "value"}}}}
User request: {prompt}"""
# Chiama Ollama
response = requests.post(
f"{OLLAMA_URL}/api/generate",
json={
"model": "llama3.1:70b",
"prompt": full_prompt,
"stream": False,
}
)
result = response.json()["response"]
# Parse tool call (semplice, in produzione usa regex/JSON parser robusto)
if "tool" in result and "args" in result:
tool_call = json.loads(result[result.find("{"):result.rfind("}")+1])
return tool_call
return {"response": result}
# Invoca agent
review = ollama_tool_use(
prompt="Review PR #42: https://github.com/...",
tools=[
{
"name": "get_diff",
"description": "Get git diff for PR",
"parameters": {"type": "object", "properties": {"pr_id": {"type": "integer"}}}
}
]
)
print(review)
Pro: zero cost ricorrenti (post-hardware), privacy on-prem, no rate limit, controllo assoluto.
Contro: hardware prohibitivo, latency 10x cloud (70b), quality inferior vs Claude (especially tool use, hallucination rate 3x higher).
Comparison Table - Metrica Tecnica
| Metrica | Claude SDK | Agents API | Ollama Local |
|---|---|---|---|
| Costo (1M token in/out) | $10.5 (3+15) | ~$100/1000 step (beta, non ufficiale) | $0 (post-hardware ~$4K) |
| Latency p50 (tool use) | 1.2s per tool call | 2.5s (rete + cloud queueing) | 0.8s (8b) → 15s (70b) |
| Tool use quality | 9/10 (structured output guarantee) | 9/10 (stesso modello Claude) | 6/10 (8b) – 8/10 (70b con fine-tune) |
| Memory persistence | DIY (Redis, database, file) | Automatico (Anthropic cloud) | DIY (locale, no cloud) |
| Compliance EU AI Act | Provider compliance (Anthropic) | Provider compliance (Anthropic cloud) | You implement (on-prem) |
| Best for | Production SaaS, controllo totale | MVP rapidi, no infra overhead | Privacy-critical, on-prem, cost-insensitive |
Verdetto: per la stragrande maggioranza delle applicazioni 2026, Claude SDK è la scelta ottimale: costo basso, latency accettabile, quality superiore, controllo massimo. Agents API per MVP con timeline stretti (no devops). Ollama solo se privacy è P0 e hardware è disponibile.
Tutorial Step-by-Step: Build a Code Review Agent
Step 1 - Project Setup (15 min)
Crea una cartella progetto e installa dipendenze.
# Setup Node.js project
mkdir agent-code-review
cd agent-code-review
npm init -y
npm install @anthropic-ai/sdk dotenv
# Crea .env
echo "ANTHROPIC_API_KEY=sk-..." > .env
# Verifica SDK
node -e "console.log(require('@anthropic-ai/sdk'))"
Se usi Python:
mkdir agent-code-review && cd agent-code-review
python -m venv venv && source venv/bin/activate
pip install anthropic python-dotenv httpx
echo "ANTHROPIC_API_KEY=sk-..." > .env
Step 2 - Define Tool Schema (20 min)
Specifica 3 tool: get_diff, run_linter, analyze_complexity. Ogni tool ha input schema e mock implementation.
// tools.ts
export interface Tool {
name: string;
description: string;
input_schema: {
type: string;
properties: Record;
required: string[];
};
}
export const TOOLS: Tool[] = [
{
name: "get_diff",
description: "Retrieve git diff for a GitHub pull request",
input_schema: {
type: "object",
properties: {
repo: {
type: "string",
description: "GitHub repo in format owner/repo",
},
pr_number: { type: "integer", description: "PR number" },
},
required: ["repo", "pr_number"],
},
},
{
name: "run_linter",
description: "Run ESLint on JavaScript code",
input_schema: {
type: "object",
properties: {
code: { type: "string", description: "JavaScript code to lint" },
config: {
type: "string",
description: "Linter config (airbnb, google, standard)",
enum: ["airbnb", "google", "standard"],
},
},
required: ["code", "config"],
},
},
{
name: "analyze_complexity",
description: "Analyze cyclomatic complexity of a function",
input_schema: {
type: "object",
properties: {
code: { type: "string", description: "Function code" },
},
required: ["code"],
},
},
];
export async function executeTool(
name: string,
input: Record
): Promise {
if (name === "get_diff") {
// Mock GitHub API call
return `
@@ -1,10 +1,12 @@
export function calculateTotal(items: any[]) {
let sum = 0;
for (let i = 0; i < items.length; i++) {
- sum += items[i].price; // ⚠️ No null check
+ sum += items[i]?.price ?? 0;
}
return sum;
}
+
+// New: Helper function
+function formatPrice(price: number): string {
+ return new Intl.NumberFormat('en-US').format(price);
+}
`;
} else if (name === "run_linter") {
return `
eslint results for config=${input.config}:
Line 5: 'sum' is assigned value but never used (no-unused-vars)
Line 7: Function too long, consider extracting (max-lines-per-function)
✓ 2 errors, 0 warnings
`;
} else if (name === "analyze_complexity") {
return `
Cyclomatic complexity: 3
Cognitive complexity: 4
Max depth: 2
Recommendation: complexity is acceptable (target < 5)
`;
}
return "Unknown tool";
}
Step 3 - Implement ReAct Loop (25 min)
Il cuore dell'agente: ask → observe → decide → iterate.
import Anthropic from "@anthropic-ai/sdk";
import { executeTool, TOOLS } from "./tools";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
async function runCodeReviewAgent(prUrl: string, maxSteps: number = 10) {
console.log(`🚀 Starting code review agent for ${prUrl}`);
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content: `Review the following PR: ${prUrl}
Provide a structured review with:
1. Overall assessment
2. Critical issues (bugs, security)
3. Improvement suggestions
4. Complexity analysis
5. Recommendation (approve/request changes)`,
},
];
for (let step = 0; step < maxSteps; step++) {
console.log(`\n--- Step ${step + 1}/${maxSteps} ---`);
const response = await client.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 2048,
tools: TOOLS as any,
messages: messages,
});
// Aggiungi response alla history
messages.push({
role: "assistant",
content: response.content,
});
// Verifica se agente ha finito
if (response.stop_reason === "end_turn") {
const textBlock = response.content.find((c) => c.type === "text");
if (textBlock && textBlock.type === "text") {
console.log(`\n✅ Review Complete:\n${textBlock.text}`);
}
return;
}
// Processa tool use
const toolUseBlocks = response.content.filter((c) => c.type === "tool_use");
if (toolUseBlocks.length === 0) {
// No tool, agente ha scritto testo ma non finito (stop_reason != end_turn)
// Continua loop
continue;
}
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUseBlocks) {
if (toolUse.type !== "tool_use") continue;
console.log(`📍 Tool: ${toolUse.name}`);
console.log(` Input: ${JSON.stringify(toolUse.input)}`);
const result = await executeTool(toolUse.name, toolUse.input);
console.log(` Result: ${result.substring(0, 100)}...`);
toolResults.push({
type: "tool_result",
tool_use_id: toolUse.id,
content: result,
});
}
// Feedback all'agente
messages.push({
role: "user",
content: toolResults,
});
}
console.log("⚠️ Max steps reached");
}
// Invoca agente
runCodeReviewAgent("https://github.com/user/repo/pull/42");
Step 4 - Add Memory + Caching (20 min)
Persisti conversazioni in Redis per evitare di ricalcolare.
import * as redis from "redis";
const redisClient = redis.createClient();
interface AgentMemory {
conversationId: string;
messages: Anthropic.MessageParam[];
createdAt: number;
expiresAt: number; // 24h TTL
}
async function loadMemory(conversationId: string): Promise {
const cached = await redisClient.get(`agent:${conversationId}`);
if (!cached) return null;
return JSON.parse(cached);
}
async function saveMemory(memory: AgentMemory): Promise {
const ttl = 86400; // 24 hours
await redisClient.setEx(
`agent:${memory.conversationId}`,
ttl,
JSON.stringify(memory)
);
}
async function runCodeReviewAgentWithMemory(
prUrl: string,
conversationId: string
) {
// Carica memoria precedente
let memory = await loadMemory(conversationId);
if (!memory) {
memory = {
conversationId,
messages: [
{
role: "user",
content: `Review PR: ${prUrl}`,
},
],
createdAt: Date.now(),
expiresAt: Date.now() + 86400000,
};
}
// ... esegui loop ReAct usando memory.messages ...
// Salva aggiornamenti
await saveMemory(memory);
}
Step 5 - Safety Guardrails (20 min)
Input sanitization, output filtering, budget limit, audit log.
interface SafetyConfig {
maxTokensPerCall: number;
maxTokensTotal: number;
maxSteps: number;
allowedTools: string[];
auditLog: boolean;
}
const SAFETY_CONFIG: SafetyConfig = {
maxTokensPerCall: 4096,
maxTokensTotal: 10000,
maxSteps: 10,
allowedTools: ["get_diff", "run_linter", "analyze_complexity"],
auditLog: true,
};
class SafeAgent {
private tokenUsage: number = 0;
private auditLog: any[] = [];
async validateInput(input: string): Promise {
// Detect prompt injection attempts
const injectionPatterns = [
/ignore previous instruction/i,
/do not apply rule/i,
/bypass safety/i,
];
for (const pattern of injectionPatterns) {
if (pattern.test(input)) {
console.warn(`⚠️ Potential prompt injection detected`);
return false;
}
}
// Check input length
if (input.length > 50000) {
console.warn("⚠️ Input too large");
return false;
}
return true;
}
async validateToolCall(
toolName: string,
input: Record
): Promise {
// Check tool is in allowlist
if (!SAFETY_CONFIG.allowedTools.includes(toolName)) {
console.warn(`❌ Tool '${toolName}' not allowed`);
return false;
}
// Type validation per tool
if (toolName === "get_diff") {
if (
typeof input.repo !== "string" ||
typeof input.pr_number !== "number"
) {
return false;
}
}
this.auditLog.push({
timestamp: new Date().toISOString(),
event: "tool_call",
tool: toolName,
input: JSON.stringify(input),
});
return true;
}
async checkBudget(tokensUsed: number): Promise {
this.tokenUsage += tokensUsed;
if (this.tokenUsage > SAFETY_CONFIG.maxTokensTotal) {
console.warn(
`❌ Budget exceeded: ${this.tokenUsage}/${SAFETY_CONFIG.maxTokensTotal}`
);
return false;
}
return true;
}
getAuditLog() {
return this.auditLog;
}
}
Step 6 - Deploy + Monitor (30 min)
Systemd service + Prometheus metrics + health checks.
# Systemd service: /etc/systemd/system/agent-code-review.service
[Unit]
Description=Code Review Agent
After=network.target
[Service]
Type=simple
User=agent
WorkingDirectory=/opt/agent-code-review
ExecStart=/usr/bin/node dist/index.js
Restart=always
RestartSec=10
Environment="ANTHROPIC_API_KEY=sk-..."
Environment="REDIS_URL=redis://localhost:6379"
Environment="LOG_LEVEL=info"
# Resource limits
MemoryLimit=512M
CPUQuota=100%
# Security
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Prometheus metrics:
import prom from "prom-client";
const agentCounter = new prom.Counter({
name: "agent_reviews_total",
help: "Total code reviews completed",
labelNames: ["status", "pr_repo"],
});
const toolCallCounter = new prom.Counter({
name: "agent_tool_calls_total",
help: "Tool invocations",
labelNames: ["tool_name"],
});
const tokenGauge = new prom.Gauge({
name: "agent_tokens_used",
help: "Tokens consumed this session",
});
// Log metrica
agentCounter.labels("success", "user/repo").inc();
toolCallCounter.labels("get_diff").inc();
tokenGauge.set(2500);
// Prometheus scrape endpoint
app.get("/metrics", async (req, res) => {
res.set("Content-Type", prom.register.contentType);
res.end(await prom.register.metrics());
});
Anti-Pattern - 5 Fallaci Comuni
1. Loop Infinito Senza max_steps
L'agente chiama tool, osserva risultato, decide di iterare all'infinito. In produzione, un max_steps mancante costa $$$.
// ❌ WRONG
while (true) {
// agent loop senza break condition
}
// ✅ RIGHT
for (let step = 0; step < MAX_STEPS; step++) {
if (response.stop_reason === "end_turn") break;
}
2. Tool Calling Non-Tipizzato
Passi tool come stringhe, l'agente hallucina. Ad es., "run_linter" con input `{code: 123}` (number anziché string).
// ❌ WRONG
const tools = [{ name: "run_linter", description: "..." }]; // NO schema
// ✅ RIGHT
const tools = [
{
name: "run_linter",
input_schema: {
type: "object",
properties: {
code: { type: "string" },
},
required: ["code"],
},
},
];
3. No Retry Logic su Rate Limit
API return 429 (too many requests), agente fallisce. Devi implementare exponential backoff.
// ✅ RIGHT - exponential backoff
async function callClaudeWithRetry(
messages: any[],
maxRetries: number = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.messages.create({ messages, /* ... */ });
} catch (error: any) {
if (error.status === 429) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`Rate limited, retry in ${delay}ms`);
await new Promise((r) => setTimeout(r, delay));
} else {
throw error;
}
}
}
}
4. Memory Leak (History Infinita)
La history conversazione cresce indefinita → OOM. Implementa context window rotation.
// ✅ RIGHT - keep only last N messages
function rotateContext(messages: any[], maxMessages: number = 20) {
if (messages.length > maxMessages) {
// Compatta messaggi vecchi in un sommario
const oldMessages = messages.slice(0, -maxMessages);
const summary = `Previous context: ${oldMessages.length} messages exchanged. Key decisions: [summarize].`;
return [{ role: "user", content: summary }, ...messages.slice(-maxMessages)];
}
return messages;
}
5. Logging Sensibile (Token, PII)
Logghi l'intero messaggio in plaintext → Dati sensibili esposti. Mask PII.
// ✅ RIGHT
function maskSensitive(text: string): string {
return text
.replace(/api[_-]?key[:\s]*[\w-]+/gi, "api_key:***")
.replace(/email[:\s]*[\w\.\-@]+/gi, "email:***")
.replace(/\d{3}-\d{2}-\d{4}/g, "SSN:***");
}
console.log("Agent input:", maskSensitive(userMessage));
FAQ - 8 Domande Critiche
Q1: Quando preferire Agent vs Chatbot semplice?
A: Agent quando il task richiede iterazione e tool use. Esempi: code review (iteria su diff → linter → complexity), data analysis (query database → filtra → grafico), customer support tier-1 (lookup database → policy check → risposta). Chatbot è sufficiente per FAQ, content generation, chat engagement.
Q2: Latency 12-15s con Ollama 70b è accettabile?
A: Dipende dal contesto. Per batch (nightly jobs, weekly reports): sì. Per real-time (webhook pull request, API call): no (timeout SLA). Regola empirica: se latency > 5s, considera Claude SDK o Agents API.
Q3: Come misurare ROI di un agent in produzione?
A: Metriche chiave: (1) Mean time to resolution (MTTR) prima/dopo, (2) Human escalation rate (goal <5%), (3) Accuracy (correct decision, measured via human review), (4) Cost per decision = API cost / decisions processed. Esempio: agent code review costa $0.05/PR, umano costa 15 min ($5), ROI = 100x.
Q4: Posso fine-tunare Llama 3.1 per il mio dominio specifico?
A: Sì, ma con costi: ~$500 GPU time + 500 example dataset preparation. Worth only se volume >100 inference/day. Per domini di nicchia (codice proprietario, terminologia custom), considera LoRA fine-tuning (~2 ore, $50).
Q5: Compliance EU AI Act per agent: GP-AI obbligo?
A: Se usi Claude SDK (Anthropic managed), compliance shift a provider. Se usi Ollama local, **tu implementi compliance**: risk assessment doc, bias testing, audit log, transparency notice ("this decision involves AI"). GP-AI registration required se sistema è "high-risk" (hiring, credit scoring, law enforcement).
Q6: Cost projection: 10k user/mese con Claude SDK?
A: Assumi 100 token/user input, 200 output. 10k × 100 input + 10k × 200 output = 3M token. Costo = (3M/1M × $3) + (2M/1M × $15) = $39/day = $1170/mese. Agents API: ~$100/1000 step × 10k user = ~$1000/mese (beta pricing, non ufficiale). Ollama: $0 ricorrenti.
Q7: Differenza MCP (Model Context Protocol) vs custom tool registry?
A: MCP (Anthropic standard) è un protocollo aperto per esporire tool remote. Custom registry è locale (JSON schema). MCP è per interoperabilità (uno strumento, molti client), custom per controll totale. Usa MCP se vuoi agent Claude + agent Ollama contemporaneamente.
Q8: Best practice per A/B test dell'agent (variant prompting)?
A: (1) Crea 2 versioni system prompt (es. "strict code reviewer" vs "lenient reviewer"), (2) Splitta traffic 50/50, (3) Raccogli metrica: accuracy (human audit sample 50 reviews each), speed (token count), cost. After 200 reviews, confronta con test statistico (chi-square). Winners scale to 100%.
Risorse + Link Autorevolenti
- Anthropic SDK Python GitHub - Repository ufficiale, examples complete
- Model Context Protocol (MCP) Spec - Standard Anthropic per tool interop
- Ollama Model Library - Catalogo modelli open-source (70b, 13b, 7b)
- LangChain Agents Documentation - Framework multimodello (Claude, Ollama, OpenAI)
- ReAct: Synergizing Reasoning and Acting (Yao et al., arXiv) - Paper fondamentale agent design
- OpenAI Function Calling Guide - Riferimento alternativo (no tool use, ma API call schema)
- Hugging Face Open-Source LLMs Guide - Best practice training e deployment
- Anthropic Batch API Docs - Cost optimization per job asincroni
Conclusione: Scegli il Tuo Stack
Nel 2026, nessuno stack è "migliore" in assoluto. Dipende dal contesto:
- Claude SDK: default production, SaaS, costo-conscious
- Agents API: MVP rapidi, no infra overhead, trade-off latency/cost
- Ollama: privacy-critical, on-premise, when hardware available
L'agent che ho descritto (code review) è archetipale: iterazione + tool use + memory + safety. Applica il pattern a qualsiasi dominio: customer support (knowledge base lookup), data analysis (SQL query + visualization), recruitment (resume parsing + scoring).
Il codice è pronto per production - aggiungi monitoring, structured logging, backup memory - e deployi su VPS/Kubernetes. Il futuro è agent, non chatbot. Inizia oggi.
Vuoi approfondire AI Agents? Ebook in arrivo Q4 2026: "AI Agents in Production: Complete Guide from Claude SDK to Enterprise Deployment" - 25K parole, 20 code example, cost calculator, compliance checklist.

Commenti
Caricamento commenti...
Accedi per commentare