MÓDULO 3.4

🧩 Embutindo o DeerFlow em outro app

Do "agente que roda no meu terminal" para "harness que vive dentro do meu produto". Embedded Python Client, API gateway, auto title generation, streaming server-side e um lab que resulta num script Python funcional rodando uma skill existente.

5
Tópicos
55
Minutos
Avançado
Nível
Prático
Tipo

💡 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.

1

📦 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".

2

🌐 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.

1

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.

2

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.

3

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.

4

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.

3

🏷️ 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 manualPOST /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.

4

📡 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.startedInício do turnoconversation_id, turn_id
plan.createdLead_agent fez planosteps[], estimated_cost
tool.callTool invocadatool, args
tool.resultTool terminououtput, error?
subagent.spawnedSub-agent iniciadorole, scope
message.deltaToken streamingtext chunk
artifact.createdArquivo produzidopath, mime, size
conversation.completedFim do turnousage, wall_time
errorQualquer falhacode, 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.

5

🧪 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.

1

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").

2

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.

3

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.

4

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.

5

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

Embedded Client = harness in-process — import, config por dict, métodos síncronos/async. Ideal para notebook, job, backend próprio.
API gateway = isolamento por HTTP — /v1/chat, /v1/chat/stream, /v1/conversations, auth em 2 camadas, OpenAPI e clients gerados.
Auto title usa modelo barato, assíncrono — feature que parece pequena evita sidebar inútil; desligue em contextos sensíveis ou com taxonomia própria.
SSE com eventos tipados é o default — conversation.started, plan.created, tool.*, message.delta, artifact.created, conversation.completed, error.
Backpressure é decisão de design — SSE droppa deltas em cliente lento, preserva tool e error. WebSocket com ack se você precisa de todo token.
Lab prova o ciclo completo — 40 linhas Python rodam skill, produzem artefatos, retornam insights. Base de qualquer app que embuta DeerFlow.

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.