cd /news/ai-agents/nao-achei-um-framework-go-production… · home topics ai-agents article
[ARTICLE · art-17226] src=dev.to pub= topic=ai-agents verified=true sentiment=↑ positive

Não achei um framework Go production-ready para agentes de IA. Então construí um.

A Go developer built and open-sourced **eywa**, a production-ready framework for conversational AI agents, after finding no existing Go solutions suitable for real-world traffic and concurrency. The framework uses a hexagonal architecture with strict domain/infrastructure separation, where business logic defines interfaces (called "ports") for distributed locking, LLM providers, and other infrastructure concerns. Eywa is released under MIT license at v1.0.0, designed to handle concurrent webhook events and provide observability that Python-based AI frameworks lack in production.

read7 min publishedMay 29, 2026

Como construí um framework Go para agentes de IA em produção — e as decisões de arquitetura que realmente importam.

Quinze anos escrevendo software profissionalmente e nunca open sourcei uma linha de código.

Não é que eu não quisesse. É que é assim que funciona quando você constrói dentro de empresa — o código é deles, os problemas são específicos do domínio deles, e quando você finalmente tinha algo que poderia abstrair pra algo útil, já tinha passado pra próxima crise.

Dois meses atrás decidi mudar isso.

Estava construindo um agente de IA conversacional em Go. Precisava de um framework. Fui procurar e encontrei... Python. Mais Python. Uns repos Go abandonados em 2023. E muito "é só envolver o SDK da OpenAI" — conselho que funciona bem até você ter tráfego real e o agente começar a responder duas vezes para a mesma mensagem.

Nada production-ready. Nada com arquitetura de verdade. Nada que eu pudesse passar para um time e falar isso aguenta.

Então construí. O resultado é o eywa — framework Go para agentes de IA conversacionais, arquitetura hexagonal, v1.0.0, licença MIT, open source.

O nome vem de Avatar — Eywa é a rede neural que conecta todos os seres vivos em Pandora. A metáfora encaixou: um sistema que conecta LLMs, canais, memória e ferramentas num organismo só, onde cada parte percebe e responde ao ambiente.

Aqui o que aprendi construindo.

O ecossistema de IA vive em Python. LangChain, LlamaIndex, CrewAI — tudo Python. Se você está prototipando ou rodando notebooks, faz sentido total.

Mas se você está rodando algo em produção com escala de verdade — usuários reais mandando mensagens reais e você precisando de observabilidade, controle de concorrência e algo que não cai às 3 da manhã — Go é uma história completamente diferente.

Go te dá:

go test -race

) — que vai encontrar bugs que Python nem vêOs frameworks Python assumem que você vai ter uma requisição por vez ou vai tratar concorrência via filas fora do framework. Quando você está lidando com webhooks de WhatsApp em escala — múltiplos eventos do mesmo usuário chegando com milissegundos de diferença — essa suposição quebra.

O princípio central do eywa é que o domínio de negócio não pode ter absolutamente nenhum conhecimento de infraestrutura.

Sem import do SDK da OpenAI no código de domínio. Sem chamadas ao Redis. Sem queries no MongoDB. Só interfaces — o que o eywa chama de ports.

O domínio define o que precisa. A infraestrutura implementa. O wiring acontece na inicialização.

Aqui o port do Bond — o lock distribuído:

type Bond interface {
    AcquireLock(ctx context.Context, key string, ttl time.Duration) (bool, error)
    ReleaseLock(ctx context.Context, key string) error
    ExtendLock(ctx context.Context, key string, ttl time.Duration) error
}

O domínio sabe que pode adquirir e liberar locks. Não sabe que a implementação usa Redis Redlock por baixo. Em testes, você injeta um no-op. Em produção, injeta o adapter Redis.

Mesmo padrão para o Oracle — a abstração de LLM:

type OracleRequest struct {
    Model         string
    SystemPrompt  string
    Messages      []OracleMessage
    Temperature   float64
    MaxTokens     int
    Tools         []OracleTool
    UseTools      bool
    Attachments   []LLMAttachment
}

O domínio manda um OracleRequest

. Se vai para Anthropic, OpenAI, Gemini, Bedrock ou VertexAI é detalhe de infraestrutura. Troca provider na inicialização. Roda múltiplos ao mesmo tempo. O domínio não sabe e não precisa saber.

Isso não é over-engineering. É o que torna o sistema testável, manutenível e sobrevivível quando o próximo provider de LLM lançar e todo mundo quiser trocar.

Uma coisa onde investi pesado: nomenclatura. Não só nomes limpos de variável — um vocabulário de domínio consistente que todo pedaço do código usa.

Sim, os nomes são intencionais. Queria um vocabulário de domínio consistente em vez de "Manager", "Service", "Handler" e "Util" — que não dizem nada sobre o que o componente realmente faz no contexto de um agente de IA.

Nome O que é
Weave
Motor de runtime — orquestra tudo por evento
Spirit
Configuração do agente — LLM, tools, system prompt, comportamento
Pulse
Evento de entrada — uma mensagem recebida de um canal
Oracle
Abstração de LLM — manda prompt, recebe resposta
Bond
Lock distribuído — evita respostas duplicadas concorrentes
Voice
Adapter de saída — manda resposta de volta pro canal
Scout
Enriquecimento de contexto — roda antes da chamada ao LLM
Lore
RAG — geração aumentada por recuperação
Imprint
Injeção de memória de longo prazo
Vigil
Human-in-the-loop — pausa o agente para resposta humana
Rite
Approval workflow — barra ações por trás de confirmação humana
Conduit
Adapter cliente MCP (Model Context Protocol)

