Skip to content

LLM APIs Proficient

🤖 AI Track · Level 4
⏱️ ~4 days 📚 Prerequisite: APIs & HTTP

When you'd use this

OpenAI, Anthropic, local models, structured output, streaming and production patterns.

Call LLM APIs (OpenAI, Anthropic) from Python — prompts, streaming, tools, structured output — to build AI features.

OpenAI API

Send prompts and get completions from OpenAI models — the baseline for LLM features.

from openai import OpenAI

client = OpenAI(api_key="sk-...")   # or set OPENAI_API_KEY env var

# ─── Basic completion ─────────────────────────────
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful Python tutor."},
        {"role": "user", "content": "Explain decorators in 3 sentences."},
    ],
    temperature=0.7,
    max_tokens=200,
)
print(response.choices[0].message.content)
# Output:
# A decorator is a function that takes another function and extends its
# behavior without modifying it. You apply it with the @ syntax above a
# function definition. It's commonly used for logging, timing, and access control.

print(f"Tokens used: {response.usage.total_tokens}")   # e.g. 87

Streaming responses

Receive tokens as they're generated for responsive, chat-like UX.

# Stream for real-time display (like ChatGPT)
stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Write a haiku about Python"}],
    stream=True,
)

full_response = ""
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
        full_response += delta
print()   # newline after streaming complete

Structured output (JSON mode)

Force the model to return valid JSON so you can parse it reliably.

from pydantic import BaseModel

class MovieReview(BaseModel):
    title: str
    rating: float
    sentiment: str
    summary: str
    keywords: list[str]

response = client.beta.chat.completions.parse(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "Extract structured movie review data."},
        {"role": "user", "content": "The new Dune movie was absolutely stunning. "
         "The visuals were breathtaking and Timothée Chalamet was perfect. 9/10."},
    ],
    response_format=MovieReview,
)

review = response.choices[0].message.parsed
print(review.title)       # Dune: Part Two
print(review.rating)      # 9.0
print(review.sentiment)   # positive
print(review.keywords)    # ['visuals', 'stunning', 'Chalamet']

Anthropic (Claude) API

Call Claude models with the Anthropic SDK — similar shape, different provider.

from anthropic import Anthropic

client = Anthropic(api_key="sk-ant-...")

message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system="You are an expert Python code reviewer.",
    messages=[
        {"role": "user", "content": "Review this code:\n```python\ndef f(x): return x*2\n```"}
    ],
)
print(message.content[0].text)
print(f"Input tokens: {message.usage.input_tokens}")
print(f"Output tokens: {message.usage.output_tokens}")

Tool calling / Function calling

Let the model request your functions so it can take actions and fetch data.

import json

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get current weather for a location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City name"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["location"],
            },
        },
    }
]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What's the weather in London?"}],
    tools=tools,
    tool_choice="auto",
)

# Model decides to call the tool
tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name)       # get_weather
print(tool_call.function.arguments)  # {"location": "London", "unit": "celsius"}

# Execute the function
args = json.loads(tool_call.function.arguments)
weather_result = get_weather(**args)   # your real function

# Send result back to model
messages = [
    {"role": "user", "content": "What's the weather in London?"},
    response.choices[0].message,
    {"role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(weather_result)},
]
final_response = client.chat.completions.create(model="gpt-4o", messages=messages)
print(final_response.choices[0].message.content)
# "The current weather in London is 15°C with partly cloudy skies."

Local models with Ollama

Run open models locally for privacy, cost, and offline use.

import httpx

# Ollama runs locally — no API key needed
response = httpx.post(
    "http://localhost:11434/api/generate",
    json={"model": "llama3", "prompt": "Explain Python decorators", "stream": False},
)
print(response.json()["response"])

# Or use the openai-compatible endpoint
from openai import OpenAI

local_client = OpenAI(base_url="http://localhost:11434/v1", api_key="unused")
response = local_client.chat.completions.create(
    model="llama3",
    messages=[{"role": "user", "content": "Hello!"}],
)

Production patterns

Retries, timeouts, cost control, and prompt management for reliable LLM apps.

Retry with exponential backoff

import time
from openai import OpenAI, RateLimitError, APIError

def call_with_retry(client, messages, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.chat.completions.create(
                model="gpt-4o", messages=messages
            )
        except RateLimitError:
            wait = 2 ** attempt
            print(f"  Rate limited. Waiting {wait}s...")
            time.sleep(wait)
        except APIError as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(1)
    raise RuntimeError("Max retries exceeded")

Token counting and cost estimation

import tiktoken

def count_tokens(text: str, model: str = "gpt-4o") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

def estimate_cost(input_tokens: int, output_tokens: int, model: str = "gpt-4o") -> float:
    # Prices as of 2024 (check current pricing)
    prices = {
        "gpt-4o": {"input": 0.005, "output": 0.015},      # per 1K tokens
        "gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
    }
    p = prices[model]
    return (input_tokens * p["input"] + output_tokens * p["output"]) / 1000

tokens = count_tokens("Hello, how are you?")
print(f"Tokens: {tokens}")   # ~6
cost = estimate_cost(1000, 500, "gpt-4o")
print(f"Estimated cost: ${cost:.4f}")   # $0.0125

Prompt templating

from string import Template

REVIEW_PROMPT = Template("""
You are a code reviewer. Review the following Python code and provide:
1. A score from 1-10
2. Issues found (list)
3. Suggestions for improvement

Code:
```python
$code

Respond in JSON format: {"score": int, "issues": [...], "suggestions": [...]} """)

def review_code(code: str) -> dict: prompt = REVIEW_PROMPT.substitute(code=code) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": prompt}], response_format={"type": "json_object"}, ) return json.loads(response.choices[0].message.content) ```


Practice Exercises

  1. Build a CLI chatbot that maintains conversation history and streams responses.
  2. Implement function calling — build an assistant that can query a database and search the web.
  3. Build a code review tool that uses structured output to return typed review objects.
  4. Implement token-aware chunking — split long documents to fit within context limits.
  5. Compare APIs — call OpenAI, Anthropic and a local model with the same prompt, compare quality and speed.
  6. Build a prompt library with templates for different tasks (summarization, extraction, code generation).

💬 Discussion

Have a question about this topic? Found an error? Share your thoughts below.