0Pricing
AI Agents · Lesson

Code Interpreter Pattern for Data Analysis

Sandboxed Python execution: running pandas/matplotlib in agent tools.

Code Interpreter Pattern for Data Analysis is a free AI Agents lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Agents learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Code Interpreter Pattern

The code interpreter pattern lets an agent generate Python code to answer data analysis questions, execute that code in a sandbox, capture the output, and interpret the results.

Instead of hardcoding every analysis operation, the agent writes custom code for each question — making it infinitely flexible for data tasks.

Core Loop: Generate → Execute → Interpret

The pattern has three steps that can repeat:

  1. Generate — LLM writes Python code to answer the question
  2. Execute — run the code in a sandbox, capture stdout and files
  3. Interpret — pass output back to LLM to explain the results
def code_interpreter_agent(question, data_path):
    # Step 1: Generate code
    code = generate_analysis_code(question, data_path)
    print('Generated code:', code[:200])

    # Step 2: Execute in sandbox
    result = execute_in_sandbox(code)

    if result['error']:
        # Try to fix the error
        fixed_code = fix_code(code, result['error'])
        result = execute_in_sandbox(fixed_code)

    # Step 3: Interpret output
    return interpret_output(question, result)

print(code_interpreter_agent(
    'What is the average order value by customer segment?',
    'data/orders.csv'
))

Code Generation Prompt

The code generation prompt must include: the data path/schema, the question, and constraints (no external APIs, use pandas, save charts to files).

CODE_GEN_PROMPT = """You are a Python data analyst. Write Python code to answer the question.
Data available at: {data_path}
Question: {question}
Write ONLY Python code (no markdown, no explanation):"""

def llm_call(prompt):
    return "```python\nprint('df.describe() results')\n```"

def generate_analysis_code(question, data_path):
    response = llm_call(CODE_GEN_PROMPT.format(question=question, data_path=data_path))
    code = response.strip()
    if code.startswith('```'):
        code = code.split('```')[1]
        if code.startswith('python'):
            code = code[6:]
    return code.strip()

print(generate_analysis_code('What is the average price?', 'data.csv'))

Subprocess Sandbox Execution

The simplest sandbox is running code in a separate subprocess with a timeout. This provides process isolation — if the code crashes, it doesn't take down the agent.

import subprocess
import tempfile
import os

def execute_in_sandbox(code, timeout=30):
    # Write code to temp file
    with tempfile.NamedTemporaryFile(suffix='.py', mode='w', delete=False) as f:
        f.write(code)
        script_path = f.name

    try:
        result = subprocess.run(
            ['python3', script_path],
            capture_output=True,
            text=True,
            timeout=timeout,
            env={**os.environ, 'MPLBACKEND': 'Agg'}  # non-interactive matplotlib
        )
        return {
            'stdout': result.stdout,
            'stderr': result.stderr,
            'returncode': result.returncode,
            'error': result.stderr if result.returncode != 0 else None
        }
    except subprocess.TimeoutExpired:
        return {'stdout': '', 'stderr': 'Timeout', 'returncode': -1, 'error': 'Code timed out'}
    finally:
        os.unlink(script_path)

if __name__ == '__main__':
    result = execute_in_sandbox('print(2 + 2)')
    print('Sandbox stdout:', result['stdout'].strip())
    print('Return code   :', result['returncode'])

E2B Cloud Sandbox

E2B provides a managed cloud sandbox for safe code execution — more secure than subprocess. It runs code in an isolated container with filesystem access.

Install with pip install e2b-code-interpreter.

from e2b_code_interpreter import Sandbox
import os

def execute_with_e2b(code, data_bytes=None):
    with Sandbox(api_key=os.getenv('E2B_API_KEY')) as sandbox:
        # Upload data file if provided
        if data_bytes:
            sandbox.files.write('/home/user/data.csv', data_bytes)

        # Execute code
        execution = sandbox.run_code(code)

        result = {
            'stdout': '\n'.join(execution.logs.stdout),
            'stderr': '\n'.join(execution.logs.stderr),
            'error': None
        }

        # Check for errors
        if execution.error:
            result['error'] = str(execution.error)

        # Download any generated files
        result['files'] = []
        for output in execution.results:
            if hasattr(output, 'png'):
                result['files'].append({
                    'type': 'image/png',
                    'data': output.png  # base64 encoded
                })

    return result

Capturing Generated Files

Code may generate charts, CSV exports, or other files. Capture these from the sandbox filesystem and pass them back to the agent for interpretation or display.

import os
import glob
import base64

OUTPUT_DIR = '/tmp/chart_output'

def execute_and_capture(code, timeout=30):
    # Create output dir
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    result = execute_in_sandbox(code, timeout=timeout)

    # Capture any generated image files
    generated_files = []
    for filepath in glob.glob(os.path.join(OUTPUT_DIR, '*.png')):
        with open(filepath, 'rb') as f:
            encoded = base64.b64encode(f.read()).decode('utf-8')
        generated_files.append({
            'filename': os.path.basename(filepath),
            'type': 'image/png',
            'base64': encoded
        })
        os.unlink(filepath)  # clean up

    result['generated_files'] = generated_files
    print(f'Captured {len(generated_files)} file(s) from sandbox')
    return result

Error Recovery Loop

Generated code often has bugs on the first run. Implement a recovery loop: send the error back to the LLM with the original code and ask for a fix. Limit to 2-3 retries.

FIX_PROMPT = '''The following Python code raised an error. Fix it.

Original code:
{code}

Error:
{error}

Return ONLY the fixed Python code (no explanation, no markdown):'''

def fix_code(code, error):
    return llm_call(FIX_PROMPT.format(code=code, error=error)).strip()

