Prerequisiti

  • Python 3.10+
  • claude-code-sdk da PyPI
  • Node.js 18+
  • @anthropic-ai/claude-code da NPM

Per visualizzare il codice sorgente dell’SDK Python, consulta il repository claude-code-sdk.

Per lo sviluppo interattivo, usa IPython: pip install ipython

Installazione

Installa claude-code-sdk da PyPI e @anthropic-ai/claude-code da NPM:

pip install claude-code-sdk
npm install -g @anthropic-ai/claude-code  # Dipendenza richiesta

(Opzionale) Installa IPython per lo sviluppo interattivo:

pip install ipython

Avvio rapido

Crea il tuo primo agente:

# legal-agent.py
import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def main():
    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un assistente legale. Identifica i rischi e suggerisci miglioramenti.",
            max_turns=2
        )
    ) as client:
        # Invia la query
        await client.query(
            "Rivedi questa clausola contrattuale per potenziali problemi: 'La parte accetta una responsabilità illimitata...'"
        )

        # Trasmetti la risposta in streaming
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                # Stampa il contenuto in streaming mentre arriva
                for block in message.content:
                    if hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

if __name__ == "__main__":
    asyncio.run(main())

Salva il codice sopra come legal-agent.py, quindi esegui:

python legal-agent.py

Per i notebook IPython/Jupyter, puoi eseguire il codice direttamente in una cella:

await main()

Gli esempi Python in questa pagina usano asyncio, ma puoi anche usare anyio.

Utilizzo di base

L’SDK Python fornisce due interfacce principali:

1. La classe ClaudeSDKClient (consigliata)

Migliore per risposte in streaming, conversazioni multi-turno e applicazioni interattive:

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def main():
    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un ingegnere delle prestazioni",
            allowed_tools=["Bash", "Read", "WebSearch"],
            max_turns=5
        )
    ) as client:
        await client.query("Analizza le prestazioni del sistema")

        # Trasmetti risposte in streaming
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

# Esegui come script
asyncio.run(main())

# O in IPython/Jupyter: await main()

2. La funzione query

Per query semplici e singole:

from claude_code_sdk import query, ClaudeCodeOptions

async for message in query(
    prompt="Analizza le prestazioni del sistema",
    options=ClaudeCodeOptions(system_prompt="Sei un ingegnere delle prestazioni")
):
    if type(message).__name__ == "ResultMessage":
        print(message.result)

Opzioni di configurazione

L’SDK Python accetta tutti gli argomenti supportati dalla riga di comando attraverso la classe ClaudeCodeOptions.

Parametri ClaudeCodeOptions

from claude_code_sdk import ClaudeCodeOptions

options = ClaudeCodeOptions(
    # Configurazione principale
    system_prompt="Sei un assistente utile",
    append_system_prompt="Istruzioni di sistema aggiuntive",
    max_turns=5,
    model="claude-3-5-sonnet-20241022",
    max_thinking_tokens=8000,
    
    # Gestione degli strumenti
    allowed_tools=["Bash", "Read", "Write"],
    disallowed_tools=["WebSearch"],
    
    # Gestione della sessione
    continue_conversation=False,
    resume="session-uuid",
    
    # Ambiente
    cwd="/percorso/alla/directory/di/lavoro",
    add_dirs=["/directory/contesto/aggiuntiva"],
    settings="/percorso/alle/impostazioni.json",
    
    # Permessi
    permission_mode="acceptEdits",  # "default", "acceptEdits", "plan", "bypassPermissions"
    permission_prompt_tool_name="mcp__approval_tool",
    
    # Integrazione MCP
    mcp_servers={
        "my_server": {
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-example"],
            "env": {"API_KEY": "your-key"}
        }
    },
    
    # Avanzate
    extra_args={"--verbose": None, "--custom-flag": "value"}
)

Dettagli dei parametri

  • system_prompt: str | None - Prompt di sistema personalizzato che definisce il ruolo dell’agente
  • append_system_prompt: str | None - Testo aggiuntivo aggiunto al prompt di sistema
  • max_turns: int | None - Numero massimo di turni di conversazione (illimitato se None)
  • model: str | None - Modello Claude specifico da utilizzare
  • max_thinking_tokens: int - Token massimi per il processo di ragionamento di Claude (predefinito: 8000)
  • allowed_tools: list[str] - Strumenti specificamente consentiti per l’uso
  • disallowed_tools: list[str] - Strumenti che non dovrebbero essere utilizzati
  • continue_conversation: bool - Continua la conversazione più recente (predefinito: False)
  • resume: str | None - UUID della sessione per riprendere una conversazione specifica
  • cwd: str | Path | None - Directory di lavoro per la sessione
  • add_dirs: list[str | Path] - Directory aggiuntive da includere nel contesto
  • settings: str | None - Percorso al file delle impostazioni o stringa JSON delle impostazioni
  • permission_mode: str | None - Modalità di gestione dei permessi
  • permission_prompt_tool_name: str | None - Nome personalizzato dello strumento di richiesta permessi
  • mcp_servers: dict | str | Path - Configurazioni del server MCP
  • extra_args: dict[str, str | None] - Passa flag CLI arbitrari alla CLI sottostante di Claude Code

Modalità di permesso

  • "default": CLI richiede conferma per strumenti pericolosi (comportamento predefinito)
  • "acceptEdits": Accetta automaticamente le modifiche ai file senza richiedere conferma
  • "plan": Modalità Piano - analizza senza apportare modifiche
  • "bypassPermissions": Consente tutti gli strumenti senza richiedere conferma (usa con cautela)

Esempio di configurazione avanzata

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def advanced_agent():
    """Esempio che mostra le opzioni di configurazione avanzate"""
    
    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            # Directory di lavoro personalizzata e contesto aggiuntivo
            cwd="/radice/progetto",
            add_dirs=["/librerie/condivise", "/utilità/comuni"],
            
            # Configurazione del modello e del ragionamento
            model="claude-3-5-sonnet-20241022",
            max_thinking_tokens=12000,
            
            # Controllo avanzato degli strumenti
            allowed_tools=["Read", "Write", "Bash", "Grep"],
            disallowed_tools=["WebSearch", "Bash(rm*)"],
            
            # Impostazioni personalizzate e argomenti CLI
            settings='{"editor": "vim", "theme": "dark"}',
            extra_args={
                "--verbose": None,
                "--timeout": "300"
            }
        )
    ) as client:
        await client.query("Analizza la struttura del codebase")
        
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

asyncio.run(advanced_agent())

Messaggi strutturati e input di immagini

L’SDK supporta il passaggio di messaggi strutturati e input di immagini:

from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async with ClaudeSDKClient() as client:
    # Messaggio di testo
    await client.query("Analizza questo codice per problemi di sicurezza")

    # Messaggio con riferimento all'immagine (l'immagine verrà letta dallo strumento Read di Claude)
    await client.query("Spiega cosa è mostrato in screenshot.png")

    # Messaggi multipli in sequenza
    messages = [
        "Prima, analizza il diagramma dell'architettura in diagram.png",
        "Ora suggerisci miglioramenti basati sul diagramma",
        "Infine, genera il codice di implementazione"
    ]

    for msg in messages:
        await client.query(msg)
        async for response in client.receive_response():
            # Elabora ogni risposta
            pass

# L'SDK gestisce i file di immagine attraverso lo strumento Read integrato di Claude
# Formati supportati: PNG, JPG, PDF e altri formati comuni

Conversazioni multi-turno

Metodo 1: Utilizzo di ClaudeSDKClient per conversazioni persistenti

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions, query

# Metodo 1: Utilizzo di ClaudeSDKClient per conversazioni persistenti
async def multi_turn_conversation():
    async with ClaudeSDKClient() as client:
        # Prima query
        await client.query("Rifacciamo il modulo di pagamento")
        async for msg in client.receive_response():
            # Elabora la prima risposta
            pass

        # Continua nella stessa sessione
        await client.query("Ora aggiungi una gestione completa degli errori")
        async for msg in client.receive_response():
            # Elabora la continuazione
            pass

        # Il contesto della conversazione viene mantenuto per tutto il tempo

# Metodo 2: Utilizzo della funzione query con gestione della sessione
async def resume_session():
    # Continua la conversazione più recente
    async for message in query(
        prompt="Ora rifai questo per prestazioni migliori",
        options=ClaudeCodeOptions(continue_conversation=True)
    ):
        if type(message).__name__ == "ResultMessage":
            print(message.result)

    # Riprendi una sessione specifica
    async for message in query(
        prompt="Aggiorna i test",
        options=ClaudeCodeOptions(
            resume="550e8400-e29b-41d4-a716-446655440000",
            max_turns=3
        )
    ):
        if type(message).__name__ == "ResultMessage":
            print(message.result)

