Blog

Chiamate API per intelligenza artificiale: Agent Skills nell’API Claude senza Claude Code

Markdown

Come collegare una skill pptx già pronta all’API di Claude: container.skills, lo strumento di esecuzione del codice, la verifica della risposta e il download della presentazione tramite Files API.

Leggi l’articolo completo

Punto chiave

Le Agent Skills già pronte per i documenti possono essere usate tramite l’API diretta di Claude: specifica la skill in container.skills e abilita code_execution. Per la prima richiesta, usa l’abbinamento compatibile di modello e strumento riportato nell’esempio ufficiale. Scarica il file generato separatamente usando il suo file_id; l’esempio usa la stessa chiave API per la richiesta e il download.

Puoi trovare ulteriori istruzioni nella documentazione di Ailoot.

Come effettuare una chiamata all’API Claude per usare una skill?

Questa guida spiega come chiamare direttamente l’API da un programma, anziché installare una skill in Claude Code. Ti servono una chiave API di Claude, l’accesso al modello selezionato e Python 3. Il codice qui sotto usa la libreria standard di Python e HTTP, quindi non dipende dalla versione dell’SDK che hai installato. La chiave viene passata tramite la variabile d’ambiente ANTHROPIC_API_KEY; non inserirla nel testo del programma o in una conversazione.

L’API offre skill Anthropic già pronte: pptx per le presentazioni, xlsx per i fogli di calcolo, docx per i documenti Word e pdf per i PDF. Si collegano usando type: "anthropic". Questa guida usa una skill già pronta, senza caricarne una personalizzata.

La guida introduttiva ufficiale, consultata durante la preparazione di questo materiale, usa l’abbinamento claude-opus-5-5 e code_execution_20260521. È l’abbinamento usato qui sotto. Questo esempio è stato verificato rispetto alla documentazione; non è il resoconto di una chiamata API a pagamento.

Quali intestazioni beta servono

L’esempio segue il contratto HTTP attuale della guida introduttiva: le intestazioni sono x-api-key, anthropic-version: 2023-06-01 e content-type: application/json; non invia anthropic-beta. Non combinare un modello, un metodo di chiamata e un formato di risposta appartenenti a generazioni diverse della documentazione.

Anche la documentazione di Files API afferma che l’API è fuori dalla beta. La vecchia intestazione files-api-2025-04-14 mantiene i vecchi formati di risposta; rimuovendo l’intestazione si passa ai formati attuali. Per questo un vecchio esempio che usa client.beta.files non può essere semplicemente combinato con uno nuovo.

Qui non stiamo migrando un servizio esistente dal vecchio contratto beta. Se hai già un servizio del genere, controlla prima le intestazioni e i formati di risposta. La parola beta nel nome di un metodo dell’SDK, da sola, non basta: la documentazione di Files API spiega separatamente come si comportano le diverse versioni dell’SDK.

Crea una presentazione e scarica il file

L’esempio invia una richiesta per creare cinque diapositive sull’energia rinnovabile, salva l’intera risposta in skill-response.json ed estrae poi gli ID dei file generati. Non ricava un percorso di salvataggio dalla risposta del modello: i file vengono salvati in una nuova cartella locale chiamata skill-output. Se la cartella esiste già, il programma si ferma per non sovrascrivere il risultato precedente. La cartella viene creata prima della chiamata API e rimane quindi anche dopo una chiamata fallita. Esamina e conserva quel tentativo prima di riprovare; non eliminarla solo per far passare una nuova esecuzione.

import json
import os
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen

API = "https://api.anthropic.com/v1"
KEY = os.environ["ANTHROPIC_API_KEY"]
HEADERS = {
    "x-api-key": KEY,
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
}