def execute_with_retry(code, max_retries=2):
    for attempt in range(max_retries + 1):
        result = execute_and_capture(code)
        if not result['error']:
            return result
        print(f'Attempt {attempt + 1} failed: {result["error"][:100]}')
        if attempt < max_retries:
            code = fix_code(code, result['error'])
    return result  # return last result even if errored

Interpreting Code Output

Raw code output (numbers, tables) needs to be translated back into a natural language answer. Pass the stdout to the LLM and ask it to explain the results in the context of the original question.

INTERPRET_PROMPT = '''A Python script was executed to answer a data analysis question.
Explain the results in clear, non-technical language.

Original question: {question}

Code output (stdout):
{output}

Provide a clear, concise answer that directly addresses the question.
Highlight the most important numbers or findings.
Answer:'''

def interpret_output(question, execution_result):
    stdout = execution_result.get('stdout', '').strip()
    error = execution_result.get('error')

    if error and not stdout:
        return f'The analysis failed with error: {error}'

    if not stdout:
        return 'The code ran successfully but produced no output.'

    return llm_call(INTERPRET_PROMPT.format(
        question=question,
        output=stdout[:3000]  # truncate very long outputs
    ))

Security Constraints in Code Generation

Generated code must not make network calls, access sensitive files, or execute system commands. Enforce this in both the prompt and with sandbox restrictions.

BLOCKED_IMPORTS = ['requests', 'httpx', 'urllib', 'socket', 'subprocess', 'os.system']

def pre_validate_code(code):
    errors = []
    for blocked in BLOCKED_IMPORTS:
        if f'import {blocked}' in code or f'from {blocked}' in code:
            errors.append(f'Blocked import: {blocked}')

    # Block shell execution
    import re
    if re.search(r'os\.system|subprocess\.run|subprocess\.call|eval\(|exec\(', code):
        errors.append('Blocked: shell execution or eval/exec')

    # Block reading outside allowed paths
    if re.search(r'open\([^)]*\.\./|open\([^)]*\/etc\/', code):
        errors.append('Blocked: unauthorized file access')

    if errors:
        raise ValueError('Security check failed:\n' + '\n'.join(errors))

    return True

if __name__ == '__main__':
    try:
        pre_validate_code('import requests\nrequests.get("http://x")')
    except ValueError as e:
        print('Rejected:', e)
    print('Safe code passed:', pre_validate_code('print(1 + 1)'))

Data Schema Injection

The LLM generates better code when it knows the data schema upfront — column names, types, and sample rows. Include a schema description in the code generation prompt.

import pandas as pd

def get_data_schema(data_path):
    df = pd.read_csv(data_path, nrows=5)
    schema_lines = []
    for col in df.columns:
        dtype = str(df[col].dtype)
        sample = df[col].dropna().iloc[0] if len(df[col].dropna()) > 0 else 'N/A'
        schema_lines.append(f'  - {col} ({dtype}): sample={sample!r}')
    schema_text = '\n'.join(schema_lines)
    return f'CSV columns:\n{schema_text}\nTotal rows: {len(pd.read_csv(data_path))}'

ENHANCED_PROMPT = CODE_GEN_PROMPT + '\n\nData schema:\n{schema}'

def generate_analysis_code_with_schema(question, data_path):
    schema = get_data_schema(data_path)
    response = llm_call(ENHANCED_PROMPT.format(
        question=question, data_path=data_path, schema=schema
    ))
    return response.strip()

Tracking Execution History

Keep a log of all code executions in a session. This lets the agent reference previous results, build on earlier computations, and explain its analysis steps to the user.

from datetime import datetime

execution_history = []

def record_execution(question, code, result):
    execution_history.append({
        'timestamp': datetime.now().isoformat(),
        'question': question,
        'code_lines': len(code.splitlines()),
        'stdout_preview': result.get('stdout', '')[:200],
        'success': result.get('error') is None,
        'generated_files': len(result.get('generated_files', []))
    })

def get_session_summary():
    total = len(execution_history)
    successful = sum(1 for e in execution_history if e['success'])
    return {
        'total_executions': total,
        'successful': successful,
        'failed': total - successful,
        'success_rate': f'{successful/max(total,1)*100:.0f}%',
        'questions_answered': [e['question'][:60] for e in execution_history]
    }

# Usage in agent loop
def code_interpreter_agent_tracked(question, data_path):
    code = generate_analysis_code_with_schema(question, data_path)
    result = execute_with_retry(code)
    record_execution(question, code, result)
    return interpret_output(question, result)

Knowledge Check

What is the main advantage of using the code interpreter pattern over hardcoding specific data analysis operations as agent tools?

Recap: Code Interpreter Pattern for Data Analysis

The code interpreter pattern: generate Python code (with schema context and security constraints) → execute in sandbox (subprocess or E2B) → capture stdout and filesretry on errorsinterpret results in natural language.

Key considerations: inject data schema for better code generation, pre-validate code for blocked imports and shell commands, use a subprocess timeout to prevent runaway execution, and capture generated charts as base64 for display.

Frequently asked questions

Is the “Code Interpreter Pattern for Data Analysis” lesson free?

Yes — the full text of “Code Interpreter Pattern for Data Analysis” is free to read here on the web, and the AI Agents course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Agents course, upgrade to CoddyKit PRO.

What will I learn in “Code Interpreter Pattern for Data Analysis”?

Sandboxed Python execution: running pandas/matplotlib in agent tools. You practise AI Agents with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start AI Agents?

No prior experience is required. AI Agents on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Code Interpreter Pattern for Data Analysis” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this AI Agents lesson?

Yes. Every AI Agents lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Code Interpreter Pattern for Data Analysis
  2. Pandas-Driven Data Agent Tools
  3. Automated Chart and Visualization Generation
  4. Statistical Summary Agents
← Back to AI Agents