Multi-Account Switching: Isolating AI Conversations and Long-Term Memory

    This article presents a practical architecture for isolating conversation context and long-term memory in AI chat applications used with multiple accounts. It clarifies the roles of identity, session, and memory; proposes authentication, session, and memory isolation layers; provides a data model and code example; and covers account-switching flow, cache key design, concurrency controls, permissions, audit logging, compliance, and a pre-launch test checklist.

    1. Background

    The same user often holds both a work account and a personal account, and the same device may be shared by multiple people in turn. In these scenarios, AI chat applications must satisfy two requirements at the same time. First, conversation context must not interfere across accounts. Second, content generated from long-term memory must serve only the current identity.

    If these requirements are not implemented, concrete problems appear. A user may see personal-account preferences while using a work account, facts from an old account may be carried into a new conversation after switching, or cached context may be read by another account. These issues can reduce answer quality and, more seriously, cause privacy leaks that are difficult to explain in a compliance review.

    This article discusses a practical isolation design from an architectural perspective.

    2. Clarifying Three Basic Concepts

    Discussions of multi-account isolation often become ambiguous because concepts are mixed together, so it is useful to define three terms first.

    1. Identity: Who is initiating the request, as determined by an authentication token. Identity must come only from server-side validation results; an account field passed from the frontend must not be trusted directly.
    2. Session: The context of one continuous interaction, including recent messages and temporary state. A session has an explicit start and end, and after it ends it should be archived or cleaned up.
    3. Memory: Information retained across sessions, such as user preferences, long-term facts, and project background. Memory must be written explicitly, and users must be able to view, modify, and delete it.

    Session isolation answers the question “what is in the current conversation,” while memory isolation answers the question “what is retained long term.” The two have different lifecycles and access patterns, so they should use different storage structures and keys and should not be managed in the same object.

    3. Three-Layer Isolation Model

    A useful approach is to divide the boundary into an authentication layer, a session layer, and a memory layer, with independent validation at each layer.

    The authentication layer handles identity resolution for every request. After the server validates the token and obtains account_id, all reads and writes should be based on this value. Even if the frontend includes another account identifier in the request body, it should be ignored or rejected directly.

    The session layer specifies that each session is bound to only one account. When switching accounts, the old session enters an archived state and no longer receives new messages. Archived sessions may be displayed read-only so users can review them, but they must not continue to participate as context in generation.

    The memory layer uses account_id as the primary key. Memory is independent of devices, browser tabs, and specific windows. The same account should read consistent memory from any entry point, while different accounts must be completely isolated. This design also has another benefit: when an account is migrated or a device is replaced, there is no need to re-infer ownership relationships.

    4. Data Model and Example Code

    The following example code illustrates key design and basic validation logic. It omits authentication, persistence, and concurrency control. It is intended only to show boundaries and does not correspond to any specific product API.

    1. from dataclasses import dataclass, field
    2. from typing import Dict, List, Optional
    3. @dataclass
    4. class Session:
    5. session_id: str
    6. account_id: str
    7. messages: List[str] = field(default_factory=list)
    8. archived: bool = False
    9. version: int = 0
    10. class MemoryStore:
    11. """Memory is keyed by account_id and is independent of sessions and devices."""
    12. def __init__(self) -> None:
    13. self._facts: Dict[str, List[str]] = {}
    14. def read(self, account_id: str) -> List[str]:
    15. # Return a copy to prevent callers from modifying internal state.
    16. return list(self._facts.get(account_id, []))
    17. def write(self, account_id: str, fact: str) -> None:
    18. self._facts.setdefault(account_id, []).append(fact)
    19. class ChatService:
    20. def __init__(self, memory: MemoryStore) -> None:
    21. self.memory = memory
    22. self.active: Optional[Session] = None
    23. def switch_account(self, account_id: str, new_session_id: str) -> None:
    24. # Step 1: Archive the old session and block further writes.
    25. if self.active is not None:
    26. self.active.archived = True
    27. # Step 2: Create a session bound only to the new account.
    28. self.active = Session(session_id=new_session_id, account_id=account_id)
    29. def send(self, account_id: str, text: str, version: int) -> None:
    30. s = self.active
    31. if s is None or s.archived or s.account_id != account_id:
    32. raise PermissionError("Session is unavailable or the account does not match")
    33. if version != s.version:
    34. raise PermissionError("Session version is out of date. Refresh and try again.")
    35. s.messages.append(text)
    36. s.version += 1

    This code demonstrates three key points. First, memory reads return a copy so external code cannot directly modify internal data. Second, before sending a message, the service validates whether the session is archived, whether the account matches, and whether the version number is consistent. Third, when switching accounts, the old session is archived first and the new session is created second. The order of these two steps is fixed, which makes auditing and rollback easier.

    5. Switching Flow and Cache Design

    Account switching should follow a fixed sequence. The recommended flow is as follows.

    1. End the current session, save any unsent drafts, and mark the session as archived.
    2. Clear in-memory context caches and temporary variables that belong to the old account.
    3. Validate the new account token, and after validation succeeds, load that account’s session list.
    4. Read only the new account’s memory, and do not carry the old account’s memory into the new session.

    Cache keys must include account information. For example:

    1. cache_key = f"{account_id}:{session_id}"

    If a cache is named only by session ID, then when a session ID is repeated across service instances or time periods, data from another account may be read. This type of problem is difficult to find through ordinary testing, so the account dimension should be included in the key at the design stage.

    Concurrent scenarios also need to be handled. When two tabs operate at the same time, an old page may still send a write request after switching is complete. The solution is to attach a version number to each session. Write requests carry the version number, and the server accepts them only after comparing it successfully. If the version does not match, the request should be rejected directly and the user should be prompted to refresh the page.

    6. Permissions, Auditing, and Compliance

    The principle of least privilege is the baseline. Memory read and write APIs should be open only to the user’s own token. If operations staff or administrators need access, they should go through a separate authorization process with a complete audit trail.

    Users should have full control over their own memory. View, modify, and delete operations must all be provided. When deleting memory, it is not enough to delete only the primary storage; caches, indexes, and backup copies must also be cleaned synchronously. Otherwise, content that the user believes has been deleted may still be recalled.

    Audit logs should record the time, actor, and account ID for account switches, memory writes, and memory deletions. Logs should not contain plaintext memory content; otherwise, the logs themselves become a new leakage entry point.

    Sensitive information should be identified and filtered before it is written to memory. Common categories include government ID numbers, bank card numbers, addresses, and health information. Filtering rules can combine regular expression matching and classification models, but high-risk fields should be rejected from storage directly rather than merely masked.

    It is also important to note that model providers often set capability boundaries at the platform layer, such as limiting large-scale reproduction of copyrighted content or bulk generation of certain types. Application developers should not place all risk control on the model side. A reasonable approach is to implement content filtering, usage limits, and anomaly detection within their own products to form multiple layers of protection.

    7. Pre-Launch Test Checklist

    Before launch, at least the following scenarios should be covered.

    • After account A writes memory and switches to account B, B’s answers do not contain A’s preferences or facts.
    • After switching, opening an old session shows a read-only interface, and send requests are rejected.
    • After a memory item is deleted, the corresponding data in caches, indexes, and backups becomes invalid synchronously.
    • When two tabs switch accounts concurrently, write requests from the old page are rejected because of a version mismatch.
    • After the token expires, the system returns to an unauthenticated state, and the page does not retain context from the previous account.
    • Audit logs show every switch and memory change, and the logs do not contain plaintext memory content.

    These checks should be included in automated tests. Account-isolation defects often appear only under specific sequences of operations, which are difficult to cover through manual clicking. Automated test cases can reproduce them more reliably.