# Esegui gli esempi
asyncio.run(multi_turn_conversation())

Prompt di sistema personalizzati

I prompt di sistema definiscono il ruolo, l’expertise e il comportamento del tuo agente:

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def specialized_agents():
    # Agente di risposta agli incidenti SRE con streaming
    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un esperto SRE. Diagnostica i problemi sistematicamente e fornisci soluzioni attuabili.",
            max_turns=3
        )
    ) as sre_agent:
        await sre_agent.query("L'API è down, investiga")

        # Trasmetti il processo diagnostico in streaming
        async for message in sre_agent.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

    # Agente di revisione legale con prompt personalizzato
    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            append_system_prompt="Includi sempre una gestione completa degli errori e test unitari.",
            max_turns=2
        )
    ) as dev_agent:
        await dev_agent.query("Rifai questa funzione")

        # Raccogli la risposta completa
        full_response = []
        async for message in dev_agent.receive_response():
            if type(message).__name__ == "ResultMessage":
                print(message.result)

asyncio.run(specialized_agents())

Strumenti personalizzati tramite MCP

Il Model Context Protocol (MCP) ti permette di dare ai tuoi agenti strumenti e capacità personalizzati:

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def mcp_enabled_agent():
    # Agente legale con accesso ai documenti e streaming
    # Nota: Configura i tuoi server MCP secondo necessità
    mcp_servers = {
        # Configurazione di esempio - decommenta e configura secondo necessità:
        # "docusign": {
        #     "command": "npx",
        #     "args": ["-y", "@modelcontextprotocol/server-docusign"],
        #     "env": {"API_KEY": "your-key"}
        # }
    }

    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            mcp_servers=mcp_servers,
            allowed_tools=["mcp__docusign", "mcp__compliance_db"],
            system_prompt="Sei un avvocato aziendale specializzato nella revisione di contratti.",
            max_turns=4
        )
    ) as client:
        await client.query("Rivedi questo contratto per i rischi di conformità")

        # Monitora l'uso degli strumenti e le risposte
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'type'):
                        if block.type == 'tool_use':
                            print(f"\n[Uso strumento: {block.name}]\n")
                        elif hasattr(block, 'text'):
                            print(block.text, end='', flush=True)
                    elif hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

            if type(message).__name__ == "ResultMessage":
                print(f"\n\nRevisione completata. Costo totale: ${message.total_cost_usd:.4f}")

asyncio.run(mcp_enabled_agent())

Strumento di richiesta permessi personalizzato

Implementa la gestione personalizzata dei permessi per le chiamate agli strumenti:

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def use_permission_prompt():
    """Esempio di utilizzo dello strumento di richiesta permessi personalizzato"""

    # Configurazione del server MCP
    mcp_servers = {
        # Configurazione di esempio - decommenta e configura secondo necessità:
        # "security": {
        #     "command": "npx",
        #     "args": ["-y", "@modelcontextprotocol/server-security"],
        #     "env": {"API_KEY": "your-key"}
        # }
    }

    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            permission_prompt_tool_name="mcp__security__approval_prompt",  # Cambiato da permission_prompt_tool
            mcp_servers=mcp_servers,
            allowed_tools=["Read", "Grep"],
            disallowed_tools=["Bash(rm*)", "Write"],
            system_prompt="Sei un auditor di sicurezza"
        )
    ) as client:
        await client.query("Analizza e risolvi i problemi di sicurezza")

        # Monitora l'uso degli strumenti e i permessi
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'type'):  # Aggiunto controllo per l'attributo 'type'
                        if block.type == 'tool_use':
                            print(f"[Strumento: {block.name}] ", end='')
                    if hasattr(block, 'text'):
                        print(block.text, end='', flush=True)

            # Controlla i rifiuti di permesso nei messaggi di errore
            if type(message).__name__ == "ErrorMessage":
                if hasattr(message, 'error') and "Permission denied" in str(message.error):
                    print(f"\n⚠️ Permesso negato: {message.error}")

# Esempio di implementazione del server MCP (Python)
# Questo sarebbe nel codice del tuo server MCP
async def approval_prompt(tool_name: str, input: dict, tool_use_id: str = None):
    """Gestore personalizzato della richiesta di permessi"""
    # La tua logica personalizzata qui
    if "allow" in str(input):
        return json.dumps({
            "behavior": "allow",
            "updatedInput": input
        })
    else:
        return json.dumps({
            "behavior": "deny",
            "message": f"Permesso negato per {tool_name}"
        })

asyncio.run(use_permission_prompt())

Formati di output

Output di testo con streaming

# Output di testo predefinito con streaming
async with ClaudeSDKClient() as client:
    await client.query("Spiega il file src/components/Header.tsx")

    # Trasmetti il testo mentre arriva
    async for message in client.receive_response():
        if hasattr(message, 'content'):
            for block in message.content:
                if hasattr(block, 'text'):
                    print(block.text, end='', flush=True)
                    # L'output viene trasmesso in tempo reale: Questo è un componente React che mostra...

Output JSON con metadati

# Raccogli tutti i messaggi con metadati
async with ClaudeSDKClient() as client:
    await client.query("Come funziona il livello dati?")

    messages = []
    result_data = None

    async for message in client.receive_messages():
        messages.append(message)

        # Cattura il messaggio di risultato con metadati
        if type(message).__name__ == "ResultMessage":
            result_data = {
                "result": message.result,
                "cost": message.total_cost_usd,
                "duration": message.duration_ms,
                "num_turns": message.num_turns,
                "session_id": message.session_id
            }
            break

    print(result_data)

Formati di input

import asyncio
from claude_code_sdk import ClaudeSDKClient

async def process_inputs():
    async with ClaudeSDKClient() as client:
        # Input di testo
        await client.query("Spiega questo codice")
        async for message in client.receive_response():
            # Elabora la risposta in streaming
            pass

        # Input di immagine (Claude userà automaticamente lo strumento Read)
        await client.query("Cosa c'è in questo diagramma? screenshot.png")
        async for message in client.receive_response():
            # Elabora l'analisi dell'immagine
            pass

        # Input multipli con contenuto misto
        inputs = [
            "Analizza l'architettura in diagram.png",
            "Confrontala con le migliori pratiche",
            "Genera una versione migliorata"
        ]

        for prompt in inputs:
            await client.query(prompt)
            async for message in client.receive_response():
                # Elabora ogni risposta
                pass

asyncio.run(process_inputs())

Esempi di integrazione di agenti

Agente di risposta agli incidenti SRE

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def investigate_incident(incident_description: str, severity: str = "medium"):
    """Agente automatizzato di risposta agli incidenti con streaming in tempo reale"""

    # Configurazione del server MCP per strumenti di monitoraggio
    mcp_servers = {
        # Configurazione di esempio - decommenta e configura secondo necessità:
        # "datadog": {
        #     "command": "npx",
        #     "args": ["-y", "@modelcontextprotocol/server-datadog"],
        #     "env": {"API_KEY": "your-datadog-key", "APP_KEY": "your-app-key"}
        # }
    }

    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un esperto SRE. Diagnostica i problemi sistematicamente e fornisci soluzioni attuabili.",
            max_turns=6,
            allowed_tools=["Bash", "Read", "WebSearch", "mcp__datadog"],
            mcp_servers=mcp_servers
        )
    ) as client:
        # Invia i dettagli dell'incidente
        prompt = f"Incidente: {incident_description} (Gravità: {severity})"
        print(f"🚨 Investigando: {prompt}\n")
        await client.query(prompt)

        # Trasmetti il processo di investigazione in streaming
        investigation_log = []
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'type'):
                        if block.type == 'tool_use':
                            print(f"[{block.name}] ", end='')
                    if hasattr(block, 'text'):
                        text = block.text
                        print(text, end='', flush=True)
                        investigation_log.append(text)

            # Cattura il risultato finale
            if type(message).__name__ == "ResultMessage":
                return {
                    'analysis': ''.join(investigation_log),
                    'cost': message.total_cost_usd,
                    'duration_ms': message.duration_ms
                }

# Utilizzo
result = await investigate_incident("API di pagamento che restituisce errori 500", "high")
print(f"\n\nInvestigazione completata. Costo: ${result['cost']:.4f}")

Revisione di sicurezza automatizzata

