DEV Community

Matheus de Camargo Marques
Matheus de Camargo Marques

Posted on

Busca de Palavras-Chave com Concorrência em OTP & Elixir: A Evolução Agêntica da IA

Busca de Palavras-Chave com Concorrência em OTP & Elixir: A Evolução Agêntica da IA

Por Matheus de Camargo Marques


Introdução: De 2023 a 2026 — Os Mesmos Padrões, Novos Disfarces

Em 2023, escrevi um artigo sobre busca de palavras-chave com concorrência usando OTP & Elixir. Apresentei em uma conferência. A ideia central era simples: dividir e conquistar. Divida um texto grande em partes, deixe processos independentes buscarem cada parte em paralelo e agregue os resultados.

Três anos depois, toda a indústria está falando sobre "IA agêntica" e "sistemas multi-agente" como se fossem conceitos novos. Não são. Os padrões que usamos em 2023 — processos isolados, passagem de mensagens, árvores de supervisão — são exatamente os padrões que a indústria de IA agora está "descobrindo" como essenciais para construir sistemas de agentes confiáveis.

Como Matheus Guimaraes disse no AWS Summit London 2026: "Os padrões nunca morrem. Eles apenas ganham novos disfarces".

Esta é a v2.0 daquele artigo. Mesmo problema. Mesma linguagem. Nova lente: IA agêntica.


Parte I: O Problema — Busca de Palavras-Chave em Escala

O Problema Original (2023)

O problema: contar quantas vezes uma palavra-chave aparece em um arquivo de texto grande. O caso de uso: pense no Google Keyword Planner, mas antes dele existir. Você precisa baixar páginas web, extrair texto e escanear palavras-chave.

Abordagem linear: Processar o texto sequencialmente. O custo é proporcional ao tamanho do texto.

Abordagem concorrente: Dividir o texto em partes. Cada parte é processada por um processo independente. A busca roda em paralelo. O custo é reduzido — mas a coordenação tem um preço.

Este é o mesmo trade-off que todo sistema distribuído enfrenta.

O Problema da IA Agêntica (2026)

Em 2026, o problema evoluiu. Não é mais apenas "contar palavras-chave". É:

  • Um agente recebe uma tarefa: "analise este documento em busca de oportunidades de SEO."
  • O agente raciocina sobre a tarefa, seleciona ferramentas, executa, observa resultados e itera.
  • O agente pode chamar outros agentes. Pode precisar lembrar contexto ao longo de múltiplos turnos.
  • Precisa se recuperar de falhas. Precisa ser observável. Precisa ser governável.

O problema de busca de palavras-chave agora é uma sub-tarefa dentro de um workflow agêntico maior. E a arquitetura que resolve isso é a mesma que construímos em 2023 — apenas com novos nomes.


Parte II: Os Padrões Que Nunca Morrem

De Microsserviços para Microsserviços Agênticos

Em abril de 2026, a Teksystems publicou um artigo mapeando conceitos de microsserviços para seus equivalentes em IA agêntica. Os paralelos são inequívocos:

Conceito de Microsserviço Equivalente em IA Agêntica Por Que Importa
Service Discovery Agent Capabilities (MCP) Agente usa protocolos como MCP para encontrar e chamar ferramentas/agentes
API Gateway Supervisor / Root Agent Um agente líder roteia a intenção do usuário para o sub-agente especializado
Lógica Stateless Gerenciamento de Estado Ferramentas gerenciam "sessões" para manter agentes leves
Payloads e Schema Contexto Estruturado O contexto é tratado como "visões compiladas"

Cada um desses "padrões agênticos" tem um equivalente direto em OTP:

  • Service Discovery → Registry e :global em OTP.
  • API Gateway / Supervisor → Supervisor e DynamicSupervisor.
  • Gerenciamento de Estado → Estado do GenServer e tabelas :ets.
  • Contratos Estruturados → Pattern matching e protocolos de mensagens.

A indústria está reinventando o que a BEAM tem como recurso nativo de runtime há décadas.

O Problema do "Monolito Cognitivo"

A Teksystems capturou o problema central perfeitamente: "Se você está construindo IA empresarial tentando encaixar 20 páginas de instruções de sistema em uma única chamada de LLM, você está repetindo uma falha arquitetural familiar. Você não está construindo um agente — você está construindo um monolito cognitivo".

