OpenAI API Complete Guide 2026 — GPT-4o, Vision, Function Calling

Sanjeev SharmaSanjeev Sharma
5 min read

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 openai
from openai import OpenAI
client = OpenAI(api_key="sk-...")  # or set OPENAI_API_KEY env var

Chat 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)
        break

Embeddings

# 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_tokens limit — 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=0 for 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-mini for classification and summarization; reserve gpt-4o for complex reasoning
  • Set max_tokens on every request to prevent unexpected large responses
  • Monitor response.usage.total_tokens per 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.stream reduces user-perceived latency by showing first tokens immediately
  • The Assistants API handles thread management and file search automatically for stateful chatbot use cases

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading