Implement generative AI and agentic solutions 2.2 Build agents by using Foundry
A backend service calls a prompt agent with the memory search tool (preview) on behalf of…
Study guide skill: Build agents that integrate retrieval, function-calling, and conversation memory
Question B2-012
A backend service calls a prompt agent with the memory search tool (preview) on behalf of thousands of customers, always using the service's own Microsoft Entra identity. Each customer's memories must stay isolated, and you don't want to hard-code customer IDs in the agent definition. How should you configure memory?
Select one answer.
Answer: A
With the memory search tool (preview), setting scope to {{$userId}} gives per-user isolation without hard-coded identifiers, and the user ID is taken from the x-memory-user-id request header, which is meant for backend scenarios where a service calls on behalf of end users. Without the header, scope falls back to the caller's Entra identity (tenant and object ID), which here is the same backend service for every customer, so memories would be shared. A static scope also shares memories, and a store per conversation loses long-term memory.
Deep dive
How it works
In Foundry Agent Service memory (preview), the scope parameter controls how memory is partitioned. Each scope in a memory store keeps its own isolated collection of memory items, so in a customer support agent each customer should get their own scope.
With the memory search tool, set scope to {{$userId}} to get per-user isolation without hard-coding identifiers. On each response call, the service resolves the end user's identity from one of two sources, in this order:
- The x-memory-user-id request header. If it's present, its value is the user ID. This is meant for proxy or backend scenarios where your service calls the API on behalf of an end user.
- The Microsoft Entra token. If the header isn't set, the scope falls back to the caller's tenant ID and object ID. That's the default for frontend apps where users sign in directly.
This backend always calls with its own identity. Without the header, every customer would resolve to the same scope and share memories. So the backend sends x-memory-user-id with each customer's ID on every response call.
The other options, and when you'd use them
- A static scope such as support-agent: A static scope is for when you don't need per-user isolation. Every customer would share one memory collection.
- {{$userId}} relying on the caller's Entra token: Without the header, the scope falls back to the caller's tenant and object ID. Here the caller is always the backend service, so all customers collapse into one scope.
- A new memory store for every conversation: Memory is designed to give agents continuity across sessions. A store per conversation throws that away, and the guidance is to create a dedicated memory store per agent, with scope separating users.
Exam tip
Backend calling on behalf of users = scope {{$userId}} + x-memory-user-id header. Users signing in directly = {{$userId}} resolves from their Entra token.
References
Last reviewed: