Blogg

Agent Skills i Claude API: så använder du en färdig skill utan Claude Code

Markdown

Så ansluter du en färdig pptx-skill till Claude API: container.skills, kodexekveringsverktyget, kontroll av svaret och nedladdning av presentationen via Files API.

Läs hela artikeln

Det viktigaste

Färdiga Agent Skills för dokument kan användas via det direkta Claude API:et: ange skillen i container.skills och aktivera code_execution. För din första begäran använder du den modell- och verktygskombination som är kompatibel och förekommer i det officiella exemplet. Ladda ned den genererade filen separat med dess file_id; exemplet använder samma API-nyckel för begäran och nedladdningen.

Du hittar fler anvisningar i Ailoot-dokumentationen.

Det här behöver du

Den här guiden handlar om att anropa API:et direkt från ett program, inte om att installera en skill i Claude Code. Du behöver en Claude API-nyckel, åtkomst till den valda modellen och Python 3. Koden nedan använder Pythons standardbibliotek och HTTP, så den är inte beroende av vilken SDK-version du har installerat. Nyckeln skickas via miljövariabeln ANTHROPIC_API_KEY; skriv inte in den i programtexten eller en konversation.

API:et erbjuder färdiga Anthropic-skills: pptx för presentationer, xlsx för kalkylblad, docx för Word-dokument och pdf för PDF-filer. De ansluts med type: "anthropic". Den här guiden använder en färdig skill, utan att ladda upp en anpassad.

Den officiella snabbstartsguiden, som öppnades när materialet förbereddes, använder kombinationen claude-opus-5-5 och code_execution_20260521. Det är den kombination som används nedan. Exemplet har kontrollerats mot dokumentationen; det är inte en rapport om ett betalt API-anrop.

Vilka betarubriker behövs?

Exemplet följer snabbstartsguidens aktuella HTTP-kontrakt: rubrikerna är x-api-key, anthropic-version: 2023-06-01 och content-type: application/json; det skickar inte anthropic-beta. Kombinera inte en modell, en anropsmetod och ett svarsformat från olika generationer av dokumentationen.

Dokumentationen för Files API anger också att API:et inte längre är i beta. Den gamla rubriken files-api-2025-04-14 behåller de gamla svarsformaten; om du tar bort rubriken övergår du till de aktuella formaten. Därför kan ett gammalt exempel som använder client.beta.files inte bara kombineras med ett nytt.

Vi migrerar inte en befintlig tjänst från det gamla betakontraktet här. Om du redan har en sådan tjänst bör du först kontrollera dess rubriker och svarsformat. Ordet beta i ett SDK-metodnamn räcker inte i sig: dokumentationen för Files API förklarar separat hur olika SDK-versioner fungerar.

Skapa en presentation och ladda ned filen

Exemplet skickar en uppgift om att skapa fem bilder om förnybar energi, sparar hela svaret i skill-response.json och hämtar sedan ID:na för de genererade filerna. Det hämtar inte någon sökväg för att spara filen från modellens svar: filerna sparas i en ny lokal mapp med namnet skill-output. Om mappen redan finns avbryts programmet för att inte skriva över det tidigare resultatet. Mappen skapas före API-anropet och finns därför kvar även efter ett misslyckat anrop. Granska och bevara försöket innan du gör något mer; radera inte mappen bara för att få en ny körning att gå igenom.

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": "Create a presentation about renewable energy with 5 slides in my preferred language.",
    }],
    "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)

Namnen result-1.pptx och så vidare har valts för den här presentationsuppgiften. Ett filnamnstillägg bevisar inte vad filen innehåller: öppna det nedladdade dokumentet och kontrollera format, antal bilder och text. Behandla inte enbart HTTP 200 eller förekomsten av ett file_id som ett lyckat resultat.

Programmet skriver ut stop_reason, orsaken till att svaret avslutades, och sparar hela svaret för granskning. Det fortsätter inte konversationen och upprepar inte automatiskt den betalda begäran. Att ha en nedladdad fil innebär inte att hela uppgiften är klar: granska det sparade svaret och själva dokumentet innan du avgör om en ny begäran behövs.

