<?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>Python | The .NET Blog</title><link>https://thedotnetblog.com/zh/tags/python/</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>Sat, 25 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/zh/tags/python/index.xml" rel="self" type="application/rss+xml"/><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>你的 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>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></channel></rss>