ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

用 Azure API Management 构建 AI 网关:awesome-copilot 中的 `llm-*` 策略实战指南

用 Azure API Management 构建 AI 网关:awesome-copilot 中的 `llm-*` 策略实战指南 用 Azure API Management 构建 AI 网关awesome-copilot 中的llm-*策略实战指南【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot本文以开源仓库 awesome-copilot 的社区指令 instructions/azure-apim-ai-gateway.instructions.md 为骨架系统讲解如何把Azure API ManagementAPIM配置为Microsoft FoundryAzure AI Foundry模型部署与任意 OpenAI 兼容 LLM API前面的AIGenAI网关涵盖基于 token 的限流与配额、token 指标观测、托管身份认证、后端池负载均衡与熔断、语义缓存和内容安全。读完本文你将掌握一套可直接复制运行的 APIM AI 网关策略模板并理解该指令文件为什么专门针对 Copilot 生成策略时最常见的四类错误做了前置纠正。为什么需要这份指令Copilot 默认会犯的四类错误该指令文件的 frontmatter 以applyTo: **/*.xml, **/policies/**, **/*.bicep声明适用范围意味着当 Copilot 处理 APIM 策略 XML 或 Bicep 文件时应优先遵循本文档。指令开篇的Field note明确记录了 Copilot 辅助 APIM 工作时的默认坏行为用了过时的 provider 专属策略默认倾向使用旧的azure-openai-*系列策略而不是当前 provider 无关的llm-*系列用请求计数限流用rate-limit-by-key这类对 LLM 流量不理解 token的策略做节流用存储密钥而非托管身份从 named value 里取api-key头去认证模型后端而不是用托管身份元素顺序任意AI 网关策略的元素是顺序敏感的随意排列会被 APIM 拒绝。指令要求当这些内容与训练数据冲突时遵循本文件并在定稿前对照 Microsoft Learn 的genai-gateway-capabilities文档或 Microsoft Docs MCP server 校验该策略面更新频繁训练数据容易过时。核心规则四条必须内化的原则1. 优先使用 provider 无关的llm-*策略llm-token-limit、llm-emit-token-metric、llm-semantic-cache-lookup/-store、llm-content-safety可以统一工作在OpenAI Chat Completions / Responses APIAnthropic Messagesv2 层级Google Vertex AI。只有当 API 是纯 Azure OpenAI 且有明确理由时才使用azure-openai-*变体。2. 按 token 限流而非按调用次数rate-limit-by-key只统计请求数对 token 成本失明。LLM API 的成本与吞吐瓶颈都以 token 计因此必须使用llm-token-limit。3. 用托管身份认证绝不存密钥RBAC 角色与 token audience取决于模型类型详见下文认证一节。Azure OpenAI 与其它 Foundry 模型的角色和 audience 不同混用是常见坑。4. 尊重策略元素顺序保留base /每个策略的元素与子元素都必须按文档顺序排列并在inbound、backend、outbound、on-error各节中保留base /。5. 逐策略核对层级支持层级支持因策略而异llm-token-limit与llm-content-safety不适用于 Consumption 层级llm-emit-token-metric与llm-semantic-cache-*适用于所有层级含 Consumption。不要假设逐个查看每个策略的 Applies to 说明。另外优先配置 APIMbackend资源携带托管身份凭据而不是内联的authentication-managed-identityset-header直接导入 Foundry API 时会自动完成这套接线。Token 限流与配额llm-token-limit该策略用于执行 tokens-per-minuteTPM速率限制、固定时间窗口的 token 配额或两者同时生效。计数器键counter-key可绑定任意维度订阅 ID、IP、JWT 声明或自定义请求头。!-- inbound -- llm-token-limit counter-key(context.Subscription.Id) tokens-per-minute500 token-quota500000 token-quota-periodMonthly estimate-prompt-tokenstrue remaining-tokens-variable-nameremainingTokens /关键行为与约束超过tokens-per-minute返回429 Too Many Requests超过token-quota返回403 Forbidden。客户端必须区分处理——这里的 403 是配额耗尽信号不是认证失败token-quota-period的合法取值Hourly、Daily、Weekly、Monthly、Yearly必填约束tokens-per-minute与token-quotatoken-quota-period至少二选一counter-key始终必填estimate-prompt-tokenstrue会在提示词进入后端之前就估算 token 并拒绝超限请求避免浪费后端算力counter-key可用策略表达式实现按应用/团队/租户隔离例如(context.Request.Headers.GetValueOrDefault(x-team-id,anon))。可观测性llm-emit-token-metric该策略向Application Insights上报 prompt/completion/total 三类 token 指标便于按消费方归因花费并可通过维度在 Azure Monitor 中切片分析。!-- inbound -- llm-emit-token-metric namespacellm-metrics dimension nameAPI ID / dimension nameSubscription ID / /llm-emit-token-metric前置条件与告警点三个前提缺一不可否则策略不会发出任何可用指标① APIM 实例已连接 Application Insights logger②LLM API 已启用 Application Insights 日志③Application Insights 已启用带维度的自定义指标发 token 指标不需要记录消息内容。完整的 prompt/completion 日志是独立的、显式 opt-in步骤——只有在明确需要时才开启因为它可能持久化 PII、密钥和其它敏感内容。若开启必须做字段脱敏、限制日志读取权限、设置短保留窗口并经过合规/隐私评审指标来自模型响应的usage段。部分 OpenAI 模型尤其是流式场景会省略 token 计数除非请求设置include_usage: truestream_options被中断的流还会产生不准确的计数。务必让客户端开启 usage 上报否则指标会静默地不完整适用于所有 APIM 层级含 Consumption每个策略最多 5 个自定义维度务必控制维度基数Azure Monitor 将自定义指标上限设为每个区域每个订阅 50,000 个活跃时间序列12 小时窗口序列数是各维度取值数目的乘积。避免使用客户端 IP、用户 ID 这类高基数维度——在正常用户规模下会迅速击穿上限导致指标被丢弃。优先使用稳定的内置维度如API ID、Subscription ID按用户归因交给日志/查询完成。认证托管身份而不是密钥RBAC 角色与 token audience 取决于模型类型这是最容易踩坑的地方——OpenAI 的角色和 audience 对其它 Foundry 模型不生效后端类型需要分配的角色token audienceAzure OpenAI 部署Cognitive Services OpenAI Userhttps://cognitiveservices.azure.com非 OpenAI 的 Foundry 模型DeepSeek、Llama、Grok 及 Azure 售卖的其他模型Cognitive Services UserOpenAI 角色不授予这些模型访问权https://ai.azure.com将角色授予 Foundry 资源上 APIM 的托管身份然后在网关处认证。内联形式以 Azure OpenAI 为例非 OpenAI Foundry 模型将resource换成https://ai.azure.com!-- inbound -- authentication-managed-identity resourcehttps://cognitiveservices.azure.com output-token-variable-namemanaged-id-access-token ignore-errorfalse / set-header nameAuthorization exists-actionoverride value(Bearer (string)context.Variables[managed-id-access-token])/value /set-header推荐形式配置一个携带托管身份凭据的backend指向匹配的 audienceAzure OpenAI 用https://cognitiveservices.azure.com/其它 Foundry 模型用https://ai.azure.com/再用set-backend-service backend-id... /引用它——这正是直接导入 Foundry API 时 APIM 自动搭建的方式。重要——Authorization头会被覆盖。上面的set-header以及 backend 形式会在请求到达后端之前用 APIM 的托管身份 token 替换调用方的Authorization。如果下游还需要调用方身份例如按用户分区语义缓存必须在覆盖之前用validate-jwt ... output-token-variable-namecallerJwt /先保存它再从变量中读取——覆盖之后Authorization里是后端身份而不是调用方的。弹性后端池、负载均衡与熔断器不要在应用代码里手写跨多个 Foundry 端点的重试/故障转移逻辑。正确做法是定义 APIMbackend 池让网关做负载均衡round-robin、加权、优先级、会话亲和并配置熔断器来尊重后端的Retry-After头。用priority优先走 PTU 端点、回退到按量付费pay-as-you-goresource pool Microsoft.ApiManagement/service/backends2023-09-01-preview { name: ${apimName}/foundry-pool properties: { description: Load-balanced Foundry endpoints type: Pool pool: { services: [ { // PTU — preferred id: backend1.id priority: 1 weight: 1 } { // PayGo — fallback id: backend2.id priority: 2 weight: 1 } ] } } } resource backend1 Microsoft.ApiManagement/service/backends2023-09-01-preview { name: ${apimName}/foundry-ptu properties: { url: https://foundry-1.openai.azure.com/openai protocol: http circuitBreaker: { rules: [ { name: trip-on-backend-failures failureCondition: { count: 3 interval: PT1H // 429 PTU/TPM saturation (honors Retry-After), 5xx backend failure statusCodeRanges: [ { min: 429 max: 429 } { min: 500 max: 599 } ] errorReasons: [ Server errors ] } tripDuration: PT1H acceptRetryAfter: true } ] } } } resource backend2 Microsoft.ApiManagement/service/backends2023-09-01-preview { name: ${apimName}/foundry-paygo properties: { url: https://foundry-2.openai.azure.com/openai protocol: http } }要点解析池类型type: Pool声明这是一个负载均衡后端池services中通过priority表达优先级数字越小越优先weight表达权重熔断规则trip-on-backend-failures在PT1H1 小时窗口内累计3 次429或5xx即触发熔断熔断持续PT1H429被纳入熔断条件是因为 PTU/TPM 饱和也会返回 429acceptRetryAfter: true让熔断器尊重后端Retry-After头该示例使用的是2023-09-01-previewAPI 版本实际部署时应按当前支持的版本核对。语义缓存llm-semantic-cache-lookup/-store按提示词的向量相似度缓存补全结果以降低 token 开销与延迟。这不是内存缓存它需要外部RediSearch 兼容缓存例如 Azure Managed Redis接入 APIM并且需要embeddings 后端。Lookup 放在inboundstore 放在outbound!-- inbound -- llm-semantic-cache-lookup score-threshold0.15 embeddings-backend-idembeddings-backend embeddings-backend-authsystem-assigned ignore-system-messagestrue max-message-count10 !-- Subscription id alone shares one partition across all users on that subscription. For user-specific responses, vary by the authenticated callers subject. Key off the caller JWT saved by validate-jwt (output-token-variable-namecallerJwt) earlier in inbound — do NOT read Authorization here; it is overwritten with APIMs managed-identity token before lookup. A cast is used because a generic (Jwt) would put a raw in the XML, which is invalid: -- vary-by(context.Variables.ContainsKey(callerJwt) ? ((Jwt)context.Variables[callerJwt]).Subject : context.Subscription.Id)/vary-by /llm-semantic-cache-lookup!-- outbound -- llm-semantic-cache-store duration60 /阈值与安全边界score-threshold越低 匹配越严格缓存命中更少、保真度更高。建议按用例调优从0.05–0.15起步用vary-by把缓存分区对齐到真正的机密边界。只按 APIM 订阅 ID 分区意味着该订阅下的所有用户共享一个分区可能收到彼此的缓存补全——这是数据暴露风险。当响应是用户特定的时把已认证调用方的 subject 加进vary-by捕获调用方 token 要在inbound早期用validate-jwt output-token-variable-namecallerJwt ... /完成在托管身份步骤覆盖Authorization之前然后用带类型转换的方式读取保存的变量(context.Variables.ContainsKey(callerJwt) ? ((Jwt)context.Variables[callerJwt]).Subject : context.Subscription.Id)。注意这里必须用显式强转——泛型Jwt会在 XML 中产生一个裸导致策略 XML 非法。查找时不要重新读取Authorization此刻它已是 APIM 的后端 token会把所有调用方折叠进同一个分区。内容安全llm-content-safety该策略在提示词到达模型之前通过Azure AI Content Safety进行筛查并可选择性在模型回复补全之后再筛查响应。配置一个内容安全后端并设置严重性阈值。注意默认值陷阱shield-prompt越狱/提示词注入检测与enforce-on-completions默认都是false因此默认情况下 inbound 策略只筛查提示词要同时筛查模型补全需设置enforce-on-completionstrue或将策略放在outbound节。!-- inbound -- llm-content-safety backend-idcontent-safety-backend shield-prompttrue categories output-typeEightSeverityLevels category nameHate threshold4 / category nameViolence threshold4 / /categories /llm-content-safety阈值语义使用0–7 严重性分级threshold4表示放行 0–3、拦截 4–7。想更宽松就调高阈值想更严格就调低。策略骨架与元素顺序将 AI 网关策略放入正确分区并保留base /。以下是一个完整、可直接作为起点的策略骨架它正确编排了各策略的顺序并解释了为什么必须如此排列policies inbound base / !-- Authenticate the caller and SAVE their token before Authorization is overwritten below. Required to partition the semantic cache per user. Fill in your issuer/audience. -- validate-jwt header-nameAuthorization output-token-variable-namecallerJwt failed-validation-httpcode401 openid-config urlhttps://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration / audiences audienceapi://your-api-client-id/audience /audiences /validate-jwt set-backend-service backend-idfoundry-pool / authentication-managed-identity resourcehttps://cognitiveservices.azure.com output-token-variable-namemi / set-header nameAuthorization exists-actionoverride value(Bearer (string)context.Variables[mi])/value /set-header llm-content-safety backend-idcontent-safety-backend shield-prompttrue categories output-typeEightSeverityLevels category nameHate threshold4 / /categories /llm-content-safety !-- Cache lookup BEFORE token-limit/metric: a cache hit short-circuits the pipeline, so a cached request must not consume the callers TPM/quota. Content safety stays above the lookup so every prompt is still screened. -- llm-semantic-cache-lookup score-threshold0.1 embeddings-backend-idembeddings-backend embeddings-backend-authsystem-assigned !-- Partition per authenticated caller (from the saved token) to prevent cross-user cache leakage. Cast, not a generic, so no raw appears in the XML. -- vary-by(context.Variables.ContainsKey(callerJwt) ? ((Jwt)context.Variables[callerJwt]).Subject : context.Subscription.Id)/vary-by /llm-semantic-cache-lookup llm-token-limit counter-key(context.Subscription.Id) tokens-per-minute500 estimate-prompt-tokenstrue / llm-emit-token-metric namespacellm-metrics dimension nameAPI ID value(context.Api.Id) / /llm-emit-token-metric /inbound backendbase //backend outbound base / llm-semantic-cache-store duration60 / /outbound on-errorbase //on-error /policies顺序设计背后的两个关键决策语义缓存查找放在 token-limit / token-metric 之前缓存命中会短路流水线因此已缓存的请求不应消耗调用方的 TPM/配额但内容安全必须放在查找之上保证每个提示词仍被筛查validate-jwt必须放在最前它在托管身份步骤覆盖Authorization之前保存调用方 token供vary-by分区使用。Foundry 原生 AI 网关集成Foundry 与 APIM 有内置集成在 Foundry 门户中可以直接创建新的 APIM 实例或把现有实例附加为 AI 网关然后在Operate → Admin → AI Gateway → Token management设置每个部署的 TPM 限制与配额——这些设置直接映射到llm-token-limit。附加现有APIM 实例有硬性前提必须与 Foundry 资源位于同一 Microsoft Entra 租户与订阅必须是v2 层级Basic v2 / Standard v2 / Premium v2至少需要对该实例具有API Management Service Contributor或 Owner角色否则不会出现在可选项里若 Foundry 资源禁用了公共网络访问APIM 实例也必须可私有访问——使用带私有端点的 Standard v2 / Premium v2或注入虚拟网络的 Premium v2。该网关还能治理注册的 agent可运行在任何地方在preview阶段还能治理MCP 工具只有不使用托管 OAuth 的新 MCP 工具会被路由策略在 Azure 门户应用而非 Foundry 门户。当仓库使用这一集成时应保持自定义策略与 Foundry 管理的配置兼容而不是覆盖它。推荐做法在 APIM 中将 API 导入为Language Model API或Azure AI Foundry API这会自动创建 backend、set-backend-service以及可选的 token/缓存/安全策略。与仓库的关联这是一份可安装的 Copilot 指令本文解析的 instructions/azure-apim-ai-gateway.instructions.md 是 awesome-copilot 仓库中社区贡献的Custom Instructions集合成员之一见 docs/README.instructions.md。安装与使用方式将该*.instructions.md文件内容复制到工作区的.github/copilot-instructions.md或放入.github/instructions/目录例如.github/instructions/azure-apim-ai-gateway.instructions.md指令安装后会自动按 frontmatter 的applyTo文件模式XML 策略文件、policies/目录、Bicep 文件作用于 Copilot 行为贡献指南见 CONTRIBUTING.md。与之配套的生态参考仓库内另一份指令 instructions/microsoft-foundry.instructions.md 从 Python SDK 侧印证了同一套安全基线——Foundry 生态只支持 Entra ID 认证本地开发用DefaultAzureCredential部署到 AzureApp Service、Container Apps、Functions用ManagedIdentityCredential且身份必须被授予相应 RBAC 角色。这与本指令网关侧用托管身份、按模型类型分配 Cognitive Services 角色的原则互为表里客户端侧用托管身份连 Foundry网关侧用托管身份代表调用方访问模型后端全程不落任何静态密钥。Grounding定稿前的校验建议AI 网关策略面演进很快。在最终确定策略 XML 之前建议针对以下内容逐项核对元素名、属性与顺序Microsoft Learn 的genai-gateway-capabilities文档及各策略的独立参考页通过 Microsoft Docs MCP server 查询最新定义对每个策略确认其 Applies to 层级声明尤其是 Consumption 层级不支持的llm-token-limit与llm-content-safety。而不是依赖模型训练数据——因为训练数据中的策略表面很可能已经过时。【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表