ユーザーごとにホストされるエージェント セッションを分離する

1 つのホストされたエージェントは、1 つのエンドポイントから多数のユーザーにサービスを提供します。 この記事では、Microsoft Foundry が各ユーザーのセッション、会話、および保存されたデータをプライベートに保持する方法と、その分離を独自のアプリケーションのユーザーに拡張する方法について説明します。 最後に、エージェントを呼び出し、1 つの呼び出し元が別の呼び出し元のセッション、会話、または格納されたデータを表示できないことを確認できます。

前提条件

Important

Foundry RBAC ロールの名前が最近変更されました。 Foundry User, Foundry Owner, Foundry Account Owner、および Foundry Project Manager は、以前は、AZURE AI ユーザー、Azure AI 所有者、Azure AI アカウント所有者、および AZURE AI Project Manager という名前でした。 名前の変更がロールアウトされている間、以前の名前が表示される場合があります。ロール ID とコア アクセス許可は、名前の変更によって変更されません。

ユーザーごとの分離について

プラットフォームは、Microsoft Entra トークンから各呼び出し元を識別し、すべての呼び出し元が 1 つの共有エンドポイントを介して同じエージェントに到達した場合でも、その ID に対してデータをプライベートに保ちます。 ユーザーごとに、次の情報が分離された状態が維持されます。

  • 会話。 各ユーザーの会話履歴 (応答プロトコルを介してスレッド処理されるメッセージ、ツール呼び出し、応答) は、そのユーザーに対してプライベートです。 あるユーザーが別のユーザーの会話を読んだり、一覧表示したりすることはできません。
  • セッション。 各呼び出し元は既定で独自のセッションを取得するため、1 人のユーザーが一覧表示して管理できるセッションには、別のユーザーのセッションは含まれません。
  • 格納されたデータ。 エージェントがユーザーに対して格納するデータは、そのユーザーにスコープ設定されているため、別のユーザーには返されません。

これは、多くのプライベート ワークスペースにサービスを提供する 1 つのエージェントと考えてください。 各セッションでは、独自のサンドボックス内のプライベート $HOME ファイルシステムも取得されます。各ユーザーが独自のセッションを取得するため、既定で分離されます。 代わりに複数のユーザーを 1 つのセッションに配置した場合、そのサンドボックスは共有されます。 1 つのホストされたエージェント セッションで複数のユーザーを多重化する方法を参照してください。 セッション モデルの詳細については、「 Foundry Agent Service のホストされたエージェント」を参照してください。

一般的なシナリオは次のとおりです。

  • ユーザーごとのチャット。 サインインしている各顧客は、独自の会話履歴、セッション、保存されたデータを取得します。
  • マルチテナント アプリ。 各テナントのユーザーは、他のすべてのテナントのユーザーから分離されます。

この分離は既定で適用されます。 次のセクションでは、既定のパスと、自分で認証するユーザーに拡張する方法を示します。

自動分離を使用してエージェントを呼び出す

サインイン ID としてエージェントを呼び出します。 プラットフォームは、その ID をスコープとするセッションを作成し、その agent_session_idを返します。

azd ai agent invoke "Summarize the latest support tickets"

セッションは、 azd auth loginの ID に属します。 同じコマンドを実行する別のサインイン ユーザーは、個別のプライベート セッションを取得します。

REST の例で使用する共有変数を設定します。

BASE_URL="https://my-account.services.ai.azure.com/api/projects/my-project"
API_VERSION="v1"
RESOURCE="https://ai.azure.com"
AGENT_NAME="my-agent"

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/openai/responses?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --body '{
        "input": "Summarize the latest support tickets",
        "stream": false
    }'

要求のMicrosoft Entra トークンは、呼び出し元を識別します。 応答ペイロードには、プラットフォームによって作成され、その ID にスコープが設定された agent_session_id が含まれます。

openai_client = project.get_openai_client(agent_name="my-agent")

response = openai_client.responses.create(
    input="Summarize the latest support tickets",
)
session_id = response.model_extra.get("agent_session_id")
print(f"Session: {session_id}")