Quando seu código fala bond.AcquireLock(...)

em vez de redisLock.Lock(...)

, você para de pensar em infraestrutura e começa a pensar no domínio. Terminologia é design.

Cenário que acontece em produção e quase nenhum framework trata:

Usuário manda mensagem no WhatsApp. Webhook dispara. Seu agente começa a processar — chamada ao LLM em andamento, 800ms dentro dela.

Usuário fica impaciente e manda a mesma mensagem de novo. Segundo webhook dispara.

Agora você tem duas goroutines processando o contexto do mesmo usuário simultaneamente. A primeira termina, escreve a resposta e atualiza a memória. A segunda termina, escreve outra resposta usando estado de memória stale, sobrescrevendo a primeira atualização.

O usuário recebe duas respostas. A memória está inconsistente. Você criou uma race condition no nível da aplicação.

Isso é o Bond.

Antes do Weave processar qualquer Pulse, ele adquire um lock distribuído com chave no session ID do usuário. Se o lock já está em posse de outra goroutine, o evento é descartado. Só um processamento ativo por usuário, sempre.

O contrato é preciso: AcquireLock

retorna (false, nil)

quando o lock está ocupado (caso esperado), e (false, error)

só para falhas de infraestrutura. Essa distinção importa — o chamador trata os dois de forma diferente.

O pipeline que roda a cada Pulse antes da chamada ao LLM:

Pulse → Scouts → Pathfinder → Spirit → Oracle → Actions → Voice

Scouts são etapas sequenciais de enriquecimento de contexto. Leem de sistemas externos e injetam conhecimento no Pulse antes do modelo ver qualquer coisa.

type Scout interface {
    GetName() string
    Harvest(ctx context.Context, event *entities.Pulse) error
    IsApplicable(event *entities.Pulse) bool
}

A decisão crítica de design: Scouts são fail-open.

Um Scout que retorna erro é logado. O pipeline continua sem os dados dele. A chamada ao LLM acontece assim mesmo.

Por quê? Porque se um Scout está batendo num CRM para enriquecer o contexto do usuário, e o CRM está lento naquela manhã, você não quer que seu agente inteiro pare de responder. Você quer que continue funcionando com menos contexto, graciosamente.

O Weave inteiro é montado na inicialização com um builder fluente:

weave, err := eywa.NewWeaveBuilder(ctx).
    WithRepositories(spiritRepo, memoryRepo, echoRepo, chronicleRepo).
    WithBond(bond).
    WithActionRegistry(eywa.NewActionRegistry()).
    WithScoutRegistry(eywa.NewScoutRegistry()).
    AddOracle(eywaopenai.NewOracle(apiKey)).
    WithConfig(config).
    Build()

MongoDB para configuração de Spirits e histórico de conversa. Redis para lock distribuído e memória em andamento. OpenAI como Oracle. Tudo injetado — nada global.

Para adicionar Anthropic como provider adicional:

AddOracle(eywaopenai.NewOracle(openaiKey)).
AddOracle(eywaanthropic.NewOracle(anthropicKey)).

Spirits definem qual provider usam. O OracleFactory seleciona o correto em runtime.

O framework inteiro é distribuído como 19 módulos Go independentes:

github.com/wmulabs/eywa                     # core
github.com/wmulabs/eywa/fiber               # adapter HTTP
github.com/wmulabs/eywa/mongo               # repositórios MongoDB
github.com/wmulabs/eywa/redis               # Bond + memória Redis
github.com/wmulabs/eywa/mcp                 # cliente MCP (Conduit)
github.com/wmulabs/eywa/providers/anthropic
github.com/wmulabs/eywa/providers/openai
github.com/wmulabs/eywa/providers/gemini
github.com/wmulabs/eywa/providers/bedrock
github.com/wmulabs/eywa/providers/vertexai
github.com/wmulabs/eywa/providers/weaviate
github.com/wmulabs/eywa/providers/qdrant
github.com/wmulabs/eywa/providers/pgvector
github.com/wmulabs/eywa/providers/pinecone
github.com/wmulabs/eywa/channels/whatsapp
github.com/wmulabs/eywa/gcp/cloudtasks
github.com/wmulabs/eywa/gcp/gcs
github.com/wmulabs/eywa/gcp/gemini

Se você não usa Bedrock, não importa. Não recebe as dependências dele no go.sum

. Não recebe a superfície de segurança dele. Desenvolvedor Go liga pra isso.

Antes de chamar isso de v1.0, fiz uma revisão de segurança séria:

file://

, ftp://

io.LimitReader

subtle.ConstantTimeCompare

— sem timing attacksgo test -race

Nada disso é animador. Tudo importa.

eywa está em v1.0.0. Estável, hardened, documentado.

Se você está construindo agentes de IA em Go — ou quer construir mas não achava nada sério o suficiente pra basear um sistema de produção — adoraria seu feedback.

Pull requests bem-vindos. Issues bem-vindas. Crítica direta bem-vinda.

Talvez o mundo não precisasse de mais um framework de IA. Mas definitivamente precisava de mais engenharia nele.

── more in #ai-agents 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/nao-achei-um-framewo…] indexed:0 read:7min 2026-05-29 ·