Este é exatamente o mesmo modo de falha que identificamos com monolitos no início dos anos 2010. Um único processo que sabe tudo se torna um gargalo.

A solução, como sempre, é a decomposição. E a unidade de decomposição em OTP é o processo.


Parte III: Os Atores — 2023 vs. 2026

Atores Originais (2023)

No meu artigo de 2023, descrevi quatro atores:

  1. TextServer — Recebe requisições de clientes.
  2. TextPolling — Supervisiona os workers de processamento de texto.
  3. TextWorker — Processa o texto e encontra palavras-chave.
  4. ScoreServer — Armazena resultados e fornece respostas.

Atores Agênticos (2026)

Em 2026, a mesma arquitetura mapeia diretamente para padrões agênticos:

Ator 2023 Papel Agêntico 2026 Implementação OTP
TextServer Root Agent / API Gateway GenServer ou gen_statem
TextPolling Supervisor / Orquestrador de Agentes DynamicSupervisor
TextWorker Agente Especializado GenServer ou gen_statem
ScoreServer Memória Compartilhada / Registro de Ferramentas GenServer + :ets

Os nomes mudam. A arquitetura permanece.

Por Que gen_statem para Loops de Agentes

A maioria dos desenvolvedores recorre ao GenServer ao construir agentes. Mas gen_statem é a joia escondida que transforma loops complexos de agentes em máquinas de estado declarativas.

Como a palestra do CodeBEAM Europe 2026 "Beyond GenServers: Declarative AI Flows With gen_statem" explica: "Enquanto a maioria dos desenvolvedores BEAM recorre ao GenServer ao construir processos, no mundo dos agentes de IA, gen_statem é a joia escondida que transforma loops complexos de agentes em máquinas de estado declarativas".

O loop ReAct (Reasoning/Actions) — reasoning → acting → observing → reasoning → ... → done — é um encaixe natural para uma máquina de estado. E é exatamente isso que minha arquitetura de busca de palavras-chave de 2023 faz, apenas com nomes diferentes.


Parte IV: Código — Da Busca de Palavras-Chave à Busca Agêntica

Exemplo 1: O Buscador de Palavras-Chave Original (2023)

Aqui está o núcleo da arquitetura de 2023, condensado:

Snippet 1 — TextWorker como GenServer:

defmodule TextWorker do
  use GenServer

  def start_link(text, keyword, score_server) do
    GenServer.start_link(__MODULE__, {text, keyword, score_server})
  end

  def init({text, keyword, score_server}) do
    count = count_keyword(text, keyword)
    GenServer.cast(score_server, {:add_score, keyword, count})
    {:ok, %{}}
  end
end
Enter fullscreen mode Exit fullscreen mode

Snippet 2 — ScoreServer como GenServer:

defmodule ScoreServer do
  use GenServer

  def start_link, do: GenServer.start_link(__MODULE__, %{})

  def handle_cast({:add_score, keyword, count}, state) do
    new_state = Map.update(state, keyword, count, &(&1 + count))
    {:noreply, new_state}
  end
end
Enter fullscreen mode Exit fullscreen mode

Snippet 3 — TextPolling como Supervisor:

defmodule TextPolling do
  use Supervisor

  def start_link, do: Supervisor.start_link(__MODULE__, [])

  def init(_) do
    children = [
      {ScoreServer, []},
      {DynamicSupervisor, name: TextWorkerSupervisor, strategy: :one_for_one}
    ]
    Supervisor.init(children, strategy: :one_for_one)
  end
end
Enter fullscreen mode Exit fullscreen mode

Esta é a fundação. Agora vamos evoluí-la.

Exemplo 2: O Buscador de Palavras-Chave Agêntico (2026)

A mesma arquitetura, mas agora com capacidades agênticas. O TextWorker se torna um agente especializado que pode raciocinar sobre o texto, não apenas contar palavras.

Snippet 4 — Agentic TextWorker com gen_statem:

defmodule AgenticTextWorker do
  @behaviour :gen_statem

  def callback_mode, do: :state_functions

  def init({text, task, score_server}) do
    state = %{text: text, task: task, score_server: score_server,
              iteration: 0, max_iterations: 5}
    {:ok, :reasoning, state}
  end
