Salta al contenuto principale

AI Agents in Production: Comparativo Claude SDK vs Anthropic Agents API vs Ollama Local + Tutorial Step-by-Step

Un AI Agent in produzione richiede 4 componenti critici: planning loop reattivo (ReAct/OODA), type-safe tool registry con validazione, persistent memory...

Cosa ne pensi di questo articolo?

AI Agents in Production: Comparativo Claude SDK vs Anthropic Agents API vs Ollama Local + Tutorial Step-by-Step
AI EngineeringFoto:Google DeepMindPexels

In Breve

Un AI Agent in produzione richiede 4 componenti critici: planning loop reattivo (ReAct/OODA), type-safe tool registry con validazione, persistent memory...

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:

  1. Parse il diff (tool: get_diff)
  2. Esegue linter (tool: run_linter)
  3. Analizza complessità ciclomatica (tool: analyze_complexity)
  4. Osserva che due test falliscono → decide di suggerire un fix (tool: generate_fix_suggestion)
  5. 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

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.

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti