Read Pipeline¶
Quando você chama memory.retrieve(), o SDK busca tudo que sabe sobre um agente e retorna os fatos mais relevantes pra sua query - ranqueados, pontuados e formatados numa string que você pode colar direto num prompt de LLM.
Você não precisa entender os internals pra usar. Basta chamar retrieve() e usar result.context. Esta página explica o que acontece por baixo dos panos, pra quando você quiser ajustar o comportamento ou debugar resultados.
flowchart LR
A["Query"] --> B["Plan"]
B --> C["Retrieve\n(3 signals)"]
C --> D["Enhance"]
D --> E["Rerank"]
E --> F["RetrieveResult"]
Visão Geral¶
Toda chamada a memory.retrieve(agent_id, query) executa cinco estágios:
- Plan - Descobre o que buscar. Detecta saudações, padrões de agregação e queries amplas. Entity resolution roda deterministicamente em paralelo.
- Retrieve - Busca fatos usando três métodos em paralelo: similaridade de significado, match de palavras-chave e travessia do grafo de relacionamentos.
- Enhance - Expande o contexto seguindo relacionamentos entre entidades pra encontrar fatos relacionados que não foram diretamente matcheados.
- Rerank - Um LLM reavalia os top resultados e reordena pela relevância real pra sua query.
- Format - Comprime os fatos ranqueados numa string com orçamento de tokens, organizada por tiers de relevância.
Estágio 1: Planner Determinístico¶
Em português claro: Antes de buscar, o pipeline analisa sua query pra decidir que tipo de busca rodar. Detecta saudações (skip), queries de agregação ("quem são meus amigos?"), requests amplas ("me conta tudo") e identifica quais entidades são mencionadas. Tudo determinístico — mesma query sempre produz o mesmo plano, zero chamadas LLM.
O planner produz um RetrievalPlan usando regex pattern matching e lookups no schema. Nenhum LLM é envolvido.
Por que sem LLM no planner?
Antes da v0.13.0, o planner chamava um LLM pra reformulação de query e extração de entidades. Isso introduzia não-determinismo: a mesma query contra a mesma memória podia retornar fatos diferentes entre runs, porque APIs cloud de LLM não são determinísticas mesmo com temperature=0 (comportamento documentado — batching, fp16 rounding, roteamento de GPU introduzem variação). A v0.13.0 substitui o planner LLM por uma implementação totalmente determinística. A query vai direto pra busca semântica sem alteração, e extração de entidades é feita por um resolver determinístico dedicado.
O Que o Planner Decide¶
| Campo | Descrição | Exemplo |
|---|---|---|
strategy |
Estratégia de retrieval | "multi_signal" (padrão) ou "skip" (para saudações) |
similarity_query |
Query para busca semântica (sempre a original) | "onde eu moro?" (passada sem alteração) |
pattern_queries |
Padrões SQL LIKE para agregação | ["person:%"] (de "quem são meus amigos?") |
broad_query |
Se deve expandir o escopo do graph | true para "me conte tudo sobre..." |
reason |
Explicação da estratégia | "deterministic", "aggregation", "broad", "greeting" |
Entity Resolution¶
Quando você pergunta "Onde o Carlos mora?", o pipeline precisa descobrir que "Carlos" significa a entidade person:carlos no banco. Ele usa dois métodos determinísticos:
-
Resolução determinística (primária) — Faz match de palavras da query contra aliases de entidades conhecidas (
MemoryEntityAlias), display names (MemoryEntity.display_name) e slugs de entity_keys. Rápido (< 10ms), confiável, custo zero de LLM. Por exemplo, "Onde o Carlos mora?" resolve deterministicamente paraperson:carlosvia slug match. -
Query expansion (priming de aliases) —
expand_query()resolve aliases e busca vizinhos 1-hop no KG, adicionando entidades relacionadas.
Ambas as fontes são unificadas antes do graph gate. Se qualquer fonte identificar uma entidade, o graph traversal roda.
O trace step "retrieval" inclui um breakdown entities_sources mostrando quais entidades vieram de cada fonte (deterministic, expansion).
Detecção de Agregação¶
Para queries como "quem são meus amigos?" ou "meus projetos", o planner faz match de keywords contra prefixos do schema e gera padrões SQL LIKE (ex: person:%). Isso só dispara quando o prefixo realmente existe no schema do usuário.
Estratégia Skip¶
Para saudações e mensagens casuais ("oi", "bom dia", "e aí"), o planner retorna strategy: "skip" via regex matching, fazendo short-circuit no pipeline. Sem queries no banco, sem chamadas LLM, resposta instantânea.
Resolução de Anáfora (Responsabilidade do Caller)¶
Se sua query contém pronomes ("Onde ela mora?"), o Arandu SDK não resolve. Resolução de pronomes depende do contexto de conversa (memória de curto prazo), que é domínio do caller. Resolva pronomes antes de chamar retrieve():
# O caller (seu agente) resolve "ela" → "Ana" usando contexto de conversa
resolved_query = "Onde a Ana mora?" # não "Onde ela mora?"
result = await memory.retrieve(agent_id="user_123", query=resolved_query)
Paralelo com neurociência
O planner espelha pistas de recuperação na psicologia cognitiva. Quando você tenta lembrar algo, seu cérebro não faz uma busca exaustiva — ele usa pistas contextuais para estreitar o espaço de busca. O planner identifica entidades e detecta padrões de query como pistas que guiam os sinais de retrieval.
Passo a passo: ciclo de vida completo de uma query
Query: "Onde o Marcos Tavares mora?"
Estágio 1 — Planejamento (determinístico):
Check saudação: sem match → prossegue
Check agregação: sem match → sem pattern queries
Check broad: sem match → broad_query = false
Resolver determinístico: "marcos tavares" → person:marcos_tavares (slug match)
similarity_query = "Onde o Marcos Tavares mora?" (original, sem alteração)
Estágio 2 — Retrieval multi-signal (paralelo):
Semântico: embedding("Onde o Marcos Tavares mora?") → top match: "Marcos Tavares lives in Porto Alegre" (0.91)
Keyword: "marcos" + "tavares" → 4 fatos sobre Marcos
Graph: BFS a partir de person:marcos_tavares → encontra fatos via entity links + relationships
Estágio 3 — Enhancement:
Spreading activation: a partir do seed "lives in Porto Alegre" → encontra fatos relacionados:
"Marcos Tavares is married to Carolina" (via entity hop)
"Carolina is an architect" (via 2-hop)
Estágio 4 — Reranking (blend multiplicativo):
"Marcos Tavares lives in Porto Alegre" → formula=0.91, reranker=1.0 → final=0.91
"Marcos Tavares is a product manager at Vertix" → formula=0.65, reranker=0.2 → final=0.28
"Carolina is an architect" → formula=0.30, reranker=0.0 → final=0.09 → filtrado (< 0.15)
Estágio 5 — Formatação:
Resultado: 1 fato altamente relevante, 210ms, 800 tokens.
Estágio 2: Retrieval Multi-Signal¶
Em português claro: O pipeline busca fatos relevantes usando três métodos diferentes ao mesmo tempo - por significado, por palavras exatas e por conexões entre entidades. Isso captura fatos que qualquer método sozinho perderia.
Três sinais independentes rodam em paralelo via asyncio.gather(), cada um encontrando candidatos de um ângulo diferente:
flowchart TD
P["RetrievalPlan"] --> S["Semantic Search\n(pgvector cosine)"]
P --> K["Keyword Search\n(SQL ILIKE)"]
P --> G["Graph Traversal\n(BFS 2-hop)"]
S --> M["Merge & Rank\n(dedup + weighted scoring)"]
K --> M
G --> M
Sinal 1: Semantic Search¶
Usa similaridade de cosseno do pgvector para encontrar fatos cujos embeddings são próximos ao embedding da query.
- Embeds a query (passada sem alteração pelo planner)
- Busca na tabela
MemoryFactcom índice HNSW - Retorna top-N candidatos acima do threshold
min_similarity - Filtros:
agent_id, fatos ativos (valid_to IS NULL), confiança >=min_confidence
Este é o sinal primário - encontra fatos que são semanticamente similares à query, mesmo que não compartilhem keywords exatas.
Sinal 2: Keyword Search¶
Matching SQL ILIKE em fact_text para hits exatos ou parciais de keywords.
- Extrai palavras significativas (> 2 caracteres) da query
- Faz match contra o texto do fato (até 5 keywords)
- Score = fração de palavras da query encontradas no fato
Complementa a busca semântica capturando matches exatos que a similaridade de embedding pode perder (ex: nomes próprios, termos técnicos, abreviações).
Sinal 3: Graph Retrieval¶
Percorre relacionamentos de entidades para encontrar fatos conectados às entidades da query.
- Começa das entidades identificadas pelo planner
- Traversal BFS até 2 hops em
MemoryEntityRelationship - Hop decay: Fatos no Hop 1 recebem score completo (1.0×). Fatos no Hop 2 recebem penalidade de 0.5×. Isso evita que fatos distantes dominem o pool de candidatos.
- Fatos são buscados via entity links (
MemoryFactEntityLink), não só peloentity_keyprimário. Isso significa que um fato "Clara saiu da Vertix" (subject primário: Clara) também é encontrado ao buscar sobre Vertix - porque o fato tem um entity link secundário pra Vertix. - Fórmula de scoring:
edge_strength × recency_factor × edge_recency_factor × query_bonus × hop_decay query_bonus: 1.5x quando o nome da entidade aparece no texto da query- Fallback: se a tabela de entity links está vazia (pré-migration), retrieval faz fallback pra match direto por
entity_key
Graph retrieval se destaca em encontrar fatos contextuais. Quando você pergunta sobre uma pessoa, ele também encontra fatos sobre seu local de trabalho, seus relacionamentos e seus projetos.
Passo a passo: retrieval cross-entity via entity links
Query: "O que aconteceu com a Vertix?"
Sem entity links (comportamento antigo):
Graph começa de organization:vertix
Busca MemoryFact WHERE entity_key = 'organization:vertix'
Encontra: apenas fatos onde Vertix é o subject PRIMÁRIO
Perde: "Clara Rezende left Vertix" (entity_key = person:clara_rezende)
Com entity links (comportamento atual):
Graph começa de organization:vertix
Busca MemoryFactEntityLink WHERE entity_key = 'organization:vertix'
Encontra fact_ids linkados à Vertix, independente do subject primário:
→ "Clara Rezende left Vertix" (primário: Clara, link: Vertix) ✅
→ "Vertix received Series A of R$ 20M" (primário: Vertix) ✅
→ "Ricardo Gomes is co-founder of Vertix" (primário: Ricardo, link: Vertix) ✅
→ "Vertix signed contract with Ambev" (primário: Vertix) ✅
Resultado: 4 fatos encontrados vs 2 sem links. A query sobre Vertix traz fatos de Clara, Ricardo e o deal da Ambev - todos linkados à Vertix mas não primariamente sobre a Vertix.
Merge & Rank¶
Depois que os três sinais retornam, os resultados são mesclados:
- Deduplicar por fact ID (o mesmo fato pode aparecer em múltiplos sinais)
- Aplicar decay de recência - Decay exponencial com half-life configurável (
recency_half_life_days, padrão 14) - Aplicar decay de confiança - Fatos mais antigos com menor confiança são penalizados
- Calcular score combinado - Soma ponderada:
O reranker faz blend com estes pesos
Por padrão, enable_reranker=True - o reranker LLM usa um blend multiplicativo com o score da fórmula computado a partir destes pesos. O score da fórmula continua sendo importante porque o reranker só pode atenuar ou amplificar, nunca zerar. Configure enable_reranker=False para depender apenas destes pesos no ranking final.
score = (
score_weights["semantic"] * semantic_score + # default 0.70
score_weights["recency"] * recency_score + # default 0.20
score_weights["importance"] * importance_score # default 0.10
)
Breakdown Completo do Score¶
Cada fato é pontuado em múltiplas dimensões. Você pode inspecionar em fact.scores pra entender por que um fato ficou onde ficou no ranking:
Cada dict ScoredFact.scores contém todos os 6 sinais computados ao longo do pipeline. A fórmula ponderada acima produz o score combinado base; estágios posteriores adicionam sinais que podem modificar o ranking final:
| Chave | Origem | Range | Descrição |
|---|---|---|---|
semantic |
Busca semântica | 0.0 - 1.0 | Similaridade de cosseno entre embeddings da query e do fato. Sinal primário de retrieval. |
keyword |
Busca por keyword | 0.0 - 1.0 | Fração de palavras da query encontradas no texto do fato. Complementa semântico para matches exatos. |
recency |
Merge & Rank | 0.0 - 1.0 | Decay exponencial a partir do created_at, half-life = recency_half_life_days (padrão 14). |
importance |
Importância dinâmica | 0.0 - 1.0 | Valor raw de importância do banco de dados. Computado pelo job de importância em background a partir de frequência de retrieval, recência de uso, correções do usuário e participação em padrões. Começa em 0.5 para fatos novos e evolui ao longo do tempo. |
confidence |
Merge & Rank | 0.0 - 1.0 | Confiança efetiva após decay temporal. Presente no dict scores para debugging, mas NÃO faz parte da fórmula ponderada (score_weights usa apenas semantic, recency, importance). A confiança base é atribuída pelo LLM durante extração (tipicamente 0.95 para afirmações assertivas). Decai ao longo do tempo e é usada como filtro (min_confidence). |
reranker |
Reranking | 0.0 - 1.0 | Score de relevância baseado em LLM. Presente apenas quando enable_reranker=True. Float contínuo retornado pelo reranker LLM. |
Sinais adicionais computados durante enhancement (não estão em score_weights mas afetam o score final):
| Chave | Origem | Descrição |
|---|---|---|
pattern |
Enhancement | Boost aditivo para fatos com alto reinforcement_count (até +0.10). |
graph |
Graph traversal | Score do traversal BFS de 2 saltos em relacionamentos de entidades. |
Configuração¶
| Parâmetro | Default | Descrição |
|---|---|---|
topk_facts |
20 |
Máximo de fatos a retornar |
topk_events |
8 |
Máximo de eventos a considerar |
min_similarity |
0.20 |
Similaridade de cosseno mínima para resultados semânticos |
min_confidence |
0.55 |
Confiança mínima do fato |
recency_half_life_days |
14 |
Half-life para decay de recência |
score_weights |
Veja acima | Pesos para cada sinal de scoring |
min_score |
0.15 |
Score final mínimo para fatos retornados |
enable_reranker |
True |
Se deve usar reranking LLM |
Paralelo com neurociência
O retrieval multi-signal espelha spreading activation em redes semânticas (Collins & Loftus, 1975). Quando você pensa em "médico", a ativação se espalha para conceitos relacionados ("hospital", "remédio", "consulta") através de links associativos. Da mesma forma, graph retrieval se espalha a partir de entidades da query ao longo de arestas de relacionamento, enquanto busca semântica ativa fatos através de proximidade de embedding.
Estágio 3: Enhancement¶
Em português claro: Depois de encontrar os resultados iniciais, o pipeline segue conexões pra descobrir fatos relacionados. Se você pergunta sobre uma pessoa, ele pode puxar fatos sobre o trabalho dela, projetos e equipe - coisas que você não perguntou diretamente mas que adicionam contexto útil.
Spreading Activation¶
A partir dos top-K fatos semente, o pipeline expande o contexto seguindo relacionamentos de entidades:
- Para cada fato semente, encontra os relacionamentos da entidade
- Percorre relacionamentos por N hops (
spreading_activation_hops, padrão 2). Defina como0para desabilitar spreading completamente. - Aplica fator de decay por hop (
spreading_decay_factor, padrão 0.50). Hop 1 usa o fator diretamente; Hop 2 usa o fator ao quadrado (decay composto). - Retorna até
spreading_facts_per_entityfatos adicionais por entidade (padrão 3), aplicado tanto no Hop 1 quanto no Hop 2.
Isso captura contexto importante que não foi diretamente matcheado. Se você perguntar "o que o Rafael faz?", spreading activation pode trazer fatos sobre seu local de trabalho, time e projetos.
Quando o spreading activation faz diferença?
O spreading tem mais impacto com 20+ entidades e relações cruzadas entre domínios (ex: pessoas → projetos → clientes → tecnologias). Com datasets pequenos (< 15 entidades), os sinais semântico, keyword e graph já cobrem todo o espaço de fatos - o spreading pode retornar candidatos mas eles serão dedupados contra os resultados existentes. Os campos do trace spreading_candidates_returned e spreading_candidates_unique permitem confirmar se o spreading está contribuindo fatos novos pro seu dataset.
Sinal de Padrão¶
Fatos com alto reinforcement_count (incrementado por decisões NOOP no write) recebem um boost aditivo no score:
- Alto reinforcement count → até 0.10 de score extra
- Captura fatos frequentemente mencionados e bem estabelecidos
Configuração¶
| Parâmetro | Default | Descrição |
|---|---|---|
spreading_activation_hops |
2 |
Máximo de hops a partir de fatos semente. Defina como 0 para desabilitar. |
spreading_decay_factor |
0.50 |
Decay de score por hop. Hop 1 = fator, Hop 2 = fator² |
spreading_facts_per_entity |
3 |
Máximo de fatos buscados por entidade no Hop 1 e Hop 2 |
spreading_max_related_entities |
5 |
Máximo de entidades KG-relacionadas exploradas no Hop 1 |
Estágio 4: Reranking (Opcional)¶
Em português claro: Os estágios anteriores encontram fatos relevantes, mas o ranking é baseado em matemática (scores de similaridade, keyword overlap). O reranker pergunta a um LLM: "Dado o que essa pessoa tá perguntando, quais desses fatos são realmente mais úteis?" Isso produz um ranking final mais inteligente.
Quando enable_reranker=True, os top candidatos são rerankeados por um LLM que considera a intenção da query:
- O reranker avalia 2×
topk_factscandidatos (padrão: 40). Esse pool expandido garante que fatos semanticamente relevantes além do top-20 inicial cheguem no reranker. Aumentetopk_factspra expandir a cobertura do reranker. - Respeita o significado semântico da query (não apenas overlap de keywords)
- Pode promover fatos que são indiretamente relevantes mas importantes
- Degradação graceful: se o reranker falhar ou exceder
reranker_timeout_sec(padrão 5.0s), o ranking original é preservado - O timeout é enforced via
asyncio.wait_for- a chamada LLM é cancelada se exceder o timeout configurado - Usa o mesmo provider LLM configurado no client (não precisa de provider separado)
O reranker é o estágio mais custoso, mas fornece a maior melhoria de qualidade para queries complexas.
Configuração¶
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
reranker_weight |
float | 0.70 |
Peso do score do reranker no blend multiplicativo |
min_reranker_score |
float | 0.10 |
Score mínimo do reranker; fatos abaixo são eliminados |
reranker_timeout_sec |
float | 5.0 |
Timeout para a chamada LLM do reranker (segundos) |
Veto do reranker: min_reranker_score
Quando enable_reranker=True, qualquer fato que recebe um score do reranker abaixo de min_reranker_score (padrão 0.10) é eliminado dos resultados (final_score definido como 0.0). Isso dá ao reranker poder de veto sobre fatos completamente irrelevantes - mesmo que o score da fórmula seja alto (ex: graph BFS dá 0.80 pra um fato distante e não relacionado). Quando enable_reranker=False, esta configuração não tem efeito. Ajuste: config_overrides={"min_reranker_score": 0.05} para resultados mais permissivos, 0.20 para filtragem mais rigorosa.
Scoring por multiplicative blend
O reranker NÃO substitui o score da fórmula. Ele usa um blend multiplicativo:
final_score = formula_score × (floor + reranker_weight × reranker_score)
onde floor = 1 - reranker_weight. Com o default reranker_weight=0.70, um fato com formula=0.9 e reranker=0.0 fica com final = 0.9 × (0.30 + 0) = 0.27 (não 0.0). Um fato com formula=0.9 e reranker=1.0 fica com final = 0.9 × (0.30 + 0.70) = 0.90. O reranker pode amplificar ou atenuar fatos mas não consegue zerar um fato com bons sinais de retrieval apenas pelo blend. Porém, min_reranker_score É uma exceção - fatos com score abaixo dele são zerados independentemente do score da fórmula. O dict scores preserva tanto formula (pré-reranker) quanto reranker (score do LLM) pra debugging.
Passo a passo: como o blend do reranker funciona
Query: "Qual o time de futebol do Bruno Almeida?"
Candidatos pré-reranker (scores da fórmula):
1. "Bruno Almeida runs marathons" → formula = 0.45 (semântico: similaridade com "sports")
2. "Bruno Almeida developed an ML model" → formula = 0.38
3. "Bruno Almeida works at Orion Tech" → formula = 0.35
Scores do reranker (avaliação do LLM):
1. "Bruno Almeida runs marathons" → reranker = 0.0 (maratona ≠ futebol)
2. "Bruno Almeida developed an ML model" → reranker = 0.0 (irrelevante)
3. "Bruno Almeida works at Orion Tech" → reranker = 0.0 (irrelevante)
Blend multiplicativo (weight=0.70, floor=0.30):
1. final = 0.45 × (0.30 + 0.70 × 0.0) = 0.45 × 0.30 = 0.135 → filtrado (< 0.15)
2. final = 0.38 × 0.30 = 0.114 → filtrado
3. final = 0.35 × 0.30 = 0.105 → filtrado
Resultado: 0 fatos retornados. Correto - não existe informação sobre o time de futebol do Bruno na memória.
Compare com uma query relevante - "O que o Bruno Almeida desenvolveu?":
Estágio 5: Formatação¶
Em portugues claro: O pipeline pega os fatos ranqueados e organiza numa string limpa, pronta pra consumo por LLM. O formato foi projetado para ser direto e sem ruido -- fatos aparecem como uma lista simples em "Known facts:", conversas relevantes em "Relevant conversations:", e padroes observados em "Observed patterns:". Tudo dentro de um orcamento de tokens pra nao estourar seu prompt.
Formato de Contexto¶
O contexto e organizado em tres secoes dentro de um orcamento de tokens (context_max_tokens):
context_max_tokens e um orcamento proporcional, nao um limite rigido
O parametro context_max_tokens controla o tamanho relativo do contexto de saida, mas a contagem real de tokens pode exceder o valor configurado. O pipeline garante um contexto minimo para fatos e usa o parametro como orcamento proporcional entre secoes. Trate como um target, nao um limite estrito.
| Secao | Conteudo |
|---|---|
| Known facts | Lista limpa de fatos, ordenados por score. Sem timestamps, sem prefixo de entidade, sem qualificadores como "assert confidently" |
| Observed patterns | Meta-observations (padroes, tendencias, insights detectados pelos background jobs) |
| Relevant conversations | Texto original de eventos recentes (ate 300 caracteres cada), com data |
O formato foi projetado para consumo direto por LLMs -- limpo, sem ruido, sem metadados desnecessarios.
Perfis de entidade nao sao injetados no contexto
Perfis de entidade (profile_text) sao usados internamente pelo write pipeline como contexto para a extracao informada. Eles nao sao incluidos no contexto de retrieval retornado por retrieve(). O retrieval retorna apenas fatos individuais, padroes e eventos.
Configuracao¶
| Parametro | Default | Descricao |
|---|---|---|
context_max_tokens |
2000 |
Maximo de tokens no contexto formatado |
hot_tier_ratio |
0.50 |
Parcela do orcamento para fatos com scores mais altos |
warm_tier_ratio |
0.30 |
Parcela do orcamento para fatos de suporte |
Formato de Output¶
A string context e formatada para injecao direta em prompts LLM:
Known facts:
- Lives in Sao Paulo
- Works at Acme Corp as a backend engineer
- Wife's name is Ana
Observed patterns:
- Prefers working late at night
Relevant conversations:
- (2026-03-28) Had a great meeting with the product team about the roadmap...
RetrieveResult¶
result = await memory.retrieve(agent_id="user_123", query="...")
# Contexto pré-formatado (pronto para prompts LLM)
print(result.context)
# Fatos individuais com scores
for fact in result.facts:
print(f"[{fact.score:.2f}] {fact.entity_name}: {fact.fact_text}")
print(f" Scores: {fact.scores}") # {"semantic": 0.85, "recency": 0.72, ...}
# Stats do pipeline
print(f"Candidates evaluated: {result.total_candidates}")
print(f"Duration: {result.duration_ms:.0f}ms")
Diagrama do Pipeline (Completo)¶
flowchart TD
Q["User query"] --> AG["Planner Determinístico\n(regex + schema)"]
AG -->|skip| SKIP["Return empty\n(greeting/casual)"]
AG -->|multi_signal| PAR["Parallel retrieval"]
PAR --> SEM["Semantic Search\n(pgvector cosine)"]
PAR --> KW["Keyword Search\n(SQL ILIKE)"]
PAR --> GR["Graph Traversal\n(BFS 2-hop)"]
SEM --> MERGE["Merge & Rank\n(dedup + weighted scoring)"]
KW --> MERGE
GR --> MERGE
MERGE --> SA["Spreading Activation\n(expand context along edges)"]
SA --> RR{"Reranker\nenabled?"}
RR -->|yes| RERANK["LLM Rerank"]
RR -->|no| FMT["Format & Compress"]
RERANK --> FMT
FMT --> RES["RetrieveResult"]
Paralelo com neurociencia
O orcamento de tokens age como o limite de capacidade da working memory. Fatos com scores mais altos recebem prioridade (foco de atencao), enquanto padroes e eventos fornecem contexto de suporte. Isso espelha o modelo de processos embutidos de Cowan, onde um numero pequeno de itens esta no foco de atencao, cercado por memoria de longo prazo ativada.