Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
18 minLesson 29 of 34
Python for AI

Using the Anthropic Claude API

Using the Anthropic Claude API

Claude's API has a different design philosophy than OpenAI's — especially around tool use, long-context handling, and prompt structure. This lesson covers Claude's unique capabilities and when to choose it.

Setup

# pip install anthropic python-dotenv
import anthropic
from dotenv import load_dotenv
import os

load_dotenv()

client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

Basic Message

# Claude's API uses messages.create, not chat.completions
response = client.messages.create(
    model="claude-opus-4-7",          # Most capable
    # model="claude-sonnet-4-6",    # Fast and capable — great default
    # model="claude-haiku-4-5-20251001",  # Fastest and cheapest
    max_tokens=1024,
    system="You are a Python expert who gives concise, practical answers.",
    messages=[
        {"role": "user", "content": "What are Python generators and when should I use them?"}
    ]
)

print(response.content[0].text)
print(f"\nModel: {response.model}")
print(f"Input tokens: {response.usage.input_tokens}")
print(f"Output tokens: {response.usage.output_tokens}")

Key Differences from OpenAI

# System prompt is a top-level parameter, not a message role
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=500,
    system="You are a helpful assistant.",  # System is here, not in messages
    messages=[
        {"role": "user", "content": "Hello!"},
        {"role": "assistant", "content": "Hi! How can I help you today?"},
        {"role": "user", "content": "What's the capital of France?"}
    ]
)

# Response content is a list of content blocks
for block in response.content:
    if block.type == "text":
        print(block.text)

Tool Use with Claude

Claude's tool use syntax is slightly different but follows the same concept:

import json

tools = [
    {
        "name": "search_database",
        "description": "Search a product database for items matching a query",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "Search terms"
                },
                "max_results": {
                    "type": "integer",
                    "description": "Maximum number of results to return",
                    "default": 5
                }
            },
            "required": ["query"]
        }
    }
]

def search_database(query: str, max_results: int = 5) -> list:
    """Mock database search."""
    mock_products = [
        {"id": 1, "name": "Python Programming Book", "price": 39.99},
        {"id": 2, "name": "Python for Data Science", "price": 44.99},
        {"id": 3, "name": "Learn Python Fast", "price": 29.99}
    ]
    return [p for p in mock_products if query.lower() in p['name'].lower()][:max_results]

def run_claude_agent(user_message: str) -> str:
    messages = [{"role": "user", "content": user_message}]
    
    while True:
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            tools=tools,
            messages=messages
        )
        
        messages.append({"role": "assistant", "content": response.content})
        
        if response.stop_reason == "end_turn":
            for block in response.content:
                if hasattr(block, 'text'):
                    return block.text
        
        # Process tool use blocks
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                if block.name == "search_database":
                    result = search_database(**block.input)
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": json.dumps(result)
                    })
        
        if tool_results:
            messages.append({"role": "user", "content": tool_results})

answer = run_claude_agent("Find me some Python books under $40")
print(answer)

Long Context: Claude's Superpower

Claude models support up to 200K tokens (about 150K words) — larger than most books. This enables unique use cases:

def analyze_long_document(document_text: str, question: str) -> str:
    """Analyze a very long document — contracts, codebases, research papers."""
    response = client.messages.create(
        model="claude-opus-4-7",  # Use Opus for best long-context performance
        max_tokens=2048,
        system="""You are an expert analyst. Read the entire document carefully 
        and answer questions with specific citations from the text.""",
        messages=[
            {
                "role": "user",
                "content": f"Document:\n\n{document_text}\n\n---\n\nQuestion: {question}"
            }
        ]
    )
    return response.content[0].text

# Examples of long-context tasks:
# - Analyze an entire codebase
# - Review a legal contract for specific clauses
# - Summarize a 400-page research report
# - Extract all data from a large CSV pasted as text

Streaming with Claude

def stream_claude(prompt: str, system: str = ""):
    """Stream Claude's response token by token."""
    kwargs = {
        "model": "claude-sonnet-4-6",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": prompt}]
    }
    if system:
        kwargs["system"] = system
    
    with client.messages.stream(**kwargs) as stream:
        full_text = ""
        for text in stream.text_stream:
            print(text, end='', flush=True)
            full_text += text
        print()
    
    return full_text

stream_claude("Explain recursion with a simple Python example", 
              system="Be brief and practical.")

Vision: Analyzing Images

import base64
from pathlib import Path

def analyze_image(image_path: str, question: str) -> str:
    """Ask Claude to analyze an image."""
    image_data = base64.standard_b64encode(
        Path(image_path).read_bytes()
    ).decode("utf-8")
    
    suffix = Path(image_path).suffix.lower()
    media_types = {'.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', 
                   '.png': 'image/png', '.gif': 'image/gif', '.webp': 'image/webp'}
    media_type = media_types.get(suffix, 'image/jpeg')
    
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": media_type,
                            "data": image_data
                        }
                    },
                    {
                        "type": "text",
                        "text": question
                    }
                ]
            }
        ]
    )
    return response.content[0].text

# Usage
description = analyze_image("chart.png", "What trend does this chart show?")
code_review = analyze_image("screenshot.png", "What's wrong with this code?")

When to Choose Claude vs GPT-4

TaskRecommendation
Long document analysis (50K+ words)Claude — 200K context
Code generation and debuggingBoth are excellent
Complex reasoning, nuanced analysisClaude — consistently thoughtful
Vision and image understandingBoth are excellent
Function calling / tool useBoth support it
Fastest/cheapest optionClaude Haiku vs GPT-4o-mini
Existing OpenAI integrationStick with GPT

Next lesson: Build an AI Chatbot in Python — combining everything into a real application.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!