0Pricing
AI Engineering Academy · Lektion

Zustandsverwaltung über mehrere Ausführungsschritte hinweg

Speichern Sie Variablen, DataFrames und importierte Bibliotheken über mehrere Code-Ausführungsschritte hinweg, damit der Agent auf früheren Ergebnissen aufbauen kann, ohne frühere Berechnungen erneut auszuführen.

Zustandsverwaltung über mehrere Ausführungsschritte hinweg ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Das Problem der Zustandslosigkeit

Jede Ausführung eines Docker-Containers startet mit einem neuen Python-Interpreter. In Iteration 1 definierte Variablen existieren in Iteration 2 nicht. Diese Zustandslosigkeit zwingt den Agenten, bei jedem Ausführungsschritt alles von Grund auf neu zu berechnen oder zu laden – es sei denn, Sie implementieren eine ausdrückliche Strategie zur Zustandsverwaltung, die den Zustand über mehrere Iterationen hinweg speichert und wiederherstellt. Ohne eine solche Strategie sind mehrstufige Analysen unmöglich.

# Iteration 1 - works fine
df = pd.read_csv('data.csv')  # df is in memory
df_cleaned = df.dropna()
print('Rows after cleaning:', len(df_cleaned))

# Iteration 2 - NEW container, df_cleaned is GONE
result = df_cleaned.groupby('category').sum()  # NameError: df_cleaned is not defined
print(result)  # This will fail!

Dateibasierte Persistenz des Zustands

Der einfachste und portabelste Ansatz besteht darin, den Zustand in Dateien zu speichern. Am Ende jedes Codeblocks speichert der Agent DataFrames, Dictionaries oder andere Objekte in Dateien im Workspace-Verzeichnis. In der nächsten Iteration lädt er sie wieder. Parquet eignet sich ideal für DataFrames, JSON für Dictionaries und pickle für beliebige Python-Objekte (wobei pickle aus nicht vertrauenswürdigem Code ein Sicherheitsrisiko darstellt).

import pandas as pd
import json
from pathlib import Path

WORKSPACE = Path('/workspace')

# Iteration 1: process and SAVE
df = pd.read_csv(WORKSPACE / 'raw_data.csv')
df_cleaned = df.dropna().reset_index(drop=True)
df_cleaned.to_parquet(WORKSPACE / 'cleaned.parquet')  # save for next iteration

stats = {'rows': len(df_cleaned), 'columns': list(df_cleaned.columns)}
with open(WORKSPACE / 'stats.json', 'w') as f:
    json.dump(stats, f)

print('Saved cleaned data:', len(df_cleaned), 'rows')

# Iteration 2: LOAD and continue
df_cleaned = pd.read_parquet(WORKSPACE / 'cleaned.parquet')  # restore state
with open(WORKSPACE / 'stats.json') as f:
    stats = json.load(f)
result = df_cleaned.groupby('category')['value'].sum()
print(result)

Dem Agenten dateibasierte Zustände beibringen

Sie können dateibasierte Zustände nicht einfach nur in Ihrer Infrastruktur implementieren – auch das LLM muss die Konvention kennen und konsequent anwenden. Nehmen Sie ausdrückliche Anweisungen in den System-Prompt auf: Nach der Berechnung eines Ergebnisses, das später benötigt wird, soll es immer unter einem aussagekräftigen Dateinamen gespeichert werden. Zu Beginn jeder Iteration sollen außerdem immer die in vorherigen Schritten erzeugten Dateien geladen werden, bevor die Verarbeitung fortgesetzt wird.

STATE_MANAGEMENT_INSTRUCTIONS = '''
State persistence rules:
- You have a persistent workspace at /workspace/
- After computing any result you will need later, SAVE it to /workspace/
  - DataFrames: use .to_parquet('/workspace/name.parquet')
  - Dicts/lists: use json.dump to /workspace/name.json
  - Text: write to /workspace/name.txt
- At the start of each code block, LOAD the files you need from previous steps
- Use clear, descriptive filenames like 'cleaned_data.parquet', not 'tmp1.parquet'
- When listing files, use: import os; print(os.listdir('/workspace/'))
'''