Enter fullscreen mode Exit fullscreen mode

Snippet 5 — Estado de reasoning (LLM decide próxima ação):

  def reasoning(:internal, _data, state) do
    response = call_llm(state.text, state.task)

    case parse_response(response) do
      {:action, tool, input} ->
        {:next_state, :acting, state,
         [{:next_event, :internal, {:execute, tool, input}}]}

      {:final, result} ->
        GenServer.cast(state.score_server, {:add_score, result})
        {:next_state, :done, state}
    end
  end
Enter fullscreen mode Exit fullscreen mode

Snippet 6 — Estado de acting (execução de ferramenta):

  def acting(:internal, {:execute, tool, input}, state) do
    result = MyApp.ToolExecutor.execute(tool, input)
    new_history = [{:tool, result} | state.history]
    {:next_state, :reasoning, %{state | history: new_history}}
  end
Enter fullscreen mode Exit fullscreen mode

Snippet 7 — Estado de done:

  def done(:internal, _data, state) do
    {:keep_state, state}
  end
end
Enter fullscreen mode Exit fullscreen mode

A busca de palavras-chave agora é uma sub-tarefa dentro de um loop de raciocínio. O agente decide quando buscar, quais partes do texto buscar e como combinar resultados.

Exemplo 3: Registro de Ferramentas com ETS (2026)

Em 2023, o TextWorker tinha lógica de busca de palavras-chave hardcoded. Em 2026, ferramentas são descobertas dinamicamente via um registro.

Snippet 8 — API do Registro de Ferramentas:

defmodule ToolRegistry do
  use GenServer
  @table __MODULE__

  def start_link(_), do: GenServer.start_link(__MODULE__, [], name: __MODULE__)

  def register(name, executor), do: GenServer.call(__MODULE__, {:register, name, executor})
  def lookup(name), do: :ets.lookup(@table, name)
end
Enter fullscreen mode Exit fullscreen mode

Snippet 9 — Inicialização e lookup do registro:

  def init(_) do
    :ets.new(@table, [:named_table, :public, :set])
    {:ok, %{}}
  end

  def handle_call({:register, name, exec}, _from, state) do
    :ets.insert(@table, {name, exec})
    {:reply, :ok, state}
  end
end
Enter fullscreen mode Exit fullscreen mode

Snippet 10 — Executor de ferramentas com tratamento de erro:

defmodule ToolExecutor do
  def execute(tool_name, input) do
    case ToolRegistry.lookup(tool_name) do
      [{^tool_name, executor}] ->
        try do
          {:ok, executor.(input)}
        rescue
          e -> {:error, Exception.message(e)}
        end
      [] -> {:error, "Ferramenta #{tool_name} não encontrada"}
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Este é o padrão do Model Context Protocol (MCP), implementado em 50 linhas de Elixir. Sem dependências externas. Sem runtime Python. Sem framework.

Exemplo 4: A Árvore de Supervisão (2023 → 2026)

Snippet 11 — Árvore de supervisão original (2023):

children = [
  {ScoreServer, []},
  {DynamicSupervisor, name: TextWorkerSupervisor, strategy: :one_for_one}
]
Supervisor.init(children, strategy: :one_for_one)
Enter fullscreen mode Exit fullscreen mode

Snippet 12 — Árvore de supervisão agêntica (2026):

children = [
  {Registry, keys: :unique, name: AgentRegistry},
  {ToolRegistry, []},
  {DynamicSupervisor, name: AgentSupervisor, strategy: :one_for_one},
  {ScoreServer, []}
]
Supervisor.init(children, strategy: :one_for_one, max_restarts: 5)
Enter fullscreen mode Exit fullscreen mode

Mesmo padrão. Mesma estratégia. Novos filhos.


Parte V: O Que Você Ganha de Graça

Agentes Auto-Curáveis

A documentação do framework Jido afirma: "Cada agente roda em seu próprio processo leve com memória isolada. O scheduler da BEAM lida com milhares de processos de agentes concorrentes com paralelismo real".

Recuperação de Estado Após Reinício

Em OTP, GenServer tem callbacks terminate/2 onde você pode persistir estado antes de um crash. gen_statem tem o mesmo. E tabelas :ets podem ser persistidas em disco.

Isolamento de Processos e Sandboxing

