Blog
AI/Voice
25 de janeiro de 202610 min

Memória de IA: histórico de conversas e tokens

Pontos-chave a reter: Dar memória a uma IA conversacional baseia-se em três mecanismos: uma janela deslizante com prioridades (prompt do sistema + últimas trocas sempre incluídas), um orçamento de tokens controlado para gerir os custos (uma conversa de 10 trocas custa 5x mais), e um sistema de fallback entre modelos LLM para garantir a disponibilidade. Esta é a diferença entre uma ferramenta e um verdadeiro assistente.

A primeira versão da IA no TAMSIV era amnésica. "Adiciona pão à minha lista de compras" funcionava perfeitamente. Mas continuar com "Coloca-a para amanhã" falhava miseravelmente — a IA não sabia de que tarefa se estava a falar. Cada troca recomeçava do zero.

Este problema é fundamental em qualquer aplicação de IA conversacional. Os LLMs não têm memória nativa. A cada pedido, é necessário reenviar todo o contexto. E isso muda tudo — em termos de UX, custo e arquitetura.

Aqui está como eu dei memória à IA do TAMSIV.

Pilha de cadernos e diários com marcadores e post-its, simbolizando a memória e o histórico de conversação
A memória da IA é como um caderno: é preciso escolher o que guardar e o que esquecer.

Por que os LLMs não têm memória?

É contraintuitivo quando se usa ChatGPT ou Claude, mas esses modelos não têm nenhuma persistência entre as requisições. Cada chamada de API é independente. A "memória" que tu percebes numa conversa do ChatGPT é a aplicação que reenvia o histórico completo a cada mensagem.

Concretamente, quando tu envias a tua 5ª mensagem numa conversa, a API recebe:

  1. O prompt do sistema (as instruções de comportamento)
  2. A mensagem 1 + a resposta 1
  3. A mensagem 2 + a resposta 2
  4. A mensagem 3 + a resposta 3
  5. A mensagem 4 + a resposta 4
  6. A tua mensagem 5

A cada troca adicional, o payload aumenta. E com ele, dois problemas: a janela de contexto (limite técnico do modelo) e o custo em tokens (cada token é faturado).

É o que a documentação da OpenAI chama de gestão do estado da conversação.

Como funciona a janela deslizante do TAMSIV?

A solução clássica é a janela deslizante: apenas os N últimos intercâmbios são mantidos. Mas uma janela deslizante bruta é demasiado simplista para uma aplicação como o TAMSIV, onde a IA precisa de compreender referências a ações passadas.

Implementei uma janela deslizante com prioridades:

  • Prioridade máxima: o prompt do sistema (sempre incluído, nunca truncado)
  • Prioridade alta: as 2 últimas trocas (o contexto imediato)
  • Prioridade alta: as chamadas de função e os seus resultados (as ações realizadas — criação de tarefa, modificação de memorando, etc.)
  • Prioridade média: as trocas anteriores (3 a N-2)
  • Prioridade baixa: as trocas antigas, resumidas ou eliminadas de acordo com o orçamento de tokens

Por que as chamadas de função são prioritárias? Porque no TAMSIV, quando o utilizador diz "Modifica a prioridade da tarefa que acabamos de criar", a IA precisa de saber qual tarefa foi criada. Essa informação está no function_result de uma troca anterior. Sem ela, a IA não consegue resolver o pronome "a".

Como gerir o orçamento de tokens sem explodir os custos?

Este é o cerne da questão. Uma conversa de 10 trocas pode custar 5 vezes mais do que uma troca isolada, porque o payload cumulativo é reenviado a cada vez.

Exemplo concreto com um modelo a 0.001$ / 1000 tokens:

  • Troca 1: ~500 tokens (prompt do sistema + mensagem) = 0.0005$
  • Troca 5: ~2500 tokens (histórico 1-4 + mensagem 5) = 0.0025$
  • Troca 10: ~5000 tokens (histórico 1-9 + mensagem 10) = 0.005$
  • Total da conversa de 10 trocas: ~25 000 tokens acumulados = 0.025$

Para uma aplicação com milhares de utilizadores, estes cêntimos somam-se rapidamente. Implementei três salvaguardas:

  1. Limite de 20 trocas por conversa: para além disso, recomenda-se iniciar uma nova conversa. Isso evita conversas-monstro de 100 trocas.
  2. Contador de tokens estimado: antes de cada chamada, o backend estima o número de tokens do payload completo. Se exceder o orçamento, as trocas mais antigas são truncadas.
  3. Escolha do modelo de acordo com a complexidade: uma mensagem simples ("Adicionar pão") usa um modelo leve. Um pedido complexo ("Reorganizar as minhas tarefas da semana por prioridade") usa um modelo mais poderoso.
Ampulheta transparente cheia de areia dourada e partículas digitais, simbolizando o orçamento de tokens
O orçamento de tokens é como uma ampulheta: cada grão conta, e é preciso decidir o que guardar.

Como funciona o fallback entre modelos LLM?

Em produção, a fiabilidade não é negociável. Se o modelo principal (configurado via OPENROUTER_MODEL) retornar um erro 429 (limite de taxa) ou 503 (serviço indisponível), o utilizador não deve notar nada.

O backend do TAMSIV implementa um fallback automático:

  1. Chamada ao modelo principal via OpenRouter
  2. Se erro 429/503 → nova tentativa com OPENROUTER_FALLBACK_MODEL
  3. O AlertService envia um e-mail ao administrador para sinalizar o fallback
  4. O utilizador recebe a sua resposta normalmente — nenhuma degradação percetível

Em produção, o TAMSIV faz 2 a 3 fallbacks por semana. É mínimo, mas acontece. Sem este mecanismo, o utilizador veria uma mensagem de erro genérica — e provavelmente sairia da aplicação.

A escolha do OpenRouter como proxy LLM (em vez de chamar diretamente a API OpenAI ou Anthropic) é estratégica: permite mudar de modelo sem modificar o código. Se um novo modelo for lançado, basta mudar uma variável de ambiente. O pipeline vocal completo permanece idêntico.

Que impacto a memória tem na experiência do utilizador?

A diferença é espetacular. Antes do histórico de conversação, cada troca era independente. Depois, a IA torna-se um verdadeiro assistente:

  • "Modifica a prioridade da tarefa que acabamos de criar" → a IA sabe qual tarefa, e a modifica
  • "Finalmente, coloca isso para sexta-feira" → a IA entende que "isso" se refere ao último evento criado
  • "Adiciona também um memorando sobre isso" → a IA retoma o assunto da conversa para criar o memorando
  • "Não, eu disse amanhã, não depois de amanhã" → a IA corrige, compreendendo a referência temporal

Esta é a diferença entre um formulário de voz (repete tudo a cada vez) e um assistente que ouve e se lembra. É o que torna o Ditafone do TAMSIV utilizável no dia a dia.

Como o prompt do sistema influencia a qualidade das respostas?

O prompt do sistema é o documento mais importante da aplicação. É ele que define o comportamento da IA: tom, formato de resposta, ferramentas de função disponíveis, restrições.

O prompt do sistema do TAMSIV inclui:

  • A persona: "Tu és o assistente de voz do TAMSIV, uma aplicação de gestão de tarefas e memorandos."
  • As ferramentas de função: as 7 funções que a IA pode chamar (create_task, update_task, create_memo, update_memo, create_calendar_event, ask_clarification, end_conversation)
  • As restrições: respostas curtas (o utilizador ouve via TTS), sem markdown, sem listas longas
  • O contexto do utilizador: o idioma preferido, o fuso horário, o plano (Free/Pro/Team)

Um prompt de sistema bem concebido reduz drasticamente as alucinações e as respostas fora do tópico. É um investimento que se reflete em cada conversa.

Como gerir conversas multimodais (voz + texto)?

No TAMSIV, o utilizador fala, mas a IA responde por voz (via OpenAI TTS) E por texto (exibido no ecrã). O histórico armazena ambas as formas:

  • Lado do utilizador: o texto transcrito pelo STT (não o áudio bruto — muito pesado em tokens)
  • Lado da IA: o texto da resposta (enviado para o TTS e exibido)

