运行 sidecar 进行本地开发

本文介绍如何使用 Docker Compose 在本地环境中运行 Microsoft Entra ID 身份验证 SDK(sidecar)。 启动四容器堆栈 - 聊天代理、sidecar、下游天气 API 和本地大型语言模型(如 (Ollama)。 然后,通过聊天 UI 发送查询,并观察从代理到 API 的完整令牌流。 在开始之前,请查看所需工具、Microsoft Entra租户对象和本地环境设置的先决条件

此示例演示了两种执行模式和两个标识流:

自治 (仅限应用) OBO (代表用户)
直接 (无 LLM) 代理提取令牌并直接调用天气 API。 同样,但 sidecar 会交换已登录用户的令牌。
Ollama + LangChain LangGraph ReAct 代理决定何时调用该工具 get_weather 代理也是如此,但它通过用户令牌进行传递。

先决条件

此示例适用于 macOS、Linux 和 Windows 10/11。

Requirement macOS Linux Windows操作系统
Docker Docker Desktop Docker 引擎 + Compose v2 Docker Desktop (建议使用 WSL 2 后端)
PowerShell 7+ brew install --cask powershell 在 Linux 上安装 PowerShell 内置(或安装 PowerShell 7+)
Azure CLI brew install azure-cli 安装 Azure CLI winget install -e Microsoft.AzureCLI

您还需要一个 Microsoft Entra 租户,其中包含以下对象:

  • 具有客户端密钥的代理程序标识蓝图。 记录其值 BLUEPRINT_APP_IDBLUEPRINT_CLIENT_SECRET
  • 从该蓝图生成的代理身份。 记录 AGENT_CLIENT_ID
  • (仅限 OBO 流)SPA 应用注册。 记录 CLIENT_SPA_APP_ID

若要创建这些对象,请遵循 Microsoft Entra 智能体 ID 示例存储库中的 PowerShell 工作流。 工作流创建蓝图应用、代理标识,以及用于 OBO 登录的 SPA 应用( 可选)。

Ollama 不是 主机上的先决条件 - 它在 Compose 堆栈中运行并自动拉取 qwen2.5:1.5b

克隆示例存储库

运行以下命令,下载示例项目并更改为 sidecar 目录,其中包含本演练的 Docker Compose 配置和代理源代码:

git clone https://github.com/microsoft/entra-agentid-samples.git
cd entra-agentid-samples/sidecar/dev

Sidecar 本地开发架构

该堆栈在内部 Docker 网络上运行四个容器:llm-agent-dev(Flask 聊天 UI,通过 3003 端口对外提供服务)、agent-id-sidecar-dev(Microsoft Entra ID 身份验证 SDK 边车容器)、weather-api-dev(用于验证代理令牌的下游 API)和 ollama-dev(本地 LLM)。 仅聊天 UI 向宿主机公开;sidecar 和天气 API 仅可从 Docker 网络内部访问。

显示 sidecar 体系结构的 显示边车体系结构的图表:Microsoft Entra ID 向边车颁发 TR 令牌,智能体向边车请求授权标头,然后使用持有者 TR 调用天气 API,天气 API 验证令牌并返回数据。

所有四个容器都在共享 Docker 网(agent-network-dev)上运行。 仅聊天界面(端口 3003)向你的主机公开。 边车和天气 API 没有主机端口,使令牌端点保持在信任边界内。

请求路径的工作方式如下所示:

  1. 在浏览器中打开 http://localhost:3003 并发送查询。
  2. 代理 (llm-agent-dev) 接收查询,并决定调用 get_weather 该工具。
  3. 该工具在 GET /AuthorizationHeader...?AgentIdentity={agentId} 请求 sidecar 提供授权标头。
  4. sidecar (agent-id-sidecar-dev) 使用 Microsoft Entra ID 执行 OAuth 2.0 交换,并接收令牌(TR)。
  5. Sidecar 将 Authorization: Bearer TR 标头返回到代理。
  6. 代理使用该标头调用天气 API (weather-api-dev)。
  7. 天气 API 验证 TR(JSON Web 密钥集(JWKS)、RS256 签名算法、颁发者、到期、受众)并返回天气数据。

代理从不直接与Microsoft Entra ID联系,也永远不会看到凭据。 它向边车请求 Authorization 标头,接收 Bearer 令牌,并将该令牌传递给天气 API。 只有边车与 login.partner.microsoftonline.cn 通信。

了解令牌流动

自治流使用两个令牌: T1 (来自客户端凭据的蓝图应用令牌)和 TR (下游 API 的代理令牌)。 OBO 流添加了第三个: Tc (来自 MSAL.js 浏览器登录的用户访问令牌)。 Sidecar 处理所有令牌获取和缓存,以便代理代码永远不会直接管理凭据。

了解自主令牌流

无需用户登录。 代理通过蓝图的客户端凭据对自身进行身份验证。

显示自治流序列的图表:智能体 → 边车 → Microsoft Entra ID → 天气 API。

  1. 用户通过聊天 UI 发送查询。
  2. 代理(或 LangGraph ReAct 代理)决定调用 get_weather 该工具。
  3. 该工具从 sidecar 请求位于 GET /AuthorizationHeaderUnauthenticated/graph-app?AgentIdentity={agentAppId} 的授权标头。
  4. 边车与 Microsoft Entra ID 执行客户端凭据交换并接收 TR(仅应用,idtyp=app)。
  5. 该工具通过 Authorization: Bearer TR 调用天气 API。
  6. 天气 API 验证 TR(签名、颁发者、到期、受众)并返回天气数据。

了解 OBO(代表)令牌流

代理代表已登录用户执行操作。 边车执行三步令牌交换。

显示代表流序列的图表:浏览器登录 → 边车令牌交换 → 天气 API。

  1. 用户在浏览器中通过 MSAL.js 登录并接收 Tc(用户访问令牌,受众 = api://{BlueprintAppId})。
  2. 用户发送查询。 代理与请求一起接收 Tc。
  3. 工具在 GET /AuthorizationHeader/graph 处向边车请求授权标头,传递 Authorization: Bearer Tc?AgentIdentity={agentAppId}
  4. sidecar 验证 Tc,执行客户端凭据交换以获取 T1,然后执行 OBO 交换来获取 TR(委托, idtyp=user)。 OBO 交换使用assertion=Tcclient_assertion=T1grant_type=jwt-bearer
  5. 该工具通过 Authorization: Bearer TR 调用天气 API。
  6. 天气 API 验证 TR 并返回天气数据。 TR 代表已登录用户执行操作。

配置环境变量

Tip

如果以前运行中有一个.env文件,TENANT_IDBLUEPRINT_APP_ID并且BLUEPRINT_CLIENT_SECRETAGENT_CLIENT_ID已填充,请跳到“启动堆栈”。 Microsoft Entra 对象在容器重启和 docker compose down 后保留。

复制该示例环境文件并添加您的 Microsoft Entra 参数值:

从示例模板创建本地环境文件,以便填写租户和应用注册值:

cp .env.example .env

在编辑器中打开 .env 并设置以下值:

Variable 说明
TENANT_ID Microsoft Entra租户标识。
BLUEPRINT_APP_ID 蓝图应用注册客户端 ID。 sidecar 作为此应用进行身份验证。
BLUEPRINT_CLIENT_SECRET 蓝图客户端密码。 仅用于本地开发。
AGENT_CLIENT_ID 你的智能体标识客户端 ID。 作为 AgentIdentity 查询参数传递给边车。
CLIENT_SPA_APP_ID SPA 应用注册客户端 ID。 仅适用于 OBO 流程。
OLLAMA_MODEL 要使用的 Ollama 模型。 默认值为 qwen2.5:1.5b.

自治流需要TENANT_IDBLUEPRINT_APP_IDBLUEPRINT_CLIENT_SECRETAGENT_CLIENT_ID。 OBO 流也需要 CLIENT_SPA_APP_ID

此 Sidecar 示例使用 ClientSecret 作为凭据来源类型。 通过在 AzureAd__ClientCredentials__0__SourceType 中的 docker-compose.yml 设置,Sidecar 支持以下凭据类型:

  • ClientSecret 仅限本地开发。 此类型是此示例的默认值。
  • SignedAssertionFromManagedIdentity部署在Azure上。 建议采用零秘密原则进行生产。
  • KeyVault来自Azure 密钥保管库的证书。
  • StoreWithThumbprint 来自本地计算机存储的证书。

设置 OBO 登录(可选)

若要测试代理流,请创建 SPA 应用并配置 OBO 同意。 从存储库根目录运行以下脚本对之一:

# Create the SPA app registration for MSAL.js browser sign-in
bash ../../scripts/setup-obo-client-app.sh
# → prints CLIENT_SPA_APP_ID

# Wire up the OBO scope + admin consent on the Blueprint
bash ../../scripts/setup-obo-blueprint.sh

运行脚本后,将 CLIENT_SPA_APP_ID 该值添加到 .env 文件。

启动堆栈

运行以下命令,生成容器映像,并在分离模式下启动所有四个服务:

docker compose up --build -d

第一次运行需要约 30 秒,Ollama 拉取 qwen2.5:1.5b 模型。 若要验证本地示例堆栈是否正在运行,并且 sidecar 和 Ollama 等组件已准备就绪,请查询状态终结点:

curl http://localhost:3003/api/status

响应显示 ollama_available: true 当堆栈就绪时。

通过聊天 UI 发送查询

执行以下步骤,通过聊天 UI 发送测试查询并观察令牌流:

  1. 在浏览器中打开 http://localhost:3003

  2. 在标头栏中,验证 租户 ID代理 ID 是否显示。

  3. 使用两个开关选择演示配置:

    • 执行模式:选择 “直接 ”以跳过 LLM 并直接调用天气 API,或选择 Ollama 以使用 LangChain ReAct 代理。
    • 标识流:为应用专用令牌选择 自主,或选择 OBO (代表) 代表已登录用户执行操作。 对于 OBO,请选择 “登录 ”以通过 MSAL.js 弹出窗口进行身份验证。
  4. 发送预填充的查询“达拉斯天气?”并查看结果。

  5. 在右侧面板中,展开标识跟踪以查看令牌流的每个步骤:

    • 向 sidecar 请求令牌,包括 AgentIdentity 参数。
    • 每个令牌的解码 JWT 声明 (适用于 OBO: Tc, T1, TR; 适用于自治: T1, TR)。
    • 下游 API 验证结果,包括签名(JWKS、RS256)、颁发者、到期和受众检查。

排查常见问题

症状 可能的原因 修复
/api/status 返回 ollama_available: false 模型仍在下载。 等待大约 30 秒。 使用 docker logs ollama-dev 检查日志。
天气 API 返回 401 Unauthorized 令牌租户不匹配、过期的密钥或签名检查失败。 验证 TENANT_ID 是否与蓝图的租户匹配。 使用 docker logs agent-id-sidecar-dev 检查 sidecar 日志。
LLM 在不调用该工具的情况下返回天气 模型 qwen2.5:1.5b 太小,无法进行可靠的工具调用。 OLLAMA_MODEL文件中的qwen2.5:7b更改为llama3.1:8b.env
OBO 登录弹出窗口被阻止 浏览器弹出窗口阻止程序处于活动状态。 允许弹出窗口。localhost:3003
4xx Sidecar 在 OBO 期间出错 CLIENT_SPA_APP_ID 缺少或 SPA 重定向 URI 不匹配。 重新运行 OBO 安装脚本。 确认 http://localhost:3003 列在 SPA 的重定向 URI 中。

若要诊断启动、身份验证或下游 API 问题,请运行以下命令显示每个容器的日志:

docker logs llm-agent-dev
docker logs agent-id-sidecar-dev
docker logs weather-api-dev

清理资源

使用完毕后,停止容器。 选择符合需求的清理级别。 第一个命令会停止演示容器,同时保留卷和映像,以便稍后更快地重启:

# Stop containers, keep volumes and images
docker compose down

# Stop containers and remove the Ollama model cache
docker compose down -v

# Remove containers, volumes, and images
docker compose down -v --rmi all