Data: 19 de Dezembro de 2025
Versão Analisada: V4.0.0
Escopo: Performance, Velocidade, Confiabilidade, Automações e Workflows
A V4 é uma arquitetura bem pensada com implementações sólidas, mas possui 8 bugs críticos, 12 inconsistências e 15 oportunidades de melhoria que impactam performance e confiabilidade.
Impacto Estimado:
- 🔴 Crítico: 3 bugs que causam falhas
- 🟠 Alto: 5 bugs que degradam performance
- 🟡 Médio: 12 inconsistências que causam comportamento inesperado
- 🟢 Baixo: 15 melhorias que otimizam velocidade/confiabilidade
Arquivo: memory-types-v4.service.ts (linha 95)
Severidade: 🔴 CRÍTICO
// ❌ PROBLEMA
const result = await query<{ id: string }>(
`INSERT INTO memories_v4 (...) VALUES ($1, $2, $3, $4, $5, $6)`,
[userId, memory.type, memory.content, JSON.stringify(embedding), ...]
);Problema: Embedding é um array de números, mas está sendo convertido para JSON string. PostgreSQL espera um vetor (vector type), não uma string JSON.
Impacto: Inserção falha ou embedding não é indexado corretamente, causando buscas semânticas lentas/ineficazes.
Fix:
// ✅ CORRETO
const embeddingVector = `[${embedding.join(',')}]`; // Formato correto para pgvector
const result = await query<{ id: string }>(
`INSERT INTO memories_v4 (..., embedding) VALUES ($1, $2, $3, $4::vector, $5, $6)`,
[userId, memory.type, memory.content, embeddingVector, ...]
);Arquivo: hybrid-retrieval-v4.service.ts (linha 120)
// ❌ PROBLEMA
const result = await query<any>(sql, params);
return result.map((row: any) => ({
memory: this.rowToMemory(row),
score: parseFloat(row.similarity) || 0,
}));Problema: row.similarity é calculado como 1 - (embedding <=> $2::vector), mas se o embedding for NULL ou inválido, retorna NULL. O parseFloat(null) retorna NaN, não 0.
Impacto: Scores inválidos causam ranking incorreto de resultados.
Fix:
// ✅ CORRETO
score: row.similarity ? parseFloat(row.similarity) : 0,Arquivo: agent-factory-v4.ts (linha 65)
// ❌ PROBLEMA
private buildCacheKey(type: AgentType, config: AgentConfig): string {
return `${type}:${config.userId}`;
}Problema: Cache key não inclui contexto (userName, conversationHistory). Dois usuários diferentes com mesmo agentType podem compartilhar cache.
Impacto: Vazamento de contexto entre usuários, respostas incorretas.
Fix:
// ✅ CORRETO
private buildCacheKey(type: AgentType, config: AgentConfig): string {
const contextHash = this.hashContext({
userName: config.userName,
historyLength: config.conversationHistory?.length || 0,
});
return `${type}:${config.userId}:${contextHash}`;
}
private hashContext(context: any): string {
return require('crypto')
.createHash('md5')
.update(JSON.stringify(context))
.digest('hex')
.substring(0, 8);
}Arquivo: span-service-v4.ts (linha 95)
// ❌ PROBLEMA
updatesList.push(`completed_at = NOW()`);
params.push(spanId);
await query(
`UPDATE agent_spans_v4
SET ${updatesList.join(', ')}
WHERE id = $${paramIndex}`,
params
);Problema: paramIndex não é incrementado para completed_at = NOW(), causando desalinhamento de parâmetros SQL.
Impacto: Erro SQL ao completar spans, tracing quebrado.
Fix:
// ✅ CORRETO
updatesList.push(`completed_at = NOW()`);
params.push(spanId);
await query(
`UPDATE agent_spans_v4
SET ${updatesList.join(', ')}
WHERE id = $${paramIndex + 1}`,
params
);Arquivo: unified-master-agent-v2.ts (linha 1200)
// ❌ PROBLEMA
const similarMemories = await searchSimilarMemories(
userId,
queryEmbedding,
5,
threshold
);Problema: searchSimilarMemories não tem timeout. Se a busca travar, bloqueia todo o processamento.
Impacto: Timeout global de 120s pode ser atingido apenas na Memory-First check.
Fix:
// ✅ CORRETO
const similarMemories = await Promise.race([
searchSimilarMemories(userId, queryEmbedding, 5, threshold),
new Promise<any[]>((_, reject) =>
setTimeout(() => reject(new Error('Memory search timeout')), 2000)
),
]).catch(() => []);Arquivo: reasoning-modes-v4.service.ts (linha 20)
// ❌ PROBLEMA
fast: {
model: 'gemini-2.5-flash',
temperature: 0.7,
maxTokens: 1000,
},Problema: gemini-2.5-flash é o modelo padrão, não o mais rápido. Deveria usar gemini-2.5-flash-lite para fast mode.
Impacto: Fast mode não é tão rápido quanto poderia ser (~500ms vs ~200ms).
Fix:
// ✅ CORRETO
fast: {
model: 'gemini-2.5-flash-lite',
temperature: 0.7,
maxTokens: 800,
},Arquivo: workflow-capture-v4.service.ts (linha 80)
// ❌ PROBLEMA
private generateHash(signature: WorkflowSignature): string {
const hashInput = JSON.stringify({...});
let hash = 0;
for (let i = 0; i < hashInput.length; i++) {
const char = hashInput.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash).toString(36);
}Problema: Hash simples tem alta taxa de colisão. Dois workflows diferentes podem ter o mesmo hash.
Impacto: Workflows são sobrescritos incorretamente, cache ineficaz.
Fix:
// ✅ CORRETO
import crypto from 'crypto';
private generateHash(signature: WorkflowSignature): string {
const hashInput = JSON.stringify({...});
return crypto.createHash('sha256').update(hashInput).digest('hex').substring(0, 16);
}Arquivo: hybrid-retrieval-v4.service.ts (linha 200)
// ❌ PROBLEMA
const result = await query(sql, params);
return (result as any[]).map((row: any) => ({
memory: this.rowToMemory(row),
score: (row.entity_overlap || 0) / queryEntities.length,
}));Problema: Divisão por queryEntities.length pode ser 0 se nenhuma entidade for extraída. Além disso, entity_overlap pode ser NULL.
Impacto: Scores inválidos (Infinity, NaN), ranking quebrado.
Fix:
// ✅ CORRETO
score: queryEntities.length > 0
? ((row.entity_overlap || 0) / queryEntities.length)
: 0,Arquivo: agent-factory-v4.ts (linha 85)
// ❌ PROBLEMA
if (this.cache.size >= this.MAX_CACHE_SIZE) {
const leastUsed = Array.from(this.cache.entries())
.sort((a, b) => a[1].accessCount - b[1].accessCount)[0];
if (leastUsed) {
this.cache.delete(leastUsed[0]);
}
}Problema: Cria array de todas as entradas e ordena (O(n log n)) toda vez que cache fica cheio. Com 50 agentes, isso é lento.
Impacto: Overhead de cache management, latência aumenta quando cache fica cheio.
Fix:
// ✅ CORRETO
if (this.cache.size >= this.MAX_CACHE_SIZE) {
let leastUsed: [string, AgentCacheEntry] | null = null;
let minCount = Infinity;
for (const entry of this.cache.entries()) {
if (entry[1].accessCount < minCount) {
minCount = entry[1].accessCount;
leastUsed = entry;
}
}
if (leastUsed) {
this.cache.delete(leastUsed[0]);
}
}Arquivo: unified-master-agent-v2.ts (linha 45)
// ❌ PROBLEMA
const SUPERMEMORY_CACHE_TTL_MS = 300_000; // 5 minutosProblema: 5 minutos é muito longo. Se o usuário atualizar uma memória, a cache antiga será usada por até 5 minutos.
Impacto: Dados desatualizados, experiência ruim.
Fix:
// ✅ CORRETO
const SUPERMEMORY_CACHE_TTL_MS = 60_000; // 1 minuto (ou 30s para dados críticos)Arquivo: memory-types-v4.service.ts
Não há validação se memory.content é vazio ou muito longo. Pode causar erros silenciosos.
Fix:
async retain(userId: string, memory: MemoryV4): Promise<string> {
if (!memory.content || memory.content.trim().length === 0) {
throw new Error('Memory content cannot be empty');
}
if (memory.content.length > 50000) {
throw new Error('Memory content exceeds maximum length (50KB)');
}
// ... resto do código
}Arquivo: hybrid-retrieval-v4.service.ts (linha 240)
// ❌ PROBLEMA
private reciprocalRankFusion(
results: Array<Array<{ memory: MemoryV4; score: number }>>
): Array<{ memory: MemoryV4; score: number }> {
const k = 60;
const fused = new Map<string, { memory: MemoryV4; score: number }>();
for (const resultList of results) {
resultList.forEach((item, index) => {
const rank = index + 1;
const score = 1 / (k + rank);
// ...
});
}
return Array.from(fused.values())
.sort((a, b) => b.score - a.score);
}Problema: Scores finais não são normalizados (0-1). Se uma estratégia retornar 0 resultados, os scores das outras estratégias serão muito altos.
Fix:
// ✅ CORRETO
const results = Array.from(fused.values())
.sort((a, b) => b.score - a.score);
const maxScore = results[0]?.score || 1;
return results.map(r => ({
...r,
score: r.score / maxScore, // Normalizar para 0-1
}));Arquivo: span-service-v4.ts
Não há índices criados na migration para agent_spans_v4. Queries podem ser lentas.
Fix: Adicionar à migration:
CREATE INDEX idx_agent_spans_v4_user_id ON agent_spans_v4(user_id);
CREATE INDEX idx_agent_spans_v4_trace_id ON agent_spans_v4(trace_id);
CREATE INDEX idx_agent_spans_v4_started_at ON agent_spans_v4(started_at DESC);Arquivo: unified-master-agent-v2.ts (linha 150)
// ❌ PROBLEMA
const FAST_PATH_PATTERNS = {
time: [/^(que|qual)\s*(hora|horas)\s*(s[aã]o|[eé]|agora)?[?\\s]*$/i, ...],
greeting: [/^(ol[aá]|oi|hey|hi|hello|e\\s*a[ií]|fala|bom\\s*dia|boa\\s*tarde|boa\\s*noite)[!\\s,]*$/i, ...],
// ...
};Problema: Padrões são muito específicos. "Que horas são agora?" não bate porque tem "agora" no final. Muitas queries legítimas caem no roteamento IA.
Impacto: Fast-path não é tão eficaz quanto poderia ser.
Fix: Usar padrões mais flexíveis:
const FAST_PATH_PATTERNS = {
time: [/\b(que|qual)\s*(hora|horas)\b/i, /\bhora\s*atual\b/i, ...],
greeting: [/^(ol[aá]|oi|hey|hi|hello)/i, /\b(bom\s*dia|boa\s*tarde|boa\s*noite)\b/i, ...],
};Arquivo: workflow-capture-v4.service.ts
Não há mecanismo para limpar workflows antigos/não usados. Cache cresce indefinidamente.
Fix: Adicionar cleanup:
async cleanup(userId: string, maxAge: number = 30 * 24 * 60 * 60 * 1000): Promise<number> {
const result = await query<{ count: number }>(
`DELETE FROM workflow_cache_v4
WHERE user_id = $1 AND last_used_at < NOW() - INTERVAL '30 days'
RETURNING COUNT(*) as count`,
[userId]
);
return result[0]?.count || 0;
}Arquivo: reasoning-modes-v4.service.ts
Se gemini-3.0-pro não estiver disponível, o sistema falha. Não há fallback.
Fix:
createLLM(mode: ReasoningMode): ChatGoogleGenerativeAI {
const apiKey = getSystemGoogleKey();
if (!apiKey) throw new Error('Google AI API key not configured');
let config = this.getConfig(mode);
// Fallback se modelo não estiver disponível
const availableModels = process.env.AVAILABLE_MODELS?.split(',') || [];
if (availableModels.length > 0 && !availableModels.includes(config.model)) {
console.warn(`[ReasoningModesV4] Model ${config.model} not available, using fallback`);
config = { ...config, model: availableModels[0] };
}
return new ChatGoogleGenerativeAI({
model: config.model,
temperature: config.temperature,
maxTokens: config.maxTokens,
apiKey,
});
}Arquivo: memory-types-v4.service.ts
Não há verificação se uma memória similar já existe. Pode haver duplicatas.
Fix:
async retain(userId: string, memory: MemoryV4): Promise<string> {
// Verificar se memória similar já existe
const similar = await this.recall(userId, memory.content, {
memoryTypes: [memory.type],
limit: 1,
});
if (similar.length > 0 && similar[0].score > 0.95) {
console.log('[MemoryTypesV4] Similar memory already exists, skipping');
return similar[0].memory.id || '';
}
// ... resto do código
}Arquivo: hybrid-retrieval-v4.service.ts (linha 160)
// ❌ PROBLEMA
const result = await query<any>(sql, params);
return result.map((row: any) => ({
memory: this.rowToMemory(row),
score: parseFloat(row.rank) || 0,
}));Problema: Se a busca full-text não encontrar nada, retorna array vazio. Sem fallback.
Fix:
// ✅ CORRETO
const result = await query<any>(sql, params);
if (result.length === 0) {
// Fallback: busca simples por LIKE
const fallbackResult = await query<any>(
`SELECT ... FROM memories_v4 WHERE user_id = $1 AND content ILIKE $2 LIMIT $3`,
[userId, `%${queryText}%`, limit]
);
return fallbackResult.map(row => ({
memory: this.rowToMemory(row),
score: 0.5, // Score mais baixo para fallback
}));
}
return result.map(row => ({...}));Arquivo: unified-master-agent-v2.ts (linha 1100)
// ❌ PROBLEMA
private convertHistoryToMessages(
history?: Array<{ role: string; content: string }>
): Array<{ role: 'user' | 'assistant'; content: string }> {
if (!history || history.length === 0) {
return [];
}
const recentHistory = history.slice(-20);
return recentHistory.map(msg => ({...}));
}Problema: Limite de 20 mensagens é fixo. Se cada mensagem tiver 5KB, são 100KB de contexto. Pode causar timeout.
Fix:
// ✅ CORRETO
private convertHistoryToMessages(
history?: Array<{ role: string; content: string }>
): Array<{ role: 'user' | 'assistant'; content: string }> {
if (!history || history.length === 0) {
return [];
}
const MAX_CONTEXT_SIZE = 50000; // 50KB máximo
let totalSize = 0;
const messages = [];
for (let i = history.length - 1; i >= 0; i--) {
const msg = history[i];
const msgSize = msg.content.length;
if (totalSize + msgSize > MAX_CONTEXT_SIZE) break;
messages.unshift({
role: msg.role === 'user' ? 'user' : 'assistant',
content: msg.content,
});
totalSize += msgSize;
}
return messages;
}Arquivo: agent-factory-v4.ts
Não há verificação de uso de memória. Cache pode crescer indefinidamente.
Fix:
private addToCache(key: string, agent: LangChainBaseAgent, userId: string): void {
// Verificar uso de memória
const memUsage = process.memoryUsage();
const heapUsedPercent = memUsage.heapUsed / memUsage.heapTotal;
if (heapUsedPercent > 0.9) {
console.warn('[AgentFactoryV4] Heap usage > 90%, clearing cache');
this.cache.clear();
}
// ... resto do código
}Não gerar embeddings para todas as memórias na busca. Gerar sob demanda.
Impacto: -30% latência em buscas com muitos resultados
Ao invés de inserir spans um por um, fazer batch insert.
Impacto: -50% latência em tracing
Cachear embeddings de queries frequentes.
Impacto: -80% latência para queries repetidas
Criar índices em (user_id, memory_type, created_at) para buscas mais rápidas.
Impacto: -40% latência em buscas filtradas
Ajustar timeout baseado em histórico de latência do usuário.
Impacto: -20% timeouts falsos
Comprimir histórico de chat antes de enviar ao LLM.
Impacto: -25% tokens, -15% custo
Pré-carregar agentes mais usados na inicialização.
Impacto: -50% latência para agentes frequentes
Se Supermemory falhar 3x, desabilitar por 5 minutos.
Impacto: -10s latência em caso de falha
Não salvar spans duplicados (mesma query, mesmo resultado).
Impacto: -60% tamanho do banco de spans
Não bloquear resposta esperando tracing completar.
Impacto: -100ms latência por resposta
Usar BM25 para reranking ao invés de RRF.
Impacto: +15% relevância de resultados
Começar a enviar resposta enquanto agente ainda está processando.
Impacto: -50% latência percebida
Aumentar pool de conexões PostgreSQL.
Impacto: -30% latência em picos
Detectar queries anormais (muito longas, muitos tokens) e rejeitar.
Impacto: -20% timeouts
Manter histórico de versões de workflows para rollback.
Impacto: +10% confiabilidade
| Categoria | Quantidade | Impacto | Prioridade |
|---|---|---|---|
| Bugs Críticos | 5 | 🔴 Falhas | P0 |
| Bugs Performance | 5 | 🟠 -30% latência | P1 |
| Inconsistências | 10 | 🟡 Comportamento inesperado | P2 |
| Melhorias | 15 | 🟢 +20-50% performance | P3 |
- ✅ Corrigir bugs críticos (1-5)
- ✅ Adicionar timeouts em Memory-First
- ✅ Corrigir embedding format
- ✅ Corrigir bugs de performance (6-10)
- ✅ Adicionar índices no banco
- ✅ Implementar circuit breaker
- ✅ Resolver inconsistências (11-20)
- ✅ Implementar melhorias (21-30)
- ✅ Testes E2E completos
- ✅ Implementar streaming
- ✅ Otimizações avançadas (31-35)
- ✅ Monitoramento em produção
A V4 é uma arquitetura sólida com boas ideias (lazy loading, memory types, hybrid retrieval), mas precisa de correções críticas antes de produção. Os 5 bugs críticos causarão falhas em produção se não forem corrigidos.
Recomendação: Não fazer deploy em produção até corrigir bugs P0 (Fase 1).