TL;DR
1import anthropic2client = anthropic.Anthropic() # Uses ANTHROPIC_API_KEY3message = client.messages.create(4 model="claude-sonnet-5",5 max_tokens=1024,6 messages=[{"role": "user", "content": "Hej Claude!"}]7)8print(message.content[0].text)Quick Reference
https://api.anthropic.comclaude-opus-5claude-sonnet-51M tokensx-api-keyHvad er Claude API?
Claude er Anthropics family af large language models. Sammenlignet med OpenAI GPT-4 har Claude nogle styrker:
- Længere kontekst - 1M tokens vs GPT-4's 128K
- Bedre tool use - Mere præcis function calling
- Konstituerende AI - Trænet til at være helpful, harmless, honest
- Konkurrencedygtig pris - Sonnet er billigere end GPT-4
Signup og API Key
For at bruge Claude API skal du:
- Opret konto på console.anthropic.com
- Tilføj betalingsmetode (pay-as-you-go)
- Generer API key under Settings → API Keys
- Gem key som environment variable:
ANTHROPIC_API_KEY
Installation
Installer den officielle SDK for dit foretrukne sprog:
pip install anthropicnpm install @anthropic-ai/sdkBasic Message
Den simpleste API call. Send en besked og få et svar:
1import anthropic2
3client = anthropic.Anthropic() # Uses ANTHROPIC_API_KEY env var4
5message = client.messages.create(6 model="claude-sonnet-5",7 max_tokens=1024,8 messages=[9 {"role": "user", "content": "Hvad er forskellen mellem REST og GraphQL?"}10 ]11)12
13print(message.content[0].text)14print(f"Input tokens: {message.usage.input_tokens}")15print(f"Output tokens: {message.usage.output_tokens}")System Prompts
System prompts definerer Claudes persona og adfærd. De er essentielle for konsistent output:
1message = client.messages.create(2 model="claude-sonnet-5",3 max_tokens=1024,4 system="""Du er en senior software arkitekt.5Svar altid med:61. En kort forklaring72. Kodeeksempel hvis relevant83. Potentielle pitfalls9
10Hold svarene koncise og tekniske. Brug dansk.""",11 messages=[12 {"role": "user", "content": "Hvordan implementerer jeg dependency injection i Python?"}13 ]14)Multi-turn Conversations
For at holde kontekst over flere beskeder, send hele samtalehistorikken:
1from typing import List, Dict2
3class Conversation:4 def __init__(self, system_prompt: str = None):5 self.messages: List[Dict] = []6 self.system = system_prompt7 self.client = anthropic.Anthropic()8
9 def chat(self, user_message: str) -> str:10 self.messages.append({"role": "user", "content": user_message})11
12 response = self.client.messages.create(13 model="claude-sonnet-5",14 max_tokens=2048,15 system=self.system,16 messages=self.messages17 )18
19 assistant_message = response.content[0].text20 self.messages.append({"role": "assistant", "content": assistant_message})21
22 return assistant_message23
24 def clear(self):25 self.messages = []26
27# Usage28conv = Conversation(system_prompt="Du er en Python ekspert.")29print(conv.chat("Forklar list comprehensions"))30print(conv.chat("Giv mig et komplekst eksempel")) # Husker kontekstenStreaming
For bedre UX, stream responsen token-by-token. Brugere ser teksten som den genereres, hvilket føles hurtigere:
1# Simple streaming2with client.messages.stream(3 model="claude-sonnet-5",4 max_tokens=1024,5 messages=[{"role": "user", "content": "Skriv en kort historie om en robot"}]6) as stream:7 for text in stream.text_stream:8 print(text, end="", flush=True)9
10# Streaming with events11with client.messages.stream(12 model="claude-sonnet-5",13 max_tokens=1024,14 messages=[{"role": "user", "content": "Forklar quantum computing"}]15) as stream:16 for event in stream:17 if event.type == "content_block_delta":18 print(event.delta.text, end="", flush=True)19 elif event.type == "message_stop":20 print("\n--- Done ---")21
22# Get final message after streaming23response = stream.get_final_message()24print(f"\nTotal tokens: {response.usage.input_tokens + response.usage.output_tokens}")Tool Use (Function Calling)
Lad Claude kalde funktioner i din kode. Kraftfuldt til agents og automation. Claude beslutter hvornår det giver mening at bruge et tool.
1import json2
3# Define tools4tools = [5 {6 "name": "get_weather",7 "description": "Hent vejret for en given by. Brug dette når brugeren spørger om vejret.",8 "input_schema": {9 "type": "object",10 "properties": {11 "city": {12 "type": "string",13 "description": "Byens navn, f.eks. 'Kobenhavn'"14 },15 "unit": {16 "type": "string",17 "enum": ["celsius", "fahrenheit"],18 "description": "Temperatur enhed"19 }20 },21 "required": ["city"]22 }23 },24 {25 "name": "search_database",26 "description": "Søg i produktdatabasen efter produkter",27 "input_schema": {28 "type": "object",29 "properties": {30 "query": {"type": "string", "description": "Søgeord"},31 "max_results": {"type": "integer", "description": "Max antal resultater"}32 },33 "required": ["query"]34 }35 }36]37
38# Your actual functions39def get_weather(city: str, unit: str = "celsius") -> dict:40 # In reality, call a weather API41 return {"city": city, "temp": 18, "unit": unit, "condition": "Overskyet"}42
43def search_database(query: str, max_results: int = 5) -> list:44 # In reality, query your database45 return [{"name": f"Produkt {i}", "price": 100 + i*10} for i in range(max_results)]46
47# Process tool calls48def process_tool_call(tool_name: str, tool_input: dict) -> str:49 if tool_name == "get_weather":50 result = get_weather(**tool_input)51 elif tool_name == "search_database":52 result = search_database(**tool_input)53 else:54 result = {"error": f"Unknown tool: {tool_name}"}55 return json.dumps(result)56
57# Make request with tools58response = client.messages.create(59 model="claude-sonnet-5",60 max_tokens=1024,61 tools=tools,62 messages=[{"role": "user", "content": "Hvordan er vejret i Aarhus?"}]63)64
65# Handle tool use66if response.stop_reason == "tool_use":67 # Find the tool use block68 tool_use = next(block for block in response.content if block.type == "tool_use")69
70 # Execute the tool71 tool_result = process_tool_call(tool_use.name, tool_use.input)72
73 # Send result back to Claude74 final_response = client.messages.create(75 model="claude-sonnet-5",76 max_tokens=1024,77 tools=tools,78 messages=[79 {"role": "user", "content": "Hvordan er vejret i Aarhus?"},80 {"role": "assistant", "content": response.content},81 {82 "role": "user",83 "content": [{84 "type": "tool_result",85 "tool_use_id": tool_use.id,86 "content": tool_result87 }]88 }89 ]90 )91 print(final_response.content[0].text)Vision (Image Input)
Claude kan analysere billeder. Send dem som base64 eller URL. Understotter JPEG, PNG, GIF og WebP.
1import base642import httpx3
4# From local file5def encode_image(image_path: str) -> str:6 with open(image_path, "rb") as f:7 return base64.standard_b64encode(f.read()).decode("utf-8")8
9# From URL10def fetch_image_base64(url: str) -> str:11 response = httpx.get(url)12 return base64.standard_b64encode(response.content).decode("utf-8")13
14# Analyze local image15message = client.messages.create(16 model="claude-sonnet-5",17 max_tokens=1024,18 messages=[19 {20 "role": "user",21 "content": [22 {23 "type": "image",24 "source": {25 "type": "base64",26 "media_type": "image/jpeg",27 "data": encode_image("diagram.jpg")28 }29 },30 {31 "type": "text",32 "text": "Forklar hvad dette arkitektur-diagram viser. List komponenterne."33 }34 ]35 }36 ]37)38
39# Multiple images40message = client.messages.create(41 model="claude-sonnet-5",42 max_tokens=1024,43 messages=[44 {45 "role": "user",46 "content": [47 {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img1_b64}},48 {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img2_b64}},49 {"type": "text", "text": "Sammenlign disse to designs. Hvad er forskellene?"}50 ]51 }52 ]53)Error Handling
Robust error handling er kritisk i production. Implementer retry logic med exponential backoff:
1from anthropic import (2 Anthropic,3 APIError,4 RateLimitError,5 APIConnectionError,6 AuthenticationError7)8import time9from functools import wraps10
11client = Anthropic()12
13def retry_with_backoff(max_retries: int = 3, base_delay: float = 1.0):14 def decorator(func):15 @wraps(func)16 def wrapper(*args, **kwargs):17 last_exception = None18 for attempt in range(max_retries):19 try:20 return func(*args, **kwargs)21 except RateLimitError as e:22 last_exception = e23 # Respect retry-after header if present24 delay = float(e.response.headers.get("retry-after", base_delay * (2 ** attempt)))25 print(f"Rate limited. Waiting {delay:.1f}s...")26 time.sleep(delay)27 except APIConnectionError as e:28 last_exception = e29 delay = base_delay * (2 ** attempt)30 print(f"Connection error. Retrying in {delay:.1f}s...")31 time.sleep(delay)32 except AuthenticationError:33 # Don't retry auth errors34 raise35 except APIError as e:36 if e.status_code >= 500:37 # Server error, worth retrying38 last_exception = e39 time.sleep(base_delay * (2 ** attempt))40 else:41 raise42 raise last_exception43 return wrapper44 return decorator45
46@retry_with_backoff(max_retries=3)47def call_claude(messages: list, **kwargs):48 return client.messages.create(49 model="claude-sonnet-5",50 messages=messages,51 **kwargs52 )Pricing og Cost Optimization
Claude priser per token. Her er strategier til at minimere costs:
Priser (september 2026)
| Model | Input/1M tokens | Output/1M tokens |
|---|---|---|
| claude-opus-5 | $5 | $25 |
| claude-sonnet-5 | $3 | $15 |
| claude-haiku-4-5 | $1 | $5 |
1# 1. Use the right model for the task2def get_model_for_task(task_complexity: str) -> str:3 """Choose model based on task complexity."""4 if task_complexity == "simple":5 return "claude-haiku-4-5" # Cheapest6 elif task_complexity == "moderate":7 return "claude-sonnet-5" # Best value8 else:9 return "claude-opus-5" # Most capable10
11# 2. Limit output tokens12response = client.messages.create(13 model="claude-sonnet-5",14 max_tokens=500, # Don't use more than needed15 messages=[...]16)17
18# 3. Use caching for repeated prompts19from functools import lru_cache20import hashlib21
22@lru_cache(maxsize=1000)23def cached_claude_call(prompt_hash: str, prompt: str) -> str:24 response = client.messages.create(25 model="claude-sonnet-5",26 max_tokens=1024,27 messages=[{"role": "user", "content": prompt}]28 )29 return response.content[0].text30
31def call_with_cache(prompt: str) -> str:32 prompt_hash = hashlib.md5(prompt.encode()).hexdigest()33 return cached_claude_call(prompt_hash, prompt)34
35# 4. Track costs36def estimate_cost(response) -> float:37 """Estimate cost in USD for a response."""38 # Sonnet 5 pricing39 input_cost = response.usage.input_tokens * 3 / 1_000_00040 output_cost = response.usage.output_tokens * 15 / 1_000_00041 return input_cost + output_costClaude vs GPT-4 Sammenligning
| Feature | Claude Sonnet 5 | GPT-4 Turbo |
|---|---|---|
| Max context | 1M tokens | 128K tokens |
| Input price | $3/1M | $10/1M |
| Tool use | Excellent | Good |
| Vision | Yes | Yes |
| Best for | Long docs, code, agents | General purpose |
Best Practices
- Brug environment variables - Aldrig hardcode API keys
- Implementer retry logic - Rate limits og netværksfejl sker
- Stream for UX - Brugere foretrækker at se tekst som den genereres
- Valider tool inputs - Trust but verify Claudes tool calls
- Log alt - Gem requests og responses til debugging
- Set max_tokens - Undga uventet lange (dyre) responses
- Monitor costs - Track token usage per endpoint
Næste skridt
Med disse fundamenter kan du bygge kraftfulde AI-applikationer. Vil du give Claude adgang til dine egne data, viser guiden til RAG-implementation hele pipelinen fra chunking til context injection. Skal svarene være mere præcise, er prompt engineering for udviklere næste skridt. Og vil du lade modellen handle selv frem for bare at svare, bygger AI-agent-guiden videre på tool use fra afsnittet ovenfor — MCP-guiden viser hvordan du deler de tools mellem flere klienter. Vil du lære AI-billedgenerering med DALL-E og Midjourney, tilbyder AI Revolution kurser i AI-billedgenerering.