HyDE é opt-in (
CHATCLI_QUALITY_HYDE_ENABLED=true) para manter o steady-state sem custo adicional. Phase 3a custa +1 LLM call cheap; Phase 3b requer configurar um embedding provider.O problema que HyDE resolve
O retrieval dememory.Fact pré-pipeline era keyword-only: o scorer bate tokens extraídos de mensagens recentes contra tags e content dos facts armazenados. Funciona bem quando o vocabulário bate exatamente — falha quando o usuário usa sinônimos ou faz perguntas abstratas.
Exemplo do gap:
- Sem HyDE
- Com HyDE 3a
- Com HyDE 3b
Usuário:
Keywords extraídas:
Fact armazenado:
Match: ❌ — “fazer” e “go” não aparecem literalmente no fact.
como fazer X em Go?Keywords extraídas:
[fazer, go]Fact armazenado:
"use goroutines for concurrency in X pipelines"Match: ❌ — “fazer” e “go” não aparecem literalmente no fact.
Phase 3a — Hypothesis-based keyword expansion
LLM gera hipótese curta
Prompt: “Write a 2-4 sentence plausible answer that uses the technical nouns that would appear in any matching note. Bilingual if the query mixes languages.”
ExtractKeywords da hipótese
O mesmo extractor já usado no chat mode (stop words en+pt, min 3 chars).
Merge unique + lower-case
Keywords originais + top-N da hipótese, cap configurável via
CHATCLI_QUALITY_HYDE_NUM_KEYWORDS (default 5).Phase 3b — Vector embeddings
Adiciona busca por cosine similarity sobre embeddings de facts.Arquitetura
Providers suportados
- Voyage (recomendado)
- OpenAI
- Null (default)
voyage-3, 1024-dim) é o sweet spot geral.Vector store pure-Go
Sem CGO, sem SQLite-vec, sem dependências externas. Só
float32[] + cosseno + persistência JSON em ~/.chatcli/memory/vector_index.json.N < 1000 facts (o caso típico do chatcli), a busca linear em memória completa em microssegundos. Sem necessidade de índice HNSW ou IVFFlat.
Dimension lock
Trocar de provider (Voyage 1024 → OpenAI 1536) não é automático: o store rejeita com erro explicativo. Razão: cosine entre vetores de dimensões diferentes é inválido matematicamente.Lazy backfill
Ao retrieve uma fact, se ela não tem vetor (fact pré-existe à ativação de embeddings), o index spawna goroutine detached para embedar as top-25 facts visíveis:Configuração completa
| Env var | Default | O que faz |
|---|---|---|
CHATCLI_QUALITY_HYDE_ENABLED | false | Master switch (phase 3a) |
CHATCLI_QUALITY_HYDE_USE_VECTORS | false | Liga phase 3b (requer provider) |
CHATCLI_QUALITY_HYDE_PROVIDER | — | Provider name para display |
CHATCLI_QUALITY_HYDE_NUM_KEYWORDS | 5 | Cap de keywords da hipótese em phase 3a |
CHATCLI_EMBED_PROVIDER | — | voyage|openai|null |
CHATCLI_EMBED_MODEL | provider default | Ex: voyage-3, text-embedding-3-small |
CHATCLI_EMBED_DIMENSIONS | provider default | Só para OpenAI |
/config quality expõe o estado
Integração com Reflexion
HyDE amplifica o valor de Reflexion: as lições persistidas pela #3 são recuperadas com muito mais recall quando a próxima tarefa não usa exatamente as mesmas keywords. Workflow:Turn 1: refactor auth.go falha (timeout)
Reflexion persiste lesson:
"use Edit tool for large files", tags [go, refactor, edit-tool].Turn 5 (dias depois): 'me ajuda a dividir pkg/engine'
Query não contém
refactor ou edit. Keyword-only perderia a lesson.HyDE 3a gera hipótese
"To split a Go package, identify logical groupings and use refactor patterns with Edit tool for surgical changes..."Keywords extraídas:
[split, package, refactor, edit, patterns, …]Caveats e tuning
Fallback gracioso: se o LLM fail ou o provider embedding retornar erro, o retrieval cai para keyword-only silenciosamente. Nenhum turn é abortado por falha de HyDE.
Leia também
#3 Reflexion
As lições que HyDE recupera com mais recall.
Bootstrap Memory
A camada embaixo: como memory.Fact é populada e mantida.
Persistent Context
/context attach para contextos explícitos de arquivos.Configuração completa
Todos os env e slashes.