Done: Foundry Memory

This commit is contained in:
Tao Chen
2026-05-13 17:12:20 -07:00
Unverified
parent 708c0a4ab8
commit c3522ac8c6
6 changed files with 46 additions and 51 deletions
@@ -1,9 +1,6 @@
FOUNDRY_PROJECT_ENDPOINT="..."
AZURE_AI_MODEL_DEPLOYMENT_NAME="..."
# Embedding model deployment (only needed by provision_memory_store.py).
AZURE_OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME="text-embedding-3-small"
# Name of the Foundry Memory Store the agent should read/write to.
FOUNDRY_MEMORY_STORE_NAME="agent_framework_memory"
# Optional scope (e.g., user id) used to isolate memories. Falls back to the
# per-session id when unset, which limits memories to a single session.
FOUNDRY_MEMORY_SCOPE="user_123"
MEMORY_STORE_NAME="agent_framework_memory"
@@ -44,8 +44,8 @@ From this directory, with the venv activated and `az login` done:
```bash
export FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
export AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4.1-mini"
export AZURE_OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
export FOUNDRY_MEMORY_STORE_NAME="agent_framework_memory"
export AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME="text-embedding-3-small"
export MEMORY_STORE_NAME="agent_framework_memory"
python provision_memory_store.py
```
@@ -54,8 +54,8 @@ Or in PowerShell:
```powershell
$env:FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4.1-mini"
$env:AZURE_OPENAI_EMBEDDING_MODEL="text-embedding-3-small"
$env:FOUNDRY_MEMORY_STORE_NAME="agent_framework_memory"
$env:AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME="text-embedding-3-small"
$env:MEMORY_STORE_NAME="agent_framework_memory"
python provision_memory_store.py
```
@@ -75,16 +75,13 @@ Follow the instructions in the [Running the Agent Host Locally](../../README.md#
In addition to the standard environment variables, this sample requires:
```bash
export FOUNDRY_MEMORY_STORE_NAME="agent_framework_memory"
# Optional — defaults to "user_123" in main.py if unset.
export FOUNDRY_MEMORY_SCOPE="user_123"
export MEMORY_STORE_NAME="agent_framework_memory"
```
Or in PowerShell:
```powershell
$env:FOUNDRY_MEMORY_STORE_NAME="agent_framework_memory"
$env:FOUNDRY_MEMORY_SCOPE="user_123"
$env:MEMORY_STORE_NAME="agent_framework_memory"
```
You can also place these in a `.env` file next to `main.py` — see [`.env.example`](.env.example).
@@ -93,7 +90,9 @@ You can also place these in a `.env` file next to `main.py` — see [`.env.examp
> Depending on how you run the agent host, you can invoke the agent using `curl` (`Invoke-WebRequest` in PowerShell) or `azd`. Please refer to the [parent README](../../README.md) for more details.
Send a POST request to the server with a JSON body containing an `"input"` field to interact with the agent. The first request seeds a memory; subsequent requests (especially in new sessions) should be able to recall it because memories are scoped to `FOUNDRY_MEMORY_SCOPE`, not to a particular session.
Send a POST request to the server with a JSON body containing an `"input"` field to interact with the agent. The first request seeds a memory; subsequent requests (especially in new sessions) should be able to recall it because memories are persisted across Foundry Hosted Agents sessions.
> In this sample, the memory is scoped to the user by specifying `scope="{{$userId}}"`, thus memories are isolated across different users but shared across different sessions from the same user.
```bash
# 1. Tell the agent something to remember.
@@ -108,17 +107,14 @@ curl -X POST http://localhost:8088/responses -H "Content-Type: application/json"
-d '{"input": "What do you remember about my preferences?"}'
```
The agent's answers to the follow-up turns should reflect the preferences shared in the first turn, even though `default_options={"store": False}` is set (so the Responses service is not persisting conversation history) — the recall is coming exclusively from the Foundry Memory Store.
## Deploying the Agent to Foundry
To host the agent on Foundry, follow the instructions in the [Deploying the Agent to Foundry](../../README.md#deploying-the-agent-to-foundry) section of the README in the parent directory.
When deploying, make sure `FOUNDRY_MEMORY_STORE_NAME` and `FOUNDRY_MEMORY_SCOPE` are set in your `azd` environment so they get injected into the hosted container per [`agent.manifest.yaml`](agent.manifest.yaml):
When deploying, make sure `MEMORY_STORE_NAME` and `FOUNDRY_MEMORY_SCOPE` are set in your `azd` environment so they get injected into the hosted container per [`agent.manifest.yaml`](agent.manifest.yaml):
```bash
azd env set FOUNDRY_MEMORY_STORE_NAME "agent_framework_memory"
azd env set FOUNDRY_MEMORY_SCOPE "user_123"
azd env set MEMORY_STORE_NAME "agent_framework_memory"
```
If these are not set, running `azd ai agent init -m <agent-manifest.yaml>` will prompt you to enter them interactively.
@@ -20,18 +20,13 @@ template:
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}"
- name: FOUNDRY_MEMORY_STORE_NAME
value: "{{FOUNDRY_MEMORY_STORE_NAME}}"
- name: FOUNDRY_MEMORY_SCOPE
value: "{{FOUNDRY_MEMORY_SCOPE}}"
- name: MEMORY_STORE_NAME
value: "{{MEMORY_STORE_NAME}}"
parameters:
properties:
- name: FOUNDRY_MEMORY_STORE_NAME
- name: MEMORY_STORE_NAME
secret: false
description: The name of the pre-provisioned Foundry Memory Store the agent will use (e.g., agent_framework_memory)
- name: FOUNDRY_MEMORY_SCOPE
secret: false
description: Scope (e.g., user id) used to isolate memories within the store (e.g., user_123)
resources:
- kind: model
id: gpt-4.1-mini
@@ -10,7 +10,5 @@ resources:
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: FOUNDRY_MEMORY_STORE_NAME
value: ${FOUNDRY_MEMORY_STORE_NAME}
- name: FOUNDRY_MEMORY_SCOPE
value: ${FOUNDRY_MEMORY_SCOPE}
- name: MEMORY_STORE_NAME
value: ${MEMORY_STORE_NAME}
@@ -6,7 +6,7 @@ This agent uses :class:`FoundryMemoryProvider` to give an otherwise stateless
hosted agent persistent, semantic memory backed by an Azure AI Foundry
Memory Store. The store itself is provisioned once via
``provision_memory_store.py`` and its name is passed in through the
``FOUNDRY_MEMORY_STORE_NAME`` environment variable.
``MEMORY_STORE_NAME`` environment variable.
Unlike the standalone ``azure_ai_foundry_memory.py`` sample, here we construct
the :class:`FoundryChatClient` first and then reuse its underlying
@@ -41,15 +41,12 @@ async def main() -> None:
# constructing a second one for the memory provider.
memory_provider = FoundryMemoryProvider(
project_client=client.project_client,
memory_store_name=os.environ["FOUNDRY_MEMORY_STORE_NAME"],
# Scope namespaces memories (e.g., per end-user). When unset, the
# provider falls back to the session id, which limits memories to a
# single session.
scope=os.environ.get("FOUNDRY_MEMORY_SCOPE", "user_123"),
# In production, leave update_delay at its default to batch updates and
# reduce cost. We use 0 here so memories are written immediately, which
# makes the sample easier to demo.
update_delay=0,
memory_store_name=os.environ["MEMORY_STORE_NAME"],
# Scope memories by user id, so each user that interacts with the agent
# has their own isolated memories in the store (assuming those users are
# granted access). `{{userId}}` is a special placeholder that the hosting
# infrastructure will replace with the actual user id at runtime.
scope="{{$userId}}",
)
agent = Agent(
@@ -2,7 +2,7 @@
"""Provision the Azure AI Foundry Memory Store used by this sample.
Creates the memory store named by ``FOUNDRY_MEMORY_STORE_NAME`` if it does not
Creates the memory store named by ``MEMORY_STORE_NAME`` if it does not
already exist. The store is configured with the user-profile capability so the
agent can remember stable facts about a user across sessions; chat-summary is
disabled to keep the demo focused on durable preferences. Safe to re-run: if a
@@ -14,10 +14,10 @@ Usage (from this directory, with the venv activated and ``az login`` done):
Required env vars (also read from a local ``.env`` file if present):
FOUNDRY_PROJECT_ENDPOINT e.g. https://<account>.services.ai.azure.com/api/projects/<project>
AZURE_AI_MODEL_DEPLOYMENT_NAME Chat model deployment used by the memory store
AZURE_OPENAI_EMBEDDING_MODEL Embedding model deployment used by the memory store
FOUNDRY_MEMORY_STORE_NAME Name of the memory store to create
FOUNDRY_PROJECT_ENDPOINT e.g. https://<account>.services.ai.azure.com/api/projects/<project>
AZURE_AI_MODEL_DEPLOYMENT_NAME Chat model deployment used by the memory store
AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME Embedding model deployment used by the memory store
MEMORY_STORE_NAME Name of the memory store to create
Your identity needs ``Azure AI User`` on the Foundry project scope.
"""
@@ -34,14 +34,14 @@ from azure.core.exceptions import ResourceNotFoundError
from azure.identity.aio import DefaultAzureCredential
from dotenv import load_dotenv
load_dotenv()
async def main() -> None:
load_dotenv()
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
memory_store_name = os.environ["FOUNDRY_MEMORY_STORE_NAME"]
memory_store_name = os.environ["MEMORY_STORE_NAME"]
chat_model = os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
embedding_model = os.environ["AZURE_OPENAI_EMBEDDING_MODEL"]
embedding_model = os.environ["AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME"]
async with (
DefaultAzureCredential() as credential,
@@ -73,6 +73,18 @@ async def main() -> None:
)
print(f"Created memory store '{created.name}' (id={created.id}).")
# Verify the store actually exists on the service by reading it back.
# ``create`` returns the requested definition, but a follow-up ``get``
# confirms the store is persisted and reachable for the agent at runtime.
try:
verified = await project.beta.memory_stores.get(name=memory_store_name)
except ResourceNotFoundError as exc:
raise RuntimeError(
f"Memory store '{memory_store_name}' was not found after creation; "
"the service may not have persisted it."
) from exc
print(f"Verified memory store '{verified.name}' is available on the service (id={verified.id}).")
if __name__ == "__main__":
asyncio.run(main())