Passo 6 · Contexto & operação · Módulo 3 · Contexto, memória & RAG
Curso de Harness Engineering · Visual Course

Contexto, memória e RAG

No caminho da nossa unidade de trabalho — pedido → tier → adapter → gates → custo → park/ship — esta lição abre o passo que decide o que entra na janela de contexto antes da chamada do modelo. Você vai entender o pack de 8 camadas, por que o Alembic indexa mas não recupera (o gap do RAG), por que a memória é composta e não recuperada, e quando RAG é a ferramenta errada.

Leia primeiro (fonte primária)
HARNESS-MAP.md, Parte III + walkinglabs — "Learn Harness Engineering (PT-BR)"

Esta lição destila a Parte III do mapa — o gap principal (retrieval) — contra três arquivos reais do repo: council/src/layered-context-pack.ts, embeddings/src/{offline-backend,index-builder}.ts e hermes/src/memory/multi-store/composer.ts. Importa para a MISSÃO porque contexto é a maior alavanca depois que o modelo está fixo — e saber onde o "RAG" do Alembic para é saber onde o roadmap começa.

Leia a versão simples, ou abra a camada técnica em qualquer seção.
1

A grande ideia


A janela de contexto é finita. A pergunta da engenharia de contexto não é "o que o modelo sabe?" — é o que cabe na janela, em que ordem, dentro de um orçamento. Essa é a maior alavanca de qualidade depois que o modelo está escolhido. O Alembic trata isso a sério em uma camada (o pack L0–L7) e, com honestidade, não trata em outra (o retrieval vetorial).

Ao fim desta lição você consegue
  • Explicar as 8 camadas do pack de contexto (L0→L7) e por que "orçamento" ali é comparação, não corte.
  • Nomear o gap principal do Alembic: ele indexa embeddings mas não recupera (não há query vetorial, topk nem rerank).
  • Entender por que o vetor offline é um hash de char-codes de 16 dimensões — e por que isso não é semântico.
  • Distinguir memória composta (lida das stores ligadas) de memória recuperada (por similaridade) — e por que uma store não-ligada nunca vaza.
  • Escolher entre fine-tune · in-context · RAG · destilação — e reconhecer quando RAG é a ferramenta errada.
Suposições tolas (o que presumimos de você)
  • Você sabe que um LLM recebe um texto de entrada (o "contexto") e devolve texto. Só isso.
  • Você não precisa saber o que é "embedding", "vetor" ou "cosseno" — a lição constrói cada termo.
  • Você leu (ou viu de relance) as lições 0001–0005: a unidade de trabalho que atravessa o harness é o nosso fio condutor.

Pense na nossa unidade de trabalho chegando no harness do Alembic. Antes de gastar um token, alguém precisa montar a "ficha" que o modelo vai ler: a tarefa em uma linha, o mapa do repositório, os arquivos certos, trechos relevantes, resumos, o histórico do debate, os artefatos e um inventário com hash. Isso é o pack de contexto. Não é "jogar tudo no prompt" — é estratificar, do mais essencial ao mais volumoso, para poder descartar de baixo pra cima quando o orçamento aperta.

Pense como… preparar uma pasta para um advogado substituto que vai pegar o caso amanhã: a capa com o pedido (1 linha), o índice dos autos, as peças inteiras que importam, os trechos grifados, os resumos, o andamento, os anexos e a lista carimbada de tudo. Se a pasta não cabe na mochila, você tira os anexos volumosos primeiro — nunca a capa. Onde a analogia quebra: a pasta jurídica é montada por uma pessoa que entende o caso; o pack do Alembic é montado por código determinístico que mede tamanho com uma régua grosseira (≈4 caracteres por token), não com leitura.

As três peças desta lição, e a etiqueta honesta de cada uma. O pack de contexto é owned (o Alembic implementa). O retrieval vetorial é gap (não construído). A memória multi-store é owned — mas composta, não recuperada, então a parte de "recuperar por similaridade" também é gap. Essa honestidade é o valor do curso: separar o que é confiável hoje do que é roadmap.