O pipeline completo é: Áudio → STT → Texto → LLM (com histórico) → Texto → TTS → Áudio. O histórico vive apenas na camada de texto, o que simplifica enormemente a arquitetura.

Rede de segurança a apanhar orbes luminosos que caem, simbolizando o sistema de fallback
O fallback entre modelos LLM: uma rede de segurança invisível para o utilizador.

Que alternativas à janela deslizante existem?

A janela deslizante não é a única abordagem. Existem outras estratégias:

  • Sumarização: resumir as trocas antigas num parágrafo condensado. Vantagem: compressão máxima. Inconveniente: perda de detalhes, e uma chamada LLM adicional para o resumo.
  • RAG (Retrieval Augmented Generation): armazenar o histórico numa base vetorial e recuperar apenas as trocas relevantes por similaridade semântica. Poderoso, mas pesado de implementar.
  • Memória explícita: armazenar "factos" extraídos das conversas (preferências do utilizador, tarefas recorrentes) numa base estruturada. É o que o ChatGPT faz com a sua funcionalidade "Memory".

Para o TAMSIV, a janela deslizante com prioridades é o melhor compromisso: simples de implementar, eficiente em tokens e suficiente para conversas de 5 a 15 trocas. Se as conversas se tornassem muito mais longas, eu consideraria o RAG.

Como implementar um histórico de conversação no teu próprio projeto?

Se estás a construir uma aplicação com um LLM, aqui estão os passos:

  1. Armazena o histórico no lado do servidor: nunca confies no cliente para manter o estado da conversação. O backend é a fonte da verdade.
  2. Implementa uma janela deslizante: começa de forma simples (mantendo as últimas N trocas), depois adiciona prioridades se necessário.
  3. Orçamenta os tokens: conta os tokens antes de cada chamada. Trunca inteligentemente se o orçamento for excedido.
  4. Adiciona um fallback: no mínimo, um modelo de backup em caso de erro do modelo principal.
  5. Mede os custos: regista cada chamada com o número de tokens utilizados. Isso permite otimizar o sistema ao longo do tempo.

O painel de administração do TAMSIV exibe as métricas de conversação em tempo real: número médio de trocas, custo médio por conversação, taxa de fallback. Estes dados são essenciais para otimizar os custos em produção.

FAQ

Quantas trocas um utilizador médio faz por conversa?

No TAMSIV, a média é de 3 a 5 trocas. O utilizador típico diz "Adiciona uma tarefa para amanhã: ligar ao dentista", confirma a pré-visualização e continua com uma modificação ("Coloca-a com alta prioridade"). As conversas longas (mais de 10 trocas) representam menos de 10% do volume.

O custo do histórico de conversação é significativo?

Sim, é o principal item de despesa do pipeline de IA. Cada troca adicional aumenta o custo acumulado. Para o TAMSIV, o custo médio por conversa é de aproximadamente 0.01 a 0.03 EUR com o modelo principal. O modelo de fallback é geralmente mais barato, o que compensa parcialmente os custos adicionais.

É necessário armazenar o histórico na base de dados?

Para o TAMSIV, o histórico vive na memória (lado do backend) durante a sessão WebSocket. Não é persistido na base de dados — quando a conexão é fechada, o histórico é perdido. É uma escolha deliberada: as conversas são curtas e transitórias. Se precisares de retomar conversas mais tarde, terás de persistir na base de dados.

OpenRouter vs chamar diretamente as APIs dos fornecedores LLM?

O OpenRouter atua como um proxy que unifica o acesso a dezenas de modelos (OpenAI, Anthropic, Google, etc.) através de uma única API. A vantagem: mudar de modelo sem modificar o código. O inconveniente: uma camada adicional (latência marginal). Para uma aplicação como o TAMSIV que precisa de flexibilidade e fallback, é uma escolha óbvia.

A memória de conversação funciona com o modo Realtime?

O TAMSIV tem três modos WebSocket. No modo LiveWebSocket (o modo padrão), o histórico é gerido manualmente como descrito neste artigo. No modo Realtime (OpenAI Realtime API), o histórico é gerido nativamente pela API — é um protocolo bidirecional com estado. O modo legado funciona em lote sem persistência.