Kernelbasierter Zustand mit persistenten Python-Prozessen

Eine Alternative zu dateibasierten Zuständen besteht darin, einen persistenten Python-Prozess (wie einen Jupyter-Kernel) zwischen den Iterationen weiterlaufen zu lassen und jeden Codeblock mit exec() darin auszuführen. In einer Iteration definierte Variablen bleiben in der nächsten zugänglich. Dieser Ansatz ist schneller und natürlicher, erfordert jedoch einen persistenten Prozess pro Agent-Sitzung statt kurzlebiger Container.

import jupyter_client

class PersistentKernel:
    def __init__(self):
        km, self.kc = jupyter_client.manager.start_new_kernel(kernel_name='python3')
        self.kc.wait_for_ready(timeout=30)
        print('Kernel started')

    def execute(self, code: str, timeout=60) -> tuple[str, str]:
        msg_id = self.kc.execute(code)
        outputs, errors = [], []
        
        while True:
            msg = self.kc.get_iopub_msg(timeout=timeout)
            if msg['msg_type'] == 'stream':
                if msg['content']['name'] == 'stdout':
                    outputs.append(msg['content']['text'])
                else:
                    errors.append(msg['content']['text'])
            if msg['msg_type'] == 'status' and msg['content']['execution_state'] == 'idle':
                break
        
        return ''.join(outputs), ''.join(errors)

    def shutdown(self):
        self.kc.shutdown()

# Variables persist across execute() calls!
kernel = PersistentKernel()
kernel.execute('x = 42')  # x is now defined in kernel
output, _ = kernel.execute('print(x)')  # prints 42 - state persists!
kernel.shutdown()

Zustandsverwaltung mit einem Zustandsobjekt

Halten Sie für die Orchestrierungsschicht des Agenten (außerhalb der Sandbox) ein ausdrückliches Zustandsobjekt vor, das den aktuellen Status der Arbeit des Agenten erfasst: welche Dateien erstellt wurden, was berechnet wurde, bei welchem Schritt sich der Agent befindet und welches Endziel verfolgt wird. Übergeben Sie dem LLM in jeder Iteration eine Zusammenfassung dieses Zustandsobjekts, damit es stets weiß, an welcher Stelle der Gesamtaufgabe es sich befindet.

from dataclasses import dataclass, field
from typing import Any

@dataclass
class ExecutionState:
    task: str
    iteration: int = 0
    workspace_files: list[str] = field(default_factory=list)
    computed_values: dict[str, Any] = field(default_factory=dict)
    completed_steps: list[str] = field(default_factory=list)
    last_output: str = ''

    def to_context_summary(self) -> str:
        return f'''Current task: {self.task}
Iteration: {self.iteration}
Completed steps: {', '.join(self.completed_steps) or 'None yet'}
Workspace files: {', '.join(self.workspace_files) or 'None yet'}
Key values: {self.computed_values}
Last output: {self.last_output[:500]}'''

    def after_execution(self, output: str, step_name: str):
        import os
        self.workspace_files = os.listdir('/workspace')
        self.completed_steps.append(step_name)
        self.last_output = output
        self.iteration += 1

Zustandskontext in Prompts einfügen

Fügen Sie jedes Mal, wenn Sie das LLM für den nächsten Codeblock aufrufen, den aktuellen Zustandskontext in die Benutzernachricht ein. Dadurch erhält das LLM genaue Informationen darüber, welche Dateien verfügbar sind, was bereits berechnet wurde und was noch erledigt werden muss. Ohne diesen Kontext versucht das LLM möglicherweise, bereits vorhandene Dateien neu zu erstellen, oder überspringt Schritte, die schon abgeschlossen sind.

def build_iteration_prompt(task: str, state: ExecutionState, last_observation: str) -> str:
    return f'''ORIGINAL TASK: {task}

CURRENT STATE:
{state.to_context_summary()}

LAST EXECUTION OUTPUT:
{last_observation}

What is the next step? Write Python code to continue. 
Remember:
- Load data from workspace files if needed
- Save any results you will need in future steps
- If the task is complete, say TASK COMPLETE and summarize the result'''

