Tilstandsbehandling på tvers av kjøringstrinn
Bevar variabler, dataframes og importerte biblioteker på tvers av flere kodekjøringstrinn, slik at agenten kan bygge videre på tidligere resultater uten å kjøre tidligere beregninger på nytt.
Tilstandsbehandling på tvers av kjøringstrinn er en gratis leksjon i AI Engineering Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i AI Engineering Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
Problemet med tilstandsløshet
Hver kjøring av en Docker-container starter med en ny Python-tolk. Variabler som ble definert i iterasjon 1, finnes ikke i iterasjon 2. Denne tilstandsløsheten tvinger agenten til å beregne eller laste inn alt på nytt fra grunnen av i hvert kjøringssteg – med mindre De implementerer en eksplisitt strategi for tilstandshåndtering som lagrer og gjenoppretter tilstanden på tvers av iterasjoner. Uten dette er analyser i flere steg umulige.
# 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!Filbasert lagring av tilstand
Den enkleste og mest portable fremgangsmåten er å lagre tilstanden i filer. På slutten av hver kodeblokk lagrer agenten DataFrames, ordbøker eller andre objekter i filer i arbeidsområdekatalogen. Den neste iterasjonen laster dem inn igjen. Parquet er ideelt for DataFrames, JSON for ordbøker og pickle for vilkårlige Python-objekter (selv om pickle fra uklarert kode utgjør en sikkerhetsrisiko).
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)Lær agenten filbasert tilstand
De kan ikke bare implementere filbasert tilstand i infrastrukturen – LLM-en må også kjenne til konvensjonen og bruke den konsekvent. Ta med eksplisitte instruksjoner i systemprompten: Når et resultat som skal brukes senere, er beregnet, skal det alltid lagres med et beskrivende filnavn, og ved starten av hver iterasjon skal filene som ble produsert i tidligere steg, alltid lastes inn før arbeidet fortsetter.
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/'))
'''Kjernebasert tilstand med vedvarende Python-prosesser
Et alternativ til filbasert tilstand er å holde en vedvarende Python-prosess (for eksempel en Jupyter-kjerne) kjørende mellom iterasjonene og legge hver kodeblokk inn i den med exec(). Variabler som defineres i én iterasjon, forblir tilgjengelige i den neste. Denne fremgangsmåten er raskere og mer naturlig, men krever at det kjøres én vedvarende prosess per agentøkt i stedet for midlertidige containere.
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()Håndtering av tilstand med et tilstandsobjekt
På orkestreringslaget for agenten (utenfor sandkassen) bør De vedlikeholde et eksplisitt tilstandsobjekt som holder oversikt over gjeldende status for agentens arbeid: hvilke filer som er opprettet, hva som er beregnet, hvilket steg agenten er på, og hva det endelige målet er. Send et sammendrag av dette tilstandsobjektet til LLM-en i hver iterasjon, slik at den alltid vet hvor den befinner seg i den overordnede oppgaven.
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 += 1Sette inn tilstandskontekst i prompter
Hver gang De kaller LLM-en for den neste kodeblokken, skal De sette inn den gjeldende tilstandskonteksten i brukermeldingen. Dette gir LLM-en nøyaktig informasjon om hvilke filer som er tilgjengelige, hva som er beregnet, og hva som gjenstår. Uten denne konteksten kan LLM-en forsøke å opprette filer som allerede finnes, eller hoppe over steg som allerede er fullført.
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)Håndtering av store mellomliggende data
Dataanalyseagenter produserer ofte store mellomliggende datasett som er kostbare å laste inn på nytt i hver iterasjon. Bruk lat innlasting: last bare inn dataene De trenger for det gjeldende steget. Bruk kolonneorienterte formater som Parquet, som støtter effektiv lesing av utvalgte kolonner. For virkelig store datasett (100 MB eller mer) bør De beholde en vedvarende kjerne, slik at DataFrame-et forblir i minnet på tvers av iterasjoner i stedet for å serialiseres og deserialiseres hver gang.
# 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 accordinglyKontrollpunkter for langvarige oppgaver
For oppgaver som går over mange iterasjoner bør De implementere kontrollpunkter: Lagre hele agenttilstanden (fullførte steg, filer i arbeidsområdet og gjeldende fremdrift) med jevne mellomrom i et varig lager, slik at oppgaven kan gjenopptas etter et avbrudd. Dette er spesielt viktig for langvarige dataanalysejobber som kan ta 30 minutter eller mer, og som kan bli avbrutt av nettverksproblemer, API-feil eller omstarter av serveren.
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 stateRydding av tilstand etter fullføring
Agentens arbeidsområder samler opp filer og kan vokse seg store over tid. Implementer alltid en oppryddingsfase som kjører når en oppgave fullføres eller mislykkes: slett mellomliggende filer (cleaned.parquet, tmp_output.csv), og behold bare de endelige utdatafilene brukeren trenger. For skylagring bør De angi livssykluspolicyer som automatisk sletter filer i arbeidsområdet etter en oppbevaringsperiode.
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]Versjonering av tilstand for feilsøking
Når en kodeagent produserer feil resultater, må De spore gjennom kjøringshistorikken for å finne ut hvor det gikk galt. Implementer tilstandsversjonering ved å lagre et øyeblikksbilde av arbeidsområdet etter hver iterasjon. Da kan De spille av agentens kjøring på nytt, undersøke mellomliggende tilstander og identifisere nøyaktig hvilken iterasjon feilen oppstod i. Lagre bare diff-en (endrede filer) for å spare plass.
Kontekstvindu kontra ekstern tilstand
Utformingen av kodeagenter innebærer en grunnleggende avveining mellom å legge tilstanden i LLM-ens kontekstvindu (umiddelbart, men begrenset) og i ekstern lagring (ubegrenset, men krever eksplisitt håndtering). Den optimale strategien er å beholde dataene for det gjeldende steget i konteksten, store mellomliggende resultater i filer, oppgavemålet og planen på høyt nivå i konteksten, og rådata permanent på disken. LLM-en håndterer oppgaven; filsystemet håndterer dataene.
Hurtigsjekk
Test forståelsen Deres av tilstandshåndtering på tvers av kodekjøringssteg fra denne leksjonen.
Oppsummering av leksjonen
I denne leksjonen har De lært at filbasert lagring av tilstand med Parquet og JSON er den mest portable måten å dele tilstand mellom kjøringer av midlertidige containere på, at vedvarende kjerner eliminerer kostnadene ved å laste inn data på nytt ved å beholde en aktiv Python-prosess på tvers av iterasjoner, og at innsetting av tilstandskontekst gir LLM-en nøyaktig kunnskap om tilgjengelige filer og fullførte steg i hver iterasjon. Neste tema er å bygge en komplett dataanalyseagent.
Lær deg Python med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 30
- Leksjoner
- 120
Ofte stilte spørsmål
Er leksjonen «Tilstandsbehandling på tvers av kjøringstrinn» gratis?
Ja – hele teksten i «Tilstandsbehandling på tvers av kjøringstrinn» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av AI Engineering Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «Tilstandsbehandling på tvers av kjøringstrinn»?
Bevar variabler, dataframes og importerte biblioteker på tvers av flere kodekjøringstrinn, slik at agenten kan bygge videre på tidligere resultater uten å kjøre tidligere beregninger på nytt. Du øver på AI Engineering Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med AI Engineering Academy?
Ingen tidligere erfaring er nødvendig. AI Engineering Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.
Hvor lang tid tar leksjonen «Tilstandsbehandling på tvers av kjøringstrinn»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne AI Engineering Academy-leksjonen?
Ja. Alle AI Engineering Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Kodekjøringssløyfen
- Sandkassing med Docker og RestrictedPython
- Tilstandsbehandling på tvers av kjøringstrinn
- Bygge en dataanalyseagent