Code Interpreter
Why a Language Model Needs a Real Interpreter
A language model, no matter how capable, does not actually execute arithmetic or logic when it generates text — it produces the next most plausible token given everything before it, which for a simple calculation usually produces the right answer, but for anything involving many steps, precise numerical computation, or manipulation of structured data (sorting a long list, computing a statistical measure, parsing and reshaping a CSV file), reasoning "in its head" as text generation becomes unreliable in a way that compounds with complexity. Code Interpreter is the platform's built-in answer to this: instead of asking the model to simulate what a computation would produce, it lets the model write actual code and have that code actually executed in a real sandboxed environment, with the genuine output fed back into the conversation.
This is a meaningfully different kind of built-in tool than web search or file search. Web search and file search both retrieve information; Code Interpreter performs computation, and the difference matters for the same reason a person doing long division on paper gets a more reliable answer than doing it purely from memory — the correctness comes from an actual mechanical process, not from confident recall.
Enabling Code Interpreter
response = client.responses.create(
model="gpt-5.6-terra",
input="I have a list of numbers: 45, 12, 78, 23, 91, 34, 67. What's the median, and how far is the largest number from the mean?",
tools=[{"type": "code_interpreter", "container": {"type": "auto"}}],
)
print(response.output_text)
Note: The exact tool configuration (the
containerfield and its accepted values) and which models support Code Interpreter can vary by SDK version. Confirm the current interface against your installed SDK version's documentation before relying on these specifics.
Given a request like this, the model doesn't attempt to compute the median and mean through text-generation "reasoning" alone — it writes a short piece of code that actually performs the calculation (using a real statistics library, most likely), that code actually runs in a sandboxed container the platform manages, and the genuine numerical output is what the model's final answer is based on. This is a strictly more reliable process for this kind of task than asking the model to compute it purely through generated text, since a real interpreter either produces the mathematically correct result or raises a real error — it cannot silently produce a plausible-sounding wrong number the way unaided text generation sometimes can.
Inspecting the Code That Actually Ran
response = client.responses.create(
model="gpt-5.6-terra",
input="Calculate the standard deviation of these values: 22, 35, 41, 18, 29, 33.",
tools=[{"type": "code_interpreter", "container": {"type": "auto"}}],
)
for item in response.output:
if item.type == "code_interpreter_call":
print("Code executed:")
print(item.code)
print("Output:")
print(item.outputs)
print(response.output_text)
Note: The exact structure of
code_interpreter_callitems (field names for the executed code and its output) can vary by SDK version. Confirm the current output shape against your installed SDK version's documentation.
Reviewing the actual code that ran, rather than only the model's final natural-language summary of the result, is worth doing routinely during development — it's a direct way to verify the model is solving the problem the way you expect (using the correct formula, the correct library, the correct interpretation of the input data) rather than trusting a plausible-sounding final answer without checking the process that produced it. This mirrors the general principle Unit 6 established for structured outputs: a result that looks right and a result that is verifiably right are different claims, and inspecting the underlying work is how the gap between them gets closed.
Working With Data Files
Code Interpreter's most practical use is analyzing an uploaded data file directly — computing statistics, filtering rows, generating a chart — since a file can be attached to the same request that enables the tool.
with open("quarterly_sales.csv", "rb") as f:
uploaded_file = client.files.create(file=f, purpose="user_data")
response = client.responses.create(
model="gpt-5.6-terra",
input=[{"role": "user", "content": [
{"type": "input_text", "text": "Which product category had the highest total sales in Q3? Show your work."},
{"type": "input_file", "file_id": uploaded_file.id},
]}],
tools=[{"type": "code_interpreter", "container": {"type": "auto", "file_ids": [uploaded_file.id]}}],
)
print(response.output_text)
This combines the Files API from Unit 7, Lesson 2 with Code Interpreter directly: the uploaded CSV is made available inside the code execution environment, letting the model write and run code that actually reads, parses, and aggregates the real file content — rather than trying to reason about a CSV's contents purely from a text description, which is unreliable for anything beyond a very small file, and which Unit 7 never attempted for exactly this reason. This pattern — attach a data file, ask a question that requires real computation over it, let Code Interpreter do the actual analysis — is the standard way to build a "let me analyze this spreadsheet for you" feature.
Generating and Retrieving Charts
Code Interpreter can also produce visual output — a chart or plot generated by real plotting code, which the response makes available as a file to download.
response = client.responses.create(
model="gpt-5.6-terra",
input=[{"role": "user", "content": [
{"type": "input_text", "text": "Create a bar chart showing total sales by category from this data."},
{"type": "input_file", "file_id": uploaded_file.id},
]}],
tools=[{"type": "code_interpreter", "container": {"type": "auto", "file_ids": [uploaded_file.id]}}],
)
for item in response.output:
if item.type == "code_interpreter_call":
for output_item in item.outputs:
if getattr(output_item, "type", None) == "image":
generated_file_id = output_item.file_id
file_content = client.files.content(generated_file_id)
with open("sales_by_category.png", "wb") as f:
f.write(file_content.read())
Note: The exact mechanism for retrieving a generated chart image (the output item's structure and the method for downloading file content) can vary by SDK version. Confirm the current interface against your installed SDK version's documentation.
The chart here is a genuine image produced by real plotting code actually executed against the real uploaded data — not a description of what a chart might look like, which a model attempting to describe a chart in words could never substitute for. Downloading the resulting image with client.files.content() and saving it to disk follows the same pattern Unit 7, Lesson 3 used for saving a generated image, since in both cases the underlying operation is "the platform produced a real image file, and your code needs to retrieve and persist it."
Multi-Step Analysis: The Model Can Iterate
A genuinely useful property of Code Interpreter is that the model can run code, see the actual output (including an error, if the code failed), and write follow-up code in response — an iterative debugging loop happening automatically within the tool, without requiring your own code to orchestrate the multi-round back-and-forth Unit 8, Lesson 3 built for custom function calls.
response = client.responses.create(
model="gpt-5.6-terra",
input=[{"role": "user", "content": [
{"type": "input_text", "text": "Find any rows in this dataset with missing values and tell me which columns are affected."},
{"type": "input_file", "file_id": uploaded_file.id},
]}],
tools=[{"type": "code_interpreter", "container": {"type": "auto", "file_ids": [uploaded_file.id]}}],
)
code_interpreter_calls = [item for item in response.output if item.type == "code_interpreter_call"]
print(f"Number of code execution steps: {len(code_interpreter_calls)}")
For a question requiring exploration (checking for missing data, trying one filtering approach and then refining it), code_interpreter_calls may contain more than one step — the model writing an initial piece of exploratory code, seeing its real output, and writing a follow-up based on what it actually found, all handled internally by the platform within a single client.responses.create() call. This is a meaningful difference from the explicit, application-code-driven loop Unit 8 required for custom functions: Code Interpreter's internal iteration doesn't require your own code to detect a "the model wants to try again" signal and manually re-invoke anything, though inspecting code_interpreter_calls afterward, as shown here, is still worth doing to understand how many steps the model actually needed.
Cost, Latency, and When to Reach for Code Interpreter
Like every built-in tool covered in this unit, Code Interpreter adds cost and latency beyond a plain text request — a real sandboxed environment has to be provisioned and code has to actually execute, which takes measurably longer than text generation alone. It is well suited to requests genuinely requiring computation or data manipulation (statistics, calculations across many data points, file parsing and aggregation, chart generation) and unnecessary for requests a model can answer reliably through ordinary reasoning (a simple arithmetic fact, a conceptual question, a request that doesn't touch any actual data). A useful heuristic: if verifying the model's answer by hand would require you to actually run a calculation or inspect real data rather than just checking whether the reasoning sounds right, that's a strong signal Code Interpreter is the appropriate tool for the request.
The Sandbox Is Isolated, and That's Deliberate
The environment Code Interpreter executes code in is a sandboxed container with no access to your own systems, network, or credentials — it can run the code the model writes and work with files explicitly provided to it, but it cannot reach an internal database, call an internal API, or access anything outside the specific files attached to the request. This is a deliberate safety boundary, not a limitation to work around: unlike a custom function (Unit 8) where you control exactly what a function can access, Code Interpreter's code is effectively written by the model itself, and running arbitrary model-written code against your real internal systems would be a significant, unnecessary risk. If a task genuinely requires touching your own systems (querying an internal database, calling an internal service), that calls for a custom function with a narrow, well-defined interface (Unit 8) rather than Code Interpreter, precisely because a custom function's implementation is code you wrote and control, while Code Interpreter's implementation is code the model wrote at request time.
Testing Code-Interpreter-Dependent Logic With Fakes
Following this unit's established pattern, code that processes a Code Interpreter response — counting execution steps, extracting generated file IDs — can be tested with fake response objects rather than a real sandboxed execution.
class FakeCodeOutput:
def __init__(self, output_type, file_id=None):
self.type = output_type
self.file_id = file_id
class FakeCodeInterpreterCall:
def __init__(self, code, outputs):
self.type = "code_interpreter_call"
self.code = code
self.outputs = outputs
class FakeResponse:
def __init__(self, output):
self.output = output
def extract_generated_image_ids(response) -> list[str]:
image_ids = []
for item in response.output:
if item.type != "code_interpreter_call":
continue
for output_item in item.outputs:
if output_item.type == "image":
image_ids.append(output_item.file_id)
return image_ids
def test_extract_generated_image_ids():
fake_response = FakeResponse(output=[
FakeCodeInterpreterCall(code="plt.bar(...)", outputs=[FakeCodeOutput("image", file_id="file-123")]),
])
result = extract_generated_image_ids(fake_response)
assert result == ["file-123"]
print("PASS: extract_generated_image_ids correctly pulls generated file IDs from a fake response")
test_extract_generated_image_ids()
This lets the file-retrieval logic itself be verified deterministically and without cost, reserving real Code Interpreter calls (which involve actually provisioning a sandbox and executing real code) for a smaller set of end-to-end tests confirming the model produces reasonable results against representative real data — the same tiered testing approach this course has applied to every other paid, non-deterministic API surface.
Common Mistakes
Asking the model to reason through a nontrivial calculation or data analysis in plain text without enabling Code Interpreter, relying on unaided text generation for a task that benefits directly from actual, verifiable code execution.
Trusting a final natural-language summary without reviewing the underlying executed code, missing an opportunity to catch a case where the code solved a subtly different problem than the one actually asked.
Enabling Code Interpreter for every request regardless of whether real computation is involved, adding unnecessary cost and latency to questions that don't need it.
Forgetting that a generated chart or output file must be explicitly retrieved and saved, rather than assuming it appears automatically somewhere outside the response object.
Best Practices
Reach for Code Interpreter specifically when a request requires genuine computation, data manipulation, or chart generation, rather than for requests a model can already answer reliably through ordinary reasoning.
Inspect the actual executed code during development, not just the final summary, to confirm the model solved the intended problem the intended way.
Combine Code Interpreter with the Files API when the task involves analyzing an uploaded data file, letting real code operate on the real file content rather than asking the model to reason about a file's contents from a text description alone.
Explicitly retrieve and save any generated output files (charts, processed data), following the same download-and-persist pattern established for other generated file types earlier in this course.