Gerenciamento de estado entre etapas de execução
Persista variáveis, quadros de dados e bibliotecas importadas entre várias etapas de execução de código para que o agente possa aproveitar resultados anteriores sem repetir cálculos já realizados.
Gerenciamento de estado entre etapas de execução é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.
O problema da ausência de estado
Cada execução de um contêiner Docker começa com um interpretador Python novo. As variáveis definidas na iteração 1 não existem na iteração 2. Essa ausência de estado obriga o agente a recalcular ou recarregar tudo do zero a cada etapa de execução — a menos que você implemente uma estratégia explícita de gerenciamento de estado para persistir e restaurar o estado entre as iterações. Sem isso, análises em várias etapas são impossíveis.
# 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!Persistência de estado baseada em arquivos
A abordagem mais simples e portátil é salvar o estado em arquivos. Ao final de cada bloco de código, o agente salva DataFrames, dicionários ou outros objetos em arquivos no diretório da área de trabalho. A iteração seguinte os carrega novamente. Parquet é ideal para DataFrames, JSON para dicionários e pickle para objetos Python arbitrários (embora pickle originado de código não confiável represente um risco de segurança).
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)Ensinando o agente a usar estado baseado em arquivos
Não basta implementar o estado baseado em arquivos na sua infraestrutura — o LLM também precisa conhecer a convenção e usá-la de forma consistente. Inclua instruções explícitas no prompt do sistema: depois de calcular um resultado que será necessário mais tarde, salve-o sempre com um nome de arquivo descritivo e, no início de cada iteração, carregue sempre os arquivos produzidos nas etapas anteriores antes de prosseguir.
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/'))
'''Estado baseado em kernel com processos Python persistentes
Uma alternativa ao estado baseado em arquivos é manter um processo Python persistente (como um kernel do Jupyter) em execução entre as iterações e inserir cada bloco de código nele com exec(). As variáveis definidas em uma iteração continuam acessíveis na seguinte. Essa abordagem é mais rápida e natural, mas exige a execução de um processo persistente por sessão de agente, em vez de contêineres efêmeros.
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()Gerenciando o estado com um objeto de estado
Na camada de orquestração do agente (fora do ambiente isolado), mantenha um objeto de estado explícito que acompanhe o status atual do trabalho do agente: quais arquivos foram criados, o que foi calculado, em qual etapa o agente está e qual é o objetivo final. Passe um resumo desse objeto de estado ao LLM em cada iteração para que ele sempre saiba em que ponto está da tarefa como um todo.
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 += 1Inserindo o contexto do estado nos prompts
Sempre que chamar o LLM para obter o próximo bloco de código, insira o contexto atual do estado na mensagem do usuário. Isso fornece ao LLM informações precisas sobre quais arquivos estão disponíveis, o que já foi calculado e o que ainda precisa ser feito. Sem esse contexto, o LLM pode tentar recriar arquivos que já existem ou ignorar etapas que já foram concluídas.
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)Gerenciando grandes volumes de dados intermediários
Agentes de análise de dados frequentemente produzem grandes conjuntos de dados intermediários que são dispendiosos de recarregar a cada iteração. Aplique o carregamento sob demanda: carregue apenas os dados necessários para a etapa atual. Use formatos colunares, como Parquet, que permitem leituras eficientes de colunas específicas. Para conjuntos de dados realmente grandes (100 MB ou mais), mantenha um kernel persistente para que o DataFrame permaneça na memória entre as iterações, em vez de ser serializado e desserializado a cada vez.
# 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 accordinglyCriando pontos de verificação para tarefas longas
Para tarefas que abrangem muitas iterações, implemente pontos de verificação: salve periodicamente todo o estado do agente (etapas concluídas, arquivos da área de trabalho e progresso atual) em um armazenamento durável, para que a tarefa possa ser retomada após uma interrupção. Isso é especialmente importante para tarefas longas de análise de dados, que podem levar mais de 30 minutos e ser interrompidas por problemas de rede, erros de API ou reinicializações do servidor.
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 stateLimpando o estado após a conclusão
As áreas de trabalho dos agentes acumulam arquivos e podem crescer muito com o tempo. Sempre implemente uma etapa de limpeza executada quando uma tarefa é concluída ou falha: exclua arquivos intermediários (cleaned.parquet, tmp_output.csv) e mantenha apenas os arquivos de resultado final relevantes para o usuário. No armazenamento em nuvem, defina políticas de ciclo de vida que excluam automaticamente os arquivos da área de trabalho após um período de retenção.
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]Versionamento do estado para depuração
Quando um agente de código produz resultados incorretos, é necessário rastrear seu histórico de execução para descobrir onde ocorreu o problema. Implemente o versionamento do estado salvando um instantâneo da área de trabalho após cada iteração. Isso permite reproduzir a execução do agente, inspecionar estados intermediários e identificar a iteração exata em que ocorreu o erro. Armazene apenas as diferenças (arquivos alterados) para economizar espaço.
Janela de contexto versus estado externo
Há uma tensão fundamental no design de agentes de código entre colocar o estado na janela de contexto do LLM (imediato, mas limitado) e no armazenamento externo (ilimitado, mas que exige gerenciamento explícito). A estratégia ideal é: manter no contexto os dados da etapa atual, manter os grandes resultados intermediários em arquivos, manter no contexto o objetivo da tarefa e o plano de alto nível e manter os dados brutos sempre no disco. O LLM gerencia a tarefa; o sistema de arquivos gerencia os dados.
Verificação rápida
Teste sua compreensão sobre o gerenciamento de estado entre etapas de execução de código apresentado nesta lição.
Recapitulação da lição
Nesta lição, você aprendeu que a persistência de estado baseada em arquivos, usando Parquet e JSON, é a forma mais portátil de compartilhar o estado entre execuções de contêineres efêmeros; que os kernels persistentes eliminam o custo de recarregamento ao manter um processo Python ativo entre as iterações; e que a inserção do contexto do estado fornece ao LLM informações precisas sobre os arquivos disponíveis e as etapas concluídas em cada iteração. A seguir, criaremos um agente completo de análise de dados.
Perguntas Frequentes
A aula “Gerenciamento de estado entre etapas de execução” é grátis?
Sim — o texto completo de “Gerenciamento de estado entre etapas de execução” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.
O que vou aprender em “Gerenciamento de estado entre etapas de execução”?
Persista variáveis, quadros de dados e bibliotecas importadas entre várias etapas de execução de código para que o agente possa aproveitar resultados anteriores sem repetir cálculos já realizados. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Engineering Academy?
Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Gerenciamento de estado entre etapas de execução”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Engineering Academy?
Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- O loop de execução de código
- Isolamento com Docker e RestrictedPython
- Gerenciamento de estado entre etapas de execução
- Criando um agente de análise de dados