LLMs can take 2-10 seconds to generate full responses. Streaming shows tokens as they're generated, improving perceived latency and user experience.
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from openai import OpenAI
app = FastAPI()
def generate_stream(prompt):
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
yield f"data: {chunk.choices[0].delta.content}\n\n"
yield "data: [DONE]\n\n"
@app.get("/stream")
async def stream(prompt: str):
return StreamingResponse(generate_stream(prompt), media_type="text/event-stream")
| Strategy | When to use | Example |
|---|---|---|
| Exact-match cache | Repeated identical queries | FAQ chatbot |
| Semantic cache | Similar but not identical queries | Customer support (same question, different wording) |
| Time-based cache | Data that changes slowly | Weekly report summaries |
import redis
import hashlib
redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
def cached_completion(prompt, model="gpt-4"):
# Create cache key
cache_key = hashlib.md5(f"{prompt}{model}".encode()).hexdigest()
# Check cache
cached = redis_client.get(cache_key)
if cached:
return cached
# Call API
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
answer = response.choices[0].message.content
# Store in cache (60 minutes TTL)
redis_client.setex(cache_key, 3600, answer)
return answer
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('all-MiniLM-L6-v2')
cache_store = [] # In production, use vector DB
def semantic_cached_completion(prompt, threshold=0.95):
prompt_embedding = model.encode(prompt)
# Check for similar prompts in cache
for cached_prompt, cached_response in cache_store:
similarity = util.cos_sim(prompt_embedding, cached_prompt)[0][0]
if similarity > threshold:
return cached_response
response = call_llm(prompt)
cache_store.append((prompt_embedding, response))
return response
| Model | Input cost/1M tokens | Output cost/1M tokens | When to use |
|---|---|---|---|
| GPT-4o | $5.00 | $15.00 | Complex reasoning, high accuracy |
| GPT-4 Turbo | $10.00 | $30.00.\] | |
| GPT-3.5 Turbo | $0.50 | $1.50 | Simple tasks, classification, prototyping |
| Claude 3 Haiku | $0.25 | $1.25 | Fast, cheap, good for basic tasks |
| Llama 3 (local) | ~$0.00 | ~$0.00 | Privacy, scale, fine-tuning |
def smart_router(question):
# First, try GPT-3.5
cheap_response = call_gpt35(question)
confidence = evaluate_confidence(cheap_response)
if confidence > 0.8:
return cheap_response, "gpt-3.5"
else:
# Upgrade to GPT-4
expensive_response = call_gpt4(question)
return expensive_response, "gpt-4"
import logging
import time
logging.basicConfig(level=logging.INFO)
def log_completion(prompt, response, model, tokens_used, latency_ms):
logging.info({
"event": "llm_completion",
"model": model,
"prompt_length": len(prompt),
"response_length": len(response),
"tokens": tokens_used,
"latency_ms": latency_ms,
"timestamp": time.time()
})
Treat prompts like code – version them, test changes, roll back when needed.
PROMPTS = {
"classify_v1": "Classify the sentiment as positive/negative/neutral: {text}",
"classify_v2": "You are a sentiment expert. Analyze this text and respond with exactly one word: POSITIVE, NEGATIVE, or NEUTRAL. Text: {text}",
"summarize_v1": "Summarize: {text}",
}
def get_prompt(name, version="latest"):
if version == "latest":
# Get the highest version number
versions = [v for v in PROMPTS if v.startswith(name)]
version = max(versions)
return PROMPTS[version]
Add Redis caching to an existing LLM function. Measure the latency difference on the second identical query.
Design a system that uses GPT-3.5 for simple questions and GPT-4 for complex ones. How would you classify complexity?
Estimate monthly costs: 100,000 queries, each averages 500 input tokens and 200 output tokens. Calculate cost for GPT-3.5 vs GPT-4.
You've finished Level 2 of the AI course. You can now:
Next: Level 3 – Professional (Architecture, Security, Fine-Tuning)