mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-02 21:58:11 +00:00
476 lines
22 KiB
Plaintext
476 lines
22 KiB
Plaintext
---
|
|
title: Flows Conversacionais
|
|
description: Crie apps de chat multi-turno com kickoff por turno, histórico de mensagens, roteamento de intenção, tracing e pontes WebSocket.
|
|
icon: comments
|
|
mode: "wide"
|
|
---
|
|
|
|
## Visão geral
|
|
|
|
Apps conversacionais tratam cada linha do usuário como uma **nova execução do flow** com o **mesmo id de sessão**. A CrewAI oferece helpers para histórico de mensagens, classificação opcional de intenção, tracing adiado, pontes para UI e um REPL local `flow.chat()` para flows conversacionais.
|
|
|
|
| Conceito | Implementação |
|
|
|---------|----------------|
|
|
| Id de sessão | `handle_turn(..., session_id=...)` → `kickoff(inputs={"id": ...})` → `state.id` |
|
|
| Linha do usuário | `handle_turn(message)` acrescenta em `state.messages` antes do grafo rodar |
|
|
| Fim do turno | `FlowFinished` só para **esta execução**; o chat segue no próximo `handle_turn` |
|
|
| Trace da sessão | `ConversationConfig(defer_trace_finalization=True)` + `finalize_session_traces()` |
|
|
|
|
## APIs de turno
|
|
|
|
Use **`flow.handle_turn(message, session_id=...)`** para cada mensagem de usuário em REST, WebSocket, testes e UIs customizadas. Use **`flow.chat()`** quando quiser um loop de chat local no terminal para um `Flow` conversacional.
|
|
|
|
`Flow.kickoff()` não aceita os argumentos nomeados `user_message=` ou `session_id=`. Para flows conversacionais, `handle_turn()` guarda a mensagem pendente e chama `kickoff(inputs={"id": session_id})` internamente.
|
|
|
|
| API | Uso |
|
|
|-----|-----|
|
|
| `handle_turn(message, session_id=...)` | Wrapper ergonômico de um turno para `Flow` conversacional |
|
|
| `chat()` | REPL local no terminal para `Flow` conversacional |
|
|
| `kickoff(inputs={...})` | Execução avançada do flow sem tratamento de turno conversacional |
|
|
| `ask()` | Prompt bloqueante **dentro** de um passo (wizard, esclarecimento) |
|
|
| `@human_feedback` | Aprovar/rejeitar **saída de um passo** — não a próxima linha do chat |
|
|
| `ChatSession.handle_turn(...)` | Camada de transporte sobre `handle_turn` (SSE / WebSocket) |
|
|
|
|
## Início rápido
|
|
|
|
```python
|
|
from uuid import uuid4
|
|
|
|
from crewai import Flow
|
|
from crewai.flow import listen
|
|
from crewai.experimental.conversational import (
|
|
ConversationConfig,
|
|
ConversationState,
|
|
)
|
|
|
|
|
|
@ConversationConfig(defer_trace_finalization=True)
|
|
class SupportFlow(Flow[ConversationState]):
|
|
conversational = True
|
|
|
|
def route_turn(self, context):
|
|
message = (self.state.current_user_message or "").lower()
|
|
if "pedido" in message or "order" in message:
|
|
return "order"
|
|
if "tchau" in message or "goodbye" in message:
|
|
return "goodbye"
|
|
return "help"
|
|
|
|
@listen("order")
|
|
def handle_order(self):
|
|
reply = "Seu pedido está a caminho."
|
|
self.append_assistant_message(reply)
|
|
return reply
|
|
|
|
@listen("help")
|
|
def handle_help(self):
|
|
reply = "Como posso ajudar?"
|
|
self.append_assistant_message(reply)
|
|
return reply
|
|
|
|
@listen("goodbye")
|
|
def handle_goodbye(self):
|
|
reply = "Até logo!"
|
|
self.append_assistant_message(reply)
|
|
return reply
|
|
|
|
|
|
session_id = str(uuid4())
|
|
flow = SupportFlow()
|
|
|
|
try:
|
|
flow.handle_turn("Onde está meu pedido?", session_id=session_id)
|
|
flow.handle_turn("E as devoluções?", session_id=session_id)
|
|
finally:
|
|
flow.finalize_session_traces() # um link de trace para o chat inteiro
|
|
```
|
|
|
|
## Ciclo de vida do turno
|
|
|
|
Cada `handle_turn` executa este pipeline:
|
|
|
|
1. **`_configure_conversational_kickoff`** — mescla `session_id` / `user_message` em `inputs`, aplica `ConversationalConfig`, habilita tracing adiado quando configurado.
|
|
2. **Restauração de estado** — se `inputs["id"]` existe e `@persist` está configurado, carrega o snapshot mais recente.
|
|
3. **`FlowStarted`** — emitido apenas no primeiro turno da sessão adiada.
|
|
4. **`prepare_conversational_turn`** — acrescenta a mensagem do usuário em `state.messages`, define `last_user_message`, limpa `last_intent`, classifica opcionalmente quando `intents` / `default_intents` + `intent_llm` estão definidos.
|
|
5. **Execução do grafo** — `@start` → `@router` → handlers `@listen`.
|
|
6. **Fim da execução** — `flow_finished` por turno e finalização de trace são **ignorados** com adiamento; `Agent.kickoff()` / crews aninhados também não fecham o batch pai.
|
|
|
|
Os handlers devem chamar **`append_assistant_message(reply)`** para que o próximo turno inclua a resposta do assistente. A linha do usuário já é salva por `handle_turn` — não acrescente de novo nos handlers.
|
|
|
|
## `ConversationalConfig` (padrões em nível de classe)
|
|
|
|
Defina na subclasse de `Flow` como `conversational_config: ClassVar[ConversationalConfig | None]`.
|
|
|
|
| Campo | Padrão | Propósito |
|
|
|-------|---------|-----------|
|
|
| `default_intents` | `None` | Rótulos de outcome para classificação automática antes do kickoff |
|
|
| `intent_llm` | `None` | Modelo para classificação (obrigatório quando há intents) |
|
|
| `interactive_prompt` | `"You: "` | Prompt para `kickoff(interactive=True)` |
|
|
| `interactive_timeout` | `None` | Timeout por linha no modo interativo |
|
|
| `exit_commands` | `exit`, `quit` | Palavras que encerram o modo interativo |
|
|
| `defer_trace_finalization` | `True` | Manter um batch de trace aberto entre turnos |
|
|
|
|
Sobrescreva por kickoff com `intents=` e `intent_llm=`.
|
|
|
|
## `ChatState` (formato persistido recomendado)
|
|
|
|
```python
|
|
from crewai.flow import ChatState
|
|
|
|
|
|
class MyChatState(ChatState):
|
|
# Herdados: id, messages, last_user_message, last_intent, session_ready
|
|
research_turn_count: int = 0
|
|
custom_flag: bool = False
|
|
```
|
|
|
|
| Campo | Função |
|
|
|-------|--------|
|
|
| `id` | UUID da sessão (igual a `session_id` / `inputs["id"]`) |
|
|
| `messages` | `list` de `{role, content}` para histórico de LLM |
|
|
| `last_user_message` | Última linha do usuário neste turno |
|
|
| `last_intent` | Rótulo de rota após classificação (se usado) |
|
|
| `session_ready` | Flag de bootstrap único (permissões, caches, etc.) |
|
|
|
|
`ConversationalInputs` é um `TypedDict` para `kickoff(inputs={...})`: `id`, `user_message`, `last_intent`.
|
|
|
|
## API conversacional em `Flow`
|
|
|
|
### Parâmetros de `kickoff` / `kickoff_async`
|
|
|
|
| Parâmetro | Propósito |
|
|
|-----------|-----------|
|
|
| `user_message` | Texto deste turno (ou `{"role": "user", "content": "..."}`) |
|
|
| `session_id` | UUID da conversa → `inputs["id"]` / `state.id` |
|
|
| `intents` | Rótulos de outcome para `classify_intent` antes do kickoff |
|
|
| `intent_llm` | LLM para classificação (obrigatório com `intents`) |
|
|
| `interactive` | Loop CLI via `ask()` (só demos locais) |
|
|
| `interactive_prompt` | Prompt no modo interativo |
|
|
| `interactive_timeout` | Timeout de `ask()` por linha |
|
|
| `exit_commands` | Palavras que encerram o modo interativo |
|
|
| `inputs` | Campos extras de estado (mesclados com chaves conversacionais) |
|
|
| `restore_from_state_id` | Hidratação fork de outro flow persistido |
|
|
|
|
### Atributos de instância
|
|
|
|
| Atributo | Propósito |
|
|
|-----------|-----------|
|
|
| `conversational_config` | Padrões `ConversationalConfig` em nível de classe |
|
|
| `defer_trace_finalization` | Flag de instância; definida automaticamente a partir do config no kickoff |
|
|
| `suppress_flow_events` | Oculta painéis Rich no console; **tracing ainda registra** eventos |
|
|
| `stream` | Habilita streaming; use com `ChatSession.handle_turn(..., stream=True)` |
|
|
|
|
### Métodos e propriedades
|
|
|
|
| Nome | Descrição |
|
|
|------|-------------|
|
|
| `append_message(role, content, **extra)` | Acrescenta em `state.messages` (roles: `user`, `assistant`, `system`, `tool`) |
|
|
| `conversation_messages` | Histórico somente leitura para chamadas LLM |
|
|
| `classify_intent(text, outcomes, *, llm, context=None)` | Mapeia texto a um outcome (mesma lógica de `@human_feedback`) |
|
|
| `receive_user_message(text, *, outcomes=None, llm=None)` | Acrescenta mensagem do usuário; opcionalmente define `last_intent` |
|
|
| `finalize_session_traces()` | Emite `flow_finished` adiado e finaliza o batch de trace da sessão |
|
|
| `_should_defer_trace_finalization()` | Se este flow adia finalização de trace por turno |
|
|
| `input_history` | Trilha de auditoria de prompts e respostas de `ask()` |
|
|
|
|
### Helpers do módulo (`crewai.flow.conversation`)
|
|
|
|
Importáveis para testes ou orquestração customizada:
|
|
|
|
| Função | Descrição |
|
|
|----------|-------------|
|
|
| `normalize_kickoff_inputs(inputs, user_message=..., session_id=...)` | Mescla kwargs conversacionais em `inputs` |
|
|
| `get_conversation_messages(flow)` | Lê mensagens do estado ou buffer interno |
|
|
| `append_message(flow, role, content, **extra)` | Igual ao método de instância |
|
|
| `prepare_conversational_turn(flow, ...)` | Hidratação do turno (geralmente chamado pelo kickoff) |
|
|
| `receive_user_message(flow, text, ...)` | Igual ao método de instância |
|
|
| `set_state_field(flow, name, value)` | Define campo em estado dict ou Pydantic |
|
|
| `get_conversational_config(flow)` | Lê `conversational_config` da classe |
|
|
| `input_history_to_messages(entries)` | Converte `input_history` para formato de mensagens LLM |
|
|
|
|
## Padrões de roteamento de intenção
|
|
|
|
### A. Pré-classificar via `ConversationalConfig` (mais simples)
|
|
|
|
Defina `default_intents` e `intent_llm`. Cada kickoff classifica antes do `@router`; leia `self.state.last_intent` em `route()`.
|
|
|
|
### B. Classificar dentro do `@router` (prompts mais ricos)
|
|
|
|
Defina `default_intents=None` para o kickoff só acrescentar a mensagem. Em `route()`, chame `classify_intent` com prompt ou descrições customizadas:
|
|
|
|
```python
|
|
@router(bootstrap)
|
|
def route(self):
|
|
intent = self.classify_intent(
|
|
self._routing_prompt(self.state.last_user_message),
|
|
("GREETING", "ORDER", "RESEARCH", "GOODBYE"),
|
|
llm=self.conversational_config.intent_llm or "gpt-4o-mini",
|
|
)
|
|
self.state.last_intent = intent
|
|
return intent
|
|
```
|
|
|
|
Use **`@listen("RESEARCH")`** (ou similar) para passos com `Agent.kickoff()` e ferramentas — não `LLM.call()` puro — quando precisar de pesquisa web ou uso multi-etapa de tools.
|
|
|
|
## Quando o flow termina mas o usuário continua conversando
|
|
|
|
`FlowFinished` significa que **esta execução do grafo** terminou. A conversa segue com outro `kickoff` e o mesmo `session_id`. `@persist` restaura `messages`, flags e contexto.
|
|
|
|
**Padrão de persistência:** prefira `@persist` em um **único passo terminal** (por exemplo `finalize`) em vez de na classe `Flow` inteira. Persist em nível de classe salva após cada método; `load_state` usa a linha mais recente, que pode ser snapshot no meio da execução e perder atualizações dos handlers no mesmo turno.
|
|
|
|
Não use `@human_feedback` para linhas de chat de follow-up, a menos que um humano precise aprovar uma saída específica antes de exibi-la.
|
|
|
|
## `Flow` conversacional (experimental)
|
|
|
|
<Warning>
|
|
**Funcionalidade experimental.** A superfície do `Flow` conversacional
|
|
(`conversational = True`, `handle_turn`, `ConversationConfig`,
|
|
`RouterConfig`, `ConversationState`, o grafo embutido + helpers) vive em
|
|
`crewai.experimental` e pode mudar de formato antes de graduar. Fixe a
|
|
versão do CrewAI se depende de comportamento específico e acompanhe o
|
|
changelog para mudanças quebradoras. Feedback / issues bem-vindos.
|
|
</Warning>
|
|
|
|
Habilite o grafo conversacional definindo `conversational = True` em uma subclasse de `Flow`. O `Flow` base passa a expor um grafo embutido `@start` / `@router` / `converse_turn` / `end_conversation`, gerencia `state.messages`, dirige o LLM de roteamento e mantém o batch de trace aberto entre os turnos. Você escreve as **rotas customizadas**; o framework cuida do resto.
|
|
|
|
Use isto quando quiser um chat multi-turno com router LLM e handlers por rota sem cablar o ciclo de vida na mão. Use `Flow[ChatState]` (o padrão de mais baixo nível acima) quando precisar de controle total.
|
|
|
|
### Exemplo rápido
|
|
|
|
```python
|
|
from crewai import LLM, Flow
|
|
from crewai.flow import listen
|
|
from crewai.experimental.conversational import (
|
|
ConversationConfig,
|
|
ConversationState,
|
|
RouterConfig,
|
|
)
|
|
|
|
|
|
ROUTER_LLM = LLM(model="gpt-4o-mini")
|
|
|
|
|
|
@ConversationConfig(
|
|
system_prompt="A multi-agent assistant for ordinary chat and tool-backed tasks.",
|
|
llm=ROUTER_LLM,
|
|
router=RouterConfig(), # rotas + descrições auto-descobertas pelos handlers @listen
|
|
)
|
|
class SupportFlow(Flow[ConversationState]):
|
|
conversational = True
|
|
|
|
@listen("INTERNET_SEARCH")
|
|
def handle_internet_search(self) -> str:
|
|
"""Fresh web research, current news, real-time lookups."""
|
|
...
|
|
self.append_assistant_message(reply)
|
|
return reply
|
|
|
|
@listen("CREWAI_DOCS")
|
|
def handle_crewai_docs(self) -> str:
|
|
"""Look up the CrewAI documentation for framework/API questions."""
|
|
...
|
|
self.append_assistant_message(reply)
|
|
return reply
|
|
|
|
|
|
flow = SupportFlow()
|
|
try:
|
|
flow.handle_turn("O que você pode fazer?") # roteia para converse (built-in)
|
|
flow.handle_turn("Pesquise na web por notícias de IA.") # roteia para INTERNET_SEARCH
|
|
flow.handle_turn("Resuma o primeiro resultado.") # volta para converse
|
|
finally:
|
|
flow.finalize_session_traces()
|
|
```
|
|
|
|
Para um chat local no terminal, use `chat()`:
|
|
|
|
```python
|
|
def kickoff() -> None:
|
|
SupportFlow().chat()
|
|
```
|
|
|
|
`chat()` envolve `handle_turn()` em um REPL, sai com `exit` / `quit`, ignora linhas em branco por padrão e chama `finalize_session_traces()` quando a sessão termina.
|
|
|
|
### `ConversationConfig`
|
|
|
|
Decorador de classe que anexa os defaults de chat por classe.
|
|
|
|
| Campo | Padrão | Propósito |
|
|
|-------|--------|-----------|
|
|
| `system_prompt` | `slices.conversational_system_prompt` (i18n) | System message usado pelo `converse_turn` embutido. Passe `""` para desativar totalmente. |
|
|
| `llm` | `None` | LLM de conversa (usado pelo `converse_turn` e como fallback do router). |
|
|
| `router` | `None` | `RouterConfig` para roteamento por LLM. Sem ele, o flow sempre cai em `converse`. |
|
|
| `answer_from_history_prompt` | padrão do framework | System message para a rota opcional `answer_from_history`. |
|
|
| `answer_from_history_llm` | `None` | Habilita o atalho `answer_from_history` quando definido. |
|
|
| `intent_llm` | `None` | LLM para o caminho legado `intents=`/`default_intents`. |
|
|
| `default_intents` | `None` | Labels de outcome para pré-classificação legada. |
|
|
| `visible_agent_outputs` | `None` | `"all"` ou lista de nomes de agentes cujos `append_agent_result()` devem virar mensagens públicas. |
|
|
| `defer_trace_finalization` | `True` | Mantém um único batch de trace aberto entre chamadas de `handle_turn()`. |
|
|
|
|
### `RouterConfig` e o catálogo de rotas auto-gerado
|
|
|
|
```python
|
|
RouterConfig(
|
|
prompt="Enquadramento de domínio opcional (política, voz, persona).",
|
|
response_format=MyRoute, # opcional; auto-gerado caso contrário
|
|
llm=ROUTER_LLM, # usa ConversationConfig.llm como fallback
|
|
routes=["INTERNET_SEARCH", "CREWAI_DOCS"], # opcional; inferido dos listeners
|
|
route_descriptions={
|
|
"INTERNET_SEARCH": "Sobrescreve a docstring só desta rota.",
|
|
},
|
|
default_intent="converse", # usado quando a chamada ao LLM falha ou não há LLM
|
|
fallback_intent="converse", # usado quando o LLM retorna rota inválida
|
|
intent_field="intent",
|
|
)
|
|
```
|
|
|
|
O prompt do router é montado automaticamente. Para cada rota o framework escolhe a descrição nesta precedência:
|
|
|
|
1. `RouterConfig.route_descriptions[label]` — override explícito.
|
|
2. `Flow.builtin_route_descriptions[label]` — texto canônico do framework para `converse`, `end`, `answer_from_history` (otimizado para o LLM de routing).
|
|
3. Primeira linha não vazia da docstring do handler `@listen(label)`.
|
|
4. Vazio (a rota aparece no catálogo sem descrição).
|
|
|
|
Na prática, **adicionar uma rota é `@listen("X")` + uma docstring de uma linha**:
|
|
|
|
```python
|
|
@listen("INTERNET_SEARCH")
|
|
def handle_internet_search(self) -> str:
|
|
"""Fresh web research, current news, real-time lookups."""
|
|
...
|
|
```
|
|
|
|
…e o LLM de routing vê:
|
|
|
|
```
|
|
Routes:
|
|
- CREWAI_DOCS: Look up the CrewAI documentation for framework/API questions.
|
|
- INTERNET_SEARCH: Fresh web research, current news, real-time lookups.
|
|
- converse: Ordinary chat, follow-ups, summaries, clarifications…
|
|
- end: User signals the conversation is finished (goodbye, exit, done).
|
|
```
|
|
|
|
`RouterConfig.prompt` é para **enquadramento de domínio** (persona do assistente, regras de negócio, voz). O catálogo de rotas é auto-gerado — não liste rotas em `prompt`; elas vão sair de sincronia assim que você adicionar um handler.
|
|
|
|
### Rotas embutidas
|
|
|
|
| Rota | Handler | Propósito |
|
|
|------|---------|-----------|
|
|
| `converse` | `converse_turn` | Handler de chat padrão. Chama `ConversationConfig.llm` com o system prompt + histórico canônico. |
|
|
| `end` | `end_conversation` | Define `state.ended = True` e emite uma resposta de encerramento. |
|
|
| `answer_from_history` | `answer_from_history_turn` | Opcional. Cai aqui quando `ConversationConfig.answer_from_history_llm` está definido e a mensagem pode ser respondida só pelo histórico. |
|
|
|
|
Você pode sobrescrever qualquer uma definindo um handler com o mesmo nome na subclasse.
|
|
|
|
### Semântica de `handle_turn()`
|
|
|
|
`flow.handle_turn(message)` roda um turno:
|
|
|
|
1. Reseta o tracking por execução (`_completed_methods`, `_method_outputs`) para o grafo re-rodar — sem isso, chamadas repetidas de `kickoff` na mesma instância dariam curto-circuito no turno 2+ porque `Flow.kickoff_async` trata `inputs={"id": ...}` como restauração de checkpoint.
|
|
2. Anexa a mensagem do usuário em `state.messages`, define `current_user_message` / `last_user_message`. `last_intent` é **preservado do turno anterior** para que o LLM de routing possa usá-lo como sinal.
|
|
3. Roda `conversation_start` → `route_conversation` → o handler `@listen` escolhido.
|
|
4. O router grava sua decisão em `state.last_intent` (visível para o contexto de routing do próximo turno).
|
|
5. Se seu handler retornou uma string e ainda não chamou `append_assistant_message`, `handle_turn` anexa para você.
|
|
|
|
Chame `handle_turn()` para mensagens de chat. Chamar `kickoff(inputs={"id": ...})` diretamente executa o grafo sem aplicar o wrapper de turno conversacional.
|
|
|
|
### `chat()` para REPLs locais
|
|
|
|
`flow.chat()` é o wrapper de terminal pronto para uso em cima de `handle_turn()`:
|
|
|
|
```python
|
|
flow = SupportFlow()
|
|
flow.chat()
|
|
```
|
|
|
|
Ele cobre o loop local comum:
|
|
|
|
1. Solicita uma mensagem do usuário.
|
|
2. Para com `exit` / `quit`, `EOFError` ou `KeyboardInterrupt`.
|
|
3. Chama `handle_turn(message, session_id=...)`.
|
|
4. Imprime o resultado do assistente.
|
|
5. Finaliza traces de sessão adiados em um bloco `finally`.
|
|
|
|
Customize o comportamento do terminal com I/O injetável:
|
|
|
|
```python
|
|
flow.chat(
|
|
session_id="demo-session",
|
|
prompt="You: ",
|
|
assistant_prefix="Assistant: ",
|
|
exit_commands=("exit", "quit", "bye"),
|
|
)
|
|
```
|
|
|
|
Para apps web, workers em background, testes e transportes customizados, continue usando `handle_turn()` diretamente.
|
|
|
|
### Comportamento customizado do router
|
|
|
|
Para rodar efeitos colaterais (setup de event bus, telemetria) em toda decisão de routing, sobrescreva `route_turn`:
|
|
|
|
```python
|
|
class SupportFlow(Flow[ConversationState]):
|
|
conversational = True
|
|
|
|
def route_turn(self, context: dict[str, Any]) -> str | None:
|
|
self.event_bus = MyBus(self)
|
|
return super().route_turn(context)
|
|
```
|
|
|
|
Para ignorar o router LLM e escolher uma rota programaticamente, retorne uma string de `route_turn`; retornar `None` cai no `_route_with_config(...)`.
|
|
|
|
### `append_assistant_message` e `append_agent_result`
|
|
|
|
Dentro de um handler `@listen(label)`, escolha:
|
|
|
|
- `self.append_assistant_message(text)` — adiciona um turno de assistente visível ao usuário em `state.messages`. O `converse_turn` do próximo turno vai vê-lo.
|
|
- `self.append_agent_result(agent_name, result, visibility="private")` — registra um evento estruturado em `state.events` e uma thread em `state.agent_threads[agent_name]`. Visibilidade pública também chama `append_assistant_message` automaticamente. Use resultados privados para trabalho de bastidor que não deve poluir o histórico canônico.
|
|
|
|
`ConversationConfig.visible_agent_outputs` pode promover globalmente os resultados privados de agentes específicos para públicos (`"all"` ou lista de nomes).
|
|
|
|
## Tracing entre turnos
|
|
|
|
Com `defer_trace_finalization=True` (padrão em `ConversationalConfig`):
|
|
|
|
- **Um batch de trace** para toda a sessão de chat.
|
|
- **`flow_started`** só no primeiro turno; **`flow_finished`** uma vez em `finalize_session_traces()`.
|
|
- **`kickoff` por turno** não exibe “Trace batch finalized”.
|
|
- **Trabalho aninhado** (`Agent.kickoff()`, crews, tools Exa) acrescenta ao batch **pai**; flows internos de `AgentExecutor` não fecham o batch da sessão cedo.
|
|
|
|
```python
|
|
flow.chat(session_id=session_id)
|
|
```
|
|
|
|
`flow.chat()` chama `finalize_session_traces()` para você. Quando você controla o loop com `handle_turn()` ou `kickoff(...)`, chame `finalize_session_traces()` quando a sessão terminar.
|
|
|
|
`suppress_flow_events=True` só oculta painéis do console; eventos de trace e método ainda são emitidos.
|
|
|
|
### Ciclo de vida de trace do `Flow` conversacional
|
|
|
|
O [`Flow` conversacional](#flow-conversacional-experimental) experimental usa o mesmo ciclo de vida de tracing: `defer_trace_finalization` é `True` por padrão, então cada `handle_turn()` mantém o trace da sessão aberto. Sempre finalize ao fim da sessão — envolva seu loop em `try/finally` e chame `flow.finalize_session_traces()` na saída. Sem isso, o batch fica aberto e a última conversa pode nunca ser exportada.
|
|
|
|
## Streaming
|
|
|
|
Defina `stream = True` na classe `Flow`. `kickoff(...)` então emitirá `assistant_delta` (e eventos relacionados) pelo event bus padrão.
|
|
|
|
## Imports
|
|
|
|
```python
|
|
from crewai.flow import (
|
|
ChatState,
|
|
ConversationalConfig,
|
|
ConversationalInputs,
|
|
Flow,
|
|
listen,
|
|
persist,
|
|
router,
|
|
start,
|
|
)
|
|
```
|
|
|
|
## Veja também
|
|
|
|
- [Dominando o Gerenciamento de Estado em Flows](/pt-BR/guides/flows/mastering-flow-state) — persistência, estado Pydantic, `@persist`
|
|
- [Construa Seu Primeiro Flow](/pt-BR/guides/flows/first-flow) — fundamentos de flow
|
|
- Demo: `lib/crewai/runner_conversational_flow_simple.py` — REPL mínimo com `RESEARCH` + agente Exa
|