Gleam.br Wiki

🧠 Memórias: Dissecando o Motor LLM (Baixo Nível) | Governança

Documentação de engenharia e especificações técnicas da Gleam-BR.

🧠 Memórias: Dissecando o Motor LLM (Baixo Nível)

Este documento serve como registro arquitetural e memória técnica da fase de implementação manual dos bindings C/C++ do llama.cpp para a Erlang VM via Rust. Embora a arquitetura atual utilize a abstração de alto nível (llama-cpp-2), o entendimento destas entranhas é fundamental para o design do Gleam-BR.

1. O Abismo do Linker (C++ e SO)

A compilação cruzada de um motor de IA moderno revelou as pesadas dependências de sistema operacional ocultas sob os tensores:

  • *Padrões de Nomenclatura GNU:* Compiladores Rust no Windows (MinGW) exigem o prefixo estrito lib nos arquivos estáticos (.a), forçando manipulação física de arquivos (std::fs::rename) para alinhar saídas do CMake com as expectativas do linker.
  • *ABI do C++ e Orientação a Objetos:* O llama.cpp utiliza classes virtuais (vtable, __cxxabiv1). O linker C padrão do Rust falha ao fundi-las sem a injeção explícita da Biblioteca Padrão do C++ (libstdc++).
  • *Multithreading em Baixo Nível:* A ativação de cálculos paralelos na CPU pelo motor GGML invoca o GNU OpenMP (GOMP_barrier). A ausência da libgomp impede a geração da DLL.
  • *Acesso Direto ao Hardware (Win32 API):* Para otimizar o cache L1/L2/L3 e a topologia de núcleos, o backend de CPU do GGML lê chaves físicas do Registro do Windows. Isso obriga a linkagem da API nativa avançada do Windows (advapi32.dll).

2. A Dança do Buffer (Alocação Dinâmica C/Rust)

Linguagens seguras (Rust) e inseguras (C++) tratam memória de forma diametralmente oposta. Na API do llama.cpp, funções como llama_tokenize não retornam simplesmente um erro se o buffer fornecido for pequeno. Elas retornam um *número negativo* representando exatamente quantos bytes faltam. * *Lição:* O padrão ouro de FFI (Foreign Function Interface) exige uma chamada otimista, captura do erro negativo, realocação dinâmica (redimensionamento do vetor) e uma segunda chamada exata.

3. O Laço de Inferência Nu e Cru

Geralmente escondido por bibliotecas (como o método .generate()), o laço real de inferência de uma rede neural possui 5 etapas físicas estritas:

  1. *Tokenização:* Conversão de strings para IDs inteiros baseados no vocabulário do modelo (usualmente Byte Pair Encoding - BPE). Requer atenção especial a tokens de controle (BOS - Begin of Stream).
  2. *Formação de Lote (Batching):* Os tokens não entram soltos na rede. Eles são empacotados num struct llama_batch que dita a posição deles no contexto temporal da IA.
  3. *Avaliação (Decode):* A execução da matemática pesada. A função llama_decode acende os núcleos do processador, passando o lote pela matriz de pesos (tensores) para atualizar o contexto (KV Cache).
  4. *Amostragem (Sampling & Logits):* A rede não retorna uma palavra, ela retorna uma matriz de probabilidades (Logits) para cada token possível no vocabulário (ex: 128.000 probabilidades). Um Greedy Sampler (Amostrador Guloso) varre essa matriz inteira manualmente em busca do maior valor (probabilidade máxima) para decidir o próximo token.
  5. *Detokenização e Fim de Fluxo:* O ID numérico vencedor é testado contra o token de parada (EOS - End of Stream). Se não for o fim, ele é convertido de volta para caracteres (char*) e reinjetado no Passo 2.

4. Referências e Leituras Essenciais