import subprocess
import asyncio
import json
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def audit_pr(pr_number: int):
    """Agente di audit di sicurezza per pull request con feedback in streaming"""
    # Ottieni il diff della PR
    pr_diff = subprocess.check_output(
        ["gh", "pr", "diff", str(pr_number)],
        text=True
    )

    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un ingegnere della sicurezza. Rivedi questa PR per vulnerabilità, pattern insicuri e problemi di conformità.",
            max_turns=3,
            allowed_tools=["Read", "Grep", "WebSearch"]
        )
    ) as client:
        print(f"🔍 Audit della PR #{pr_number}\n")
        await client.query(pr_diff)

        findings = []
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if hasattr(block, 'text'):
                        # Trasmetti i risultati mentre vengono scoperti
                        print(block.text, end='', flush=True)
                        findings.append(block.text)

            if type(message).__name__ == "ResultMessage":
                return {
                    'pr_number': pr_number,
                    'findings': ''.join(findings),
                    'metadata': {
                        'cost': message.total_cost_usd,
                        'duration': message.duration_ms,
                        'severity': 'high' if 'vulnerability' in ''.join(findings).lower() else 'medium'
                    }
                }

# Utilizzo
report = await audit_pr(123)
print(f"\n\nAudit completato. Gravità: {report['metadata']['severity']}")
print(json.dumps(report, indent=2))

Assistente legale multi-turno

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

async def legal_review():
    """Revisione di documenti legali con sessione persistente e streaming"""

    async with ClaudeSDKClient(
        options=ClaudeCodeOptions(
            system_prompt="Sei un avvocato aziendale. Fornisci analisi legali dettagliate.",
            max_turns=2
        )
    ) as client:
        # Revisione multi-step nella stessa sessione
        steps = [
            "Rivedi contract.pdf per le clausole di responsabilità",
            "Controlla la conformità ai requisiti GDPR",
            "Genera un riassunto esecutivo dei rischi"
        ]

        review_results = []

        for step in steps:
            print(f"\n📋 {step}\n")
            await client.query(step)

            step_result = []
            async for message in client.receive_response():
                if hasattr(message, 'content'):
                    for block in message.content:
                        if hasattr(block, 'text'):
                            text = block.text
                            print(text, end='', flush=True)
                            step_result.append(text)

                if type(message).__name__ == "ResultMessage":
                    review_results.append({
                        'step': step,
                        'analysis': ''.join(step_result),
                        'cost': message.total_cost_usd
                    })

        # Riassunto
        total_cost = sum(r['cost'] for r in review_results)
        print(f"\n\n✅ Revisione legale completata. Costo totale: ${total_cost:.4f}")
        return review_results

# Utilizzo
results = await legal_review()

Migliori pratiche specifiche per Python

Pattern chiave

import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions

# Usa sempre i context manager
async with ClaudeSDKClient() as client:
    await client.query("Analizza questo codice")
    async for msg in client.receive_response():
        # Elabora i messaggi in streaming
        pass

# Esegui più agenti contemporaneamente
async with ClaudeSDKClient() as reviewer, ClaudeSDKClient() as tester:
    await asyncio.gather(
        reviewer.query("Rivedi main.py"),
        tester.query("Scrivi test per main.py")
    )

# Gestione degli errori
from claude_code_sdk import CLINotFoundError, ProcessError

try:
    async with ClaudeSDKClient() as client:
        # Il tuo codice qui
        pass
except CLINotFoundError:
    print("Installa CLI: npm install -g @anthropic-ai/claude-code")
except ProcessError as e:
    print(f"Errore di processo: {e}")

# Raccogli la risposta completa con metadati
async def get_response(client, prompt):
    await client.query(prompt)
    text = []
    async for msg in client.receive_response():
        if hasattr(msg, 'content'):
            for block in msg.content:
                if hasattr(block, 'text'):
                    text.append(block.text)
        if type(msg).__name__ == "ResultMessage":
            return {'text': ''.join(text), 'cost': msg.total_cost_usd}

Suggerimenti per IPython/Jupyter

# In Jupyter, usa await direttamente nelle celle
client = ClaudeSDKClient()
await client.connect()
await client.query("Analizza data.csv")
async for msg in client.receive_response():
    print(msg)
await client.disconnect()

# Crea funzioni helper riutilizzabili
async def stream_print(client, prompt):
    await client.query(prompt)
    async for msg in client.receive_response():
        if hasattr(msg, 'content'):
            for block in msg.content:
                if hasattr(block, 'text'):
                    print(block.text, end='', flush=True)

Risorse correlate