Buscar/Criar um serviço de memória para agentes de IA sem misturar as memórias de cada usuário

Criar um serviço de memória para agentes de IA sem misturar as memórias de cada usuário

Use ao criar ou ampliar a memória de longo prazo de agentes de IA. Mantém cada banco de memória separado, distingue ingestão, recuperação e raciocínio, e cobre migrações de banco de dados, clientes de API, testes julgados por outro modelo e configurações por inquilino ou banco.

Para usar estas regras de IA
## Separar os tipos de memória e não misturar dados entre bancos Mantenha distintos os tipos de conhecimento armazenado, pois a ingestão, a recuperação e o raciocínio os utilizam de formas diferentes. ### Modelar a memória explicitamente - Fatos do mundo representam conhecimento geral. - Fatos de experiência representam eventos pessoais atribuídos a um usuário ou agente. - Modelos mentais consolidam padrões sintetizados a partir de vários fatos. - Permita que cada banco de memória mantenha contexto de fundo e traços de disposição, como ceticismo, literalismo e empatia, em uma escala de 1–5. - Aplique as disposições apenas ao raciocínio reflexivo; não permita que alterem a recordação de fatos. ### Isolar os bancos - Trate cada banco como um repositório de memória independente para um único usuário ou agente. - Impeça vazamentos entre bancos no armazenamento, na recuperação, no raciocínio e nos testes. - Opere em exatamente 1 banco por solicitação de API. - Faça os clientes orquestrarem qualquer fluxo de trabalho com vários bancos, em vez de enfraquecer o limite do servidor. ## Separar ingestão, recuperação e raciocínio, e combinar vários métodos de busca Separe as três operações principais, compartilhando abstrações estáveis para modelos, embeddings, entidades e classificação. ### Preservar a semântica das operações - Retain ingere conteúdo e extrai fatos, entidades e relações. - Recall recupera memórias existentes sem aplicar traços de disposição. - Reflect raciocina sobre as memórias e os modelos mentais consolidados levando em conta as disposições. - Mantenha a orquestração separada da extração de fatos, da normalização de entidades, do gerenciamento de vínculos e dos adaptadores de provedores. ### Construir a recuperação como um pipeline - Execute em paralelo 4 estratégias complementares de recuperação: semântica, lexical BM25, por grafo e temporal. - Combine os resultados classificados com fusão recíproca de rankings antes da reclassificação por cross-encoder. - Mantenha a expansão do grafo atrás de uma interface de recuperação, para que estratégias alternativas continuem intercambiáveis. - Ofereça suporte a provedores locais e remotos de modelos, embeddings e reclassificação por meio de wrappers de escopo restrito. ### Sincronizar os contratos da API - Regenere a especificação OpenAPI após alterações nos endpoints. - Regenere todos os SDKs de cliente compatíveis, incluindo Python, TypeScript e Rust, após alterações na especificação. - Quando um parâmetro de API mudar, atualize em conjunto a rota de proxy, a extração da solicitação, a chamada ao SDK, o tipo do cliente e qualquer interface consumidora. ## Escrever uma migração que funcione no PostgreSQL e no Oracle Use um único histórico de migrações para todos os bancos de dados compatíveis, deixando explícitas as diferenças entre dialetos. ### Definir a revisão - Dê a cada migração um identificador hexadecimal de revisão exclusivo de 12 caracteres e faça `down_revision` apontar para seu antecessor. - Mantenha os comportamentos de upgrade e downgrade emparelhados. - Faça o despacho por um único roteador de dialetos que selecione a implementação com base na conexão ativa. - Faça o teste da estrutura da migração falhar quando o despachador estiver ausente. ### Implementar cada dialeto - Forneça funções separadas de upgrade e downgrade para PostgreSQL e bancos de dados compatíveis com Oracle. - Qualifique o SQL PostgreSQL bruto com o esquema de inquilino configurado, quando houver. - Use execução no nível do driver apenas para operações de banco de dados que o framework de migração não consiga modelar, como operações especializadas de vetores, texto ou partições. - Se uma migração realmente se aplicar a apenas 1 dialeto, omita deliberadamente a outra posição; nunca a deixe vazia por descuido. - Considere durante a revisão os desvios de esquema entre dialetos. ### Verificar a execução - Execute as migrações no esquema-base e em todos os esquemas de inquilinos. - Também ofereça uma execução direcionada a 1 esquema de inquilino identificado por nome para uma verificação focada. - Quando as migrações forem executadas automaticamente na inicialização do serviço, teste a inicialização em todos os dialetos e escopos de inquilino compatíveis. ## Passar nas verificações obrigatórias e na revisão de código antes do push Use o conjunto de ferramentas canônico após cada alteração de implementação e diferencie defeitos bloqueadores de limpezas apenas recomendadas. ### Executar as verificações obrigatórias - Execute formatação, lint e verificação de tipos após alterações em Python ou TypeScript. - Trate imports e variáveis não utilizados, arquivos de cliente órfãos e dependências de pacotes não listadas como falhas bloqueadoras. - Trate funções inteiras não utilizadas e exports intencionalmente amplos de bibliotecas de componentes como recomendações, a menos que a política do projeto os eleve a bloqueadores. - Execute testes unitários, testes de integração da API e benchmarks relevantes por meio dos comandos padrão do repositório. - Regenere especificações de API e clientes quando necessário e confirme que nenhuma diferença não commitada em artefatos gerados permaneça. ### Revisar antes da publicação - Faça uma revisão de código estruturada após a implementação. - Corrija todos os achados de correção obrigatória relacionados a testes ausentes, código morto, segurança de tipos, isolamento de dados ou divergência de arquivos gerados. - Não envie código nem crie uma solicitação de alteração até que todos os achados de correção obrigatória sejam resolvidos. - Não adicione manualmente entradas ainda não lançadas ao changelog; deixe o processo de lançamento criar entradas versionadas. ## Testar a lógica fixa diretamente e deixar outro modelo julgar as respostas do modelo Escolha as asserções conforme o comportamento seja mecanicamente determinístico ou dependa da interpretação do modelo. ### Testar diretamente os mecanismos determinísticos - Use asserções diretas para contagens, campos obrigatórios, montagem do prompt, lógica de supressão e substrings injetadas. - Mantenha a maioria dos testes rápidos com modelos simulados ou funções puras. - Combine testes de comportamento do modelo com testes unitários que cubram a preparação determinística ao redor deles. ### Avaliar o comportamento semântico do modelo 1. Marque um teste semântico para o job do modelo principal com um único provedor; reserve o marcador de matriz de provedores para aceitação entre provedores. 2. Chame o pipeline real configurado, não uma simulação. 3. Resuma a resposta com os rótulos semânticos necessários para a avaliação. 4. Peça a um modelo avaliador independente que determine se a resposta atende aos critérios explícitos no contexto fornecido. 5. Nunca avalie com a mesma chamada de modelo que está sendo testada. - Use asserções do modelo avaliador para classificação, atribuição, preservação de dimensões e cumprimento de instruções. - Não fixe strings exatas nem valores de enum para comportamentos que possam variar de forma válida entre modelos e execuções. ## Levar as mudanças da API a todos os clientes e adicionar CI às novas integrações Uma integração só está completa quando o comportamento em execução, os testes, a integração contínua, o registro de lançamento e as interfaces expostas pelos clientes estão alinhados. ### Atualizar os consumidores da API - Ao adicionar um campo de solicitação, extraia-o na rota de proxy e passe-o à chamada do SDK. - Atualize o tipo do método do cliente e todas as interfaces que forneçam ou leiam o campo. - Mantenha cada solicitação limitada a 1 banco e preserve a orquestração no lado do cliente para casos de uso com vários bancos. ### Completar uma integração - Adicione testes que simulem ou exercitem a interface do framework externo e verifiquem se a integração chama corretamente o serviço de memória. - Não considere testes unitários apenas de funções auxiliares uma cobertura de integração suficiente. - Adicione um job de integração contínua limitado à alteração que faça o build, instale dependências e execute os testes de integração. - Registre a integração no fluxo de trabalho padrão de lançamento. - Use estruturas tipadas em vez de dicionários brutos para dados estruturados e evite retornar tuplas com vários itens. - Não faça merge nem publique enquanto faltarem testes, detecção de alterações na CI ou registro de lançamento. ## Decidir se uma nova configuração pode mudar por inquilino ou banco antes de adicioná-la Classifique cada configuração antes da implementação para manter consistentes o escopo das substituições e a documentação. ### Escolher o nível de configuração - Resolva configurações hierárquicas partindo de valores globais do ambiente, passando por substituições do inquilino, até substituições de banco de dados no nível do banco. - Use configuração hierárquica para provedores de modelos, nomes de modelos, chaves de API, opções específicas de operações e sinalizadores de recursos específicos de clientes. - Mantenha endereços, hosts e portas de bancos de dados, limites globais de simultaneidade e sinalizadores de todo o sistema estáticos no nível do servidor. - Não adicione um campo estático ao conjunto de campos configuráveis remotamente. ### Adicionar um campo por completo 1. Defina o nome da variável de ambiente e o valor padrão. 2. Adicione um campo tipado ao objeto central de configuração. 3. Adicione-o à lista de permissão de campos configuráveis somente quando as substituições de inquilino ou banco forem válidas. 4. Inicialize-o a partir do ambiente. 5. Adicione uma opção de linha de comando somente quando uma substituição por linha de comando for necessária. 6. Leia valores hierárquicos por meio do resolvedor por banco e valores estáticos por meio do acessador global. 7. Atualize a referência de configuração e o modelo de ambiente com descrição, valor padrão e status da hierarquia. 8. Sincronize todas as cópias incluídas do modelo de ambiente e mantenha o teste de sincronização de modelos passando. - Nunca exponha valores reais de credenciais em documentação, modelos, logs ou testes.