Série: Aprendendo a Programar com IA

Como o Engine Conversa com Qualquer Modelo Que Você Trouxer

A camada de IA é uma interface: traga qualquer modelo sem religar o engine.

IA como Interface, Não como Dependência Quem chama na frente. Modelos atrás. Um contrato pequeno, estável e burro. Árvores de comportamento Navegação Simulação de multidões Sensorial Árvores de decisão interface de gerenciamento de modelos — handles e tensores SLM no dispositivo LLM na nuvem política aprendida heurística Troque um modelo. Troque um fornecedor. Nada acima da linha muda.
Cada limite de interface é um lugar onde uma mudança futura pode acontecer sem quebrar quem chama.

Traga qualquer modelo que você quiser. A camada de IA do RakuAI é feita de interfaces, não de imports — então o mercado de modelos pode fazer seu chilique trimestral sobre quem é o melhor, e seu engine nunca precisa se importar.

Alguém me fez uma pergunta afiada neste fim de semana. “Se a IA é um primitivo de runtime dentro do seu engine, então o engine fica preso a qualquer modelo que você conectou. Na próxima vez que o fornecedor do modelo mudar, você vai ter que reescrever o engine.”

Preocupação justa. E errada, mas justa.

O primitivo de IA no runtime não é um modelo específico. É uma interface. Cinco subsistemas separados, cada um com sua própria API em C, cada um endereçável a partir do resto do engine sem que ninguém precise saber qual modelo, quais pesos, ou qual caminho de inferência está produzindo a resposta. Os modelos vivem atrás da interface. Quem chama vive na frente dela. O contrato entre eles é pequeno, estável e burro de propósito.

Este é o post sobre como esse limite é traçado, e por que eu continuo tirando mais valor de tê-lo traçado.

Para onde “primitivo de IA” realmente aponta

A camada de IA no nosso runtime não é uma coisa só. São cinco.

  • Árvores de comportamento. A camada de execução determinística. Diz a um agente o que fazer uma vez que a intenção é conhecida.
  • Malha de navegação e busca de caminho. A camada de “como eu me movo por esse espaço”.
  • Simulação de multidões. A camada de “como muitos agentes se evitam e se comportam de forma coerente juntos”.
  • Sistemas sensoriais e percepção. A camada de “o que o agente observa”.
  • Árvores de decisão e lógica de IA complexa. A camada de “dado tudo o que eu sei, o que eu quero fazer”.

Cada um é seu próprio subsistema. Cada um é entregue como sua própria DLL. Cada um tem uma API pública em C. Nenhum deles importa um modelo específico. Todos conversam com o resto do engine por meio de suas respectivas interfaces, e conversam uns com os outros da mesma forma.

Quando um arquivo de experiência .raku diz "ai_behavior": "strafe", ele não está nomeando um modelo. Está nomeando um comportamento registrado. O runtime resolve a string. A string mapeia para uma implementação. A implementação pode ser uma árvore de comportamento, uma árvore de decisão, uma política aprendida, ou uma heurística escrita à mão. Quem chama não sabe. O arquivo não sabe. A implementação pode ser trocada sem tocar em nenhum dos dois.

Esse é o truque todo.

A camada de gerenciamento de modelos é o seu próprio subsistema

Quando precisamos de inferência de machine learning de verdade dentro do runtime, não a encaixamos à força em nenhum dos cinco subsistemas acima. Adicionamos uma sexta preocupação com sua própria superfície de API: gerenciamento de modelos.

// Aproximadamente como é a superfície, simplificada para o post.
RakuModelHandle raku_ai_load_model(const char* model_id, RakuModelOptions opts);
RakuInferenceResult raku_ai_infer(RakuModelHandle h, const RakuTensor* input);
void raku_ai_unload_model(RakuModelHandle h);

Um nó de árvore de comportamento que quer chamar um modelo passa por essa API. Não importando um SDK de fornecedor. Não linkando com um runtime específico. Pedindo ao subsistema de gerenciamento de modelos por um handle e usando-o.

Isso significa que o subsistema de gerenciamento de modelos é o único lugar na base de código que conhece formatos de modelo, fornecedores, ou frameworks de inferência específicos. Em todo o resto do engine, o que se vê são handles e tensores. Troque um modelo. Troque um runtime. Troque um fornecedor. Nada mais precisa mudar.

