mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-05 17:22:36 +00:00
## Summary
- Reverts `b0e2fda` ("fix(flow): add execution_id separate from state.id", COR-48): removes `Flow.execution_id` and points `current_flow_id` / `current_flow_request_id` back at `flow_id` (i.e. `state.id`). The separate per-run tracking id was no longer the right abstraction once `restore_from_state_id` reshapes how `state.id` is assigned;
- Adds an optional `restore_from_state_id` kwarg to `Flow.kickoff` / `Flow.kickoff_async` that hydrates state from a previously-persisted flow's latest snapshot
- Reassigns `state.id` to a fresh value (or `inputs["id"]` if pinned) so the new run's `@persist` writes don't extend the source's history
- Existing `inputs["id"]` resume, `@persist`, and `from_checkpoint` paths are unchanged
## Problem
`@persist` only supports *resume* today: `kickoff(inputs={"id": <uuid>})` hydrates state and continues writing under the same `flow_uuid`. There's no way to **fork** — hydrate from a snapshot but persist under a separate key, leaving the source's history intact. This PR adds that.
| | `state.id` after kickoff | `@persist` writes land under |
|---|---|---|
| `inputs["id"]` (resume) | supplied id | supplied id (extends history) |
| `restore_from_state_id` (fork) | fresh id, or `inputs["id"]` if pinned | new id (source preserved) |
## Behavior
| `inputs.id` | `restore_from_state_id` | Effect |
|---|---|---|
| — | — | Fresh kickoff |
| set | — | Existing resume |
| — | UUID | Fork — new `state.id`, hydrated from source |
| set | UUID | Fork into a pinned `state.id`, hydrated from source |
- Source not found → silent fallback (mirrors existing resume)
- Both `from_checkpoint` and `restore_from_state_id` set → `ValueError`
- `restore_from_state_id=None` → byte-identical to current main
## Design
Fork hydration runs before the existing `inputs` block in `kickoff_async`. On a hit, it calls the same `_restore_state` primitive used by resume, then overwrites `state.id` with a fresh UUID (or `inputs["id"]`). A `fork_succeeded` flag gates the existing `inputs["id"]` path so we don't double-load. `_completed_methods` / `_is_execution_resuming` are intentionally untouched — skip-completed-methods remains the territory of `apply_checkpoint` and `from_pending`.
## Test plan
- [ ] `pytest tests/test_flow_persistence.py` — 5 new tests (four-row matrix, not-found fallback, default no-op, conflict raise) + 6 existing as regression
- [ ] `pytest tests/test_flow.py` — broader flow suite
- [ ] Manual end-to-end against an HITL `@persist` flow
338 lines
13 KiB
Plaintext
338 lines
13 KiB
Plaintext
---
|
||
title: Dominando o Gerenciamento de Estado em Flows
|
||
description: Um guia abrangente sobre como gerenciar, persistir e utilizar o estado em CrewAI Flows para construir aplicações de IA robustas.
|
||
icon: diagram-project
|
||
mode: "wide"
|
||
---
|
||
|
||
## Entendendo o Poder do Estado em Flows
|
||
|
||
O gerenciamento de estado é a espinha dorsal de qualquer workflow de IA sofisticado. Nos Flows da CrewAI, o sistema de estado permite manter o contexto, compartilhar dados entre etapas e construir lógicas de aplicação complexas. Dominar o gerenciamento de estado é essencial para criar aplicações de IA confiáveis, sustentáveis e poderosas.
|
||
|
||
Este guia vai te levar por tudo o que você precisa saber sobre como gerenciar o estado em CrewAI Flows, desde conceitos básicos até técnicas avançadas, com exemplos práticos de código ao longo do conteúdo.
|
||
|
||
### Por Que o Gerenciamento de Estado Importa
|
||
|
||
Um gerenciamento de estado efetivo possibilita que você:
|
||
|
||
1. **Mantenha o contexto entre as etapas de execução** – Transfira informações de forma transparente entre diferentes estágios do seu workflow
|
||
2. **Construa lógicas condicionais complexas** – Tome decisões baseadas nos dados acumulados
|
||
3. **Crie aplicações persistentes** – Salve e recupere o progresso do workflow
|
||
4. **Trate erros de forma elegante** – Implemente padrões de recuperação para aplicações mais robustas
|
||
5. **Escalone suas aplicações** – Ofereça suporte a workflows complexos com organização apropriada dos dados
|
||
6. **Habilite aplicações conversacionais** – Armazene e acesse o histórico da conversa para interações de IA com contexto
|
||
|
||
Vamos explorar como aproveitar essas capacidades de forma eficiente.
|
||
|
||
## Fundamentos do Gerenciamento de Estado
|
||
|
||
### O Ciclo de Vida do Estado em um Flow
|
||
|
||
Nos Flows da CrewAI, o estado segue um ciclo de vida previsível:
|
||
|
||
1. **Inicialização** – Quando um flow é criado, seu estado é inicializado (como um dicionário vazio ou uma instância de modelo Pydantic)
|
||
2. **Modificação** – Os métodos do flow acessam e modificam o estado durante a execução
|
||
3. **Transmissão** – O estado é automaticamente passado entre os métodos do flow
|
||
4. **Persistência** (opcional) – O estado pode ser salvo em um armazenamento e recuperado posteriormente
|
||
5. **Conclusão** – O estado final reflete as mudanças acumuladas de todos os métodos executados
|
||
|
||
Compreender esse ciclo de vida é crucial para projetar flows eficientes.
|
||
|
||
### Duas Abordagens Para Gerenciar Estado
|
||
|
||
A CrewAI oferece duas maneiras para você gerenciar o estado nos seus flows:
|
||
|
||
1. **Estado Não Estruturado** – Usando objetos do tipo dicionário para mais flexibilidade
|
||
2. **Estado Estruturado** – Usando modelos Pydantic para segurança de tipo e validação
|
||
|
||
Vamos analisar cada abordagem em detalhe.
|
||
|
||
## Gerenciamento de Estado Não Estruturado
|
||
|
||
O estado não estruturado utiliza uma abordagem semelhante a dicionários, oferecendo flexibilidade e simplicidade para aplicações diretas.
|
||
|
||
### Como Funciona
|
||
|
||
Com estado não estruturado:
|
||
- Você acessa o estado via `self.state`, que se comporta como um dicionário
|
||
- Pode adicionar, modificar ou remover chaves livremente a qualquer momento
|
||
- Todo o estado está disponível automaticamente para todos os métodos do flow
|
||
|
||
### Exemplo Básico
|
||
|
||
Veja um exemplo simples de gerenciamento de estado não estruturado:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
### Quando Usar Estado Não Estruturado
|
||
|
||
O estado não estruturado é ideal para:
|
||
- Prototipagem rápida e flows simples
|
||
- Necessidade de estado que evolui dinamicamente
|
||
- Casos onde a estrutura pode não ser conhecida antecipadamente
|
||
- Flows com requisitos de estado simples
|
||
|
||
Embora seja flexível, o estado não estruturado não possui checagem de tipos nem validação de esquema, o que pode gerar erros em aplicações mais complexas.
|
||
|
||
## Gerenciamento de Estado Estruturado
|
||
|
||
O estado estruturado utiliza modelos Pydantic para definir um esquema para o estado do seu flow, provendo segurança de tipo, validação e melhor experiência de desenvolvimento.
|
||
|
||
### Como Funciona
|
||
|
||
Ao utilizar estado estruturado:
|
||
- Você define um modelo Pydantic que representa a estrutura do seu estado
|
||
- Passa este tipo de modelo para sua classe Flow como parâmetro de tipo
|
||
- Acessa o estado via `self.state`, que se comporta como uma instância do modelo Pydantic
|
||
- Todos os campos são validados de acordo com os tipos definidos
|
||
- O IDE oferece autocompletar e suporte à checagem de tipos
|
||
|
||
### Exemplo Básico
|
||
|
||
Veja como implementar o gerenciamento de estado estruturado:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
### Benefícios do Estado Estruturado
|
||
|
||
Utilizar estado estruturado traz várias vantagens:
|
||
|
||
1. **Segurança de Tipo** – Detecte erros de tipo durante o desenvolvimento
|
||
2. **Autodocumentação** – O modelo de estado documenta claramente quais dados estão disponíveis
|
||
3. **Validação** – Validação automática de tipos de dados e restrições
|
||
4. **Suporte do IDE** – Obtenha autocompletar e documentação inline
|
||
5. **Valores Padrão** – Defina facilmente valores padrões para falta de dados
|
||
|
||
### Quando Usar Estado Estruturado
|
||
|
||
O estado estruturado é recomendado para:
|
||
- Flows complexos com esquemas de dados bem definidos
|
||
- Projetos em equipe com múltiplos desenvolvedores no mesmo código
|
||
- Aplicações onde a validação de dados é importante
|
||
- Flows que precisam impor tipos de dados e restrições específicas
|
||
|
||
## O ID de Estado Automático
|
||
|
||
Tanto estados não estruturados quanto estruturados recebem automaticamente um identificador único (UUID) para ajudar a rastrear e gerenciar instâncias de estado.
|
||
|
||
### Como Funciona
|
||
|
||
- Para estado não estruturado, o ID é acessível via `self.state["id"]`
|
||
- Para estado estruturado, o ID é acessível via `self.state.id`
|
||
- Este ID é gerado automaticamente ao criar o flow
|
||
- O ID permanece igual durante todo o ciclo de vida do flow
|
||
- O ID pode ser usado para rastreamento, logs e recuperação de estados persistidos
|
||
|
||
Este UUID é útil especialmente ao implementar persistência ou monitorar múltiplas execuções de flows.
|
||
|
||
## Atualizações Dinâmicas de Estado
|
||
|
||
Independente de você usar estado estruturado ou não estruturado, é possível atualizar o estado dinamicamente ao longo da execução do flow.
|
||
|
||
### Passando Dados Entre Etapas
|
||
|
||
Métodos do flow podem retornar valores que serão passados como argumento para métodos listeners:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
Esse padrão permite combinar passagem de dados direta com atualizações de estado para obter máxima flexibilidade.
|
||
|
||
## Persistindo o Estado do Flow
|
||
|
||
Uma das funcionalidades mais poderosas da CrewAI é a habilidade de persistir o estado do flow entre execuções. Isso habilita workflows que podem ser pausados, retomados e até recuperados após falhas.
|
||
|
||
### O Decorador @persist()
|
||
|
||
O decorador `@persist()` automatiza a persistência de estado, salvando o estado do flow em pontos chave da execução.
|
||
|
||
#### Persistência em Nível de Classe
|
||
|
||
Ao aplicar em nível de classe, `@persist()` salva o estado após cada execução de método:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
#### Persistência em Nível de Método
|
||
|
||
Para mais controle, você pode aplicar `@persist()` em métodos específicos:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
#### Forking de Estado Persistido
|
||
|
||
`@persist` suporta dois modos distintos de hidratação em `kickoff` / `kickoff_async`. Use **resume** (`inputs["id"]`) para continuar a mesma linhagem; use **fork** (`restore_from_state_id`) para iniciar uma nova linhagem a partir de um snapshot:
|
||
|
||
| | `state.id` após o kickoff | Escritas do `@persist` vão para |
|
||
|---|---|---|
|
||
| `inputs["id"]` (resume) | id informado | id informado (estende o histórico) |
|
||
| `restore_from_state_id` (fork) | id novo, ou `inputs["id"]` se fixado | id novo (origem preservada) |
|
||
|
||
```python
|
||
from crewai.flow.flow import Flow, start
|
||
from crewai.flow.persistence import persist
|
||
from pydantic import BaseModel
|
||
|
||
class CounterState(BaseModel):
|
||
id: str = ""
|
||
counter: int = 0
|
||
|
||
@persist
|
||
class CounterFlow(Flow[CounterState]):
|
||
@start()
|
||
def step(self):
|
||
self.state.counter += 1
|
||
|
||
# Execução 1: estado novo, counter 0 -> 1
|
||
flow_1 = CounterFlow()
|
||
flow_1.kickoff()
|
||
|
||
# Fork: hidrata do snapshot mais recente de flow_1, mas escreve sob um state.id NOVO
|
||
flow_2 = CounterFlow()
|
||
flow_2.kickoff(restore_from_state_id=flow_1.state.id)
|
||
# flow_2 começa com counter=1 (hidratado), e step() incrementa para 2.
|
||
# O histórico do flow_uuid de flow_1 não é alterado.
|
||
```
|
||
|
||
Notas sobre o comportamento:
|
||
|
||
- `restore_from_state_id` não encontrado na persistência → o kickoff retorna silenciosamente ao comportamento padrão (espelha o comportamento de `inputs["id"]` quando não encontrado). Nenhuma exceção é lançada.
|
||
- Combinar `restore_from_state_id` com `from_checkpoint` lança um `ValueError` — eles miram sistemas de estado diferentes (`@persist` vs. Checkpointing) e não podem ser combinados.
|
||
- `restore_from_state_id=None` (padrão) é byte-idêntico a um kickoff sem o parâmetro.
|
||
- Fixar `inputs["id"]` durante o fork significa que a nova execução compartilha uma chave de persistência com outro flow — geralmente você quer apenas `restore_from_state_id`.
|
||
|
||
## Padrões Avançados de Estado
|
||
|
||
### Lógica Condicional Baseada no Estado
|
||
|
||
Você pode usar o estado para implementar lógicas condicionais complexas em seus flows:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
### Manipulações Complexas de Estado
|
||
|
||
Para transformar estados complexos, você pode criar métodos dedicados:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
Esse padrão de criar métodos auxiliares mantém seus métodos de flow limpos, enquanto permite manipulações complexas de estado.
|
||
|
||
## Gerenciamento de Estado com Crews
|
||
|
||
Um dos padrões mais poderosos na CrewAI é combinar o gerenciamento de estado do flow com a execução de crews.
|
||
|
||
### Passando Estado para Crews
|
||
|
||
Você pode usar o estado do flow para parametrizar crews:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
### Manipulando Saídas de Crews no Estado
|
||
|
||
Quando um crew finaliza, é possível processar sua saída e armazená-la no estado do flow:
|
||
|
||
```python
|
||
# código não traduzido
|
||
```
|
||
|
||
## Boas Práticas para Gerenciamento de Estado
|
||
|
||
### 1. Mantenha o Estado Focado
|
||
|
||
Projete seu estado para conter somente o necessário:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### 2. Use Estado Estruturado em Flows Complexos
|
||
|
||
À medida que seus flows evoluem em complexidade, o estado estruturado se torna cada vez mais valioso:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### 3. Documente Transições de Estado
|
||
|
||
Para flows complexos, documente como o estado muda ao longo da execução:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### 4. Trate Erros de Estado de Forma Elegante
|
||
|
||
Implemente tratamento de erros ao acessar o estado:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### 5. Use o Estado Para Acompanhar o Progresso
|
||
|
||
Aproveite o estado para monitorar o progresso em flows de longa duração:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### 6. Prefira Operações Imutáveis Quando Possível
|
||
|
||
Especialmente com estado estruturado, prefira operações imutáveis para maior clareza:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
## Depurando o Estado do Flow
|
||
|
||
### Logando Alterações no Estado
|
||
|
||
Ao desenvolver, adicione logs para acompanhar mudanças no estado:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
### Visualizando o Estado
|
||
|
||
Você pode adicionar métodos para visualizar seu estado durante o debug:
|
||
|
||
```python
|
||
# Exemplo não traduzido
|
||
```
|
||
|
||
## Conclusão
|
||
|
||
Dominar o gerenciamento de estado em CrewAI Flows te dá poder para construir aplicações de IA sofisticadas e robustas, que mantêm contexto, tomam decisões complexas e entregam resultados consistentes.
|
||
|
||
Seja escolhendo estado não estruturado ou estruturado, implementar boas práticas de gerenciamento de estado irá ajudar a criar flows manteníveis, extensíveis e eficazes na resolução de problemas do mundo real.
|
||
|
||
À medida que desenvolver flows mais complexos, lembre-se de que um bom gerenciamento de estado está relacionado ao equilíbrio entre flexibilidade e estrutura, tornando seu código tanto poderoso quanto fácil de entender.
|
||
|
||
<Check>
|
||
Agora você domina os conceitos e práticas de gerenciamento de estado em CrewAI Flows! Com este conhecimento, você pode criar workflows de IA robustos que mantêm contexto, compartilham dados entre as etapas e constroem lógicas avançadas de aplicação.
|
||
</Check>
|
||
|
||
## Próximos Passos
|
||
|
||
- Experimente usar estado estruturado e não estruturado em seus flows
|
||
- Teste a implementação de persistência de estado para workflows de longa duração
|
||
- Explore [como construir seu primeiro crew](/pt-BR/guides/crews/first-crew) para ver como crews e flows podem funcionar juntos
|
||
- Confira a [documentação de referência de Flow](/pt-BR/concepts/flows) para funcionalidades mais avançadas
|