Messages (Anthropic)

Senast uppdaterad:

På denna sida
text
POST https://api.staik.se/v1/messages

Anthropic Messages API-kompatibel endpoint — Claude Code, Anthropic SDK och andra verktyg som pratar Anthropic-protokollet fungerar direkt. Autentisera med x-api-key eller Authorization: Bearer (samma nyckel).

python
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.staik.se",
    api_key="sk-st-your-key",
)

message = client.messages.create(
    model="qwen3.6:35b-a3b",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Förklara hur en transformer fungerar."}],
)
print(message.content[0].text)

Modellmappning

Skicka antingen staik-modellnamn eller Claude-modellnamn — Claude-namn mappas automatiskt (främst för sömlös Claude Code-integration):

Skickat modellnamnMappas till
claude-sonnet-4-6qwen3.6:35b-a3b
claude-opus-4-6qwen3.6:35b-a3b
claude-haiku-4-5-20251001qwen3.5:9b

Prompt caching

cache_control-breakpoints stöds (max 4 per request, som hos Anthropic). Markerad kontext cachas och återanvänds — den cachade delen billas som rabatterad cache_read i stället för fullpris varje tur. TTL är 5 minuter, eller 1 timme med ttl: "1h". Cache-träffarna syns i svarets usage-fält.

json
{
  "system": [
    {
      "type": "text",
      "text": "...stor systemprompt eller kontext...",
      "cache_control": {"type": "ephemeral"}
    }
  ]
}

Funktioner som stöds

  • Streaming i Anthropic-format. Händelserna är message_start, content_block_start, content_block_delta, content_block_stop, message_delta och message_stop.
  • Tool calling: tools, tool_use och tool_result översätts automatiskt.
  • System prompt som sträng eller content blocks.
  • Kvoter och köer är desamma som för OpenAI-endpointen.

Verktygsval (tool_choice)

tool_choice stöds med alla fyra typerna. disable_parallel_tool_use: true ger högst ett verktygsanrop per svar.

tool_choiceBetydelse
{"type": "auto"}Modellen väljer själv (standard)
{"type": "any"}Modellen måste anropa något av verktygen
{"type": "tool", "name": "extract_invoice"}Modellen måste anropa just det verktyget
{"type": "none"}Modellen får inte anropa verktyg

Ett tvingat verktyg är det säkra sättet att få strukturerad data ur en modell:

python
message = client.messages.create(
    model="qwen3.6:35b-a3b",
    max_tokens=1024,
    tools=[{
        "name": "extract_invoice",
        "description": "Fält från en faktura",
        "input_schema": {
            "type": "object",
            "properties": {"total": {"type": "number"}, "due_date": {"type": "string"}},
            "required": ["total"],
        },
    }],
    tool_choice={"type": "tool", "name": "extract_invoice"},
    messages=[{"role": "user", "content": "Fakturan: totalt 1 234,50 kr, förfaller 30/11."}],
)
print(message.content[0].input)  # {"total": 1234.5, "due_date": "..."}

tool_choice utan tools ignoreras. Ett name som inte finns bland tools ger 400. Modellerna på staiks GPU:er följer valet. Egna GPU-noder med Ollama följer ett tvingat verktyg (tool och any) men inte auto med strict.

Argumenten följer input_schema

När modellen tvingas anropa ett verktyg ({"type": "tool"}, eller {"type": "any"}) begränsas genereringen till verktygets input_schema, både med och utan streaming. Det är samma mekanism som response_format med json_schema (strict) i chat completions. Svaret är ett tool_use-block med stop_reason: "tool_use". Med any och flera verktyg väljer modellen ett av dem, och argumenten följer just det verktygets schema.

"strict": true på ett verktyg begränsar argumenten även när modellen själv väljer att anropa det (auto). Det fungerar på qwen3.6:35b-a3b och qwen3.5:9b, men inte på gemma4:31b.

För verktyg med schema rekommenderar vi qwen3.6:35b-a3b. gemma4:31b rekommenderas inte: den kan fastna i blanktecken tills max_tokens även när argumenten begränsas, och den begränsar inte strict med auto.

