AI / Core OpenAI Codex Application Fundamentals Interview Questions
1. What is OpenAI Codex and how has it evolved from its original form?
OpenAI Codex began as a language model specifically trained for code generation, first released in 2021 as the engine behind GitHub Copilot. Over time, "Codex" evolved into something broader: OpenAI's agentic software engineering platform - a cloud-based coding agent that performs end-to-end software tasks rather than just generating snippets in response to prompts.
Today Codex refers to a complete product suite:
| Component | Description |
|---|---|
| Codex App | Desktop and web command center for agentic coding sessions |
| Codex CLI | Open-source command-line tool for terminal-native agentic coding |
| Codex IDE Extension | Integration into VS Code and other IDEs |
| Codex Cloud | Cloud-hosted agentic environment accessible from web/mobile |
| Codex SDK/API | Programmatic access via the Responses API |
The models powering Codex have also advanced substantially. Early 2025 introduced codex-1 (a version of o3 optimised for software engineering). By mid-2026 the recommended models are from the GPT-5.x family - primarily gpt-5.5 and gpt-5.4 - which unify reasoning, coding specialisation, and general intelligence in a single model line.
The architectural shift is fundamental: Codex evolved from a passive completion model ("give me code") into an active agent that reads repositories, writes and runs code, fixes test failures, and opens pull requests - operating more like an autonomous colleague than a syntax autocomplete tool.
2. What are the current recommended models for OpenAI Codex and the API, and when do you choose each?
Model selection in the OpenAI / Codex ecosystem as of mid-2026 centres on the GPT-5.x family. The right choice depends on task complexity, latency requirements, and cost.
| Model | Best for | Context window | Key capability |
|---|---|---|---|
| gpt-5.5 | API-based code generation and general agentic tasks | Large | Strongest for complex coding, reasoning, and professional workflows |
| gpt-5.4 | Codex app/CLI default - most tasks | 1M (experimental) | Native computer use, complex tool use, long-horizon tasks |
| gpt-5.4-mini | Faster, lower-cost option for lighter tasks or subagents | Standard | Speed and cost efficiency |
| gpt-5.3-codex | Maximum agentic coding capability, complex real-world SE | Standard | 25% faster than predecessor; strongest coding + reasoning fusion |
| gpt-5.3-codex-spark | Near-instant coding iteration (research preview, Pro only) | 128k tokens | 1000+ tokens/second; text-only at launch; powered by Cerebras |
| codex-mini-latest | CLI optimised, low-latency code Q&A | Standard | Priced $1.50/1M input, $6/1M output via Responses API |
Key guidance:
- For API-based code generation: start with
gpt-5.5 - For Codex app/CLI most tasks:
gpt-5.4is the default - For maximum agentic coding power:
gpt-5.3-codex - For speed and lower cost:
gpt-5.4-miniorcodex-mini-latest
Note: gpt-5.2-codex and gpt-5.3-codex (when accessed via ChatGPT sign-in) are deprecated in the Codex surfaces - update references to current models.
3. What is the OpenAI Responses API and how does it differ from the Chat Completions API?
The Responses API (/v1/responses), launched in March 2025, is OpenAI's recommended API primitive for new projects. It is a superset of the Chat Completions API, providing everything Chat Completions offers plus built-in agentic capabilities.
| Feature | Chat Completions | Responses API |
|---|---|---|
| Endpoint | /v1/chat/completions | /v1/responses |
| Status | Fully supported; not deprecated | Recommended for all new projects |
| Built-in tools | None (manual function calling only) | Web search, file search, computer use, code interpreter, remote MCPs |
| State management | Manual - must pass full history each turn | store: true persists state; previous_response_id chains turns |
| Output format | choices[].message.content | output array of typed Items |
| Reasoning models | Limited tool support | Full reasoning + tool support (e.g. GPT-5 series) |
| Prompt caching | Available | 40-80% improved cache utilisation vs Chat Completions |
| Performance | Baseline | 3% improvement on SWE-bench with same prompt (internal evals) |
# Responses API - Python from openai import OpenAI client = OpenAI() result = client.responses.create( model="gpt-5.5", input="Find the null pointer exception: ...your code here...", reasoning={"effort": "high"}, ) print(result.output_text) # Chaining turns with previous_response_id: followup = client.responses.create( model="gpt-5.5", input="Now fix it.", previous_response_id=result.id, )
The Responses API uses Items (a typed union of model actions) instead of Messages. Key advantages include stateful multi-turn interactions, better cache utilisation, and first-class support for reasoning models and built-in tools.
4. What are the built-in tools available in the OpenAI Responses API?
The Responses API ships with several built-in tools that the model can invoke automatically without you writing wrapper code. These tools connect the model to the real world and the developer's environment.
| Tool | What it does | Key use case |
|---|---|---|
| web_search | Fetches real-time, cited information from the internet | Research agents, shopping assistants, live data queries |
| file_search | Retrieves relevant content from uploaded document repositories with metadata filtering | RAG-style Q&A over documentation, contracts, PDFs |
| computer_use | Lets the model interact with a computer - click, type, navigate UI | Browser automation, GUI testing, UI-driven workflows |
| code_interpreter | Executes Python code in a sandboxed container; can produce charts/files | Data analysis, calculations, generating visualisations |
| remote MCP servers | Connects to any Model Context Protocol server over the internet | Custom tooling, enterprise API integrations, specialised data sources |
# Using web_search in the Responses API: from openai import OpenAI client = OpenAI() response = client.responses.create( model="gpt-5.5", tools=[{"type": "web_search_preview"}], input="What are the latest changes to Python's asyncio in 3.12?", ) print(response.output_text) # Using multiple tools together: response = client.responses.create( model="gpt-5.5", tools=[ {"type": "web_search_preview"}, {"type": "file_search", "vector_store_ids": ["vs_abc123"]} ], input="Summarise our internal Q3 report and compare it with industry trends.", )
Tools can be combined in a single request. The model decides when and how to invoke them - the developer does not need to manually manage tool invocation loops as with function calling in Chat Completions.
5. What is the OpenAI Agents SDK and what are its four core primitives?
The OpenAI Agents SDK (launched March 2025, evolved from the experimental Swarm project) is an open-source, lightweight framework for building multi-step agentic workflows on top of the Responses API and other providers. It is available for Python (openai-agents) and TypeScript.
| Primitive | Purpose | Key behaviour |
|---|---|---|
| Agents | AI models equipped with instructions and tools | Execute tasks, call tools, produce outputs |
| Handoffs | Delegation mechanism between specialised agents | One agent passes control to another better suited for a sub-task |
| Guardrails | Input/output validation layer | Validate, filter, or block inputs/outputs before/after model calls |
| Tracing | Built-in observability for agent runs | Logs all steps, tool calls, and decisions for debugging and evals |
from agents import Agent, Runner # Define an agent coding_agent = Agent( name="CodingAgent", instructions="You are an expert Python developer. Write clean, tested code.", tools=[web_search_tool, code_interpreter_tool], model="gpt-5.5", ) # Run the agent import asyncio result = asyncio.run(Runner.run( coding_agent, "Write a Python function that parses JWT tokens and validates expiry.", )) print(result.final_output)
Provider agnostic: despite being OpenAI's SDK, it works with 100+ other LLMs via the Chat Completions API - including models from Anthropic, Mistral, and others via LiteLLM. This prevents vendor lock-in.
When to use Responses API vs Agents SDK: use the Responses API when a single model call with tools and your own application logic is sufficient. Use the Agents SDK when your application owns orchestration, tool execution, approvals, and state management across a multi-agent system.
6. What is the Codex CLI and what are its key features?
The Codex CLI is an open-source, terminal-native agentic coding tool that brings OpenAI's coding models directly into your command line. It was rebuilt in 2025 around agentic workflows, making it significantly more capable than a simple code-generation prompt wrapper.
| Feature | Description |
|---|---|
| Agentic execution | Works through multi-step tasks autonomously - reads files, writes code, runs tests |
| Image input | Attach screenshots, wireframes, and diagrams to build shared context |
| To-do tracking | Tracks progress on complex tasks with a visible to-do list |
| Web search | Built-in web search for looking up APIs and documentation |
| MCP support | Connect to Model Context Protocol servers for external tool integration |
| Three approval modes | read-only, auto (workspace-scoped), full-access (network + anywhere) |
| Model selection | --model flag or /model command; defaults to gpt-5.4 if unspecified |
| Thread management | /model command switches model mid-thread; --model flag sets it at start |
# Installation npm install -g @openai/codex # Basic usage - interactive session codex # Run with a specific model codex --model gpt-5.5 # Execute a single task non-interactively codex exec "Add comprehensive docstrings to all public functions in src/" # Exec with specific model codex exec --model gpt-5.4-mini "Fix all linting errors in utils.py" # Change model during an active thread: # /model gpt-5.5 # Specify model in config.toml: # [codex] # model = "gpt-5.5"
The CLI and IDE extension share the same config.toml configuration file. Authentication supports both ChatGPT account sign-in (for ChatGPT subscribers) and API key authentication (for direct API access).
7. What is the Chat Completions API and when should you still use it?
The Chat Completions API (/v1/chat/completions) is OpenAI's original and most widely adopted API, introduced with GPT-3.5 and GPT-4. It uses an array of messages with role (system, user, assistant) and content fields to generate responses.
from openai import OpenAI client = OpenAI() # Classic Chat Completions call response = client.chat.completions.create( model="gpt-5.5", messages=[ {"role": "system", "content": "You are an expert Python developer."}, {"role": "user", "content": "Explain asyncio.gather() with an example."}, ], temperature=0.2, max_tokens=1024, ) print(response.choices[0].message.content)
When to continue using Chat Completions:
- Your application does NOT need built-in tools (web search, file search, computer use)
- You have extensive existing integrations built on Chat Completions and migration is not yet justified
- You need maximum compatibility with third-party libraries and frameworks
- Simple, single-turn completions without stateful context
Important note for reasoning models: starting with GPT-5.4, tool calling is NOT supported in Chat Completions with reasoning: none. For tool use with reasoning models, migrate to the Responses API.
OpenAI has committed to continuing to release new models to Chat Completions as long as those models' capabilities don't depend on built-in tools or multiple model calls.
8. What is function calling (tool use) in the OpenAI API and how does it work?
Function calling (referred to as tool use in the Responses API) allows you to describe external functions to the model in a structured JSON schema format. The model then decides when and how to call those functions, returning structured arguments you can use to invoke your actual code.
# Chat Completions - function calling from openai import OpenAI import json client = OpenAI() # 1. Define functions as tools tools = [{ "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "City name"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["city"] } } }] # 2. First call - model decides to call a function response = client.chat.completions.create( model="gpt-5.5", messages=[{"role": "user", "content": "What's the weather in Tokyo?"}], tools=tools, tool_choice="auto", # "auto" | "required" | {"type":"function","function":{"name":"..."}} ) # 3. Extract the function call message = response.choices[0].message tool_call = message.tool_calls[0] function_args = json.loads(tool_call.function.arguments) # 4. Execute your function weather_result = get_weather(**function_args) # your actual implementation # 5. Second call - send function result back response2 = client.chat.completions.create( model="gpt-5.5", messages=[ {"role": "user", "content": "What's the weather in Tokyo?"}, message, # assistant turn with tool_calls {"role": "tool", "content": json.dumps(weather_result), "tool_call_id": tool_call.id} ], tools=tools, )
In the Responses API, the same concept is called tool use and requires less manual state management - you can use previous_response_id to chain turns instead of manually reconstructing the message array.
9. What are structured outputs in the OpenAI API and how do you use them?
Structured outputs guarantee that a model's response strictly conforms to a developer-defined JSON schema. This eliminates the need for output parsing heuristics and makes AI outputs reliably machine-readable.
from openai import OpenAI from pydantic import BaseModel client = OpenAI() # Method 1: Pydantic model (Python SDK - simplest approach) class CodeReview(BaseModel): issues: list[str] severity: str # "low" | "medium" | "high" suggested_fix: str confidence_score: float # Responses API with structured output response = client.responses.create( model="gpt-5.5", input="Review this Python function for bugs: def add(a, b): return a - b", text={ "format": { "type": "json_schema", "json_schema": { "name": "code_review", "schema": CodeReview.model_json_schema(), "strict": True } } } ) review = CodeReview.model_validate_json(response.output_text) print(f"Severity: {review.severity}") print(f"Issues: {review.issues}") # Chat Completions with parse() helper (beta): completion = client.beta.chat.completions.parse( model="gpt-5.5", messages=[{"role": "user", "content": "Extract: Alice is 30, is an engineer."}], response_format=CodeReview, ) result = completion.choices[0].message.parsed
Key differences between APIs: in the Responses API, use text.format with type: json_schema. In Chat Completions, use response_format with type: json_schema. Both support strict: true which enforces the schema constraint at the grammar level, eliminating the possibility of schema violations.
10. What is the OpenAI Assistants API and what is its deprecation timeline?
The Assistants API was OpenAI's original high-level framework for building stateful, multi-turn AI assistants with persistent threads, file handling, and built-in tools. It introduced key concepts like Threads (conversation state), Runs (execution instances), and Vector Stores (document retrieval).
| Concept | Description |
|---|---|
| Assistant | A configured AI model with instructions, tools, and optional files |
| Thread | A persistent conversation history (persisted server-side) |
| Run | An execution of an assistant on a thread - produces a response |
| Message | A single turn added to a Thread |
| Vector Store | A server-side store of embedded documents for file search |
Deprecation timeline: OpenAI formally announced the Assistants API deprecation in 2025. The planned sunset date is mid-2026, once full feature parity is achieved in the Responses API. Key migration points:
- Threads - replaced by
previous_response_idchaining or the Conversations API in Responses - Vector Stores - now a standalone resource, still used with
file_searchtool in Responses API - Code Interpreter - available as a built-in tool in Responses API
- Assistant objects - replaced by the system instructions field in Responses calls
Recommendation: all new projects should use the Responses API with the Agents SDK. Existing Assistants API integrations should plan migration before mid-2026 to avoid disruption.
11. What is prompt caching in the OpenAI API and how does it reduce costs?
Prompt caching allows OpenAI's servers to reuse portions of a prompt that were computed in a previous request, reducing both latency and cost. When a significant portion of your prompt matches a cached prefix, you are charged a reduced rate for the cached portion.
How it works: OpenAI automatically caches prompts that share a long common prefix (system prompt, tool definitions, document content). On cache hits, the model skips recomputing those tokens. Cached tokens are cheaper than fresh input tokens.
| Metric | Chat Completions | Responses API |
|---|---|---|
| Cache utilisation improvement | Baseline | 40-80% improvement over Chat Completions (internal tests) |
| Cost reduction | Standard input pricing for all tokens | Discounted rate for cached tokens (e.g. 75% discount for codex-mini-latest) |
| Latency reduction | Baseline | Lower time-to-first-token for repeated prompts |
# The cache works automatically - no special API call needed. # Maximise cache hits by: # 1. Keeping system prompts identical across calls # 2. Placing stable content (instructions, tool definitions) at the START # 3. Placing variable content (user query, session data) at the END # Example: maximise caching for a code review assistant response = client.responses.create( model="gpt-5.5", instructions="""You are an expert Python code reviewer. Follow PEP 8, identify security issues, and suggest improvements. [... 2000 token system prompt stays identical across all calls ...] """, # This large stable prefix gets cached after first call input=f"Review this PR: {variable_code_diff}", # This varies per call ) # codex-mini-latest: 75% prompt caching discount # $1.50/1M -> $0.375/1M on cache hits
Best practices for maximising cache hits: structure prompts with stable content first (system instructions, tool schemas, large documents) and dynamic content last (the user's specific request). The Responses API achieves 40-80% better cache utilisation than Chat Completions due to its state management design.
12. What are reasoning models in the OpenAI API and what is the 'effort' parameter?
Reasoning models (originating with the o1/o3 family and now integrated into the GPT-5.x line) spend additional compute "thinking" through a problem before producing a final answer. This hidden chain-of-thought reasoning dramatically improves performance on complex multi-step tasks like mathematics, coding, and planning.
| Model | Reasoning behaviour |
|---|---|
| gpt-5.5 | Reasoning built-in; effort parameter controls depth |
| gpt-5.4 | Adaptive reasoning - dynamically adjusts thinking time based on task complexity |
| gpt-5.3-codex | Combined frontier coding + strong reasoning in one model |
| gpt-5.4-mini | Faster, lighter reasoning for cost-sensitive tasks |
from openai import OpenAI client = OpenAI() # Responses API with reasoning effort result = client.responses.create( model="gpt-5.5", input="Design a thread-safe cache with LRU eviction in Python.", reasoning={"effort": "high"}, # "low" | "medium" | "high" ) print(result.output_text) # "low" - faster, cheaper; suitable for simple code Q&A # "medium" - balanced; good default for most coding tasks # "high" - maximum reasoning; for complex architecture, hard bugs # Encrypted reasoning (reasoning without exposing thinking tokens): result = client.responses.create( model="gpt-5.5", input="Find all race conditions in this concurrent code: ...", reasoning={"effort": "high", "summary": "auto"}, # get reasoning summary )
Adaptive reasoning in gpt-5.4: this model dynamically adjusts reasoning depth per task. On simple requests it responds quickly (using far fewer tokens); on complex tasks it automatically uses more compute. Testing showed gpt-5.4 uses 93.7% fewer tokens than gpt-5.5 for the bottom 10% of simple user turns, while maintaining full capability on hard tasks.
13. What are OpenAI's key API authentication and security concepts?
Proper authentication and security practices are fundamental to building production OpenAI applications. Mistakes here can lead to credential exposure, unexpected costs, or data breaches.
import os from openai import OpenAI # 1. NEVER hardcode API keys - use environment variables client = OpenAI( api_key=os.environ.get("OPENAI_API_KEY"), # required organization=os.environ.get("OPENAI_ORG_ID"), # optional project=os.environ.get("OPENAI_PROJECT_ID"), # optional ) # 2. Project API keys (recommended over user keys) # Create per-project keys at: platform.openai.com/api-keys # Scoped to a specific project - limits blast radius on leak # 3. Organisation structure for teams: # Organisation > Projects > API keys (per project) # Rate limits and costs tracked per project # 4. Service accounts (enterprise) # Use service account keys for production, not personal user keys # 5. IP allowlists (available in API settings) # Restrict which IPs can use an API key # 6. Codex CLI authentication options: # a) API key: OPENAI_API_KEY env var # b) ChatGPT sign-in: codex auth (auto-generates key for ChatGPT subscribers)
| Practice | Reason |
|---|---|
| Use environment variables | Never expose keys in code, logs, or repositories |
| Use project-scoped API keys | Limits blast radius if a key is leaked - only one project is affected |
| Rotate keys regularly | Limits exposure window from undetected leaks |
| Set spending limits | Prevents runaway costs from bugs or abuse |
| Enable IP allowlists | Prevents use from unexpected network locations |
| Use service accounts in prod | Personal user keys tied to employment - service accounts are stable |
OpenAI never charges for API key creation. Billing is based on tokens consumed. Set monthly spend limits in the organisation settings to prevent unexpected charges during development.
14. What are rate limits in the OpenAI API and how do you handle them in production?
OpenAI enforces rate limits to ensure fair access and prevent abuse. Limits are applied on three dimensions and vary by model and usage tier. Hitting rate limits returns a 429 Too Many Requests error.
| Dimension | Abbreviation | What it limits |
|---|---|---|
| Requests per minute | RPM | Number of API calls in 60 seconds |
| Tokens per minute | TPM | Total input + output tokens processed per 60 seconds |
| Requests per day | RPD | Total API calls in 24 hours (some lower tiers) |
import time import openai from openai import OpenAI client = OpenAI() # 1. Exponential backoff with jitter - handle 429 errors gracefully def call_with_retry(prompt: str, max_retries: int = 5): for attempt in range(max_retries): try: return client.responses.create( model="gpt-5.5", input=prompt, ) except openai.RateLimitError as e: if attempt == max_retries - 1: raise wait = (2 ** attempt) + (0.1 * attempt) # exponential + jitter print(f"Rate limited. Waiting {wait:.1f}s...") time.sleep(wait) # 2. The Python SDK retries automatically by default # Configure retry behaviour: client = OpenAI( max_retries=3, # default is 2 timeout=60.0, # request timeout in seconds ) # 3. Use the Batch API for large non-time-sensitive workloads # Batch processing: ~50% cost reduction, no rate limit impact response = client.batches.create( input_file_id="file-abc123", endpoint="/v1/responses", completion_window="24h", )
Tier progression: accounts start at Tier 1 with conservative limits. Limits automatically increase as spending grows (Tier 2 at $100 spend, Tier 3 at $500, etc.). For production workloads needing higher limits, contact OpenAI to request increases.
15. What is the Batch API and when should you use it?
The Batch API allows you to submit many API requests asynchronously in a single file, receive results up to 24 hours later, and pay approximately 50% less than standard synchronous pricing. It is designed for large-scale, non-time-sensitive workloads.
from openai import OpenAI import jsonlines client = OpenAI() # 1. Create a JSONL file with requests batch_requests = [ { "custom_id": "review-001", "method": "POST", "url": "/v1/responses", "body": { "model": "gpt-5.5", "input": "Review: def fib(n): return fib(n-1) + fib(n-2)", "max_output_tokens": 500, } }, # ... thousands more requests ] # Write JSONL with open("batch_input.jsonl", "w") as f: for req in batch_requests: f.write(json.dumps(req) + "\n") # 2. Upload the file batch_file = client.files.create( file=open("batch_input.jsonl", "rb"), purpose="batch" ) # 3. Create the batch batch = client.batches.create( input_file_id=batch_file.id, endpoint="/v1/responses", completion_window="24h", ) print(f"Batch ID: {batch.id}") # 4. Poll for completion (or use webhooks) batch_status = client.batches.retrieve(batch.id) if batch_status.status == "completed": results = client.files.content(batch_status.output_file_id) # Parse JSONL results
| Aspect | Synchronous | Batch API |
|---|---|---|
| Cost | Standard pricing | ~50% reduction |
| Latency | Real-time (<1 min typical) | Up to 24 hours |
| Rate limits | Counts against RPM/TPM | Separate batch limits |
| Use cases | Interactive apps, real-time tools | Evals, dataset generation, bulk analysis |
| Max requests per batch | N/A | Up to 50,000 requests |
16. What is streaming in the OpenAI API and how do you implement it?
Streaming delivers the model's output token by token as it is generated, rather than waiting for the complete response. This dramatically improves perceived performance in interactive applications by showing text appearing in real time.
from openai import OpenAI client = OpenAI() # Chat Completions streaming with client.chat.completions.stream( model="gpt-5.5", messages=[{"role": "user", "content": "Write a Python web scraper."}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) # Access final complete response: final = stream.get_final_completion() # Responses API streaming with client.responses.stream( model="gpt-5.5", input="Explain async/await in Python with examples.", ) as stream: for event in stream: # Events: response.created, response.in_progress, # response.output_item.added, response.content_part.delta, # response.completed, etc. if event.type == "response.output_text.delta": print(event.delta, end="", flush=True) final_response = stream.get_final_response() # Async streaming for FastAPI/async applications: async def stream_response(): async with client.responses.stream( model="gpt-5.5", input="Review this code: ...", ) as stream: async for text in stream.text_stream: yield text # SSE to browser
| Event | When it fires |
|---|---|
| response.created | Once at the start - response object initialised |
| response.output_text.delta | For each text token chunk as it arrives |
| response.output_item.added | When a new output item (text block, tool call) starts |
| response.completed | Once when the full response is finished |
Both APIs support streaming. The Responses API streaming events are more granular and expose tool call streaming - you can see tool call arguments being built token by token, enabling more sophisticated streaming UIs.
17. What is OpenAI's Codex Skills feature and what are Automations?
Two higher-level Codex product features extend beyond direct coding assistance:
Skills are reusable, project-specific capabilities that Codex learns and applies consistently. They go beyond writing code to encompass code understanding, prototyping, and documentation - aligned with your team's specific standards and patterns. Skills allow Codex to understand your team's conventions, architectural patterns, and tooling preferences, producing outputs that fit directly into your existing workflows.
Automations allow Codex to work unprompted on routine but important tasks. Instead of waiting for a developer to ask, Codex proactively picks up work like:
- Issue triage - categorising and labelling new GitHub issues
- Alert monitoring - responding to CI failures or monitoring alerts
- CI/CD pipeline tasks - running checks, updating dependencies
- Scheduled code quality tasks - running linters, generating reports
# Automations can be configured to: # - Monitor GitHub issue queues and triage new issues # - Watch CI/CD pipelines and fix recurring failures # - Respond to monitoring alerts and attempt automated remediation # - Run scheduled code quality reviews # Skills examples: # - "Our team uses pytest with the Arrange-Act-Assert pattern" # - "All new API endpoints need OpenAPI docstrings following our schema" # - "Refactoring should preserve backward compatibility per our versioning policy" # These are configured in the Codex App UI, not via the API directly
Together, Skills and Automations represent the shift from Codex as a passive responder to an active software engineering team member that proactively contributes to quality and productivity without requiring a developer to initiate every interaction.
18. What is Model Context Protocol (MCP) and how does it integrate with OpenAI tools?
Model Context Protocol (MCP) is an open standard for connecting AI models to external tools and data sources through a standardised interface. OpenAI has adopted MCP as a first-class integration in both the Responses API and the Codex CLI, enabling models to call tools exposed by MCP servers without requiring custom integration code per tool.
| Integration point | How MCP is used |
|---|---|
| Responses API | remote MCP servers as a built-in tool type - call any MCP-compatible server directly |
| Codex CLI | /mcp command to connect CLI sessions to MCP servers |
| Codex App | MCP and personality actions accessible from the command palette |
| Agents SDK | MCP connectors for external system integration |
| Secure MCP Tunnel | Enterprise feature: connect to private/on-prem MCP servers without public exposure |
# Using a remote MCP server in the Responses API: response = client.responses.create( model="gpt-5.5", tools=[ { "type": "mcp", "server_url": "https://mcp.example.com/tools", "server_label": "my-internal-tools", "require_approval": "never", # auto-approve tool calls } ], input="Query the production database for user count by region.", ) # Secure MCP Tunnel (enterprise - for private servers): # 1. Deploy tunnel-client on your internal network # 2. Register tunnel in OpenAI platform # 3. Reference as a remote MCP without exposing server publicly # In Codex CLI during an active session: # /mcp - shows available MCP servers # /mcp connect https://my-mcp-server.example.com/sse
MCP enables a composable ecosystem: any organisation can publish MCP servers for their internal systems (databases, ticketing systems, deployment tools) and connect them to Codex without OpenAI needing to build specific integrations for each tool.
19. What is fine-tuning in the OpenAI API and when should you use it?
Fine-tuning creates a customised version of an OpenAI model trained on your own examples. It is used when prompting or few-shot examples are insufficient to achieve the desired style, format, or domain-specific accuracy.
| Method | Description | Best for |
|---|---|---|
| Supervised fine-tuning (SFT) | Train on (prompt, ideal completion) pairs | Style, format, domain-specific knowledge |
| Direct Preference Optimisation (DPO) | Train on (prompt, preferred, rejected) triplets | Aligning outputs with human preferences |
| Reinforcement fine-tuning (RFT) | Train with a reward signal (verifiable tasks) | Math, coding tasks with deterministic correct answers |
from openai import OpenAI client = OpenAI() # 1. Prepare training data (JSONL format) # Each line: {"messages": [{"role": "system", "content": "..."}, ...]} # Save as training.jsonl # 2. Upload training file training_file = client.files.create( file=open("training.jsonl", "rb"), purpose="fine-tune" ) # 3. Create fine-tuning job job = client.fine_tuning.jobs.create( training_file=training_file.id, model="gpt-4.1-mini-2025-04-14", # supported base models # model="gpt-4.1-2025-04-14", hyperparameters={ "n_epochs": 3, } ) # 4. Monitor job job_status = client.fine_tuning.jobs.retrieve(job.id) print(f"Status: {job_status.status}") # 5. Use fine-tuned model response = client.chat.completions.create( model=job_status.fine_tuned_model, # e.g. ft:gpt-4.1-mini:my-org::abc123 messages=[{"role": "user", "content": "..."}], )
When NOT to fine-tune first: prompt engineering, few-shot examples, and RAG (retrieval-augmented generation) should be tried before fine-tuning. Fine-tuning requires training data, incurs training costs, and has longer iteration cycles. Reserve it for cases where the base model consistently fails despite good prompting.
20. What are embeddings in the OpenAI API and what are they used for?
Embeddings convert text (or other content) into dense numerical vectors that capture semantic meaning. Texts with similar meaning produce similar vectors, enabling mathematical operations on language: search, clustering, classification, and anomaly detection without requiring labelled training data for each task.
from openai import OpenAI import numpy as np client = OpenAI() # Generate embeddings response = client.embeddings.create( model="text-embedding-3-large", # 3072 dimensions # model="text-embedding-3-small", # 1536 dimensions, cheaper input=[ "OpenAI Codex is an agentic coding assistant.", "GitHub Copilot helps developers write code.", "The stock market rose 2% today.", ] ) # Extract vectors vectors = [item.embedding for item in response.data] # Semantic similarity via cosine similarity def cosine_similarity(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) sim_coding = cosine_similarity(vectors[0], vectors[1]) # high - both about coding AI sim_unrelated = cosine_similarity(vectors[0], vectors[2]) # low - different topic print(f"Coding similarity: {sim_coding:.3f}") # e.g. 0.89 print(f"Unrelated similarity: {sim_unrelated:.3f}") # e.g. 0.21 # Dimension reduction (for storage/speed tradeoff): response = client.embeddings.create( model="text-embedding-3-large", input="example text", dimensions=512, # reduce from 3072 to 512 )
| Model | Dimensions | Use case |
|---|---|---|
| text-embedding-3-large | 3072 (reducible) | Highest quality; production RAG, reranking |
| text-embedding-3-small | 1536 (reducible) | Fast, cheaper; good for classification, clustering |
Common use cases: RAG (Retrieval-Augmented Generation) where documents are embedded and stored in a vector database, then the most relevant chunks are retrieved for a query; semantic search; clustering documents; recommendation systems; and classifying content without labelled training data.
21. What is the OpenAI moderation API and why is it important for application safety?
The Moderation API classifies text (and now images) against OpenAI's usage policies, detecting harmful content across multiple categories. It is free to use and essential for any application that accepts user-generated content.
from openai import OpenAI client = OpenAI() # Standalone moderation check response = client.moderations.create( model="omni-moderation-latest", input="I want to hurt someone.", ) result = response.results[0] if result.flagged: print("Content flagged!") for category, flagged in result.categories.__dict__.items(): if flagged: print(f" - {category}: score {getattr(result.category_scores, category):.3f}") # Image moderation (omni-moderation-latest supports images): response = client.moderations.create( model="omni-moderation-latest", input=[ {"type": "text", "text": "Check this text"}, {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}} ] ) # Inline moderation with Responses API (2026 feature): response = client.responses.create( model="gpt-5.5", input="User message here", moderation={}, # get moderation scores inline with the response )
| Category | What it detects |
|---|---|
| hate | Content promoting hatred based on protected characteristics |
| harassment | Content targeting individuals with threats or abuse |
| self-harm | Content promoting self-injury or suicide |
| sexual | Explicit or suggestive sexual content |
| violence | Graphic violence or glorification of harm |
| illicit | Instructions for illegal activities |
Best practice: run moderation on user inputs before sending to the model to prevent policy violations. The Moderation API is free - there is no reason not to use it in consumer-facing applications. In 2026, OpenAI added inline moderation scores directly to the Responses API, enabling a single request to get both the model's response and moderation results.
22. What are OpenAI's image generation models and how do you use them in applications?
OpenAI offers image generation models accessible via the Images API. As of mid-2026 the recommended models are gpt-image-2 and gpt-image-1, following the deprecation of DALL-E 2 and DALL-E 3 in May 2026.
| Model | Key capability | API endpoint |
|---|---|---|
| gpt-image-2 | Most advanced; highest quality generation and editing | v1/images/generate, v1/images/edits |
| gpt-image-1 | Strong generation; also available via Responses API image tool | v1/images/generate, Responses API |
| gpt-image-1-mini | Faster, lighter image generation | v1/images/generate |
| chatgpt-image-latest | Always points to the latest image model | v1/images/generate |
from openai import OpenAI import base64 client = OpenAI() # Generate an image (gpt-image-2) response = client.images.generate( model="gpt-image-2", prompt="A Python snake debugging code on a computer, photorealistic", size="1024x1024", quality="high", n=1, response_format="b64_json", # or "url" ) image_data = base64.b64decode(response.data[0].b64_json) # Image editing (inpainting) response = client.images.edit( model="gpt-image-2", image=open("original.png", "rb"), mask=open("mask.png", "rb"), # transparent area = area to edit prompt="Replace the background with a futuristic city skyline", ) # Via Responses API (gpt-image-1 as a tool): response = client.responses.create( model="gpt-5.5", input="Create a diagram of a microservices architecture.", tools=[{"type": "image_generation"}], )
Note on DALL-E deprecation: DALL-E 2 and DALL-E 3 model snapshots were deprecated and removed from the API on May 12, 2026. Applications referencing dall-e-2 or dall-e-3 will now receive errors and must migrate to gpt-image-2, gpt-image-1, or gpt-image-1-mini.
23. What is the OpenAI Realtime API and what use cases does it enable?
The Realtime API (generally available since 2025) enables low-latency, bidirectional audio and text streaming - powering live voice agents, speech-to-speech applications, and real-time transcription. As of 2026, the product line has expanded significantly.
| Model | Purpose |
|---|---|
| GPT-Realtime-2 | Next-gen realtime voice with configurable reasoning for speech-to-speech agents |
| GPT-Realtime-Translate | Streaming speech translation between languages |
| GPT-Realtime-Whisper | Streaming speech-to-text (transcription) |
| gpt-audio-mini | Efficient audio model for production voice pipelines |
import asyncio import websockets import json # Realtime API uses WebSocket connection: async def realtime_session(): url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2" headers = { "Authorization": f"Bearer {OPENAI_API_KEY}", "OpenAI-Beta": "realtime=v1" } async with websockets.connect(url, extra_headers=headers) as ws: # Configure session await ws.send(json.dumps({ "type": "session.update", "session": { "modalities": ["text", "audio"], "voice": "alloy", "instructions": "You are a helpful coding assistant.", "input_audio_format": "pcm16", "output_audio_format": "pcm16", } })) # Stream audio input await ws.send(json.dumps({ "type": "input_audio_buffer.append", "audio": base64_pcm16_audio_chunk, })) # Commit and request response await ws.send(json.dumps({"type": "input_audio_buffer.commit"})) await ws.send(json.dumps({"type": "response.create"}))
Key use cases: voice customer service agents, real-time meeting transcription and translation, voice-controlled coding assistants, accessibility tools, and interactive voice tutorials. The SIP IP ranges feature added in 2026 enables integration with traditional telephony systems.
24. What is retrieval-augmented generation (RAG) and how do you implement it with OpenAI?
Retrieval-Augmented Generation (RAG) is a technique that enhances a language model's responses by providing relevant context retrieved from an external knowledge base at query time. Instead of relying solely on the model's training data, RAG retrieves up-to-date or private information and includes it in the prompt.
from openai import OpenAI client = OpenAI() # ---- FULL RAG PIPELINE ---- # Step 1: Embed and index your documents (do this once) def embed_documents(texts: list[str]) -> list[list[float]]: response = client.embeddings.create( model="text-embedding-3-large", input=texts, ) return [item.embedding for item in response.data] docs = [ "Our refund policy: returns accepted within 30 days with receipt.", "API rate limits: 3500 RPM for Tier 2 customers.", "Python 3.12 introduced GIL opt-out via Py_GIL_DISABLED=1.", ] doc_embeddings = embed_documents(docs) # Store doc_embeddings + docs in a vector database (Pinecone, Weaviate, pgvector...) # Step 2: At query time, retrieve relevant chunks user_query = "Can I return a product after 2 months?" query_embedding = embed_documents([user_query])[0] # similarity_search(query_embedding) -> returns top-k relevant docs relevant_docs = ["Our refund policy: returns accepted within 30 days with receipt."] # Step 3: Generate with context response = client.responses.create( model="gpt-5.5", instructions="Answer based only on the provided context. If unsure, say so.", input=f"Context:\n{chr(10).join(relevant_docs)}\n\nQuestion: {user_query}", ) print(response.output_text) # "Based on our policy, returns are only accepted within 30 days with a receipt, # so a return after 2 months would not be eligible."
OpenAI's built-in RAG via file_search: instead of building the embedding + vector search pipeline yourself, you can upload files to OpenAI and use the file_search built-in tool in the Responses API. OpenAI handles chunking, embedding, and retrieval automatically. This is simpler but less customisable than a self-managed vector store.
25. What is OpenAI's approach to responsible use and safety in the API?
OpenAI's usage policies, safety systems, and model training all work together to define what the API will and won't do. Understanding these boundaries is essential for building compliant, safe applications.
| Layer | Mechanism | Developer control |
|---|---|---|
| Usage policies | Rules governing acceptable use cases | Agree at sign-up; apply for elevated access use cases |
| Moderation | Model refuses clearly harmful requests | No opt-out; adjust system prompt for legitimate edge cases |
| Preparedness Framework | Safety classification for high-capability models | Awareness; some high-risk capabilities require vetted access |
| System prompt controls | Operators can restrict or expand model behaviour | Yes - use system prompt to set context and constraints |
| Data training opt-out | Business data not used for training by default | Confirmed at platform level; no per-request flag needed |
Key policies for application developers:
- Applications must not use the API to generate content that violates the usage policy (CSAM, weapons instructions, deceptive content, etc.)
- As the API user (operator), you are responsible for how end-users interact with the model through your application
- The moderation API is provided free to help you screen user inputs
- High-risk use cases (medical diagnosis, legal advice, financial recommendations) require additional safeguards and clear disclaimers
Agentic safety: for agentic applications, minimise tool permissions to only what is needed (principle of least privilege), require human approval for irreversible actions, and implement guardrails at input and output.
26. What is the OpenAI token system and how do you count and optimise token usage?
OpenAI models process text as tokens - chunks of characters roughly 3-4 characters long for English text, or about 75% of a word. Pricing is per token (input + output), so understanding tokenisation directly impacts application costs.
| Content | Approximate token count |
|---|---|
| 1 English word | ~1.3 tokens on average |
| 1 page of text (~500 words) | ~650 tokens |
| 1,000 characters | ~250 tokens |
| Short code function (20 lines) | ~80-150 tokens |
| Full file (200 lines of Python) | ~800-1500 tokens |
import tiktoken # Count tokens before sending (avoid surprises) encoding = tiktoken.encoding_for_model("gpt-5.5") def count_tokens(text: str, model: str = "gpt-5.5") -> int: enc = tiktoken.encoding_for_model(model) return len(enc.encode(text)) # Count tokens for a Chat Completions messages array: def count_message_tokens(messages: list, model: str = "gpt-5.5") -> int: enc = tiktoken.encoding_for_model(model) total = 3 # reply overhead for msg in messages: total += 4 # per-message overhead for key, value in msg.items(): total += len(enc.encode(str(value))) return total # Example: tokens = count_tokens("Write a Python function that sorts a list using quicksort.") print(f"Prompt tokens: {tokens}") # ~15 tokens # Via API (most accurate, no tiktoken required): response = client.responses.create( model="gpt-5.5", input="Explain recursion.", ) print(f"Input tokens: {response.usage.input_tokens}") print(f"Output tokens: {response.usage.output_tokens}") print(f"Total: {response.usage.total_tokens}")
Cost optimisation strategies:
- Use
max_output_tokensto cap output length on tasks with known response sizes - Use prompt caching for repeated system prompts (40-80% better with Responses API)
- Choose smaller models (
gpt-5.4-mini,codex-mini-latest) for lightweight tasks - Use Batch API for non-real-time workloads (~50% discount)
- Compress context: summarise long conversation histories instead of passing full history
27. What are guardrails in the context of OpenAI application development?
Guardrails are safety and quality validation layers that intercept, evaluate, and potentially modify or block inputs and outputs at various points in an LLM application pipeline. They are especially critical in agentic systems where the model may take actions with real-world consequences.
| Type | Where applied | What it does |
|---|---|---|
| Input guardrails | Before model call | Validate, sanitise, or reject user inputs |
| Output guardrails | After model response | Validate, reformat, or block model outputs |
| Semantic guardrails | Both | Check meaning and intent, not just syntax |
| Action guardrails | Before tool execution | Require approval for high-risk agent actions |
| Agents SDK guardrails | SDK layer | Declarative guardrails run automatically on agent I/O |
from agents import Agent, Runner, GuardrailFunctionOutput, InputGuardrail from pydantic import BaseModel # Define a guardrail that validates math homework requests class HomeworkCheck(BaseModel): is_homework_question: bool reasoning: str guardrail_agent = Agent( name="HomeworkGuardrail", instructions="Check if the user is asking for homework help.", output_type=HomeworkCheck, ) async def homework_guardrail(ctx, agent, input): result = await Runner.run(guardrail_agent, input, context=ctx.context) if result.final_output.is_homework_question: raise GuardrailFunctionOutput( output_info=result.final_output, tripwire_triggered=True, # block the request ) return GuardrailFunctionOutput(output_info=result.final_output) # Attach guardrail to the main agent: main_agent = Agent( name="TutorAgent", instructions="Help students learn programming concepts.", input_guardrails=[InputGuardrail(guardrail_function=homework_guardrail)], ) # For irreversible agent actions - require human approval: def confirm_database_write(action_description: str) -> bool: print(f"Agent wants to: {action_description}") return input("Approve? (y/n): ").lower() == "y"
In the Agents SDK, guardrails run in parallel with the agent's primary model call for minimum added latency. They use a fast, cheap model to evaluate the input, raising a tripwire_triggered flag to halt execution if a policy violation is detected.
28. What is the OpenAI Files API and how is it used for document management?
The Files API allows you to upload files to OpenAI's servers for use across multiple API features - fine-tuning, batch processing, assistants, and the file_search tool. Files are identified by a file ID and persist until explicitly deleted.
from openai import OpenAI client = OpenAI() # 1. Upload a file with open("technical-docs.pdf", "rb") as f: uploaded = client.files.create( file=f, purpose="assistants" # or "fine-tune", "batch", "vision" ) file_id = uploaded.id # e.g. "file-abc123" print(f"Uploaded: {file_id}, size: {uploaded.bytes} bytes") # 2. List files files = client.files.list(purpose="assistants") for f in files.data: print(f.id, f.filename, f.created_at) # 3. Use file in a Vector Store for file_search: vector_store = client.vector_stores.create(name="TechDocs") client.vector_stores.files.create( vector_store_id=vector_store.id, file_id=file_id ) # 4. Use vector store with file_search tool: response = client.responses.create( model="gpt-5.5", tools=[{ "type": "file_search", "vector_store_ids": [vector_store.id] }], input="What is the maximum API request size?" ) print(response.output_text) # 5. Delete file when done: client.files.delete(file_id)
| purpose | Used for |
|---|---|
| assistants | Assistants API and file_search in Responses API |
| fine-tune | Fine-tuning training data |
| batch | Batch API input files |
| vision | Image files for vision tasks |
Vector Stores (previously part of the Assistants API) are now a standalone resource, usable directly with the file_search tool in the Responses API. They handle chunking, embedding, and indexing automatically.
29. How do you implement multi-agent systems using the OpenAI Agents SDK?
Multi-agent systems decompose complex tasks across multiple specialised agents that collaborate via handoffs. Each agent focuses on what it does best, improving overall quality and maintainability compared to a monolithic agent trying to do everything.
from agents import Agent, Runner, handoff import asyncio # Define specialised agents: code_agent = Agent( name="CodeWriter", instructions="Write clean, well-documented Python code. Focus on correctness.", model="gpt-5.5", ) review_agent = Agent( name="CodeReviewer", instructions="Review code for bugs, security issues, and performance problems.", model="gpt-5.5", ) doc_agent = Agent( name="DocWriter", instructions="Write clear docstrings and README documentation.", model="gpt-5.4-mini", # cheaper model for docs ) # Orchestrator agent with handoffs: orchestrator = Agent( name="Orchestrator", instructions="""Manage the coding workflow: 1. Use CodeWriter to implement features 2. Use CodeReviewer to review and fix issues 3. Use DocWriter to document the final code """, handoffs=[ handoff(code_agent), handoff(review_agent), handoff(doc_agent), ], model="gpt-5.5", ) async def run_pipeline(task: str): result = await Runner.run( orchestrator, task, max_turns=20, # prevent infinite loops ) return result.final_output # Run: output = asyncio.run(run_pipeline( "Implement a thread-safe LRU cache class with comprehensive tests" )) print(output)
Handoff patterns: an agent can hand off to a more specialised sub-agent mid-task (unidirectional), or the orchestrator can send tasks to parallel workers and aggregate results. The SDK handles the state transfer between agents so each agent receives the full context it needs.
30. What is the OpenAI Evals framework and why is evaluation critical for production applications?
Evals (evaluations) are automated tests that measure an LLM application's quality, accuracy, and reliability. OpenAI provides both an Evals API (for running evaluations programmatically) and the OpenAI Evals Framework (open-source, run locally). Without systematic evals, you cannot confidently iterate on prompts, upgrade models, or know if your application is regressing.
from openai import OpenAI client = OpenAI() # Using the Evals API: # 1. Create a dataset for evaluation: dataset = client.evals.datasets.create( name="code-review-eval", items=[ {"input": "Review: def add(a,b): return a-b", "expected": "Bug: subtraction used instead of addition"}, {"input": "Review: import os; os.system(user_input)", "expected": "Security: OS injection vulnerability"}, ] ) # 2. Create and run an eval: eval_run = client.evals.runs.create( name="code-reviewer-v2-test", model="gpt-5.5", data_source={"type": "dataset", "id": dataset.id}, grader_config={ "type": "llm_as_judge", "model": "gpt-5.4-mini", # fast/cheap grader "criteria": "Does the review correctly identify all bugs and security issues?" } ) print(f"Score: {eval_run.result.score}") # Open-source evals (run locally): # pip install evals # oaieval gpt-5.5 my-code-review-eval # Compare two models: # oaieval gpt-5.5 my-eval # oaieval gpt-5.4 my-eval
When to evaluate:
- Before deploying any prompt change to production
- Before upgrading to a new model version
- After any significant change to the application logic
- Periodically in production to detect model drift
Good evals catch regressions before users do and give you confidence to upgrade models without fear of breaking existing behaviour.
31. How do you implement error handling in OpenAI API applications?
Robust error handling is essential for production OpenAI applications. The Python SDK raises typed exceptions that map to HTTP error codes, allowing fine-grained recovery strategies per error type.
import openai from openai import OpenAI import time client = OpenAI() def robust_api_call(prompt: str) -> str: """Production-ready API call with comprehensive error handling.""" try: response = client.responses.create( model="gpt-5.5", input=prompt, timeout=30.0, ) return response.output_text except openai.AuthenticationError as e: # 401 - Invalid API key raise ValueError("Invalid API key. Check OPENAI_API_KEY.") from e except openai.PermissionDeniedError as e: # 403 - Access denied to model or feature raise PermissionError(f"Permission denied: {e.message}") from e except openai.RateLimitError as e: # 429 - Rate limited: implement exponential backoff for attempt in range(5): wait = (2 ** attempt) + 0.1 time.sleep(wait) try: return client.responses.create(model="gpt-5.5", input=prompt).output_text except openai.RateLimitError: continue raise except openai.BadRequestError as e: # 400 - Invalid request (bad parameters, context overflow) if "context_length_exceeded" in str(e): raise ValueError("Prompt too long - reduce input size.") from e raise except openai.InternalServerError as e: # 500 - OpenAI server error: retry with backoff time.sleep(5) return client.responses.create(model="gpt-5.5", input=prompt).output_text except openai.APIConnectionError as e: # Network error: check connectivity raise ConnectionError("Network error connecting to OpenAI API.") from e except openai.APITimeoutError as e: # Request timed out raise TimeoutError("API request timed out.") from e
| Exception | HTTP code | When raised |
|---|---|---|
| AuthenticationError | 401 | Invalid or missing API key |
| PermissionDeniedError | 403 | Insufficient permissions for model/feature |
| RateLimitError | 429 | RPM or TPM limit exceeded |
| BadRequestError | 400 | Invalid parameters or context overflow |
| InternalServerError | 500 | Transient OpenAI server failure |
| APIConnectionError | N/A | Network connectivity failure |
| APITimeoutError | N/A | Request exceeded timeout setting |
32. What is the OpenAI Codex App and what are its main features for software teams?
The Codex App is the primary desktop and web interface for the full Codex product suite. It serves as a command center for agentic coding sessions, allowing individual developers and teams to delegate complex software tasks to AI agents.
| Feature | Description |
|---|---|
| Parallel task execution | Run multiple coding tasks simultaneously across different parts of your codebase |
| Natural language task assignment | Assign tasks by describing goals, not implementation details |
| Code review integration | Codex can review PRs, suggest improvements, and fix review comments |
| Repository understanding | Deep indexing of your codebase for context-aware responses |
| PR creation | Automatically opens pull requests after completing tasks |
| Automations | Scheduled and event-driven tasks (issue triage, dependency updates) |
| Skills | Project-specific learned capabilities aligned with team standards |
| Team collaboration | Shared task history, handoffs, and collaborative sessions |
| Mobile access | Monitor and steer tasks from GitHub Mobile |
# Interacting with Codex programmatically (Responses API): from openai import OpenAI client = OpenAI() # Create a software engineering task via API: response = client.responses.create( model="gpt-5.3-codex", # or gpt-5.5 for API use instructions="""You are a senior Python engineer. Follow the team conventions in CONTRIBUTING.md. Write tests before implementation (TDD). Use type hints throughout. """, input="Add rate limiting middleware to our FastAPI app. Limit to 100 req/min per IP.", tools=[ {"type": "code_interpreter"}, # execute and test code {"type": "file_search", "vector_store_ids": ["vs_codebase123"]}, ], reasoning={"effort": "high"}, )
The Codex App differentiates from the CLI in that it provides a visual interface suited for task management, team workflows, and non-terminal users. The CLI is preferred for developers who live in the terminal and want to integrate AI directly into their development environment.
33. What are the key differences between OpenAI's o-series reasoning models and the GPT series?
The o-series (o1, o3, o4) were OpenAI's dedicated reasoning models - designed to spend significant compute on hidden chain-of-thought before answering. The GPT-5.x series (mid-2025 onwards) has progressively integrated reasoning capabilities, creating a unified model line that adapts reasoning depth per task.
| Aspect | o-series (o1/o3/o4) | GPT-5.x (current) |
|---|---|---|
| Reasoning | Explicit separate thinking phase | Integrated; adaptive based on task complexity |
| Speed | Slower on simple tasks (always reasons) | Adaptive: fast on simple, deeper on complex |
| API | Mostly Chat Completions | Responses API recommended |
| Tool use in reasoning | Limited (some models) | Full interleaved thinking + tool use |
| Cost | Higher per-token (reasoning tokens billed) | Reasoning tokens included or separately billed |
| Status | Legacy; o4 models still active | Current recommended family |
# Legacy o-series (still supported but not recommended for new projects): response = client.chat.completions.create( model="o4-mini", messages=[{"role": "user", "content": "Find all bugs in this code: ..."}], reasoning_effort="medium", ) # Modern GPT-5.x with integrated reasoning (recommended): response = client.responses.create( model="gpt-5.5", input="Find all bugs in this code: ...", reasoning={"effort": "high"}, # same concept, unified API ) # gpt-5.3-codex: reasoning + coding fused in one model # No separate "thinking phase" - adapts dynamically response = client.responses.create( model="gpt-5.3-codex", input="Architect a microservices system for a real-time trading platform.", reasoning={"effort": "high"}, )
Key insight: the o-series were specialised branches of the model tree; the GPT-5.x series represents a unification where general intelligence, coding specialisation, and adaptive reasoning coexist in one model family. For most new projects, GPT-5.x supersedes the need to choose between a "smart reasoning model" and a "fast general model".
34. How does the Codex IDE extension integrate with development environments?
The Codex IDE Extension brings the full Codex agentic capability directly into code editors, enabling developers to access AI assistance without leaving their development environment. It is available for VS Code and supports other IDEs through the Language Server Protocol.
| Capability | Description |
|---|---|
| Agentic code generation | Generate full features, not just snippets, with multi-file awareness |
| Code explanation | Select any code and get a clear explanation in natural language |
| Refactoring | Instruct Codex to refactor with specific constraints (keep API, add types, etc.) |
| Test generation | Generate comprehensive test suites for selected functions or files |
| Bug detection | Highlight code and ask Codex to find and explain potential issues |
| PR review | Get AI review of staged changes before committing |
| Context-aware completion | Completions that understand the entire project structure, not just the open file |
# Example .codex/config.toml (shared with CLI): [codex] model = "gpt-5.5" approval_mode = "auto" # auto, manual, or strict [context] max_file_tokens = 50000 # limit context per file exclude_patterns = [ # files to exclude from context "node_modules/**", "*.lock", "dist/**", ] [coding] preferred_language = "python" style_guide = "pep8" test_framework = "pytest" # Keyboard shortcuts (VS Code): # Ctrl+Shift+A - Open Codex chat panel # Ctrl+Shift+G - Generate code for selection # Ctrl+Shift+E - Explain selection # Ctrl+Shift+T - Generate tests for selection
The IDE extension shares config.toml with the Codex CLI, meaning your preferences (model selection, approval mode, context exclusions) are consistent across both surfaces. Changes to the config affect both environments immediately.
35. What are the key considerations for building production-grade OpenAI applications?
Moving from a prototype to a production OpenAI application requires addressing several concerns that do not arise during development: reliability, cost control, observability, and safety.
| Area | Key considerations |
|---|---|
| Cost control | Set spending limits; use Batch API for bulk; choose right model per task; track usage per user |
| Rate limits | Implement exponential backoff; design for asynchrony; use Batch API to sidestep synchronous limits |
| Observability | Log all prompts and responses; use Agents SDK tracing; monitor token usage and latency |
| Safety | Run Moderation API on user inputs; implement guardrails; require approval for irreversible actions |
| Reliability | Implement retries; handle timeouts; have fallback models; test with evals |
| Latency | Use streaming for interactive UIs; prompt caching for repeated prompts; choose model/effort for task |
| Privacy | Understand data handling for your tier; use project API keys; implement data minimisation |
| Versioning | Pin model versions (avoid -latest aliases in production); run evals before model upgrades |
# Production patterns: # 1. Never use -latest model aliases in production # BAD: client.responses.create(model="gpt-5-latest", ...) # behaviour changes without notice # GOOD: client.responses.create(model="gpt-5.5", ...) # stable, predictable # 2. Set both usage limits AND per-request caps: client.responses.create( model="gpt-5.5", input=user_message, max_output_tokens=2048, # prevent runaway outputs timeout=30.0, # prevent hanging requests ) # 3. Log everything for debugging: import logging logger = logging.getLogger("openai-app") response = client.responses.create(model="gpt-5.5", input=prompt) logger.info({ "model": "gpt-5.5", "input_tokens": response.usage.input_tokens, "output_tokens": response.usage.output_tokens, "response_id": response.id, })
36. What is the OpenAI Codex and API pricing model and how do you estimate costs?
OpenAI uses a pay-per-token pricing model for API access. For Codex CLI and App, costs are consumed from your ChatGPT or API credits balance. Understanding the cost structure helps in designing cost-efficient applications.
| Model | Input price | Output price | Use case |
|---|---|---|---|
| gpt-5.5 | ~$5/1M tokens | ~$20/1M tokens | API general use |
| gpt-5.4-mini | ~$0.60/1M tokens | ~$2.40/1M tokens | Lightweight tasks, subagents |
| codex-mini-latest | $1.50/1M tokens | $6/1M tokens | CLI-optimised Q&A |
| gpt-5.3-codex-spark | Metered (high-throughput) | Metered | Pro plan only, 1000+ tps |
| Batch API (any model) | ~50% of standard | ~50% of standard | Bulk non-real-time workloads |
| text-embedding-3-small | ~$0.02/1M tokens | N/A | Embeddings for RAG |
# Cost estimation example: # Scenario: Code review agent processes 100 PRs/day # Average PR: 2000 input tokens + 500 output tokens = 2500 tokens daily_prs = 100 avg_input_tokens = 2000 avg_output_tokens = 500 # Using gpt-5.5 at standard pricing: input_cost_per_million = 5.00 output_cost_per_million = 20.00 daily_input_cost = (daily_prs * avg_input_tokens / 1_000_000) * input_cost_per_million daily_output_cost = (daily_prs * avg_output_tokens / 1_000_000) * output_cost_per_million daily_total = daily_input_cost + daily_output_cost monthly_total = daily_total * 30 print(f"Daily cost: ${daily_total:.2f}") print(f"Monthly cost: ${monthly_total:.2f}") # With Batch API (50% discount): batch_monthly = monthly_total * 0.5 print(f"Monthly cost (Batch API): ${batch_monthly:.2f}") # With prompt caching (40% cache hit rate, 75% discount on cached): # Effective input cost reduction ~30% # + Batch API = significant overall saving
Cost reduction hierarchy: choose the right model for the task (biggest lever) > use prompt caching > use Batch API for bulk > use smaller models for sub-tasks > use streaming to reduce perceived latency without changing cost.
37. What is the OpenAI computer use capability and what does it enable?
Computer use is a capability that allows an OpenAI model to interact with a computer's graphical interface - clicking buttons, filling forms, navigating browsers, and reading screen content - just as a human user would. It is available as a built-in tool in the Responses API and as a core feature of the Codex CLI.
| Capability | Example use case |
|---|---|
| Browser navigation | Research competitor products, scrape structured data, fill web forms |
| GUI interaction | Test desktop applications, automate legacy software with no API |
| Screen reading | Extract data from PDFs opened in viewers, read application states |
| Keyboard and mouse control | Any repetitive UI workflow |
| Multi-application workflows | Copy data from one app to another |
# Computer use via the Responses API: response = client.responses.create( model="gpt-5.4", # gpt-5.4 has strong computer use support tools=[{ "type": "computer_use_preview", "display_width": 1280, "display_height": 800, "environment": "browser", # or "desktop", "linux", "windows" }], input="Go to github.com/openai/codex, find all open issues labelled bug, and return a summary.", truncation="auto", ) # In Codex CLI - computer use is built into the tool automatically: # codex # > Open the browser and check if our staging deployment is up at staging.example.com # Codex will: open browser, navigate to URL, read the page, report status # Safety considerations: # 1. Sandbox environments recommended # 2. Require approval for form submissions, purchases, account changes # 3. Log all actions taken by the computer use agent
Approval modes and computer use: in Codex CLI, the full-access approval mode enables computer use with network access. The auto mode (workspace-scoped) limits computer use to the local workspace. For production use, always implement human-in-the-loop approval for actions that modify state or involve external services.
38. How do you use the OpenAI API for code generation, review, and debugging tasks?
Code-related tasks are among the most common and well-supported use cases in the OpenAI API. The following patterns apply across code generation, review, and debugging.
from openai import OpenAI client = OpenAI() # 1. Code generation with constraints: generated = client.responses.create( model="gpt-5.5", instructions="""You are a senior Python engineer. Always: - Add type hints - Write docstrings (Google style) - Include basic error handling - Add a usage example in if __name__ == "__main__" """, input="Write a function to parse a CSV file and return a list of dicts.", reasoning={"effort": "medium"}, ) # 2. Code review with structured output: from pydantic import BaseModel class Review(BaseModel): summary: str bugs: list[str] security_issues: list[str] performance_issues: list[str] suggested_improvements: list[str] severity: str # "clean" | "low" | "medium" | "high" | "critical" review = client.responses.create( model="gpt-5.5", input=f"Review this code:\n\n```python\n{code_to_review}\n```", text={"format": {"type": "json_schema", "json_schema": {"name": "review", "schema": Review.model_json_schema(), "strict": True}}}, ) result = Review.model_validate_json(review.output_text) # 3. Debugging: debug_response = client.responses.create( model="gpt-5.5", input=f"""Debug this code. I get this error:\n\n{error_traceback}\n\nCode:\n{code}\n\nExplain the root cause and provide a fix.""", reasoning={"effort": "high"}, ) # 4. Unit test generation: tests = client.responses.create( model="gpt-5.5", instructions="Generate comprehensive pytest tests. Include edge cases, error cases, and typical usage.", input=f"Generate tests for:\n\n{function_code}", tools=[{"type": "code_interpreter"}], # run tests to verify they pass )
Best practices for code tasks: be explicit about constraints in the system prompt (type hints, test framework, error handling style). Use structured outputs for code reviews to get machine-readable results. Use reasoning: effort: high for debugging complex issues. Use code_interpreter to actually run and verify generated code.
39. What is the role of system prompts (instructions) in OpenAI applications and how do you design them effectively?
The system prompt (called instructions in the Responses API, system in Chat Completions) sets the model's persona, behaviour, constraints, and context for the entire conversation. It is the primary lever for customising model behaviour without fine-tuning.
# Chat Completions system prompt: response = client.chat.completions.create( model="gpt-5.5", messages=[ { "role": "system", "content": "You are an expert Python engineer...", # system message }, {"role": "user", "content": "Write a web scraper."}, ] ) # Responses API instructions: response = client.responses.create( model="gpt-5.5", instructions="You are an expert Python engineer...", # top-level parameter input="Write a web scraper.", ) # Effective system prompt patterns: EFFECTIVE_SYSTEM_PROMPT = """ Role: You are an expert Python engineer at a fintech startup. Constraints: - Always use type hints and write Google-style docstrings - Prefer standard library over third-party when possible - Financial calculations must use Decimal, never float - Every function must have at least 2 unit tests Output format: - First, explain your approach in 2-3 sentences - Then provide the complete implementation - Finally, provide usage examples Do not: - Generate code you cannot verify is correct - Suggest experimental or deprecated libraries - Skip error handling for edge cases """
System prompt design principles:
- Be specific - vague instructions produce inconsistent results
- Include constraints - what NOT to do is as important as what to do
- Specify output format - tell the model exactly how to structure the response
- Give the model a role - "You are an expert X" sets context effectively
- Keep it stable - place system prompts at the start to maximise prompt caching
- Test iteratively - use evals to measure the impact of system prompt changes
40. How do you handle context window management in long-running OpenAI applications?
Every OpenAI model has a finite context window - the maximum tokens (input + output) it can process in one call. In long-running applications (chat sessions, agentic workflows, document analysis), managing this window efficiently is critical for both functionality and cost.
from openai import OpenAI import tiktoken client = OpenAI() enc = tiktoken.encoding_for_model("gpt-5.5") # Context window strategy 1: Sliding window # Keep the most recent N turns, discarding the oldest def sliding_window(messages: list, max_tokens: int = 100_000) -> list: total = sum(len(enc.encode(str(m["content"]))) for m in messages) while total > max_tokens and len(messages) > 2: # Remove oldest user+assistant pair (keep system message) removed = messages.pop(1) total -= len(enc.encode(str(removed["content"]))) return messages # Context window strategy 2: Summarisation # Summarise old conversation instead of dropping it entirely async def summarise_history(messages: list[dict]) -> str: summary = await client.responses.create( model="gpt-5.4-mini", # cheap model for summarisation input=f"Summarise this conversation concisely:\n{messages}", ) return summary.output_text # Strategy 3: Responses API state management (avoids manual history) # Use previous_response_id - OpenAI manages the context server-side first = client.responses.create(model="gpt-5.5", input="Hello!", store=True) second = client.responses.create( model="gpt-5.5", input="What did I just say?", previous_response_id=first.id, # server retrieves context automatically ) # Strategy 4: use file_search for large static documents # Instead of pasting 100k-token documents into every prompt: # Upload once to a vector store, retrieve only relevant chunks vector_store_id = "vs_abc123" response = client.responses.create( model="gpt-5.5", tools=[{"type": "file_search", "vector_store_ids": [vector_store_id]}], input="What does section 4.2 of our API spec say about authentication?", # Only the relevant section is retrieved, not the entire doc )
| Strategy | Best for | Trade-off |
|---|---|---|
| Sliding window | Conversational UIs | May lose important early context |
| Summarisation | Long research sessions | Adds latency and cost for summariser call |
| previous_response_id | Responses API multi-turn | Requires store:true; server manages context |
| RAG / file_search | Large static documents | Retrieval may miss nuanced context |
