💡 Como ler este módulo
Duas portas de entrada, dois casos de uso: Embedded Client é para quando você quer rodar DeerFlow dentro do seu processo Python (notebook, job, backend); o API gateway é para quando você prefere isolar o harness num serviço e consumir via HTTP. Escolhas de arquitetura diferentes, mesmas capacidades. Este módulo cobre as duas e termina com um lab usando a primeira.
📦 Embedded Python Client — harness como biblioteca
O Embedded Python Client é o modo "import deerflow" do harness. Em vez de subir servidor, você instancia o harness no seu próprio processo Python, passa config via dict, e chama métodos síncronos ou assíncronos. É o caminho mais curto entre "tenho um script" e "tenho um script com um agente dentro".
🎯 Conceito Central
O Embedded Client resolve dois problemas que o servidor HTTP não resolve bem:
- •Latência zero — nada de loopback TCP, serialização JSON, ou processo extra
- •Contexto do processo — variáveis locais, conexões abertas, objetos Python podem ser passados direto
- •Ciclo de vida explícito — você controla quando o harness nasce e morre, sem cron restart
- •Uso em notebook — Jupyter chama
await harness.chat(...)e a resposta vira célula
Snippet mínimo
from deerflow import Harness
h = Harness.from_config({
"basic_model": {
"base_url": "https://openrouter.ai/api/v1",
"model": "anthropic/claude-sonnet-4.5",
"api_key": os.environ["OPENROUTER_API_KEY"],
},
"sandbox": {"mode": "docker"},
"skills": ["deep-research", "data-analysis"],
})
result = h.run_skill(
"data-analysis",
prompt="Analise este CSV e me diga a coluna mais correlacionada com churn",
files=["/tmp/users.csv"],
)
print(result.text)
for chart in result.artifacts:
print(f"- {chart.path}")
h.close()
💡 Dica prática
Use Harness como context manager (with Harness.from_config(...) as h:) em scripts. Ele fecha o sandbox Docker, escreve o trace final e libera conexões mesmo se o script falhar. É a diferença entre "um container órfão a cada run" e "ambiente limpo".
🌐 API gateway e documentação de API
Quando embutir direto não faz sentido (app poliglota, infra segrega tudo em serviços, time que não quer mexer em Python), o DeerFlow expõe um API gateway HTTP com endpoints versionados, documentação OpenAPI e autenticação por token. Do ponto de vista do seu app, é "mais um serviço REST" — separação limpa entre frontend e harness.
Endpoints core
O essencial: mensagem, stream, histórico, title
POST /v1/chat envia mensagem síncrona; POST /v1/chat/stream retorna SSE; GET /v1/conversations/{id} lê histórico; POST /v1/conversations/{id}/title dispara auto-title. Cada um tem schema JSON explícito no OpenAPI.
Autenticação
API key por aplicação, tokens JWT por usuário
Duas camadas: a aplicação se autentica no gateway via header X-DeerFlow-Key; o usuário final vem num JWT opcional que o gateway valida e usa para isolar memória. Ambas precisam estar ligadas em prod.
Versionamento
/v1 estável, /v2 em beta com breaking changes
O DeerFlow segue semver no gateway: /v1 é contrato estável, /v2-beta pode mudar. Upgrade do core do harness não quebra /v1. Se seu app depende de evento novo, pode optar por /v2-beta e aceitar instabilidade.
OpenAPI e clients gerados
/docs serve Swagger UI e schema bruto
O gateway publica /openapi.json e /docs (Swagger UI). Use openapi-generator para gerar clients em TypeScript, Go, Rust, Java. O contrato vira source of truth — se o schema mudou, o client quebra no build, não em runtime.
🏷️ Auto title generation
Parece detalhe de UI, é detalhe caro. Auto title gera um nome curto para a conversa a partir das primeiras mensagens — o que aparece na sidebar como "Análise de churn Q1" em vez de "New chat (42)". Sem isso, qualquer app com histórico vira sopa de letras.
🎯 Como o DeerFlow faz
Após o segundo turno (usuário + agente), um job assíncrono pega as 2 mensagens iniciais e passa para um modelo barato com o prompt "gere um título de 3 a 6 palavras". O resultado vira campo na conversa e pode ser regenerado sob demanda se o tópico mudar muito.
- •Modelo — sempre o mais barato (gpt-5-mini, gemini-2.5-flash); nunca o lead_agent
- •Assincronia — não bloqueia o primeiro turno; o título aparece segundos depois
- •Cache — gerado 1 vez, não regerado a cada turno
- •Regeneração manual —
POST /v1/conversations/{id}/title?regenerate=true
💡 Quando desligar
Se seu app tem domínio muito específico (ex.: tickets de suporte numerados), auto title atrapalha — você quer "Ticket #1234" no lugar de "Usuário perdeu acesso ao painel". Desligue com auto_title: false na config e preencha o título você via API. Também vale desligar em contextos sensíveis (saúde, jurídico) onde o título não deveria existir em clear text.
📡 Streaming server-side — SSE e eventos ricos
Streaming não é só "resposta aparece digitando". É a forma correta de mostrar o agente pensando — tool sendo chamada, sub-agent sendo iniciado, resultado parcial chegando. O DeerFlow usa Server-Sent Events (SSE) com eventos tipados por default, e expõe WebSocket para casos em que o cliente precisa enviar dados bidirecionalmente durante o stream.
📊 Tipos de evento no stream
| Evento | Quando | Payload |
|---|---|---|
conversation.started | Início do turno | conversation_id, turn_id |
plan.created | Lead_agent fez plano | steps[], estimated_cost |
tool.call | Tool invocada | tool, args |
tool.result | Tool terminou | output, error? |
subagent.spawned | Sub-agent iniciado | role, scope |
message.delta | Token streaming | text chunk |
artifact.created | Arquivo produzido | path, mime, size |
conversation.completed | Fim do turno | usage, wall_time |
error | Qualquer falha | code, message, recoverable |
⚠️ Backpressure
Se seu cliente é lento (ex.: browser atrás de proxy corporativo), o buffer do SSE enche. O DeerFlow tem estratégia default: drop de eventos message.delta (o modelo continua gerando) mas preserva tool.* e error. Se seu cliente precisa de todo token, use WebSocket com ack, não SSE.
🧪 Lab: embutir como biblioteca + rodar skill programaticamente
Hora de sair do conceito. Você vai escrever um script Python de ~40 linhas que (1) importa o DeerFlow, (2) configura um harness com Docker sandbox e OpenRouter, (3) roda a skill data-analysis num CSV local, (4) lê o resultado e imprime insights + caminho dos artefatos, (5) fecha limpamente. Se isso funcionar, você consegue embutir o DeerFlow em qualquer app Python.
Instale como dependência
pip install deerflow num venv limpo. Verifique que Docker está rodando (sandbox default) e que você tem API key de algum provider. Gere um CSV pequeno de teste — pandas.DataFrame({"age": ..., "churn": ...}).to_csv("/tmp/users.csv").
Escreva o script
Use o snippet do tópico 1 como base. Adicione logging.basicConfig(level="INFO") para ver o que o harness está fazendo durante o run. Salve como run_analysis.py.
Rode e observe
python run_analysis.py. O harness vai subir sandbox Docker, carregar a skill, pedir ao modelo um plano, executar código Python no sandbox, produzir gráfico(s) PNG e texto de resumo. Cada passo vai aparecer no log.
Inspecione os artefatos
O script imprime paths dos PNGs gerados. Abra-os. Confirme que o gráfico faz sentido para seu CSV. Se o gráfico está errado, a causa é prompt ou modelo — não o harness.
Adicione streaming
Troque h.run_skill(...) por async for event in h.run_skill_stream(...) e imprima cada evento. Você verá plan.created, tool.call, message.delta e conversation.completed passando pelo loop. Isso é a base para um frontend reativo.
💡 Próximo passo natural
Se o script funcionou, transforme-o em uma função chamável de um endpoint FastAPI. Você acabou de construir, em ~100 linhas, um serviço próprio com um agente rodando dentro. A única diferença para o API gateway oficial é que esse é seu — você escolhe o schema e só expõe o que precisa.
📝 Resumo do Módulo
Próximo Módulo:
3.5 — 🤝 Contribuindo upstream
Último módulo da trilha: como devolver valor para o projeto via PRs que passam na primeira revisão.