Esse é um trabalho de infraestrutura nada glamouroso. Também é o que nos permite não entrar em pânico quando o ecossistema de IA faz seu chilique trimestral sobre qual modelo é o novo melhor.

O limite também protege o formato de arquivo

Dê uma olhada no bloco ai no topo de qualquer arquivo de experiência .raku. Ele tem chaves como:

"ai": {
  "dda_enabled": true,
  "target_flow_state": 0.7,
  "profiler_mode": "active"
}

Nenhuma delas nomeia um modelo. Elas nomeiam capacidades. “O ajuste dinâmico de dificuldade está ligado. O runtime deve mirar em um estado de fluxo de 0.7. O profiler está ativo.” O runtime decide quais subsistemas entram em ação para entregar essas capacidades. Se a resposta certa neste trimestre é uma árvore de comportamento, é isso que roda. Se no próximo trimestre virar um pequeno modelo no dispositivo, o arquivo não muda.

Cada limite de interface que você traça em um sistema é um lugar onde uma mudança futura pode acontecer sem quebrar quem chama. Nós os traçamos agressivamente desde o início. Estamos gastando a economia agora.

Por que isso continua importando cada vez mais, não menos

Três razões.

Um. O mercado de modelos não para de se mexer. O melhor modelo do ano passado é o caro deste ano. O melhor deste ano fica velho no próximo. Times que fixaram um fornecedor de modelo no código do engine já fizeram essa integração duas ou três vezes até agora. Times que colocaram uma interface de gerenciamento de modelos no meio do caminho fizeram isso uma vez.

Dois. No dispositivo importa mais do que importava. A interface nos permite rodar o mesmo ai_behavior: "strafe" contra um modelo do lado do servidor em desenvolvimento e um modelo no dispositivo em produção. Quem chama não sabe. Essa flexibilidade é a única razão pela qual a inferência no dispositivo é viável sem reescrever a camada de experiência.

Três. Assistentes de IA no loop de desenvolvimento se beneficiam de limites limpos. Quando peço a um assistente para adicionar um novo comportamento, o contrato que ele precisa respeitar é a interface de comportamento registrado. Não um emaranhado de SDKs de fornecedores. Quanto mais limpa a interface, mais rápido o assistente produz código correto, e menor o custo de revisão do meu lado.

O que é difícil nisso

Os custos honestos.

Projetar a interface leva mais tempo do que a implementação. É genuinamente tentador pular a etapa da interface e simplesmente escrever a versão que funciona. Resista. Cada atalho que você toma aqui, você paga depois quando precisa trocar a implementação.

Você precisa ter disciplina sobre o que entra na interface. Cada parâmetro é um contrato que você não pode quebrar facilmente. Adicione menos do que você acha que precisa. Espere o segundo caso de uso te mostrar o que é realmente geral. A primeira versão da interface de IA tinha cinco parâmetros que acabaram não pertencendo ali. Removê-los depois foi doloroso.

Comportamentos registrados precisam de versionamento. Quando "strafe" significa uma coisa em uma build do runtime e algo ligeiramente diferente na próxima, quem chama descobre isso via regressões de jogabilidade. Nós versionamos comportamentos e fixamos arquivos .raku a versões do runtime. É irritante. É necessário.

Às vezes você realmente quer a dependência. Esse é o herético. Existem casos em que um modelo específico tem uma capacidade específica que nenhuma interface genérica consegue expressar. O movimento honesto é estender a interface para que a capacidade se torne genérica, não vazar o modelo para quem chama. Já nos pegamos querendo tomar o atalho mais de uma vez.

O argumento arquitetural é direto. IA é um primitivo de runtime. O formato de arquivo que o dirige nomeia capacidades, não modelos. O runtime resolve capacidades para qualquer subsistema que atualmente as entregue. O fio entre as três camadas é a interface. A interface é pequena, estável e burra de propósito.

Esse é o post inteiro.

De volta a construir.

Traga seu modelo. A interface está esperando.

O RakuAI conversa com qualquer modelo por meio de handles e tensores — do lado do servidor em desenvolvimento, no dispositivo em produção, e quem chama nunca percebe a diferença. Veja como seus pesos se conectam a um runtime espacial construído para sobreviver ao mercado de modelos.

← Todos os posts