Duration: 4 hours | Difficulty: Intermediate | Prerequisites: Modules 01–02
Learning Objectives
By the end of this module, you will be able to:
- Integrate OpenAI, Anthropic Claude, and Google Gemini APIs into Python applications
- Implement streaming responses for real-time user experiences
- Use function calling / tool use to extend LLM capabilities
- Handle errors, rate limits, and retries gracefully
- Estimate and optimize API costs across providers
1. The LLM API Landscape
Why Multiple Providers?
Nobody wins every benchmark forever. In production you might pick by latency, price, context, compliance, or modalities (vision, audio).
| Provider | Often strongest for | Cost vibe |
|---|---|---|
| OpenAI (GPT family) | Tooling, dev experience, coding | Mid (varies by model) |
| Anthropic (Claude) | Long docs, nuanced writing | Mid |
| Google (Gemini) | Multimodal + Google stack | Low–mid on some SKUs |
| Open-weight / self-host | Privacy, control | Infra + people time |
Try This! Make a one-page “model card” for your app: allowed models, max tokens, PII rules, fallback provider.
2. OpenAI API Deep Dive
Basic Chat Completion
Most tutorials start here: messages is an ordered transcript; temperature and max_tokens shape behavior.
| Field | Role |
|---|---|
model | Which weights + tokenizer policy |
messages | System / user / assistant (+ tool) turns |
stream=True | SSE-style token stream for UX |
tools | JSON schemas the model may call |
Key Example: Non-streaming chat with usage fields you’ll log for cost dashboards.
[object Object], openai ,[object Object], OpenAI
client = OpenAI(api_key=,[object Object],)
response = client.chat.completions.create(
model=,[object Object],,
messages=[
{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],},
{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],},
],
temperature=,[object Object],,
max_tokens=,[object Object],,
top_p=,[object Object],,
)
,[object Object],(response.choices[,[object Object],].message.content)
,[object Object],(,[object Object],, response.usage.total_tokens)
,[object Object],(,[object Object],, response.choices[,[object Object],].finish_reason)Streaming (Conceptual)
With stream=True, you iterate chunks and print partial text—chat UIs feel alive. You still concatenate chunks server-side if you need the final string for storage.
| Streaming win | Streaming watch-out |
|---|---|
| Perceived speed | You must handle partial JSON carefully |
| Early cancel | More client logic |
3. Anthropic Claude API
Claude’s Python SDK uses messages.create with system as a top-level string (not always a message with role system in the older style).
| Piece | Notes |
|---|---|
max_tokens | Required cap on assistant output |
messages | Alternating user/assistant content blocks |
| Streaming | Iterator over events; same mental model as OpenAI |
Fun Fact: Providers disagree on tiny details (content blocks vs plain strings)—wrappers like LiteLLM exist because of that friction.
4. Google Gemini API
Gemini often starts with GenerativeModel(model_name) then generate_content or a start_chat session object for multi-turn state.
| Mode | When |
|---|---|
Single-shot generate_content | One question, one answer |
| Chat session | Conversation with history managed for you |
| Multimodal | Pass image/audio parts alongside text (check current API) |
5. Universal LLM Client
Why teams build a thin wrapper
| Benefit | What you hide |
|---|---|
| Swap models in config | Auth, retries, logging |
| Uniform return type | Token counts + text + raw |
| Cost estimation | Multiply usage × price table |
You don’t need abstraction on day one—add it when you have two providers or two environments.
6. Error Handling and Retry Logic
Typical production errors:
| Error | First move |
|---|---|
| 429 rate limit | Exponential backoff + jitter |
| 5xx / timeout | Retry with cap |
| 400 bad request | Log body; fix prompt/schema |
| Broken tool JSON | Repair loop or re-ask model |
Key Example: Exponential backoff on rate limits—pattern is the same across SDKs; swap the client call for Anthropic/Gemini.
[object Object], time
,[object Object], openai ,[object Object], OpenAI, RateLimitError, APIConnectionError, APITimeoutError
client = OpenAI(api_key=,[object Object],)
,[object Object], ,[object Object],(,[object Object],):
,[object Object], attempt ,[object Object], ,[object Object],(max_retries):
,[object Object],:
,[object Object], client.chat.completions.create(
model=model,
messages=messages,
timeout=,[object Object],,
)
,[object Object], (RateLimitError, APIConnectionError, APITimeoutError):
,[object Object], attempt == max_retries - ,[object Object],:
,[object Object],
time.sleep(base_delay * (,[object Object],**attempt))
resp = chat_with_retry(
[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
)
,[object Object],(resp.choices[,[object Object],].message.content)7. Cost Optimization Strategies
| Lever | Idea |
|---|---|
| Model routing | Cheap model for triage; expensive for hard cases |
| Prompt compression | Drop decorative prose in system prompts |
| Cache | Hash(prompt+model) for idempotent answers (careful with PII) |
| Batch where supported | Fewer HTTP envelopes |
| Anti-pattern | Why it hurts |
|---|---|
| Giant pasted context “just in case” | Linear $ and latency |
| Max tokens sky-high always | Pay for completion headroom you don’t use |
Key Takeaway
Treat tokens like cloud spend: log per route, alert on spikes, cap per user.
Practice Exercises
| Level | Task |
|---|---|
| Beginner | Same 3 prompts to 2 providers; compare latency + vibe |
| Intermediate | Terminal chat with streaming + /model switch |
| Intermediate | One tool (get_time) wired through function calling |
| Advanced | Async parallel calls; pick fastest answer above quality bar |
Mini-Project: LLM API Gateway
FastAPI service: /chat accepts {model, messages} → routes to provider, caches deterministic prompts, /stats returns spend estimates. Start with OpenAI only; add a second provider behind the same response schema.
Key Takeaways
Key Takeaway
- Chat APIs are mostly the same story: messages + sampling knobs + usage metadata.
- Streaming and tools are product features, not academic extras.
- Retries belong in your client layer, not copy-pasted per call site.
- Abstract only after pain is real (2+ providers or environments).
- Observability (tokens, latency, errors) is how you keep bills honest.