Legion, apresentado na ElixirConf EU 2026, mostra como executar código Elixir gerado por LLM em sandboxes isolados: "Ao permitir que LLMs executem código Elixir vetado em sandboxes isolados, Legion permite que agentes criem outros agentes, troquem mensagens e reajam a eventos em tempo real".

Observabilidade

:observer te dá uma visão ao vivo da árvore de processos. :sys.get_state/1 te permite inspecionar o estado de qualquer GenServer. :sys.trace/3 te permite rastrear fluxos de mensagens.


Parte VI: O Ecossistema em 2026

Jido — O Framework de Agentes Elixir

Jido é o framework de agentes Elixir para construir sistemas multi-agente autônomos e de longa duração em OTP e BEAM. Tem 124.282 downloads totais e alcançou a versão 2.3.3 em 2026.

"Jido é um framework fundamental para construir sistemas de agentes autônomos e distribuídos em Elixir. Pense nele como um kit de ferramentas para criar workflows inteligentes e composáveis que podem evoluir e responder ao seu ambiente".

LoomEx — Agentes a Partir de Primitivas OTP

LoomEx tece conversas, chamadas de ferramentas e raciocínio em agentes coerentes usando GenServer, Task.Supervisor e ETS.

Kyber-BEAM — Um Harness de Agente LLM Customizado

Kyber-BEAM usa uma arquitetura de fluxo de dados unidirecional com um log de deltas append-only, um reducer puro e um sistema de plugins de GenServer hot-reloadable.

ExMCP — MCP e ACP em Elixir

ExMCP é uma implementação Elixir abrangente do Model Context Protocol e Agent Client Protocol, com árvores de supervisão nativas de OTP e 88 eventos de telemetria.


Parte VII: Os Padrões Que Nunca Morrem

Volto à frase do AWS Summit London 2026: "Os padrões nunca morrem. Eles apenas ganham novos disfarces".

Os padrões agênticos que a indústria está "descobrindo" em 2026 não são novos. São os mesmos padrões que usei em 2023 para busca de palavras-chave com concorrência:

  • Responsabilidade Única → Cada agente é um processo separado.
  • Service Discovery → Registry, :global e tabelas :ets.
  • API Gateway → Supervisor e DynamicSupervisor.
  • Contratos Estruturados → Pattern matching e protocolos de mensagens.
  • Tolerância a Falhas → Árvores de supervisão com estratégias de reinício configuráveis.
  • Isolamento de Processos → Processos leves da BEAM com heaps independentes.

Como Niko Maroulis escreveu no LinkedIn: "Quanto mais 'agênticos' nossos sistemas se tornam, mais Elixir/Erlang/OTP parece o runtime que foi construído para isso".


Conclusão: Mesmo Problema, Nova Lente

Em 2023, resolvi busca de palavras-chave com concorrência. Em 2026, a mesma arquitetura resolve workflows agênticos.

A BEAM foi construída para sistemas que são concorrentes, distribuídos, tolerantes a falhas e com estado. Essas são exatamente as propriedades que sistemas agênticos exigem.

O hype vai passar. Os padrões vão permanecer.


Referências

  1. Marques, M. C. (2023). Keyword Search with Concurrency in OTP & Elixir.

  2. AWS Developers Podcast, Episódio 206: "The Evolution of Microservices: Agents, Monoliths, and the Patterns That Never Die" — 29 de abril de 2026.

  3. Teksystems, Arvind Sambaraj: "From Microservices to Multi-Agent AI Systems" — 3 de abril de 2026.

  4. CodeBEAM Europe 2026: "Beyond GenServers: Declarative AI Flows With gen_statem".

  5. Jido — Framework de agentes Elixir. jido.run.

  6. LoomEx — hex.pm/packages/loom_ex.

  7. Kyber-BEAM — github.com/bombadil-labs/kyber.

  8. ExMCP — Implementação Elixir de MCP & ACP.

  9. ElixirConf 2026: "AI Agents - Elixir is all you need".

  10. Erlang/OTP Design Principles — Supervisor Behaviour.


Matheus de Camargo Marques é engenheiro de software com foco em Elixir, Erlang e sistemas distribuídos. Este artigo reflete uma análise pessoal baseada em pesquisa independente e não representa a posição oficial de nenhuma organização.

Top comments (0)