# Use in the main loop
for step_num in range(max_iterations):
    context = build_iteration_prompt(task, state, last_observation)
    response = llm.complete(messages + [{'role': 'user', 'content': context}])
    code = extract_code_block(response)
    if not code:
        break  # done
    output, err = execute_in_sandbox(code)
    state.after_execution(output, step_name=f'step_{step_num}')
    last_observation = format_observation(output, err)

Umgang mit großen Zwischendaten

Agenten für Datenanalysen erzeugen häufig große Zwischendatensätze, deren erneutes Laden in jeder Iteration kostspielig ist. Wenden Sie Lazy Loading an: Laden Sie nur die Daten, die Sie für den aktuellen Schritt benötigen. Verwenden Sie spaltenbasierte Formate wie Parquet, die effizientes Lesen ausgewählter Spalten unterstützen. Bei wirklich großen Datensätzen (ab 100 MB) sollten Sie einen persistenten Kernel verwenden, damit der DataFrame über mehrere Iterationen hinweg im Speicher bleibt, anstatt ihn jedes Mal zu serialisieren und zu deserialisieren.

# Good: load only needed columns
df = pd.read_parquet('/workspace/full_data.parquet', columns=['date', 'revenue', 'region'])

# Bad: load everything even if you only need 2 columns
# df = pd.read_parquet('/workspace/full_data.parquet')  # loads 50 columns you don't need

# Good: filter early before loading full dataset
df = pd.read_parquet('/workspace/full_data.parquet', filters=[('region', '=', 'EMEA')])

# For very large files, tell the LLM about data shape upfront
df_info = {'shape': (1_000_000, 50), 'size_mb': 850, 'columns': [...]}
# Include df_info in state so LLM plans accordingly

Checkpointing für lang laufende Aufgaben

Implementieren Sie für Aufgaben, die sich über viele Iterationen erstrecken, Checkpointing: Speichern Sie den vollständigen Zustand des Agenten (abgeschlossene Schritte, Workspace-Dateien und aktuellen Fortschritt) regelmäßig in einem dauerhaften Speicher, damit die Aufgabe nach einer Unterbrechung fortgesetzt werden kann. Dies ist besonders für lang laufende Datenanalyseaufträge wichtig, die 30 Minuten oder länger dauern können und durch Netzwerkprobleme, API-Fehler oder Neustarts des Servers unterbrochen werden könnten.

import json
import time

def checkpoint_state(state: ExecutionState, checkpoint_id: str, db):
    data = {
        'task': state.task,
        'iteration': state.iteration,
        'completed_steps': state.completed_steps,
        'workspace_files': state.workspace_files,
        'timestamp': time.time()
    }
    db.execute(
        'INSERT INTO agent_checkpoints (id, state) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET state=excluded.state',
        (checkpoint_id, json.dumps(data))
    )
    print(f'Checkpoint saved at iteration {state.iteration}')

def resume_from_checkpoint(checkpoint_id: str, db) -> ExecutionState | None:
    row = db.execute('SELECT state FROM agent_checkpoints WHERE id = ?', (checkpoint_id,)).fetchone()
    if not row:
        return None
    data = json.loads(row[0])
    state = ExecutionState(task=data['task'])
    state.iteration = data['iteration']
    state.completed_steps = data['completed_steps']
    print(f'Resumed from iteration {state.iteration}')
    return state

Zustand nach Abschluss bereinigen

In den Workspaces von Agenten sammeln sich Dateien an, sodass sie mit der Zeit sehr groß werden können. Implementieren Sie immer eine Bereinigungsphase, die bei erfolgreichem Abschluss oder Fehlschlagen einer Aufgabe ausgeführt wird: Löschen Sie Zwischendateien (cleaned.parquet, tmp_output.csv) und behalten Sie nur die finalen Ausgabedateien, die für den Benutzer relevant sind. Legen Sie für Cloud-Speicher Lifecycle-Richtlinien fest, die Workspace-Dateien nach Ablauf einer Aufbewahrungsfrist automatisch löschen.

