<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Azure Functions | The .NET Blog</title><link>https://thedotnetblog.com/zh/tags/azure-functions/</link><description>Articles, tutorials and insights from the .NET community.</description><generator>Hugo</generator><language>zh</language><managingEditor>@thedotnetblog (The .NET Blog)</managingEditor><webMaster>@thedotnetblog</webMaster><lastBuildDate>Sun, 31 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/zh/tags/azure-functions/index.xml" rel="self" type="application/rss+xml"/><item><title>Microsoft Agent Framework中的持久工作流：从内存到Azure Functions</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/maf-durable-workflows-azure-functions-durable-task/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/maf-durable-workflows-azure-functions-durable-task/</guid><description>MAF的工作流编程模型现在支持由Durable Task支持的持久执行——以下是如何构建可组合的代理工作流，这些工作流能够在进程重启后继续运行并在Azure Functions上扩展。</description><content:encoded>&lt;p&gt;早期AI代理工作流的痛点之一：它们很脆弱。绑定到单个进程的长时间运行多步骤工作流意味着进程重启 = 状态丢失。对于简单的演示这没问题。对于生产工作负载则不然。&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework的工作流编程模型现在支持&lt;strong&gt;持久执行&lt;/strong&gt;，由Durable Task框架支持，通过Azure Functions托管。以下是编程模型的工作原理以及持久性为何重要。&lt;/p&gt;
&lt;h2 id="核心构建块"&gt;核心构建块&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Executor&lt;/strong&gt;是工作的基本单元。每个都是类型化的——接受特定输入并生成特定输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Workflows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;internal&lt;/span&gt; &lt;span class="kd"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderLookup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderCancelRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;OrderLookup&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OrderCancelRequest&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;IWorkflowContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 查找订单，返回它&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;工作流&lt;/strong&gt;使用流畅构建器将执行器连接成有向图。框架处理执行、步骤之间的数据流和错误传播。&lt;/p&gt;
&lt;p&gt;您可以建模：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;顺序链（步骤A → 步骤B → 步骤C）&lt;/li&gt;
&lt;li&gt;并行fan-out/fan-in（并行运行代理A、B、C，聚合结果）&lt;/li&gt;
&lt;li&gt;条件分支&lt;/li&gt;
&lt;li&gt;人在回路审批（暂停工作流，等待外部信号）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="本地开发的内存运行器"&gt;本地开发的内存运行器&lt;/h2&gt;
&lt;p&gt;入门很快：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workflows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;核心包包含轻量级进程内运行器。无外部依赖，无数据库，无Azure资源。非常适合本地开发和单元测试。&lt;/p&gt;
&lt;h2 id="使用durable-task添加持久性"&gt;使用Durable Task添加持久性&lt;/h2&gt;
&lt;p&gt;当工作流需要在进程重启后继续运行时——因为它运行时间长，因为它有人在回路步骤，因为它分散在许多并行代理调用中——内存运行器不够用。&lt;/p&gt;
&lt;p&gt;MAF的Durable Task集成将工作流状态存储在Azure Storage中。如果进程重启，工作流从中断处继续。编程模型保持不变；只需替换运行器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workflows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DurableTask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;相同的执行器，相同的工作流图——由持久状态支持。&lt;/p&gt;
&lt;h2 id="azure-functions托管"&gt;Azure Functions托管&lt;/h2&gt;
&lt;p&gt;第三层是Azure Functions托管。您的工作流成为Function应用：通过HTTP端点触发工作流，持久运行时处理扩展、状态和可靠性。&lt;/p&gt;
&lt;p&gt;这意味着具有并行调用、条件分支和人工审批的多代理工作流可以在无服务器Functions环境中扩展，无需自定义状态管理。&lt;/p&gt;
&lt;h2 id="为什么这很重要"&gt;为什么这很重要&lt;/h2&gt;
&lt;p&gt;这种组合对真实AI系统很重要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并行代理调用&lt;/strong&gt;——同时分发给多个专门代理而不阻塞，所有代理完成时聚合结果&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长时间运行进程&lt;/strong&gt;——涉及人工审批或外部事件的工作流可以跨小时或天暂停和恢复&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;扩展性&lt;/strong&gt;——Azure Functions水平扩展执行；Durable Task框架管理并行状态协调&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果您正在构建超越简单本地演示的MAF工作流，这就是走向生产质量执行的道路。&lt;/p&gt;
&lt;p&gt;原始文章：&lt;a href="https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/"&gt;Durable Workflows in the Microsoft Agent Framework&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>停止锤打一个挣扎中的依赖：Azure Functions + Service Bus 的重试模式</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/azure-functions-service-bus-exponential-backoff-circuit-breaker/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/azure-functions-service-bus-exponential-backoff-circuit-breaker/</guid><description>指数退避和熔断器模式现在为 Service Bus 触发的 Azure Functions 提供原生支持 — 以下是它们的工作原理以及为什么你需要两者。</description><content:encoded>&lt;p&gt;以下是可恢复故障在 Functions 应用中变成服务中断的过程：依赖项开始超时，每个 Functions 实例立即无限重试，依赖项被数百个并发失败的请求轰炸，原本只是短暂故障的问题变成了全系统的反压事件。&lt;/p&gt;
&lt;p&gt;你可能对这个故事很熟悉。Azure Functions 快速扩展 — 这就是整个意义所在。但&amp;quot;快速扩展&amp;quot;和&amp;quot;立即重试&amp;quot;结合在一起可能会使故障急剧恶化。&lt;/p&gt;
&lt;p&gt;两种模式有所帮助。指数退避和熔断器。两者现在都为 Service Bus 触发的 Azure Functions 提供原生支持。&lt;/p&gt;
&lt;h2 id="两种模式不同角色"&gt;两种模式，不同角色&lt;/h2&gt;
&lt;p&gt;这些模式是互补的，而非替代：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;指数退避&lt;/strong&gt;回答：&lt;em&gt;我应该什么时候重试？&lt;/em&gt;
它增加重试之间的延迟，让依赖项有时间恢复。在消息级别，调整重试时机。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;熔断器&lt;/strong&gt;回答：&lt;em&gt;我现在是否应该调用这个依赖项？&lt;/em&gt;
在达到失败阈值后停止对不健康依赖项的重复调用，然后在冷却期后谨慎地探测。在系统级别，防止重试风暴。&lt;/p&gt;
&lt;p&gt;你需要两者。退避处理每条消息的重试节奏。熔断器处理聚合的健康决策。&lt;/p&gt;
&lt;h2 id="为什么这对-service-bus-特别重要"&gt;为什么这对 Service Bus 特别重要&lt;/h2&gt;
&lt;p&gt;队列吸收突发流量，这很好。但没有控制的话，队列可能增长，而工作者继续在会失败的调用上浪费计算资源。有毒消息保持活跃的时间比应该的更长。热分区或有限的下游容量会造成级联问题。&lt;/p&gt;
&lt;p&gt;更安全的设计：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检测瞬时故障&lt;/li&gt;
&lt;li&gt;使用指数退避延迟下一次尝试&lt;/li&gt;
&lt;li&gt;当达到失败阈值时停止调用依赖项（电路打开）&lt;/li&gt;
&lt;li&gt;冷却期后谨慎恢复（电路探测）&lt;/li&gt;
&lt;li&gt;将不可恢复的工作移到 dead-letter 或隔离路径&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="原生支持的外观"&gt;原生支持的外观&lt;/h2&gt;
&lt;p&gt;新支持与现有的 Azure Functions 主机模型集成 — 无需额外库，无需自定义实现。配置进入你的 &lt;code&gt;host.json&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;extensions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;serviceBus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;messageHandlerOptions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;maxRetryCount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;retryPolicy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;exponentialBackoff&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;minBackoff&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;00:00:02&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;maxBackoff&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;00:05:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;maxRetryCount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;熔断器配置设置失败阈值和重置间隔，这样不健康的依赖项在恢复期间不会被轰炸。&lt;/p&gt;
&lt;h2 id="涵盖的语言"&gt;涵盖的语言&lt;/h2&gt;
&lt;p&gt;这不仅仅是 .NET。该功能涵盖 dotnet、JavaScript、TypeScript 和 Python — Azure Functions 中 Service Bus 触发器支持的完整语言集。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;重试模式在配置时并不令人兴奋，直到第一次下游中断导致你的 Functions 加剧问题而不是优雅降级。主动配置这些是廉价的。在事故中进行改造则不然。&lt;/p&gt;
&lt;p&gt;原始文章：&lt;a href="https://devblogs.microsoft.com/azure-sdk/exponential-backoff-circuit-breaker-azure-functions/"&gt;Exponential backoff and circuit breaker for Service Bus-triggered Azure Functions&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>MCP Apps 迎来 Fluent API — 三步在 .NET 中构建丰富的 AI 工具界面</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/mcp-fluent-api-azure-functions-dotnet/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/mcp-fluent-api-azure-functions-dotnet/</guid><description>Azure Functions 上 MCP Apps 的全新 Fluent 配置 API 让你只需几行代码就能将任何 .NET MCP 工具转变为带有视图、权限和 CSP 策略的完整应用。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/news/emiliano-montesdeoca/mcp-fluent-api-azure-functions-dotnet/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MCP 工具非常适合赋予 AI 代理各种能力。但如果你的工具需要向用户展示某些东西呢？比如仪表板、表单或交互式可视化？这就是 MCP Apps 的用武之地，而且现在构建它们变得简单多了。&lt;/p&gt;
&lt;p&gt;Azure SDK 团队的 Lilian Kasem &lt;a href="https://devblogs.microsoft.com/azure-sdk/mcp-as-easy-as-1-2-3-introducing-the-fluent-api-for-mcp-apps/"&gt;发布了全新的 Fluent 配置 API&lt;/a&gt;，用于 .NET Azure Functions 上的 MCP Apps。这种开发者体验的改进会让你想，为什么以前不一直这么简单呢。&lt;/p&gt;
&lt;h2 id="什么是-mcp-apps"&gt;什么是 MCP Apps？&lt;/h2&gt;
&lt;p&gt;MCP Apps 扩展了 Model Context Protocol，让工具可以携带自己的 UI 视图、静态资源和安全控制。你的 MCP 工具不再只是返回文本，而是可以渲染完整的 HTML 体验 — 交互式仪表板、数据可视化、配置表单 — 全部可由 AI 代理调用，并通过 MCP 客户端呈现给用户。&lt;/p&gt;
&lt;p&gt;问题在于，手动连接这一切需要深入了解 MCP 规范：&lt;code&gt;ui://&lt;/code&gt; URI、特殊 MIME 类型、工具和资源之间的元数据协调。不难，但很繁琐。&lt;/p&gt;
&lt;h2 id="fluent-api-三步走"&gt;Fluent API 三步走&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;第一步：定义你的函数。&lt;/strong&gt; 标准的 Azure Functions MCP 工具：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[Function(nameof(HelloApp))]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;HelloApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [McpToolTrigger(&amp;#34;HelloApp&amp;#34;, &amp;#34;A simple MCP App that says hello.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ToolInvocationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello from app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二步：将其提升为 MCP App。&lt;/strong&gt; 在程序启动中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigureMcpTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;HelloApp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsMcpApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;assets/hello-app.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello App&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpAppPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClipboardWrite&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;McpAppPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClipboardRead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCsp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;csp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowBaseUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://www.microsoft.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://www.microsoft.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第三步：添加你的 HTML 视图。&lt;/strong&gt; 创建 &lt;code&gt;assets/hello-app.html&lt;/code&gt;，放入你需要的界面。&lt;/p&gt;
&lt;p&gt;就这样。Fluent API 处理了所有 MCP 协议的管道工作 — 生成合成资源函数、设置正确的 MIME 类型、注入将工具与其视图连接起来的元数据。&lt;/p&gt;
&lt;h2 id="api-设计精良"&gt;API 设计精良&lt;/h2&gt;
&lt;p&gt;几个我特别喜欢的地方：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;视图源灵活。&lt;/strong&gt; 你可以从磁盘文件提供 HTML，也可以将资源直接嵌入程序集中以实现自包含部署：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpViewSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;assets/my-view.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpViewSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromEmbeddedResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;MyApp.Resources.view.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;CSP 可组合。&lt;/strong&gt; 你明确允许应用所需的来源，遵循最小权限原则。多次调用 &lt;code&gt;WithCsp&lt;/code&gt;，来源会累积：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCsp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;csp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://api.example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadResourcesFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://cdn.example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://youtube.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;可见性控制。&lt;/strong&gt; 你可以让工具仅对 LLM 可见、仅对宿主 UI 可见，或两者兼具。想要一个只渲染 UI 而不应被模型调用的工具？简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithVisibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpVisibility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// UI-only, hidden from the model&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="开始使用"&gt;开始使用&lt;/h2&gt;
&lt;p&gt;添加预览包：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Mcp --version 1.5.0-preview.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你已经在用 Azure Functions 构建 MCP 工具，这只是一个包更新。如果你是新手，&lt;a href="https://learn.microsoft.com/azure/azure-functions/scenario-mcp-apps?tabs=bash%2Clinux&amp;amp;pivots=programming-language-csharp"&gt;MCP Apps 快速入门&lt;/a&gt;是最好的起点。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;MCP Apps 是 AI 工具领域最令人兴奋的发展之一 — 不仅能&lt;em&gt;做事&lt;/em&gt;，还能向用户&lt;em&gt;展示事物&lt;/em&gt;的工具。Fluent API 消除了协议复杂性，让你专注于真正重要的事：工具的逻辑和界面。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/azure-sdk/mcp-as-easy-as-1-2-3-introducing-the-fluent-api-for-mcp-apps/"&gt;完整文章&lt;/a&gt;获取完整的 API 参考和示例。&lt;/p&gt;</content:encoded></item><item><title>将 Azure Functions 上的 MCP 服务器连接到 Foundry 代理 — 方法在这里</title><link>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/foundry-agents-mcp-servers-azure-functions/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/news/emiliano-montesdeoca/foundry-agents-mcp-servers-azure-functions/</guid><description>一次构建 MCP 服务器，部署到 Azure Functions，通过适当的身份验证连接到 Microsoft Foundry 代理。你的工具随处可用 — VS Code、Cursor，现在还有企业级 AI 代理。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/news/emiliano-montesdeoca/foundry-agents-mcp-servers-azure-functions/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是我喜欢 MCP 生态系统的一点：你只需构建一次服务器，它就能在任何地方运行。VS Code、Visual Studio、Cursor、ChatGPT — 每个 MCP 客户端都能发现并使用你的工具。现在，微软正在向这个列表中添加另一个消费者：Foundry 代理。&lt;/p&gt;
&lt;p&gt;Azure SDK 团队的 Lily Ma &lt;a href="https://devblogs.microsoft.com/azure-sdk/give-your-foundry-agent-custom-tools-with-mcp-servers-on-azure-functions/"&gt;发布了一份实用指南&lt;/a&gt;，介绍如何将部署在 Azure Functions 上的 MCP 服务器与 Microsoft Foundry 代理连接。如果你已经有了 MCP 服务器，这纯粹是增值 — 无需重新构建。&lt;/p&gt;
&lt;h2 id="为什么这种组合有意义"&gt;为什么这种组合有意义&lt;/h2&gt;
&lt;p&gt;Azure Functions 为托管 MCP 服务器提供了可扩展的基础设施、内置身份验证和无服务器计费。Microsoft Foundry 为你提供能够推理、规划和行动的 AI 代理。连接两者意味着你的自定义工具 — 查询数据库、调用业务 API、运行验证逻辑 — 成为企业 AI 代理可以自主发现和使用的能力。&lt;/p&gt;
&lt;p&gt;关键点：你的 MCP 服务器保持不变。你只是将 Foundry 添加为另一个消费者。在 VS Code 设置中运行的相同工具现在为你的团队或客户交互的 AI 代理提供动力。&lt;/p&gt;
&lt;h2 id="身份验证选项"&gt;身份验证选项&lt;/h2&gt;
&lt;p&gt;这是文章真正增值的地方。根据你的场景提供四种身份验证方法：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;使用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;基于密钥&lt;/strong&gt;（默认）&lt;/td&gt;
&lt;td&gt;开发或没有 Entra 身份验证的服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft Entra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;使用托管标识的生产环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OAuth 身份透传&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;每个用户单独认证的生产环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;无身份验证&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;开发/测试或仅公开数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于生产环境，使用代理身份的 Microsoft Entra 是推荐路径。OAuth 身份透传适用于用户上下文重要的场景 — 代理提示用户登录，每个请求携带用户自己的令牌。&lt;/p&gt;
&lt;h2 id="设置方法"&gt;设置方法&lt;/h2&gt;
&lt;p&gt;大致流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;将 MCP 服务器部署到 Azure Functions&lt;/strong&gt; — &lt;a href="https://github.com/Azure-Samples/remote-mcp-functions-dotnet"&gt;.NET&lt;/a&gt;、Python、TypeScript 和 Java 的示例均可用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在你的函数应用上启用内置 MCP 身份验证&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获取你的端点 URL&lt;/strong&gt; — &lt;code&gt;https://&amp;lt;FUNCTION_APP_NAME&amp;gt;.azurewebsites.net/runtime/webhooks/mcp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在 Foundry 中添加 MCP 服务器作为工具&lt;/strong&gt; — 在门户中导航到你的代理，添加新的 MCP 工具，提供端点和凭据&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后在 Agent Builder 操场中发送一个会触发你某个工具的提示来测试它。&lt;/p&gt;
&lt;h2 id="我的看法"&gt;我的看法&lt;/h2&gt;
&lt;p&gt;这里的组合性故事变得非常强大。用 .NET（或 Python、TypeScript、Java）构建一次 MCP 服务器，部署到 Azure Functions，每个 MCP 兼容的客户端都能使用它 — 编码工具、聊天应用，现在还有企业 AI 代理。这是一个真正有效的&amp;quot;一次编写，到处使用&amp;quot;模式。&lt;/p&gt;
&lt;p&gt;特别是对于 .NET 开发者，&lt;a href="https://github.com/Azure-Samples/remote-mcp-functions-dotnet"&gt;Azure Functions MCP 扩展&lt;/a&gt;让这一切变得简单明了。你将工具定义为 Azure Functions，部署，就拥有了一个具备 Azure Functions 所提供的所有安全性和可扩展性的生产级 MCP 服务器。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;如果你有在 Azure Functions 上运行的 MCP 工具，将它们连接到 Foundry 代理是一个快速的胜利 — 你的自定义工具变成了企业 AI 能力，具有适当的身份验证，且服务器本身无需代码更改。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/azure-sdk/give-your-foundry-agent-custom-tools-with-mcp-servers-on-azure-functions/"&gt;完整指南&lt;/a&gt;了解每种身份验证方法的分步说明，查看&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-mcp-foundry-tools?tabs=entra%2Cmcp-extension%2Cfoundry"&gt;详细文档&lt;/a&gt;了解生产环境配置。&lt;/p&gt;</content:encoded></item></channel></rss>