python
tools=[{"name": "extract_invoice", "strict": True, "input_schema": {...}}]

Svarshuvudet x-staik-tool-schema-enforced finns när anropet har ett tvingat verktyg eller ett strict-verktyg:

VärdeBetydelse
trueArgumenten är begränsade till hela schemat
falseInte hela schemat kunde begränsas: schemat har nyckelord som inte stöds, eller modellen kan inte begränsa strict med auto. Validera argumenten själv

Ett svar som kapas av max_tokens (stop_reason: "max_tokens") kan ha ofullständiga argument även när huvudet är true.

JSON Schema-nyckelord som begränsas: type (även listor som ["string", "null"]), properties, required, additionalProperties, items, prefixItems, enum, const, anyOf, oneOf, $ref (lokala, #/$defs/...), $defs, definitions, minLength, maxLength, pattern, format (date, date-time, time, duration, email, hostname, ipv4, ipv6, uri, uri-reference, uri-template, uuid, json-pointer, relative-json-pointer), minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems och patternProperties. Beskrivande fält som title, description, default och examples påverkar inte.

Stöds inte: allOf, not, if/then/else, dependentRequired, dependentSchemas, unevaluatedProperties, unevaluatedItems, propertyNames, uniqueItems, contains, minContains, maxContains, minProperties, maxProperties, externa $ref och andra format. De tas bort ur begränsningen, resten av schemat begränsas och huvudet blir false.

Fält som kan saknas

Ett obligatoriskt fält av typen string måste alltid fyllas i. Saknas uppgiften i underlaget skriver modellen något, till exempel en tom sträng. Ge fältet typen ["string", "null"] om det får saknas, så kan modellen svara null.

PDF och dokument

document-block stöds. En PDF skickas som base64, och staik läser den som Claude gör: för varje sida får modellen sidans textlager och en bild av sidan, i sidordning och med rubriken "Sida 3 av 7". Blockets title och context följer med.

python
import base64

pdf = base64.standard_b64encode(open("faktura.pdf", "rb").read()).decode()

message = client.messages.create(
    model="qwen3.6:35b-a3b",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "document",
                "title": "faktura.pdf",
                "source": {"type": "base64", "media_type": "application/pdf", "data": pdf},
            },
            {"type": "text", "text": "Vilket är totalbeloppet?"},
        ],
    }],
)
source.typeHur det läses
base64 (application/pdf)Textlager och sidbild per sida
textTexten som den är
contentBlocken i content (text och base64-bilder)
url, file400. staik hämtar inga URL:er eller filer, skicka base64

Dokument fungerar i user-meddelanden, i tool_result och i system.

Gränser:

  • högst 20 sidor per PDF och 40 sidor per anrop
  • hela anropet får vara högst 20 MB, så en PDF kan vara ungefär 15 MB (base64 gör den en tredjedel större)
  • PDF:er med lösenord och trasiga filer ger 400

Över gränsen svarar API:t med 400 i stället för att korta dokumentet.

Kostnad: varje sidbild räknas som en bild i usage.input_tokens, plus textlagret. En A4-sida blir ungefär 2 100 bildtokens på Qwen-modellerna och ungefär 420 på gemma4:31b.

Skannade PDF:er har inget textlager och kan bara läsas som bild, så de kräver en modell med vision. En modell utan vision får bara textlagret, och en sida utan text ger då 400.

Fel

Fel kommer i Anthropics format, så Anthropic-SDK:n visar meddelandet direkt:

json
{
  "type": "error",
  "error": {"type": "invalid_request_error", "message": "PDF:en har 25 sidor; max är 20 per dokument. ..."}
}

Begränsningar

  • Extended thinking: thinking-parametern ignoreras och svaret kommer utan resonemang. -thinking-alias räknas som okänd modell och besvaras av standardmodellen. Thinking finns via chat completions.
  • Bilder skickas som base64-bildblock (samma modeller och regler som chat completions). Bilder via URL ger 400.

Claude Code

Två miljövariabler räcker: ANTHROPIC_BASE_URL=https://api.staik.se och ANTHROPIC_API_KEY=sk-st-.... Full guide under Claude Code.