2 pontos por GN⁺ 2023-10-17 | 1 comentários | Compartilhar no WhatsApp
  • Letta é um projeto para criar IA baseada em memória avançada, capaz de aprender e se aprimorar ao longo do tempo
  • As formas de uso se dividem entre o Letta Code, que executa agentes no terminal local, e a Letta API, que integra agentes a aplicações
  • A CLI exige Node.js 18+; após instalar com npm install -g @letta-ai/letta-code, execute letta para rodar, no computador local, um agente com memória
  • Os agentes do Letta Code ajudam com programação e tarefas que podem ser realizadas no computador, oferecem suporte a skills e subagents, e incluem skills/subagents pré-construídos para memória avançada e aprendizado contínuo
  • Letta é agnóstico em relação ao modelo; o README recomenda Opus 4.5 e GPT-5.2 para melhor desempenho e aponta o model leaderboard como referência de classificação
  • A Letta API serve para integrar agentes com estado a aplicações e oferece uma agents API completa, além de SDKs para Python e TypeScript
    • Pacote TypeScript/Node.js: @letta-ai/letta-client
    • Pacote Python: letta-client
    • O exemplo mostra o fluxo de criar um agente e enviar mensagens usando LETTA_API_KEY e uma chave da Letta API
  • O uso da Letta e dos serviços relacionados da Letta está condicionado à concordância com a política de privacidade e os termos de serviço