def request(path, payload=None, binary=False):
    data = None if payload is None else json.dumps(payload).encode("utf-8")
    req = Request(API + path, data=data, headers=HEADERS)
    try:
        with urlopen(req, timeout=600) as result:
            body = result.read()
    except HTTPError as error:
        try:
            details = json.loads(error.read().decode("utf-8"))
        except (ValueError, UnicodeError):
            details = {}
        info = details.get("error", {})
        request_id = error.headers.get("request-id") or details.get("request_id")
        diagnostic = {
            "http_status": error.code,
            "request_id": request_id,
            "error_type": info.get("type"),
            "message": str(info.get("message", "No JSON error message")).replace(KEY, "[REDACTED]")[:1000],
        }
        (out / "skill-error.json").write_text(
            json.dumps(diagnostic, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        raise RuntimeError(
            f"Claude API HTTP {error.code}; request_id={request_id}; inspect skill-error.json"
        ) from None
    return body if binary else json.loads(body)

out = Path("skill-output")
out.mkdir(exist_ok=False)
response = request("/messages", {
    "model": "claude-opus-5-5",
    "max_tokens": 16000,
    "container": {
        "skills": [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]
    },
    "messages": [{
        "role": "user",
        "content": "Crea una presentazione sull’energia rinnovabile con 5 diapositive nella mia lingua preferita.",
    }],
    "tools": [{"type": "code_execution_20260521", "name": "code_execution"}],
})
(out / "skill-response.json").write_text(
    json.dumps(response, ensure_ascii=False, indent=2), encoding="utf-8"
)
print("stop_reason:", response.get("stop_reason"))

file_ids = []
for block in response["content"]:
    if block["type"] == "bash_code_execution_tool_result":
        result = block["content"]
        if result["type"] == "bash_code_execution_result":
            for item in result["content"]:
                file_id = item.get("file_id")
                if file_id and file_id not in file_ids:
                    file_ids.append(file_id)
if not file_ids:
    raise RuntimeError("No generated file_id; inspect skill-response.json")

for index, file_id in enumerate(file_ids, start=1):
    from urllib.parse import quote
    file_path = "/files/" + quote(file_id, safe="")
    metadata = request(file_path)
    if metadata.get("downloadable") is not True:
        raise RuntimeError("This file cannot be downloaded through Files API")
    target = out / f"result-{index}.pptx"
    target.write_bytes(request(file_path + "/content", binary=True))
    print("Saved:", target)

I nomi result-1.pptx e così via sono stati scelti per questa attività di presentazione. Un’estensione di file non dimostra che cosa contiene il file: apri il documento scaricato e controllane il formato, il numero di diapositive e il testo. Non considerare sufficiente una risposta HTTP 200 o la presenza di un file_id per concludere che il risultato sia riuscito.

Il programma stampa stop_reason, ovvero il motivo per cui la risposta si è interrotta, e salva la risposta completa per l’ispezione. Non prosegue la conversazione e non ripete automaticamente la richiesta a pagamento. Avere un file scaricato non significa che l’intera attività sia completa: controlla la risposta salvata e il documento stesso prima di decidere se serve un’altra richiesta.

Per un tentativo fallito, esamina skill-error.json se presente. Registra stato HTTP, ID della richiesta quando fornito e messaggio del fornitore con lunghezza limitata e chiave API configurata rimossa. Prima di condividerlo verifica che il messaggio non contenga altre informazioni private. Distingui errori di autenticazione, permessi/modello, fatturazione e formato tramite il riferimento ufficiale; non ogni errore richiede un’altra generazione a pagamento.

Se skill-response.json contiene già i file_id generati e solo un download è fallito, conserva la risposta e diagnostica metadati e download con lo stesso accesso autorizzato al workspace. Non eseguire di nuovo la generazione per scaricare un risultato esistente. Se l’esito della richiesta è sconosciuto, conserva il suo ID e chiariscine lo stato prima di inviare un’altra generazione. Solo quando una nuova generazione è giustificata, scegli una cartella inutilizzata, per esempio out = Path("skill-output-attempt-2"), mantenendo exist_ok=False. Una cartella nuova evita la sovrascrittura; non evita un addebito API duplicato.

Quali autorizzazioni servono per i file

Files API associa i file a un workspace, anziché a un singolo utente della tua applicazione o a una conversazione. Secondo la documentazione, qualsiasi chiave API con accesso a quel workspace può accedere ai file caricati. L’esempio usa la stessa chiave per il download e per la generazione. Non accettare mai un file_id da utenti finali o da altre fonti non attendibili. Memorizza questi ID sul server e gestisci nella tua applicazione la corrispondenza tra utenti e file.

Controlla separatamente i metadati del file: devono contenere downloadable: true. La documentazione consente di scaricare i file generati dalle skill o dallo strumento di esecuzione del codice; i file caricati da te hanno downloadable: false e un tentativo di download restituisce 400. L’accesso al workspace e la possibilità di scaricare un determinato file sono requisiti distinti.

Per un’applicazione multiutente, la documentazione di Files API raccomanda un workspace separato per ogni cliente come limite di isolamento dei file. Questa raccomandazione riguarda specificamente i file; non estenderla a tutte le entità e autorizzazioni senza aver consultato l’API pertinente.

Skill già pronte e skill personalizzate

Le skill già pronte hanno gli ID pptx, xlsx, docx e pdf. Nel riferimento all’elenco delle skill, l’origine custom è descritta come privata del workspace, mentre anthropic è condivisa e di sola lettura.

version: "latest" nel primo esempio indica la versione più recente pubblicata della skill. Per un’integrazione riproducibile, tieni presente che questa selezione può cambiare; per passare a una versione fissa devi scegliere una versione esistente della skill che usi, anziché inventare un ID prendendolo da un esempio.

Limiti e passaggio successivo

L’esempio riguarda solo la creazione di una presentazione con una skill già pronta e il relativo download. Il caricamento di skill personalizzate, la loro eliminazione e l’accesso a servizi di terze parti non sono stati testati qui. Queste attività richiedono una verifica separata dell’API pertinente.

Se la tua attività riguarda i file nell’interfaccia di Claude, c’è una guida separata su come caricare un file su Claude. Per le chiamate dirette, consulta come calcolare l’utilizzo dei token API. Per lavorare con un agente da terminale, leggi come scegliere le skill di Claude Code: si collegano in modo diverso.

Per il primo controllo basta una skill pptx già pronta: esamina la risposta, scarica un file che è consentito scaricare e aprilo. Aggiungi skill personalizzate e la separazione dell’accesso tra clienti dopo questo controllo.

Quando vuoi, scopri Ailoot.

Maggiori dettagli

Domande frequenti

Perché un file_id non basta per dichiarare pronta una presentazione?

L’ID indica che è stato restituito un file, non che la presentazione sia utilizzabile. Controlla nei metadati downloadable: true, scaricalo con l’accesso al workspace e aprilo per verificare formato, numero di slide e testo.

Posso scaricare qualsiasi file caricato nella Claude Files API?

No. La guida distingue i file generati con downloadable: true dai file caricati con downloadable: false. Accesso al workspace e permesso di scaricare un file specifico sono verifiche separate; non accettare ID di file arbitrari dagli utenti finali.

Tutti gli articoli