Saltar al contenido
DedicatedPHP Contactar

Memoria conversacional en PHP: cómo aislar el contexto entre usuarios y organizaciones

Diseña la memoria de un asistente en PHP para que cada conversación respete la identidad, la organización y los permisos vigentes, sin cruces de contexto.

Diagrama conceptual de conversaciones separadas por usuario y organización en una aplicación PHP

Cuando un asistente responde con información de otra persona o empresa, el problema no es solo de calidad: puede ser una vulneración de privacidad y control de acceso. En una aplicación PHP multiusuario, la memoria conversacional debe tratarse como datos con propietario, ámbito y ciclo de vida definidos. No basta con guardar mensajes y recuperarlos por un identificador de sesión.

El aislamiento de contexto conversacional en aplicaciones PHP consiste en garantizar que el material utilizado para generar una respuesta pertenece a la conversación actual y sigue estando autorizado. Esto incluye mensajes anteriores, resúmenes y cualquier dato recuperado. La búsqueda en documentos puede complementar el contexto, pero tiene reglas de acceso y objetivos distintos.

Separar memoria conversacional, historial y documentos

Separar memoria conversacional, historial y documentos — guía visual de DedicatedPHP

El historial completo es el registro de mensajes de una conversación. La memoria, en cambio, es el subconjunto que la aplicación decide recuperar para una tarea: por ejemplo, los últimos turnos o un resumen actualizado. Los documentos recuperados mediante búsqueda son otra fuente, seleccionada a partir de una consulta y de permisos documentales. No deben confundirse ni guardarse como si fueran mensajes pronunciados por el usuario.

Esta distinción facilita decisiones verificables. Se puede conservar el historial por razones de auditoría o producto, mientras se limita la memoria enviada al modelo. Asimismo, cada fragmento documental puede mantener su propio origen y control de acceso. Si se mezclan esas fuentes sin identificarlas, cuesta explicar qué dato influyó en una respuesta y aplicar su política de retención.

Definir quién es propietario de cada conversación

Antes de diseñar la recuperación, establezca una identidad estable para la conversación. Como mínimo, considere:

  • Conversación: identificador aleatorio o no predecible, sin asumir que conocerlo concede acceso.
  • Usuario: identidad autenticada que inició la interacción o tiene permiso para consultarla.
  • Organización: ámbito de datos al que pertenece, si la aplicación opera con varias empresas o espacios de trabajo.
  • Permisos vigentes: autorización evaluada en el momento de cada lectura, no una copia indefinida de los permisos iniciales.

La sesión web puede servir para autenticar una petición, pero no debería ser la única clave de propiedad persistente. Una persona puede cerrar sesión, cambiar de organización o perder un permiso mientras una conversación sigue almacenada. En cada solicitud, la aplicación debe comprobar que el usuario actual puede acceder a esa conversación dentro de la organización activa.

Conviene definir explícitamente los cambios de contexto. Si alguien cambia de organización, ¿puede continuar la conversación anterior, debe abrir una nueva o solo conservar un resumen aprobado? No hay una respuesta universal: depende del producto y de sus requisitos de privacidad. La decisión debe reflejarse en reglas comprobables, no en una suposición implícita de la interfaz.

Aplicar el ámbito de acceso antes de recuperar contexto

La autorización debe formar parte de la consulta que obtiene los datos, antes de incorporarlos al prompt. Recuperar primero una colección amplia y filtrar después en PHP aumenta el riesgo de que un error, una ruta alternativa o un registro de depuración exponga contenido ajeno.

En una base relacional, la consulta puede incluir a la vez el identificador de conversación, el usuario y la organización autorizados. Por ejemplo, de forma conceptual:

SELECT message_id, role, content, created_at
FROM conversation_messages
WHERE conversation_id = :conversation_id
  AND organization_id = :organization_id
  AND conversation_id IN (
      SELECT conversation_id
      FROM conversations
      WHERE owner_user_id = :user_id
         OR EXISTS (/* comprobar una concesión vigente */)
  )
ORDER BY created_at DESC
LIMIT :message_limit

El esquema real puede ser distinto, pero la propiedad importante es que el ámbito de acceso restrinja los registros recuperados. Use parámetros enlazados y una capa de autorización coherente para las operaciones de lectura, escritura, exportación y borrado. Si se utiliza una base vectorial o un servicio de búsqueda, las restricciones por organización y permisos deben aplicarse en la consulta de recuperación; no basta con pedir al modelo que ignore los resultados no autorizados.