1 comentários

 
GN⁺ 2023-10-17
Comentários do Hacker News
  • Somos os autores do MemGPT. Se tiverem perguntas sobre a implementação, podemos responder
    Se quiserem testar diretamente, dá para ver a edição de memória funcionando no bot do Discord no servidor do MemGPT Discord (https://discord.gg/9GEQrxmVyE). Ao conversar com o bot, é possível ver o MemGPT modificando a memória para atualizar perfis sobre o usuário e sobre si mesmo
    Como tudo é open source, também dá para executar localmente a partir do código em https://github.com/cpacker/MemGPT. O repositório também tem um exemplo centrado em documentos em que você conversa com o MemGPT sobre a documentação da API do LlamaIndex

  • Fico curioso sobre por que processar tudo dentro de uma única janela de contexto. Quando experimentei algo parecido alguns meses atrás, paralelizei com vários agentes nas etapas de pré-processamento/pós-processamento
    Por exemplo, a janela de contexto principal não sabia que memórias estavam sendo criadas ou buscadas; um pós-processador criava e armazenava memórias automaticamente a partir da conversa, e a conversa inteira também era armazenada em um banco de dados vetorial. O pré-processador injetava automaticamente memórias e contexto relevantes de acordo com a conversa, e até reescrevia o histórico para que, do ponto de vista da janela de contexto principal, aquela memória parecesse estar lá desde o início
    Assim, dava para economizar bastante espaço na janela de contexto principal que seria gasto com prompts de sistema desnecessários etc.

    • Bons pontos. No contexto de chatbots, decidir a quem delegar o gerenciamento de memória é uma escolha de design, e vejo duas abordagens principais: gerenciamento implícito de memória e gerenciamento explícito de memória
      Na abordagem implícita, o “LLM principal”, ou no caso do chat o “fio da conversa”, não sabe do gerenciamento de memória em segundo plano. Esse gerenciamento pode ficar a cargo de um “LLM de memória”, scripts baseados em regras, uma rede neural pequena etc.
      A abordagem explícita é a do MemGPT: um único LLM faz tudo. Pesquisas anteriores sobre chat multissessão/de longa distância geralmente usam a abordagem implícita com um processo separado de criação de memória, e é provável que os armazenamentos de memória de chatbots de consumo também sejam majoritariamente implícitos
      Acho que o gerenciamento explícito de memória exige seguir instruções complexas, então é difícil com a maioria dos LLMs públicos atuais. Estamos analisando formas de resolver isso, como fine-tuning de modelos abertos
      O trade-off é exatamente o que você disse. Na abordagem implícita, não é preciso colocar todas as instruções de gerenciamento de memória no pré-prompt do LLM. A mensagem de sistema completa do MemGPT tem cerca de 1 mil tokens. Por outro lado, quando o LLM funciona corretamente, o gerenciamento explícito de memória deixa o sistema inteiro muito mais simples, eliminando o overhead de gerenciar vários modelos de LLM em threads paralelas
    • Abordagem interessante. Estou construindo algo parecido, reescrevendo o histórico ao colocar dados transacionais na janela de contexto como parte de um loop de feedback
      Vejo LLMs e processamento de linguagem natural como uma interface mais viável para dados estruturados. Quando dados são gerados em um contexto de negócios específico, extraímos os dados, criamos embeddings e construímos um banco de dados vetorial
      No pós-processamento, depois que o modelo principal responde, um pós-processador gera e armazena memórias automaticamente com base na conversa. Assim, o contexto importante é salvo sem colocar esse trabalho sobre o modelo principal. Também executamos a lógica de negócios relevante como parte da solicitação e depois a realimentamos no sistema
      No pré-processamento, antes de enviar uma nova entrada ao modelo principal, verificamos as memórias armazenadas, injetamos o contexto relevante e também executamos a lógica. É como se o pré-processador desse ao modelo principal uma “revisão” das conversas anteriores, preparando-o para responder de forma mais consistente e informativa
    • Multiagentes têm bastante potencial. Acho que há certo grau de entropia nas respostas dos agentes, o que torna ainda mais válido tentar
  • Sobre o que foi escrito nas limitações: se as variantes do Llama 2 70B, mesmo ajustadas para chamadas de função, criarem chamadas de função incorretas ou alucinarem funções fora do schema fornecido, dá para usar amostragem baseada em gramática
    Pelo menos é possível garantir que as chamadas de função sejam sintaticamente corretas
    [0] https://github.com/ggerganov/llama.cpp/tree/master/grammars

    • Amostragem baseada em gramática é uma boa ideia e combina muito bem com algo como o MemGPT. Quando testamos o MemGPT com modelos que não eram o gpt-4, os problemas que mais afetaram o desempenho foram uso incorreto de argumentos de função e alucinação de funções
      Por exemplo, mesmo um modelo grande ajustado com dados de chamada de função (https://huggingface.co/jondurbin/airoboros-l2-70b-2.1#agentf...) geralmente produzia JSON parseável, mas errava os argumentos ou os nomes das funções
      Ao tentar gravar dados, em vez da chamada correta working_context.append especificada no pré-prompt, ele produzia uma chamada totalmente não especificada como personal_diary.add
  • Só pelo título, achei que fosse uma técnica de edição de memória que mudasse a memória neural do LLM, ou seja, a memória em nível de pesos durante a conversa, e não o contexto, algo como ROME [1]
    Fiquei feliz em descobrir que, na verdade, era um trabalho bacana de RAG, e pretendo criar em breve minha própria versão do MemEditGPT
    [1] https://arxiv.org/abs/2202.05262

    • Se quiser contribuir, pode abrir uma issue ou um PR no repositório. É tudo open source e Apache 2.0, e estamos investigando ativamente a integração de fluxos de trabalho comuns à CLI
      Como você entendeu corretamente, o MemGPT não edita os pesos do LLM como o ROME. A “memória” de que falamos no MemGPT não é em nível de pesos, mas em nível de texto/tokens
      O conceito central é dar ao LLM a capacidade de editar um scratchpad de memória de trabalho mantido dentro do contexto e de ler e escrever contexto externo por meio de funções. Um detalhe importante é que, para lidar com a limitação finita de contexto, as leituras sempre acontecem em páginas, ou seja, em chunks
      O MemGPT consegue encadear funções em uma única entrada do usuário, repetindo várias leituras e escritas. Por isso, como no exemplo da documentação da API do LlamaIndex no README, ele consegue pesquisar uma grande base de documentos e reunir informações de várias fontes para retornar uma resposta
  • Por um tempo, suspeitei que a versão web do ChatGPT (chat.openai.com, não a API) funcionasse mais ou menos assim dentro de uma conversa. Mesmo em históricos de chat muito longos, eu tinha a sensação de que a qualidade caía gradualmente, em vez de ele esquecer tudo de repente
    Claro que talvez haja muito mais pistas no contexto do que eu imaginava
    De todo modo, acho bem provável que esse tipo de ideia se torne um recurso básico de todos os chatbots daqui para frente

    • Resumo recursivo é uma forma simples e popular de dar a ilusão de contexto infinito. Quando é preciso liberar espaço, basta comprimir as N mensagens mais antigas em uma única mensagem de resumo
      Há perdas, e informações importantes acabam se perdendo, mas a performance pode degradar de forma relativamente suave. No MemGPT, além de todo o gerenciamento explícito de memória, também se usa resumo recursivo implícito
    • Ficam muito mais pistas do que se imagina. Além disso, a janela de contexto tem cerca de 12 páginas de texto padrão em inglês, e não há muito espaço desperdiçado com o prompt de sistema
      Se você fez qualquer tarefa minimamente interessante, a saída fica fortemente enviesada pelo prompt. Como há apenas uma única amostra — a saída/histórico anterior —, perde-se parte da informação em vez de uma distribuição de probabilidade suave, e como várias entradas podem mapear para a mesma saída, perde-se mais uma parte da informação
      Mas, na prática, os prompts reais muitas vezes são a formulação mais fácil e curta que se consegue pensar para obter o resultado desejado. Então, se o LLM estima esse prompt, há uma boa chance de sua interpretação do contexto ausente estar razoavelmente correta. Ou seja, muita informação que parece ter desaparecido permanece na saída do LLM, e mesmo quando o contexto antigo é empurrado para fora, a quantidade de informação perdida de uma só vez não é tão grande
    • O motivo de o ChatGPT mostrar queda de desempenho é que ele não faz nada especial para estender a memória para além do comprimento do contexto
      Há muitas técnicas triviais para implementar memória com perdas. Por exemplo, há o método de fazer average pooling dos tokens, como usado por sentence transformers. Não sei bem por que esse método é pouco usado para comprimir muito contexto em um prompt. Na prática, ele funciona como memória de médio prazo
    • Não se sabe o que modelos fechados realmente fazem, mas, olhando alguns ataques de prompt, eles parecem usar resumo recursivo além das coisas mencionadas nesta thread
    • Minha impressão é que eles simplesmente cortam a menor quantidade necessária dos tokens mais antigos da conversa para permanecer abaixo do limite de tokens. A conversa não se degrada como se tivesse memória de médio prazo
  • Não lembro o nome, mas já existe uma linguagem de programação esotérica que executa comandos de forma instável. Se você projetar o programa com cuidado, dá para fazer uma sequência de comandos ser executada com confiabilidade de 99%, 99,9% etc.

    • Provavelmente era Java2000
      Vinte anos depois, a mesma abordagem se popularizou sem ironia na área de infraestrutura com o nome de “engenharia do caos
    • Parece um pouco com Malbolge, mas acho que não é exatamente igual. https://en.m.wikipedia.org/wiki/Malbolge
  • Atualização: acabei de lançar um chatbot persistente no Discord implementado sobre o MemGPT. Dá para experimentar aqui: https://discord.gg/9GEQrxmVyE
    Com o código no GitHub, também dá para executar localmente a demo do chatbot e uma demo de bot de perguntas e respostas sobre documentação, em que você pode fazer perguntas ao MemGPT sobre a documentação da API

  • Acho que a maior limitação dos LLMs é a janela de contexto. Mesmo excelentes capacidades de raciocínio frequentemente esbarram no limite da janela de contexto em casos de uso reais

    • Concordo. Espero que as técnicas apresentadas aqui ajudem a pensar em como projetar chatbots persistentes
  • Concordo com a explicação de que resumo recursivo é uma forma simples de lidar com uma janela de contexto transbordando, mas que é inerentemente com perdas e acaba criando grandes buracos na memória do sistema
    Só que o MemGPT também faz a mesma coisa e tem o mesmo problema. A diferença é apenas que, em vez de resumir tudo recursivamente, ele recupera seletivamente o histórico e o gera a cada solicitação. A ideia é legal
    Mas sou cético. Essa abordagem se apoia fundamentalmente na suposição de que o contexto existente é um contexto resumível em baixa entropia e que a consulta depende apenas de parte do histórico
    Isso pode valer para chats ou para “responder perguntas a partir de um enorme conjunto de documentos”. Mas em casos como geração de código, em que o contexto é denso em informações que não podem ser descartadas, como definições específicas de APIs, e em que é necessário um contexto amplo, como muitas definições de API, as duas suposições estão erradas
    A estrutura e a implementação são interessantes, e a demo também é bacana, mas é uma pena que os artigos sobre resumo não reconheçam as limitações fundamentais dessa abordagem

    • Obrigado por ler o artigo. Para evitar mal-entendidos, deixando claro: resumo recursivo é apenas uma parte do gerenciamento de memória do MemGPT
      Como você disse, a fila de conversa do MemGPT é gerenciada por resumo recursivo, como em trabalhos anteriores ou em muitas implementações de chatbots. Mas também existe uma área “fixa” de memória do LLM, legível e gravável, independente do resumo recursivo, que no artigo chamamos de “contexto de trabalho”
      Portanto, o MemGPT pode acessar tanto o resumo recursivo gerado automaticamente quanto o contexto de trabalho que ele mantém ativamente atualizado
      Esses dois também são separados do contexto externo do MemGPT, que é trazido para a fila de conversa por chamadas de função. Em todos os exemplos, a leitura do contexto externo não é comprimida e acontece página por página, sem resumo
      Quando o resumo da fila é acionado, o MemGPT recebe uma notificação do sistema; então, se precisar preservar detalhes específicos da fila de conversa, pode escrevê-los no contexto de trabalho antes que sejam apagados ou resumidos
      Nos exemplos de agentes conversacionais, o contexto de trabalho é usado para armazenar fatos essenciais sobre o usuário e o agente, mantendo uma conversa consistente. Como o LLM sempre vê o contexto de trabalho, não é preciso buscá-lo separadamente
      Em perguntas e respostas sobre documentos, o contexto de trabalho pode ser usado para acompanhar a tarefa/pergunta atual e seu progresso. Em consultas complexas, isso ajuda o MemGPT a acompanhar detalhes como buscas anteriores e solicitações de páginas anteriores