- 现代 C# 代理将 LLM 推理与工具、内存和工作流相结合,以处理复杂的、目标驱动的任务。
- Azure OpenAI Assistants 和 Microsoft Agent Framework 为 .NET 中的助手、会话、工具和执行提供核心原语。
- 强大的架构将专用代理分开,持久化状态,协调工作流程,并强制执行严格的测试、可观测性和安全性。
- Azure AI Foundry 和 VS Code AI 扩展等云工具简化了生产级代理的开发、评估和部署。
使用 C# 工具构建 AI 代理已经从一项研究实验转变为一种为商业应用程序添加真正智能的非常实用的方法。 微软的现代框架以及最新的 OpenAI 和 Azure OpenAI SDK 使得超越简单的聊天机器人成为可能,可以将大型语言模型与代码、文件、工作流和企业系统连接起来,同时还能控制安全性、成本和可靠性。
本指南将引导您了解设计 C# 中可用于生产的代理所需的核心概念、架构决策和具体的 .NET 示例。 我们将把 Azure OpenAI 助手、Microsoft Agent Framework、编排模式、测试、可观测性和云部署等方面的想法整合起来,解释所有这些如何融入到现实世界应用程序的统一策略中。
AI代理究竟是什么(以及它在.NET中的重要性)
在 .NET 生态系统中,AI 代理最好理解为由 LLM 驱动的目标驱动型软件组件,它可以进行推理、选择工具并在您的应用程序中采取行动。 代理程序不会像传统程序那样始终遵循相同的路径,而是接受开放式的输入,决定下一步该做什么,并使用你的代码和数据来达成目标。
在纯文本生成功能的基础上增加三种功能,代理的实用性将大大提高。 你赋予它们推理和决策能力(通过逻辑逻辑模型、搜索或规划算法),调用工具的能力(本地 C# 函数、MCP 服务器、API、代码执行),以及对上下文的感知能力(聊天记录、主题、向量存储、企业知识图谱或文件搜索)。这使得简单的聊天自动完成功能能够转变为一个可以自主协调多步骤工作的组件。
随着目标变得越来越复杂,你很少会把所有事情都当作一个巨大的、不透明的提示来运行;你会将工作分解成工作流程。 工作流程是指为达成目标所需的一系列步骤或流程图,例如:收集需求、设计、实现、测试和部署功能。每个步骤都可以包含子任务,并且可能会因错误或新信息而循环执行,因此流程编排很快就成为首要考虑因素。
当您将代理放置在这些工作流程中时,您会得到 代理工作流程代理协作执行、调整和优化任务的流程。 您可能需要一个代理来分析日志,另一个代理来编写代码修复程序,还有一个代理来准备利益相关者报告。关键在于它们如何传递信息,如何协调彼此的工作,以及如何确保整个系统的可观察性和可审计性。
人工智能助手和代理的核心构建模块
大多数面向 C# 和 .NET 的现代 AI 代理平台都共享一小部分核心组件,即使 Azure OpenAI Assistants 和 Microsoft Agent Framework 之间的命名略有不同。 理解这些模块有助于你设计自己的架构,而不是盲目复制代码片段。
助手或代理是使用 LLM plus 配置来处理指令、管理对话和调用工具的中央 AI 客户端。 在 Azure OpenAI Assistants 中,此对象封装了模型配置、指令和工具配置。在 Microsoft Agent Framework 中, AIAgent 它封装了聊天客户端(OpenAI 或 Azure OpenAI)以及工具和说明,并且有意设计为无状态的,以便可以并行处理多个对话。
线程或会话代表用户与代理之间的一次对话,包括所有消息和相关状态。 Azure OpenAI 助手谈论 线程,它拥有消息并处理自动截断以适应模型上下文。Microsoft Agent Framework 谈到了 AgentSession其中包含历史记录,可以序列化和存储。两者都服务于相同的目的:跟踪跨多个回合的上下文。
消息是指用户或助手在主题或会话中发布的单个内容。 消息可以包含纯文本、图像或文件,在 Assistant API 中,它们以有序列表的形式存储在线程中。在 C# 端,通常将它们作为强类型集合检索,以便检查文本、注释和文件引用。
运行、执行或调用是指在给定线程或会话之上对代理的单次激活。 您获取现有上下文,将其连同工具和配置一起发送给模型,然后等待运行直至达到终止状态。在运行期间,代理可以生成新消息、调用工具并更新线程或会话状态。
执行步骤详细记录了代理运行期间发生的一切。 助手在处理任务的过程中,可能会多次调用文件搜索工具、触发代码解释器或调用自定义函数。将这些步骤结构化地记录下来,对于理解特定答案的生成原因以及后续的调试或行为审计都非常有用。
使用 Azure OpenAI Assistant 创建一个最小化的 C# 控制台代理
要了解这些概念的实际应用,您可以启动一个最小的 .NET 控制台应用程序,该应用程序使用官方的 OpenAI 或 Azure OpenAI SDK 构建一个助手,该助手可以从文件中读取数据并生成可视化效果。 其理念是将 LLM 与文件搜索和代码执行连接起来,然后让它用自然语言回答分析问题。
第一步是项目设置:创建一个新的 .NET 控制台应用程序,并添加 OpenAI 和 Azure.AI.OpenAI 的 NuGet 包。 然后,您在其中实例化主客户端。 Program.cs可以直接用于 OpenAI,也可以使用凭据(例如)用于 Azure OpenAI。 DefaultAzureCredential从 OpenAI 客户端,您可以获得一个 AssistantClient 管理助理和单独的 OpenAIFileClient 用于文件上传。
接下来,您需要准备代理要使用的真实数据,方法是在内存中构建文档,将其序列化为 JSON,然后将其流式传输到文件客户端。 在这个示例中,这段 JSON 数据编码了一家虚构公司几个月的产品销售数据,并将月份映射到每个产品的数量。通过上传它, Assistants 文件用途:将其标记为代理可以搜索的材料。
数据存在于系统后,您可以通过以下方式配置助手: AssistantCreationOptions 启用文件搜索和代码解释器工具。 您指定一个名称、一组清晰的指令(“您是一名助手,负责查找销售数据并在需要时生成可视化图表”),然后附加工具:a FileSearchToolDefinition 因此,助手可以查询文件,此外…… CodeInterpreterToolDefinition 因此,它可以在沙盒环境中编写和运行代码,用于分析或图表生成。
要使文件搜索真正使用您上传的销售文档,您需要将其与内部的一个新矢量图库关联起来。 ToolResources. 助手 VectorStoreCreationHelper 它将上传的文件 ID 绑定到一个矢量存储库中,助手可以对该存储库进行语义查询,而无需扫描原始文本。这是一种轻量级但功能强大的方法,可以添加检索增强型生成行为。
设置好选项后,您可以通过传递目标模型(例如)来创建助手。 gpt-4o)以及配置,然后您就可以通过初始用户消息启动对话线程。 第一个提示可能是这样的:“产品 113045 在二月份的表现如何?绘制其随时间变化的趋势图。” 最后,你打电话 CreateThreadAndRun它既创建线程又启动运行。
由于运行本质上是异步的,控制台应用程序通常会轮询运行状态,直到状态变为终止。 之后,按升序提取线程消息并遍历它们:打印辅助文本、输出文件引用或生成文件的注释,以及使用文件客户端下载图像输出,以便将代码解释器生成的图表保存到磁盘作为 PNG 文件。
最终成果是一个独立的 C# 控制台应用程序,其中单个助手可以搜索结构化的销售数据,通过代码执行计算,并在全自动循环中返回文本见解和可视化图表。 一旦添加了持久性和身份验证,这种模式就可以很好地扩展到 Web 后端或后台服务。
使用 C# 设计健壮的代理架构
从演示版过渡到实际应用时,代理的组织方式与你选择哪种模型同样重要。 良好的架构可以更轻松地测试、扩展、保护和改进您的解决方案,而不会最终导致难以维护的提示和回调混乱不堪。
行之有效的策略是将智能体视为专门的组件,而不是单一的“万能大脑”。 例如,您可以定义一个专注于信息检索和验证的代理,另一个专门用于编写和总结内容的代理,以及一个唯一负责与外部 API 或数据库交互的代理。这种分离方式允许进行有针对性的单元测试、独立部署以及更细粒度的安全性和令牌限制。
如果把状态和记忆当作事后才考虑的事情,它们很快就会成为瓶颈。 对话历史记录会随着时间推移而不断增长,每次都盲目地将整个对话记录发送给模型会增加延迟和成本。实用的策略包括定期对先前的消息进行摘要,将对话按用户或用例分割成不同的线程,以及实施基于语义重要性的压缩策略,以便仅保留过去最相关的部分。
在生产环境中,您还需要一个持久化的内存存储,以便对话能够在进程重启、故障或重新部署后仍然存在。 诸如 Microsoft Agent Framework 之类的代理框架使会话可序列化为 JsonElement您可以将这些数据推送到 SQL Server、Redis 或任何 NoSQL 存储中。同样的功能也支持审计跟踪和合规性,因为您可以准确地重建代理做出决策时的状态。
工具和函数调用使代理不再被动,而是开始做有用的工作。 将原生 C# 方法作为工具公开,可以让模型调用诸如查询 CRM、运行数据分析或触发工作流等行为。每个工具都应使用清晰的元数据(描述和参数文档)进行注释,以便 LLM 知道何时调用它以及使用哪些参数。
因为一个运行不正常的工具可能会破坏整个交互,所以你需要围绕它构建强大的工程机制:输入验证、超时、异常处理和防护措施。 不要假设模型总能完美传递参数;务必验证参数并清理所有外部调用。此外,还要考虑每个工具的配额和速率限制,以避免成本失控或下游系统意外过载。
对于雄心勃勃的场景,多智能体编排可以释放单个单体智能体难以实现的能力。 您可以设置一个“研究员”代理负责收集和核查信息,一个“分析师”代理负责解读调查结果,还有一个“撰稿人”代理负责将调查结果撰写成报告,每个代理都通过结构化消息进行沟通,并共享一个工作界面(例如共享文档或知识库)。这种模式可以提高专业化程度,并在您日后需要审查或审核结果时,使决策路径可追溯。
从语义内核和自动生成到微软代理框架
微软一直在整合其 .NET 代理工具,将语义内核和 AutoGen 项目的理念融合到一个新的、统一的 Microsoft Agent Framework (MAF) 中。 该框架旨在为您提供企业级稳定性和功能,同时简化您构建多轮代理和基于图的工作流的方式。
MAF 目前处于公开预览阶段,并以 MIT 许可证发布,支持 .NET 和 Python 版本。 尽管某些 API 在发布候选版本之间仍在不断发展,但总体方向很明确:AIAgents 用于智能行为,AgentSessions 用于状态管理,以及基于图和执行器的工作流系统用于更确定性的管道。
该框架的核心在于区分代理和工作流,二者分别针对不同的问题类型。 智能体是动态系统,它们使用逻辑逻辑模型(LLM)来解释输入、决定调用哪些工具并生成响应。它们在技术支持对话等用户可能提出任何问题的不可预测领域表现出色。相比之下,工作流是以图形式连接的明确步骤序列,适用于需要确定性、定义明确的处理过程,例如数据管道或审批链。
官方指南可以概括为“如果你能将一项任务作为标准功能来实现,那么你可能就不需要为此使用代理了。” 换句话说,在确实无法预先定义所有步骤的领域,应保留代理;而对于可重复、确定性的流程,则应依赖工作流或传统代码。在合适的地方将两者结合使用,是构建可维护系统的关键。
为了更具体地说明这一点,想象一下使用 Microsoft Agent Framework 构建的基于 ASP.NET Core 10 API 的支持聊天机器人。 该代理使用聊天客户端(由 Azure OpenAI 或 OpenAI 提供支持)作为其推理引擎,其主要目的是回答有关存储在 Markdown 文件中的内部文档的问题,同时保持来自同一用户的多条消息之间的上下文。
有趣的是,该示例可以故意跳过 RAG 嵌入,并通过以平面文件上的关键字搜索为起点,仍然保持现实性。 这样一来,重点就放在了 MAF 如何构建代理、工具和会话上,而不是迷失在向量数据库配置中,同时仍然支持非常合理的交互支持。
Microsoft Agent Framework 中的五个关键概念
MAF 的官方教程将学习内容分为五个循序渐进的概念,这与 C# 开发人员对服务和状态的思考方式非常吻合。 熟悉这些概念能为你用 .NET 构建的任何代理程序打下坚实的基础。
首先是你的初始代理人: AIAgent 由聊天客户端、指令和名称构建而成。 您将代理指向 AzureOpenAIClient 或 OpenAI 提供的聊天模型,提供系统级指导(“您是一位乐于助人的支持助理”),然后致电 RunAsync 并可接收用户输入。关键在于,代理实例是无状态的,可以同时处理多个独立的对话。
其次是工具,它们只是用装饰器修饰的 C# 方法。 属性并通过以下方式转换为可调用函数 AIFunctionFactory.Create(). 当代理运行时,LLM 会接收一个从这些属性派生出的模式,并能自主决定何时以及如何调用每个工具,包括参数。这时,您的业务逻辑和外部集成就成为代理操作空间的一部分。
第三点是多轮对话支持,MAF 通过以下方式处理它: AgentSession 对象。 计划 AIAgent 它本身不记得任何事情,每次对话都存在于用它创建的会话中。 CreateSessionAsync()您可以将该会话传递回后续通话,以便客服人员能够跟踪之前的消息、用户偏好和未解决的问题。
第四点是内存和持久性,这得益于会话可以序列化为一个 JsonElement. 这样就可以轻松地将它们存储在内存、Redis、SQL 表或任何其他你喜欢的存储介质中,然后使用以下方式重建它们: DeserializeSessionAsync()对于支持场景,这意味着用户可以关闭浏览器,稍后恢复之前的对话,或者在重启后,不同的服务实例可以无缝接管。
第五点是工作流程,由……构建 WorkflowBuilder 当您需要明确协调多个代理或顺序处理步骤时。 您可以将执行器定义为处理单元,通过边将它们连接起来,然后让工作流引擎处理路由和转换。在许多对话场景中,您根本不需要工作流,但当您需要在代理周围实现结构化的路由、分类或人机交互步骤时,工作流就变得非常有用。
使用 MAF、工具和会话实现真正的支持机器人
一个具体的例子可以说明上述概念,那就是由 ASP.NET Core 10 项目支持的 SupportBot API。 该服务公开一个 HTTP 端点,该端点接受用户消息和会话标识符,将推理委托给 AIAgent,并持久化会话,以便在请求之间保留上下文。
在这种情况下,核心工具是文档工具,它知道如何搜索内部 Markdown 文件。 它的职责是查找相关的指南、常见问题解答或模块手册,并返回有助于代理构建答案的文本片段。应用于其方法的属性并非装饰性的;MAF 使用它们来构建 LLM 读取的功能模式,而这些描述的清晰度会极大地影响模型选择和调用工具的有效性。
该工具内部的一个务实设计选择是,如果没有文档与请求的主题足够匹配,则返回所有文档。 与其让智能体完全没有信息,不如提供过多的背景信息,让模型从中挑选最佳素材,而不是让它在真空中胡乱猜测。这种“安全回退”模式在健壮的智能体实现中经常出现。
然后,SupportAgentFactory 通过接收一个参数将所有内容连接起来。 AzureOpenAIClient通过以下方式提取聊天客户端 GetChatClient()并对其进行改编 AsIChatClient() 然后将其转化为 AIAgent - AsAIAgent(). 在最后一步中,已注册的工具和指令会成为代理配置的一部分,用于每次对话。通常,您需要将构建好的代理注册为依赖注入容器中的单例,以便它可以同时服务多个会话。
会话管理被抽象化到后台。 InMemorySessionStore 在开发过程中,会举行会议, JsonElement 值。 线程安全 ConcurrentDictionary 这里这样做就足以避免手动锁定。在实际部署中,您可以将此实现替换为基于 Redis 或数据库的存储,这样既能保持接口不变,又能获得持久存储和横向扩展能力。
API 接口 Program.cs 刻意保持简洁:一个 POST 请求 /chat 接受会话 ID 和用户消息的端点。 请求处理程序加载或创建会话,执行代理,异步序列化更新后的会话(注意: SerializeSessionAsync 在 RC1 版本中是异步的(即使早期文档另有说明),它会将会话 ID 持久化并返回给客户端。从前端的角度来看,“保持在同一对话中”仅仅意味着每次调用都发送相同的会话 ID。
运行 API 并与之聊天时,您可以像真人客服代表一样,看到代理在回合之间传递上下文信息。 第一条消息可能描述登录问题;第二个问题使用相同的会话 ID 发送,可以提到“再次出现该错误”,而无需重新陈述全部细节,代理仍然可以连贯地回答,因为状态与会话存储相关联。
只有添加了诸如自动意图分类、路由到专业代理(计费、访问、报告)或升级到人工服务等功能,工作流程才能真正发挥作用。 然后,您可以在工作流图的前端引入分类执行器,并将其连接到特定主题的代理,或者添加一个人工参与节点,当置信度较低时,该节点会停止自动化并将上下文交给人。
工作流、编排模式和多代理协作
即使在 MAF 之外,思考如何协调包含代理的工作流程也很有帮助,因为它们的结构会影响延迟、成本和可追溯性。 在不同的项目和框架中,存在一些常见的模式。
顺序编排意味着代理依次处理任务,并将输出向前传递。 例如,检索代理首先收集相关文档,然后将其传递给分析代理,分析代理再将分析结果传递给报告代理。这种方式易于理解和调试,但代价是端到端延迟较高。
并发编排并行运行多个代理,每个代理专注于问题的不同方面。 一个代理可能同时计算指标,另一个代理可能搜索近期事件,第三个代理可能评估合规性影响。完成后,协调员会将结果汇总成一个单一答案。这种模式可以降低延迟,但需要谨慎的资源控制和冲突解决。
交接流程根据条件或中间结果,明确地将任务的所有权从一个代理转移到另一个代理。 如果客服人员检测到某个问题实际上与销售相关,它可以将对话转接给专业的销售人员,并可选择保留聊天记录和元数据。这在复杂的客户旅程中尤为有用,因为在这些旅程中,责任会在不同的团队之间合理地转移。
群聊式设置允许多个客服人员在共享的对话频道中协作,实时交换消息。 每个参与者都带来各自的视角或工具集,而中央协调者或LLM主持人可以管理对话,使其趋于一致,而不是无限循环。这种模式功能强大,但需要强有力的保障措施来避免噪音和不必要的成本。
最后,磁性指挥法让一位“领导者”或指挥者负责指挥其他人。 主控代理将任务分解,把子任务分配给合适的专家,然后汇总他们的输出。这类似于工程经理协调开发团队,可以在复杂的领域中产生清晰、可审计的流程。
测试、可观测性、成本控制和安全性
如果没有测试、监控、成本和安全计划,就将人工智能代理投入生产,势必会带来意想不到的麻烦。 对任何关键的 .NET 服务所采用的严谨性也必须延伸到代理层,只是要适应 LLM 的概率特性。
在考虑模型行为之前,先使用经典的单元测试和集成测试来测试工具和编排路径。 代理可以调用的每个 C# 函数都应该是可独立测试的,并且具有确定性的输入和输出。然后设计受控对话脚本,模拟完整的交互路径,不仅验证最终结果,还要验证调用了哪些工具以及状态是如何演变的。
可观测性应跟踪不同执行路径的延迟、令牌消耗和成功率。 衡量每次交互的提示和完成标记数量非常有用,并可按工作流程、工具或用户类型进行细分,以便发现性能下降和成本飙升的情况。较长的对话成本尤其高昂,因此应投资于自动摘要和智能截断策略,以保持上下文简洁。
一旦你的代理人接触到敏感数据或客户数据,安全就不容妥协。 您应该对代理可以访问的工具和数据集实施严格的访问控制,记录每次工具调用以进行审计,并对所有外部调用进行安全过滤。凭证绝不应嵌入代码中;应依赖托管身份、密钥存储以及您已应用于非 AI 微服务的常规云安全实践。
合规性要求也会影响您存储和处理对话历史记录的方式。 由于会话和线程可能包含个人身份信息或机密内容,因此应尽早定义保留策略、匿名化策略和数据最小化规则。序列化和反序列化代理会话的功能非常强大,但必须兼顾法律和监管义务。
在成本方面,不要低估即使是微小的效率低下在规模上的影响。 提示信息大小、工具调用频率或并发代理数量的微小变化都可能导致每月账单大幅上涨。因此,对系统进行监控、定期审查遥测数据并调整提示信息、内存策略和模型选择,对于长期保持成本可持续至关重要。
将控制平面(配置代理和工作流的地方)与推理平面(运行实际模型调用的地方)分开,可以更轻松地进行部署和扩展。 基于容器的编排、用于长时间运行操作的消息队列以及用于 LLM 托管的托管云服务,共同提升了系统的弹性。分析结果随后可以导入仪表板或 Power BI 等 BI 工具,从而形成完整的分析反馈闭环,并展现业务价值。
集成工具(例如 AI Toolkit 和 Azure AI Foundry 的 Visual Studio Code 扩展)可以简化此生命周期的大部分流程。 在编辑器中,您可以浏览模型目录,通过 Ollama 部署 GitHub 托管或本地模型,并排比较输出结果,构建和运行评估器,在数据整理器中可视化结果,设计带有系统提示的代理,连接 MCP 服务器以进行工具集成,以及调试代理交互。Azure AI Foundry 还增加了可视化设计器、YAML 同步、用于 Azure 模型访问的代码生成功能,以及与 Bing 搜索和代码解释器等工具的一流集成。
当你把这些要素——稳固的代理架构、周全的状态管理、强大的工具、在需要时基于图的工作流、深度可观测性和云原生部署——加在一起,你就能得到 C# AI 代理,它们不仅是巧妙的演示,而且是大型企业系统中可靠的组成部分。 通过精心设计和正确使用 Azure OpenAI Assistants 和 Microsoft Agent Framework,这些代理可以显著提高整个组织的效率、信息质量和自动化水平,同时保持可维护性和安全性。