import shutil
from pathlib import Path

INTERMEDIATE_PATTERNS = ['*.parquet', 'tmp_*.csv', 'step_*.json', 'debug_*.txt']
FINAL_OUTPUT_PATTERNS = ['report.pdf', 'final_*.csv', 'summary.json']

def cleanup_workspace(workspace_dir: str, keep_final=True):
    workspace = Path(workspace_dir)
    final_outputs = []
    
    if keep_final:
        for pattern in FINAL_OUTPUT_PATTERNS:
            final_outputs.extend(workspace.glob(pattern))
        # Move final outputs to output directory
        output_dir = workspace.parent / 'outputs'
        output_dir.mkdir(exist_ok=True)
        for f in final_outputs:
            shutil.move(str(f), str(output_dir / f.name))
    
    # Delete the workspace
    shutil.rmtree(workspace_dir)
    print(f'Workspace cleaned up. Kept {len(final_outputs)} output files.')
    return [str(f) for f in final_outputs]

Zustandsversionierung zur Fehlersuche

Wenn ein Code-Agent falsche Ergebnisse erzeugt, müssen Sie seine Ausführungshistorie zurückverfolgen, um die Fehlerstelle zu finden. Implementieren Sie eine Zustandsversionierung, indem Sie nach jeder Iteration einen Snapshot des Workspace speichern. So können Sie die Ausführung des Agenten wiedergeben, Zwischenzustände untersuchen und die genaue Iteration identifizieren, in der der Fehler aufgetreten ist. Speichern Sie nur die Differenz (geänderte Dateien), um Speicherplatz zu sparen.

Kontextfenster und externer Zustand

Beim Entwurf von Code-Agenten besteht ein grundlegender Zielkonflikt zwischen der Ablage des Zustands im Kontextfenster des LLM (unmittelbar verfügbar, aber begrenzt) und in externem Speicher (unbegrenzt, aber mit explizitem Verwaltungsaufwand). Die optimale Strategie lautet: Bewahren Sie die Daten des aktuellen Schritts im Kontext auf, speichern Sie große Zwischenergebnisse in Dateien, halten Sie das Aufgabenziel und den übergeordneten Plan im Kontext und speichern Sie Rohdaten immer auf der Festplatte. Das LLM verwaltet die Aufgabe; das Dateisystem verwaltet die Daten.

Schnelltest

Testen Sie Ihr Verständnis der Zustandsverwaltung über mehrere Codeausführungsschritte hinweg aus dieser Lektion.

Zusammenfassung der Lektion

In dieser Lektion haben Sie gelernt: Die dateibasierte Zustandspersistenz mit Parquet und JSON ist die portabelste Möglichkeit, Zustände zwischen kurzlebigen Containerausführungen zu teilen; persistente Kernel vermeiden den Aufwand des erneuten Ladens, indem sie einen aktiven Python-Prozess über mehrere Iterationen hinweg beibehalten; und das Einfügen des Zustandskontexts gibt dem LLM in jeder Iteration genaue Informationen über verfügbare Dateien und abgeschlossene Schritte. Als Nächstes erstellen wir einen vollständigen Agenten für Datenanalysen.

Häufig gestellte Fragen

Ist die Lektion „Zustandsverwaltung über mehrere Ausführungsschritte hinweg“ kostenlos?

Ja — der vollständige Text von „Zustandsverwaltung über mehrere Ausführungsschritte hinweg“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Zustandsverwaltung über mehrere Ausführungsschritte hinweg“?

Speichern Sie Variablen, DataFrames und importierte Bibliotheken über mehrere Code-Ausführungsschritte hinweg, damit der Agent auf früheren Ergebnissen aufbauen kann, ohne frühere Berechnungen erneut… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Engineering Academy zu starten?

Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Zustandsverwaltung über mehrere Ausführungsschritte hinweg“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?

Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Die Code-Ausführungsschleife
  2. Sandboxing mit Docker und RestrictedPython
  3. Zustandsverwaltung über mehrere Ausführungsschritte hinweg
  4. Einen Datenanalyse-Agent entwickeln
← Zurück zu AI Engineering Academy