When you need more than a single prompt
A single AI call handles simple tasks. But real-world problems need chains — sequences of AI calls where each step's output feeds the next step's input. This guide shows you how to build chains in pure Python, no frameworks needed.
Pattern: Classify → Process → Validate
from openai import OpenAI
import json
client = OpenAI(
api_key="izzi-YOUR_KEY_HERE",
base_url="https://api.izziapi.com/v1"
)
def classify(text: str) -> str:
"""Step 1: Classify the input type."""
response = client.chat.completions.create(
model="qwen3-30b-a3b", # Free model for classification
messages=[{
"role": "user",
"content": f"Classify this text as one of: bug_report, feature_request, question, feedback.\n\n{text}"
}],
max_tokens=20
)
return response.choices[0].message.content.strip().lower()
def process(text: str, category: str) -> str:
"""Step 2: Process based on classification."""
prompts = {
"bug_report": "Extract: severity, steps to reproduce, expected vs actual behavior.",
"feature_request": "Extract: use case, proposed solution, priority.",
"question": "Provide a clear, technical answer.",
"feedback": "Summarize key points and suggested actions.",
}
response = client.chat.completions.create(
model="claude-sonnet-4-20250514", # Paid model for quality
messages=[{
"role": "user",
"content": f"{prompts.get(category, prompts['question'])}\n\n{text}"
}],
max_tokens=1000
)
return response.choices[0].message.content
def validate(result: str) -> dict:
"""Step 3: Validate and structure the output."""
response = client.chat.completions.create(
model="qwen3-30b-a3b", # Free model for validation
messages=[{
"role": "user",
"content": f"Rate this response quality 1-10 and return JSON: {{"score": N, "issues": []}}\n\n{result}"
}],
max_tokens=200
)
return json.loads(response.choices[0].message.content)
# Run the chain
def process_ticket(text: str) -> dict:
category = classify(text) # Free: ~0 cost
result = process(text, category) # Paid: main cost
quality = validate(result) # Free: ~0 cost
return {
"category": category,
"response": result,
"quality_score": quality["score"]
}Cost optimization: mix free and paid models
In the chain above, only Step 2 uses a paid model. Steps 1 and 3 use free models.
| Step | Model | Cost | Purpose |
|---|---|---|---|
| Classify | Qwen3 30B (free) | $0 | Simple classification |
| Process | Claude Sonnet 4 | ~$0.012 | Complex reasoning |
| Validate | Qwen3 30B (free) | $0 | Quality check |
| Total | $0.012/chain |
Parallel chains for speed
import asyncio
from openai import AsyncOpenAI
async_client = AsyncOpenAI(
api_key="izzi-YOUR_KEY_HERE",
base_url="https://api.izziapi.com/v1"
)
async def parallel_chain(texts: list[str]) -> list[dict]:
"""Process multiple items concurrently."""
tasks = [process_ticket(text) for text in texts]
return await asyncio.gather(*tasks)