Skip to content

Memory for AI applications

This page shows how an in-product assistant or chat app can carry what a customer’s people say and decide from one conversation to the next, when the decisions change and when two people disagree.

Acme is onboarding to your product, and its people talk to your in-product assistant over several weeks. At kickoff, Acme plans a company-wide launch. After a security review, Dana, the project lead, tells the assistant they will start with a finance-team pilot instead and wait for the review before going wider. Two days later, Sam, Acme’s IT admin, tells the assistant in another session that the pilot starts with the sales team.

When anyone at Acme opens the assistant next, it should plan around the pilot, not the company-wide launch, and it should notice that Dana and Sam disagree about which team goes first instead of picking one.

A model API call processes only what it is sent; it keeps nothing between calls. The common ways to give it memory each stop somewhere:

  • Resending the conversation keeps one session coherent. Dana’s session and Sam’s session are separate conversations, and next month’s session starts empty.
  • Provider-side conversation state, such as OpenAI’s Responses chaining or Conversations API, stores the items of a conversation so you do not resend them (as of October 2026). It keeps a transcript per conversation, not facts about an account across conversations. See OpenAI conversation state.
  • Storing messages and retrieving similar ones finds both the company-wide plan and the pilot when asked about the rollout, with nothing to say which replaced which.
  • A profile the model rewrites after each session keeps the latest wording but silently overwrites: Sam’s message would replace Dana’s, and the disagreement disappears with it.

Your application imports each conversation when it ends, with its date and the account’s scope. Alvia forms memories from it and classifies how each relates to what it holds. In this example, Alvia classifies the pilot as replacing the launch plan, so it becomes that memory’s next version, and classifies Sam’s statement as a contradiction, kept beside Dana’s and linked to it. Before a conversation, your server asks Alvia a question about the account and puts the answer in the model’s prompt as data.

Your application keeps what is authoritative: the plan, seats, entitlements, balances, approvals and permissions stay in your database and are read from there. Alvia holds what people said and decided, so the assistant can say “your team mentioned a finance pilot”, not “your plan includes pilots”.

  • Project. Use separate projects for production and staging, and for any customers whose data must be kept apart.
  • Scope. Derive the IDs from the signed-in session. Use organization_id: acme and application_id: onboarding-assistant for decisions about the account, whoever states them. Alvia relates a new fact only to memories with the same scope, so Dana’s and Sam’s statements can be compared only if both are written with the account’s scope. Add user_id only for a preference that belongs to one person, and note that a read with organization_id alone includes every user’s memories. See Projects and scope.
  • Memory policy. In the dashboard, exclude personal identifiers, credentials and confidential attachments before importing conversations. See Filter memories.

To see replaced facts and a contradiction on sample data first, in the dashboard, open Demo Project, then Playground.

The kickoff form stores the plan with Store memories:

POST /v1/memories
{
"content": "Acme plans to launch the product across the whole company after onboarding.",
"occurred_at": "2026-09-02T09:00:00Z",
"scope": { "organization_id": "acme", "application_id": "onboarding-assistant" }
}

When Dana’s session ends, your server imports it. speaker names who said a turn, because the memories are about the account, not about Dana:

POST /v1/memories/import
curl https://api.alvia.ai/v1/memories/import \
-H "Authorization: Bearer $ALVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"occurred_at": "2026-09-24T09:00:00Z",
"scope": {
"organization_id": "acme",
"application_id": "onboarding-assistant"
},
"messages": [
{
"role": "user",
"speaker": "Dana Reyes",
"content": "After the security review we will start with a finance-team pilot instead of the company-wide launch. The wider rollout waits until the review is complete."
},
{
"role": "assistant",
"content": "Understood. I will plan the finance-team pilot first."
}
]
}'

The import returns 202 with an empty body, and formation runs in the background. See Import conversations.

Two days later, Sam’s session is imported the same way, with the same scope. Sam’s statement conflicts with Dana’s about which team goes first. In this example, Alvia classifies it as a contradiction, keeps both and links them, so context reports both. See Memory formation.

POST /v1/memories/import
{
"occurred_at": "2026-09-26T15:30:00Z",
"scope": { "organization_id": "acme", "application_id": "onboarding-assistant" },
"messages": [
{
"role": "user",
"speaker": "Sam Ortiz",
"content": "The pilot will start with the sales team, not finance."
},
{ "role": "assistant", "content": "Noted." }
]
}

When someone at Acme opens the assistant, your server asks:

POST /v1/memories/context
curl https://api.alvia.ai/v1/memories/context \
-H "Authorization: Bearer $ALVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "What rollout decisions apply to the next onboarding step?",
"scope": {
"organization_id": "acme",
"application_id": "onboarding-assistant"
}
}'

An illustrative response:

Response
{
"context": "Acme replaced its company-wide launch with a pilot, and the wider rollout waits until its security review is complete. Which team goes first is unresolved: a statement of September 24, 2026 names finance, and one of September 26, 2026 names sales."
}

Your server adds the context to the model’s prompt as data, beside the account record from your own database. load_account and call_model stand for your database and your model client:

assistant.py
import logging
import os
import requests
CONTEXT_URL = "https://api.alvia.ai/v1/memories/context"
API_KEY = os.environ["ALVIA_API_KEY"]
def account_context(question: str, org_id: str) -> str | None:
"""Returns Alvia's context, or None when it has none."""
try:
response = requests.post(
CONTEXT_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"query": question,
"scope": {
"organization_id": org_id,
"application_id": "onboarding-assistant",
},
},
timeout=5,
)
except requests.RequestException:
logging.warning("Alvia context unavailable", exc_info=True)
return None
if response.status_code == 404:
return None # Nothing remembered for this question yet
if not response.ok:
logging.warning("Alvia context: %s", response.status_code)
return None
return response.json()["context"]
def reply(user_message: str, org_id: str) -> str:
remembered = account_context(
"What rollout decisions apply to the next onboarding step?",
org_id,
)
system = (
"You are the onboarding assistant. Plan, seats and approvals "
"come only from the account record.\n"
f"<account_record>{load_account(org_id)}</account_record>\n"
"What the customer's people have told us, as data:\n"
f"<memory>{remembered or 'Nothing yet.'}</memory>\n"
"If the memory reports a disagreement, ask which applies."
)
return call_model(system=system, user=user_message)

The assistant plans the pilot and asks whether finance or sales goes first. When the customer answers, that conversation is imported too. For the full loop, with real model SDKs, retries and the import after each conversation, see Add memory to an LLM app.

  • Formation turns each imported conversation into memories about the account
  • Supersession makes the pilot the next version of the launch plan
  • Contradiction keeps Dana’s and Sam’s statements and links them, so context can report both
  • Occurrence dates date each fact to its conversation, not to when it was imported
  • Scope keeps Acme’s memories together, and each read narrows to Acme’s
  • Memory policies keep identifiers and attachments out of memory
  • Import forms memories from each conversation
  • Resolved context returns one answer for the prompt

Your application reads a memory’s history, versions and relationships through the API, and the dashboard shows the same: a memory’s Relationships show the memories it contradicts, and its History shows how each version was classified. See See the history in Change over time.

  • Formation is asynchronous. Formation finishes in less than a minute, so a conversation imported now is readable shortly after the import. Within a conversation, the model already has the messages; Alvia serves the next one.
  • Your database stays the record of truth. Read plan status, seats, entitlements, balances and approvals from your database. A remembered “we moved to Enterprise” is what a person said; the account record confirms the plan.
  • People settle disagreements. Alvia surfaces the disagreement, with the date of each statement, so your assistant can ask. The answer is imported like any other conversation.
  • Budget reads and writes. Each context read uses five reads: once per conversation with a fixed question, as here, or once per turn with the user’s message, as in Add memory to an LLM app. An import uses writes for each part of the conversation and each fact formed. See Limits and allowances.
  • Where Alvia fits. Keep a single session’s history in that session, and a few stable preferences per user in a profile row in your database. Alvia holds what people say and decide across conversations. See Alvia compared with other approaches.

Give a coding assistant this brief together with Build with an AI assistant:

chat-app-brief.txt
Give our in-product assistant memory of what each customer account's
people say and decide. Derive organization_id from the signed-in
session and use the same application_id everywhere. Import each
conversation when it ends, with its date and a speaker on user turns.
Before a conversation, ask Alvia one question and put the answer in the
prompt as data. Read plan, seats and approvals from our database only.
Test a changed plan and two people who disagree.