A moldura "Self-Learning Agents" — onde o Alembic fica Modelpesos + inferência delegatedgateway + MLX Harnessloop · gates · routing owned (a casa)custo · observabilidade Contextmemória + skills owned, mas COMPOSTOnão recuperado o 4º elemento — o sinal do usuário (o veredito humano que realimenta) — é o gap estratégico (clímax da 0008)
Esta lição vive nas caixas Harness (o pack que monta o contexto) e Context (a memória). Repare: Context é "owned, mas composto" — o ponto da §4.

Por baixo do capô

"Engenharia de contexto" no mapa é o princípio #2. O Alembic o realiza com buildLayeredContextPack (packages/council/src/layered-context-pack.ts): uma função pura que recebe brief, repoMap, arquivos, snippets, resumos, estado de debate, artefatos/constraints e um manifesto com hash de conteúdo, valida tudo com Zod e devolve um Result — nunca lança. O id do pack e do manifesto são SHA-256, então o bundle é reprodutível a partir do hash.

O "RAG" de hoje (princípio #13) é, no mapa, o gap principal: o subsistema @alembic/embeddings tem o lado de escrita (constrói índices) mas não o de leitura (não há cosine/topK/rerank/queryIndex em nenhum arquivo de packages/ — um grep confirma vazio). Logo, "RAG" hoje = o funil de destilação offline + o pack de contexto montado à mão, não recuperação por similaridade.

An educational diagram of an eight-tier pyramid of context layers labeled L0 at the narrow top widening to L7 at the wide base, each tier a distinct horizontal bar with room for a
An educational diagram of an eight-tier pyramid of context layers labeled L0 at the narrow top widening to L7
2

O pack de 8 camadas (L0→L7)


O pack estratifica o contexto do mais estreito (L0, uma linha) ao mais largo (L7, o manifesto inteiro com hash). A ideia: sob pressão de orçamento, um chamador pode jogar fora as camadas de baixo valor — de baixo pra cima — mantendo o pack reproduzível pelo hash. É a "pirâmide" do contexto.

L0 · brief (1 linha) L1 · mapa do repo L2 · arquivos inteiros L3 · snippets (+reason) L4 · resumos L5 · estado do debate L6 · artefatos + constraints L7 · manifesto (hash de conteúdo) descarta de baixo pra cima sob pressão de orçamento
Da nossa unidade de trabalho: L0 é o pedido; L7 é o carimbo. Largura = volume de tokens. Aperta o orçamento → some L7, depois L6… L0 é a última a cair.
As camadas, em uma frase cada
CamadaO que carrega
L0brief — a tarefa em uma linha
L1repoMap — lista de caminhos
L2arquivos inteiros (verbatim)
L3snippets + um reason de por que importam
L4resumos comprimidos
L5estado de debate/fase
L6artefatos (referência) + constraints
L7manifesto: cada arquivo com SHA-256, tamanho, nº de linhas
Por que estratificar (e não "jogar tudo")

Um prompt achatado não te deixa escolher o que sacrificar. Estratificado, o descarte vira política: "se estourar, tire L7, depois L6". E o L7 sendo hash de conteúdo, qualquer byte que muda em qualquer arquivo muda o id do manifesto — detecção de mudança grátis, e reprodutibilidade pelo hash.

owned Um primitivo de contexto endereçável por conteúdo e ciente de orçamento. CLI: alembic context-pack.

arquivo Asha256: 9f3a… arquivo Bsha256: c1d8… manifesto L7id: ctxm_ab12… id do packctxp_… (reproduzível) muda 1 byte em A → muda sha256(A) → muda o id do manifesto → detecção de mudança grátis
Endereçamento por conteúdo: o id do manifesto (e do pack) deriva dos hashes dos arquivos, ordenados por caminho. Reproduzível pelo hash, e qualquer alteração é visível.

Orçamento é uma comparação, não um corte

Este é o ponto mais incompreendido. O pack não trunca nada sozinho. Ele mede o custo estimado, compara com o orçamento e te entrega os dois números mais um booleano withinBudget. Você decide: falhar fechado ou descartar camadas. O harness te dá o velocímetro; quem pisa no freio é o chamador.

Faça sua aposta antes de revelar

O orçamento é em tokens. Como o pack estima quantos tokens um bundle gasta, sem chamar um tokenizer de verdade?

Ele serializa o valor em JSON e divide o comprimento por 4: Math.ceil(JSON.stringify(x).length / 4), no mínimo 1. É uma régua grosseira (≈4 caracteres por token) — ótima para decidir o que descartar, ruim para encaixe exato. O próprio mapa marca isso como uma nuance: a decisão de shedding é confiável; o packing exato não.

Brinque com a política de descarte abaixo. Cada camada tem um peso de tokens fictício; clique para tirar/pôr e veja o medidor cruzar (ou não) o orçamento.

withinBudget: true
estimado 0 / orçamento 1400 tokens  ·  tudo cabe — nada a descartar

Demo: o pack mede e compara; você escolhe descartar. Repare que L0 (o brief) é minúsculo e L7 (o manifesto) é o mais pesado — exatamente por isso o descarte começa por baixo.

O cálculo do orçamento, do arquivo real

packages/council/src/layered-context-pack.ts
// estima tokens pela serialização JSON (~4 chars/token), no mínimo 1
export const estimateTokens = (value: unknown): number =>
  Math.max(1, Math.ceil(JSON.stringify(value).length / 4));

// ... dentro de buildLayeredContextPack:
const estimatedTokens = estimateTokens(layers);
tokenBudget: {
  estimatedTokens,
  maxTokens: input.tokenBudget,
  withinBudget: estimatedTokens <= input.tokenBudget,  // <- comparação, não corte
},

Note: o pack carrega os dois números e o booleano e devolve. Nenhuma camada é removida aqui. "Fail closed ou shed layers" é decisão do chamador. E selectTokenBudget resolve o teto por modelo > papel > default — orçamentos diferentes para modelos diferentes.

3

O gap do retrieval (o titular)


Agora o ponto mais honesto do curso. Quando as pessoas dizem "RAG" (Retrieval-Augmented Generation), imaginam: fatiar um corpus em pedaços, transformar cada pedaço em um vetor, e na hora da pergunta buscar os pedaços mais parecidos com a pergunta, ordenar e enfiar no contexto. São duas metades: escrever o índice e ler o índice.

O Alembic tem só a primeira metade. Ele constrói índices de embeddings (buildChunkIndexwriteChunkIndex, append-only, dedupe por chunk_id). Mas não existe lado de leitura: nenhum cosine, topK, rerank, queryIndex ou knn em packages/. Ele indexa, mas não recupera.

METADE DE ESCRITA — existe (owned) corpus / chunks buildChunkIndex(embed) writeChunkIndexappend-only · dedupe index/<family>.jsonlvetores no disco METADE DE LEITURA — NÃO existe (gap) pergunta embed querycosine / topK rerankordenar relevância chunks no contexto grep por cosine|topK|rerank|queryIndex|knn em packages/ → 0 resultados o único .search( é uma busca na WEB; os "similarity" são de STRING (QA de marketing)
O índice é construído e fica no disco — mas nada nunca o lê para responder. A linha tracejada vermelha é o roadmap, não o código.
Atenção — o detalhe que mais confundeOs vetores offline não são semânticos. No caminho offline (o default, $0, hermético), o vetor de um chunk é um hash polinomial de 16 dimensões derivado só dos códigos dos caracteres da string. É um pseudo-vetor: estável e reproduzível (serve para encanar índice, cache, testes), mas não mede significado. Dois textos com o mesmo sentido e palavras diferentes geram vetores distantes. Um vetor semântico de verdade só vem do caminho --online (fetch-backend.ts). Ou seja: offline, mesmo que existisse uma query, não haveria nada semanticamente significativo para recuperar.
Embedding semântico (de verdade)

"cachorro" e "cão" ficam perto no espaço vetorial; "cachorro" e "planilha" ficam longe. A proximidade mede sentido. É o que o caminho --online produz.

Pseudo-vetor offline (char-code hash)

"cachorro" e "cão" ficam longe (caracteres diferentes); "cachorro" e "carchoro" (typo) podem ficar perto. A proximidade mede bytes, não sentido. Serve de impressão digital, não de busca.

espaço SEMÂNTICO (--online) cachorro cão planilha perto pseudo-vetor CHAR-CODE (offline) cachorro cão longe
Mesmo par de palavras, dois espaços. À esquerda a distância significa algo; à direita ela só reflete os caracteres. Por isso o backend offline avisa, no próprio cabeçalho, que não é um embedding semântico.

Veja o backend offline declarando isso ele mesmo — o cabeçalho do arquivo é a fonte mais honesta:

packages/embeddings/src/offline-backend.ts
/**
 * O vetor NÃO é um embedding semântico real — é uma impressão digital
 * estável e reproduzível, adequada para encanamento, cache e índice sob
 * condições herméticas. Nunca lança através da fronteira.
 *
 * Derivação: para cada um dos OFFLINE_DIMENSION (=16) slots, dobra cada
 * char code com um multiplicador por-slot e a posição corrente em um
 * acumulador unsigned de 32 bits (hash polinomial), depois espreme em [-1,1).
 */
export const OFFLINE_DIMENSION = 16;  // 16 dimensões, fixas
embedOne("petição") → vetor de 16 componentes em [-1, 1) 0 determinístico: a MESMA string → o MESMO vetor, sempre · mas mede char-codes, não significado
16 componentes, cada um um squash de um acumulador de 32 bits por-slot. Acima/abaixo de zero = sinal do componente. É uma impressão digital estável — não um mapa de sentido.
rows novas[c1, c2, c3] lê ids já no arquivo{c1} já existe dedupe por chunk_idc1 → pulado append [c2, c3].jsonl no disco re-rodar sobre os mesmos chunk_ids escreve nada → o índice CONVERGE (idempotente)
O lado de escrita que existe: writeChunkIndex, append-only, dedupe por chunk_id. Note o que falta na figura: nenhuma seta de volta "ler para responder".
freshness: a clássica "stale retrieval" não se aplica — não há recuperador corpus muda re-sync + re-indexappend-only converge índice atualizado no disco(ainda sem lado de leitura) "staleness" aqui = frescor do CORPUS, não um retriever velho (o gap nº 1 elimina essa classe de bug)
Um efeito colateral curioso do gap: sem recuperador, não há "retrieval velho" para dar errado. A frescura vira responsabilidade do corpus (append-only + re-sync), não de um índice de busca.
Por que isto é uma decisão, não um descuido. O Alembic é uma camada de orquestração. Construir o índice é encanamento barato e determinístico; o lado de leitura (query vetorial, rerank, freshness) é um subsistema inteiro. O mapa o lista como o gap nº 1 exatamente para não fingir que existe. "RAG hoje" no Alembic = o funil de destilação (corpus → LEARNINGS/SIGNALS) + o pack de contexto montado à mão. owned construir índice · gap recuperar.

An educational two-row diagram contrasting the two halves of retrieval-augmented generation. Top row, drawn solid and complete: a corpus box, an embed box, an index-write box, and
An educational two-row diagram contrasting the two halves of retrieval-augmented generation. Top row, drawn so
4

Memória: composta, não recuperada


O Alembic tem memória multi-store: cinco "gavetas" em JSONL append-only — episodic (o que aconteceu), semantic (conceitos), procedural (procedimentos), decision (decisões) e transcript (conversas). Mas repare na palavra-chave: a memória é composta no prompt, não recuperada por similaridade. O composeMemoryContext lê cada gaveta, filtra por pisos (salience/confidence), ordena por data (mais recente primeiro) e corta por um limite por gaveta. Em momento nenhum ele ordena por "parecido com a pergunta".

COMPOSTA (o que o Alembic faz) "pega o mais RECENTE de cada gaveta,filtra por piso, corta no limite" recente A recente B recente C critério = DATA determinístico, sem rede RECUPERADA (o que NÃO faz) "buscaria o mais PARECIDO coma tarefa de agora, por similaridade" top-k por cosseno critério = SIMILARIDADE exigiria query vetorial (gap)
A diferença prática: a memória do Alembic te dá o recente, não necessariamente o mais pertinente ao tópico de agora. Para o segundo, faltaria o lado de leitura do §3.
episodic (max 10) semantic (max 10) procedural (max 5) decision (max 5) transcript (max 20) filtra (pisos)salience≥0.2 · conf≥0.3 ordena por datarecente 1º · id tie-break corta (max*)slice por gaveta systemPrompt (identidade + seções)+ estimatedTokens (~4 chars/token) nenhuma etapa ordena por "parecido com a pergunta"
Da nossa unidade: se ela for tocada por um AI Employee, é assim que a memória dele vira contexto. Filtra → ordena por recência → corta. Determinístico: re-rodar sobre as mesmas gavetas dá um bundle byte-idêntico.

"Composta" quer dizer: o sistema junta os registros mais recentes e relevantes de cada gaveta e os escreve no prompt. "Recuperada" (que o Alembic não faz aqui) quer dizer: o sistema buscaria os registros mais parecidos com a tarefa atual, por similaridade vetorial. A diferença prática: a memória do Alembic te dá o recente, não necessariamente o mais pertinente ao tópico de agora.

O composeMemoryContext é uma função pura async (não uma classe). As cinco stores entram por trás de uma porta estreita RecordReader (só .query(BaseQuery) é exigido), então produção injeta logs reais e teste injeta fakes em memória. Nunca lança: uma store que falha degrada para vazio ("memória nunca quebra a chamada"). O taskHint opcional vira um filtro search de string nas reads semantic/procedural — não uma query vetorial. Ranking: sort((a,b) => (b.at - a.at) || (a.id < b.id ? -1 : 1)) — data desc, id como desempate estável.

gaveta episodic — do muito ao pouco todos os registros(centenas) piso de salience≥ 0.2 (descarta fracos) corta no maxslice(0, 10) 10 no prompt a ordem dentro do corte é por DATA (recência), nunca por similaridade à tarefa
Cada gaveta tem seu piso e seu teto: episodic (sal.≥0.2, max 10), semantic (conf.≥0.3, max 10), procedural (max 5), decision (max 5), transcript (max 20). Filtra → ordena por data → corta.

Uma gaveta não-ligada nunca vaza

Cada AI Employee declara quais gavetas ele usa. Se ele não declarou "transcript", o sistema não constrói um leitor para "transcript". Não há o que consultar — então não há como vazar. A proteção não é um filtro que poderia ser burlado; é ausência estrutural: sem leitor, sem leitura. (É a mesma postura do MCP read-only: capacidade por ausência.)

DECLARADAS (têm leitor) episodic → lê do disco decision → lê do disco NÃO declaradas semantic → EMPTY_READER → [] procedural → EMPTY_READER → [] transcript → EMPTY_READER → [] systemPromptsó episodic + decision
resolveMemoryBinding devolve só as stores declaradas. As demais recebem um leitor vazio (retorna []) — contribuem nada, vazam nada.

O mecanismo, do arquivo real

packages/hermes/src/employee/employee.ts
export const resolveMemoryBinding = (
  employee: EmployeeDefinition,
): { agent: string; stores: readonly EmployeeMemoryStore[] } | undefined =>
  employee.memory === undefined
    ? undefined                                   // sem memória → nada a ligar
    : { agent: employee.memory.agentId, stores: [...employee.memory.stores] };

O chamador (a camada de run) constrói leitores apenas para stores. Para as gavetas de fora, passa um leitor vazio ao composeMemoryContext. O composer lê exatamente as MemoryStores que recebe — uma gaveta sem registros (ou sem leitor) some do prompt. Sem binding nenhum, a memória inteira é um no-op e a chamada segue normal.

5

Fine-tune · in-context · RAG · destilação


Quatro formas de fazer o modelo se comportar do jeito que você precisa. Não são intercambiáveis — cada uma resolve um problema e é a ferramenta errada para os outros. O Alembic é quase inteiramente in-context por decisão de arquitetura.

As quatro, em uma frase
EstratégiaO que muda
Fine-tuneos pesos do modelo (treino)
In-contexto prompt (exemplos/instruções na janela)
RAGo prompt, mas preenchido por busca em tempo real
Destilaçãotreina um modelo menor (aluno) a partir de um maior
Onde o Alembic fica

owned In-context: pack L0–L7, memória composta, soul + skills do AI Employee. É a aposta dominante.

delegated Fine-tune: de quem treina os pesos (gateway/MLX). Fora da cintura.

gap RAG: índice construído, nunca lido (§3).

gap* Destilação de modelo: não feito. Cuidado: o Alembic usa "distill" para destilar um corpus (T0→T3), não um modelo — palavra sobrecarregada.

Armadilha de vocabulárioNo Alembic, alembic distill não é destilação de modelo (ML). É o funil de destilação de conhecimento: pega um corpus e o destila em LEARNINGS + SIGNALS. Mesma palavra, técnica completamente diferente. Quando alguém disser "o Alembic faz distillation", pergunte de quê.
o que você precisa? conhecimento frescoe específico → RAG poucos exemplos,na hora → in-context comportamento fixo,barato → fine-tune menor/mais rápidodestilação errar a ferramenta custa caro: fine-tune para fatos que mudam = retreino sem fim; RAG para estilo fixo = busca cara à toa
Árvore de decisão. A pergunta certa primeiro: o conhecimento muda? é específico? cabe em poucos exemplos? precisa ser menor?
quanto o Alembic POSSUI de cada estratégia (área de superfície) in-context owned · dominante fine-tune delegated RAG só escrita do índice gap (sem leitura) destilação gap (de modelo)
A aposta é clara: o Alembic é quase todo in-context. Fine-tune é delegado; RAG existe só pela metade; destilação de modelo não existe. Uma aposta coerente para uma camada de orquestração sobre modelos hospedados.
Exemplo guiado — escolhendo a ferramenta para a nossa unidade
1
Tarefa: a unidade precisa redigir uma petição no estilo de um escritório específico, citando teses recentes daquele escritório.
2
O estilo é estável e cabe em exemplos? Sim → in-context (soul + skills do AI Employee). Não justifica fine-tune.
3
As teses recentes mudam e são específicas do escritório? Sim → o caso de uso de RAG. Mas no Alembic hoje isso é gap: você as traria via funil de destilação ou as colocaria à mão no pack (L2/L3), não por busca vetorial.
4
Agora você tenta: e se a unidade tivesse que rodar 10.000×/dia, barata e com comportamento idêntico? Qual estratégia entra em cena? (Dica: pense em treinar um aluno menor.)
flashcard
Por que o orçamento do pack é "comparação, não corte"?
clique para virar
O pack mede o custo estimado, compara com o teto e devolve os dois números + withinBudget. Quem descarta camadas (ou falha fechado) é o chamador — o pack nunca trunca sozinho.
flashcard
Qual a "metade" do RAG que o Alembic não tem?
clique para virar
A metade de leitura: embed-da-query + cosine/topK + rerank. Ele constrói o índice (escrita) mas não há query vetorial em packages/.
flashcard
Vetor offline: semântico ou não?
clique para virar
Não. É um hash polinomial de 16 dimensões dos char-codes. Estável e reproduzível, mas mede bytes, não sentido. Semântico só no caminho --online.
flashcard
Memória: composta ou recuperada?
clique para virar
Composta. Filtra por pisos, ordena por data (recência) e corta por limite. Nunca ordena por similaridade à pergunta.
flashcard
Como uma gaveta não-ligada "nunca vaza"?
clique para virar
Por ausência estrutural: resolveMemoryBinding só entrega as stores declaradas; as demais recebem um leitor vazio. Sem leitor, não há o que consultar.
flashcard
alembic distill destila o quê?
clique para virar
Um corpus (T0→T3 → LEARNINGS/SIGNALS), não um modelo. "Distillation" aqui é metáfora de domínio, não a técnica de ML.

Use o seletor abaixo para descrever a sua necessidade e ver qual das quatro estratégias se encaixa — e o que o Alembic faz nesse caso.

1. O conhecimento que falta muda com frequência (é fresco)?
2. Ele cabe em poucos exemplos/instruções na janela?
3. Sua prioridade é custo/latência mínimos em altíssima escala?
responda acima
Escolha as opções para ver a recomendação

Demo: heurística de decisão. Não há "resposta universal" — a ferramenta certa depende das três perguntas. E o rótulo do Alembic (owned/delegated/gap) aparece junto.

An educational decision-tree illustration for choosing among four model-specialization strategies. A single root question node at the top branches with four arrows to four distinct
An educational decision-tree illustration for choosing among four model-specialization strategies. A single ro
6

Recapitule em slides


Os seis beats da lição, em sequência. Use as setas ou os pontos.

Engenharia de contexto

A pergunta certa não é "o que o modelo sabe?"

É o que cabe na janela, em que ordem, sob orçamento. A maior alavanca depois que o modelo está fixo.

O pack L0→L7

Estratifica para poder descartar

Do brief (L0) ao manifesto com hash (L7). Sob pressão, some de baixo pra cima. Orçamento é comparação, não corte.

L0L3L5L7 (hash)

O gap titular

Indexa, mas não recupera

Existe a metade de escrita (constrói o índice). Não existe a de leitura: zero cosine/topK/rerank em packages/.

Cuidado

O vetor offline não é semântico

Hash de char-codes, 16 dimensões. Mede bytes, não sentido. Semântico só no caminho --online.

Memória

Composta, não recuperada

Filtra → ordena por recência → corta. Gaveta não-ligada não tem leitor → nunca vaza.

Estratégia

Quatro ferramentas, não uma

Fine-tune · in-context (a aposta do Alembic) · RAG (gap) · destilação. Errar a ferramenta custa caro.

1 / 6setas
o razão desta lição: owned · delegated · gap OWNED • pack de contexto L0–L7 • orçamento = comparação • memória COMPOSTA • escrita do índice • in-context (dominante) DELEGATED • fine-tune dos pesos (gateway / MLX, fora da cintura) GAP (roadmap) • leitura/query vetorial • vetor semântico offline • rerank / freshness • destilação de MODELO (distill = de corpus, não)
A foto da lição inteira. Esquerda: o que confiar hoje. Centro: o que é de outra camada. Direita: onde o roadmap começa — e onde "self-learning" ainda não chegou.
As Dez sobre contexto, memória e RAG no Alembic
  1. Contexto é a maior alavanca de qualidade depois que o modelo está escolhido.
  2. O pack tem 8 camadas: L0 (brief) → L7 (manifesto com hash). Largura = volume.
  3. Orçamento é comparação (withinBudget), não truncamento automático.
  4. A estimativa de tokens é length/4 — régua grosseira, boa p/ descartar, ruim p/ encaixe exato.
  5. O L7 é hash de conteúdo → detecção de mudança e reprodutibilidade grátis.
  6. RAG tem duas metades; o Alembic só tem a de escrita (indexa, não recupera). É o gap nº 1.
  7. O vetor offline é um hash de char-codes de 16 dim — não é semântico.
  8. Memória é composta (recência), não recuperada (similaridade).
  9. Gaveta não-ligada não tem leitor → vaza nada (capacidade por ausência).
  10. Quatro estratégias: in-context (owned) · fine-tune (delegated) · RAG (gap) · destilação (de corpus, não de modelo).
Leve isto com você"RAG" no Alembic hoje = funil de destilação + pack de contexto montado à mão. Não é busca por similaridade. Saber onde o retrieval para é saber onde o roadmap começa — e essa honestidade é a diferença entre um harness confiável e marketing.
Você é o professor agora: pegue o backend offline e calcule à mão o primeiro componente do vetor de "oi" — convença-se de que é determinístico e não semântico. Dúvida boa para levar à próxima lição: se não medimos similaridade, como medimos qualidade? É exatamente o gap de evals — e os spans, e o custo — que a lição 0007 abre.
7

Revisão (verifique no boundary)


Três perguntas. A pontuação corre sozinha. Cada opção explica por que.

Checagem cumulativa
1. No pack de contexto, o que acontece quando estimatedTokens > maxTokens?
Correto: b. O pack mede e compara — carrega os dois números e o booleano. Ele nunca trunca sozinho (a) nem lança (c): a casa toda devolve Result, never-throws. Quem pisa no freio é o chamador.
2. Por que "o Alembic indexa mas não recupera"?
Correto: c. Um grep por cosine|topK|rerank|queryIndex|knn em packages/ volta vazio. Não é criptografia (a) nem delegação ao gateway (b) — a query vetorial simplesmente não foi construída. É o gap nº 1 do mapa.
3. Como a memória multi-store garante que uma gaveta não-ligada nunca vaze?
Correto: a. resolveMemoryBinding entrega só as stores declaradas; as demais recebem um leitor vazio. Não é um filtro em runtime que poderia falhar (b), nem criptografia (c) — é a mesma postura do MCP read-only: capacidade por ausência.
Acertos: 0/3
Confira você mesmo (a prova no boundary)
HARNESS-MAP.md §13/§20 + ai-engineering-from-scratch

Rode no repo: grep -rE "cosine|topK|rerank|queryIndex|knn" packages/ → vazio (confirma o gap). Abra packages/embeddings/src/offline-backend.tsOFFLINE_DIMENSION = 16 e o cabeçalho "NÃO é um embedding semântico real". Abra packages/hermes/src/memory/multi-store/composer.ts → o rank ordena por at (data), não por similaridade.