Cuando la búsqueda documental y la memoria conversacional se combinan, aplique primero la autorización correspondiente a cada fuente. Mantenga metadatos de procedencia y evite convertir resultados documentales en memoria permanente sin una política explícita.

Evitar cruces en cachés, colas y componentes compartidos

Un acceso correcto a la base de datos no garantiza el aislamiento si otras capas comparten estado. Una clave de caché como conversation:123 puede ser insuficiente si el mismo identificador se usa en más de un ámbito, se reutiliza o una configuración de caché permite colisiones. Incluya en la clave los identificadores de organización y conversación y, cuando proceda, una versión de permisos o de datos. No utilice contenido sensible como parte de la clave.

En trabajos en segundo plano, transporte un contexto mínimo y explícito: organización, conversación, actor y propósito del trabajo. Al ejecutarlo, vuelva a validar que la tarea conserva autorización y que no está usando una identidad tomada de un estado global compartido. Evite variables estáticas, servicios singleton con datos de usuario mutables y objetos de sesión reutilizados entre peticiones, especialmente en procesos PHP persistentes.

Defina también qué ocurre con errores y reintentos. Un trabajo reintentado no debería cambiar de organización por el estado de otro proceso, y una respuesta almacenada en caché no debería sobrevivir a una revocación si la política exige invalidarla. El comportamiento debe ser deliberado y observable.

Limitar la memoria a lo necesario para la tarea

Aislar no significa enviar todo el historial al modelo. Recupere los turnos recientes o un resumen que aporte valor a la petición actual, con límites de cantidad y tamaño. Considere la vigencia: preferencias antiguas, datos corregidos y decisiones revocadas no deberían tratarse automáticamente como hechos actuales.

Si se usan resúmenes, guarde su ámbito y procedencia, y actualícelos con reglas claras. Un resumen no es una fuente de verdad ni sustituye la comprobación de permisos. Para datos críticos, consulte el sistema de registro autorizado en lugar de confiar en una afirmación guardada en una conversación anterior. Una ventana de contexto pequeña reduce exposición y coste, pero no compensa una autorización incorrecta.

Probar que una conversación no influye en otra

Las pruebas deben cubrir tanto los accesos permitidos como los denegados. Cree casos con usuarios y organizaciones distintas y compruebe que una petición no recupera mensajes, resúmenes ni documentos de otra identidad. Incluya situaciones límite:

  • Un usuario cambia de organización y vuelve a abrir un identificador de conversación antiguo.
  • Se revoca un permiso después de crear la conversación, pero antes de recuperar su memoria.
  • Dos usuarios consultan simultáneamente y comparten procesos, caché o infraestructura de colas.
  • Un identificador inexistente o ajeno produce una respuesta controlada sin revelar si pertenece a otra persona.
  • Una tarea se reintenta después de un cambio de permisos o de organización.

Además de pruebas unitarias, pruebe el recorrido completo desde la petición autenticada hasta la construcción del contexto. Puede introducir mensajes marcadores en conversaciones separadas y verificar que el resultado recuperado para cada una nunca contiene el marcador de la otra. El objetivo es probar la frontera de datos, no evaluar si el modelo redacta una respuesta convincente.

Investigar incidentes sin registrar contenido sensible

Investigar incidentes sin registrar contenido sensible — guía visual de DedicatedPHP

La observabilidad debe permitir seguir el flujo sin copiar mensajes privados a los logs. Registre identificadores técnicos adecuados, decisión de autorización, número de elementos recuperados, origen de los datos, duración y resultado de cada etapa. Use identificadores seudónimos cuando sea posible y restrinja el acceso y la retención de los registros.

Señales como una recuperación vacía inesperada, una organización discordante, una tasa inusual de denegaciones o una clave de caché reutilizada fuera de su ámbito ayudan a detectar fallos. Evite registrar prompts completos, documentos o respuestas por defecto. Si se necesita diagnóstico detallado, establezca un procedimiento temporal, autorizado y limitado, con redacción de datos sensibles.

Un diseño seguro hace explícitos el propietario, el ámbito y la vigencia de cada fragmento de contexto. Aplicar esas reglas en las consultas, las cachés y los trabajos asíncronos, y verificar los casos negativos, convierte el aislamiento en una propiedad comprobable de la aplicación PHP, no en una expectativa depositada en el asistente.

¿Quieres aplicar estas ideas a tu proyecto?Hablemos de tu plataforma PHP.
Ver servicio relacionado