首页
/ AutoGen.NET 函数调用实战:为 OpenAIChatAgent 接入工具调用能力(FunctionCallMiddleware 与类型安全函数定义)

AutoGen.NET 函数调用实战:为 OpenAIChatAgent 接入工具调用能力(FunctionCallMiddleware 与类型安全函数定义)

2026-09-04 23:47:58作者:丁柯新Fawn

本篇指南基于 AutoGen.NET 的官方文档与配套示例,完整演示如何为 AutoGen.OpenAI.OpenAIChatAgent 接入函数调用(Function Calling)能力:先通过源生成器以类型安全的方式定义 GetWeather 函数,再用 OpenAIChatRequestMessageConnectorFunctionCallMiddlewareToolCallMessage / ToolCallResultMessage 串进 Agent 的消息流,最终实现"LLM 发起工具调用 → 框架自动执行函数 → 把结果交还给模型"的完整闭环。读完后你能够独立复现这一流程,并理解每个组件在源码层面的职责边界。

准备依赖:AutoGen.OpenAI 与 AutoGen.SourceGenerator

首先需要安装以下两个 NuGet 包(AUTOGEN_VERSION 为版本占位符,使用时替换为当前仓库实际发布的版本号):

<ItemGroup>
    <PackageReference Include="AutoGen.OpenAI" Version="AUTOGEN_VERSION" />
    <PackageReference Include="AutoGen.SourceGenerator" Version="AUTOGEN_VERSION" />
</ItemGroup>

[!Note] AutoGen.SourceGenerator 包内置了一个 Roslyn 源生成器,用于自动生成类型安全的函数定义(即 FunctionContract 属性与参数反序列化包装方法)。更多细节可参考仓库中的 Create type-safe function call 一文。

[!NOTE] 如果你使用 VSCode 作为编辑器,可能需要重启编辑器才能看到生成的代码。

这两个包分别承担了两个职责:

  • AutoGen.OpenAI:提供 OpenAIChatAgent(封装 OpenAI SDK 的 ChatClient 的流式聊天 Agent)和 OpenAIChatRequestMessageConnector(负责 AutoGen 消息类型与 OpenAI ChatMessage 之间的双向转换)。
  • AutoGen.SourceGenerator:提供 FunctionCallGenerator 源生成器,在编译期为标记了 [Function] 的方法生成契约代码。

定义类型安全函数:[Function] 特性与源生成器

导入所需的命名空间(见示例文件 OpenAICodeSnippet.cs):

using AutoGen.Core;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;

然后定义一个 public partial classFunctions,其中包含 GetWeather 方法:

public partial class Functions
{
    [Function]
    public async Task<string> GetWeather(string location)
    {
        return "The weather in " + location + " is sunny.";
    }
}

几个关键点:

  1. 类必须是 partial:源生成器 FunctionCallGenerator 在扫描语法树时,只处理 partial 修饰的类,并为每个匹配类追加一段同名 partial 扩展(生成的文件名形如 {className}_{guid}.generated.cs)。
  2. [Function] 特性:定义于 FunctionAttribute.cs,可选参数为 functionNamedescription;不传时,函数名取方法名,描述优先取 Description 命名参数,其次从 XML 文档注释的 <summary> 段落提取(参数描述同理取自 <param> 段),都取不到时退化为方法前置注释或方法名本身。
  3. 源生成器产物:从 FunctionCallTemplate.tt 模板可以看出,针对 GetWeather 方法,编译期会在 Functions 类中追加两类成员:
    • GetWeatherFunctionContract:一个返回 FunctionContract(含名称、描述、返回类型、参数契约列表)的属性,供 FunctionCallMiddleware 向模型声明工具;
    • GetWeatherWrapper(string arguments):把模型返回的 JSON 参数字符串反序列化为参数对象(CamelCase 命名策略)后,调用真正的 GetWeather 方法。
    • 参数类型到 JSON Schema 的映射也在生成器中固定(见 FunctionCallGenerator.cs):stringstringstring[]arrayint/longintegerfloat/doublenumberboolbooleanDateTime/Guidstring、其余类型默认 object;带默认值的参数会被标记为可选。

FunctionContractFunctionParameterContract 的完整定义见 FunctionAttribute.cs,它还提供了到 Microsoft.Extensions.AI.AIFunction 的隐式转换,便于与其他函数调用框架互通。

创建 OpenAIChatAgent 并注册消息连接器

接下来创建 OpenAIChatAgent 并通过扩展方法 RegisterMessageConnector() 注册 OpenAIChatRequestMessageConnector,使其支持 AutoGen.Core.ToolCallMessageAutoGen.Core.ToolCallResultMessage。这两类消息是 FunctionCallMiddleware 处理函数调用的基础:

var openAIKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new Exception("Please set OPENAI_API_KEY environment variable.");
var modelId = "gpt-3.5-turbo";
var openAIClient = new OpenAIClient(openAIKey);

// create an open ai chat agent
var openAIChatAgent = new OpenAIChatAgent(
    chatClient: openAIClient.GetChatClient(modelId),
    name: "assistant",
    systemMessage: "You are an assistant that help user to do some tasks.")
    .RegisterMessageConnector();

构造函数参数说明(来自 OpenAIChatAgent.cs 的签名):

参数 说明
chatClient OpenAI SDK 的 ChatClient,决定实际调用的模型
name Agent 名称,用于消息的 From 溯源
systemMessage 系统消息,默认 "You are a helpful AI assistant";若历史消息中已包含 SystemChatMessage 则不会重复注入
temperature / maxTokens / seed 采样温度、最大输出 token、确定性种子,均可选
responseFormat 设为 ChatResponseFormat 可启用 JSON 模式
functions 可直接传入 IEnumerable<ChatTool> 的工具定义,是另一种不经过中间件的声明方式