OpenAI クライアントは呼び出し元のMicrosoft Entra資格情報を使用して認証を行うので、セッションはその ID にスコープ設定されます。

const openAIClient = project.getOpenAIClient({
    azureConfig: { allowPreview: true, agentName: "my-agent" },
});

const response = await openAIClient.responses.create({
    input: "Summarize the latest support tickets",
});
const sessionId = (response as any).agent_session_id;
console.log(`Session: ${sessionId}`);

OpenAI クライアントは呼び出し元のMicrosoft Entra資格情報を使用して認証を行うので、セッションはその ID にスコープ設定されます。

独自のユーザーのセッションを分離する

アプリケーションが独自のエンド ユーザー (たとえば、Google、GitHub、カスタム ID プロバイダーを通じて) を認証する場合、信頼されたサービスは、要求が属するエンド ユーザーを Foundry に通知できるため、プラットフォームは呼び出し元のサービスごとにではなく、エンド ユーザーごとにセッションを分離します。

サービスは、エンド ユーザーの安定した識別子を x-ms-user-identity ヘッダーに送信します。 プラットフォームは、値を不透明な文字列として扱い、セッションのスコープを設定します。 値は 1 ~ 256 文字にする必要があり、文字、数字、および . _ : - @文字のみを含む必要があります。その他の値は拒否されます。

x-ms-user-identityを渡すには、呼び出し元 ID がエージェントに対するMicrosoft.CognitiveServices/accounts/AIServices/agents/endpoints/UserIdentityImpersonation/actionアクセス許可を保持している必要があります。 このアクセス許可は、組み込みロールには含 まれません 。 以前は Microsoft.CognitiveServices/* データ アクションの対象でしたが、そのアクションでは許可されなくなります。 データ アクションを含むカスタム ロールを作成し、そのロールを中間層サービスの ID に割り当てることで、明示的に付与します。 それを持たない呼び出し元は、403 を受け取ります。 カスタム ロール定義と割り当てコマンドについては、「 エンドユーザー ID の委任」を参照してください。

サービスがこのアクセス許可を保持しているが、要求でヘッダーを送信しない場合、プラットフォームはそのセッションをエンド ユーザーではなくサービスの独自の ID にスコープします。 サービスでは、委任された呼び出しと委任されていない呼び出しを混在させることができますが、 x-ms-user-identity を含む要求のみがエンド ユーザーごとに分離されます。

Warning

委任内では、プラットフォームは委任されたエンド ユーザーを別のエンド ユーザーからフェンスしません。 委任された呼び出し元と委任されていない呼び出し元の間にのみハード境界が適用されます。これにより、委任されたユーザーは、アプリが作成したセッションに参加できます。 各ユーザーに独自のセッション ID を付与します。2 人のユーザーを同じセッションにルーティングすると、ユーザーは互いのデータを表示できます。 1 つのセッションを意図的に共有するには、 1 つのホストされたエージェント セッションで複数のユーザーを多重化する方法に関するページを参照してください。

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/openai/responses?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "x-ms-user-identity=<stable-end-user-id>" \
    --body '{
        "input": "Summarize my open tickets",
        "stream": false
    }'

<stable-end-user-id>を、テナント スコープのユーザー ID など、サインインしているエンド ユーザーにサービスが割り当てる識別子に置き換えます。

openai_client = project.get_openai_client(agent_name="my-agent")

response = openai_client.responses.create(
    input="Summarize my open tickets",
    extra_headers={"x-ms-user-identity": "<stable-end-user-id>"},
)

<stable-end-user-id>を、サインインしているエンド ユーザーにサービスが割り当てる識別子に置き換えます。 セッションのスコープは、呼び出し元のサービスではなく、そのエンド ユーザーに対して行われます。

const openAIClient = project.getOpenAIClient({
    azureConfig: { allowPreview: true, agentName: "my-agent" },
});

const response = await openAIClient.responses.create(
    { input: "Summarize my open tickets" },
    { headers: { "x-ms-user-identity": "<stable-end-user-id>" } },
);
console.log(response.output_text);

<stable-end-user-id>を、サインインしているエンド ユーザーにサービスが割り当てる識別子に置き換えます。 セッションのスコープは、呼び出し元のサービスではなく、そのエンド ユーザーに対して行われます。

Azure Developer CLI では、エージェントが独自のサインイン ID として呼び出されるため、委任されたエンド ユーザー ID は渡されません。 サービスの REST または SDK パスを使用して、 x-ms-user-identityを送信します。

エンド ユーザー ID をセキュリティで保護する

委任された分離を使用する場合、サービスは信頼の境界になります。 ユーザーごとに安定していて、一意で推測が難しい識別子を選択します。 セッションが正常に再開されるように、同じユーザーに同じ値を再利用します。

Important

認証されたサーバー側 ID から x-ms-user-identity 値を派生させます。ブラウザーまたはクライアントが直接提供する値からは取得されません。 それ以外の場合、呼び出し元はヘッダーを別のユーザーの識別子に設定し、そのユーザーのデータを読み取ることができます。 委任アクセス許可を持つサービスは、エンド ユーザーに代わって動作できるため、信頼できるサービスにのみ付与します。

分離を確認する

2 つの ID が 2 つの個別のセッションを取得することを確認します。

  1. エージェントを 1 つの ID として呼び出し、返された agent_session_idをメモします。
  2. エージェントを 2 つ目の ID (別のサインイン ユーザーまたは別の x-ms-user-identity 値) として呼び出し、その agent_session_idをメモします。
  3. 2 つの ID が異なること、および各 ID でセッションを一覧表示した際に、その ID のセッションのみが返されることを確認します。

分離をエンド ツー エンドで確認するには、 メモを取るエージェント サンプルをデプロイします。このサンプルでは、セッションごとのノートが $HOME に格納されます。各 ID のノートは、セッション ファイル API を介して一覧表示またはダウンロードできる個別のセッション ファイルに配置されます。

ユーザー間のセッションを表示する

既定では、各呼び出し元には独自のセッションのみが表示されます。 プロジェクトで Foundry User ロールを保持する管理者またはオートメーションは、エージェントを作成した ID に関係なく、エージェント上のすべてのセッションを一覧表示および管理できます。 セッションを管理するには、「 ホストされたエージェント セッションの管理」を参照してください。

コンテナー プロトコル 1.0.0 の分離キー (非推奨)

コンテナー プロトコル バージョン 1.0.0 のエージェントは、以前の分離キー モデルを使用します。呼び出し元は、Microsoft Entra トークンから ID を派生させるプラットフォームではなく、セッションのスコープに分離キーを提供します。 このモデルとプロトコル 1.0.0 自体は非推奨です。 プロトコル 1.0.0 のエージェントは、2026 年 7 月 31 日まで引き続き動作します。その後、プラットフォームはプロトコル 1.0.0 で引き続き実行されるエージェントへの要求をブロックします。

プロトコル 2.0.0 にアップグレードして、この記事で前述したユーザーごとの自動分離を取得します。 プロトコル 2.0.0 では、それをサポートする AgentServer SDK (Pythonazure-ai-agentserver-core 2.0.0b7 以降、.NETでは 1.0.0-beta.26 以降Azure.AI.AgentServer.Core) が必要です。 以前のバージョンではプロトコル 1.0.0 が使用されています。アップグレードの一環として更新します。

分離の問題をトラブルシューティングする

症状: 考えられる原因 何を試すか
403 または session_not_accessible セッションにアクセスする際に セッションは別の ID に属しています。 セッションを作成したのと同じ ID を使用するか、Foundry User ロールを保持して他の ID のセッションを表示します。
403 を設定するリクエストの x-ms-user-identity 呼び出し元は、現在は組み込みロールでは付与されない UserIdentityImpersonation アクセス許可を持っていません。 Microsoft.CognitiveServices/accounts/AIServices/agents/endpoints/UserIdentityImpersonation/action データ アクションを含むカスタム ロールを作成し、呼び出し元サービスに割り当てます。
ローカル実行でセッションが分離されない ローカル実行では、分離は強制されません。 デプロイされたエージェントに対して分離性をテストする。 ローカル モード (--localazd ai agent run) は、1 人のユーザーを対象とします。