LocalLens
Arquitetura

RAG vs LLM

Dois trabalhos, dois modelos — o retrieval acha a evidência, o LLM escreve a resposta.

As duas letras em RAG referem-se a dois trabalhos distintos. Retrieval acha a evidência. Geração escreve a resposta. No LocalLens esses dois trabalhos estão divididos em dois modelos distintos, em módulos distintos, de propósito.

LadoModeloO que faz
Retrieval (RAG)GTE_LARGE_FP16Embute documentos e a pergunta. Devolve os top-K chunks mais próximos.
Geração (LLM)QWEN3_1_7B_INST_Q4 (fallback QWEN3_600M_INST_Q4)Lê a pergunta + os chunks recuperados. Escreve a resposta com citações.

O lado RAG é mecânico — similaridade vetorial no workspace, sem entendimento de linguagem. O lado LLM é onde acontecem o raciocínio e a prosa. Os chunks recuperados são evidência; a resposta é o que o LLM faz com essa evidência.

O retrieval acha a evidência

O retrieval é o trabalho da camada RAG do QVAC, conduzida pelo embedding model:

  • ragChunk divide um documento em janelas de tokens com overlap.
  • ragIngest escreve esses chunks num workspace, embutindo cada um com GTE_LARGE_FP16.
  • ragSearch embute a pergunta com o mesmo modelo e devolve os top-K chunks mais próximos.

Retrieval não é uma resposta. É uma lista de excerpts que podem conter a resposta, rankeados por similaridade semântica com a pergunta. Um resultado de busca é útil mesmo quando nada deu match — o LLM pode dizer isso direto, em vez de inventar algo confiantemente errado.

O embedding model nunca lê histórico de chat, nunca produz texto, e nunca vê a resposta final. O único output dele são vetores.

A geração escreve a resposta

A geração é o trabalho do chat LLM. No LocalLens isso é o QWEN3_1_7B_INST_Q4 por default, com QWEN3_600M_INST_Q4 como fallback quando o 1.7B não consegue carregar.

  • completion() recebe o ChatMessage[] que o prompt builder produziu e streama texto de volta como tokens contentDelta.
  • O system prompt obriga o modelo a responder a partir dos excerpts recuperados e a citá-los entre colchetes.
  • O modelo nunca toca o disco e nunca embute nada. Só lê a sua context window — regras do system, excerpts numerados, a pergunta.

Esse é o passo onde a resposta de fato existe. Tudo antes só produziu evidência e um prompt empacotado. Pula esse passo, e você tem um buscador, não um chat.

A separação é o que mantém o prompt builder pequeno e o QVAC gateway limpo. O prompt builder não sabe nada de embeddings nem de geração. O gateway tem os dois modelos mas expõe por dois métodos independentes (search e answer).

A costura entre os dois

buildGroundedHistory(question, hits) é a costura. Pega a pergunta e a lista de hits e produz um prompt onde:

  • os excerpts vêm numerados ([1], [2], …) pro LLM citar;
  • as regras do system são explícitas e curtas;
  • existe exatamente um turno de usuário. Nenhum histórico conversacional é replicado, porque cada pergunta é tratada como uma rodada de retrieval nova.

Se o search não devolver nada útil, o prompt mesmo assim passa pelo LLM, mas com "No matching chunks were found." no lugar dos excerpts. A primeira regra do system prompt então entra em cena e o LLM diz isso claramente:

Only use facts that appear in the excerpts. If the answer is not in them, say so plainly.

Essa é a estratégia anti-alucinação inteira. Dois modelos, uma regra de prompt, e funciona.

Por que não há histórico de chat?

O LocalLens trata cada pergunta como uma rodada de retrieval independente. O retrieval é novo, o contexto do LLM é novo, e os follow-ups não conseguem herdar meias-verdades de turnos anteriores. Se você quer diálogo multi-turno, coloca acima do buildGroundedHistory, não dentro.

On this page