OpenAI Assistants API

Medium 25 min read

Assistants Overview

Why OpenAI Assistants API Matters

The Problem: Building stateful AI assistants requires managing conversation history, file storage, tool execution, and run lifecycle -- all complex infrastructure concerns.

The Solution: The Assistants API provides a managed, stateful agent platform with persistent threads, built-in tools (code interpreter, file search), and automatic conversation management.

Real Impact: The Assistants API powers thousands of production applications from customer support bots to code analysis tools, with OpenAI managing the infrastructure.

Real-World Analogy

Think of the Assistants API as a corporate help desk system:

  • Assistant = A trained help desk agent with specific expertise
  • Thread = A support ticket that tracks the entire conversation
  • Messages = Individual exchanges within the ticket
  • Run = The agent actively working on the ticket
  • Tools = Software the agent uses (code runner, file search, databases)

Core Assistants Concepts

Assistants

Persistent AI entities with instructions, model configuration, and tool access. Created once and reused across conversations.

Threads

Conversation sessions that store message history. OpenAI manages context windows and message truncation automatically.

Code Interpreter

Built-in sandboxed Python execution environment for data analysis, math, file generation, and visualization.

File Search

Automatic RAG over uploaded documents using vector embeddings, with chunk retrieval and citation support.

Threads & Messages

Assistants API Flow: Thread to Run to Steps to Response
Thread Messages Run Processing Step: Think Step: Tool Call Step: Respond Response + Citations
assistants_basic.py
from openai import OpenAI

client = OpenAI()

# Create an assistant
assistant = client.beta.assistants.create(
    name="Data Analyst",
    instructions="You are a data analyst. Analyze data and create visualizations.",
    model="gpt-4-turbo",
    tools=[
        {"type": "code_interpreter"},
        {"type": "file_search"},
    ],
)

# Create a thread
thread = client.beta.threads.create()

# Add a message
client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Analyze this CSV and create a chart of sales by month",
)

# Create a run
run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant.id,
)

# Get the response
if run.status == "completed":
    messages = client.beta.threads.messages.list(thread_id=thread.id)
    for msg in messages.data:
        if msg.role == "assistant":
            print(msg.content[0].text.value)

Built-in Tools

Available Tools

  • Code Interpreter: Sandboxed Python for data analysis, math, charts, and file generation
  • File Search: Vector-based search over uploaded documents with automatic chunking
  • Function Calling: Custom functions you define that the assistant can invoke

File Handling

file_handling.py
# Upload a file for code interpreter
file = client.files.create(
    file=open("sales_data.csv", "rb"),
    purpose="assistants",
)

# Attach file to message
client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Analyze this sales data",
    attachments=[{
        "file_id": file.id,
        "tools": [{"type": "code_interpreter"}],
    }],
)

# Create vector store for file search
vector_store = client.beta.vector_stores.create(name="knowledge_base")
client.beta.vector_stores.files.create(
    vector_store_id=vector_store.id,
    file_id=file.id,
)

Runs & Steps

Common Pitfall

Problem: Runs get stuck in "requires_action" status because function call outputs are not submitted.

Solution: Always check for run.status == "requires_action" and submit tool outputs using client.beta.threads.runs.submit_tool_outputs(). Use create_and_poll() for simpler cases.

Quick Reference

FunctionDescriptionExample
assistants.create()Create assistantclient.beta.assistants.create(...)
threads.create()Create threadclient.beta.threads.create()
messages.create()Add messageclient.beta.threads.messages.create(...)
runs.create_and_poll()Run and waitclient.beta.threads.runs.create_and_poll(...)
messages.list()Get messagesclient.beta.threads.messages.list(thread_id)
files.create()Upload fileclient.files.create(file=f, purpose="assistants")
submit_tool_outputs()Return function resultsruns.submit_tool_outputs(run_id=..., tool_outputs=[...])