<?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>The .NET Blog</title><link>https://thedotnetblog.com/zh/</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>Mon, 14 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/zh/index.xml" rel="self" type="application/rss+xml"/><item><title>NDC Oslo 2026</title><link>https://thedotnetblog.com/zh/events/ndc-oslo-2026/</link><pubDate>Mon, 14 Sep 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/events/ndc-oslo-2026/</guid><description>欧洲最大的开发者大会之一 — 在 Oslo Spektrum 举办的5天工作坊、演讲和社交活动，150多位演讲者，160场演讲。</description><content:encoded>&lt;p&gt;&lt;strong&gt;NDC Oslo 2026&lt;/strong&gt; 于 &lt;strong&gt;2026年9月14日至18日&lt;/strong&gt; 在挪威奥斯陆的 &lt;strong&gt;Oslo Spektrum&lt;/strong&gt; 举办。&lt;/p&gt;
&lt;p&gt;NDC Oslo 是欧洲最大、最受尊敬的开发者大会之一，涵盖 .NET、云计算、安全、架构、AI 等众多主题。2026年版目前正在预订阶段，正在组建庞大的演讲阵容。&lt;/p&gt;
&lt;h2 id="数据概览"&gt;数据概览&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;160 场演讲&lt;/strong&gt;（预订中）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;150 位演讲者&lt;/strong&gt;（预订中）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;15 场工作坊&lt;/strong&gt;（预订中）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5 天&lt;/strong&gt; — 工作坊 + 大会&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="已确认的演讲者"&gt;已确认的演讲者&lt;/h2&gt;
&lt;p&gt;演讲者名单正在建设中，已确认的名字包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nick Chapsas&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maddy Montaquila&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Troy Hunt&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kevlin Henney&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Venkat Subramaniam&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jeff Fritz&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Philippe De Ryck&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nhlanhla Lucky Nkosi&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aleksander Stensby&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="门票"&gt;门票&lt;/h2&gt;
&lt;p&gt;早鸟票已开售 — 早鸟优惠截止至 &lt;strong&gt;2026年5月22日&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;CFP（征稿）也已开放。&lt;/p&gt;
&lt;h2 id="2026年其他-ndc-活动"&gt;2026年其他 NDC 活动&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;NDC Sydney — 2026年4月22日–24日&lt;/li&gt;
&lt;li&gt;NDC Toronto — 2026年5月5日–8日&lt;/li&gt;
&lt;li&gt;NDC Copenhagen — 2026年6月1日–4日&lt;/li&gt;
&lt;li&gt;NDC AI — 2026年6月8日–10日&lt;/li&gt;
&lt;li&gt;NDC TechTown — 2026年9月21日–24日&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="链接"&gt;链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ndcoslo.com/"&gt;活动网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ndcoslo.com/tickets"&gt;门票&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ndcoslo.com/call-for-papers"&gt;Call for Papers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ndcoslo.com/speakers"&gt;演讲者&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>.NET Day Switzerland 2026</title><link>https://thedotnetblog.com/zh/events/dotnet-day-switzerland-2026/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/events/dotnet-day-switzerland-2026/</guid><description>面向 .NET 开发者、架构师和专家的非营利社区大会 — 涵盖 .NET、C#、ASP.NET Core、Azure 等 — 在苏黎世举办。</description><content:encoded>&lt;p&gt;&lt;strong&gt;.NET Day Switzerland 2026&lt;/strong&gt; 于 &lt;strong&gt;2026年8月25日&lt;/strong&gt; 在 &lt;strong&gt;Arena Cinemas Sihlcity&lt;/strong&gt;（Kalanderplatz 8, 8045 苏黎世）举办。&lt;/p&gt;
&lt;p&gt;这是一场独立的非营利社区大会，面向开发者、架构师和专家，讨论 .NET、C#、ASP.NET Core、Azure 和更广泛的 Microsoft 开发生态系统。所有演讲者和工作人员都是志愿参与，门票销售的盈余将捐赠给慈善机构或瑞士 .NET 社区。&lt;/p&gt;
&lt;h2 id="参会收获"&gt;参会收获&lt;/h2&gt;
&lt;ul&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;茶歇期间与演讲者直接交流&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="门票"&gt;门票&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类别&lt;/th&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;超早鸟票（4月1日–30日）&lt;/td&gt;
&lt;td&gt;299 CHF&lt;/td&gt;
&lt;td&gt;最多100张&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;早鸟票&lt;/td&gt;
&lt;td&gt;399 CHF&lt;/td&gt;
&lt;td&gt;最多100张&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;普通票&lt;/td&gt;
&lt;td&gt;449 CHF&lt;/td&gt;
&lt;td&gt;售完即止&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;演讲者和日程尚未公布 — 演讲者征集已在 &lt;a href="https://sessionize.com/net-day-switzerland-2026/"&gt;Sessionize&lt;/a&gt; 上开放。&lt;/p&gt;
&lt;h2 id="组织者"&gt;组织者&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/FabianGosebrink"&gt;Fabian Gosebrink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/manumeyer1"&gt;Manuel Meyer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/gassmannt"&gt;Thomas Gassmann&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="链接"&gt;链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnetday.ch/"&gt;活动网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://eepurl.com/dDoFEn"&gt;订阅通讯&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>SDD Conference 2026</title><link>https://thedotnetblog.com/zh/events/sdd-conference-2026/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/events/sdd-conference-2026/</guid><description>在伦敦 Barbican Centre 举办的5天软件开发大会，78场演讲和14场工作坊，涵盖架构、.NET、AI、Azure、DevOps 等主题。</description><content:encoded>&lt;p&gt;&lt;strong&gt;SDD 2026&lt;/strong&gt; 于 &lt;strong&gt;2026年5月11日至15日&lt;/strong&gt; 在 &lt;strong&gt;伦敦 Barbican Centre&lt;/strong&gt; 举办。为期3天的核心大会从周二到周四，周一和周五有可选的全天工作坊。&lt;/p&gt;
&lt;p&gt;拥有 &lt;strong&gt;78场演讲&lt;/strong&gt; 和 &lt;strong&gt;14场工作坊&lt;/strong&gt;，是欧洲内容最丰富的开发者大会之一。&lt;/p&gt;
&lt;h2 id="主题"&gt;主题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;架构思维&lt;/li&gt;
&lt;li&gt;C# 13 中的函数式代码&lt;/li&gt;
&lt;li&gt;无服务器设计&lt;/li&gt;
&lt;li&gt;语义 AI&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Services&lt;/li&gt;
&lt;li&gt;精益 DevOps 策略&lt;/li&gt;
&lt;li&gt;模型上下文协议 (MCP)&lt;/li&gt;
&lt;li&gt;.NET 中的智能代理 AI&lt;/li&gt;
&lt;li&gt;重构单体应用&lt;/li&gt;
&lt;li&gt;使用 LLM 更快编程&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;strong&gt;Kevlin Henney&lt;/strong&gt;、&lt;strong&gt;Neal Ford&lt;/strong&gt;、&lt;strong&gt;Sander Hoogendoorn&lt;/strong&gt;、&lt;strong&gt;Andrew Clymer&lt;/strong&gt;、&lt;strong&gt;Jacqui Read&lt;/strong&gt;、&lt;strong&gt;Christian Weyer&lt;/strong&gt;、&lt;strong&gt;Jeff Prosise&lt;/strong&gt;、&lt;strong&gt;Jules May&lt;/strong&gt;、&lt;strong&gt;Oliver Sturm&lt;/strong&gt; 和 &lt;strong&gt;Raju Gandhi&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="门票和信息"&gt;门票和信息&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sddconf.com/"&gt;活动网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sddvault.s3.amazonaws.com/assets/SDD_2026_schedule.pdf"&gt;完整议程 PDF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sddconf.com/register"&gt;注册选项&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;98%的 SDD 2025 参会者将整体体验评为&amp;quot;好&amp;quot;、&amp;ldquo;非常好&amp;quot;或&amp;quot;优秀&amp;rdquo;。&lt;/p&gt;</content:encoded></item><item><title>Azure DevOps MCP服务器4月更新：WIQL查询、PAT认证和实验性MCP Apps</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-mcp-server-april-2026-wiql-pat-apps/</link><pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-mcp-server-april-2026-wiql-pat-apps/</guid><description>Azure DevOps MCP服务器获得了WIQL驱动的工作项查询、个人访问令牌身份验证、MCP注解，以及将常见工作流打包成可重用工具的实验性MCP Apps功能。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/azure-devops-mcp-server-april-2026-wiql-pat-apps/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Azure DevOps MCP服务器持续改进。Dan Hellem的四月更新同时覆盖了本地和远程服务器。&lt;/p&gt;
&lt;h2 id="wiql查询支持"&gt;WIQL查询支持&lt;/h2&gt;
&lt;p&gt;新的&lt;code&gt;wit_query_by_wiql&lt;/code&gt;工具允许直接从MCP客户端运行工作项查询语言查询。&lt;/p&gt;
&lt;h2 id="个人访问令牌"&gt;个人访问令牌&lt;/h2&gt;
&lt;p&gt;本地服务器上的PAT身份验证 — 对于没有交互式身份验证的集成场景很重要。&lt;/p&gt;
&lt;h2 id="mcp注解"&gt;MCP注解&lt;/h2&gt;
&lt;p&gt;只读、破坏性和开放世界工具的元数据标签 — 代理可靠性的基础。&lt;/p&gt;
&lt;h2 id="wiki工具整合"&gt;Wiki工具整合&lt;/h2&gt;
&lt;p&gt;5个独立的wiki工具 → 2个更强大的工具。工具越少 = LLM性能越好。&lt;/p&gt;
&lt;h2 id="实验性mcp-apps"&gt;实验性：MCP Apps&lt;/h2&gt;
&lt;p&gt;在MCP服务器环境中打包的工作流。方向是对的。&lt;/p&gt;
&lt;p&gt;Dan Hellem的原始文章：&lt;a href="https://devblogs.microsoft.com/devops/azure-devops-mcp-server-april-update/"&gt;Azure DevOps MCP Server April Update&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>SQL Server 2025作为代理就绪数据库：一个引擎中的安全、备份和MCP</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/sql-server-2025-agent-ready-security-mcp/</link><pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/sql-server-2025-agent-ready-security-mcp/</guid><description>Polyglot Tax系列的最终篇解决了生产环境中的难题：跨关系、JSON、图形和向量数据的统一行级安全，加上使SQL Server 2025真正代理就绪的MCP集成。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/sql-server-2025-agent-ready-security-mcp/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我一直饶有兴趣地关注Aditya Badramraju的Polyglot Tax系列。第4部分用实际决定你是否会在生产环境中信任这种架构的部分来结束系列。&lt;/p&gt;
&lt;h2 id="所有数据模型的单一安全模型"&gt;所有数据模型的单一安全模型&lt;/h2&gt;
&lt;p&gt;一个行级安全策略覆盖所有数据模型。对审计员来说，一个策略，一个证明。&lt;/p&gt;
&lt;h2 id="统一备份--原子恢复"&gt;统一备份 = 原子恢复&lt;/h2&gt;
&lt;p&gt;在多语言堆栈中，跨五个数据库的时间点恢复是一场一致性噩梦。只有一个数据库时，恢复在定义上就是原子的。&lt;/p&gt;
&lt;h2 id="mcp集成无需手动编写中间件"&gt;MCP集成：无需手动编写中间件&lt;/h2&gt;
&lt;p&gt;SQL Server 2025直接支持SQL MCP服务器。代理调用工具，引擎自动强制租户隔离和列掩码。&lt;/p&gt;
&lt;p&gt;原始文章（Aditya Badramraju著）：&lt;a href="https://devblogs.microsoft.com/azure-sql/the-polyglot-tax-part-4/"&gt;The Polyglot Tax – Part 4&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>.NET 10 随 Ubuntu 26.04 LTS 发布 — 新特性概览</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-ubuntu-2604-resolute-raccoon-net10/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-ubuntu-2604-resolute-raccoon-net10/</guid><description>Ubuntu 26.04 LTS (Resolute Raccoon) 携 .NET 10 作为一等工具链发布。Native AOT、Chiseled 容器、Linux 7.0。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-ubuntu-2604-resolute-raccoon-net10/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ubuntu LTS 发布日。&lt;a href="https://canonical.com/blog/canonical-releases-ubuntu-26-04-lts-resolute-raccoon"&gt;Ubuntu 26.04 (Resolute Raccoon)&lt;/a&gt; 今天发布，与每个 Ubuntu LTS 一样，携带最新的 .NET LTS — 这次是 &lt;a href="https://devblogs.microsoft.com/dotnet/whats-new-for-dotnet-in-ubuntu-2604/"&gt;.NET 10&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="两条命令安装-net-10"&gt;两条命令安装 .NET 10&lt;/h2&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;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install dotnet-sdk-10.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;.NET 是 &lt;a href="https://ubuntu.com/toolchains"&gt;Ubuntu 官方支持的工具链&lt;/a&gt;之一，不是第三方附加组件。&lt;/p&gt;
&lt;h2 id="容器将--noble-更新为--resolute"&gt;容器：将 &lt;code&gt;-noble&lt;/code&gt; 更新为 &lt;code&gt;-resolute&lt;/code&gt;&lt;/h2&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;sed -i &lt;span class="s2"&gt;&amp;#34;s/noble/resolute/g&amp;#34;&lt;/span&gt; Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;包括 &lt;a href="https://devblogs.microsoft.com/dotnet/announcing-dotnet-chiseled-containers/"&gt;Chiseled&lt;/a&gt; 在内的所有现有镜像变体均可用。&lt;/p&gt;
&lt;h2 id="native-aot3ms-启动14mb-二进制文件"&gt;Native AOT：3ms 启动，1.4MB 二进制文件&lt;/h2&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;apt install -y dotnet-sdk-aot-10.0 clang
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet publish app.cs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1.4MB 原生二进制文件，启动时间 3ms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于冷启动时间至关重要的云原生工作负载——Functions、容器、Serverless——这是真正的游戏规则改变者。&lt;/p&gt;
&lt;h2 id="需要-net-8-或-9"&gt;需要 .NET 8 或 9？&lt;/h2&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;apt install -y software-properties-common
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;add-apt-repository ppa:dotnet/backports
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apt install -y dotnet-sdk-8.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/whats-new-for-dotnet-in-ubuntu-2604/"&gt;完整文章&lt;/a&gt;包含有关 cgroup v2、后量子密码学和 Linux 7.0 的更多详情。&lt;/p&gt;</content:encoded></item><item><title>Agent Framework中的CodeAct：如何将智能体延迟减半</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/codeact-agent-framework-hyperlight-50-percent-faster/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/codeact-agent-framework-hyperlight-50-percent-faster/</guid><description>CodeAct将多步骤工具链压缩为单个沙盒代码块——延迟降低52%，令牌使用量减少64%。了解它对您的智能体意味着什么以及何时使用它。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需阅读原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/codeact-agent-framework-hyperlight-50-percent-faster/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;在每个智能体项目中，都会有这样一个时刻：你查看追踪信息，心想：&amp;ldquo;为什么这要花这么长时间？&amp;ldquo;模型没问题，工具也能运行，但为了获得一个本可一步计算出的结果，却需要七次往返请求。&lt;/p&gt;
&lt;p&gt;这正是CodeAct解决的问题——&lt;a href="https://devblogs.microsoft.com/agent-framework/codeact-with-hyperlight/"&gt;Agent Framework团队刚刚发布了Alpha支持&lt;/a&gt;，通过新的&lt;code&gt;agent-framework-hyperlight&lt;/code&gt;包实现。&lt;/p&gt;
&lt;h2 id="什么是codeact"&gt;什么是CodeAct？&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/2402.01030"&gt;CodeAct模式&lt;/a&gt;优雅而简单：不再给模型一个工具列表让它逐一调用，而是给它一个单一的&lt;code&gt;execute_code&lt;/code&gt;工具，让它将&lt;em&gt;整个计划&lt;/em&gt;表达为一个简短的Python程序。智能体只需编写一次代码，沙盒执行它，你就能得到一个统一的结果。&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;th&gt;令牌&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;传统方式&lt;/td&gt;
&lt;td&gt;27.81秒&lt;/td&gt;
&lt;td&gt;6,890&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeAct&lt;/td&gt;
&lt;td&gt;13.23秒&lt;/td&gt;
&lt;td&gt;2,489&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;strong&gt;52.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;63.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="安全机制hyperlight微型虚拟机"&gt;安全机制：Hyperlight微型虚拟机&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;agent-framework-hyperlight&lt;/code&gt;包使用&lt;a href="https://github.com/hyperlight-dev/hyperlight"&gt;Hyperlight&lt;/a&gt;微型虚拟机。每次&lt;code&gt;execute_code&lt;/code&gt;调用都在一个全新的微型VM中运行。启动时间以毫秒计算。隔离几乎是免费的。&lt;/p&gt;
&lt;p&gt;你的工具仍在主机上运行。模型生成的&lt;em&gt;粘合代码&lt;/em&gt;在沙盒中运行。这是正确的分工。&lt;/p&gt;
&lt;h2 id="最小配置"&gt;最小配置&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework_hyperlight&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HyperlightCodeActProvider&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="nd"&gt;@tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;str&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="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Return the current weather for a city.&amp;#34;&amp;#34;&amp;#34;&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="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;city&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;temperature_c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;21.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;conditions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;partly cloudy&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;codeact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HyperlightCodeActProvider&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;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_weather&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;approval_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;never_require&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&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;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client&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;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CodeActAgent&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;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&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;context_providers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;codeact&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;h2 id="何时使用codeact何时不用"&gt;何时使用CodeAct（何时不用）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;使用CodeAct的情况：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务需要链接许多小型工具调用（查询、连接、计算）&lt;/li&gt;
&lt;li&gt;延迟和令牌成本很重要&lt;/li&gt;
&lt;li&gt;需要对模型生成的代码进行强隔离&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;继续使用传统工具调用的情况：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;智能体每轮只进行一两次工具调用&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;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;pip install agent-framework-hyperlight --pre
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请查阅&lt;a href="https://devblogs.microsoft.com/agent-framework/codeact-with-hyperlight/"&gt;Agent Framework博客的完整文章&lt;/a&gt;获取更深入的介绍。&lt;/p&gt;</content:encoded></item><item><title>Azure MCP Server 现在是 .mcpb — 无需任何运行时即可安装</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-mcpb-no-runtime-install/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-mcpb-no-runtime-install/</guid><description>Azure MCP Server 现已作为 MCP Bundle (.mcpb) 提供 — 下载、拖入 Claude Desktop，完成。无需 Node.js、Python 或 .NET 运行时。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-mcpb-no-runtime-install/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;你知道配置 MCP 服务器有什么烦人的地方吗？需要运行时。npm 版需要 Node.js，pip/uvx 需要 Python，dotnet 版需要 .NET SDK。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-mcp-server-mcpb-support/"&gt;Azure MCP Server 刚刚改变了这一切&lt;/a&gt;。它现在作为 &lt;code&gt;.mcpb&lt;/code&gt; — MCP Bundle — 提供，配置方式是拖放。&lt;/p&gt;
&lt;h2 id="什么是-mcp-bundle"&gt;什么是 MCP Bundle？&lt;/h2&gt;
&lt;p&gt;把它想象成 VS Code 扩展（&lt;code&gt;.vsix&lt;/code&gt;）或浏览器扩展（&lt;code&gt;.crx&lt;/code&gt;），但用于 MCP 服务器。&lt;code&gt;.mcpb&lt;/code&gt; 文件是一个独立的 ZIP 存档，包含服务器二进制文件及其所有依赖项。&lt;/p&gt;
&lt;h2 id="如何安装"&gt;如何安装&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. 为你的平台下载 Bundle&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前往 &lt;a href="https://github.com/microsoft/mcp/releases?q=Azure.Mcp.Server"&gt;GitHub Releases 页面&lt;/a&gt;，下载适合你 OS 和架构的 &lt;code&gt;.mcpb&lt;/code&gt; 文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 在 Claude Desktop 中安装&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最简单的方式：在扩展设置页面（&lt;code&gt;☰ → 文件 → 设置 → 扩展&lt;/code&gt;）打开时，将 &lt;code&gt;.mcpb&lt;/code&gt; 文件拖放到 Claude Desktop 窗口中。查看服务器详情，点击安装，确认。完成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 向 Azure 进行身份验证&lt;/strong&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;az login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就这样。Azure MCP Server 使用你现有的 Azure 凭据。&lt;/p&gt;
&lt;h2 id="能做什么"&gt;能做什么&lt;/h2&gt;
&lt;p&gt;直接从 AI 客户端访问 100 多个 Azure 服务工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询和管理 Cosmos DB、Storage、Key Vault、App Service、Foundry&lt;/li&gt;
&lt;li&gt;为任何任务生成 &lt;code&gt;az&lt;/code&gt; CLI 命令&lt;/li&gt;
&lt;li&gt;创建 Bicep 和 Terraform 模板&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="开始使用"&gt;开始使用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;下载&lt;/strong&gt;: &lt;a href="https://github.com/microsoft/mcp/releases?q=Azure.Mcp.Server-"&gt;GitHub Releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;仓库&lt;/strong&gt;: &lt;a href="https://aka.ms/azmcp"&gt;aka.ms/azmcp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档&lt;/strong&gt;: &lt;a href="https://aka.ms/azmcp/docs"&gt;aka.ms/azmcp/docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-mcp-server-mcpb-support/"&gt;完整文章&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>Azure SDK 2026年4月：AI Foundry 2.0及.NET开发者须知</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-sdk-april-2026-ai-foundry-2-stable/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-sdk-april-2026-ai-foundry-2-stable/</guid><description>2026年4月Azure SDK发布带来了Azure.AI.Projects 2.0.0稳定版（包含重大破坏性变更）、Cosmos DB关键安全修复以及.NET的新Provisioning库。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/azure-sdk-april-2026-ai-foundry-2-stable/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;月度SDK发布通常容易被忽略。这次有几件事值得关注——特别是如果你在使用AI Foundry、Java版Cosmos DB或从.NET代码进行基础设施配置。&lt;/p&gt;
&lt;h2 id="azureaiprojects-200--有意义的破坏性变更"&gt;Azure.AI.Projects 2.0.0 — 有意义的破坏性变更&lt;/h2&gt;
&lt;p&gt;命名空间拆分、类型重命名、布尔属性统一使用&lt;code&gt;Is*&lt;/code&gt;命名规则。&lt;/p&gt;
&lt;h2 id="cosmos-db-java关键安全修复rce"&gt;Cosmos DB Java：关键安全修复（RCE）&lt;/h2&gt;
&lt;p&gt;4.79.0版本修复了&lt;strong&gt;远程代码执行漏洞（CWE-502）&lt;/strong&gt;。立即更新。&lt;/p&gt;
&lt;h2 id="net的新provisioning库"&gt;.NET的新Provisioning库&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Azure.Provisioning.Network/1.0.0"&gt;Azure.Provisioning.Network 1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Azure.Provisioning.PrivateDns/1.0.0"&gt;Azure.Provisioning.PrivateDns 1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原始文章：&lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-april-2026/"&gt;Azure SDK Release (April 2026)&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>GPT-5.5 已来到 Azure Foundry — .NET 开发者需要了解的一切</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/gpt-55-foundry-ga-what-dotnet-developers-need-to-know/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/gpt-55-foundry-ga-what-dotnet-developers-need-to-know/</guid><description>GPT-5.5 在 Microsoft Foundry 正式发布。从 GPT-5 到 5.5 的演进、真正改进了什么，以及今天如何在你的 Agent 中开始使用它。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/gpt-55-foundry-ga-what-dotnet-developers-need-to-know/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;微软刚刚宣布 &lt;a href="https://azure.microsoft.com/en-us/blog/openais-gpt-5-5-in-microsoft-foundry-frontier-intelligence-on-an-enterprise-ready-platform/"&gt;GPT-5.5 在 Microsoft Foundry 正式发布&lt;/a&gt;。如果你一直在 Azure 上构建 Agent，这就是你一直等待的更新。&lt;/p&gt;
&lt;h2 id="gpt-5-的演进"&gt;GPT-5 的演进&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GPT-5&lt;/strong&gt;：将推理与速度统一到单一系统中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.4&lt;/strong&gt;：更强的多步推理，面向企业的早期 Agent 能力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.5&lt;/strong&gt;：更深入的长上下文推理，更可靠的 Agent 执行，更好的 Token 效率&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="真正发生了什么变化"&gt;真正发生了什么变化&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Agent 编码改进&lt;/strong&gt;：GPT-5.5 在大型代码库中保持上下文，诊断架构级故障，并预测测试需求。模型在行动前推理&lt;em&gt;修复还会影响什么&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Token 效率&lt;/strong&gt;：更少的 Token 和更少的重试产生更高质量的输出。生产部署的成本和延迟直接降低。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长上下文分析&lt;/strong&gt;：处理大量文档和多会话历史记录而不失去线索。&lt;/p&gt;
&lt;h2 id="定价"&gt;定价&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模型&lt;/th&gt;
&lt;th&gt;输入 ($/M tokens)&lt;/th&gt;
&lt;th&gt;缓存输入&lt;/th&gt;
&lt;th&gt;输出 ($/M tokens)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5&lt;/td&gt;
&lt;td&gt;$5.00&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5 Pro&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$180.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="为什么-foundry-很重要"&gt;为什么 Foundry 很重要&lt;/h2&gt;
&lt;p&gt;Foundry Agent Service 允许你在 YAML 中定义 Agent，或与 Microsoft Agent Framework、GitHub Copilot SDK、LangGraph 或 OpenAI Agents SDK 连接——并将它们作为具有持久文件系统、独立 Microsoft Entra 身份和零扩展定价的隔离托管 Agent 运行。&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;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aiProjectClient&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;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-5.5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;你是一个有用的助手。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;我的Agent&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;a href="https://azure.microsoft.com/en-us/blog/openais-gpt-5-5-in-microsoft-foundry-frontier-intelligence-on-an-enterprise-ready-platform/"&gt;完整公告&lt;/a&gt;了解所有详情。&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.118：Copilot CLI 获得会话名称、模型徽章和 TypeScript 7.0 夜间版选择加入</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-118-copilot-cli-session-names-model-badge/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-118-copilot-cli-session-names-model-badge/</guid><description>Visual Studio Code 1.118 是一个专注于 Copilot CLI 改进的版本——会话命名、模型徽章、自动模型选择以及 TypeScript 7.0 夜间版选择加入。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-118-copilot-cli-session-names-model-badge/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://code.visualstudio.com/updates/v1_118"&gt;Visual Studio Code 1.118&lt;/a&gt; 是一个较小的专注版本——主要是 Copilot CLI 的改进——但有几点值得关注。&lt;/p&gt;
&lt;h2 id="copilot-cli会话拥有真实名称"&gt;Copilot CLI：会话拥有真实名称&lt;/h2&gt;
&lt;p&gt;Copilot CLI SDK 的会话标题 API 现在用作会话名称的真实来源。会话显示 SDK 中的实际名称，而非自动生成的标签。&lt;/p&gt;
&lt;h2 id="使用键盘快捷键快速切换会话"&gt;使用键盘快捷键快速切换会话&lt;/h2&gt;
&lt;p&gt;Agents 应用现在绑定了 &lt;code&gt;Ctrl+1&lt;/code&gt;、&lt;code&gt;Ctrl+2&lt;/code&gt; 等快捷键，用于快速切换会话。&lt;/p&gt;
&lt;h2 id="聊天中的模型徽章"&gt;聊天中的模型徽章&lt;/h2&gt;
&lt;p&gt;Copilot CLI 在聊天面板中的回复现在显示模型徽章——一眼即可看出哪个模型处理了每个请求。&lt;/p&gt;
&lt;h2 id="copilot-cli-中的自动模型选择"&gt;Copilot CLI 中的自动模型选择&lt;/h2&gt;
&lt;p&gt;自动模型选择功能——之前在 Copilot 的其他部分已可用——现在也在 Copilot CLI 代理中工作。&lt;/p&gt;
&lt;h2 id="typescript-70-夜间版选择加入"&gt;TypeScript 7.0 夜间版选择加入&lt;/h2&gt;
&lt;p&gt;现在可以直接从 VS Code 设置中选择加入测试 TypeScript 7.0 夜间版。TypeScript 7.0 是一个重大版本（&lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/"&gt;测试版几天前发布&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://code.visualstudio.com/updates/v1_118"&gt;完整发行说明&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>你的 Agent 在哪里记住事情？聊天历史存储实践指南</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/chat-history-storage-patterns-agent-framework/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/chat-history-storage-patterns-agent-framework/</guid><description>服务管理还是客户端管理？线性还是分叉？这个架构决策决定了你的 AI Agent 能做什么——附 C# 和 Python 代码示例。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/chat-history-storage-patterns-agent-framework/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;在构建 AI Agent 时，你把大部分精力花在模型、工具和提示词上。&lt;em&gt;对话历史存储在哪里&lt;/em&gt;这个问题看起来像是实现细节——但实际上是你将做出的最重要的架构决策之一。&lt;/p&gt;
&lt;p&gt;它决定了用户能否分叉对话、撤销回答、重启后恢复会话，以及数据是否会离开你的基础设施。&lt;a href="https://devblogs.microsoft.com/agent-framework/chat-history-storage-patterns-in-microsoft-agent-framework/"&gt;Agent Framework 团队发布了一篇深度分析&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="两种基本模式"&gt;两种基本模式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;服务管理型&lt;/strong&gt;：AI 服务存储对话状态。你的应用保持一个引用，服务自动在每次请求中包含相关历史记录。更简单，控制更少。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;客户端管理型&lt;/strong&gt;：你的应用维护完整历史记录，并在每次请求时发送相关消息。服务无状态。你控制一切。&lt;/p&gt;
&lt;h2 id="agent-framework-如何抽象这一切"&gt;Agent Framework 如何抽象这一切&lt;/h2&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;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;我叫 Alice。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;我叫什么名字？&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&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;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_session&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;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;我叫 Alice。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&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;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;我叫什么名字？&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&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;Session 处理底层差异。无论切换什么提供商，应用代码不变。&lt;/p&gt;
&lt;h2 id="提供商快速参考"&gt;提供商快速参考&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;提供商&lt;/th&gt;
&lt;th&gt;存储位置&lt;/th&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;OpenAI/Azure Chat Completions&lt;/td&gt;
&lt;td&gt;客户端&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Foundry Agent Service&lt;/td&gt;
&lt;td&gt;服务端&lt;/td&gt;
&lt;td&gt;线性&lt;/td&gt;
&lt;td&gt;服务端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responses API（默认）&lt;/td&gt;
&lt;td&gt;服务端&lt;/td&gt;
&lt;td&gt;分叉型&lt;/td&gt;
&lt;td&gt;服务端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Claude, Ollama&lt;/td&gt;
&lt;td&gt;客户端&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="如何选择"&gt;如何选择&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;需要分叉对话或&amp;quot;撤销&amp;quot;？&lt;/strong&gt; → 服务管理型 Responses API&lt;/li&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;/ol&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/agent-framework/chat-history-storage-patterns-in-microsoft-agent-framework/"&gt;完整文章&lt;/a&gt;了解完整决策树。&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2：Bun支持、更好的容器和更少的调试摩擦</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-bun-container-enhancements/</link><pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-bun-container-enhancements/</guid><description>Aspire 13.2为Vite应用添加了一流的Bun支持，修复了Yarn可靠性问题，并带来了使本地开发行为更可预测的容器改进。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/aspire-132-bun-container-enhancements/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;如果你在Aspire中构建.NET后端和JavaScript前端，13.2是那种悄悄让你一天变得更好的更新。&lt;/p&gt;
&lt;h2 id="bun现在是一等公民"&gt;Bun现在是一等公民&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&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="nx"&gt;addViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./frontend&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="nx"&gt;withBun&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;如果你的团队已经使用Bun，Aspire不再让你逆流而上。&lt;/p&gt;
&lt;h2 id="yarn更可靠了"&gt;Yarn更可靠了&lt;/h2&gt;
&lt;p&gt;Yarn用户在&lt;code&gt;withYarn()&lt;/code&gt;和&lt;code&gt;addViteApp()&lt;/code&gt;中会遇到更少的神秘失败。&lt;/p&gt;
&lt;h2 id="容器改进"&gt;容器改进&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ImagePullPolicy.Never&lt;/code&gt;用于使用本地镜像而不访问注册表。PostgreSQL 18+数据卷现在可以正确工作。&lt;/p&gt;
&lt;h2 id="调试改进"&gt;调试改进&lt;/h2&gt;
&lt;p&gt;核心类型上的&lt;code&gt;DebuggerDisplayAttribute&lt;/code&gt;，&lt;code&gt;WaitFor&lt;/code&gt;的更好错误消息，&lt;code&gt;BeforeResourceStartedEvent&lt;/code&gt;在正确时机触发。&lt;/p&gt;
&lt;p&gt;David Pine的原始文章：&lt;a href="https://devblogs.microsoft.com/aspire/aspire-bun-support-and-container-enhancements/"&gt;Aspire 13.2: Bun Support and Container Enhancements&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>azd钩子支持Python、TypeScript和.NET：告别Shell脚本</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-hooks-python-javascript-typescript-dotnet/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-hooks-python-javascript-typescript-dotnet/</guid><description>Azure Developer CLI现在支持用Python、JavaScript、TypeScript或.NET编写钩子。不再需要仅仅为了运行迁移脚本就切换到Bash。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-hooks-python-javascript-typescript-dotnet/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;如果你曾经有一个完全用.NET构建的项目，却还需要为azd钩子编写Bash脚本，你一定懂那种痛苦。当项目其他部分都是C#时，为什么要在pre-provisioning步骤中切换到Shell语法呢？&lt;/p&gt;
&lt;p&gt;这个问题现在有了官方解决方案。Azure Developer CLI &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-multi-language-hooks/"&gt;刚刚发布了钩子的多语言支持&lt;/a&gt;，效果正如预期的那么好。&lt;/p&gt;
&lt;h2 id="什么是钩子"&gt;什么是钩子&lt;/h2&gt;
&lt;p&gt;钩子是在&lt;code&gt;azd&lt;/code&gt;生命周期关键节点运行的脚本——预置配置之前、部署之后等。它们在&lt;code&gt;azure.yaml&lt;/code&gt;中定义，无需修改CLI即可注入自定义逻辑。&lt;/p&gt;
&lt;p&gt;此前只支持Bash和PowerShell。现在可以使用&lt;strong&gt;Python、JavaScript、TypeScript或.NET&lt;/strong&gt;——&lt;code&gt;azd&lt;/code&gt;会自动处理其余的一切。&lt;/p&gt;
&lt;h2 id="检测机制"&gt;检测机制&lt;/h2&gt;
&lt;p&gt;只需将钩子指向一个文件，&lt;code&gt;azd&lt;/code&gt;就会从文件扩展名推断语言：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;preprovision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./hooks/setup.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;postdeploy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./hooks/seed.ts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;postprovision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./hooks/migrate.cs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;无需额外配置。如果扩展名不明确，可以添加&lt;code&gt;kind: python&lt;/code&gt;（或相应语言）来明确指定。&lt;/p&gt;
&lt;h2 id="各语言的重要细节"&gt;各语言的重要细节&lt;/h2&gt;
&lt;h3 id="python"&gt;Python&lt;/h3&gt;
&lt;p&gt;在脚本旁边（或任意父目录中）放置&lt;code&gt;requirements.txt&lt;/code&gt;或&lt;code&gt;pyproject.toml&lt;/code&gt;，&lt;code&gt;azd&lt;/code&gt;会自动创建虚拟环境、安装依赖并运行脚本。&lt;/p&gt;
&lt;h3 id="javascript和typescript"&gt;JavaScript和TypeScript&lt;/h3&gt;
&lt;p&gt;同样的模式——在脚本附近放置&lt;code&gt;package.json&lt;/code&gt;，&lt;code&gt;azd&lt;/code&gt;会先运行&lt;code&gt;npm install&lt;/code&gt;。对于TypeScript，使用&lt;code&gt;npx tsx&lt;/code&gt;，无需编译步骤，也不需要&lt;code&gt;tsconfig.json&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="net"&gt;.NET&lt;/h3&gt;
&lt;p&gt;提供两种模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;项目模式&lt;/strong&gt;：如果脚本旁边有&lt;code&gt;.csproj&lt;/code&gt;文件，&lt;code&gt;azd&lt;/code&gt;会自动运行&lt;code&gt;dotnet restore&lt;/code&gt;和&lt;code&gt;dotnet build&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单文件模式&lt;/strong&gt;：在.NET 10+上，独立的&lt;code&gt;.cs&lt;/code&gt;文件可通过&lt;code&gt;dotnet run script.cs&lt;/code&gt;直接运行，无需项目文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="执行器特定配置"&gt;执行器特定配置&lt;/h2&gt;
&lt;p&gt;每种语言都支持可选的&lt;code&gt;config&lt;/code&gt;块：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;preprovision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./hooks/setup.ts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;packageManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pnpm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;postprovision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./hooks/migrate.cs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Release&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;net10.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="对net开发者的意义"&gt;对.NET开发者的意义&lt;/h2&gt;
&lt;p&gt;钩子曾是基于azd的项目中最后一个强制语言切换的地方。现在，整个部署流水线——从应用代码到基础设施脚本再到生命周期钩子——都可以使用同一种语言。你可以在钩子中复用现有的.NET工具，引用共享类库，不再需要维护Shell脚本。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;这看起来是个小改动，但它切实减少了日常azd工作流程中的摩擦。钩子的多语言支持现已可用——查阅&lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-multi-language-hooks/"&gt;官方文章&lt;/a&gt;获取完整文档。&lt;/p&gt;</content:encoded></item><item><title>Foundry Toolboxes：AI Agent工具的统一端点</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-toolboxes-curate-manage-tools-ai-agents/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-toolboxes-curate-manage-tools-ai-agents/</guid><description>Microsoft Foundry已推出公开预览版Toolboxes——一种通过单一MCP兼容端点管理和公开AI Agent工具的方式，无需在每个Agent中重新配置所有内容。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-toolboxes-curate-manage-tools-ai-agents/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;有一个问题听起来无聊，直到你真正遇到它：你的组织在构建多个AI Agent，每个都需要工具，每个团队都从头开始配置。相同的Web搜索集成、相同的Azure AI Search配置、相同的GitHub MCP服务器连接——但在不同的仓库里，由不同的团队，使用不同的凭据，没有任何共享治理。&lt;/p&gt;
&lt;p&gt;Microsoft Foundry刚刚以公开预览版发布了&lt;a href="https://devblogs.microsoft.com/foundry/introducing-toolboxes-in-foundry/"&gt;Toolboxes&lt;/a&gt;，这是对该问题的直接回应。&lt;/p&gt;
&lt;h2 id="什么是toolbox"&gt;什么是Toolbox&lt;/h2&gt;
&lt;p&gt;Toolbox是一个有命名的、可复用的工具包，在Foundry中定义一次，通过单一MCP兼容端点公开。任何能够使用MCP的Agent运行时都可以消费它——不受限于Foundry Agents。&lt;/p&gt;
&lt;p&gt;承诺很简单：&lt;strong&gt;build once, consume anywhere&lt;/strong&gt;。定义工具，集中配置身份验证（OAuth直通、Entra托管标识），发布端点。需要这些工具的每个Agent连接到端点即可获取全部工具。&lt;/p&gt;
&lt;h2 id="四个支柱今天两个可用"&gt;四个支柱（今天两个可用）&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;支柱&lt;/th&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;Discover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;即将推出&lt;/td&gt;
&lt;td&gt;无需手动搜索即可发现已批准的工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;现已可用&lt;/td&gt;
&lt;td&gt;将工具整合到可复用包中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consume&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;现已可用&lt;/td&gt;
&lt;td&gt;单一MCP端点公开所有工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Govern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;即将推出&lt;/td&gt;
&lt;td&gt;集中身份验证+所有工具调用的可观测性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="实践示例"&gt;实践示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.identity&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&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="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&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;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;FOUNDRY_PROJECT_ENDPOINT&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;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DefaultAzureCredential&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;toolbox_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toolboxes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_toolbox_version&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;toolbox_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;customer-feedback-triaging-toolbox&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;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;搜索文档并回应GitHub issues&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;tools&lt;/span&gt;&lt;span class="o"&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 class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;web_search&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;搜索公开文档&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="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;azure_ai_search&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;index_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;internal-docs&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="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mcp_server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;server_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://your-github-mcp-server.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;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;发布后，Foundry提供统一端点。一次连接，获取所有工具。&lt;/p&gt;
&lt;h2 id="不受限于foundry-agents"&gt;不受限于Foundry Agents&lt;/h2&gt;
&lt;p&gt;Toolboxes在Foundry中&lt;strong&gt;创建和管理&lt;/strong&gt;，但消费面是开放的MCP协议。可以从使用Microsoft Agent Framework或LangGraph的自定义Agent、GitHub Copilot和其他MCP兼容IDE以及任何支持MCP的运行时中使用它们。&lt;/p&gt;
&lt;h2 id="为什么现在重要"&gt;为什么现在重要&lt;/h2&gt;
&lt;p&gt;多Agent浪潮正在进入生产环境。每个新Agent都是重复配置、过期凭据和不一致行为的新风险面。Build + Consume基础足以开始集中化。当Govern支柱推出时，你将拥有对整个Agent群完全可观测、集中控制的工具层。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;还是早期阶段——公开预览，Python SDK优先，Discover和Govern仍在路上。但模型是稳固的，MCP原生设计意味着它可以与你已经在构建的工具配合使用。查阅&lt;a href="https://devblogs.microsoft.com/foundry/introducing-toolboxes-in-foundry/"&gt;官方公告&lt;/a&gt;了解详情。&lt;/p&gt;</content:encoded></item><item><title>Windows App Dev CLI v0.3：从终端实现F5调试和面向智能体的UI自动化</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/windows-app-dev-cli-v03-run-ui-automation/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/windows-app-dev-cli-v03-run-ui-automation/</guid><description>Windows App Development CLI v0.3带来了winapp run（从终端进行调试启动）、winapp ui（UI自动化）以及一个让dotnet run支持打包应用的NuGet包。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/windows-app-dev-cli-v03-run-ui-automation/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Visual Studio的F5体验非常棒。但是，仅仅为了启动和调试一个打包的Windows应用而打开VS，在CI流水线、自动化工作流或AI智能体执行测试时就显得过于繁重了。&lt;/p&gt;
&lt;p&gt;Windows App Development CLI v0.3&lt;a href="https://devblogs.microsoft.com/ifdef-windows/windows-app-development-cli-v0-3-new-run-and-ui-commands-plus-dotnet-run-support-for-packaged-apps/"&gt;正式发布&lt;/a&gt;，通过两个核心功能直接解决了这个问题：&lt;code&gt;winapp run&lt;/code&gt;和&lt;code&gt;winapp ui&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="winapp-run随处可用的f5"&gt;winapp run：随处可用的F5&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;winapp run&lt;/code&gt;接受一个未打包的应用文件夹和清单，执行VS在调试启动时所做的一切：注册松散包、启动应用，并在重新部署之间保留&lt;code&gt;LocalState&lt;/code&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;&lt;span class="c1"&gt;# 构建应用，然后作为打包应用运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;winapp run ./bin/Debug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;支持WinUI、WPF、WinForms、Console、Avalonia等。各模式同时面向开发者和自动化工作流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--detach&lt;/code&gt;&lt;/strong&gt;：启动后立即将控制权返回给终端。非常适合CI/自动化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--unregister-on-exit&lt;/code&gt;&lt;/strong&gt;：应用关闭时清理已注册的包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--debug-output&lt;/code&gt;&lt;/strong&gt;：实时捕获&lt;code&gt;OutputDebugString&lt;/code&gt;消息和异常。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="新nuget包打包应用的dotnet-run支持"&gt;新NuGet包：打包应用的dotnet run支持&lt;/h2&gt;
&lt;p&gt;面向.NET开发者，新增了一个NuGet包：&lt;code&gt;Microsoft.Windows.SDK.BuildTools.WinApp&lt;/code&gt;。安装后，&lt;code&gt;dotnet run&lt;/code&gt;处理整个内循环：构建、准备松散布局包、在Windows中注册和启动——一步完成。&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;winapp init
&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;dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="winapp-ui从命令行实现ui自动化"&gt;winapp ui：从命令行实现UI自动化&lt;/h2&gt;
&lt;p&gt;这是开启智能体场景的功能。&lt;code&gt;winapp ui&lt;/code&gt;从终端提供对任何正在运行的Windows应用（WPF、WinForms、Win32、Electron、WinUI3）的完整UI自动化访问。&lt;/p&gt;
&lt;p&gt;可以实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;列出所有顶层窗口&lt;/li&gt;
&lt;li&gt;遍历窗口的完整UI自动化树&lt;/li&gt;
&lt;li&gt;按名称、类型或自动化ID搜索元素&lt;/li&gt;
&lt;li&gt;单击、调用和设置值&lt;/li&gt;
&lt;li&gt;截图&lt;/li&gt;
&lt;li&gt;等待元素出现——非常适合测试同步&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将&lt;code&gt;winapp ui&lt;/code&gt;与&lt;code&gt;winapp run&lt;/code&gt;结合使用，即可从终端实现完整的构建→启动→验证工作流。智能体可以运行应用、检查UI状态、以编程方式交互并验证结果。&lt;/p&gt;
&lt;h2 id="其他新功能"&gt;其他新功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;winapp unregister&lt;/code&gt;&lt;/strong&gt;：测试完成后删除旁加载的包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;winapp manifest add-alias&lt;/code&gt;&lt;/strong&gt;：添加别名，从终端按名称启动应用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tab补全&lt;/strong&gt;：一条命令配置PowerShell补全。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安装方式"&gt;安装方式&lt;/h2&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;winget install Microsoft.WinAppCli
&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;npm install -g @microsoft/winappcli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CLI处于公开预览阶段。完整文档请查看&lt;a href="https://github.com/microsoft/WinAppCli"&gt;GitHub仓库&lt;/a&gt;，所有详细信息请查看&lt;a href="https://devblogs.microsoft.com/ifdef-windows/windows-app-development-cli-v0-3-new-run-and-ui-commands-plus-dotnet-run-support-for-packaged-apps/"&gt;原始公告&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>每天花68分钟重新解释代码？这里有个解决方案</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/auto-memory-stop-re-explaining-code-to-copilot/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/auto-memory-stop-re-explaining-code-to-copilot/</guid><description>上下文腐烂是真实存在的——你的AI代理在30轮之后就会迷失，你每小时都在支付压缩税。auto-memory给GitHub Copilot CLI提供了外科式的记忆，而不需要消耗数千个token。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/auto-memory-stop-re-explaining-code-to-copilot/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;你知道那个时刻——当你的Copilot会话触发&lt;code&gt;/compact&lt;/code&gt;，代理完全忘记你在做什么？你花接下来五分钟重新解释文件结构、失败的测试、你已经尝试过的三种方法。然后又发生了。&lt;/p&gt;
&lt;p&gt;Desi Villanueva测量了一下：&lt;strong&gt;每天68分钟&lt;/strong&gt; — 仅用于重新定向。不是写代码，不是审查PR，只是让AI了解它已经知道的事情。&lt;/p&gt;
&lt;h2 id="上下文窗口的谎言"&gt;上下文窗口的谎言&lt;/h2&gt;
&lt;p&gt;实际计算：200K总上下文，减去MCP工具65K，减去指令文件10K，实际上&lt;strong&gt;在你输入任何内容之前只剩125K&lt;/strong&gt;。LLM在60%容量时会撞墙，有效限制是&lt;strong&gt;45K token&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="压缩税"&gt;压缩税&lt;/h2&gt;
&lt;p&gt;残忍的部分：&lt;strong&gt;记忆已经存在。&lt;/strong&gt; Copilot CLI将每个会话写入&lt;code&gt;~/.copilot/session-store.db&lt;/code&gt;中的本地SQLite数据库。代理只是无法读取它。&lt;/p&gt;
&lt;h2 id="auto-memory召回层而非记忆系统"&gt;auto-memory：召回层，而非记忆系统&lt;/h2&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;pip install auto-memory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;~1,900行Python。零依赖。30秒安装完成。&lt;/p&gt;
&lt;p&gt;不是用grep结果淹没上下文，而是给代理外科式访问真正重要的内容——&lt;strong&gt;50个token而不是10,000个&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;上下文腐烂是真实的架构约束。auto-memory通过给你的代理提供廉价、精确的召回机制来绕过它。&lt;/p&gt;
&lt;p&gt;查看：&lt;a href="https://github.com/dezgit2025/auto-memory"&gt;GitHub上的auto-memory&lt;/a&gt;。Desi Villanueva的原始文章：&lt;a href="https://devblogs.microsoft.com/all-things-azure/i-wasted-68-minutes-a-day-re-explaining-my-code-then-i-built-auto-memory/"&gt;I Wasted 68 Minutes a Day&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>立即打补丁：.NET 10.0.7 OOB安全更新 (ASP.NET Core Data Protection)</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-10-0-7-oob-security-patch-data-protection/</link><pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-10-0-7-oob-security-patch-data-protection/</guid><description>.NET 10.0.7是修复Microsoft.AspNetCore.DataProtection中安全漏洞的带外发布——管理的认证加密器在错误的字节上计算HMAC，可能导致权限提升。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文已自动翻译。要查看原始版本，请&lt;a href="https://thedotnetblog.com/posts/emiliano-montesdeoca/dotnet-10-0-7-oob-security-patch-data-protection/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;此更新不是可选的。如果您的应用程序使用&lt;code&gt;Microsoft.AspNetCore.DataProtection&lt;/code&gt;，您需要更新到10.0.7。&lt;/p&gt;
&lt;h2 id="发生了什么"&gt;发生了什么&lt;/h2&gt;
&lt;p&gt;Patch Tuesday &lt;code&gt;.NET 10.0.6&lt;/code&gt;发布后，一些用户报告解密失败。调查过程中，团队发现了安全漏洞&lt;strong&gt;CVE-2026-40372&lt;/strong&gt;：HMAC验证标签在payload的&lt;strong&gt;错误字节&lt;/strong&gt;上计算，可能导致权限提升。&lt;/p&gt;
&lt;h2 id="如何修复"&gt;如何修复&lt;/h2&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.AspNetCore.DataProtection --version 10.0.7
&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;Rahul Bhandari的原始公告：&lt;a href="https://devblogs.microsoft.com/dotnet/dotnet-10-0-7-oob-security-update/"&gt;.NET 10.0.7 Out-of-Band Security Update&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>azd + GitHub Copilot：AI 驱动的项目设置和智能错误修复</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-copilot-integration-ai-setup-troubleshooting/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-copilot-integration-ai-setup-troubleshooting/</guid><description>Azure Developer CLI 现已与 GitHub Copilot 集成，可以生成项目基础架构并修复部署错误——无需离开终端。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。如需阅读英文原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-copilot-integration-ai-setup-troubleshooting/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你是否有过这样的经历：想把现有应用部署到 Azure，却盯着空白的 &lt;code&gt;azure.yaml&lt;/code&gt; 发呆，想不起来 Express API 到底该用 Container Apps 还是 App Service？这种时刻即将成为历史。&lt;/p&gt;
&lt;p&gt;Azure Developer CLI（&lt;code&gt;azd&lt;/code&gt;）现已与 GitHub Copilot 以两种实用的方式集成：&lt;code&gt;azd init&lt;/code&gt; 时的 AI 辅助项目脚手架，以及部署失败时的智能错误排查。两项功能都完全在终端内运行——正是我想要的方式。&lt;/p&gt;
&lt;h2 id="在-azd-init-中使用-copilot-设置"&gt;在 azd init 中使用 Copilot 设置&lt;/h2&gt;
&lt;p&gt;运行 &lt;code&gt;azd init&lt;/code&gt; 时，现在会出现&amp;quot;Set up with GitHub Copilot (Preview)&amp;ldquo;选项。选择它，Copilot 会分析你的代码库，根据实际代码生成 &lt;code&gt;azure.yaml&lt;/code&gt;、基础架构模板和 Bicep 模块。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd init
# 选择：&amp;#34;Set up with GitHub Copilot (Preview)&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前提条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;azd 1.23.11 或更高版本&lt;/strong&gt; — 用 &lt;code&gt;azd version&lt;/code&gt; 检查，或用 &lt;code&gt;azd update&lt;/code&gt; 更新&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有效的 GitHub Copilot 订阅&lt;/strong&gt;（Individual、Business 或 Enterprise）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub CLI（&lt;code&gt;gh&lt;/code&gt;）&lt;/strong&gt; — 必要时 &lt;code&gt;azd&lt;/code&gt; 会提示登录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我觉得真正实用的是它能双向工作。从零开始构建？Copilot 从一开始就帮你配置正确的 Azure 服务。有现有应用想部署？把 Copilot 指向它，无需重构代码即可生成配置。&lt;/p&gt;
&lt;h3 id="它实际做什么"&gt;它实际做什么&lt;/h3&gt;
&lt;p&gt;假设你有一个 Node.js Express API，依赖 PostgreSQL。不必手动在 Container Apps 和 App Service 之间抉择，也不必从零编写 Bicep，Copilot 检测到你的技术栈后会生成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包含正确 &lt;code&gt;language&lt;/code&gt;、&lt;code&gt;host&lt;/code&gt; 和 &lt;code&gt;build&lt;/code&gt; 设置的 &lt;code&gt;azure.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Azure Container Apps 的 Bicep 模块&lt;/li&gt;
&lt;li&gt;Azure Database for PostgreSQL 的 Bicep 模块&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;并在做任何更改前运行预检——验证 git 工作目录是否干净，提前请求 MCP 服务器工具的授权。一切都在你知情的情况下进行。&lt;/p&gt;
&lt;h2 id="copilot-驱动的错误排查"&gt;Copilot 驱动的错误排查&lt;/h2&gt;
&lt;p&gt;部署错误无可避免。缺少参数、权限问题、SKU 可用性问题——而错误信息很少告诉你真正需要知道的那一件事：&lt;em&gt;如何修复&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;没有 Copilot 时的循环：复制错误 → 搜索文档 → 读三篇不相关的 Stack Overflow 回答 → 运行一些 &lt;code&gt;az&lt;/code&gt; CLI 命令 → 重试并祈祷。有了集成在 &lt;code&gt;azd&lt;/code&gt; 中的 Copilot，这个循环消失了。任何 &lt;code&gt;azd&lt;/code&gt; 命令失败时，它会立即提供四个选项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explain&lt;/strong&gt; — 用通俗语言解释出了什么问题&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guidance&lt;/strong&gt; — 逐步修复指导&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diagnose and Guide&lt;/strong&gt; — 完整分析 + Copilot 应用修复（经你批准）+ 可选重试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skip&lt;/strong&gt; — 自己处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键在于：Copilot 已经了解你的项目、失败的命令和错误详情。它的建议针对&lt;em&gt;你的具体情况&lt;/em&gt;，而非泛泛的文档。&lt;/p&gt;
&lt;h3 id="设置默认行为"&gt;设置默认行为&lt;/h3&gt;
&lt;p&gt;如果你总是选择同一个选项，可以跳过交互式提示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config set copilot.errorHandling.category troubleshoot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可选值：&lt;code&gt;explain&lt;/code&gt;、&lt;code&gt;guidance&lt;/code&gt;、&lt;code&gt;troubleshoot&lt;/code&gt;、&lt;code&gt;fix&lt;/code&gt;、&lt;code&gt;skip&lt;/code&gt;。还可以启用自动修复和重试：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config set copilot.errorHandling.fix allow
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;随时重置为交互模式：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config unset copilot.errorHandling.category
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;这正是真正有价值的 Copilot 集成。运行 &lt;code&gt;azd update&lt;/code&gt; 获取最新版本，在下一个项目中试试 &lt;code&gt;azd init&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-copilot-integration/"&gt;原文公告&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>用 C# 和 .NET Native AOT 编写 Node.js 原生插件</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/nodejs-addons-csharp-native-aot/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/nodejs-addons-csharp-native-aot/</guid><description>C# Dev Kit 团队用 .NET Native AOT 替换了 C++ 编写的 Node.js 插件——结果更简洁、更安全，只需要 .NET SDK。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。如需阅读英文原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/nodejs-addons-csharp-native-aot/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是一个我很喜欢的场景：一个开发 .NET 工具的团队，用 C++ 编写了原生 Node.js 插件，通过 &lt;code&gt;node-gyp&lt;/code&gt; 编译。它能运行。但每个开发者的机器上都需要安装 Python——而且是旧版本的 Python——仅仅为了构建一个团队里没有人会直接接触的包。&lt;/p&gt;
&lt;p&gt;于是他们提出了一个很合理的问题：我们已经装了 .NET SDK，为什么还要写 C++？&lt;/p&gt;
&lt;p&gt;答案是 Native AOT，结果相当优雅。&lt;/p&gt;
&lt;h2 id="基本思路"&gt;基本思路&lt;/h2&gt;
&lt;p&gt;Node.js 原生插件是一个共享库（Windows 上的 &lt;code&gt;.dll&lt;/code&gt;，Linux 上的 &lt;code&gt;.so&lt;/code&gt;，macOS 上的 &lt;code&gt;.dylib&lt;/code&gt;），Node.js 可以在运行时加载它。接口叫做 &lt;a href="https://nodejs.org/api/n-api.html"&gt;N-API&lt;/a&gt;——一个稳定的、ABI 兼容的 C API。N-API 不关心是什么语言产生了这个库，只关心它是否导出了正确的符号。&lt;/p&gt;
&lt;p&gt;.NET Native AOT 恰好可以做到这一点。它将 C# 代码提前编译成具有任意入口点的本地共享库。这就是全部的技巧。&lt;/p&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-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Microsoft.NET.Sdk&amp;#34;&lt;/span&gt;&lt;span class="nt"&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="nt"&gt;&amp;lt;PropertyGroup&amp;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;lt;TargetFramework&amp;gt;&lt;/span&gt;net10.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;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;lt;PublishAot&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/PublishAot&amp;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;lt;AllowUnsafeBlocks&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/AllowUnsafeBlocks&amp;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;lt;/PropertyGroup&amp;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;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;PublishAot&lt;/code&gt; 告诉 SDK 在 &lt;code&gt;dotnet publish&lt;/code&gt; 时生成共享库。&lt;code&gt;AllowUnsafeBlocks&lt;/code&gt; 是 N-API interop 使用函数指针和固定缓冲区所必需的。&lt;/p&gt;
&lt;h2 id="导出入口点"&gt;导出入口点&lt;/h2&gt;
&lt;p&gt;Node.js 期望你的库导出 &lt;code&gt;napi_register_module_v1&lt;/code&gt;。在 C# 中，&lt;code&gt;[UnmanagedCallersOnly]&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;unsafe&lt;/span&gt; &lt;span class="kd"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistryAddon&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="na"&gt; [UnmanagedCallersOnly(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; EntryPoint = &amp;#34;napi_register_module_v1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; CallConvs = [typeof(CallConvCdecl)]&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;exports&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="n"&gt;Initialize&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;RegisterFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;readStringValue&amp;#34;&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ReadStringValue&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exports&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;code&gt;nint&lt;/code&gt; 是本机大小的整数——&lt;code&gt;intptr_t&lt;/code&gt; 的托管等价物。&lt;code&gt;u8&lt;/code&gt; 后缀生成包含 UTF-8 字符串字面量的 &lt;code&gt;ReadOnlySpan&amp;lt;byte&amp;gt;&lt;/code&gt;，直接传递给 N-API，无需任何编码分配。&lt;code&gt;[UnmanagedCallersOnly]&lt;/code&gt; 用 Node.js 所寻找的确切入口点名称导出方法。&lt;/p&gt;
&lt;h2 id="将-n-api-解析到宿主进程"&gt;将 N-API 解析到宿主进程&lt;/h2&gt;
&lt;p&gt;N-API 函数由 &lt;code&gt;node.exe&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="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Initialize&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="n"&gt;NativeLibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetDllImportResolver&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;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reflection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetExecutingAssembly&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;ResolveDllImport&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;static&lt;/span&gt; &lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;ResolveDllImport&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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;libraryName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;assembly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DllImportSearchPath&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;searchPath&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libraryName&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;node&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;NativeLibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetMainProgramHandle&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;有了这个，P/Invoke 声明通过 &lt;code&gt;[LibraryImport]&lt;/code&gt; 和源生成的 marshalling 就能正常工作了。&lt;/p&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="na"&gt;[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)]&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="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;ReadStringValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;info&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;try&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;keyPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetStringArg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valueName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetStringArg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyPath&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;valueName&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;null&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="n"&gt;ThrowError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Expected two string arguments: keyPath, valueName&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="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&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&gt;&lt;/span&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;var&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenSubKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valueName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="k"&gt;value&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;CreateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&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;GetUndefined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&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="n"&gt;ThrowError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$&amp;#34;Registry read failed: {ex.Message}&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="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&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;code&gt;try/catch&lt;/code&gt; 的重要说明：&lt;code&gt;[UnmanagedCallersOnly]&lt;/code&gt; 方法中未处理的异常会导致宿主进程崩溃。始终要捕获异常并通过 &lt;code&gt;ThrowError&lt;/code&gt; 转发给 JavaScript。&lt;/p&gt;
&lt;h2 id="从-typescript-调用"&gt;从 TypeScript 调用&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;./native/win32-x64/RegistryAddon.node&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;RegistryAddon&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sdkPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readStringValue&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="s1"&gt;&amp;#39;SOFTWARE\\dotnet\\Setup\\InstalledVersions\\x64\\sdk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;InstallLocation&amp;#39;&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;TypeScript → C#，无需 Python，无需 C++。&lt;/p&gt;
&lt;h2 id="他们获得了什么"&gt;他们获得了什么&lt;/h2&gt;
&lt;p&gt;立竿见影的好处是改善了贡献者体验：不再需要特定版本的 Python，&lt;code&gt;yarn install&lt;/code&gt; 只需 Node.js 和 .NET SDK 就能工作。CI 流水线也得到了简化。性能与 C++ 实现相当。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;C# Dev Kit 团队用团队里每个人都能编写和调试的简洁 C# 代码，替换了 Python/C++ 的复杂性。如需包含所有字符串 marshalling 辅助方法的完整演练，请查看 &lt;a href="https://devblogs.microsoft.com/dotnet/writing-nodejs-addons-with-dotnet-native-aot/"&gt;.NET 博客上的原文&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.117：Agent 拥有了自己的 Git 分支，我举双手赞成</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-117-agents-autopilot-worktrees/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-117-agents-autopilot-worktrees/</guid><description>VS Code 1.117 为 Agent 会话带来了 worktree 隔离、持久化 Autopilot 模式和子 Agent 支持。Agent 编码工作流变得更加真实了。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-117-agents-autopilot-worktrees/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;ldquo;AI 助手&amp;quot;和&amp;quot;AI 队友&amp;quot;之间的界限越来越模糊。VS Code 1.117 刚刚发布，&lt;a href="https://code.visualstudio.com/updates/v1_117"&gt;完整的发行说明&lt;/a&gt;内容丰富，但核心很明确：Agent 正在成为你开发工作流中的一等公民。&lt;/p&gt;
&lt;p&gt;以下是真正重要的内容。&lt;/p&gt;
&lt;h2 id="autopilot-模式终于能记住你的偏好了"&gt;Autopilot 模式终于能记住你的偏好了&lt;/h2&gt;
&lt;p&gt;以前，你每次开始新会话都得重新启用 Autopilot。很烦。现在你的权限模式会在会话之间持久化，你还可以配置默认值。&lt;/p&gt;
&lt;p&gt;Agent Host 支持三种会话配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default&lt;/strong&gt; — 工具在运行前会请求确认&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bypass&lt;/strong&gt; — 自动批准一切&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autopilot&lt;/strong&gt; — 完全自主，自己回答问题并继续执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你正在搭建一个带有迁移、Docker 和 CI 的新 .NET 项目——设置一次 Autopilot 就行了。这个偏好会一直保持。&lt;/p&gt;
&lt;h2 id="agent-会话的-worktree-和-git-隔离"&gt;Agent 会话的 worktree 和 git 隔离&lt;/h2&gt;
&lt;p&gt;这是重头戏。Agent 会话现在支持完整的 worktree 和 git 隔离。这意味着当一个 Agent 处理任务时，它会获得自己的分支和工作目录。你的主分支完全不受影响。&lt;/p&gt;
&lt;p&gt;更好的是——Copilot CLI 会为这些 worktree 会话生成有意义的分支名称。不再是 &lt;code&gt;agent-session-abc123&lt;/code&gt;。你会得到一个真正描述 Agent 正在做什么的名称。&lt;/p&gt;
&lt;p&gt;对于管理多个功能分支或在长时间脚手架任务运行期间修复 bug 的 .NET 开发者来说，这是一个游戏规则的改变。你可以让一个 Agent 在一个 worktree 中构建 API 控制器，同时你在另一个 worktree 中调试服务层问题。没有冲突。没有 stash。没有混乱。&lt;/p&gt;
&lt;h2 id="子-agent-和-agent-团队"&gt;子 Agent 和 Agent 团队&lt;/h2&gt;
&lt;p&gt;Agent Host Protocol 现在支持子 Agent。一个 Agent 可以启动其他 Agent 来处理任务的各个部分。把它想象成委派——你的主 Agent 负责协调，专门的 Agent 处理各个部分。&lt;/p&gt;
&lt;p&gt;这还处于早期阶段，但对 .NET 工作流的潜力显而易见。想象一下，一个 Agent 处理你的 EF Core 迁移，另一个设置你的集成测试。我们还没有完全到达那里，但协议支持现在落地意味着工具很快就会跟上。&lt;/p&gt;
&lt;h2 id="agent-发送输入时终端输出自动包含"&gt;Agent 发送输入时终端输出自动包含&lt;/h2&gt;
&lt;p&gt;虽小但有意义。当 Agent 向终端发送输入时，终端输出现在会自动包含在上下文中。以前，Agent 需要额外的一个回合才能读取发生了什么。&lt;/p&gt;
&lt;p&gt;如果你曾经看到一个 Agent 运行 &lt;code&gt;dotnet build&lt;/code&gt;，失败了，然后又需要一次往返才能看到错误——这种摩擦消失了。它立即看到输出并做出反应。&lt;/p&gt;
&lt;h2 id="macos-上的-agents-应用自动更新"&gt;macOS 上的 Agents 应用自动更新&lt;/h2&gt;
&lt;p&gt;macOS 上的独立 Agents 应用现在可以自动更新了。不再需要手动下载新版本。它会自动保持最新。&lt;/p&gt;
&lt;h2 id="值得了解的小改进"&gt;值得了解的小改进&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;package.json 悬停提示&lt;/strong&gt;现在同时显示已安装版本和最新可用版本。如果你在 .NET 项目旁边管理 npm 工具，这很有用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSDoc 注释中的图片&lt;/strong&gt;在悬停和补全中正确渲染。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copilot CLI 会话&lt;/strong&gt;现在会显示是由 VS Code 还是外部创建的——当你在终端之间切换时很方便。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copilot CLI、Claude Code 和 Gemini CLI&lt;/strong&gt; 被识别为 shell 类型。编辑器知道你在运行什么。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;VS Code 1.117 不是一个花哨的功能堆砌。它是基础设施。Worktree 隔离、持久化权限、子 Agent 协议——这些是构建一个工作流的基石，在这个工作流中，Agent 可以处理真实的并行任务而不会干扰你的代码。&lt;/p&gt;
&lt;p&gt;如果你正在用 .NET 开发，还没有尝试 Agent 工作流，说实话，现在就是开始的时候。&lt;/p&gt;</content:encoded></item><item><title>Foundry的RFT更便宜、更智能了 — 看看有什么变化</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-fine-tuning-april-2026-rft-graders/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-fine-tuning-april-2026-rft-graders/</guid><description>Microsoft Foundry本月发布了三项RFT更新：o4-mini的全球训练、新的GPT-4.1模型评分器，以及一份能为你节省数小时调试时间的最佳实践指南。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-fine-tuning-april-2026-rft-graders/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你正在开发依赖微调模型的.NET应用，这个月的Foundry更新值得关注。Reinforcement Fine-Tuning变得更易获取，价格也大幅降低。&lt;/p&gt;
&lt;p&gt;完整详情请参阅&lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-foundry-finetune-april-2026/"&gt;官方公告&lt;/a&gt;，这里是实用要点总结。&lt;/p&gt;
&lt;h2 id="o4-mini的全球训练"&gt;o4-mini的全球训练&lt;/h2&gt;
&lt;p&gt;o4-mini是推理密集型和智能体工作负载的首选模型。重大消息：你现在可以从13+个Azure区域启动微调任务，与Standard训练相比，每token的训练费率更低。相同的基础设施，相同的质量，更广的覆盖范围。&lt;/p&gt;
&lt;p&gt;如果你的团队分布在不同地区，这很重要。你不再局限于少数几个区域来进行训练。&lt;/p&gt;
&lt;p&gt;以下是启动全球训练任务的REST API调用：&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;curl -X POST &lt;span class="s2"&gt;&amp;#34;https://&amp;lt;your-resource&amp;gt;.openai.azure.com/openai/fine_tuning/jobs?api-version=2025-04-01-preview&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;api-key: &lt;/span&gt;&lt;span class="nv"&gt;$AZURE_OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;model&amp;#34;: &amp;#34;o4-mini&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;training_file&amp;#34;: &amp;#34;&amp;lt;your-training-file-id&amp;gt;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;method&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;type&amp;#34;: &amp;#34;reinforcement&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;reinforcement&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;grader&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;type&amp;#34;: &amp;#34;string_check&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;name&amp;#34;: &amp;#34;answer-check&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;input&amp;#34;: &amp;#34;{{sample.output_text}}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;reference&amp;#34;: &amp;#34;{{item.reference_answer}}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;operation&amp;#34;: &amp;#34;eq&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;hyperparameters&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;n_epochs&amp;#34;: 2,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;compute_multiplier&amp;#34;: 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;trainingType&amp;#34;: &amp;#34;globalstandard&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那个&lt;code&gt;trainingType: globalstandard&lt;/code&gt;标志就是关键区别。&lt;/p&gt;
&lt;h2 id="新模型评分器gpt-41系列"&gt;新模型评分器：GPT-4.1系列&lt;/h2&gt;
&lt;p&gt;评分器定义了模型优化所针对的奖励信号。此前，基于模型的评分器仅限于较少的模型集合。现在你有三个新选项：GPT-4.1、GPT-4.1-mini和GPT-4.1-nano。&lt;/p&gt;
&lt;p&gt;什么时候应该使用模型评分器而不是确定性评分器？当你的任务输出是开放式的，当你需要在多个维度上进行部分评分，或者当你在构建智能体工作流且工具调用的正确性取决于语义上下文时。&lt;/p&gt;
&lt;p&gt;关键在于，分层策略很实用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1-nano&lt;/strong&gt; 用于初始迭代。低成本，快速反馈循环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1-mini&lt;/strong&gt; 当你的评分标准稳定并需要更高保真度时使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1&lt;/strong&gt; 用于生产环境评分或每个评分决策都至关重要的复杂标准。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你甚至可以在单个RFT任务中混合使用评分器类型。用string-match来评判&amp;quot;正确答案&amp;quot;维度，用模型评分器来评估推理质量。说实话，这种灵活性才是它对实际工作负载真正有用的地方。&lt;/p&gt;
&lt;h2 id="rft数据格式的陷阱"&gt;RFT数据格式的陷阱&lt;/h2&gt;
&lt;p&gt;这是很多人会踩的坑。RFT的数据格式与SFT不同。每行的最后一条消息必须是User或Developer角色——不是Assistant。期望的答案放在顶层键中，如&lt;code&gt;reference_answer&lt;/code&gt;，评分器会直接引用它。&lt;/p&gt;
&lt;p&gt;如果你之前一直在做监督微调并想切换到RFT，你需要重新组织训练数据。不要跳过这一步，否则你的任务会静默失败。&lt;/p&gt;
&lt;h2 id="为什么这对net开发者很重要"&gt;为什么这对.NET开发者很重要&lt;/h2&gt;
&lt;p&gt;如果你通过Azure OpenAI SDK从.NET应用中调用微调模型，更便宜的训练意味着你可以更积极地迭代。模型评分器选项意味着你可以针对细微的任务进行微调——不仅仅是精确匹配场景。&lt;a href="https://github.com/microsoft-foundry/fine-tuning/blob/main/Demos/Agentic_RFT_PrivatePreview/RFT_Best_Practice.md"&gt;GitHub&lt;/a&gt;上的最佳实践指南将为你节省真正的调试时间。&lt;/p&gt;
&lt;p&gt;从小处开始。十到一百个样本。简单的评分器。验证循环。然后扩展。&lt;/p&gt;</content:encoded></item><item><title>Global Azure Spain 2026</title><link>https://thedotnetblog.com/zh/events/global-azure-spain-2026/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/events/global-azure-spain-2026/</guid><description>西班牙最大的 Azure 社区活动 — 一整天的 Azure、AI、数据、安全和云原生开发主题演讲，38位演讲者，3个分场。</description><content:encoded>&lt;p&gt;Global Azure Spain 2026 于 &lt;strong&gt;2026年4月18日&lt;/strong&gt; 在马德里 Alcobendas 的 &lt;strong&gt;Kinépolis Diversia&lt;/strong&gt; 举办。这是西班牙最大的社区驱动 Azure 活动，38位演讲者在3个平行分场分享 AI 代理、Azure 网络、Cosmos DB、Fabric、IoT、安全等主题。&lt;/p&gt;
&lt;p&gt;活动时间为 &lt;strong&gt;08:30 至 18:30&lt;/strong&gt;，包括主题演讲、茶歇、午餐和闭幕问答环节。&lt;/p&gt;
&lt;h2 id="议程亮点"&gt;议程亮点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domando Agentes de IA&lt;/strong&gt;：使用 Azure AI Foundry 和 Azure API Management 的治理、工具和 API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Construyendo agentes con LibreChat en Azure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How Can I Steal Your Data with Azure Private Endpoints&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop Building APIs. Forge Agents with Azure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic DevOps Meets IoT: Real-Time Systems with Fabric and GitHub Copilot&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;El regreso de los tamagotchis!&lt;/strong&gt;：多代理系统实战&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundry Control Plane como plataforma de Agentes global&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rompiendo el perímetro: Zero Trust aplicado en Azure&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="门票"&gt;门票&lt;/h2&gt;
&lt;p&gt;注册为象征性捐赠 — 门票全部收入直接捐赠给 &lt;strong&gt;Plan International&lt;/strong&gt;，支持全球儿童权利和平等。名额有限，请尽早报名。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.eventbrite.es/e/entradas-global-azure-spain-2026-en-madrid-1981594189564"&gt;在 Eventbrite 获取门票&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://globalazure.es/"&gt;活动网站&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="azure-tour-2026"&gt;Azure Tour 2026&lt;/h2&gt;
&lt;p&gt;除马德里外，Global Azure Tour 2026 还将在 &lt;strong&gt;萨拉戈萨&lt;/strong&gt;、&lt;strong&gt;特内里费&lt;/strong&gt; 和 &lt;strong&gt;塞维利亚&lt;/strong&gt; 举办。&lt;/p&gt;</content:encoded></item><item><title>你在Azure上的AI实验正在烧钱——这样解决</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/cloud-cost-optimization-ai-workloads-azure/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/cloud-cost-optimization-ai-workloads-azure/</guid><description>Azure上的AI工作负载很容易变得昂贵。让我们聊聊在不拖慢开发进度的情况下，什么方法真正有效地控制成本。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/cloud-cost-optimization-ai-workloads-azure/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你现在正在Azure上构建AI驱动的应用，你可能已经注意到一件事：你的云账单看起来和以前不一样了。不只是更高了——更奇怪了。波动很大，难以预测。&lt;/p&gt;
&lt;p&gt;Microsoft刚刚发布了一篇关于&lt;a href="https://azure.microsoft.com/en-us/blog/cloud-cost-optimization-principles-that-still-matter/"&gt;仍然重要的云成本优化原则&lt;/a&gt;的优秀文章，说实话，时机再好不过了。因为AI工作负载在成本方面已经改变了游戏规则。&lt;/p&gt;
&lt;h2 id="为什么ai工作负载不一样"&gt;为什么AI工作负载不一样&lt;/h2&gt;
&lt;p&gt;事情是这样的。传统的.NET工作负载相对可预测。你了解你的App Service层级，了解你的SQL DTU，可以相当准确地估算每月开支。AI工作负载呢？完全不是这么回事。&lt;/p&gt;
&lt;p&gt;你在测试多个模型看哪个合适。你在启动GPU支持的基础设施进行微调。你在调用Azure OpenAI的API，而token消耗量会因prompt长度和用户行为的不同而产生巨大差异。每个实验都要花真金白银，你可能需要运行几十次才能找到正确的方法。&lt;/p&gt;
&lt;p&gt;这种不可预测性正是成本优化至关重要的原因——不是事后才想到，而是从第一天开始。&lt;/p&gt;
&lt;h2 id="管理与优化了解区别"&gt;管理与优化——了解区别&lt;/h2&gt;
&lt;p&gt;文章中有一个我认为开发者容易忽视的区别：成本&lt;em&gt;管理&lt;/em&gt;和成本&lt;em&gt;优化&lt;/em&gt;是不同的。&lt;/p&gt;
&lt;p&gt;管理是跟踪和报告。你在Azure Cost Management中设置预算，收到警报，查看仪表板。这是基本功。&lt;/p&gt;
&lt;p&gt;优化是你真正做决策的地方。你真的需要S3层级，还是S1就能处理你的负载？那个始终运行的计算实例周末是不是闲着？你能否用竞价实例来跑训练任务？&lt;/p&gt;
&lt;p&gt;作为.NET开发者，我们往往专注于代码，把基础设施决策留给&amp;quot;运维团队&amp;quot;。但如果你在Azure上部署，这些决策也是你的决策。&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; 给你的资源打标签。我是认真的。如果你无法分辨哪个项目或实验在消耗你的预算，你就无法优化任何东西。配合适当标签的Azure Cost Management是你最好的朋友。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实验之前设好护栏。&lt;/strong&gt; 使用Azure Policy限制dev/test环境中昂贵的SKU。为你的Azure OpenAI部署设置消费上限。不要等到账单到了才发现有人让GPU集群在周末一直运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;持续进行合理配置。&lt;/strong&gt; 原型阶段选的那个VM？可能不适合生产环境。Azure Advisor会给你建议——真的去看看。每月审查，而不是每年。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;考虑生命周期。&lt;/strong&gt; 开发资源应该关闭。测试环境不需要7×24小时运行。使用自动关机策略。特别是对于AI工作负载，考虑使用按执行付费的无服务器选项，而不是让计算资源一直保持运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;衡量价值，而不仅仅是成本。&lt;/strong&gt; 这一点容易忘记。一个成本更高但能产出显著更好结果的模型可能才是正确的选择。目标不是花最少的钱——而是花得聪明。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;云成本优化不是一次性的清理工作。它是一个习惯。随着AI工作负载让开支比以往任何时候都更难预测，尽早养成这个习惯可以帮你避免日后的痛苦惊喜。&lt;/p&gt;
&lt;p&gt;如果你是一名在Azure上构建的.NET开发者，开始像对待代码一样对待你的云账单吧——定期审查，混乱时重构，永远不要在不了解成本的情况下部署。&lt;/p&gt;</content:encoded></item><item><title>Docker Sandbox 让 Copilot 代理重构你的代码而不危及你的机器</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/copilot-docker-sandbox-agentic-refactoring/</link><pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/copilot-docker-sandbox-agentic-refactoring/</guid><description>Docker Sandbox 为 GitHub Copilot 代理提供安全的微型虚拟机，让它们可以自由重构——无需权限提示，不会对主机造成风险。这就是它为什么会改变大规模 .NET 现代化的一切。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/copilot-docker-sandbox-agentic-refactoring/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你用过 Copilot 的代理模式做一些超出小修改范围的事情，你一定知道那种痛苦。每次写文件，每个终端命令——又一个权限提示。现在想象一下在 50 个项目上这样操作。一点都不好玩。&lt;/p&gt;
&lt;p&gt;Azure 团队刚发布了一篇关于 &lt;a href="https://devblogs.microsoft.com/all-things-azure/best-of-both-worlds-for-agentic-refactoring-github-copilot-microvms-via-docker-sandbox/"&gt;GitHub Copilot 代理的 Docker Sandbox&lt;/a&gt; 的文章，说实话，这是我见过的最实用的代理工具改进之一。它使用微型虚拟机为 Copilot 提供一个完全隔离的环境，让它可以随意操作——安装包、运行构建、执行测试——而不会触及你的主机系统。&lt;/p&gt;
&lt;h2 id="docker-sandbox-实际给你带来什么"&gt;Docker Sandbox 实际给你带来什么&lt;/h2&gt;
&lt;p&gt;核心思路很简单：启动一个带有完整 Linux 环境的轻量级微型虚拟机，将你的工作区同步进去，然后让 Copilot 代理在里面自由操作。完成后，更改会同步回来。&lt;/p&gt;
&lt;p&gt;以下是让它不仅仅是&amp;quot;在容器里运行东西&amp;quot;的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双向工作区同步&lt;/strong&gt;，保留绝对路径。你的项目结构在沙箱内看起来完全一样。不会有路径相关的构建失败。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;私有 Docker 守护进程&lt;/strong&gt;在微型虚拟机内运行。代理可以构建和运行容器，而无需挂载你主机的 Docker socket。这对安全性来说意义重大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP/HTTPS 过滤代理&lt;/strong&gt;控制代理在网络上可以访问什么。你来决定允许哪些注册表和端点。沙箱内恶意 &lt;code&gt;npm install&lt;/code&gt; 带来的供应链攻击？已封锁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;YOLO 模式&lt;/strong&gt;——是的，他们就是这么叫的。代理运行时无需权限提示，因为它根本无法损坏你的主机。每一个破坏性操作都被隔离了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="为什么-net-开发者应该关注"&gt;为什么 .NET 开发者应该关注&lt;/h2&gt;
&lt;p&gt;想想现在有多少团队正在面对现代化工作。你有一个包含 30 个项目的 .NET Framework 解决方案，需要迁移到 .NET 9。那是数百个文件的更改——项目文件、命名空间更新、API 替换、NuGet 迁移。&lt;/p&gt;
&lt;p&gt;使用 Docker Sandbox，你可以将 Copilot 代理指向一个项目，让它在微型虚拟机内自由重构，运行 &lt;code&gt;dotnet build&lt;/code&gt; 和 &lt;code&gt;dotnet test&lt;/code&gt; 进行验证，然后只接受那些真正有效的更改。不用担心它在实验过程中意外破坏你的本地开发环境。&lt;/p&gt;
&lt;p&gt;文章还描述了运行&lt;strong&gt;并行代理舰队&lt;/strong&gt;的场景——每个代理在自己的沙箱中——同时处理不同的项目。对于大型 .NET 解决方案或微服务架构来说，这是一个巨大的时间节省。每个服务一个代理，全部隔离运行，全部独立验证。&lt;/p&gt;
&lt;h2 id="安全角度很重要"&gt;安全角度很重要&lt;/h2&gt;
&lt;p&gt;大多数人忽略的一点是：当你让 AI 代理执行任意命令时，你是在把整台机器都托付给它。Docker Sandbox 翻转了这个模型。代理在一次性环境中获得完全自主权。网络代理确保它只能从已批准的来源下载。你的主机文件系统、Docker 守护进程和凭据完好无损。&lt;/p&gt;
&lt;p&gt;对于有合规要求的团队——这是大多数企业级 .NET 公司的情况——这就是&amp;quot;我们不能使用代理式 AI&amp;quot;和&amp;quot;我们可以安全地采用它&amp;quot;之间的区别。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker Sandbox 解决了代理式编程的根本矛盾：代理需要自由才能发挥作用，但在你的主机上拥有自由是危险的。微型虚拟机两者兼得。如果你正在规划任何大规模的 .NET 重构或现代化，现在就值得设置起来。Copilot 的代码智能与安全执行环境的结合，正是生产团队一直在等待的。&lt;/p&gt;</content:encoded></item><item><title>别再盯着终端了：Aspire 的分离模式改变了工作流程</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-detached-mode-free-your-terminal/</link><pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-detached-mode-free-your-terminal/</guid><description>Aspire 13.2 让你在后台运行 AppHost 并释放终端。结合新的 CLI 命令和代理支持，这比听起来重要得多。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-detached-mode-free-your-terminal/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;每次运行 Aspire AppHost，你的终端就没了。被锁住了。一直占用到你按 Ctrl+C 为止。需要快速运行个命令？打开另一个标签页。想查看日志？再开一个标签页。这是一种小摩擦，但积少成多。&lt;/p&gt;
&lt;p&gt;Aspire 13.2 解决了这个问题。James Newton-King &lt;a href="https://devblogs.microsoft.com/aspire/aspire-detached-mode-and-process-management/"&gt;写了完整的详情&lt;/a&gt;，说实话，这是那种一用就立刻改变工作方式的功能。&lt;/p&gt;
&lt;h2 id="分离模式一条命令终端回来了"&gt;分离模式：一条命令，终端回来了&lt;/h2&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;aspire start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是 &lt;code&gt;aspire run --detach&lt;/code&gt; 的简写。你的 AppHost 在后台启动，终端立即回到你手中。不需要额外的标签页。不需要终端多路复用器。就是你的提示符，随时可用。&lt;/p&gt;
&lt;h2 id="管理正在运行的进程"&gt;管理正在运行的进程&lt;/h2&gt;
&lt;p&gt;关键在于——在后台运行只有在你能管理那些进程时才有用。Aspire 13.2 为此提供了一整套 CLI 命令：&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;&lt;span class="c1"&gt;# List all running AppHosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire ps
&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="c1"&gt;# Inspect the state of a specific AppHost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire describe
&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="c1"&gt;# Stream logs from a running AppHost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire logs
&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="c1"&gt;# Stop a specific AppHost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这让 Aspire CLI 变成了一个真正的进程管理器。你可以启动多个 AppHost，检查它们的状态，跟踪日志，然后关闭它们——全部在一个终端会话中完成。&lt;/p&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;aspire start --isolated
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire start --isolated
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个实例都会获得随机端口、独立的密钥和自己的生命周期。用 &lt;code&gt;aspire ps&lt;/code&gt; 查看两者，用 &lt;code&gt;aspire stop&lt;/code&gt; 停掉不需要的那个。&lt;/p&gt;
&lt;h2 id="为什么这对编码代理意义重大"&gt;为什么这对编码代理意义重大&lt;/h2&gt;
&lt;p&gt;这才是真正有趣的地方。在你的终端中工作的编码代理现在可以：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 &lt;code&gt;aspire start&lt;/code&gt; 启动应用&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;aspire describe&lt;/code&gt; 查询状态&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;aspire logs&lt;/code&gt; 检查日志来诊断问题&lt;/li&gt;
&lt;li&gt;完成后用 &lt;code&gt;aspire stop&lt;/code&gt; 停止应用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所有操作都不会失去终端会话。在分离模式之前，运行你的 AppHost 的代理会把自己锁在终端里。现在它可以启动、观察、迭代和清理——这正是你期望自主代理的工作方式。&lt;/p&gt;
&lt;p&gt;Aspire 团队在这方面下了功夫。运行 &lt;code&gt;aspire agent init&lt;/code&gt; 会设置一个 Aspire 技能文件，教会代理这些命令。这样，像 Copilot 的编码代理这样的工具就能直接管理你的 Aspire 工作负载。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;分离模式是一个伪装成简单标志的工作流升级。你不再需要在终端之间切换上下文，代理不再阻塞自己，新的 CLI 命令让你真正看到正在运行的内容。它实用、干净，让日常开发循环明显更顺畅。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/aspire/aspire-detached-mode-and-process-management/"&gt;完整文章&lt;/a&gt;了解所有详情，并通过 &lt;code&gt;aspire update --self&lt;/code&gt; 获取 Aspire 13.2。&lt;/p&gt;</content:encoded></item><item><title>Azure MCP 工具现已内置于 Visual Studio 2022 — 无需安装扩展</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-tools-built-into-visual-studio-2022/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-tools-built-into-visual-studio-2022/</guid><description>Azure MCP 工具作为 Visual Studio 2022 Azure 开发工作负载的一部分随附发布。超过 230 个工具、45 项 Azure 服务，零扩展安装。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-tools-built-into-visual-studio-2022/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你一直通过单独的扩展在 Visual Studio 中使用 Azure MCP 工具，那你一定很熟悉这套流程——安装 VSIX、重启、祈祷别出问题、处理版本不匹配。这种摩擦现在消失了。&lt;/p&gt;
&lt;p&gt;Yun Jung Choi &lt;a href="https://devblogs.microsoft.com/visualstudio/azure-mcp-tools-now-ship-built-into-visual-studio-2022-no-extension-required/"&gt;宣布&lt;/a&gt;，Azure MCP 工具现在直接作为 Visual Studio 2022 中 Azure 开发工作负载的一部分发布。无需扩展，无需 VSIX，无需重启。&lt;/p&gt;
&lt;h2 id="这实际意味着什么"&gt;这实际意味着什么&lt;/h2&gt;
&lt;p&gt;从 Visual Studio 2022 版本 17.14.30 开始，Azure MCP Server 捆绑在 Azure 开发工作负载中。如果你已经安装了该工作负载，只需在 GitHub Copilot Chat 中启用它即可。&lt;/p&gt;
&lt;p&gt;超过 230 个工具，覆盖 45 项 Azure 服务——直接从聊天窗口即可访问。列出你的存储账户、部署 ASP.NET Core 应用、诊断 App Service 问题、查询 Log Analytics——全程无需打开浏览器标签页。&lt;/p&gt;
&lt;h2 id="为什么这比听起来更重要"&gt;为什么这比听起来更重要&lt;/h2&gt;
&lt;p&gt;开发工具有个道理：每多一个步骤就是摩擦，摩擦会扼杀采用率。MCP 作为单独的扩展意味着版本不匹配、安装失败，以及又多了一个需要保持更新的东西。将它内置到工作负载中意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单一的更新路径&lt;/strong&gt;——通过 Visual Studio Installer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无版本偏差&lt;/strong&gt;——扩展和 IDE 之间不会出现版本不一致&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;始终保持最新&lt;/strong&gt;——MCP Server 随 VS 常规发布一起更新&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于标准化使用 Azure 的团队来说，这意义重大。安装一次工作负载，启用工具，每次会话都能使用。&lt;/p&gt;
&lt;h2 id="你能用它做什么"&gt;你能用它做什么&lt;/h2&gt;
&lt;p&gt;这些工具通过 Copilot Chat 覆盖完整的开发生命周期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;学习&lt;/strong&gt;——询问 Azure 服务、最佳实践、架构模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设计与开发&lt;/strong&gt;——获取服务推荐，配置应用代码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;——预配资源并直接从 IDE 进行部署&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排查问题&lt;/strong&gt;——查询日志、检查资源健康状况、诊断生产环境问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个简单的例子——在 Copilot Chat 中输入：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;List my storage accounts in my current subscription.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Copilot 在后台调用 Azure MCP 工具，查询你的订阅，返回一个包含名称、位置和 SKU 的格式化列表。无需打开门户。&lt;/p&gt;
&lt;h2 id="如何启用"&gt;如何启用&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;更新到 Visual Studio 2022 &lt;strong&gt;17.14.30&lt;/strong&gt; 或更高版本&lt;/li&gt;
&lt;li&gt;确保已安装 &lt;strong&gt;Azure development&lt;/strong&gt; 工作负载&lt;/li&gt;
&lt;li&gt;打开 GitHub Copilot Chat&lt;/li&gt;
&lt;li&gt;点击 &lt;strong&gt;Select tools&lt;/strong&gt; 按钮（双扳手图标）&lt;/li&gt;
&lt;li&gt;开启 &lt;strong&gt;Azure MCP Server&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;就这样。跨会话保持启用状态。&lt;/p&gt;
&lt;h2 id="一个注意事项"&gt;一个注意事项&lt;/h2&gt;
&lt;p&gt;这些工具默认是禁用的——你需要手动启用。而且 VS 2026 特有的工具在 VS 2022 中不可用。工具的可用性还取决于你的 Azure 订阅权限，与门户中一样。&lt;/p&gt;
&lt;h2 id="更大的图景"&gt;更大的图景&lt;/h2&gt;
&lt;p&gt;这是一个清晰趋势的一部分：MCP 正在成为在开发者 IDE 中呈现云工具的标准方式。我们已经看到了 &lt;a href="https://devblogs.microsoft.com/azure-sdk/announcing-azure-mcp-server-2-0-stable-release/"&gt;Azure MCP Server 2.0 稳定版发布&lt;/a&gt;以及在 VS Code 和其他编辑器中的 MCP 集成。将其内置到 Visual Studio 的工作负载系统中是自然而然的演进。&lt;/p&gt;
&lt;p&gt;对于我们这些常年在 Visual Studio 中工作的 .NET 开发者来说，这又少了一个需要切换到 Azure 门户的理由。说实话，标签页切换越少越好。&lt;/p&gt;</content:encoded></item><item><title>Pin 聚类终于登陆 .NET MAUI Maps — 一个属性，零痛苦</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/maui-maps-pin-clustering-finally/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/maui-maps-pin-clustering-finally/</guid><description>.NET MAUI 11 Preview 3 为 Map 控件添加了原生 Pin 聚类功能。一个属性、独立的聚类分组和点击处理 — 全部内置。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/maui-maps-pin-clustering-finally/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你知道那种感觉吗？在地图上加载一百个 Pin，然后整个地图变成一团看不清的东西？对，这就是 .NET MAUI Maps 一直以来的体验。现在不会了。&lt;/p&gt;
&lt;p&gt;David Ortinau &lt;a href="https://devblogs.microsoft.com/dotnet/pin-clustering-in-dotnet-maui-maps/"&gt;刚刚宣布&lt;/a&gt; .NET MAUI 11 Preview 3 在 Android 和 iOS/Mac Catalyst 上内置了 Pin 聚类功能。而且最棒的是 — 启用它简单得不可思议。&lt;/p&gt;
&lt;h2 id="一个属性统治一切"&gt;一个属性统治一切&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;maps:Map&lt;/span&gt; &lt;span class="na"&gt;IsClusteringEnabled=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;True&amp;#34;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就这样。相邻的 Pin 会被分组到带有计数徽章的聚类中。放大时展开，缩小时折叠。这是用户对任何现代地图都期望的行为 — 现在你只需一个属性就能获得。&lt;/p&gt;
&lt;h2 id="独立的聚类分组"&gt;独立的聚类分组&lt;/h2&gt;
&lt;p&gt;这才是有趣的地方。不是所有 Pin 都应该聚在一起。咖啡店和公园是不同的东西，你的地图应该知道这一点。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ClusteringIdentifier&lt;/code&gt; 属性让你可以将 Pin 分成独立的组：&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;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Pin&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;Label&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Pike Place Coffee&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;Location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47.6097&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;122.3331&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;ClusteringIdentifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;coffee&amp;#34;&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Pin&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;Label&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Occidental Square&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;Location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47.6064&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;122.3325&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;ClusteringIdentifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;parks&amp;#34;&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;具有相同标识符的 Pin 会聚在一起。不同的标识符即使在地理位置很近的情况下也会形成独立的聚类。没有标识符？默认分组。干净且可预测。&lt;/p&gt;
&lt;h2 id="处理聚类点击"&gt;处理聚类点击&lt;/h2&gt;
&lt;p&gt;当用户点击一个聚类时，你会收到一个 &lt;code&gt;ClusterClicked&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="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterClicked&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;DisplayAlert&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="s"&gt;$&amp;#34;Cluster ({e.Pins.Count} pins)&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;names&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="s"&gt;&amp;#34;OK&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Suppress default zoom-to-cluster behavior:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// e.Handled = true;&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;code&gt;Pins&lt;/code&gt;（聚类中的 Pin）、&lt;code&gt;Location&lt;/code&gt;（地理中心）和 &lt;code&gt;Handled&lt;/code&gt;（如果你想覆盖默认缩放行为，设置为 &lt;code&gt;true&lt;/code&gt;）。简单、实用，完全符合预期。&lt;/p&gt;
&lt;h2 id="值得了解的平台细节"&gt;值得了解的平台细节&lt;/h2&gt;
&lt;p&gt;在 Android 上，聚类使用自定义的基于网格的算法，在缩放变化时重新计算 — 没有外部依赖。在 iOS 和 Mac Catalyst 上，它利用了 MapKit 原生的 &lt;code&gt;MKClusterAnnotation&lt;/code&gt; 支持，这意味着流畅的平台原生动画。&lt;/p&gt;
&lt;p&gt;这是 MAUI 团队做出正确决策的案例之一 — 在有意义的地方依靠平台能力。&lt;/p&gt;
&lt;h2 id="为什么这很重要"&gt;为什么这很重要&lt;/h2&gt;
&lt;p&gt;Pin 聚类一直是 .NET MAUI 中最受期待的功能之一（&lt;a href="https://github.com/dotnet/maui/issues/11811"&gt;issue #11811&lt;/a&gt;），这是有充分理由的。每个在地图上显示位置的应用 — 配送追踪、门店定位、房地产 — 都需要它。以前你必须自己构建或引入第三方库。现在它是内置的。&lt;/p&gt;
&lt;p&gt;对于我们构建跨平台移动应用的 .NET 开发者来说，这正是那种让 MAUI 成为地图密集型场景中真正实用选择的生活质量改善。&lt;/p&gt;
&lt;h2 id="开始使用"&gt;开始使用&lt;/h2&gt;
&lt;p&gt;安装 &lt;a href="https://dotnet.microsoft.com/download/dotnet/11.0"&gt;.NET 11 Preview 3&lt;/a&gt; 并更新 .NET MAUI 工作负载。&lt;a href="https://github.com/dotnet/maui-samples/tree/main/10.0/UserInterface/Views/Map/MapDemo/WorkingWithMaps"&gt;Maps 示例&lt;/a&gt;包含一个新的聚类页面，你可以立即上手体验。&lt;/p&gt;
&lt;p&gt;去用它构建点什么吧 — 让你的地图终于能喘口气。&lt;/p&gt;</content:encoded></item><item><title>.NET 2026年4月服务更新 — 你今天就该应用的安全补丁</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-april-2026-servicing-security-patches/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-april-2026-servicing-security-patches/</guid><description>2026年4月的服务更新修补了 .NET 10、.NET 9、.NET 8 和 .NET Framework 中的6个CVE — 其中包括两个远程代码执行漏洞。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-april-2026-servicing-security-patches/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.NET 和 .NET Framework 的 &lt;a href="https://devblogs.microsoft.com/dotnet/dotnet-and-dotnet-framework-april-2026-servicing-updates/"&gt;2026年4月服务更新&lt;/a&gt; 已发布，这次包含了你需要尽快应用的安全修复。共修补了六个CVE，其中包括两个远程代码执行（RCE）漏洞。&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;CVE&lt;/th&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;CVE-2026-26171&lt;/td&gt;
&lt;td&gt;安全功能绕过&lt;/td&gt;
&lt;td&gt;.NET 10, 9, 8 + .NET Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2026-32178&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;远程代码执行&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;.NET 10, 9, 8 + .NET Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2026-33116&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;远程代码执行&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;.NET 10, 9, 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2026-32203&lt;/td&gt;
&lt;td&gt;拒绝服务&lt;/td&gt;
&lt;td&gt;.NET 10, 9, 8 + .NET Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2026-23666&lt;/td&gt;
&lt;td&gt;拒绝服务&lt;/td&gt;
&lt;td&gt;.NET Framework 3.0–4.8.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2026-32226&lt;/td&gt;
&lt;td&gt;拒绝服务&lt;/td&gt;
&lt;td&gt;.NET Framework 2.0–4.8.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两个RCE CVE（CVE-2026-32178 和 CVE-2026-33116）影响范围最广，应当优先处理。&lt;/p&gt;
&lt;h2 id="更新版本"&gt;更新版本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;.NET 10&lt;/strong&gt;：10.0.6&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET 9&lt;/strong&gt;：9.0.15&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET 8&lt;/strong&gt;：8.0.26&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;均可通过常规渠道获取 — &lt;a href="https://dotnet.microsoft.com/download/dotnet/10.0"&gt;dotnet.microsoft.com&lt;/a&gt;、MCR上的容器镜像以及Linux包管理器。&lt;/p&gt;
&lt;h2 id="应该怎么做"&gt;应该怎么做&lt;/h2&gt;
&lt;p&gt;将你的项目和CI/CD管道更新到最新的补丁版本。如果你在运行容器，拉取最新的镜像。如果你在使用 .NET Framework，请查看 &lt;a href="https://learn.microsoft.com/dotnet/framework/release-notes/release-notes"&gt;.NET Framework 发行说明&lt;/a&gt; 获取对应的补丁。&lt;/p&gt;
&lt;p&gt;对于在生产环境运行 .NET 10 的用户（这是当前版本），10.0.6 是必须更新的。.NET 9.0.15 和 .NET 8.0.26 也是如此，如果你在使用这些LTS版本的话。两个RCE漏洞可不是你能拖延的事情。&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2 新增 MongoDB EF Core 和 Azure Data Lake — 两个值得尝试的集成</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-mongodb-efcore-data-lake/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-mongodb-efcore-data-lake/</guid><description>Aspire 13.2 新增了 MongoDB Entity Framework Core 和 Azure Data Lake Storage 集成，支持零配置健康检查和服务发现。来看看它们在实践中是什么样的。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-mongodb-efcore-data-lake/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Aspire 13.2 刚刚发布，带来了&lt;a href="https://devblogs.microsoft.com/aspire/aspire-new-database-integrations/"&gt;两个新的数据库集成&lt;/a&gt;，值得关注：MongoDB Entity Framework Core 和 Azure Data Lake Storage。如果你一直想在 Aspire 应用中使用 EF Core 操作 MongoDB，或者需要将 Data Lake 工作负载与服务发现连接起来，这个版本同时满足了这两个需求。&lt;/p&gt;
&lt;h2 id="mongodb-在-aspire-中遇见-ef-core"&gt;MongoDB 在 Aspire 中遇见 EF Core&lt;/h2&gt;
&lt;p&gt;这是让我最兴奋的一个。Aspire 支持 MongoDB 已经有一段时间了，但一直是原始驱动程序——没有 EF Core，没有 &lt;code&gt;DbContext&lt;/code&gt;，没有对文档的 LINQ 查询。现在你可以获得完整的 EF Core 体验配合 MongoDB，加上 Aspire 的自动健康检查和服务发现。&lt;/p&gt;
&lt;p&gt;配置遵循典型的 Aspire 模式。在你的 AppHost 中：&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mongodb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddMongoDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;mongodb&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;WithDataVolume&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;WithLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerLifetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Persistent&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApiService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;api&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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mongodb&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;然后在消费项目中，添加 EF Core 集成：&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 Aspire.MongoDB.EntityFrameworkCore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注册你的 &lt;code&gt;DbContext&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="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddMongoDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;mongodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;mydb&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;接下来就是标准的 EF Core 了。定义你的实体，像使用其他任何提供程序一样使用 &lt;code&gt;DbContext&lt;/code&gt;。集成会在后台处理连接池、OpenTelemetry 跟踪和健康检查。&lt;/p&gt;
&lt;p&gt;对于那些一直使用原始驱动程序操作 MongoDB 并手动配置连接字符串的 .NET 开发者来说，这是一个很好的体验提升。你可以获得完整的 EF Core 抽象，同时不会失去 Aspire 的服务发现。&lt;/p&gt;
&lt;h2 id="azure-data-lake-storage-加入阵营"&gt;Azure Data Lake Storage 加入阵营&lt;/h2&gt;
&lt;p&gt;第二个重大新增是 &lt;a href="https://aspire.dev/integrations/cloud/azure/azure-storage-datalake/"&gt;Azure Data Lake Storage (ADLS) 集成&lt;/a&gt;。如果你正在构建数据管道、ETL 流程或分析平台，现在可以像连接其他 Aspire 依赖项一样连接 Data Lake 资源。&lt;/p&gt;
&lt;p&gt;在 AppHost 中：&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAzureStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;azure-storage&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dataLake&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDataLake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fileSystem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDataLakeFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake-file-system&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;analyticsService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnalyticsService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;analytics&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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataLake&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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileSystem&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;/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;AddAzureDataLakeServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAzureDataLakeFileSystemClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake-file-system&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;不需要手动管理连接字符串，不需要四处寻找凭据。Aspire 负责资源的预配和注入。对于我们这些构建同时涉及运营数据和分析工作负载的云原生 .NET 应用的人来说，这让 Data Lake 在 Aspire 模型中真正成为了一等公民。&lt;/p&gt;
&lt;h2 id="值得关注的小修复"&gt;值得关注的小修复&lt;/h2&gt;
&lt;p&gt;除了主要功能之外，还有一些值得一提的改进：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MongoDB 连接字符串修复&lt;/strong&gt; — 数据库名称前的斜杠现在可以正确处理了。如果你之前有临时解决方案，现在可以移除了&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Server 导出&lt;/strong&gt; — &lt;code&gt;Aspire.Hosting.SqlServer&lt;/code&gt; 现在导出额外的服务器配置选项，提供更精细的控制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模拟器更新&lt;/strong&gt; — ServiceBus 模拟器 2.0.0、App Configuration 模拟器 1.0.2，CosmosDB 的预览模拟器现在包含就绪检查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Managed Redis&lt;/strong&gt; — 现在默认使用 &lt;code&gt;rediss://&lt;/code&gt;（Redis Secure），连接开箱即加密&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一点虽然不起眼但很重要——默认加密的 Redis 意味着生产环境中少了一项需要配置的东西。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Aspire 13.2 是一个增量版本，但 MongoDB EF Core 和 Data Lake 集成填补了真实的空白。如果你一直在等待 Aspire 中 MongoDB 的正式 EF Core 支持，或者需要 Data Lake 成为一等依赖项，&lt;a href="https://get.aspire.dev"&gt;升级到 13.2&lt;/a&gt; 试试看吧。&lt;code&gt;aspire add&lt;/code&gt; 命令会为你生成所需的一切。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://aspire.dev/whats-new/aspire-13-2/#-integrations-updates"&gt;完整的发行说明&lt;/a&gt;了解更多详情，查看&lt;a href="https://aspire.dev/integrations/gallery/"&gt;集成库&lt;/a&gt;获取完整列表。&lt;/p&gt;</content:encoded></item><item><title>azd update — 一个命令搞定所有包管理器</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-update-universal-upgrade-command/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-update-universal-upgrade-command/</guid><description>Azure Developer CLI 现在有了一个通用的更新命令，无论你是通过 winget、Homebrew、Chocolatey 还是安装脚本安装的，都能正常工作。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-update-universal-upgrade-command/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你知道那个每隔几周就会弹出来的&amp;quot;azd 有新版本可用&amp;quot;提示吗？就是那个你总是忽略掉的，因为你根本想不起来当初是用 winget、Homebrew 还是半年前跑的那个 curl 脚本安装的 &lt;code&gt;azd&lt;/code&gt;。好了，这个问题终于解决了。&lt;/p&gt;
&lt;p&gt;Microsoft 刚刚发布了 &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-update/"&gt;&lt;code&gt;azd update&lt;/code&gt;&lt;/a&gt; — 一个命令就能将 Azure Developer CLI 更新到最新版本，不管你最初是怎么安装的。Windows、macOS、Linux — 都一样。就一个命令。&lt;/p&gt;
&lt;h2 id="工作原理"&gt;工作原理&lt;/h2&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;azd update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就这么简单。如果你想提前体验新功能，可以切换到每日 Insiders 构建：&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;azd update --channel daily
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd update --channel stable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个命令会自动检测你当前的安装方式，并在后台使用对应的更新机制。再也不用纠结&amp;quot;等等，这台机器上我用的是 winget 还是 choco 来着？&amp;quot;&lt;/p&gt;
&lt;h2 id="一个小前提"&gt;一个小前提&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd update&lt;/code&gt; 从版本 1.23.x 开始提供。如果你用的是更早的版本，需要用原来的安装方式做最后一次手动更新。之后，&lt;code&gt;azd update&lt;/code&gt; 就能接管一切了。&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;azd version&lt;/code&gt; 查看你当前的版本。如果需要全新安装，&lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd"&gt;安装文档&lt;/a&gt; 可以帮到你。&lt;/p&gt;
&lt;h2 id="为什么这很重要"&gt;为什么这很重要&lt;/h2&gt;
&lt;p&gt;这是一个小小的生活质量改善，但对于我们这些每天都在用 &lt;code&gt;azd&lt;/code&gt; 把 AI Agent 和 Aspire 应用部署到 Azure 的人来说，保持最新意味着更少的&amp;quot;这个 bug 在最新版本里已经修复了&amp;quot;的尴尬时刻。少操心一件事。&lt;/p&gt;
&lt;p&gt;阅读 &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-update/"&gt;完整公告&lt;/a&gt; 和 Jon Gallant 的 &lt;a href="https://blog.jongallant.com/2026/04/azd-update"&gt;深入分析&lt;/a&gt; 了解更多。&lt;/p&gt;</content:encoded></item><item><title>Azure DevOps Server 2026年4月补丁 — PR完成修复和安全更新</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-server-april-2026-patch/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-server-april-2026-patch/</guid><description>Azure DevOps Server 发布补丁3，修复了PR完成失败问题，改进了注销验证，并恢复了GitHub Enterprise Server PAT连接。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-server-april-2026-patch/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给运行自托管Azure DevOps Server的团队快速提个醒：Microsoft发布了&lt;a href="https://devblogs.microsoft.com/devops/april-patches-for-azure-devops-server/"&gt;2026年4月补丁3&lt;/a&gt;，包含三个针对性修复。&lt;/p&gt;
&lt;h2 id="修复内容"&gt;修复内容&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull Request完成失败&lt;/strong&gt; — 工作项自动完成期间的空引用异常可能导致PR合并失败。如果你遇到过随机的PR完成错误，这很可能就是原因&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注销重定向验证&lt;/strong&gt; — 改进了注销期间的验证，以防止潜在的恶意重定向。这是一个值得尽快应用的安全修复&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Enterprise Server PAT连接&lt;/strong&gt; — 创建到GitHub Enterprise Server的Personal Access Token连接之前无法正常工作，现在已恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="如何更新"&gt;如何更新&lt;/h2&gt;
&lt;p&gt;下载&lt;a href="https://aka.ms/devopsserverpatch3"&gt;补丁3&lt;/a&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;&amp;lt;patch-installer&amp;gt;.exe CheckInstall
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你在本地运行Azure DevOps Server，Microsoft强烈建议保持最新补丁，以确保安全性和可靠性。查看&lt;a href="https://learn.microsoft.com/azure/devops/server/release-notes/azuredevopsserver?view=azure-devops#azure-devops-server-patch-3-release-date-april-14-2026"&gt;发行说明&lt;/a&gt;了解完整详情。&lt;/p&gt;</content:encoded></item><item><title>Azure Smart Tier 正式发布 — 无需生命周期规则即可自动优化 Blob Storage 成本</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-smart-tier-blob-storage-ga/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-smart-tier-blob-storage-ga/</guid><description>Azure Blob Storage smart tier 现已正式发布，根据实际访问模式自动在 hot、cool 和 cold 层之间移动对象 — 无需生命周期规则。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-smart-tier-blob-storage-ga/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你曾经花时间调整 Azure Blob Storage 的生命周期策略，然后看着它们在访问模式变化时土崩瓦解，那这篇文章就是为你准备的。微软刚刚宣布了 Azure Blob 和 Data Lake Storage 的 &lt;a href="https://azure.microsoft.com/en-us/blog/optimize-object-storage-costs-automatically-with-smart-tier-now-generally-available/"&gt;smart tier 正式发布&lt;/a&gt; — 这是一项完全托管的分层功能，根据实际使用情况自动在 hot、cool 和 cold 层之间移动对象。&lt;/p&gt;
&lt;h2 id="smart-tier-实际做了什么"&gt;Smart tier 实际做了什么&lt;/h2&gt;
&lt;p&gt;概念很简单：smart tier 持续评估存储账户中每个对象的最后访问时间。频繁访问的数据保持在 hot 层，不活跃的数据在 30 天后移到 cool 层，再过 60 天移到 cold 层。当数据被再次访问时，立即提升回 hot 层。循环重新开始。&lt;/p&gt;
&lt;p&gt;无需配置生命周期规则。无需预测访问模式。无需手动调优。&lt;/p&gt;
&lt;p&gt;在预览期间，微软报告称 &lt;strong&gt;超过 50% 的 smart tier 管理容量根据实际访问模式自动转移到了更冷的层级&lt;/strong&gt;。对于大型存储账户来说，这是一笔可观的成本节省。&lt;/p&gt;
&lt;h2 id="为什么这对-net-开发者很重要"&gt;为什么这对 .NET 开发者很重要&lt;/h2&gt;
&lt;p&gt;如果你正在构建生成日志、遥测数据、分析数据或任何类型的不断增长的数据资产的应用 — 说实话，谁不是呢 — 存储成本会很快累积起来。传统的做法是编写生命周期管理策略，测试它们，然后在应用的访问模式变化时重新调整。Smart tier 完全消除了这个工作流。&lt;/p&gt;
&lt;p&gt;一些实用的场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;应用遥测和日志&lt;/strong&gt; — 调试时是 hot，几周后几乎不再访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据管道和 ETL 输出&lt;/strong&gt; — 处理期间频繁访问，之后大多处于 cold 状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户生成内容&lt;/strong&gt; — 最近上传的是 hot，较老的内容逐渐变冷&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;备份和归档数据&lt;/strong&gt; — 偶尔因合规需要访问，大部分时间处于闲置状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="如何设置"&gt;如何设置&lt;/h2&gt;
&lt;p&gt;启用 smart tier 是一次性配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;新账户&lt;/strong&gt;：在创建存储账户时选择 smart tier 作为默认访问层（需要区域冗余）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现有账户&lt;/strong&gt;：将 blob 访问层从当前默认值切换到 smart tier&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;小于 128 KiB 的对象保持在 hot 层，不产生监控费用。其他所有对象按照标准 hot/cool/cold 容量费率计费，没有层级转换费用，没有提前删除罚金，没有数据检索成本。每个对象的月度监控费用涵盖编排服务。&lt;/p&gt;
&lt;h2 id="需要了解的权衡"&gt;需要了解的权衡&lt;/h2&gt;
&lt;p&gt;Smart tier 的分层规则是固定的（30 天 → cool，90 天 → cold）。如果你需要自定义阈值 — 比如某个特定工作负载在 7 天后移到 cool — 生命周期规则仍然是正确的选择。而且不要混用：避免对 smart tier 管理的对象使用生命周期规则，因为它们可能会产生冲突。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;这算不上革命性的改变，但它解决了一个实实在在的运维痛点。如果你管理着不断增长的 blob storage 账户，并且厌倦了维护生命周期策略，&lt;a href="https://learn.microsoft.com/en-us/azure/storage/blobs/access-tiers-smart"&gt;启用 smart tier&lt;/a&gt; 让 Azure 来处理吧。目前在几乎所有区域公有云区域都可以使用。&lt;/p&gt;</content:encoded></item><item><title>Azure上のAIエージェントはどこにホストすべき？実践的な判断ガイド</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-ai-agent-hosting-options-guide/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-ai-agent-hosting-options-guide/</guid><description>Azure提供六种托管AI代理的方式——从原始容器到完全托管的Foundry Hosted Agents。以下是如何为你的.NET工作负载选择合适方案。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-ai-agent-hosting-options-guide/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你现在正在用.NET构建AI代理，你可能已经注意到一件事：在Azure上托管它们的方式&lt;em&gt;太多了&lt;/em&gt;。Container Apps、AKS、Functions、App Service、Foundry Agents、Foundry Hosted Agents——在你真正需要选择之前，每个都听起来合理。Microsoft刚刚发布了一份&lt;a href="https://devblogs.microsoft.com/all-things-azure/hostedagent/"&gt;Azure AI代理托管综合指南&lt;/a&gt;来澄清这个问题，我想从.NET开发者的实践角度来拆解它。&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;th&gt;你需要管理&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container Apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;无需K8s复杂性的完整容器控制&lt;/td&gt;
&lt;td&gt;可观测性、状态、生命周期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AKS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;企业合规、多集群、自定义网络&lt;/td&gt;
&lt;td&gt;所有东西（这就是重点）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Azure Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;事件驱动的短时代理任务&lt;/td&gt;
&lt;td&gt;几乎不需要——真正的无服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;简单的HTTP代理、可预测的流量&lt;/td&gt;
&lt;td&gt;部署、扩展配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foundry Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;通过门户/SDK的无代码代理&lt;/td&gt;
&lt;td&gt;几乎不需要&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foundry Hosted Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;托管基础设施上的自定义框架代理&lt;/td&gt;
&lt;td&gt;仅你的代理代码&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;前四个是通用计算——你&lt;em&gt;可以&lt;/em&gt;在上面运行代理，但它们不是为此设计的。最后两个是代理原生的：它们将对话、工具调用和代理生命周期理解为一等概念。&lt;/p&gt;
&lt;h2 id="foundry-hosted-agentsnet代理开发者的最佳选择"&gt;Foundry Hosted Agents——.NET代理开发者的最佳选择&lt;/h2&gt;
&lt;p&gt;这是引起我注意的地方。Foundry Hosted Agents正好处于中间位置：你获得运行自己代码的灵活性（Semantic Kernel、Agent Framework、LangGraph——随便什么），但平台处理基础设施、可观测性和对话管理。&lt;/p&gt;
&lt;p&gt;关键部分是&lt;strong&gt;Hosting Adapter&lt;/strong&gt;——一个将你的代理框架连接到Foundry平台的薄抽象层。对于Microsoft Agent Framework，看起来是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.agentserver.agentframework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;from_agent_framework&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="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatAgent&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;chat_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AzureAIAgentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&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;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_local_time&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&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;from_agent_framework&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&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;这就是你的整个托管方案。适配器自动处理协议转换、通过server-sent events的流式传输、对话历史和OpenTelemetry追踪。不需要自定义中间件，不需要手动配置。&lt;/p&gt;
&lt;h2 id="部署真的很简单"&gt;部署真的很简单&lt;/h2&gt;
&lt;p&gt;我以前在Container Apps上部署过代理，虽然可以工作，但最后你会写很多胶水代码来处理状态管理和可观测性。使用Hosted Agents和&lt;code&gt;azd&lt;/code&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;&lt;span class="c1"&gt;# 安装AI代理扩展&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ext install azure.ai.agents
&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="c1"&gt;# 从模板初始化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ai agent init
&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="c1"&gt;# 构建、推送、部署——完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个单独的&lt;code&gt;azd up&lt;/code&gt;会构建你的容器、推送到ACR、配置Foundry项目、部署模型端点并启动你的代理。五个步骤压缩成一个命令。&lt;/p&gt;
&lt;h2 id="内置对话管理"&gt;内置对话管理&lt;/h2&gt;
&lt;p&gt;这是在生产中节省最多时间的部分。不需要构建自己的对话状态存储，Hosted Agents原生处理：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&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="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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="c1"&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;response1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&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;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MyAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&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="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Remember: my favorite number is 42.&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&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="n"&gt;response2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&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;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MyAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&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="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Multiply my favorite number by 10.&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;不需要Redis。不需要Cosmos DB会话存储。不需要自定义中间件来序列化消息。平台直接处理了。&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;需要零基础设施？&lt;/strong&gt; → Foundry Agents（门户/SDK，无容器）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有自定义代理代码但想要托管主机？&lt;/strong&gt; → Foundry Hosted Agents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要事件驱动的短期代理任务？&lt;/strong&gt; → Azure Functions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要不用K8s的最大容器控制？&lt;/strong&gt; → Container Apps&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要严格合规和多集群？&lt;/strong&gt; → AKS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有流量可预测的简单HTTP代理？&lt;/strong&gt; → App Service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于大多数使用Semantic Kernel或Microsoft Agent Framework构建的.NET开发者来说，Hosted Agents可能是正确的起点。你能获得scale-to-zero、内置OpenTelemetry、对话管理和框架灵活性——无需管理Kubernetes或搭建自己的可观测性栈。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Azure上的代理托管格局正在快速成熟。如果你今天要开始一个新的AI代理项目，我会在习惯性地使用Container Apps或AKS之前认真考虑Foundry Hosted Agents。托管基础设施节省实际时间，而hosting adapter模式让你保留框架选择。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/all-things-azure/hostedagent/"&gt;Microsoft的完整指南&lt;/a&gt;和&lt;a href="https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents"&gt;Foundry Samples仓库&lt;/a&gt;获取可运行的示例。&lt;/p&gt;</content:encoded></item><item><title>.NET的Agent Skills变得真正灵活了</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-skills-dotnet-three-authoring-patterns/</link><pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-skills-dotnet-three-authoring-patterns/</guid><description>Microsoft Agent Framework现在支持三种创建技能的方式——文件、类和内联代码——全部通过单一provider组合。这篇文章解释为什么这很重要以及如何使用每种方式。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-skills-dotnet-three-authoring-patterns/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你一直在用Microsoft Agent Framework构建代理，那你已经熟悉流程了：定义技能，连接到provider，让代理决定调用哪个。新的是你&lt;em&gt;如何&lt;/em&gt;创建这些技能——灵活性的提升非常显著。&lt;/p&gt;
&lt;p&gt;最新更新引入了三种agent skill编写模式：&lt;strong&gt;基于文件的&lt;/strong&gt;、&lt;strong&gt;基于类的&lt;/strong&gt;和&lt;strong&gt;内联代码定义的&lt;/strong&gt;。三种都连接到单一的 &lt;code&gt;AgentSkillsProviderBuilder&lt;/code&gt;，意味着你可以自由混搭，无需路由逻辑或特殊粘合代码。让我带你了解每种模式以及何时使用。&lt;/p&gt;
&lt;h2 id="基于文件的技能起点"&gt;基于文件的技能：起点&lt;/h2&gt;
&lt;p&gt;基于文件的技能顾名思义——磁盘上的一个目录，包含 &lt;code&gt;SKILL.md&lt;/code&gt; 文件、可选脚本和参考文档。给代理添加新能力最直接的方式：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;skills/
└── onboarding-guide/
├── SKILL.md
├── scripts/
│ └── check-provisioning.py
└── references/
└── onboarding-checklist.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 的frontmatter声明技能名称和描述，指令部分告诉代理如何使用脚本和参考：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&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;name: onboarding-guide
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;description: &amp;gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Walk new hires through their first-week setup checklist.
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Instructions
&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="k"&gt;1.&lt;/span&gt; Ask for the employee&amp;#39;s name and start date.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; Run &lt;span class="sb"&gt;`scripts/check-provisioning.py`&lt;/span&gt; to verify accounts.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;3.&lt;/span&gt; Walk through &lt;span class="sb"&gt;`references/onboarding-checklist.md`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;4.&lt;/span&gt; Follow up on incomplete items.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后用 &lt;code&gt;SubprocessScriptRunner.RunAsync&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProvider&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;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&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;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&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="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&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;GetResponsesClient&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;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatClientAgentOptions&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;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;HRAgent&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;ChatOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are a helpful HR assistant.&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;AIContextProviders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;skillsProvider&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="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deploymentName&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;/p&gt;
&lt;h2 id="基于类的技能通过nuget分发"&gt;基于类的技能：通过NuGet分发&lt;/h2&gt;
&lt;p&gt;这里对团队来说变得有趣了。基于类的技能继承自 &lt;code&gt;AgentClassSkill&amp;lt;T&amp;gt;&lt;/code&gt; 并使用 &lt;code&gt;[AgentSkillResource]&lt;/code&gt; 和 &lt;code&gt;[AgentSkillScript]&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="kd"&gt;public&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;BenefitsEnrollmentSkill&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentClassSkill&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenefitsEnrollmentSkill&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="n"&gt;AgentSkillFrontmatter&lt;/span&gt; &lt;span class="n"&gt;Frontmatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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="s"&gt;&amp;#34;benefits-enrollment&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="s"&gt;&amp;#34;Enroll an employee in health, dental, or vision plans.&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;plans&lt;/span&gt; &lt;span class="n"&gt;resource&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="m"&gt;2.&lt;/span&gt; &lt;span class="n"&gt;Confirm&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="n"&gt;wants&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="m"&gt;3.&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;enroll&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="n"&gt;enrollment&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="s"&gt;&amp;#34;&amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&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; [AgentSkillResource(&amp;#34;available-plans&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Description(&amp;#34;Plan options with monthly pricing.&amp;#34;)]&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;AvailablePlans&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;##&lt;/span&gt; &lt;span class="n"&gt;Available&lt;/span&gt; &lt;span class="n"&gt;Plans&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2026&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;Health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Basic&lt;/span&gt; &lt;span class="n"&gt;HMO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Premium&lt;/span&gt; &lt;span class="n"&gt;PPO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&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;Dental&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Standard&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Enhanced&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&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;Vision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Basic&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&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="s"&gt;&amp;#34;&amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&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; [AgentSkillScript(&amp;#34;enroll&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Description(&amp;#34;Enrolls employee in the specified benefit plan.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Enroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;planCode&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="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnrollInPlan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planCode&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planCode&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;妙处在于团队可以将其打包为NuGet包。你添加到项目中，放入builder，它就能和基于文件的技能一起工作，无需协调：&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&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;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&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;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&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;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&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;Build&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;/p&gt;
&lt;h2 id="内联技能快速桥接"&gt;内联技能：快速桥接&lt;/h2&gt;
&lt;p&gt;你知道那个时刻吗，另一个团队正在构建你需要的技能，但要到下个sprint才能完成？&lt;code&gt;AgentInlineSkill&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timeOffSkill&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentInlineSkill&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;time-off-balance&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;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Calculate remaining vacation and sick days.&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;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;Ask&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;provided&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="m"&gt;2.&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="n"&gt;balance&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="m"&gt;3.&lt;/span&gt; &lt;span class="n"&gt;Present&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="n"&gt;clearly&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="s"&gt;&amp;#34;&amp;#34;&amp;#34;)
&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;AddScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;calculate-balance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;)&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAnnualAllowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;daysUsed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetDaysUsed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;daysUsed&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daysUsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remaining&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;和其他技能一样添加到builder：&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&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;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&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;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&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;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeOffSkill&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;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&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;Build&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;当NuGet包最终发布时，你只需将内联技能替换为基于类的版本。代理不会注意到区别。&lt;/p&gt;
&lt;p&gt;但内联技能不仅仅用于桥接。当你需要在运行时动态生成技能——想想从配置加载的每个业务单元一个技能——或者当脚本需要捕获不属于DI容器的本地状态时，它们也是正确的选择。&lt;/p&gt;
&lt;h2 id="脚本审批人在回路中"&gt;脚本审批：人在回路中&lt;/h2&gt;
&lt;p&gt;对我们构建生产代理的.NET开发者来说，这是真正打开部署讨论的部分。有些脚本有实际后果——给某人注册福利、查询生产基础设施。开启 &lt;code&gt;UseScriptApproval&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&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;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&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;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&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;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeOffSkill&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;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&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;UseScriptApproval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;Build&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;当代理想执行脚本时，它会返回一个审批请求。你的应用收集决定——批准或拒绝——代理相应继续。在受监管的环境中，这就是&amp;quot;我们可以部署这个&amp;quot;和&amp;quot;法务说不行&amp;quot;之间的区别。&lt;/p&gt;
&lt;h2 id="为什么这种组合很重要"&gt;为什么这种组合很重要&lt;/h2&gt;
&lt;p&gt;真正的力量不在于任何单一模式——而在于组合。你可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用基于文件的技能&lt;strong&gt;从小处开始&lt;/strong&gt;，迭代指令，不写C#就能发布&lt;/li&gt;
&lt;li&gt;将&lt;strong&gt;可复用的技能&lt;/strong&gt;作为NuGet包分发，其他团队一行代码就能添加&lt;/li&gt;
&lt;li&gt;当&lt;em&gt;现在&lt;/em&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;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一切都通过 &lt;code&gt;AgentSkillsProviderBuilder&lt;/code&gt; 组合。没有特殊路由，没有条件逻辑，没有技能类型检查。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;.NET中的agent skills现在拥有了真正灵活的编写模型。无论你是用基于文件的技能做原型的独立开发者，还是通过NuGet分发打包能力的企业团队，这些模式都能适配。脚本审批机制使其在需要人工检查点的环境中也能投入生产。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/agent-framework/agent-skills-in-net-three-ways-to-author-one-provider-to-run-them/"&gt;原始公告&lt;/a&gt;、Microsoft Learn上的&lt;a href="https://learn.microsoft.com/en-us/agent-framework/agents/skills"&gt;Agent Skills文档&lt;/a&gt;和GitHub上的&lt;a href="https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/02-agents/AgentSkills"&gt;.NET示例&lt;/a&gt;开始动手吧。&lt;/p&gt;</content:encoded></item><item><title>Azure MCP Server 2.0 正式发布——自托管智能云自动化来了</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-2-self-hosted-agentic-cloud/</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-2-self-hosted-agentic-cloud/</guid><description>Azure MCP Server 2.0 稳定版发布，支持自托管远程部署、57 个 Azure 服务中的 276 个工具，以及企业级安全性——这是 .NET 开发者构建智能工作流需要了解的内容。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文为自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-mcp-server-2-self-hosted-agentic-cloud/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;如果你最近一直在用 MCP 和 Azure 构建东西，你可能已经知道本地体验非常好。接入一个 MCP 服务器，让你的 AI 智能体与 Azure 资源对话，然后继续工作。但一旦你需要在团队中共享这个设置？那就会变得复杂。&lt;/p&gt;
&lt;p&gt;不再是这样了。Azure MCP Server &lt;a href="https://devblogs.microsoft.com/azure-sdk/announcing-azure-mcp-server-2-0-stable-release/"&gt;刚刚发布 2.0 稳定版&lt;/a&gt;，而主打功能正是企业团队一直在要求的：&lt;strong&gt;自托管远程 MCP 服务器支持&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="什么是-azure-mcp-server"&gt;什么是 Azure MCP Server？&lt;/h2&gt;
&lt;p&gt;快速回顾一下。Azure MCP Server 实现了 &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro"&gt;Model Context Protocol&lt;/a&gt; 规范，并将 Azure 功能暴露为结构化、可发现的工具，AI 智能体可以调用。把它看作是你的智能体和 Azure 之间的标准化桥梁——配置、部署、监控、诊断，都通过一个统一的接口。&lt;/p&gt;
&lt;p&gt;这些数字说明一切：&lt;strong&gt;跨越 57 个 Azure 服务的 276 个 MCP 工具&lt;/strong&gt;。这是真正的覆盖范围。&lt;/p&gt;
&lt;h2 id="重大突破自托管远程部署"&gt;重大突破：自托管远程部署&lt;/h2&gt;
&lt;p&gt;关键是这样的。在你的本地机器上运行 MCP 对于开发和实验来说没问题。但在真实的团队场景中，你需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发者和内部智能体系统的共享访问&lt;/li&gt;
&lt;li&gt;集中化配置（租户上下文、订阅默认值、遥测）&lt;/li&gt;
&lt;li&gt;企业网络和策略边界&lt;/li&gt;
&lt;li&gt;与 CI/CD 流程的集成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Azure MCP Server 2.0 解决了所有这些问题。你可以将其部署为一个集中管理的内部服务，具有基于 HTTP 的传输、适当的身份验证和一致的治理。&lt;/p&gt;
&lt;p&gt;对于身份验证，你有两个不错的选择：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;托管标识&lt;/strong&gt;——在 &lt;a href="https://aka.ms/azmcp/self-host/foundry"&gt;Microsoft Foundry&lt;/a&gt; 旁边运行时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代表流 (OBO 流)&lt;/strong&gt;——OpenID Connect 委托，使用已登录用户的上下文调用 Azure API&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于我们 .NET 开发者来说，OBO 流特别有趣。这意味着你的智能工作流可以使用用户的实际权限运行，而不是某个过度特权的服务账户。最小权限原则，内置其中。&lt;/p&gt;
&lt;h2 id="安全加固"&gt;安全加固&lt;/h2&gt;
&lt;p&gt;这不仅仅是一个功能发布——它也是一个安全发布。2.0 版本添加了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更强的端点验证&lt;/li&gt;
&lt;li&gt;针对面向查询工具中注入模式的保护&lt;/li&gt;
&lt;li&gt;更严格的开发环境隔离控制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你要将 MCP 暴露为共享服务，这些保障措施很重要。非常重要。&lt;/p&gt;
&lt;h2 id="你可以在哪里使用它"&gt;你可以在哪里使用它？&lt;/h2&gt;
&lt;p&gt;客户端兼容性范围很广。Azure MCP Server 2.0 可与以下配合使用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IDE&lt;/strong&gt;：VS Code、Visual Studio、IntelliJ、Eclipse、Cursor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI 智能体&lt;/strong&gt;：GitHub Copilot CLI、Claude Code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立版&lt;/strong&gt;：用于简单设置的本地服务器&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自托管远程&lt;/strong&gt;：2.0 的新星&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，还有针对 Azure 美国政府版和由 21Vianet 运营的 Azure 的主权云支持，这对于受管制的部署至关重要。&lt;/p&gt;
&lt;h2 id="为什么这对-net-开发者很重要"&gt;为什么这对 .NET 开发者很重要&lt;/h2&gt;
&lt;p&gt;如果你使用 .NET 构建智能应用——无论是使用 Semantic Kernel、Microsoft Agent Framework，还是你自己的编排——Azure MCP Server 2.0 让你能够以生产级的方式让你的智能体与 Azure 基础设施交互。没有自定义 REST 包装。没有服务特定的集成模式。只是 MCP。&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;MCP 应用流畅 API&lt;/a&gt;，.NET MCP 生态系统正在快速成熟。&lt;/p&gt;
&lt;h2 id="开始使用"&gt;开始使用&lt;/h2&gt;
&lt;p&gt;选择你的路径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp"&gt;GitHub 仓库&lt;/a&gt;&lt;/strong&gt;——源代码、文档，一切&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/download/docker"&gt;Docker 镜像&lt;/a&gt;&lt;/strong&gt;——容器化部署&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/download/vscode"&gt;VS Code 扩展&lt;/a&gt;&lt;/strong&gt;——IDE 集成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/self-host"&gt;自托管指南&lt;/a&gt;&lt;/strong&gt;——2.0 的旗舰功能&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Azure MCP Server 2.0 正是那种在演示中看起来不起眼但在实践中改变一切的基础设施升级。具有适当身份验证、安全加固和主权云支持的自托管远程 MCP 意味着 MCP 已为在 Azure 上构建真实智能工作流的真实团队做好准备。如果你一直在等待&amp;quot;企业就绪&amp;quot;的信号——就是现在。&lt;/p&gt;</content:encoded></item><item><title>.NET Aspire 13.2想成为你AI智能体的好朋友</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-agentic-development-build-run-observe/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-agentic-development-build-run-observe/</guid><description>Aspire 13.2全力投入智能体开发 — 结构化CLI输出、隔离运行、自愈环境以及完整的OpenTelemetry数据，让你的AI智能体能够真正构建、运行和观察你的应用。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-agentic-development-build-run-observe/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你知道那种感觉吗？你的AI编码智能体写出了不错的代码，你很兴奋，然后当它试图&lt;em&gt;运行&lt;/em&gt;这个东西时一切都崩溃了？端口冲突、幽灵进程、错误的环境变量 — 突然你的智能体在排查启动问题上烧掉了大量token，而不是构建功能。&lt;/p&gt;
&lt;p&gt;Aspire团队刚刚发布了一篇关于这个问题的&lt;a href="https://devblogs.microsoft.com/aspire/agentic-dev-aspirations/"&gt;深思熟虑的文章&lt;/a&gt;，他们的答案很有说服力：Aspire 13.2的设计不仅面向人类，更面向AI智能体。&lt;/p&gt;
&lt;h2 id="问题是真实存在的"&gt;问题是真实存在的&lt;/h2&gt;
&lt;p&gt;AI智能体在写代码方面令人难以置信。但交付一个可工作的全栈应用涉及的远不止生成文件。你需要按正确的顺序启动服务、管理端口、设置环境变量、连接数据库，以及在出问题时获得反馈。目前，大多数智能体通过试错来处理所有这些 — 运行命令、读取错误输出、再试一次。&lt;/p&gt;
&lt;p&gt;我们叠加Markdown指令、自定义技能和提示来引导它们，但这些是不可预测的，无法编译，而且仅仅解析就要消耗token。Aspire团队抓住了核心洞察：智能体需要&lt;strong&gt;编译器和结构化API&lt;/strong&gt;，而不是更多的Markdown。&lt;/p&gt;
&lt;h2 id="aspire作为智能体基础设施"&gt;Aspire作为智能体基础设施&lt;/h2&gt;
&lt;p&gt;以下是Aspire 13.2为智能体开发带来的内容：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;整个技术栈用类型化代码描述。&lt;/strong&gt; AppHost用可编译的TypeScript或C#定义你的完整拓扑 — API、前端、数据库、缓存：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBuilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;./.modules/aspire.js&amp;#39;&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;createBuilder&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postgres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addPostgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;catalog&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cache&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&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="nx"&gt;addNodeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;src/index.ts&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="nx"&gt;withHttpEndpoint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PORT&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="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postgres&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="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&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="nx"&gt;addViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./frontend&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="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&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="nx"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;run&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;em&gt;通过构建来验证&lt;/em&gt;。编译器会立即告诉它哪里出了问题。不需要猜测，不需要在配置文件上反复试错。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个命令统治所有。&lt;/strong&gt; 智能体不再需要在&lt;code&gt;docker compose up&lt;/code&gt;、&lt;code&gt;npm run dev&lt;/code&gt;和数据库启动脚本之间来回切换，一切只需&lt;code&gt;aspire start&lt;/code&gt;。所有资源按正确顺序、在正确的端口、用正确的配置启动。长时间运行的进程也不会挂起智能体 — Aspire负责管理它们。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;并行智能体的隔离模式。&lt;/strong&gt; 使用&lt;code&gt;--isolated&lt;/code&gt;，每次Aspire运行都会获得自己的随机端口和独立的用户密钥。多个智能体在git worktree中工作？它们不会冲突。这对于VS Code的后台智能体等创建并行环境的工具来说意义重大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通过遥测赋予智能体视野。&lt;/strong&gt; 这是真正强大的地方。Aspire CLI在开发期间暴露完整的OpenTelemetry数据 — 追踪、指标、结构化日志。你的智能体不是只读控制台输出然后祈祷一切顺利。它可以跨服务追踪失败的请求、分析慢端点，并精确定位问题所在。这是开发循环中的生产级可观察性。&lt;/p&gt;
&lt;h2 id="保龄球护栏类比"&gt;保龄球护栏类比&lt;/h2&gt;
&lt;p&gt;Aspire团队用了一个很棒的类比：把Aspire想象成AI智能体的保龄球道护栏。如果智能体不够完美（它确实不会完美），护栏会防止它打出沟球。技术栈定义防止配置错误，编译器捕获错误，CLI处理进程管理，遥测提供反馈循环。&lt;/p&gt;
&lt;p&gt;将此与Playwright CLI之类的工具结合，你的智能体就可以真正&lt;em&gt;使用&lt;/em&gt;你的应用 — 点击流程、检查DOM、在遥测中发现问题、修复代码、重启并重新测试。构建、运行、观察、修复。这就是我们一直追求的自主开发循环。&lt;/p&gt;
&lt;h2 id="入门"&gt;入门&lt;/h2&gt;
&lt;p&gt;Aspire新手？从&lt;a href="https://get.aspire.dev"&gt;get.aspire.dev&lt;/a&gt;安装CLI并遵循&lt;a href="https://aspire.dev/get-started/first-app"&gt;入门指南&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;已经在使用Aspire？运行&lt;code&gt;aspire update --self&lt;/code&gt;获取13.2，然后将你最喜欢的编码智能体指向你的仓库。有了Aspire的护栏，你可能会惊讶于它能走多远。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Aspire 13.2不再仅仅是一个分布式应用框架 — 它正在成为必不可少的智能体基础设施。结构化的技术栈定义、一键启动、隔离的并行运行和实时遥测，为AI智能体提供了从编写代码到交付应用所需的一切。&lt;/p&gt;
&lt;p&gt;阅读Aspire团队的&lt;a href="https://devblogs.microsoft.com/aspire/agentic-dev-aspirations/"&gt;完整文章&lt;/a&gt;获取所有细节和演示视频。&lt;/p&gt;</content:encoded></item><item><title>Aspire的隔离模式解决了并行开发中端口冲突的噩梦</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-isolated-mode-parallel-instances/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-isolated-mode-parallel-instances/</guid><description>Aspire 13.2引入--isolated模式：随机端口、独立密钥，运行同一AppHost的多个实例时零冲突。完美适用于AI智能体、worktree和并行工作流。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-isolated-mode-parallel-instances/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你曾试过同时运行同一个项目的两个实例，你就知道那种痛苦。端口8080已被占用。端口17370已被使用。杀掉进程、重启、摆弄环境变量 — 这是生产力杀手。&lt;/p&gt;
&lt;p&gt;这个问题在变得更严重，而不是更好。AI智能体创建git worktree来独立工作。后台智能体启动独立环境。开发者为了功能分支两次checkout同一个仓库。每一个场景都撞上了同一堵墙：同一个应用的两个实例在争夺相同的端口。&lt;/p&gt;
&lt;p&gt;Aspire 13.2用一个flag就解决了这个问题。Aspire团队的James Newton-King&lt;a href="https://devblogs.microsoft.com/aspire/aspire-isolated-mode-parallel-development/"&gt;写了完整的细节&lt;/a&gt;，这是那种&amp;quot;我们怎么之前没有这个&amp;quot;的功能。&lt;/p&gt;
&lt;h2 id="解决方案--isolated"&gt;解决方案：&lt;code&gt;--isolated&lt;/code&gt;&lt;/h2&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;aspire run --isolated
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就这样。每次运行获得：&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; — 连接字符串和API密钥在每个实例间保持独立&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不需要手动重新分配端口。不需要摆弄环境变量。每次运行自动获得一个干净的、无冲突的环境。&lt;/p&gt;
&lt;h2 id="这个功能发光的真实场景"&gt;这个功能发光的真实场景&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;多次checkout。&lt;/strong&gt; 你有一个功能分支在一个目录，一个bugfix在另一个：&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;&lt;span class="c1"&gt;# Terminal 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/projects/my-app-feature
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire run --isolated
&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="c1"&gt;# Terminal 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/projects/my-app-bugfix
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire run --isolated
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;两个都无冲突运行。仪表盘显示什么在运行以及在哪里运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VS Code中的后台智能体。&lt;/strong&gt; 当Copilot Chat的后台智能体创建git worktree来独立处理你的代码时，它可能需要运行你的Aspire AppHost。没有&lt;code&gt;--isolated&lt;/code&gt;，这就会和你的主worktree产生端口冲突。有了它，两个实例就能正常运行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aspire agent init&lt;/code&gt;附带的Aspire技能会自动指导智能体在worktree中工作时使用&lt;code&gt;--isolated&lt;/code&gt;。所以Copilot的后台智能体应该能原生处理这个问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;开发同时运行集成测试。&lt;/strong&gt; 需要在继续开发功能的同时对活跃的AppHost运行测试？隔离模式给每个上下文提供独立的端口和配置。&lt;/p&gt;
&lt;h2 id="底层工作原理"&gt;底层工作原理&lt;/h2&gt;
&lt;p&gt;当你传递&lt;code&gt;--isolated&lt;/code&gt;时，CLI会为该运行生成一个唯一的实例ID。这驱动两个行为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;端口随机化&lt;/strong&gt; — 不再绑定到AppHost配置中定义的可预测端口，隔离模式为所有内容选择随机可用端口 — 仪表盘、服务端点，全部。服务发现自动调整，所以服务能找到彼此，不管它们落在哪个端口上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;密钥隔离&lt;/strong&gt; — 每个隔离运行获得自己的用户密钥存储，以实例ID为键。一次运行的连接字符串和API密钥不会泄露到另一次运行中。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你的代码不需要任何改动。Aspire的服务发现在运行时解析端点，所以不管端口分配如何，一切都能正确连接。&lt;/p&gt;
&lt;h2 id="何时使用"&gt;何时使用&lt;/h2&gt;
&lt;p&gt;当同时运行同一AppHost的多个实例时使用&lt;code&gt;--isolated&lt;/code&gt; — 无论是并行开发、自动化测试、AI智能体还是git worktree。对于偏好可预测端口的单实例开发，常规的&lt;code&gt;aspire run&lt;/code&gt;仍然可以正常使用。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;隔离模式是一个解决真实且越来越常见问题的小功能。随着AI辅助开发推动我们走向更多并行工作流 — 多个智能体、多个worktree、多个上下文 — 能够简单地启动另一个实例而不必争夺端口是必不可少的。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/aspire/aspire-isolated-mode-parallel-development/"&gt;完整文章&lt;/a&gt;获取所有技术细节，并用&lt;code&gt;aspire update --self&lt;/code&gt;获取13.2来试用。&lt;/p&gt;</content:encoded></item><item><title>GitHub Copilot 的现代化评估是你还没用上的最好迁移工具</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-modernization-assessment-github-copilot/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-modernization-assessment-github-copilot/</guid><description>GitHub Copilot 的现代化扩展不仅仅建议代码更改 — 它生成完整的迁移评估，包含可操作的问题、Azure 目标比较和协作工作流。以下是评估文档为何是一切关键的原因。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/dotnet-modernization-assessment-github-copilot/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;将传统 .NET Framework 应用迁移到现代 .NET 是那种每个人都知道应该做但没人想开始的任务。它从来不是简单的&amp;quot;更改目标框架&amp;quot;。而是消失的 API、不再存在的包、工作方式完全不同的托管模型，以及关于什么要容器化、什么要重写、什么要保持不变的无数小决策。&lt;/p&gt;
&lt;p&gt;Jeffrey Fritz 刚刚发布了一篇 &lt;a href="https://devblogs.microsoft.com/dotnet/your-migrations-source-of-truth-the-modernization-assessment/"&gt;GitHub Copilot 现代化评估的深入解析&lt;/a&gt;，说实话？这是我见过的 .NET 最好的迁移工具。不是因为代码生成 — 那现在已经是标配了。而是因为它生成的评估文档。&lt;/p&gt;
&lt;h2 id="它不仅仅是代码建议引擎"&gt;它不仅仅是代码建议引擎&lt;/h2&gt;
&lt;p&gt;VS Code 扩展遵循&lt;strong&gt;评估 → 计划 → 执行&lt;/strong&gt;模型。评估阶段分析你的整个代码库，生成一份结构化文档，捕获一切：什么需要更改、需要配置哪些 Azure 资源、使用什么部署模型。下游的一切 — 基础设施即代码、容器化、部署清单 — 都源自评估发现的内容。&lt;/p&gt;
&lt;p&gt;评估存储在项目的 &lt;code&gt;.github/modernize/assessment/&lt;/code&gt; 下。每次运行产生一份独立的报告，因此你可以积累历史记录，并在修复问题时跟踪迁移态势的演变。&lt;/p&gt;
&lt;h2 id="两种开始方式"&gt;两种开始方式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;推荐评估&lt;/strong&gt; — 快捷路径。从策划好的领域（Java/.NET 升级、云就绪、安全）中选择，无需配置即可获得有意义的结果。非常适合初次了解应用的状态。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自定义评估&lt;/strong&gt; — 定向路径。精确配置要分析的内容：目标计算（App Service、AKS、Container Apps）、目标操作系统、容器化分析。选择多个 Azure 目标来并排比较迁移方法。&lt;/p&gt;
&lt;p&gt;那个比较视图真的很有用。一个应用在 App Service 上可能有 3 个必须解决的问题，在 AKS 上可能有 7 个。看到两者有助于在确定迁移路径之前做出托管决策。&lt;/p&gt;
&lt;h2 id="问题分解是可操作的"&gt;问题分解是可操作的&lt;/h2&gt;
&lt;p&gt;每个问题都带有严重程度级别：&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; — 推荐的改进，不会阻止迁移&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个问题都链接到受影响的文件和行号，提供详细描述说明什么地方有问题以及为什么对目标平台重要，给出具体的修复步骤（不仅仅是&amp;quot;修复这个&amp;quot;），并包含官方文档链接。&lt;/p&gt;
&lt;p&gt;你可以将单个问题分配给开发者，他们拥有行动所需的一切。这就是告诉你&amp;quot;有个问题&amp;quot;的工具和告诉你如何解决的工具之间的区别。&lt;/p&gt;
&lt;h2 id="涵盖的升级路径"&gt;涵盖的升级路径&lt;/h2&gt;
&lt;p&gt;针对 .NET 具体来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET Framework → .NET 10&lt;/li&gt;
&lt;li&gt;ASP.NET → ASP.NET Core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每条升级路径都有检测规则，知道哪些 API 被移除、哪些模式没有直接等价物、哪些安全问题需要关注。&lt;/p&gt;
&lt;p&gt;对于管理多个应用的团队，还有一个 CLI 支持多仓库批量评估 — 克隆所有仓库，全部评估，获取每个应用的报告加上汇总的组合视图。&lt;/p&gt;
&lt;h2 id="我的看法"&gt;我的看法&lt;/h2&gt;
&lt;p&gt;如果你坐拥传统 .NET Framework 应用（说实话，大多数企业团队都是这样），这就是&lt;em&gt;那个&lt;/em&gt;应该开始使用的工具。仅评估文档就值得投入时间 — 它将模糊的&amp;quot;我们应该现代化&amp;quot;变成了一个具体的、有优先级的工作项列表，指明了前进的方向。&lt;/p&gt;
&lt;p&gt;协作工作流也很聪明：导出评估、与团队分享、无需重新运行即可导入。决策者不是运行工具的人的架构评审？涵盖了。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;GitHub Copilot 的现代化评估将 .NET 迁移从一个可怕的、不明确的项目转变为一个结构化的、可跟踪的过程。从推荐评估开始了解你的现状，然后使用自定义评估来比较 Azure 目标并制定迁移计划。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/dotnet/your-migrations-source-of-truth-the-modernization-assessment/"&gt;完整演练&lt;/a&gt;并获取 &lt;a href="https://aka.ms/ghcp-appmod/vscode-ext"&gt;VS Code 扩展&lt;/a&gt;在你自己的代码库上试试。&lt;/p&gt;</content:encoded></item><item><title>MCP Apps 迎来 Fluent API — 三步在 .NET 中构建丰富的 AI 工具界面</title><link>https://thedotnetblog.com/zh/posts/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/posts/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/posts/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>Microsoft Foundry 2026年3月 — GPT-5.4、Agent Service GA，以及改变一切的SDK刷新</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/microsoft-foundry-march-2026-whats-new/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/microsoft-foundry-march-2026-whats-new/</guid><description>Microsoft Foundry 2026年3月更新非常重大：Agent Service正式GA，GPT-5.4带来可靠推理，azure-ai-projects SDK在所有语言中稳定发布，Fireworks AI将开放模型引入Azure。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/microsoft-foundry-march-2026-whats-new/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;每月的&amp;quot;Microsoft Foundry新动态&amp;quot;文章通常是增量改进和偶尔亮点功能的混合。&lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-microsoft-foundry-mar-2026/"&gt;2026年3月版&lt;/a&gt;呢？基本上全是亮点功能。Foundry Agent Service正式GA，GPT-5.4投入生产，SDK获得重要的稳定版本发布，Fireworks AI将开放模型推理引入Azure。让我来解析对.NET开发者来说什么最重要。&lt;/p&gt;
&lt;h2 id="foundry-agent-service已准备好投入生产"&gt;Foundry Agent Service已准备好投入生产&lt;/h2&gt;
&lt;p&gt;这是最大的新闻。新一代代理运行时已正式发布 — 构建在OpenAI Responses API之上，与OpenAI代理协议兼容，并向多个提供商的模型开放。如果您今天正在使用Responses API构建，迁移到Foundry将在您现有的代理逻辑之上添加企业级安全性、私有网络、Entra RBAC、完整追踪和评估功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PromptAgentDefinition&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="n"&gt;project_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&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;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_PROJECT_ENDPOINT&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;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DefaultAzureCredential&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_version&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;agent_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-enterprise-agent&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;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PromptAgentDefinition&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;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&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;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&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="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键新增功能：端到端私有网络、MCP认证扩展（包括OAuth透传）、语音对语音代理的Voice Live预览，以及在6个新区域托管代理。&lt;/p&gt;
&lt;h2 id="gpt-54--可靠性优于纯粹的智能"&gt;GPT-5.4 — 可靠性优于纯粹的智能&lt;/h2&gt;
&lt;p&gt;GPT-5.4不是为了变得更聪明，而是为了变得更可靠。在长时间交互中更强的推理能力、更好的指令遵循性、更少的工作流中途故障，以及集成的计算机使用功能。对于生产环境的代理来说，这种可靠性比基准测试分数重要得多。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模型&lt;/th&gt;
&lt;th&gt;价格（每百万token）&lt;/th&gt;
&lt;th&gt;最佳用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 (≤272K)&lt;/td&gt;
&lt;td&gt;$2.50 / $15 输出&lt;/td&gt;
&lt;td&gt;生产代理、编码、文档工作流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 Pro&lt;/td&gt;
&lt;td&gt;$30 / $180 输出&lt;/td&gt;
&lt;td&gt;深度分析、科学推理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 Mini&lt;/td&gt;
&lt;td&gt;经济实惠&lt;/td&gt;
&lt;td&gt;分类、提取、轻量级工具调用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;聪明的策略是路由：GPT-5.4 Mini处理高吞吐量、低延迟的工作，而GPT-5.4负责推理密集型的请求。&lt;/p&gt;
&lt;h2 id="sdk终于稳定了"&gt;SDK终于稳定了&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azure-ai-projects&lt;/code&gt; SDK在所有语言中发布了稳定版 — Python 2.0.0、JS/TS 2.0.0、Java 2.0.0和.NET 2.0.0（4月1日）。&lt;code&gt;azure-ai-agents&lt;/code&gt;依赖已经消失 — 一切都在&lt;code&gt;AIProjectClient&lt;/code&gt;下。使用&lt;code&gt;pip install azure-ai-projects&lt;/code&gt;安装，包中直接捆绑了&lt;code&gt;openai&lt;/code&gt;和&lt;code&gt;azure-identity&lt;/code&gt;作为依赖项。&lt;/p&gt;
&lt;p&gt;对于.NET开发者来说，这意味着一个NuGet包就能覆盖Foundry的全部功能。不再需要在多个代理SDK之间来回切换。&lt;/p&gt;
&lt;h2 id="fireworks-ai将开放模型引入azure"&gt;Fireworks AI将开放模型引入Azure&lt;/h2&gt;
&lt;p&gt;也许是架构上最有趣的新增：Fireworks AI每天处理超过13万亿token，速度达到~180K请求/秒，现在可以通过Foundry使用。DeepSeek V3.2、gpt-oss-120b、Kimi K2.5和MiniMax M2.5在发布时可用。&lt;/p&gt;
&lt;p&gt;真正的故事是&lt;strong&gt;自带权重&lt;/strong&gt; — 从任何地方上传量化或微调的权重，无需更改服务栈。通过无服务器按token付费或预配置吞吐量进行部署。&lt;/p&gt;
&lt;h2 id="其他亮点"&gt;其他亮点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phi-4 Reasoning Vision 15B&lt;/strong&gt; — 针对图表、图形和文档布局的多模态推理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluations GA&lt;/strong&gt; — 开箱即用的评估器，配合持续生产监控，直接接入Azure Monitor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Priority Processing&lt;/strong&gt;（预览）— 面向延迟敏感型工作负载的专用计算通道&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Voice Live&lt;/strong&gt; — 直接连接到Foundry代理的语音对语音运行时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracing GA&lt;/strong&gt; — 具有排序和过滤功能的端到端代理追踪检查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PromptFlow弃用&lt;/strong&gt; — 在2027年1月前迁移到Microsoft Framework Workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;2026年3月是Foundry的转折点。Agent Service GA、所有语言的稳定SDK、用于可靠生产代理的GPT-5.4，以及通过Fireworks AI实现的开放模型推理 — 该平台已准备好应对严肃的工作负载。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-microsoft-foundry-mar-2026/"&gt;完整汇总&lt;/a&gt;并&lt;a href="https://learn.microsoft.com/azure/foundry/quickstarts/get-started-code"&gt;构建您的第一个代理&lt;/a&gt;来开始吧。&lt;/p&gt;</content:encoded></item><item><title>SQL MCP Server — 给 AI 代理数据库访问的正确方式</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/sql-mcp-server-data-api-builder/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/sql-mcp-server-data-api-builder/</guid><description>Data API builder 的 SQL MCP Server 为 AI 代理提供安全、确定性的数据库访问，无需暴露架构或依赖 NL2SQL。RBAC、缓存、多数据库支持 — 全部内置。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/sql-mcp-server-data-api-builder/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;说实话：今天市面上大多数数据库 MCP 服务器都很可怕。它们接受自然语言查询，即时生成 SQL，然后在你的生产数据上执行。有什么可能出错的？（一切。一切都可能出错。）&lt;/p&gt;
&lt;p&gt;Azure SQL 团队刚刚&lt;a href="https://devblogs.microsoft.com/azure-sql/introducing-sql-mcp-server/"&gt;发布了 SQL MCP Server&lt;/a&gt;，它采用了一种根本不同的方法。作为 Data API builder（DAB）2.0 的功能构建，它为 AI 代理提供结构化、确定性的数据库操作访问 — 没有 NL2SQL，不暴露你的架构，每一步都有完整的 RBAC。&lt;/p&gt;
&lt;h2 id="为什么不用-nl2sql"&gt;为什么不用 NL2SQL？&lt;/h2&gt;
&lt;p&gt;这是最有趣的设计决策。模型不是确定性的，复杂查询最容易产生微妙的错误。用户希望 AI 能生成的那些查询，恰恰也是在非确定性生成时最需要审查的查询。&lt;/p&gt;
&lt;p&gt;相反，SQL MCP Server 使用 &lt;strong&gt;NL2DAB&lt;/strong&gt; 方法。代理使用 Data API builder 的实体抽象层和内置查询构建器来确定性地生成准确、格式良好的 T-SQL。对用户来说结果相同，但没有幻觉 JOIN 或意外数据泄露的风险。&lt;/p&gt;
&lt;h2 id="七个工具不是七百个"&gt;七个工具，不是七百个&lt;/h2&gt;
&lt;p&gt;SQL MCP Server 精确暴露七个 DML 工具，与数据库大小无关：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;describe_entities&lt;/code&gt; — 发现可用实体和操作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create_record&lt;/code&gt; — 插入行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read_records&lt;/code&gt; — 查询表和视图&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update_record&lt;/code&gt; — 修改行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete_record&lt;/code&gt; — 删除行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;execute_entity&lt;/code&gt; — 运行存储过程&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aggregate_records&lt;/code&gt; — 聚合查询&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这很聪明，因为上下文窗口是代理的思考空间。用数百个工具定义淹没它们会减少推理空间。七个固定工具让代理专注于&lt;em&gt;思考&lt;/em&gt;而不是&lt;em&gt;导航&lt;/em&gt;。&lt;/p&gt;
&lt;p&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="s2"&gt;&amp;#34;runtime&amp;#34;&lt;/span&gt;&lt;span class="err"&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;mcp&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;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;path&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/mcp&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;dml-tools&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;describe-entities&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;create-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;read-records&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;update-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;delete-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;execute-entity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;aggregate-records&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;h2 id="三条命令开始"&gt;三条命令开始&lt;/h2&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;dab init &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --database-type mssql &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --connection-string &lt;span class="s2"&gt;&amp;#34;@env(&amp;#39;sql_connection_string&amp;#39;)&amp;#34;&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;dab add Customers &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --source dbo.Customers &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --permissions &lt;span class="s2"&gt;&amp;#34;anonymous:*&amp;#34;&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;dab start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就是一个运行中的 SQL MCP Server，暴露你的 Customers 表。实体抽象层意味着你可以为名称和列创建别名、按角色限制字段，并精确控制代理看到的内容 — 而不暴露内部架构细节。&lt;/p&gt;
&lt;h2 id="安全故事很扎实"&gt;安全故事很扎实&lt;/h2&gt;
&lt;p&gt;这是 Data API builder 成熟度发挥价值的地方：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;每一层都有 RBAC&lt;/strong&gt; — 每个实体定义哪些角色可以读取、创建、更新或删除，以及哪些字段可见&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Key Vault 集成&lt;/strong&gt; — 安全管理连接字符串和密钥&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Entra + 自定义 OAuth&lt;/strong&gt; — 生产级认证&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内容安全策略&lt;/strong&gt; — 代理通过受控契约交互，而不是原始 SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;架构抽象特别重要。你的内部表名和列名永远不会暴露给代理。你定义对 AI 交互有意义的实体、别名和描述 — 而不是你的数据库 ERD 图。&lt;/p&gt;
&lt;h2 id="多数据库和多协议"&gt;多数据库和多协议&lt;/h2&gt;
&lt;p&gt;SQL MCP Server 支持 Microsoft SQL、PostgreSQL、Azure Cosmos DB 和 MySQL。由于它是 DAB 的功能，你可以从同一配置同时获取 REST、GraphQL 和 MCP 端点。相同的实体定义、相同的 RBAC 规则、相同的安全性 — 跨所有三种协议。&lt;/p&gt;
&lt;p&gt;DAB 2.0 的自动配置甚至可以检查你的数据库并动态构建配置，如果你愿意为快速原型设计减少抽象的话。&lt;/p&gt;
&lt;h2 id="我的看法"&gt;我的看法&lt;/h2&gt;
&lt;p&gt;这就是 AI 代理的企业级数据库访问应该如何工作。不是&amp;quot;嘿 LLM，给我写点 SQL 然后对生产环境 YOLO&amp;quot;。而是：定义良好的实体层、确定性查询生成、每一步的 RBAC、缓存、监控和遥测。以最好的方式无聊着。&lt;/p&gt;
&lt;p&gt;对于 .NET 开发者，集成故事很清晰 — DAB 是 .NET 工具，MCP Server 作为容器运行，与大多数人已经在用的 Azure SQL 配合工作。如果你正在构建需要数据访问的 AI 代理，从这里开始。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;SQL MCP Server 是免费、开源的，可在任何地方运行。这是微软为给 AI 代理提供安全数据库访问的规范性方法。查看&lt;a href="https://devblogs.microsoft.com/azure-sql/introducing-sql-mcp-server/"&gt;完整文章&lt;/a&gt;和&lt;a href="https://aka.ms/sql/mcp"&gt;文档&lt;/a&gt;开始使用。&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.116 — Agents应用获得键盘导航和文件上下文补全</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-116-agents-app-updates/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-116-agents-app-updates/</guid><description>VS Code 1.116专注于Agents应用的优化 — 专属快捷键、辅助功能改进、文件上下文补全，以及CSS @import链接解析。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-116-agents-app-updates/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;VS Code 1.116是2026年4月的版本，虽然比最近的一些更新更轻量，但变化是有针对性且有意义的 — 尤其是如果你每天都在使用Agents应用。&lt;/p&gt;
&lt;p&gt;以下是基于&lt;a href="https://code.visualstudio.com/updates/v1_116"&gt;官方发行说明&lt;/a&gt;的更新内容。&lt;/p&gt;
&lt;h2 id="agents应用改进"&gt;Agents应用改进&lt;/h2&gt;
&lt;p&gt;Agents应用继续通过可用性优化不断成熟，这些改进在日常工作流中产生了真正的影响：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;专属快捷键&lt;/strong&gt; — 现在你可以用专属命令和键盘快捷键来聚焦更改视图、更改中的文件树，以及聊天自定义视图。如果你之前一直在Agents应用中到处点击来导航，这带来了完全由键盘驱动的工作流。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;辅助功能帮助对话框&lt;/strong&gt; — 在聊天输入框中按&lt;code&gt;Alt+F1&lt;/code&gt;现在会打开一个辅助功能帮助对话框，显示可用的命令和快捷键。屏幕阅读器用户还可以控制播报的详细程度。良好的辅助功能让每个人受益。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;文件上下文补全&lt;/strong&gt; — 在Agents应用聊天中输入&lt;code&gt;#&lt;/code&gt;来触发限定在当前工作区范围内的文件上下文补全。这是那些加速每次交互的小型生活质量改进之一 — 不再需要在引用代码时输入完整的文件路径。&lt;/p&gt;
&lt;h2 id="css-import链接解析"&gt;CSS &lt;code&gt;@import&lt;/code&gt;链接解析&lt;/h2&gt;
&lt;p&gt;前端开发者的好消息：VS Code现在可以解析使用node_modules路径的CSS &lt;code&gt;@import&lt;/code&gt;引用。当使用打包工具时，你可以通过&lt;code&gt;Ctrl+点击&lt;/code&gt;跳转到像&lt;code&gt;@import &amp;quot;some-module/style.css&amp;quot;&lt;/code&gt;这样的导入。虽小但消除了CSS工作流中的一个摩擦点。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;VS Code 1.116是关于改进的 — 让Agents应用更易导航、更易访问、更友好的键盘操作。如果你在Agents应用中花费大量时间（我猜很多人都是如此），这些变化会累积起来。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://code.visualstudio.com/updates/v1_116"&gt;完整发行说明&lt;/a&gt;获取完整列表。&lt;/p&gt;</content:encoded></item><item><title>构建不像黑盒的实时多智能体UI</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/ag-ui-real-time-multi-agent-ui-maf/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/ag-ui-real-time-multi-agent-ui-maf/</guid><description>AG-UI和Microsoft Agent Framework联手为多智能体工作流提供真正的前端——实时流式传输、人工审批，以及对智能体行为的完整可视化。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/ag-ui-real-time-multi-agent-ui-maf/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;多智能体系统的问题在于：它们在演示中看起来令人难以置信。三个智能体互相传递工作、解决问题、做出决策。然后你试图把它展示给真实用户，得到的却是……沉默。一个旋转的加载指示器。完全不知道哪个智能体在做什么，或者系统为什么暂停了。这不是产品——这是信任问题。&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework团队刚刚发布了一篇&lt;a href="https://devblogs.microsoft.com/agent-framework/ag-ui-multi-agent-workflow-demo/"&gt;精彩的教程&lt;/a&gt;，介绍如何将MAF工作流与&lt;a href="https://github.com/ag-ui-protocol/ag-ui"&gt;AG-UI&lt;/a&gt;配合使用。AG-UI是一个开放协议，通过Server-Sent Events将智能体执行事件流式传输到前端。说实话，这正是我们一直缺少的桥梁。&lt;/p&gt;
&lt;h2 id="为什么这对net开发者很重要"&gt;为什么这对.NET开发者很重要&lt;/h2&gt;
&lt;p&gt;如果你在构建AI驱动的应用，可能已经遇到过这堵墙。你的后端编排工作得很好——智能体之间传递任务、工具触发、决策做出。但前端完全不知道幕后发生了什么。AG-UI通过定义一个标准协议来解决这个问题，将智能体事件（想想&lt;code&gt;RUN_STARTED&lt;/code&gt;、&lt;code&gt;STEP_STARTED&lt;/code&gt;、&lt;code&gt;TOOL_CALL_*&lt;/code&gt;、&lt;code&gt;TEXT_MESSAGE_*&lt;/code&gt;）通过SSE直接传输到你的UI层。&lt;/p&gt;
&lt;p&gt;他们构建的演示是一个包含三个智能体的客户支持工作流：一个路由请求的分诊智能体、一个处理退款事务的退款智能体，以及一个管理换货的订单智能体。每个智能体都有自己的工具，交接拓扑是明确定义的——没有&amp;quot;从提示词中猜测&amp;quot;的感觉。&lt;/p&gt;
&lt;h2 id="交接拓扑才是真正的主角"&gt;交接拓扑才是真正的主角&lt;/h2&gt;
&lt;p&gt;让我眼前一亮的是&lt;code&gt;HandoffBuilder&lt;/code&gt;如何让你声明智能体之间的有向路由图：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HandoffBuilder&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;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ag_ui_handoff_workflow_demo&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;participants&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;refund&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;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;termination_condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;termination_condition&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&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;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Refunds, damaged-item claims...&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&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;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Replacement, exchange...&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;,&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;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Replacement logistics needed after refund.&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&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;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;After replacement/shipping tasks complete.&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;code&gt;add_handoff&lt;/code&gt;创建一条带有自然语言描述的有向边。框架基于这个拓扑为每个智能体生成交接工具。因此路由决策是基于你的编排结构，而不是LLM随意决定的。这对生产环境的可靠性意义重大。&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;code&gt;approval_mode=&amp;quot;always_require&amp;quot;&lt;/code&gt;的工具时，工作流暂停并发出事件。前端渲染一个包含工具名称和参数的审批模态框。没有烧掉token的重试循环——只是一个干净的暂停-审批-恢复流程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;信息请求中断&lt;/strong&gt; ——当智能体需要用户提供更多上下文（比如订单ID）时，它会暂停并询问。前端显示问题，用户回答，执行从停止的地方精确恢复。&lt;/p&gt;
&lt;p&gt;两种模式都作为标准AG-UI事件进行流式传输，所以你的前端不需要针对每个智能体的自定义逻辑——只需渲染通过SSE连接传来的任何事件。&lt;/p&gt;
&lt;h2 id="接入出奇地简单"&gt;接入出奇地简单&lt;/h2&gt;
&lt;p&gt;MAF和AG-UI之间的集成就是一个函数调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework.ag_ui&lt;/span&gt; &lt;span class="kn"&gt;import&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;AgentFrameworkWorkflow&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;add_agent_framework_fastapi_endpoint&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&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&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="n"&gt;demo_workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AgentFrameworkWorkflow&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;workflow_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;_thread_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;create_handoff_workflow&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;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ag_ui_handoff_workflow_demo&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;add_agent_framework_fastapi_endpoint&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="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;demo_workflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/handoff_demo&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;code&gt;workflow_factory&lt;/code&gt;为每个线程创建一个新的工作流，这样每个对话都有隔离的状态。端点自动处理所有SSE管道。如果你已经在使用FastAPI（或者可以把它作为轻量层添加），这几乎是零摩擦的。&lt;/p&gt;
&lt;h2 id="我的看法"&gt;我的看法&lt;/h2&gt;
&lt;p&gt;对于我们.NET开发者来说，第一个问题是：&amp;ldquo;我能用C#做这个吗？&amp;ldquo;Agent Framework同时支持.NET和Python，AG-UI协议是语言无关的（只是SSE）。所以虽然这个特定演示使用Python和FastAPI，但模式可以直接移植。你可以用ASP.NET Core最小API配合SSE端点，遵循相同的AG-UI事件模式来实现。&lt;/p&gt;
&lt;p&gt;更重要的启示是，多智能体UI正在成为一等公民的关注点，而不是事后才想到的事情。如果你在构建任何需要智能体与人类交互的东西——客户支持、审批工作流、文档处理——MAF编排加AG-UI透明度的组合就是应该遵循的模式。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;AG-UI + Microsoft Agent Framework给你两全其美：后端强大的多智能体编排和前端的实时可视化。不再有黑盒式的智能体交互。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/agent-framework/ag-ui-multi-agent-workflow-demo/"&gt;完整教程&lt;/a&gt;和&lt;a href="https://github.com/ag-ui-protocol/ag-ui"&gt;AG-UI协议仓库&lt;/a&gt;以深入了解。&lt;/p&gt;</content:encoded></item><item><title>将 Azure Functions 上的 MCP 服务器连接到 Foundry 代理 — 方法在这里</title><link>https://thedotnetblog.com/zh/posts/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/posts/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/posts/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><item><title>那个你不知道的Visual Studio浮动窗口设置（但你应该知道）</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-floating-windows-powertoys/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-floating-windows-powertoys/</guid><description>Visual Studio的一个隐藏设置让你完全控制浮动窗口 — 独立的任务栏条目、正确的多显示器行为，以及完美的FancyZones集成。一个下拉菜单改变一切。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-floating-windows-powertoys/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你在Visual Studio中使用多个显示器（说实话，现在谁不用呢？），你可能经历过这种烦恼：浮动工具窗口在你最小化主IDE时消失，它们总是在所有窗口之上，而且不会在任务栏中显示为单独的按钮。这对某些工作流有效，但对多显示器设置来说很令人沮丧。&lt;/p&gt;
&lt;p&gt;Visual Studio团队的Mads Kristensen &lt;a href="https://devblogs.microsoft.com/visualstudio/take-full-control-of-your-floating-windows-in-visual-studio/"&gt;分享了一个鲜为人知的设置&lt;/a&gt;，它完全改变了浮动窗口的行为。一个下拉菜单。就这样。&lt;/p&gt;
&lt;h2 id="设置"&gt;设置&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tools &amp;gt; Options &amp;gt; Environment &amp;gt; Windows &amp;gt; Floating Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下拉菜单&amp;quot;These floating windows are owned by the main window&amp;quot;有三个选项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;None&lt;/strong&gt; — 完全独立。每个浮动窗口都有自己的任务栏条目，行为就像普通的Windows窗口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Windows&lt;/strong&gt;（默认）— 文档自由浮动，工具窗口保持与IDE绑定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documents and Tool Windows&lt;/strong&gt; — 经典的Visual Studio行为，所有窗口都绑定到主窗口。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="为什么none是多显示器设置的最佳选择"&gt;为什么&amp;quot;None&amp;quot;是多显示器设置的最佳选择&lt;/h2&gt;
&lt;p&gt;将其设置为&lt;strong&gt;None&lt;/strong&gt;，突然间你所有的浮动工具窗口和文档都像真正的Windows应用程序一样运行。它们出现在任务栏中，当你最小化Visual Studio主窗口时保持可见，并且不再强制自己始终在最前面。&lt;/p&gt;
&lt;p&gt;将此与&lt;strong&gt;PowerToys FancyZones&lt;/strong&gt;结合使用，效果惊人。在你的显示器上创建自定义布局，将解决方案资源管理器放在一个区域，调试器放在另一个区域，代码文件放在你想要的任何地方。一切都保持在原位，一切都可以独立访问，你的工作空间感觉有条理而不是混乱的。&lt;/p&gt;
&lt;h2 id="快速建议"&gt;快速建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多显示器高级用户&lt;/strong&gt;：设置为&lt;strong&gt;None&lt;/strong&gt;，搭配FancyZones&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;偶尔浮动的用户&lt;/strong&gt;：&lt;strong&gt;Tool Windows&lt;/strong&gt;（默认）是不错的折中方案&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传统工作流&lt;/strong&gt;：&lt;strong&gt;Documents and Tool Windows&lt;/strong&gt;保持经典行为&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;专业提示：在任何工具窗口的标题栏上&lt;strong&gt;Ctrl + 双击&lt;/strong&gt;即可立即浮动或停靠。更改设置后无需重启。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;这是那种&amp;quot;我不敢相信我之前不知道&amp;quot;的设置之一。如果Visual Studio中的浮动窗口曾经让你烦恼，现在就去改掉它。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/visualstudio/take-full-control-of-your-floating-windows-in-visual-studio/"&gt;完整文章&lt;/a&gt;获取详细信息和截图。&lt;/p&gt;</content:encoded></item><item><title>智能体平台工程正在成为现实 — Git-APE展示了方法</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agentic-platform-engineering-git-ape/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agentic-platform-engineering-git-ape/</guid><description>微软的Git-APE项目将智能体平台工程付诸实践 — 使用GitHub Copilot智能体和Azure MCP将自然语言请求转化为经过验证的云基础设施。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agentic-platform-engineering-git-ape/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;平台工程一直是那种在技术大会上听起来很棒的术语，但通常意味着&amp;quot;我们搭了一个内部门户和一个Terraform封装器。&amp;ldquo;真正的承诺 — 真正安全、受治理且快速的自助式基础设施 — 总是差那么几步。&lt;/p&gt;
&lt;p&gt;Azure团队刚刚发布了&lt;a href="https://devblogs.microsoft.com/all-things-azure/putting-agentic-platform-engineering-to-the-test/"&gt;智能体平台工程系列的第二部分&lt;/a&gt;，这次全是关于动手实现。他们称之为&lt;strong&gt;Git-APE&lt;/strong&gt;（是的，这个缩写是故意的），这是一个开源项目，使用GitHub Copilot智能体加Azure MCP服务器，将自然语言请求转化为经过验证和部署的基础设施。&lt;/p&gt;
&lt;h2 id="git-ape究竟做什么"&gt;Git-APE究竟做什么&lt;/h2&gt;
&lt;p&gt;核心思路：开发者不再需要学习Terraform模块、浏览门户UI或向平台团队提交工单，而是直接和Copilot智能体对话。智能体理解意图、生成基础设施即代码、根据策略进行验证并部署 — 全部在VS Code内完成。&lt;/p&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;git clone https://github.com/Azure/git-ape
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; git-ape
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在VS Code中打开工作区，GitHub Copilot会自动发现智能体配置文件。你直接与智能体交互：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@git-ape deploy a function app with storage in West Europe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;智能体在底层使用Azure MCP Server与Azure服务交互。VS Code设置中的MCP配置启用特定功能：&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;azureMcp.serverMode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;namespace&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;azureMcp.enabledServices&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="s2"&gt;&amp;#34;deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bestpractices&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;group&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="s2"&gt;&amp;#34;subscription&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;functionapp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;storage&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="s2"&gt;&amp;#34;sql&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;monitor&amp;#34;&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="nt"&gt;&amp;#34;azureMcp.readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;h2 id="为什么这很重要"&gt;为什么这很重要&lt;/h2&gt;
&lt;p&gt;对于我们在Azure上构建的人来说，这将平台工程的对话从&amp;quot;如何构建一个门户&amp;quot;转变为&amp;quot;如何将我们的护栏描述为API。&amp;ldquo;当你的平台接口是AI智能体时，你的约束和策略的质量就成了产品本身。&lt;/p&gt;
&lt;p&gt;第一部分博客阐述了理论：描述良好的API、控制模式和明确的护栏使平台做好了智能体化的准备。第二部分通过交付实际工具证明它确实有效。智能体不会盲目生成资源 — 它会根据最佳实践进行验证、遵守命名约定并应用你组织的策略。&lt;/p&gt;
&lt;p&gt;清理同样简单：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@git-ape destroy my-resource-group
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="我的看法"&gt;我的看法&lt;/h2&gt;
&lt;p&gt;说实话 — 这里更多是关于模式而非具体工具。Git-APE本身是一个演示/参考架构。但底层的理念 — 智能体作为平台的接口、MCP作为协议、GitHub Copilot作为宿主 — 这就是企业开发者体验的前进方向。&lt;/p&gt;
&lt;p&gt;如果你是一个正在寻找如何让内部工具对智能体友好的平台团队，没有比这更好的起点了。如果你是.NET开发者想知道这和你的世界如何关联：Azure MCP Server和GitHub Copilot智能体可以与任何Azure工作负载配合使用。你的ASP.NET Core API、你的.NET Aspire技术栈、你的容器化微服务 — 都可以成为智能体部署流程的目标。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Git-APE是对智能体平台工程实践的一个早期但具体的展示。克隆&lt;a href="https://github.com/Azure/git-ape"&gt;仓库&lt;/a&gt;，试试演示，开始思考你的平台的API和策略需要是什么样子，才能让智能体安全地使用它们。&lt;/p&gt;
&lt;p&gt;阅读&lt;a href="https://devblogs.microsoft.com/all-things-azure/putting-agentic-platform-engineering-to-the-test/"&gt;完整文章&lt;/a&gt;获取详细教程和演示视频。&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.115 — 后台终端通知、SSH Agent 模式及更多</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-115-agent-improvements/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-115-agent-improvements/</guid><description>VS Code 1.115 带来了面向 Agent 的后台终端通知、SSH 远程 Agent 托管、终端文件粘贴以及会话感知的编辑追踪。以下是对 .NET 开发者重要的内容。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。如需查看原文，&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-115-agent-improvements/"&gt;请点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;VS Code 1.115 刚刚&lt;a href="https://code.visualstudio.com/updates/v1_115"&gt;发布&lt;/a&gt;了，虽然从主要功能来看这是一个较轻量的版本，但如果你每天都在使用 AI 编程助手，那么与 Agent 相关的改进确实非常实用。&lt;/p&gt;
&lt;p&gt;让我来重点介绍一下真正值得了解的内容。&lt;/p&gt;
&lt;h2 id="后台终端与-agent-通信"&gt;后台终端与 Agent 通信&lt;/h2&gt;
&lt;p&gt;这是本次最突出的功能。后台终端现在会在命令完成时自动通知 Agent，包括退出代码和终端输出。后台终端中的输入提示也会被检测并展示给用户。&lt;/p&gt;
&lt;p&gt;这为什么重要？如果你用过 Copilot 的 Agent 模式在后台运行构建命令或测试套件，你肯定知道&amp;quot;那个跑完了没？&amp;ldquo;的痛苦——后台终端基本上就是发射后不管。现在 Agent 会在你的 &lt;code&gt;dotnet build&lt;/code&gt; 或 &lt;code&gt;dotnet test&lt;/code&gt; 完成时收到通知，看到输出，并相应地做出反应。这是一个小改动，但让 Agent 驱动的工作流程变得更加可靠。&lt;/p&gt;
&lt;p&gt;还有一个新的 &lt;code&gt;send_to_terminal&lt;/code&gt; 工具，允许 Agent 在用户确认后向后台终端发送命令，解决了 &lt;code&gt;run_in_terminal&lt;/code&gt; 带超时参数时会将终端移到后台并使其变为只读的问题。&lt;/p&gt;
&lt;h2 id="ssh-远程-agent-托管"&gt;SSH 远程 Agent 托管&lt;/h2&gt;
&lt;p&gt;VS Code 现在支持通过 SSH 连接到远程机器，自动安装 CLI 并以 Agent 主机模式启动。这意味着你的 AI Agent 会话可以直接针对远程环境——对于在 Linux 服务器或云虚拟机上构建和测试的 .NET 开发者来说非常有用。&lt;/p&gt;
&lt;h2 id="agent-会话中的编辑追踪"&gt;Agent 会话中的编辑追踪&lt;/h2&gt;
&lt;p&gt;Agent 会话期间进行的文件编辑现在会被追踪和恢复，支持差异对比、撤销/重做和状态恢复。如果 Agent 修改了你的代码并且出了问题，你可以准确地看到哪些内容发生了变化并将其回滚。让 Agent 修改代码库时更加安心。&lt;/p&gt;
&lt;h2 id="浏览器标签页感知及其他改进"&gt;浏览器标签页感知及其他改进&lt;/h2&gt;
&lt;p&gt;还有一些生活质量方面的提升：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;浏览器标签页追踪&lt;/strong&gt; — 聊天现在可以追踪和链接会话期间打开的浏览器标签页，这样 Agent 可以引用你正在查看的网页&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;终端文件粘贴&lt;/strong&gt; — 使用 Ctrl+V、拖放或右键点击将文件（包括图片）粘贴到终端&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小地图中的测试覆盖率&lt;/strong&gt; — 测试覆盖率指示器现在显示在小地图中，提供快速的视觉概览&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mac 上的双指缩放&lt;/strong&gt; — 集成浏览器支持双指缩放手势&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话中的 Copilot 使用权限&lt;/strong&gt; — 状态栏在会话视图中显示使用信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;转到文件中的网站图标&lt;/strong&gt; — 打开的网页在快速选择列表中显示网站图标&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;VS Code 1.115 是一个渐进式版本，但 Agent 改进——后台终端通知、SSH Agent 托管和编辑追踪——加在一起为 AI 辅助开发带来了明显更流畅的体验。如果你在 .NET 项目中使用 Copilot 的 Agent 模式，这些正是每天减少摩擦的生活质量改进。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://code.visualstudio.com/updates/v1_115"&gt;完整的发行说明&lt;/a&gt;了解所有细节。&lt;/p&gt;</content:encoded></item><item><title>C# 15 引入联合类型 — 正是我们一直在期待的</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/csharp-15-union-types-exhaustive-matching/</link><pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/csharp-15-union-types-exhaustive-matching/</guid><description>C# 15 引入了 union 关键字 — 编译器强制的可区分联合类型，支持穷举模式匹配。来看看它们长什么样、为什么重要，以及如何今天就试用。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/csharp-15-union-types-exhaustive-matching/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是我一直在等的那个功能。C# 15 引入了 &lt;code&gt;union&lt;/code&gt; 关键字 — 真正的可区分联合类型，带有编译器强制的穷举模式匹配。如果你曾经羡慕过 F# 的可区分联合或 Rust 的 enum，你就明白这为什么重要了。&lt;/p&gt;
&lt;p&gt;Bill Wagner 在 .NET 博客上&lt;a href="https://devblogs.microsoft.com/dotnet/csharp-15-union-types/"&gt;发布了深度解析&lt;/a&gt;，说实话？设计干净、实用，非常 C#。让我带你看看实际有什么，以及为什么它比乍看之下更重要。&lt;/p&gt;
&lt;h2 id="联合类型解决的问题"&gt;联合类型解决的问题&lt;/h2&gt;
&lt;p&gt;在 C# 15 之前，从方法返回&amp;quot;多个可能类型之一&amp;quot;总是一种妥协：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;object&lt;/code&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; — 同样的问题，而且类型需要共同的祖先&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些都无法给你真正想要的东西：一个封闭的类型集合，编译器保证你已经处理了每种情况。这就是联合类型的作用。&lt;/p&gt;
&lt;h2 id="语法优雅简洁"&gt;语法优雅简洁&lt;/h2&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="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&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="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&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="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&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;public&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt; &lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bird&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;code&gt;Pet&lt;/code&gt; 可以包含一个 &lt;code&gt;Cat&lt;/code&gt;、一个 &lt;code&gt;Dog&lt;/code&gt; 或一个 &lt;code&gt;Bird&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="n"&gt;Pet&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Rex&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;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Dog { Name = Rex }&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;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="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt; &lt;span class="k"&gt;switch&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;Dog&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&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;Cat&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&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;Bird&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&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;code&gt;_&lt;/code&gt;。编译器知道这个 switch 覆盖了所有可能的情况。如果你之后向联合添加第四个类型，每个没有处理它的 switch 表达式都会产生警告。缺失的情况在编译时被捕获，而不是在运行时。&lt;/p&gt;
&lt;h2 id="真正实用的地方"&gt;真正实用的地方&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Pet&lt;/code&gt; 的例子很可爱，但这里才是联合类型在真实代码中真正发光的地方。&lt;/p&gt;
&lt;h3 id="返回不同形状的-api-响应"&gt;返回不同形状的 API 响应&lt;/h3&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt; &lt;span class="n"&gt;ApiResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ApiError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ValidationFailure&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;现在每个消费者都被强制处理成功、错误和验证失败。再也不会有&amp;quot;忘记检查错误情况&amp;quot;的 bug 了。&lt;/p&gt;
&lt;h3 id="单值或集合"&gt;单值或集合&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OneOrMore&amp;lt;T&amp;gt;&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt; &lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AsEnumerable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="k"&gt;switch&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;T&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;single&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;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;multiple&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;multiple&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="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;/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;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;dotnet&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;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;moreTags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;csharp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;unions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;preview&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsEnumerable&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;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$&amp;#34;[{tag}] &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="c1"&gt;// [dotnet]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="组合不相关的类型"&gt;组合不相关的类型&lt;/h3&gt;
&lt;p&gt;这是相对于传统继承层次结构的杀手级功能。你可以联合没有任何共同点的类型 — &lt;code&gt;string&lt;/code&gt; 和 &lt;code&gt;Exception&lt;/code&gt;、&lt;code&gt;int&lt;/code&gt; 和 &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;。不需要共同祖先。&lt;/p&gt;
&lt;h2 id="为现有库创建自定义联合"&gt;为现有库创建自定义联合&lt;/h2&gt;
&lt;p&gt;这是一个聪明的设计选择：任何带有 &lt;code&gt;[Union]&lt;/code&gt; 属性的类或结构体都会被识别为联合类型，只要它遵循基本模式（case 类型的公共构造函数和 &lt;code&gt;Value&lt;/code&gt; 属性）。像 OneOf 这样已经提供类似联合功能的库可以选择加入编译器支持，而无需重写其内部实现。&lt;/p&gt;
&lt;p&gt;对于使用值类型的性能敏感场景，库可以通过 &lt;code&gt;HasValue&lt;/code&gt; 和 &lt;code&gt;TryGetValue&lt;/code&gt; 方法实现无装箱的访问模式。&lt;/p&gt;
&lt;h2 id="更大的图景"&gt;更大的图景&lt;/h2&gt;
&lt;p&gt;联合类型是 C# 即将到来的更广泛穷举性故事的一部分：&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;code&gt;closed&lt;/code&gt; 修饰符阻止在定义程序集之外派生类（已提议）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密封枚举&lt;/strong&gt; — 阻止创建声明成员之外的值（已提议）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三个功能结合在一起，将使 C# 拥有所有主流语言中最全面的类型安全模式匹配系统之一。&lt;/p&gt;
&lt;h2 id="今天就试试"&gt;今天就试试&lt;/h2&gt;
&lt;p&gt;联合类型在 .NET 11 Preview 2 中可用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装 &lt;a href="https://dotnet.microsoft.com/download/dotnet"&gt;.NET 11 Preview SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;在项目中目标设为 &lt;code&gt;net11.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;设置 &lt;code&gt;&amp;lt;LangVersion&amp;gt;preview&amp;lt;/LangVersion&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个注意事项：在 Preview 2 中，你需要在项目中声明 &lt;code&gt;UnionAttribute&lt;/code&gt; 和 &lt;code&gt;IUnion&lt;/code&gt;，因为它们还没有包含在运行时中。从 docs 仓库获取 &lt;a href="https://github.com/dotnet/docs/blob/e68b5dd1e557b53c45ca43e61b013bc919619fb9/docs/csharp/language-reference/builtin-types/snippets/unions/RuntimePolyfill.cs"&gt;RuntimePolyfill.cs&lt;/a&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;namespace&lt;/span&gt; &lt;span class="nn"&gt;System.Runtime.CompilerServices&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="na"&gt; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; AllowMultiple = false)]&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;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UnionAttribute&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Attribute&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;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IUnion&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="kt"&gt;object?&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&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;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;联合类型是那种让你不禁感叹&amp;quot;以前没有它们我们是怎么过来的&amp;quot;的功能。编译器强制的穷举匹配、简洁的语法、泛型支持，以及与现有模式匹配的集成 — 这是我们一直要求的一切，以 C# 的方式实现。&lt;/p&gt;
&lt;p&gt;在 .NET 11 Preview 2 中试用它们，尽情折腾，并&lt;a href="https://github.com/dotnet/csharplang/discussions/9663"&gt;在 GitHub 上分享你的反馈&lt;/a&gt;。这是预览版，C# 团队正在积极倾听。你的边界情况和设计反馈将塑造最终版本。&lt;/p&gt;
&lt;p&gt;完整的语言参考请查看&lt;a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/union"&gt;联合类型文档&lt;/a&gt;和&lt;a href="https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/unions"&gt;功能规范&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2 自带文档 CLI — 你的 AI 代理也能用</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-docs-cli-ai-skills/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-docs-cli-ai-skills/</guid><description>.NET Aspire 13.2 新增了 aspire docs — 一个无需离开终端即可搜索、浏览和阅读官方文档的 CLI。它也可以作为 AI 代理的工具。这就是为什么这很重要。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-docs-cli-ai-skills/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你知道那种时刻吗——你正深入一个 Aspire AppHost，接入各种集成，然后需要确认 Redis 集成到底需要哪些参数？你 Alt-Tab 切到浏览器，在 aspire.dev 上翻来翻去，眯着眼看 API 文档，然后切回编辑器。上下文没了，心流断了。&lt;/p&gt;
&lt;p&gt;Aspire 13.2 刚刚&lt;a href="https://devblogs.microsoft.com/aspire/aspire-docs-in-your-terminal/"&gt;发布了解决方案&lt;/a&gt;。&lt;code&gt;aspire docs&lt;/code&gt; CLI 让你直接从终端搜索、浏览和阅读 Aspire 官方文档。而且因为它由可复用的服务支撑，AI 代理和技能可以使用同样的命令来查找文档，而不是幻想出不存在的 API。&lt;/p&gt;
&lt;h2 id="这到底解决了什么问题"&gt;这到底解决了什么问题&lt;/h2&gt;
&lt;p&gt;David Pine 在原文中说得很到位：AI 代理在帮助开发者构建 Aspire 应用方面&lt;em&gt;糟糕透了&lt;/em&gt;。它们推荐 &lt;code&gt;dotnet run&lt;/code&gt; 而不是 &lt;code&gt;aspire run&lt;/code&gt;，引用 learn.microsoft.com 来查找实际在 aspire.dev 上的文档，建议过时的 NuGet 包，还有——我个人最喜欢的——幻想出根本不存在的 API。&lt;/p&gt;
&lt;p&gt;为什么？因为 Aspire 作为 .NET 专属工具的时间远比它成为多语言工具的时间长，而且 LLM 使用的训练数据早于最新功能。当你给 AI 代理真正查找当前文档的能力时，它就不再猜测，开始变得有用了。&lt;/p&gt;
&lt;h2 id="三个命令零个浏览器标签页"&gt;三个命令，零个浏览器标签页&lt;/h2&gt;
&lt;p&gt;CLI 简洁得令人耳目一新：&lt;/p&gt;
&lt;h3 id="列出所有文档"&gt;列出所有文档&lt;/h3&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;aspire docs list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;返回 aspire.dev 上所有可用的文档页面。需要机器可读的输出？加上 &lt;code&gt;--format Json&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="搜索主题"&gt;搜索主题&lt;/h3&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;aspire docs search &lt;span class="s2"&gt;&amp;#34;redis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同时搜索标题和内容，使用加权相关性评分。与内部驱动文档工具的搜索引擎完全一样。你会得到带有标题、slug 和相关性分数的排名结果。&lt;/p&gt;
&lt;h3 id="阅读完整页面或仅一个章节"&gt;阅读完整页面（或仅一个章节）&lt;/h3&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;aspire docs get redis-integration
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将完整页面以 markdown 格式流式传输到你的终端。只需要一个章节？&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;aspire docs get redis-integration --section &lt;span class="s2"&gt;&amp;#34;Add Redis resource&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;精准定位。不用滚动 500 行。只看你需要的部分。&lt;/p&gt;
&lt;h2 id="ai-代理的视角"&gt;AI 代理的视角&lt;/h2&gt;
&lt;p&gt;对于我们这些使用 AI 工具进行开发的人来说，这才是真正有趣的地方。同样的 &lt;code&gt;aspire docs&lt;/code&gt; 命令可以作为 AI 代理的工具——通过技能、MCP 服务器或简单的 CLI 封装。&lt;/p&gt;
&lt;p&gt;你的 AI 助手不再根据过时的训练数据编造 Aspire API，而是可以调用 &lt;code&gt;aspire docs search &amp;quot;postgres&amp;quot;&lt;/code&gt;，找到官方集成文档，阅读正确的页面，给你文档记录的方案。实时的、最新的文档——而不是模型六个月前记住的内容。&lt;/p&gt;
&lt;p&gt;背后的架构是有意为之的。Aspire 团队构建了可复用的服务（&lt;code&gt;IDocsIndexService&lt;/code&gt;、&lt;code&gt;IDocsSearchService&lt;/code&gt;、&lt;code&gt;IDocsFetcher&lt;/code&gt;、&lt;code&gt;IDocsCache&lt;/code&gt;），而不是一次性集成。这意味着同一个搜索引擎为终端中的人类、编辑器中的 AI 代理以及 CI 流水线中的自动化服务。&lt;/p&gt;
&lt;h2 id="真实场景"&gt;真实场景&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;终端快速查询：&lt;/strong&gt; 你已经深入到第三个文件，需要 Redis 配置参数。两个命令，九十秒，回去干活：&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;aspire docs search &lt;span class="s2"&gt;&amp;#34;redis&amp;#34;&lt;/span&gt; --limit &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs get redis-integration --section &lt;span class="s2"&gt;&amp;#34;Configuration&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;AI 辅助开发：&lt;/strong&gt; 你的 VS Code 技能封装了 CLI 命令。你问&amp;quot;给我的 AppHost 添加一个 PostgreSQL 数据库&amp;quot;，代理在回答之前先查阅真实文档。没有幻觉。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CI/CD 验证：&lt;/strong&gt; 你的流水线以编程方式根据官方文档验证 AppHost 配置。&lt;code&gt;--format Json&lt;/code&gt; 输出可以干净地通过管道传递给 &lt;code&gt;jq&lt;/code&gt; 和其他工具。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自定义知识库：&lt;/strong&gt; 在构建自己的 AI 工具？将结构化 JSON 输出直接导入你的知识库：&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;aspire docs search &lt;span class="s2"&gt;&amp;#34;monitoring&amp;#34;&lt;/span&gt; --format Json &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;[.[] | {slug, title, summary}]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不需要网页抓取。不需要 API 密钥。与文档工具内部使用的完全一样的结构化数据。&lt;/p&gt;
&lt;h2 id="文档始终是最新的"&gt;文档始终是最新的&lt;/h2&gt;
&lt;p&gt;这是我最欣赏的部分。CLI 不会下载快照——它通过基于 ETag 的缓存查询 aspire.dev。文档一旦更新，你的 CLI 和构建在其之上的所有技能都会反映出来。没有过时的副本，没有&amp;quot;但是 wiki 上说的是&amp;hellip;&amp;ldquo;的尴尬时刻。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;aspire docs&lt;/code&gt; 是那种以简洁方式解决真实问题的小功能之一。人类获得了终端原生的文档访问。AI 代理获得了停止猜测、开始引用真实文档的方式。而且一切都由同一个事实来源支撑。&lt;/p&gt;
&lt;p&gt;如果你正在使用 .NET Aspire 开发，还没试过这个 CLI，运行 &lt;code&gt;aspire docs search &amp;quot;你的主题&amp;quot;&lt;/code&gt; 看看感觉如何。然后考虑将这些命令封装到你正在使用的任何 AI 技能或自动化设置中——你的代理会感谢你的。&lt;/p&gt;
&lt;p&gt;查看 &lt;a href="https://davidpine.dev/posts/aspire-docs-mcp-tools/"&gt;David Pine 的深入分析&lt;/a&gt;了解文档工具是如何构建的，以及&lt;a href="https://aspire.dev/reference/cli/commands/aspire-docs/"&gt;官方 CLI 参考&lt;/a&gt;获取所有细节。&lt;/p&gt;</content:encoded></item><item><title>Microsoft Agent Framework 正式发布 1.0 — 这些才是 .NET 开发者真正需要关注的</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-framework-1-0-production-ready/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-framework-1-0-production-ready/</guid><description>Microsoft Agent Framework 1.0 已具备生产环境就绪能力，拥有稳定的 API、多代理编排以及所有主流 AI 提供商的连接器。以下是作为 .NET 开发者你需要了解的内容。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。如需查看原文，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agent-framework-1-0-production-ready/"&gt;点击此处&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你一直在关注 Agent Framework 从早期 Semantic Kernel 和 AutoGen 时代走来的历程，这次的消息意义重大。Microsoft Agent Framework 刚刚&lt;a href="https://devblogs.microsoft.com/agent-framework/microsoft-agent-framework-version-1-0/"&gt;发布了 1.0 版本&lt;/a&gt; — 生产就绪、API 稳定、长期支持承诺。它同时支持 .NET 和 Python，并且真正可以承载实际工作负载。&lt;/p&gt;
&lt;p&gt;让我跳过公告的噪音，专注于你用 .NET 构建 AI 驱动应用时真正重要的内容。&lt;/p&gt;
&lt;h2 id="简短版本"&gt;简短版本&lt;/h2&gt;
&lt;p&gt;Agent Framework 1.0 将之前的 Semantic Kernel 和 AutoGen 统一为一个开源 SDK。一个代理抽象。一个编排引擎。多个 AI 提供商。如果你之前一直在 Semantic Kernel（企业模式）和 AutoGen（研究级多代理工作流）之间来回切换，现在可以停了。这就是那个唯一的 SDK。&lt;/p&gt;
&lt;h2 id="入门简单得几乎不公平"&gt;入门简单得几乎不公平&lt;/h2&gt;
&lt;p&gt;这是一个在 .NET 中运行的代理：&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="c1"&gt;// dotnet add package Microsoft.Agents.AI.OpenAI --prerelease&lt;/span&gt;
&lt;/span&gt;&lt;/span&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&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="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Foundry&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="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Identity&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;https://your-project.services.ai.azure.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;GetResponsesClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-5.3&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;AsAIAgent&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;HaikuBot&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;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are an upbeat assistant that writes beautifully.&amp;#34;&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Write a haiku about shipping 1.0.&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;就这些。几行代码，你就有了一个在 Azure Foundry 上运行的 AI 代理。Python 的等效代码同样简洁。随着需求增长，逐步添加函数工具、多轮对话和流式输出 — API 表面会平稳地扩展，不会变得奇怪。&lt;/p&gt;
&lt;h2 id="多代理编排--这才是真正的核心"&gt;多代理编排 — 这才是真正的核心&lt;/h2&gt;
&lt;p&gt;单个代理对演示来说够了，但生产场景通常需要协调。Agent Framework 1.0 附带了经过实战考验的编排模式，直接来自 Microsoft Research 和 AutoGen：&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; — 一个代理根据意图委托给另一个代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;群组聊天&lt;/strong&gt; — 多个代理讨论并收敛到一个解决方案&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Magentic-One&lt;/strong&gt; — 来自 MSR 的研究级多代理模式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有这些都支持流式处理、检查点、人机回路审批以及暂停/恢复。检查点部分至关重要 — 长时间运行的工作流在进程重启后依然可以恢复。对于我们这些用 Azure Functions 构建过持久工作流的 .NET 开发者来说，这感觉很熟悉。&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; 你知道 ASP.NET Core 有中间件管道吗？同样的概念，但用于代理执行。拦截每个阶段 — 添加内容安全、日志记录、合规策略 — 而无需触碰代理的提示词。这就是让代理达到企业级标准的方式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可插拔内存。&lt;/strong&gt; 对话历史、持久键值状态、基于向量的检索。选择你的后端：Foundry Agent Service、Mem0、Redis、Neo4j，或者自己实现。内存是将无状态的 LLM 调用变成真正能记住上下文的代理的关键。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;声明式 YAML 代理。&lt;/strong&gt; 在版本控制的 YAML 文件中定义代理的指令、工具、内存和编排拓扑。通过单个 API 调用加载和运行。这对于想要在不重新部署代码的情况下迭代代理行为的团队来说是颠覆性的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A2A 和 MCP 支持。&lt;/strong&gt; MCP（Model Context Protocol）让代理能够动态发现和调用外部工具。A2A（Agent-to-Agent 协议）实现跨运行时协作 — 你的 .NET 代理可以与其他框架中运行的代理进行协调。A2A 1.0 支持即将推出。&lt;/p&gt;
&lt;h2 id="值得关注的预览功能"&gt;值得关注的预览功能&lt;/h2&gt;
&lt;p&gt;1.0 中有些功能以预览形式发布 — 功能可用但 API 可能会演进：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DevUI&lt;/strong&gt; — 一个基于浏览器的本地调试器，用于实时可视化代理执行、消息流和工具调用。可以把它想象成 Application Insights，但用于代理推理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot SDK 和 Claude Code SDK&lt;/strong&gt; — 直接从编排代码中使用 Copilot 或 Claude 作为代理工具。在同一工作流中将编程代理与其他代理组合在一起。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Harness&lt;/strong&gt; — 一个可定制的本地运行时，为代理提供对 shell、文件系统和消息循环的访问。可以理解为编码代理和自动化模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skills&lt;/strong&gt; — 可复用的领域能力包，为代理提供开箱即用的结构化能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="从-semantic-kernel-或-autogen-迁移"&gt;从 Semantic Kernel 或 AutoGen 迁移&lt;/h2&gt;
&lt;p&gt;如果你有现有的 Semantic Kernel 或 AutoGen 代码，有专门的迁移助手可以分析你的代码并生成逐步迁移计划。&lt;a href="https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel"&gt;Semantic Kernel 迁移指南&lt;/a&gt;和 &lt;a href="https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-autogen"&gt;AutoGen 迁移指南&lt;/a&gt;会引导你完成所有步骤。&lt;/p&gt;
&lt;p&gt;如果你一直在使用 RC 包，升级到 1.0 只需更改版本号。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Agent Framework 1.0 是企业团队一直在等待的生产里程碑。稳定的 API、多提供商支持、真正能在大规模下运行的编排模式，以及从 Semantic Kernel 和 AutoGen 的迁移路径。&lt;/p&gt;
&lt;p&gt;该框架已&lt;a href="https://github.com/microsoft/agent-framework"&gt;在 GitHub 上完全开源&lt;/a&gt;，你今天就可以通过 &lt;code&gt;dotnet add package Microsoft.Agents.AI&lt;/code&gt; 开始使用。查看&lt;a href="https://learn.microsoft.com/en-us/agent-framework/get-started/"&gt;快速入门指南&lt;/a&gt;和&lt;a href="https://github.com/microsoft/agent-framework"&gt;示例&lt;/a&gt;来动手实践。&lt;/p&gt;
&lt;p&gt;如果你一直在等待&amp;quot;可以安全用于生产&amp;quot;的信号 — 就是现在。&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2的Dashboard现在有了遥测API — 这改变了一切</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-dashboard-export-telemetry/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-dashboard-export-telemetry/</guid><description>.NET Aspire 13.2带来了更智能的遥测导出、可编程的trace和日志API，以及GenAI可视化改进。了解为什么这对你的调试工作流很重要。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/aspire-132-dashboard-export-telemetry/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你一直在用 .NET Aspire 构建分布式应用，你已经知道dashboard是整个体验中最棒的部分。所有的trace、日志和指标都在一个地方 — 不需要外部的Jaeger，不需要Seq配置，不需要&amp;quot;让我看看另一个终端&amp;quot;的时刻。&lt;/p&gt;
&lt;p&gt;Aspire 13.2 刚刚做了重大改进。James Newton-King &lt;a href="https://devblogs.microsoft.com/aspire/aspire-dashboard-improvements-export-and-telemetry/"&gt;发布了更新公告&lt;/a&gt;，说实话，单是遥测导出和API功能就值得升级。&lt;/p&gt;
&lt;h2 id="像正常人一样导出遥测数据"&gt;像正常人一样导出遥测数据&lt;/h2&gt;
&lt;p&gt;这是我们都经历过的场景：你在调试一个分布式问题，花了二十分钟终于复现了，现在你需要和团队分享发生了什么。之前？截图。复制粘贴trace ID。一如既往的混乱。&lt;/p&gt;
&lt;p&gt;Aspire 13.2 添加了一个&lt;strong&gt;管理日志和遥测&lt;/strong&gt;对话框，你可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;清除所有遥测（在复现bug之前很有用）&lt;/li&gt;
&lt;li&gt;将选定的遥测数据导出为标准OTLP/JSON格式的ZIP文件&lt;/li&gt;
&lt;li&gt;稍后将该ZIP重新导入任何Aspire dashboard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一点是杀手级功能。你复现一个bug，导出遥测数据，附加到工作项，你的队友可以导入到自己的dashboard中，看到你所看到的完全一样的内容。不再需要&amp;quot;你能在你的机器上复现吗？&amp;quot;&lt;/p&gt;
&lt;p&gt;单个trace、span和日志也在上下文菜单中有了&amp;quot;Export JSON&amp;quot;选项。需要分享一个特定的trace？右键点击，复制JSON，粘贴到PR描述中。搞定。&lt;/p&gt;
&lt;h2 id="遥测api才是真正的革命性变化"&gt;遥测API才是真正的革命性变化&lt;/h2&gt;
&lt;p&gt;这是最让我兴奋的。Dashboard现在在&lt;code&gt;/api/telemetry&lt;/code&gt;下暴露了HTTP API，用于编程式查询遥测数据。可用端点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/resources&lt;/code&gt; — 列出有遥测数据的资源&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/spans&lt;/code&gt; — 带过滤器查询span&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/logs&lt;/code&gt; — 带过滤器查询日志&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/traces&lt;/code&gt; — 列出trace&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/traces/{traceId}&lt;/code&gt; — 获取特定trace的所有span&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一切都以OTLP JSON格式返回。这驱动了新的CLI命令&lt;code&gt;aspire agent mcp&lt;/code&gt;和&lt;code&gt;aspire otel&lt;/code&gt;，但真正的意义更大：你现在可以构建工具、脚本和AI代理集成，直接查询你应用的遥测数据。&lt;/p&gt;
&lt;p&gt;想象一个AI编码代理在调试时能看到你实际的分布式trace。这不再是假设 — 这就是这个API所实现的。&lt;/p&gt;
&lt;h2 id="genai遥测变得实用"&gt;GenAI遥测变得实用&lt;/h2&gt;
&lt;p&gt;如果你正在用Semantic Kernel或Microsoft.Extensions.AI构建AI驱动的应用，你会喜欢改进的GenAI遥测可视化器。Aspire 13.2 新增了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI工具描述以Markdown渲染&lt;/li&gt;
&lt;li&gt;Trace页面上的专用GenAI按钮，方便快速访问&lt;/li&gt;
&lt;li&gt;对截断或非标准GenAI JSON更好的错误处理&lt;/li&gt;
&lt;li&gt;工具定义之间的点击高亮导航&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文章提到VS Code Copilot chat、Copilot CLI和OpenCode都支持配置&lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;。将它们指向Aspire dashboard，你可以通过遥测数据实时观看你的AI代理思考过程。这是你在其他任何地方都找不到的调试体验。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Aspire 13.2将dashboard从&amp;quot;不错的调试UI&amp;quot;转变为&amp;quot;可编程的可观测性平台&amp;quot;。单是导出/导入工作流就能在分布式调试中节省真实时间，而遥测API为AI辅助诊断打开了大门。&lt;/p&gt;
&lt;p&gt;如果你已经在用Aspire，升级吧。如果还没有 — 这是一个了解&lt;a href="https://aspire.dev"&gt;aspire.dev&lt;/a&gt;的好理由。&lt;/p&gt;</content:encoded></item><item><title>azd现在可以在本地运行和调试AI代理了 — 2026年3月都有哪些变化</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-march-2026-local-ai-agent-debugging/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-march-2026-local-ai-agent-debugging/</guid><description>Azure Developer CLI在2026年3月发布了七个版本。亮点：AI代理的本地运行和调试循环、GitHub Copilot项目设置集成、Container App Jobs支持。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azd-march-2026-local-ai-agent-debugging/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一个月七个版本。这是Azure Developer CLI (&lt;code&gt;azd&lt;/code&gt;) 团队在2026年3月发布的成果，而头条功能正是我一直在等的：&lt;strong&gt;AI代理的本地运行和调试循环&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;PC Chan &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-march-2026/"&gt;发布了完整摘要&lt;/a&gt;，虽然内容很多，但让我筛选出对构建AI驱动应用的.NET开发者真正重要的部分。&lt;/p&gt;
&lt;h2 id="不用部署就能运行和调试ai代理"&gt;不用部署就能运行和调试AI代理&lt;/h2&gt;
&lt;p&gt;这是最大的亮点。新的 &lt;code&gt;azure.ai.agents&lt;/code&gt; 扩展添加了一组命令，为AI代理提供了完整的内循环体验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;azd ai agent run&lt;/code&gt; — 在本地启动你的代理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent invoke&lt;/code&gt; — 向其发送消息（本地或已部署的）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent show&lt;/code&gt; — 显示容器状态和健康状况&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent monitor&lt;/code&gt; — 实时流式传输容器日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以前，测试AI代理意味着每次修改都要部署到Microsoft Foundry。现在你可以在本地迭代，测试代理行为，准备好了再部署。&lt;/p&gt;
&lt;h2 id="github-copilot为你配置azd项目"&gt;GitHub Copilot为你配置azd项目&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd init&lt;/code&gt; 现在提供了&amp;quot;Set up with GitHub Copilot (Preview)&amp;ldquo;选项。无需手动回答关于项目结构的提示，Copilot代理为你生成配置。当命令失败时，&lt;code&gt;azd&lt;/code&gt; 提供AI辅助的问题排查——全程不需要离开终端。&lt;/p&gt;
&lt;h2 id="container-app-jobs和部署改进"&gt;Container App Jobs和部署改进&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Container App Jobs&lt;/strong&gt;：&lt;code&gt;azd&lt;/code&gt;现在通过现有的&lt;code&gt;host: containerapp&lt;/code&gt;配置部署&lt;code&gt;Microsoft.App/jobs&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可配置的部署超时&lt;/strong&gt;：&lt;code&gt;azd deploy&lt;/code&gt;的新&lt;code&gt;--timeout&lt;/code&gt;标志和&lt;code&gt;azure.yaml&lt;/code&gt;中的&lt;code&gt;deployTimeout&lt;/code&gt;字段。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;远程构建回退&lt;/strong&gt;：当ACR构建失败时，&lt;code&gt;azd&lt;/code&gt;自动回退到本地Docker/Podman构建。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地预检验证&lt;/strong&gt;：部署前在本地验证Bicep参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="开发体验改进"&gt;开发体验改进&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自动检测pnpm/yarn&lt;/strong&gt; — JS/TS项目&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pyproject.toml支持&lt;/strong&gt; — Python打包&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地模板目录&lt;/strong&gt; — &lt;code&gt;azd init --template&lt;/code&gt;接受文件系统路径&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更好的错误消息&lt;/strong&gt; — &lt;code&gt;--no-prompt&lt;/code&gt;模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构建环境变量&lt;/strong&gt; — 注入到所有框架构建子进程（.NET、Node.js、Java、Python）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;本地AI代理调试循环是这个版本的明星，但部署改进和DX优化的积累使&lt;code&gt;azd&lt;/code&gt;比以往更加成熟。如果你在Azure上部署.NET应用——特别是AI代理——这次更新值得关注。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-march-2026/"&gt;完整发行说明&lt;/a&gt;了解所有细节。&lt;/p&gt;</content:encoded></item><item><title>Azure DevOps终于修好了所有人都在抱怨的Markdown编辑器</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-markdown-editor-work-items/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-markdown-editor-work-items/</guid><description>Azure DevOps的工作项Markdown编辑器获得了更清晰的预览与编辑模式区分。一个小改动，却解决了一个真正恼人的工作流问题。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-markdown-editor-work-items/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你使用Azure Boards，你可能经历过这种情况：你在阅读一个工作项描述，也许在检查验收标准，然后不小心双击了。砰——你进入了编辑模式。你根本不想编辑任何东西。你只是在阅读。&lt;/p&gt;
&lt;p&gt;Dan Hellem &lt;a href="https://devblogs.microsoft.com/devops/improving-the-markdown-editor-for-work-items/"&gt;宣布了这个修复&lt;/a&gt;，这是那种听起来很小但确实从日常工作流中消除了真正摩擦的改动。&lt;/p&gt;
&lt;h2 id="什么变了"&gt;什么变了&lt;/h2&gt;
&lt;p&gt;工作项文本字段的Markdown编辑器现在&lt;strong&gt;默认以预览模式打开&lt;/strong&gt;。你可以阅读和交互内容——跟随链接、检查格式——不用担心意外进入编辑模式。&lt;/p&gt;
&lt;p&gt;当你真的想要编辑时，点击字段顶部的编辑图标。完成后，显式退出到预览模式。简单、有意图、可预测。&lt;/p&gt;
&lt;h2 id="为什么这比听起来更重要"&gt;为什么这比听起来更重要&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://developercommunity.visualstudio.com/t/Markdown-editor-for-work-item-multi-line/10935496"&gt;社区反馈帖子&lt;/a&gt;很长。双击编辑的行为是在2025年7月随Markdown编辑器引入的，投诉几乎立刻开始了。&lt;/p&gt;
&lt;p&gt;对于使用Azure Boards进行冲刺计划、需求梳理或代码审查的团队来说，这种微摩擦会累积。&lt;/p&gt;
&lt;h2 id="部署状态"&gt;部署状态&lt;/h2&gt;
&lt;p&gt;已经在向部分客户推出，将在未来两到三周内扩展到所有人。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;不是每个改进都需要成为头条功能。有时候最好的更新就是简单地移除恼人的东西。这就是其中之一——一个小小的UX修复，让Azure Boards对只想安静阅读工作项的人变得不再那么敌意。&lt;/p&gt;</content:encoded></item><item><title>Bookmark Studio为Visual Studio书签带来基于槽位的导航和分享功能</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/bookmark-studio-visual-studio-extension/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/bookmark-studio-visual-studio-extension/</guid><description>Mads Kristensen的新Bookmark Studio扩展为Visual Studio书签添加了键盘驱动的槽位导航、书签管理器、颜色、标签和导出功能。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/bookmark-studio-visual-studio-extension/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Visual Studio中的书签一直&amp;hellip;还行。你设置一个，导航到下一个，然后忘记哪个是哪个。它们能用，但从来不是你会称之为强大的功能。&lt;/p&gt;
&lt;p&gt;Mads Kristensen刚刚&lt;a href="https://devblogs.microsoft.com/visualstudio/bookmark-studio-evolving-bookmarks-in-visual-studio/"&gt;发布了Bookmark Studio&lt;/a&gt;，一个实验性扩展，精确填补了你可能遇到的空缺。&lt;/p&gt;
&lt;h2 id="基于槽位的导航"&gt;基于槽位的导航&lt;/h2&gt;
&lt;p&gt;书签可以分配到1-9号槽位，通过&lt;code&gt;Alt+Shift+1&lt;/code&gt;到&lt;code&gt;Alt+Shift+9&lt;/code&gt;直接跳转。新书签自动获得下一个可用槽位。&lt;/p&gt;
&lt;h2 id="书签管理器"&gt;书签管理器&lt;/h2&gt;
&lt;p&gt;新的工具窗口在一个地方显示所有书签，支持按名称、文件、位置、颜色或槽位过滤。&lt;/p&gt;
&lt;h2 id="用标签颜色和文件夹组织"&gt;用标签、颜色和文件夹组织&lt;/h2&gt;
&lt;p&gt;书签可以有标签、颜色，并分组到文件夹中。元数据按解决方案存储。&lt;/p&gt;
&lt;h2 id="导出和分享"&gt;导出和分享&lt;/h2&gt;
&lt;p&gt;Bookmark Studio允许将书签导出为纯文本、Markdown或CSV。&lt;/p&gt;
&lt;h2 id="跟随代码移动的书签"&gt;跟随代码移动的书签&lt;/h2&gt;
&lt;p&gt;Bookmark Studio相对于锚定的文本跟踪书签，所以编辑时不会漂移到错误的行。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Bookmark Studio没有重新发明任何东西。它把一个多年来&amp;quot;够用&amp;quot;的功能变得真正有用。从&lt;a href="https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BookmarkStudio"&gt;Visual Studio Marketplace&lt;/a&gt;下载吧。&lt;/p&gt;</content:encoded></item><item><title>Visual Studio 3月更新允许构建自定义Copilot代理 — find_symbol是一大亮点</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-march-2026-custom-copilot-agents/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-march-2026-custom-copilot-agents/</guid><description>Visual Studio 2026年3月更新带来了自定义Copilot代理、可复用的代理技能、语言感知的find_symbol工具、以及从Test Explorer进行的Copilot性能分析。</description><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原始版本，请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/visual-studio-march-2026-custom-copilot-agents/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Visual Studio刚刚获得了最重要的Copilot更新。Mark Downie &lt;a href="https://devblogs.microsoft.com/visualstudio/visual-studio-march-update-build-your-own-custom-agents/"&gt;发布了3月版本&lt;/a&gt;，标题是自定义代理——但说实话，&lt;code&gt;find_symbol&lt;/code&gt;工具可能才是最能改变你工作流的功能。&lt;/p&gt;
&lt;h2 id="仓库中的自定义copilot代理"&gt;仓库中的自定义Copilot代理&lt;/h2&gt;
&lt;p&gt;想让Copilot遵循你团队的编码标准？自定义代理定义为&lt;code&gt;.github/agents/&lt;/code&gt;中的&lt;code&gt;.agent.md&lt;/code&gt;文件。每个代理都有完整的工作区感知、代码理解、工具、首选模型和MCP连接访问权限。&lt;/p&gt;
&lt;h2 id="代理技能可复用的指令包"&gt;代理技能：可复用的指令包&lt;/h2&gt;
&lt;p&gt;技能从仓库的&lt;code&gt;.github/skills/&lt;/code&gt;或个人资料的&lt;code&gt;~/.copilot/skills/&lt;/code&gt;自动加载。&lt;/p&gt;
&lt;h2 id="find_symbol语言感知导航"&gt;find_symbol：语言感知导航&lt;/h2&gt;
&lt;p&gt;新的&lt;code&gt;find_symbol&lt;/code&gt;工具为Copilot的代理模式提供了基于语言服务的符号导航。代理不再搜索文本，而是可以找到符号的所有引用并访问类型信息和作用域。&lt;/p&gt;
&lt;p&gt;对于.NET开发者来说这是巨大改进——拥有深层类型层次结构的C#代码库受益匪浅。&lt;/p&gt;
&lt;h2 id="用copilot分析测试性能"&gt;用Copilot分析测试性能&lt;/h2&gt;
&lt;p&gt;Test Explorer上下文菜单中新增了&lt;strong&gt;Profile with Copilot&lt;/strong&gt;。Profiling Agent自动运行测试并分析性能。&lt;/p&gt;
&lt;h2 id="实时调试中的perf-tips"&gt;实时调试中的Perf Tips&lt;/h2&gt;
&lt;p&gt;性能优化现在在调试过程中进行。Visual Studio内联显示执行时间。看到慢的行？点击Perf Tip向Copilot请求优化建议。&lt;/p&gt;
&lt;h2 id="从solution-explorer修复nuget漏洞"&gt;从Solution Explorer修复NuGet漏洞&lt;/h2&gt;
&lt;p&gt;当检测到NuGet包漏洞时，Solution Explorer中直接显示&lt;strong&gt;Fix with GitHub Copilot&lt;/strong&gt;链接。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;自定义代理和技能是标题，但&lt;code&gt;find_symbol&lt;/code&gt;是隐藏的亮点——它从根本上改变了Copilot重构.NET代码时的准确性。下载&lt;a href="https://visualstudio.microsoft.com/downloads/"&gt;Visual Studio 2026 Insiders&lt;/a&gt;来体验所有新功能。&lt;/p&gt;</content:encoded></item><item><title>KubeCon Europe 2026：.NET 开发者真正需要关注的内容</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/kubecon-2026-aks-updates-dotnet-developers/</link><pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/kubecon-2026-aks-updates-dotnet-developers/</guid><description>微软在 KubeCon Europe 2026 上发布了大量 Kubernetes 公告。这是过滤后的版本——只有当你在交付 .NET 应用时真正重要的 AKS 和云原生更新。</description><content:encoded>&lt;p&gt;&lt;em&gt;本文为自动翻译。查看原文请&lt;a href="https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/kubecon-2026-aks-updates-dotnet-developers/"&gt;点击这里&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;你知道那种感觉吗？一个巨大的公告文章出来了，你一边滚动一边想&amp;quot;不错，但这对我到底有什么改变&amp;quot;？这就是我每个 KubeCon 季的状态。&lt;/p&gt;
&lt;p&gt;微软刚刚发布了他们的 &lt;a href="https://opensource.microsoft.com/blog/2026/03/24/whats-new-with-microsoft-in-open-source-and-kubernetes-at-kubecon-cloudnativecon-europe-2026/"&gt;KubeCon Europe 2026 完整总结&lt;/a&gt;——出自 Brendan Burns 本人之手——说实话？这次有真正的干货。不只是功能清单，而是真正改变你在生产环境中运维方式的运营改进。&lt;/p&gt;
&lt;p&gt;让我来梳理一下对我们 .NET 开发者真正重要的内容。&lt;/p&gt;
&lt;h2 id="不用付服务网格税的-mtls"&gt;不用付服务网格税的 mTLS&lt;/h2&gt;
&lt;p&gt;服务网格的问题在于：每个人都想要安全保障，没人想要运营负担。AKS 终于在弥补这个差距了。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://aka.ms/aks/application-network"&gt;Azure Kubernetes Application Network&lt;/a&gt; 给你提供了双向 TLS、应用感知授权和流量遥测——不需要部署一个带 sidecar 的重型 mesh。结合 &lt;a href="https://aka.ms/acns/cilium-mtls"&gt;Advanced Container Networking Services 中的 Cilium mTLS&lt;/a&gt;，你可以获得使用 X.509 证书和 SPIRE 身份管理的加密 pod 间通信。&lt;/p&gt;
&lt;p&gt;这在实践中意味着什么：你的 ASP.NET Core API 与后台 worker 通信，你的 gRPC 服务互相调用——全部在网络层加密和身份验证，零应用代码更改。这意义重大。&lt;/p&gt;
&lt;p&gt;对于从 &lt;code&gt;ingress-nginx&lt;/code&gt; 迁移的团队，还有 &lt;a href="https://aka.ms/aks/app-routing/gateway-api"&gt;Meshless Istio 的 Application Routing&lt;/a&gt; 全面支持 Kubernetes Gateway API。无 sidecar。基于标准。并且发布了 &lt;code&gt;ingress2gateway&lt;/code&gt; 工具用于增量迁移。&lt;/p&gt;
&lt;h2 id="不再是事后想到的-gpu-可观测性"&gt;不再是事后想到的 GPU 可观测性&lt;/h2&gt;
&lt;p&gt;如果你在 .NET 服务旁运行 AI 推理（说实话，谁现在还没开始？），你可能遇到过 GPU 监控盲区。CPU/内存仪表板很棒，然后 GPU 部分…没有手动配置导出器就什么都没有。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://aka.ms/aks/managed-gpu-metrics"&gt;AKS 现在原生暴露 GPU 指标&lt;/a&gt; 到托管的 Prometheus 和 Grafana。同样的技术栈，同样的仪表板，同样的告警管道。无需自定义导出器，无需第三方代理。&lt;/p&gt;
&lt;p&gt;在网络方面，增加了 HTTP、gRPC 和 Kafka 流量的逐流可见性，配合&lt;a href="https://learn.microsoft.com/en-us/azure/aks/container-network-observability-logs"&gt;一键 Azure Monitor 体验&lt;/a&gt;。IP、端口、工作负载、流方向、策略决策——全部在内置仪表板中。&lt;/p&gt;
&lt;p&gt;让我看了两遍的是：&lt;a href="https://learn.microsoft.com/en-us/azure/aks/advanced-container-networking-services-overview"&gt;agentic container networking&lt;/a&gt; 添加了一个 Web UI，你可以用自然语言询问集群的网络状态。&amp;ldquo;为什么 pod X 无法到达服务 Y？&amp;quot;→ 从实时遥测获取只读诊断。凌晨两点真的很有用。&lt;/p&gt;
&lt;h2 id="不需要博士学位的跨集群网络"&gt;不需要博士学位的跨集群网络&lt;/h2&gt;
&lt;p&gt;多集群 Kubernetes 历来是&amp;quot;自带网络胶水&amp;quot;的体验。Azure Kubernetes Fleet Manager 现在通过托管 Cilium 集群网格提供&lt;a href="https://aka.ms/kubernetes-fleet/networking/cross-cluster"&gt;跨集群网络&lt;/a&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AKS 集群间的统一连接&lt;/li&gt;
&lt;li&gt;用于跨集群发现的全局服务注册表&lt;/li&gt;
&lt;li&gt;集中管理配置，而不是每个集群重复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你为了弹性或合规在多个区域运行 .NET 微服务，这替代了很多脆弱的自定义胶水。West Europe 的服务 A 可以通过网格发现和调用 East US 的服务 B，使用一致的路由和安全策略。&lt;/p&gt;
&lt;h2 id="不需要勇气的升级"&gt;不需要勇气的升级&lt;/h2&gt;
&lt;p&gt;说实话——生产环境中的 Kubernetes 升级是有压力的。&amp;ldquo;升级然后祈祷&amp;quot;一直是太多团队的实际策略，也是集群版本落后的主要原因。&lt;/p&gt;
&lt;p&gt;两个新功能改变了这一点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blue-green 代理池升级&lt;/strong&gt; 用新配置创建一个并行节点池。验证行为，逐步转移流量，保持干净的回滚路径。不再在生产节点上进行就地变更。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代理池回滚&lt;/strong&gt; 允许你在升级出问题后将节点池恢复到之前的 Kubernetes 版本和节点镜像——无需重建集群。&lt;/p&gt;
&lt;p&gt;两者结合，终于给运维人员提供了对升级生命周期的真正控制。对于 .NET 团队来说很重要，因为平台速度直接控制你能多快采用新的运行时、安全补丁和网络能力。&lt;/p&gt;
&lt;h2 id="ai-工作负载成为-kubernetes-一等公民"&gt;AI 工作负载成为 Kubernetes 一等公民&lt;/h2&gt;
&lt;p&gt;上游开源工作同样重要。Dynamic Resource Allocation (DRA) 刚在 Kubernetes 1.36 中 GA，使 GPU 调度成为真正的一等功能而不是变通方案。&lt;/p&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;a href="https://github.com/kaito-project/kubeairunway"&gt;AI Runway&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;推理的通用 Kubernetes API——不懂 K8s 也能部署模型，带 HuggingFace 发现和成本估算&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.cncf.io/blog/2026/01/07/holmesgpt-agentic-troubleshooting-built-for-the-cloud-native-era/"&gt;HolmesGPT&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;云原生的智能体故障排除——现在是 CNCF Sandbox 项目&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/project-dalec/dalec"&gt;Dalec&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;带 SBOM 生成的声明式容器镜像构建——构建阶段减少 CVE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;方向很明确：你的 .NET API、Semantic Kernel 编排层和推理工作负载应该都运行在一个一致的平台模型上。我们正在接近。&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;先搞可观测性&lt;/strong&gt;——在非生产集群中启用 GPU 指标和网络流日志。看看你一直错过了什么。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试 blue-green 升级&lt;/strong&gt;——在下次生产集群升级前测试回滚工作流。建立对流程的信心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;试点身份感知网络&lt;/strong&gt;——选择一个内部服务路径并用 Cilium 启用 mTLS。测量开销（剧透：很小）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估 Fleet Manager&lt;/strong&gt;——如果你运行超过两个集群，跨集群网络光减少自定义胶水就能回本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;小实验，快反馈。这永远是正确的做法。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;KubeCon 公告可能让人应接不暇，但这批更新确实为 AKS 上的 .NET 团队带来了实质性改变。更好的网络安全（无 mesh 开销）、真正的 GPU 可观测性、更安全的升级以及更强大的 AI 基础设施支撑。&lt;/p&gt;
&lt;p&gt;如果你已经在用 AKS，现在是加强运营基准的好时机。如果你计划将 .NET 工作负载迁移到 Kubernetes——平台刚刚变得更加适合生产环境了。&lt;/p&gt;</content:encoded></item><item><title>SQL MCP Server、SSMS 中的 Copilot 以及带 AI 代理的 Database Hub：SQLCon 2026 真正重要的内容</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agentic-ai-microsoft-databases-what-matters/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/agentic-ai-microsoft-databases-what-matters/</guid><description>Microsoft 在 SQLCon 2026 上发布了一系列数据库公告。如果你在 Azure SQL 上构建 AI 应用，这些才是真正重要的内容。</description><content:encoded>&lt;p&gt;Microsoft 刚刚在&lt;a href="https://www.microsoft.com/en-us/sql-server/blog/2026/03/18/advancing-agentic-ai-with-microsoft-databases-across-a-unified-data-estate/"&gt;亚特兰大与 FabCon 同期举办了 SQLCon 2026&lt;/a&gt;，内容非常多。原始公告涵盖了从节省计划到企业合规功能的方方面面。我打算跳过企业定价的幻灯片，专注于对使用 Azure SQL 和 AI 进行开发的人来说真正重要的部分。&lt;/p&gt;
&lt;h2 id="sql-mcp-server"&gt;SQL MCP Server&lt;/h2&gt;
&lt;p&gt;这是我眼中的头条新闻。Azure SQL Database Hyperscale 现在有了一个 &lt;strong&gt;SQL MCP Server&lt;/strong&gt; 公共预览版，让你可以使用 &lt;a href="https://modelcontextprotocol.io/"&gt;Model Context Protocol&lt;/a&gt; 将 SQL 数据安全地连接到 AI 代理和 Copilot。&lt;/p&gt;
&lt;p&gt;如果你一直在关注 MCP 的浪潮——说实话，现在想不注意到都难——这是一个大事件。你不再需要构建自定义数据管道来为 AI 代理提供来自数据库的上下文，而是获得了一个标准化协议来直接公开 SQL 数据。你的代理可以查询、推理并基于实时数据库信息采取行动。&lt;/p&gt;
&lt;p&gt;对于我们这些用 Semantic Kernel 或 Microsoft Agent Framework 构建 AI 代理的人来说，这打开了一条干净的集成路径。你的代理需要检查库存？查找客户记录？验证订单？MCP 提供了一种结构化的方式来做这些事情，而不需要你为每个场景编写定制的数据获取代码。&lt;/p&gt;
&lt;h2 id="ssms-22-中的-github-copilot-现已正式发布"&gt;SSMS 22 中的 GitHub Copilot 现已正式发布&lt;/h2&gt;
&lt;p&gt;如果你在 SQL Server Management Studio 中花过任何时间——说实话，我们大多数人还在用——GitHub Copilot 现在已在 SSMS 22 中正式发布。和你在 VS Code 和 Visual Studio 中使用的 Copilot 体验一样，但用于 T-SQL。&lt;/p&gt;
&lt;p&gt;实际价值很直接：基于聊天的辅助来编写查询、重构存储过程、排查性能问题和处理管理任务。概念上没什么革命性的，但直接在 SSMS 中使用意味着你不需要为了获得数据库工作的 AI 帮助而切换到另一个编辑器。&lt;/p&gt;
&lt;h2 id="向量索引获得了重大升级"&gt;向量索引获得了重大升级&lt;/h2&gt;
&lt;p&gt;Azure SQL Database 现在拥有更快、更强大的向量索引，完全支持插入、更新和删除操作。这意味着你的向量数据可以实时保持最新——不需要批量重建索引。&lt;/p&gt;
&lt;p&gt;新功能如下：&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; 实现可预测的性能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你正在使用 Azure SQL 作为向量存储进行 Retrieval-Augmented Generation (RAG)，这些改进直接有用。你可以将向量和关系数据放在同一个数据库中，相比运行单独的向量数据库，这大大简化了你的架构。&lt;/p&gt;
&lt;p&gt;同样的向量增强功能在 Fabric 中的 SQL Database 也可用，因为两者底层运行的是同一个 SQL 引擎。&lt;/p&gt;
&lt;h2 id="fabric-中的-database-hub代理式管理"&gt;Fabric 中的 Database Hub：代理式管理&lt;/h2&gt;
&lt;p&gt;这个更偏向未来，但很有意思。Microsoft 宣布了 &lt;strong&gt;Microsoft Fabric 中的 Database Hub&lt;/strong&gt;（抢先体验），为你提供跨 Azure SQL、Cosmos DB、PostgreSQL、MySQL 和 SQL Server via Arc 的统一视图。&lt;/p&gt;
&lt;p&gt;有意思的不仅仅是统一视图——而是代理式的管理方法。AI 代理持续监控你的数据库群，展示发生了什么变化，解释为什么重要，并建议下一步该做什么。这是一个人机协作（human-in-the-loop）模型，代理做前期工作，你来做决策。&lt;/p&gt;
&lt;p&gt;对于管理多个数据库的团队来说，这可能真正减少运维噪音。代理把信号带给你，而不是让你在各个门户之间跳来跳去手动检查指标。&lt;/p&gt;
&lt;h2 id="这对-net-开发者意味着什么"&gt;这对 .NET 开发者意味着什么&lt;/h2&gt;
&lt;p&gt;贯穿所有这些公告的主线很清晰：Microsoft 正在将 AI 代理嵌入数据库技术栈的每一层。不是作为噱头，而是作为实用的工具层。&lt;/p&gt;
&lt;p&gt;如果你正在构建基于 Azure SQL 的 .NET 应用，以下是我实际会做的事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;试试 SQL MCP Server&lt;/strong&gt;，如果你在构建 AI 代理的话。这是给代理提供数据库访问最干净的方式，不需要自定义的管道代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在 SSMS 中启用 Copilot&lt;/strong&gt;，如果还没有的话——对日常 SQL 工作来说是免费的生产力提升。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;了解一下向量索引&lt;/strong&gt;，如果你在做 RAG 且目前运行着单独的向量存储。整合到 Azure SQL 意味着少管理一个服务。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;完整公告还有更多内容——节省计划、迁移助手、合规功能——但对开发者来说，重点在 MCP Server、向量改进和代理式管理层。这些才是改变你构建方式的东西，而不仅仅是改变你做预算的方式。&lt;/p&gt;
&lt;p&gt;查看 &lt;a href="https://www.microsoft.com/en-us/sql-server/blog/2026/03/18/advancing-agentic-ai-with-microsoft-databases-across-a-unified-data-estate/"&gt;Shireesh Thota 的完整公告&lt;/a&gt; 获取全貌，如果你想试试新的管理体验，可以&lt;a href="https://aka.ms/database-hub"&gt;注册 Database Hub 抢先体验&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>Azure DevOps MCP Server 登陆 Microsoft Foundry：这对你的 AI 代理意味着什么</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-mcp-server-microsoft-foundry/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/azure-devops-mcp-server-microsoft-foundry/</guid><description>Azure DevOps MCP Server 现已在 Microsoft Foundry 中可用。只需几次点击，即可将你的 AI 代理直接连接到 DevOps 工作流 — 工作项、仓库、管道。</description><content:encoded>&lt;p&gt;MCP（Model Context Protocol）正在迎来它的高光时刻。如果你一直在关注 AI 代理生态系统，你可能已经注意到 MCP 服务器到处涌现 — 通过标准化协议赋予代理与外部工具和服务交互的能力。&lt;/p&gt;
&lt;p&gt;现在 &lt;a href="https://devblogs.microsoft.com/devops/remote-mcp-server-preview-in-microsoft-foundry/"&gt;Azure DevOps MCP Server 已在 Microsoft Foundry 中可用&lt;/a&gt;，这是那种让你思考实际可能性的集成之一。&lt;/p&gt;
&lt;h2 id="这里到底发生了什么"&gt;这里到底发生了什么&lt;/h2&gt;
&lt;p&gt;Microsoft 已经发布了 Azure DevOps MCP Server 的&lt;a href="https://devblogs.microsoft.com/devops/azure-devops-remote-mcp-server-public-preview"&gt;公开预览版&lt;/a&gt; — 那是 MCP 服务器本身。新的是 Foundry 集成。你现在可以直接从工具目录将 Azure DevOps MCP Server 添加到 Foundry 代理中。&lt;/p&gt;
&lt;p&gt;对于还不熟悉 Foundry 的人：它是 Microsoft 用于大规模构建和管理 AI 驱动应用程序和代理的统一平台。模型访问、编排、评估、部署 — 全部在一个地方。&lt;/p&gt;
&lt;h2 id="配置"&gt;配置&lt;/h2&gt;
&lt;p&gt;配置出奇地简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在你的 Foundry 代理中，进入 &lt;strong&gt;Add Tools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Catalog&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;搜索 &amp;ldquo;Azure DevOps&amp;rdquo;&lt;/li&gt;
&lt;li&gt;选择 Azure DevOps MCP Server（preview）并点击 &lt;strong&gt;Create&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;输入你的组织名称并连接&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;就这样。你的代理现在可以访问 Azure DevOps 工具了。&lt;/p&gt;
&lt;h2 id="控制代理可以访问什么"&gt;控制代理可以访问什么&lt;/h2&gt;
&lt;p&gt;这是我欣赏的部分：你不会被困在全有或全无的方式中。你可以指定哪些工具对代理可用。如果你只想让它读取工作项但不碰管道，可以这样配置。最小权限原则，应用到你的 AI 代理上。&lt;/p&gt;
&lt;p&gt;这在企业场景中很重要，你不希望一个代理因为有人让它&amp;quot;帮忙发布&amp;quot;就意外触发部署管道。&lt;/p&gt;
&lt;h2 id="为什么这对-net-团队很有趣"&gt;为什么这对 .NET 团队很有趣&lt;/h2&gt;
&lt;p&gt;想想这在实践中能实现什么：&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; — 因为能实际读取你的仓库和关联的工作项，所以理解你的 PR 上下文的代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件响应&lt;/strong&gt; — 可以创建工作项、查询最近的部署并将 bug 与最近的更改关联的代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发者入职&lt;/strong&gt; — &amp;ldquo;我应该做什么？&amp;ldquo;得到基于实际项目数据的真实回答&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于已经在 CI/CD 管道和项目管理中使用 Azure DevOps 的 .NET 团队来说，拥有一个能直接与这些系统交互的 AI 代理是迈向有用自动化的重要一步。&lt;/p&gt;
&lt;h2 id="更大的-mcp-图景"&gt;更大的 MCP 图景&lt;/h2&gt;
&lt;p&gt;这是更广泛趋势的一部分：MCP 服务器正在成为 AI 代理与外部世界交互的标准方式。我们在 GitHub、Azure DevOps、数据库、SaaS API 中都能看到它们 — 而 Foundry 正在成为所有这些连接汇聚的中心。&lt;/p&gt;
&lt;p&gt;如果你在 .NET 生态系统中构建代理，MCP 值得关注。协议是标准化的，工具正在成熟，Foundry 集成使其无需手动配置服务器连接即可访问。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Foundry 中的 Azure DevOps MCP Server 目前处于预览阶段，所以预计它会继续发展。但核心工作流是可靠的：连接、配置工具访问，让你的代理使用你的 DevOps 数据工作。如果你已经在 Foundry 生态系统中，只需几次点击就能开始。试试看你能构建什么工作流。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/devops/remote-mcp-server-preview-in-microsoft-foundry/"&gt;完整公告&lt;/a&gt;获取完整的配置步骤和更多详情。&lt;/p&gt;</content:encoded></item><item><title>Foundry Agent Service 正式发布：对 .NET 代理开发者真正重要的是什么</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-agent-service-ga-what-matters/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/foundry-agent-service-ga-what-matters/</guid><description>微软的 Foundry Agent Service 刚刚正式发布，带来了私有网络、Voice Live、生产评估和开放的多模型运行时。这是你需要知道的。</description><content:encoded>&lt;p&gt;说实话 — 构建一个 AI 代理原型是简单的部分。困难的是之后的一切：用适当的网络隔离投入生产、运行真正有意义的评估、处理合规要求，以及不在凌晨 2 点搞崩东西。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/foundry/foundry-agent-service-ga/"&gt;Foundry Agent Service 刚刚正式发布&lt;/a&gt;，这个版本像激光一样聚焦在&amp;quot;之后一切&amp;quot;的鸿沟上。&lt;/p&gt;
&lt;h2 id="构建在-responses-api-之上"&gt;构建在 Responses API 之上&lt;/h2&gt;
&lt;p&gt;标题新闻：新一代 Foundry Agent Service 构建在 OpenAI Responses API 之上。如果你已经在用这个 wire protocol 构建，迁移到 Foundry 只需最少的代码改动。你获得的：企业安全、私有网络、Entra RBAC、完整追踪和评估 — 在你现有的代理逻辑之上。&lt;/p&gt;
&lt;p&gt;架构是有意开放的。你不被锁定在一个模型提供商或一个编排框架上。用 DeepSeek 做规划、OpenAI 做生成、LangGraph 做编排 — 运行时处理一致性层。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PromptAgentDefinition&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="k"&gt;with&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;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;credential&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;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_PROJECT_ENDPOINT&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;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;project_client&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;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_openai_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;openai_client&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="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_version&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;agent_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-enterprise-agent&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;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PromptAgentDefinition&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;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&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;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&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="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="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&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="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;What are best practices for building AI agents?&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;extra_body&lt;/span&gt;&lt;span class="o"&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="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&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="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&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;blockquote&gt;
&lt;p&gt;如果你从 &lt;code&gt;azure-ai-agents&lt;/code&gt; 包迁移过来，代理现在是 &lt;code&gt;azure-ai-projects&lt;/code&gt; 中 &lt;code&gt;AIProjectClient&lt;/code&gt; 的一等操作。移除独立依赖，使用 &lt;code&gt;get_openai_client()&lt;/code&gt; 来驱动响应。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="私有网络企业阻碍已移除"&gt;私有网络：企业阻碍已移除&lt;/h2&gt;
&lt;p&gt;这是解锁企业采用的功能。Foundry 现在支持完整的端到端私有网络配合 BYO VNet：&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; — MCP 服务器、Azure AI Search、Fabric 数据代理都通过私有路径运作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一点至关重要。不只是推理调用保持私有 — 每个工具调用和检索调用也都留在你的网络边界内。对于在数据分类策略下禁止外部路由的团队来说，这就是缺失的那块。&lt;/p&gt;
&lt;h2 id="mcp-认证做对了"&gt;MCP 认证做对了&lt;/h2&gt;
&lt;p&gt;MCP 服务器连接现在支持完整的认证模式谱系：&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;/td&gt;
&lt;td&gt;组织范围内部工具的简单共享访问&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entra Agent Identity&lt;/td&gt;
&lt;td&gt;服务间；代理以自身身份认证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entra Managed Identity&lt;/td&gt;
&lt;td&gt;按项目隔离；无凭证管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth Identity Passthrough&lt;/td&gt;
&lt;td&gt;用户委托访问；代理代表用户行事&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;OAuth Identity Passthrough 是有趣的那个。当用户需要授予代理访问他们的个人数据 — 他们的 OneDrive、Salesforce 组织、按用户范围的 SaaS API — 代理使用标准 OAuth 流程代表他们行事。没有假装是所有人的共享系统身份。&lt;/p&gt;
&lt;h2 id="voice-live无需管道工程的语音对语音"&gt;Voice Live：无需管道工程的语音对语音&lt;/h2&gt;
&lt;p&gt;给代理添加语音曾经意味着拼凑 STT、LLM 和 TTS — 三个服务、三次延迟跳转、三个计费面，全部手动同步。&lt;strong&gt;Voice Live&lt;/strong&gt; 将这一切压缩为单个托管 API：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义语音活动和轮次结束检测（理解含义，不仅仅是沉默）&lt;/li&gt;
&lt;li&gt;服务端噪声抑制和回声消除&lt;/li&gt;
&lt;li&gt;插话支持（用户可以在响应中途打断）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;语音交互通过与文本相同的代理运行时。相同的评估器、相同的追踪、相同的成本可见性。对于客户支持、现场服务或无障碍场景，这取代了以前需要自定义音频管道的方案。&lt;/p&gt;
&lt;h2 id="评估从勾选框到持续监控"&gt;评估：从勾选框到持续监控&lt;/h2&gt;
&lt;p&gt;这是 Foundry 认真对待生产质量的地方。评估系统现在有三层：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;开箱即用评估器&lt;/strong&gt; — 连贯性、相关性、扎实度、检索质量、安全性。连接到数据集或实时流量获取分数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;自定义评估器&lt;/strong&gt; — 编码你自己的业务逻辑、语调标准和领域特定合规规则。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;持续评估&lt;/strong&gt; — Foundry 采样实时生产流量，运行你的评估器套件，并在仪表板中显示结果。设置 Azure Monitor 告警以监控扎实度下降或安全阈值突破。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一切发布到 Azure Monitor Application Insights。代理质量、基础设施健康、成本和应用遥测 — 全在一处。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;eval_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&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;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Agent Quality Evaluation&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;data_source_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DataSourceConfigCustom&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="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;custom&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;item_schema&lt;/span&gt;&lt;span class="o"&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="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;object&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="s2"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;string&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="s2"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;query&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="n"&gt;include_sample_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&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="n"&gt;testing_criteria&lt;/span&gt;&lt;span class="o"&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="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;azure_ai_evaluator&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="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;fluency&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="s2"&gt;&amp;#34;evaluator_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;builtin.fluency&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="s2"&gt;&amp;#34;initialization_parameters&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="s2"&gt;&amp;#34;deployment_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&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="s2"&gt;&amp;#34;data_mapping&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="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{{item.query}}&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="s2"&gt;&amp;#34;response&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{{sample.output_text}}&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="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;h2 id="六个新区域支持托管代理"&gt;六个新区域支持托管代理&lt;/h2&gt;
&lt;p&gt;托管代理现在在 East US、North Central US、Sweden Central、Southeast Asia、Japan East 等区域可用。这对数据驻留要求很重要，也有助于在代理靠近数据源运行时压缩延迟。&lt;/p&gt;
&lt;h2 id="为什么这对-net-开发者重要"&gt;为什么这对 .NET 开发者重要&lt;/h2&gt;
&lt;p&gt;虽然 GA 公告中的代码示例是 Python 优先的，但底层基础设施是语言无关的 — &lt;code&gt;azure-ai-projects&lt;/code&gt; 的 .NET SDK 遵循相同的模式。Responses API、评估框架、私有网络、MCP 认证 — 这些都可以从 .NET 使用。&lt;/p&gt;
&lt;p&gt;如果你一直在等 AI 代理从&amp;quot;酷炫演示&amp;quot;变成&amp;quot;我真的可以在工作中交付&amp;quot;，这个 GA 版本就是信号。私有网络、适当的认证、持续评估和生产监控是缺失的那些拼图。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;Foundry Agent Service 现在可用。安装 SDK，打开&lt;a href="https://ai.azure.com"&gt;门户&lt;/a&gt;，开始构建。&lt;a href="https://learn.microsoft.com/azure/foundry/quickstarts/get-started-code"&gt;快速入门指南&lt;/a&gt;带你在几分钟内从零到运行中的代理。&lt;/p&gt;
&lt;p&gt;包含所有代码示例的完整技术深度分析，请查看 &lt;a href="https://devblogs.microsoft.com/foundry/foundry-agent-service-ga/"&gt;GA 公告&lt;/a&gt;。&lt;/p&gt;</content:encoded></item><item><title>Microsoft Agent Framework 中的后台响应：告别超时焦虑</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/background-responses-agent-framework-long-running-tasks/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/background-responses-agent-framework-long-running-tasks/</guid><description>Microsoft Agent Framework 现在允许通过延续令牌卸载长时间运行的 AI 任务。了解后台响应如何工作以及为什么它们对你的 .NET 代理很重要。</description><content:encoded>&lt;p&gt;如果你用 o3 或 GPT-5.2 等推理模型构建过任何东西，你就知道那种痛苦。你的代理开始思考一个复杂的任务，客户端在那里等待，在&amp;quot;没问题&amp;quot;和&amp;quot;它是不是崩了？&amp;ldquo;之间的某个时刻，你的连接超时了。那些工作？全没了。&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework 刚刚推出了&lt;a href="https://devblogs.microsoft.com/agent-framework/handling-long-running-operations-with-background-responses/"&gt;后台响应&lt;/a&gt; — 说实话，这是那种从第一天就应该存在的功能。&lt;/p&gt;
&lt;h2 id="阻塞调用的问题"&gt;阻塞调用的问题&lt;/h2&gt;
&lt;p&gt;在传统的请求-响应模式中，你的客户端会阻塞直到代理完成。对于快速任务来说没问题。但当你让推理模型做深度研究、多步分析或生成 20 页报告时？你面对的是几分钟的实际等待时间。在这个窗口期：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP 连接可能超时&lt;/li&gt;
&lt;li&gt;网络抖动会杀死整个操作&lt;/li&gt;
&lt;li&gt;你的用户盯着一个加载动画想知道是否有事情在发生&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后台响应彻底翻转了这个局面。&lt;/p&gt;
&lt;h2 id="延续令牌如何工作"&gt;延续令牌如何工作&lt;/h2&gt;
&lt;p&gt;你不再阻塞等待，而是启动代理任务并获得一个&lt;strong&gt;延续令牌&lt;/strong&gt;。把它想象成修理店的取件单 — 你不需要站在柜台前等着，准备好了再回来取就行。&lt;/p&gt;
&lt;p&gt;流程很简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;AllowBackgroundResponses = true&lt;/code&gt; 发送请求&lt;/li&gt;
&lt;li&gt;如果代理支持后台处理，你会收到一个延续令牌&lt;/li&gt;
&lt;li&gt;按你的节奏轮询，直到令牌返回 &lt;code&gt;null&lt;/code&gt; — 这意味着结果准备好了&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这是 .NET 版本：&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;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&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="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://&amp;lt;myresource&amp;gt;.openai.azure.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="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&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;GetResponsesClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;lt;deployment-name&amp;gt;&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;AsAIAgent&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="n"&gt;AgentRunOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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="n"&gt;AllowBackgroundResponses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&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="n"&gt;AgentResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&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="s"&gt;&amp;#34;Write a detailed market analysis for the Q4 product launch.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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="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;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;null&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;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&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;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&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;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&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;/p&gt;
&lt;h2 id="带恢复的流式传输真正的魔法"&gt;带恢复的流式传输：真正的魔法&lt;/h2&gt;
&lt;p&gt;轮询对于即发即忘的场景没问题，但当你想要实时进度呢？后台响应也支持带内置恢复功能的流式传输。&lt;/p&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;AgentRunOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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="n"&gt;AllowBackgroundResponses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&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;AgentResponseUpdate&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;latestUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunStreamingAsync&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="s"&gt;&amp;#34;Write a detailed market analysis for the Q4 product launch.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&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;latestUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&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="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&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="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="c1"&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;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;latestUpdate&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&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;/p&gt;
&lt;h2 id="什么时候该真正使用这个"&gt;什么时候该真正使用这个&lt;/h2&gt;
&lt;p&gt;不是每个代理调用都需要后台响应。对于快速完成，你只是在无故增加复杂性。但以下场景是它们大放异彩的地方：&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; — 移动客户端、边缘部署、不稳定的企业 VPN&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步 UX 模式&lt;/strong&gt; — 提交任务，去做别的事，回来取结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于构建企业应用的 .NET 开发者来说，最后一点特别有趣。想想一个 Blazor 应用，用户请求一个复杂的报告 — 你启动代理任务，显示进度指示器，让他们继续工作。不需要 WebSocket 体操，不需要自定义队列基础设施，只需一个令牌和一个轮询循环。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;后台响应现在通过 Microsoft Agent Framework 在 .NET 和 Python 中都可用。如果你构建的代理做的事情比简单的问答更复杂，这值得加入你的工具包。延续令牌模式保持简单的同时解决了一个非常真实的生产问题。&lt;/p&gt;
&lt;p&gt;查看&lt;a href="https://devblogs.microsoft.com/agent-framework/handling-long-running-operations-with-background-responses/"&gt;完整文档&lt;/a&gt;获取完整的 API 参考和更多示例。&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.112：.NET 开发者真正应该关注的内容</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-112-dotnet-developers/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/vscode-1-112-dotnet-developers/</guid><description>VS Code 1.112 刚刚发布，满载代理升级、集成浏览器调试器、MCP 沙箱和 monorepo 支持。如果你用 .NET 开发，这些是真正重要的内容。</description><content:encoded>&lt;p&gt;VS Code 1.112 刚落地，说实话？如果你每天都在 .NET 的世界里，这个版本感觉不一样。&lt;a href="https://code.visualstudio.com/updates/v1_112"&gt;官方发布说明&lt;/a&gt; 里有很多内容，但让我帮你省点滚动，专注于对我们真正重要的东西。&lt;/p&gt;
&lt;h2 id="copilot-cli-变得更有用了"&gt;Copilot CLI 变得更有用了&lt;/h2&gt;
&lt;p&gt;这个版本的大主题是&lt;strong&gt;代理自主性&lt;/strong&gt; — 给 Copilot 更多空间做它的事，不需要你看管每一步。&lt;/p&gt;
&lt;h3 id="消息引导和排队"&gt;消息引导和排队&lt;/h3&gt;
&lt;p&gt;你知道 Copilot CLI 在任务进行到一半时，你突然想起忘了提什么东西的那个时刻吗？以前你只能等。现在你可以在请求还在运行时发送消息 — 要么引导当前响应，要么排队后续指令。&lt;/p&gt;
&lt;p&gt;这对那些较长的 &lt;code&gt;dotnet&lt;/code&gt; 脚手架任务来说太棒了，你看着 Copilot 设置项目然后想&amp;quot;哦等等，我还需要 MassTransit&amp;quot;。&lt;/p&gt;
&lt;h3 id="权限级别"&gt;权限级别&lt;/h3&gt;
&lt;p&gt;这是我最兴奋的。Copilot CLI 会话现在支持三个权限级别：&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; — 完全自主：批准工具、回答自己的问题、持续到任务完成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你在做类似用 Entity Framework、migrations 和 Docker 设置创建新的 ASP.NET Core API 这样的事 — 自动驾驶模式意味着你描述想要什么然后去拿杯咖啡。它会搞定的。&lt;/p&gt;
&lt;p&gt;你可以用 &lt;code&gt;chat.autopilot.enabled&lt;/code&gt; 设置启用自动驾驶。&lt;/p&gt;
&lt;h3 id="委托前预览更改"&gt;委托前预览更改&lt;/h3&gt;
&lt;p&gt;当你把任务委托给 Copilot CLI 时，它会创建一个 worktree。以前如果你有未提交的更改，你得检查源代码管理来看什么会受影响。现在聊天视图会在你决定复制、移动或忽略之前直接显示待处理的更改。&lt;/p&gt;
&lt;p&gt;小事情，但省去了&amp;quot;等等，我 staging 了什么？&amp;ldquo;的时刻。&lt;/p&gt;
&lt;h2 id="不离开-vs-code-就能调试-web-应用"&gt;不离开 VS Code 就能调试 Web 应用&lt;/h2&gt;
&lt;p&gt;集成浏览器现在支持&lt;strong&gt;完整调试&lt;/strong&gt;。你可以设断点、单步执行代码、检查变量 — 全在 VS Code 内。不用再切换到 Edge DevTools 了。&lt;/p&gt;
&lt;p&gt;有一个新的 &lt;code&gt;editor-browser&lt;/code&gt; 调试类型，如果你已经有 &lt;code&gt;msedge&lt;/code&gt; 或 &lt;code&gt;chrome&lt;/code&gt; 的启动配置，迁移只需改 &lt;code&gt;launch.json&lt;/code&gt; 里的 &lt;code&gt;type&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;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;editor-browser&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;request&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;launch&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;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Debug Blazor 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="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://localhost:5001&amp;#34;&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;对 Blazor 开发者来说，这是颠覆性的。你已经在终端运行 &lt;code&gt;dotnet watch&lt;/code&gt; — 现在调试也留在同一个窗口里。&lt;/p&gt;
&lt;p&gt;浏览器还获得了独立的缩放级别（终于）、正确的右键上下文菜单，缩放按网站记忆。&lt;/p&gt;
&lt;h2 id="mcp-服务器沙箱"&gt;MCP 服务器沙箱&lt;/h2&gt;
&lt;p&gt;这比你想的更重要。如果你在用 MCP 服务器 — 也许你为 Azure 资源或数据库查询设置了自定义的 — 它们一直以和你的 VS Code 进程相同的权限运行。这意味着对你的文件系统、网络等一切的完全访问。&lt;/p&gt;
&lt;p&gt;现在你可以对它们做沙箱处理。在你的 &lt;code&gt;mcp.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;servers&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;my-azure-tools&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;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;node&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;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./mcp-server.js&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;sandboxEnabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;当沙箱化的服务器需要访问它没有的东西时，VS Code 会提示你授予权限。比&amp;quot;希望没人做奇怪的事&amp;quot;的方式好太多了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 沙箱目前在 macOS 和 Linux 上可用。Windows 支持即将到来 — 不过 WSL 等远程场景是可以工作的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="monorepo-自定义发现"&gt;Monorepo 自定义发现&lt;/h2&gt;
&lt;p&gt;如果你在 monorepo 中工作（说实话，很多企业 .NET 解决方案最终都变成了 monorepo），这解决了一个真正的痛点。&lt;/p&gt;
&lt;p&gt;以前，如果你打开仓库的子文件夹，VS Code 找不到仓库根目录的 &lt;code&gt;copilot-instructions.md&lt;/code&gt;、&lt;code&gt;AGENTS.md&lt;/code&gt; 或自定义技能。现在通过 &lt;code&gt;chat.useCustomizationsInParentRepositories&lt;/code&gt; 设置，它会向上查找到 &lt;code&gt;.git&lt;/code&gt; 根目录并发现所有内容。&lt;/p&gt;
&lt;p&gt;这意味着你的团队可以在 monorepo 中跨所有项目共享代理指令、提示文件和自定义工具，不需要每个人都打开根文件夹。&lt;/p&gt;
&lt;h2 id="troubleshoot-用于代理调试"&gt;/troubleshoot 用于代理调试&lt;/h2&gt;
&lt;p&gt;有没有设置过自定义指令或技能，然后纳闷为什么没被检测到？新的 &lt;code&gt;/troubleshoot&lt;/code&gt; 技能读取代理调试日志并告诉你发生了什么 — 哪些工具被使用或跳过了，为什么指令没加载，什么导致了慢响应。&lt;/p&gt;
&lt;p&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;github.copilot.chat.agentDebugLog.enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;github.copilot.chat.agentDebugLog.fileLogging.enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;code&gt;/troubleshoot why is my custom skill not loading?&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;你现在还可以导出和导入这些调试日志，当某些东西不按预期工作时，和团队分享很方便。&lt;/p&gt;
&lt;h2 id="图像和二进制文件支持"&gt;图像和二进制文件支持&lt;/h2&gt;
&lt;p&gt;代理现在可以从磁盘原生读取图像文件和二进制文件。二进制文件以 hexdump 格式呈现，图像输出（如集成浏览器的截图）以轮播视图显示。&lt;/p&gt;
&lt;p&gt;对 .NET 开发者来说：把 UI bug 的截图粘贴到聊天中让代理理解问题所在，或者让它分析 Blazor 组件渲染的输出。&lt;/p&gt;
&lt;h2 id="自动符号引用"&gt;自动符号引用&lt;/h2&gt;
&lt;p&gt;小的生活质量改善：当你复制一个符号名称（类、方法等）并粘贴到聊天中时，VS Code 现在自动将其转换为 &lt;code&gt;#sym:Name&lt;/code&gt; 引用。这给代理提供了关于该符号的完整上下文，无需手动添加。&lt;/p&gt;
&lt;p&gt;如果你想要纯文本，使用 &lt;code&gt;Ctrl+Shift+V&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="插件现在可以启用禁用"&gt;插件现在可以启用/禁用&lt;/h2&gt;
&lt;p&gt;以前禁用 MCP 服务器或插件意味着卸载它。现在你可以开关它们 — 全局和按工作区都可以。在扩展视图或自定义视图中右键单击就行。&lt;/p&gt;
&lt;p&gt;npm 和 pypi 的插件现在也可以自动更新了，不过会先请求批准，因为更新意味着在你的机器上运行新代码。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;VS Code 1.112 明显在大力推进代理体验 — 更多自主性、更好的调试、更严格的安全。对 .NET 开发者来说，集成浏览器调试和 Copilot CLI 改进是最突出的功能。&lt;/p&gt;
&lt;p&gt;如果你还没试过为 .NET 项目在自动驾驶模式下运行完整的 Copilot CLI 会话，这个版本是开始的好时机。记得设置你的权限然后让它干活。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://code.visualstudio.com/updates/v1_112"&gt;下载 VS Code 1.112&lt;/a&gt; 或在 VS Code 内通过&lt;strong&gt;帮助 &amp;gt; 检查更新&lt;/strong&gt;进行更新。&lt;/p&gt;</content:encoded></item><item><title>从笔记本到生产：用两个命令将 AI 代理部署到 Microsoft Foundry</title><link>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/deploy-ai-agents-foundry-azd-two-commands/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/zh/posts/emiliano-montesdeoca/deploy-ai-agents-foundry-azd-two-commands/</guid><description>Azure Developer CLI 现在有了 'azd ai agent' 命令，可以在几分钟内将你的 AI 代理从本地开发带到 Foundry 的生产端点。这是完整的工作流程。</description><content:encoded>&lt;p&gt;你知道&amp;quot;在我的机器上能跑&amp;quot;和&amp;quot;已部署并正在处理流量&amp;quot;之间的鸿沟吗？对于 AI 代理来说，这个鸿沟一直痛苦地大。你需要配置资源、部署模型、配置身份、设置监控 — 这些都是在任何人能实际调用你的代理之前要做的。&lt;/p&gt;
&lt;p&gt;Azure Developer CLI 刚刚把这变成了&lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-ai-agent-end-to-end/"&gt;两个命令的事&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="新的-azd-ai-agent-工作流"&gt;新的 &lt;code&gt;azd ai agent&lt;/code&gt; 工作流&lt;/h2&gt;
&lt;p&gt;让我带你看看这实际是什么样子。你有一个 AI 代理项目 — 比如说一个酒店礼宾代理。它在本地运行正常。你想让它在 Microsoft Foundry 上运行。&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;azd ai agent init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就这样。两个命令。&lt;code&gt;azd ai agent init&lt;/code&gt; 在你的仓库中生成基础设施即代码，&lt;code&gt;azd up&lt;/code&gt; 在 Azure 上配置一切并发布你的代理。你会得到一个直接指向 Foundry 门户中你的代理的链接。&lt;/p&gt;
&lt;h2 id="底层发生了什么"&gt;底层发生了什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;init&lt;/code&gt; 命令在你的仓库中生成真实的、可检查的 Bicep 模板：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个 &lt;strong&gt;Foundry Resource&lt;/strong&gt;（顶层容器）&lt;/li&gt;
&lt;li&gt;一个 &lt;strong&gt;Foundry Project&lt;/strong&gt;（你的代理所在的地方）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型部署&lt;/strong&gt;配置（GPT-4o 等）&lt;/li&gt;
&lt;li&gt;带有适当 RBAC 角色分配的&lt;strong&gt;托管身份&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;服务映射用的 &lt;code&gt;azure.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;带有代理元数据和环境变量的 &lt;code&gt;agent.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键是：这一切都是你的。它是仓库中的版本化 Bicep。你可以检查它、自定义它，并与你的代理代码一起提交。没有魔法黑盒。&lt;/p&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;azd ai agent run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这会在本地启动你的代理。配合 &lt;code&gt;azd ai agent invoke&lt;/code&gt; 发送测试提示，你就有了一个紧密的反馈循环。编辑代码、重启、调用、重复。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;invoke&lt;/code&gt; 命令的路由也很智能 — 当本地代理在运行时，它会自动指向本地。不在运行时，指向远程端点。&lt;/p&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;azd ai agent monitor --follow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;流经你的代理的每个请求和响应都会实时传输到你的终端。对于调试生产问题，这是无价之宝。不用挖 Log Analytics，不用等指标聚合 — 你看到的就是现在正在发生的事情。&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;code&gt;azd ai agent init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;用 IaC 搭建 Foundry 代理项目&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd up&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;配置 Azure 资源并部署代理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent invoke&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;向远程或本地代理发送提示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在本地运行代理用于开发&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent monitor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从已发布的代理流式传输实时日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent show&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检查代理健康状态和状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;清理所有 Azure 资源&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="为什么这对-net-开发者重要"&gt;为什么这对 .NET 开发者重要&lt;/h2&gt;
&lt;p&gt;虽然公告中的示例是基于 Python 的，但基础设施的故事是语言无关的。你的 .NET 代理得到相同的 Bicep 脚手架、相同的托管身份设置、相同的监控管道。如果你已经在用 &lt;code&gt;azd&lt;/code&gt; 部署 .NET Aspire 应用或 Azure 部署，这直接融入你现有的工作流。&lt;/p&gt;
&lt;p&gt;AI 代理的部署鸿沟一直是生态系统中最大的摩擦点之一。从一个工作原型到一个具有适当身份、网络和监控的生产端点，不应该需要一周的 DevOps 工作。现在只需要两个命令和几分钟。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd ai agent&lt;/code&gt; 现在可用。如果你一直因为基础设施设置看起来工作量太大而推迟部署 AI 代理，试试看。查看&lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-ai-agent-end-to-end/"&gt;完整教程&lt;/a&gt;获取包括前端聊天应用集成在内的完整步骤。&lt;/p&gt;</content:encoded></item><item><title>Emiliano Montesdeoca</title><link>https://thedotnetblog.com/zh/authors/emiliano-montesdeoca/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/authors/emiliano-montesdeoca/</guid><description/><content:encoded/></item><item><title>为 The .NET Blog 投稿</title><link>https://thedotnetblog.com/zh/contribute/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/zh/contribute/</guid><description>与 .NET 社区分享你的知识。了解如何成为作者并提交你的第一篇文章。</description><content:encoded>&lt;p&gt;The .NET Blog 是一个由社区驱动的出版物，开发者们在这里分享关于 .NET、Azure、AI 和云原生开发的见解、教程和故事。&lt;strong&gt;我们欢迎各个水平的开发者投稿&lt;/strong&gt; — 无论你是在写第一篇技术文章，还是经验丰富的演讲者。&lt;/p&gt;
&lt;h2 id="如何加入"&gt;如何加入&lt;/h2&gt;
&lt;p&gt;所有内容都在 GitHub 上，采用 Pull Request 工作流。以下是入门步骤：&lt;/p&gt;
&lt;h3 id="1-fork-仓库"&gt;1. Fork 仓库&lt;/h3&gt;
&lt;p&gt;访问 &lt;a href="https://github.com/thedotnetblog/blog"&gt;github.com/thedotnetblog/blog&lt;/a&gt; 并将其 Fork 到你的 GitHub 账户。&lt;/p&gt;
&lt;h3 id="2-创建作者简介"&gt;2. 创建作者简介&lt;/h3&gt;
&lt;p&gt;如果这是你的第一次投稿，请在 &lt;code&gt;content/authors/your-username/&lt;/code&gt; 下创建文件夹并添加 &lt;code&gt;index.md&lt;/code&gt; 文件，包含你的姓名、职位、简介和社交链接。将头像图片（正方形，至少 200×200px）添加到 &lt;code&gt;static/img/authors/&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="3-撰写文章"&gt;3. 撰写文章&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;content/posts/your-username/your-post-slug/&lt;/code&gt; 下创建文件夹并添加 &lt;code&gt;index.md&lt;/code&gt;，包含标题、日期、作者、描述和标签。&lt;/p&gt;
&lt;h3 id="4-提交-pull-request"&gt;4. 提交 Pull Request&lt;/h3&gt;
&lt;p&gt;将更改推送到 Fork，并向 &lt;code&gt;main&lt;/code&gt; 分支发起 Pull Request。我们的团队会在几天内审阅并提供反馈。&lt;/p&gt;
&lt;h2 id="我们在寻找什么"&gt;我们在寻找什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;教程&lt;/strong&gt; — .NET、Azure、AI、Blazor、Aspire 等的分步指南&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;深度解析&lt;/strong&gt; — 对技术、模式或架构的深入探讨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社区故事&lt;/strong&gt; — 你在生产环境中使用 .NET 的经验&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;活动回顾&lt;/strong&gt; — 会议、Meetup 或网络研讨会的总结&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="规范"&gt;规范&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;内容应与 .NET 生态系统相关且具有技术性&lt;/li&gt;
&lt;li&gt;代码示例必须准确且在真实项目中经过测试&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;a href="https://github.com/thedotnetblog/blog/issues"&gt;GitHub&lt;/a&gt; 上提交 Issue，或在 &lt;a href="https://x.com/thedotnetblog"&gt;X / Twitter&lt;/a&gt; 上联系我们。我们很乐意欢迎你加入社区！&lt;/p&gt;</content:encoded></item></channel></rss>