RegisterMessageConnector() 本身是一个扩展方法(OpenAIAgentExtension.cs),内部就是 agent.RegisterStreamingMiddleware(connector),返回类型为 MiddlewareStreamingAgent<OpenAIChatAgent>

OpenAIChatRequestMessageConnector 的源码可以确认它在函数调用链中的两个核心转换:

  • 入站ProcessIncomingMessages 支持 TextMessageImageMessageMultiModalMessageToolCallMessageToolCallResultMessage 以及 AggregateMessage<ToolCallMessage, ToolCallResultMessage> 等类型,并把它们转换成 OpenAI 的 ChatMessage;其中 ToolCallMessage 会被转为带工具调用部分的 AssistantChatMessageToolCallResultMessage 会被逐条转为 ToolChatMessage
  • 出站PostProcessChatResponseMessage 检查模型返回——若 ChatCompletion.ToolCalls 非空,则输出 AutoGen 的 ToolCallMessage(保留 ToolCallId 与可选文本);否则输出 TextMessage。正是这一步把"模型想调工具"翻译成中间件可以识别的 ToolCallMessage

创建 FunctionCallMiddleware 并注册到 Agent

创建 FunctionCallMiddleware,传入 GetWeather 函数,并注册到上面的 Agent:

var functions = new Functions();
var functionCallMiddleware = new FunctionCallMiddleware(
    functions: [functions.GetWeatherFunctionContract], // GetWeatherFunctionContract is auto-generated from the GetWeather function
    functionMap: new Dictionary<string, Func<string, Task<string>>>
    {
        { functions.GetWeatherFunctionContract.Name, functions.GetWeatherWrapper } // GetWeatherWrapper is a wrapper function for GetWeather, which is also auto-generated
    });

openAIChatAgent = openAIChatAgent.RegisterStreamingMiddleware(functionCallMiddleware);

注意 functionMap 的意义:它声明了"当 Agent 回复了一个 GetWeather 的函数调用时,由框架自动执行该函数"。这里传入的 GetWeatherWrapper 就是源生成器自动生成的包装方法,因此参数反序列化是类型安全的,无需手写 JSON 解析。

FunctionCallMiddleware 的实现逻辑值得深入看一下(FunctionCallMiddleware.cs):

  1. 拦截入站消息:如果上下文最后一条消息是 ToolCallMessage,且其函数都在 functionMap 中,则直接执行这些函数并返回 ToolCallResultMessage内层 Agent 被短路、不会发起 LLM 请求;若某个函数不在 functionMap 中,会生成一条包含 "Function {name} is not available. Available functions are: ..." 的错误结果消息。
  2. 注入函数声明:调用前会把中间件持有的 functionsGenerateReplyOptions.Functions 合并后传给内层 Agent,最终由 OpenAIChatAgent.CreateChatCompletionsOptions 转为 OpenAI 的 ChatTool 列表。
  3. 处理模型回复:若内层 Agent 回复的是 ToolCallMessage 且函数在 functionMap 中,则执行函数并把"工具调用消息 + 工具结果消息"打包为 ToolCallAggregateMessage 返回;否则原样返回模型回复。
  4. 流式支持:作为 IStreamingMiddleware,它会把流式的 ToolCallMessageUpdate 增量合并为完整的 ToolCallMessage 后再触发函数执行(见 InvokeAsync)。

构造函数还支持两种等价写法:直接传 FunctionContract 集合 + functionMap 字典(本例),或传 IEnumerable<AIFunction> 集合由框架自动建立 functionMap(参数通过 JSON 反序列化绑定,见 FunctionCallMiddleware.csAIToolInvokeWrapper)。

与 Agent 对话并验证函数调用

最后,向 Agent 提问即可触发 GetWeather 函数调用:

var reply = await openAIChatAgent.SendAsync("what is the weather in Seattle?");
reply.GetContent().Should().Be("The weather in Seattle is sunny.");
reply.GetToolCalls().Count.Should().Be(1);
reply.GetToolCalls().First().Should().Be(this.GetWeatherFunctionContract.Name);

官方示例测试用 FluentAssertions 断言了三件事:最终回复文本是函数返回值(说明工具结果已经被送回模型并综合成自然语言);本次回复携带了 1 个工具调用记录;该工具调用名与 GetWeather 函数契约名一致。完整的可运行代码位于 OpenAICodeSnippet.csOpenAIChatAgentGetWeatherFunctionCallAsync 方法)。

一次典型调用在消息流上的路径是:

SendAsync("what is the weather in Seattle?")
  → FunctionCallMiddleware 合并函数声明
    → OpenAIChatRequestMessageConnector 转成 ChatMessage
      → OpenAIChatAgent 调用 LLM,返回 ToolCalls
    ← Connector 将其还原为 ToolCallMessage
  ← FunctionCallMiddleware 查 functionMap,执行 GetWeatherWrapper
    → 返回 ToolCallAggregateMessage(ToolCallMessage + ToolCallResultMessage)
  → 结果消息经 Connector 转为 ToolChatMessage 再次提交给 LLM
    → LLM 基于 "The weather in Seattle is sunny." 生成自然语言回答

小结与延伸阅读

本流程中三个组件各司其职:源生成器负责类型安全的函数契约生成OpenAIChatRequestMessageConnector 负责 AutoGen 消息与 OpenAI 协议消息的转换FunctionCallMiddleware 负责函数声明注入与自动执行。相关源码与文档入口:

运行前提:设置 OPENAI_API_KEY 环境变量,并具备可调用目标模型(示例中为 gpt-3.5-turbo)的访问权限。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384