OpenAI API Complete Guide 2026 — GPT-4o, Vision, Function Calling
Advertisement
Introduction
Why This Matters
The OpenAI API powers more production AI applications than any other provider. Understanding its full feature set — not just basic chat completions — is the difference between a demo app and a production system that handles real user needs, integrates with your data, and operates within cost constraints.
Function calling alone unlocks the entire class of AI agent applications. Structured outputs eliminate a category of post-processing bugs. Embeddings enable semantic search across your entire dataset. Each feature serves a distinct architectural need, and most production apps use at least three of them together.
This guide covers every major API feature with production-ready examples you can use today.
Setup
pip install openaifrom openai import OpenAI
client = OpenAI(api_key="sk-...") # or set OPENAI_API_KEY env varChat Completions
# Basic completion
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a helpful coding assistant."},
{"role": "user", "content": "Explain async/await in Python"},
],
max_tokens=500,
temperature=0.7,
)
print(response.choices[0].message.content)
print(f"Tokens used: {response.usage.total_tokens}")
# Streaming — lower perceived latency for users
with client.chat.completions.stream(
model="gpt-4o",
messages=[{"role": "user", "content": "Write a quicksort in Go"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Vision: Analyze Images
import base64
with open("screenshot.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe any bugs or issues you see in this UI screenshot"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_data}"}},
],
}],
)
print(response.choices[0].message.content)Function Calling (Tool Use)
Function calling lets the LLM decide when and which of your functions to call based on the user request.
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"],
},
},
},
]
def get_weather(location: str, unit: str = "celsius") -> dict:
return {"temperature": 28, "condition": "sunny", "location": location}
messages = [{"role": "user", "content": "What is the weather in Mumbai?"}]
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto",
)
message = response.choices[0].message
messages.append(message)
if response.choices[0].finish_reason == "tool_calls":
for tool_call in message.tool_calls:
fn_args = json.loads(tool_call.function.arguments)
result = get_weather(**fn_args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result),
})
else:
print(message.content)
breakEmbeddings
# Single embedding
response = client.embeddings.create(
model="text-embedding-3-large",
input="The quick brown fox jumps over the lazy dog",
)
vector = response.data[0].embedding # 3072-dimensional list of floats
# Semantic search with cosine similarity
import numpy as np
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
texts = ["Python tutorial", "JavaScript guide", "chocolate cake recipe"]
vectors = [client.embeddings.create(model="text-embedding-3-large", input=t).data[0].embedding for t in texts]
query_vec = client.embeddings.create(model="text-embedding-3-large", input="learn coding").data[0].embedding
scores = [(cosine_similarity(query_vec, v), t) for v, t in zip(vectors, texts)]
scores.sort(reverse=True)
print("Most similar:", scores[0][1]) # "Python tutorial"Structured Outputs with Pydantic
from pydantic import BaseModel
from typing import Optional
class CodeReview(BaseModel):
overall_quality: str # "good" | "needs_work" | "critical"
bugs_found: int
suggestions: list[str]
refactored_code: Optional[str] = None
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{
"role": "user",
"content": "Review this Python code:\n\ndef add(a, b):\n return a + b"
}],
response_format=CodeReview,
)
review = response.choices[0].message.parsed
print(f"Quality: {review.overall_quality}, Bugs: {review.bugs_found}")
for s in review.suggestions:
print(f" - {s}")Rate Limiting and Retries
from openai import RateLimitError
import time
def call_with_retry(prompt: str, max_retries: int = 3) -> str:
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
)
return response.choices[0].message.content
except RateLimitError:
wait = 2 ** attempt # 1s, 2s, 4s
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
raise Exception("Max retries exceeded")Common Mistakes / Pitfalls
- Using GPT-4o for every task — gpt-4o-mini is 95% as capable at 10% of the cost for simple tasks
- Not streaming for user-facing chat — streaming reduces perceived latency dramatically
- Ignoring the
max_tokenslimit — without it, runaway responses inflate your bill - Not handling RateLimitError — production apps must implement exponential backoff
- Parsing JSON from content strings instead of using structured outputs — always use
response_format
Best Practices
- Use
temperature=0for factual tasks (extraction, classification) and 0.7 for creative tasks - Cache responses at
temperature=0— same input always produces the same output - Use
gpt-4o-minifor classification and summarization; reservegpt-4ofor complex reasoning - Set
max_tokenson every request to prevent unexpected large responses - Monitor
response.usage.total_tokensper request to track costs in production
Key Takeaways
- GPT-4o supports text, images, and function calling in a single unified API
- Function calling enables full AI agent loops where the LLM decides which tools to invoke
- Structured outputs with Pydantic models eliminate JSON parsing errors completely
text-embedding-3-large(3072 dims) is the highest-quality embedding model from OpenAI in 2026- Exponential backoff is required for production apps — rate limits are guaranteed to hit at scale
- GPT-4o-mini costs 95% less than GPT-4o and handles most classification and summarization tasks well
- Streaming with
client.chat.completions.streamreduces user-perceived latency by showing first tokens immediately - The Assistants API handles thread management and file search automatically for stateful chatbot use cases
Advertisement