Granska skill-error.json vid ett misslyckat försök, om filen finns. Den innehåller HTTP-status, eventuellt request-ID och ett begränsat felmeddelande från leverantören där den konfigurerade API-nyckeln har tagits bort. Kontrollera att meddelandet inte innehåller andra privata uppgifter innan du delar det. Jämför autentiseringsfel, behörighets-/modellfel, faktureringsgränser och formatfel med den officiella felreferensen; anta inte att alla fel kräver ännu en betald generering.

Om skill-response.json redan innehåller genererade file_id-värden och bara nedladdningen misslyckades ska du behålla svaret och undersöka filmetadata/nedladdning med samma godkända arbetsyteåtkomst. Kör inte genereringsblocket igen bara för att hämta ett befintligt resultat. Om utfallet är okänt, bevara request-ID:t och klarlägg status innan du skickar en ny generering. Först när du har avgjort att en ny generering behövs ändrar du den lokala utdataraden till en oanvänd sökväg, till exempel out = Path("skill-output-attempt-2"), och behåller exist_ok=False. En ny mapp förhindrar överskrivning; den förhindrar inte en dubbel API-kostnad.

Vilka filbehörigheter behövs?

Files API kopplar filer till en arbetsyta, inte till en enskild användare av din applikation eller en konversation. Enligt dokumentationen kan alla API-nycklar med åtkomst till den arbetsytan komma åt filer som laddats upp där. Exemplet använder samma nyckel för nedladdning som för generering. Acceptera aldrig ett file_id från slutanvändare eller andra otillförlitliga källor. Lagra dessa ID:n på servern och hantera kopplingen mellan användarna och deras filer i din egen applikation.

Kontrollera filens metadata separat: den måste innehålla downloadable: true. Dokumentationen tillåter nedladdning av filer som genererats av skills eller kodexekveringsverktyget; filer som du laddar upp har downloadable: false, och ett försök att ladda ned dem ger statuskod 400. Åtkomst till arbetsytan och möjligheten att ladda ned en viss fil är separata krav.

För applikationer med flera användare rekommenderar dokumentationen för Files API en separat arbetsyta för varje klient som gräns för filisolering. Rekommendationen gäller specifikt filer; utvidga den inte till alla entiteter och behörigheter utan att kontrollera relevant API-dokumentation.

Färdiga skills och anpassade skills

De färdiga skillsen har ID:na pptx, xlsx, docx och pdf. I referensen för skill-listan beskrivs källan custom som privat för arbetsytan, medan anthropic delas och är skrivskyddad.

version: "latest" i det första exemplet betyder den senaste publicerade versionen av skillen. För en reproducerbar integration bör du tänka på att valet kan ändras; om du vill byta till en fast version måste du välja en befintlig version av skillen du använder, i stället för att hitta på ett ID från ett exempel.

Begränsningar och nästa steg

Exemplet omfattar endast att skapa en presentation med en färdig skill och ladda ned den. Uppladdning av anpassade skills, borttagning av dem och åtkomst till tjänster från tredje part har inte testats här. Dessa uppgifter kräver en separat kontroll av relevant API.

Om din uppgift gäller filer i Claude-gränssnittet finns en separat guide om hur du laddar upp en fil till Claude. För direkta anrop kan du läsa så beräknar du API-tokenanvändning. För arbete i en terminalagent kan du läsa så väljer du Claude Code-skills: de ansluts på ett annat sätt.

För den första kontrollen räcker en färdig pptx-skill: granska svaret, ladda ned en fil som får laddas ned och öppna den. Lägg till anpassade skills och åtkomstseparering mellan klienter efter den kontrollen.

När du är redo kan du bekanta dig med Ailoot.

Fler detaljer

Frågor om den här guiden: Agent Skills i Claude API: så använder du en färdig skill utan Claude Code

Varför räcker inte ett file_id för att presentationen ska räknas som klar?

ID:t visar att en fil returnerades, inte att det är en användbar presentation. Kontrollera att dess metadata anger downloadable: true, hämta filen med arbetsyteåtkomst och öppna den för att verifiera filformat, antal bilder och text.

Kan jag hämta vilken fil som helst som laddats upp till Claude Files API?

Nej. Guiden skiljer mellan genererade filer märkta downloadable: true och uppladdade filer märkta downloadable: false. Arbetsyteåtkomst och rätt att hämta en viss fil är separata kontroller; acceptera inte godtyckliga fil-ID:n från slutanvändare.

Alla artiklar