跳到主要内容 AI 大模型应用开发初探:基于 Semantic Kernel 构建简易 Agent | 极客日志
C# AI
AI 大模型应用开发初探:基于 Semantic Kernel 构建简易 Agent 探讨了 AI Agent 的概念及其在应用开发中的新范式地位。文章详细解析了 Agent 的感知、规划、记忆、工具使用和行动五大核心组件,并对比了代码驱动与低代码平台两种开发模式。重点通过 C# 语言和 Semantic Kernel 框架,演示了构建 MES 工单助手的具体实现,涵盖 Kernel 初始化、Function Calling 注册、配置管理及安全最佳实践。内容旨在帮助开发者掌握利用大模型构建自主执行任务 Agent 的技术路径。
1qazxsw2 发布于 2025/2/7 更新于 2026/4/20 1 浏览
AI 大模型应用开发初探:基于 Semantic Kernel 构建简易 Agent
近期,随着大语言模型(LLM)技术的飞速发展,AI Agent 被视为下一代应用开发的新范式。本文将深入探讨 AI Agent 的核心概念、架构原理,并基于 C# 和 Semantic Kernel 框架,手把手演示如何开发一个具备 Function Calling 能力的简易 Agent。
AI Agent:可以帮你执行任务的助手 学术界和工业界对术语'AI Agent'提出了各种定义。其中,OpenAI 将 AI Agent 定义为'以大语言模型为大脑驱动的系统,具备自主理解、感知、规划、记忆和使用工具的能力,能够自动化执行完成复杂任务的系统。'
通俗来说,大多数时候你给它一个最终你想要达成的目标,它能直接交付结果,过程你啥都不用管。如果说人和动物的区别是人会使用各种工具,那么 Agent 和大模型的区别亦然。
我们可以把 Agent 与 LLM 形象地比作生物体与其大脑。Agent 有手有脚,可以自己干活自己执行,而 LLM 呢,就是它的大脑。比如,如果你使用 LLM 大模型,它可能只能给你输出一份食谱,告诉你需要哪些食材和步骤来制作。但如果你使用 Agent,它可能就是不仅提供食谱和步骤,还会根据你的需求,帮你选择合适的食材甚至自动下单购买,监控烹饪过程,确保食物口感,最终为你呈上一份佳肴。
AI Agent 如何工作? AI Agent 的架构是其智能行为的基础,它通常包括感知、规划、记忆、工具使用和行动 等关键组件,这些组件协同工作以实现高效的智能行为。
1. 感知 (Perception) Agent 首先需要感知环境。这包括接收用户的自然语言输入、读取传感器数据或访问外部 API 获取当前状态。感知模块负责将非结构化信息转化为 Agent 可理解的上下文。
2. 规划 (Planning) 这是 Agent 的'大脑'部分。基于感知到的信息和长期/短期记忆,LLM 会进行推理,制定达成目标的步骤序列。例如,用户要求'更新工单数量',Agent 需要规划出先查询工单是否存在,再校验状态,最后执行更新的逻辑链条。
3. 记忆 (Memory) 记忆机制允许 Agent 记住过去的交互历史、用户偏好以及任务执行过程中的中间状态。短期记忆通常用于当前的对话上下文,而长期记忆可以通过向量数据库存储历史经验,以便在类似场景下复用知识。
4. 工具使用 (Tool Use) Agent 本身不具备物理操作能力,必须通过调用外部工具来改变世界。这包括调用 RESTful API、运行脚本、查询数据库或使用第三方服务。Function Calling 是实现这一能力的关键技术。
5. 行动 (Action) 执行规划好的工具调用,并将结果反馈给 LLM 进行下一轮决策,形成闭环。
AI Agent 的工作流程其实就是一个连续的循环过程 。它从感知环境开始,经过信息处理、规划和决策,然后执行行动。最后,根据执行结果和环境反馈进行调整,以优化未来的行动和决策。通过这种结构化和层次化的方式,AI Agent 能够有效地处理信息,做出决策,并在复杂环境中执行任务。
如何开发 AI Agent?
模式一:代码驱动开发 基于 Python 或 C# 等编程语言,结合 LangChain 或 Semantic Kernel 等大模型应用开发框架,集成某个大模型 API 和企业内部的业务 API 能力,来完成具体领域的 Agent。这种方式灵活性高,适合复杂业务逻辑和深度定制。
模式二:低代码/平台化开发 基于 Coze、Dify、AutoGen 等 Agent 开发管理平台,通过拖拽的方式快速生成一个 Agent。与其说是开发,不如说是 Workflow 一样的配置。当然,也需要给这些平台注册封装好的企业内部 API 平台提供的能力供配置好的 Agent 去实现工具调用。这种方式上手快,适合快速原型验证。
本文重点介绍基于 C# + Semantic Kernel 的代码驱动开发模式。
使用 Semantic Kernel 开发 AI Agent 这里我们快速使用 Semantic Kernel 开发一个简易的 WorkOrder Agent(MES 工单助手),重点关注如何给 LLM 添加 Function Calling 能力,直观了解 Agent 规划任务和执行任务的效果。
效果对比
没有实现 Function Calling 的效果 :它就只是个 Chatbot。用户询问工单信息时,它只能基于训练数据回答,无法获取实时数据。
实现了 Function Calling 的效果 :它可以称为 Agent。用户发出指令后,它能自主决定调用哪个 API,并按顺序执行,最终返回准确结果。
我的需求其实包含两个步骤:第一步是更新工单的 Quantity,第二步是查询更新后的工单信息。而这两个步骤我们假设其实都是需要去调用 MES WorkOrderService API 才能获得的,这就需要我们给 LLM 加入 Function Calling 的能力,当然 LLM 自己得知道如何规划执行的步骤,哪个步骤先执行,哪个后执行。
示例代码结构 我们将项目分为几个关键部分:配置管理、API 处理、业务服务模拟、以及主程序逻辑。
1. 配置管理 (Shared) 首先定义 OpenAI 兼容服务的配置类,支持多提供商切换。
public class OpenAiConfiguration
{
public string Provider { get ; set ; }
public string ModelId { get ; set ; }
public string EndPoint { get ; set ; }
public string ApiKey { get ; set ; }
public OpenAiConfiguration (string modelId, string endPoint, string apiKey )
{
Provider = ConfigConstants.LLMProviders.OpenAI;
ModelId = modelId;
EndPoint = endPoint;
ApiKey = apiKey;
}
public OpenAiConfiguration (string provider, string modelId, string endPoint, string apiKey )
{
Provider = provider;
ModelId = modelId;
EndPoint = endPoint;
ApiKey = apiKey;
}
}
为了支持不同的 LLM 提供商(如智谱 AI、通义千问等),我们需要自定义 HttpClientHandler 来重写请求路径。
public class CustomLLMApiHandler : HttpClientHandler
{
private readonly string _openAiProvider;
private readonly string _openAiBaseAddress;
public CustomLLMApiHandler (string openAiProvider, string openAiBaseAddress )
{
_openAiProvider = openAiProvider;
_openAiBaseAddress = openAiBaseAddress;
}
protected override async Task<HttpResponseMessage> SendAsync (
HttpRequestMessage request, CancellationToken cancellationToken )
{
UriBuilder uriBuilder;
Uri uri = new Uri(_openAiBaseAddress);
switch (request.RequestUri?.LocalPath)
{
case "/v1/chat/completions" :
switch (_openAiProvider)
{
case ConfigConstants.LLMProviders.ZhiPuAI:
uriBuilder = new UriBuilder(request.RequestUri)
{
Scheme = "https" ,
Host = uri.Host,
Path = ConfigConstants.LLMApiPaths.ZhiPuAIChatCompletions,
};
request.RequestUri = uriBuilder.Uri;
break ;
default :
uriBuilder = new UriBuilder(request.RequestUri)
{
Scheme = "https" ,
Host = uri.Host,
Path = ConfigConstants.LLMApiPaths.OpenAIChatCompletions,
};
request.RequestUri = uriBuilder.Uri;
break ;
}
break ;
}
HttpResponseMessage response = await base .SendAsync(request, cancellationToken);
return response;
}
}
2. 业务服务模拟 (WorkOrderService) 在实际场景中,这里应该替换为真实的 HTTP 客户端调用企业 ERP 或 MES 系统的 API。为了演示方便,我们直接在内存中模拟数据。
public class WorkOrderService
{
private static List<WorkOrder> workOrders = new List<WorkOrder>
{
new WorkOrder { WorkOrderName = "9050100" , ProductName = "A5E900100" , ProductVersion = "001 / AB" , Quantity = 100 , Status = "Ready" },
new WorkOrder { WorkOrderName = "9050101" , ProductName = "A5E900101" , ProductVersion = "001 / AB" , Quantity = 200 , Status = "Ready" },
new WorkOrder { WorkOrderName = "9050102" , ProductName = "A5E900102" , ProductVersion = "001 / AB" , Quantity = 300 , Status = "InProcess" },
new WorkOrder { WorkOrderName = "9050103" , ProductName = "A5E900103" , ProductVersion = "001 / AB" , Quantity = 400 , Status = "InProcess" },
new WorkOrder { WorkOrderName = "9050104" , ProductName = "A5E900104" , ProductVersion = "001 / AB" , Quantity = 500 , Status = "Completed" }
};
public WorkOrder GetWorkOrderInfo (string orderName )
{
return workOrders.Find(o => o.WorkOrderName == orderName);
}
public string UpdateWorkOrderStatus (string orderName, string newStatus )
{
var workOrder = this .GetWorkOrderInfo(orderName);
if (workOrder == null )
return "Operate Failed : The work order is not existing!" ;
workOrder.Status = newStatus;
return "Operate Succeed!" ;
}
public string ReduceWorkOrderQuantity (string orderName, int newQuantity )
{
var workOrder = this .GetWorkOrderInfo(orderName);
if (workOrder == null )
return "Operate Failed : The work order is not existing!" ;
if (workOrder.Status == "Completed" )
return "Operate Failed : The work order is completed, can not be reduced!" ;
if (newQuantity <= 1 || newQuantity >= workOrder.Quantity)
return "Operate Failed : The new quantity is invalid!" ;
workOrder.Quantity = newQuantity;
return "Operate Succeed!" ;
}
}
public class WorkOrder
{
public string WorkOrderName { get ; set ; }
public string ProductName { get ; set ; }
public string ProductVersion { get ; set ; }
public int Quantity { get ; set ; }
public string Status { get ; set ; }
}
3. 配置文件 (appsettings.json) 建议使用环境变量或密钥管理服务(如 Azure Key Vault、HashiCorp Vault)来管理敏感信息,避免硬编码在配置文件中。
{
"LLM_API_PROVIDER" : "ZhiPuAI" ,
"LLM_API_MODEL" : "glm-4" ,
"LLM_API_BASE_URL" : "https://open.bigmodel.cn" ,
"LLM_API_KEY" : "your_api_key_here"
}
4. 初始化 Kernel 与插件 在应用程序启动时,加载配置并初始化 Semantic Kernel。
private Kernel _kernel = null ;
private OpenAIPromptExecutionSettings _settings = null ;
private IChatCompletionService _chatCompletion = null ;
private ChatHistory _chatHistory = null ;
private void ChatForm_Load (object sender, EventArgs e )
{
var configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.{ConfigConstants.LLM_API_PROVIDER} .json" ).Build();
var config = configuration;
var openAiConfiguration = new OpenAiConfiguration(
config["LLM_API_PROVIDER" ],
config["LLM_API_MODEL" ],
config["LLM_API_BASE_URL" ],
config["LLM_API_KEY" ]);
var openAiClient = new HttpClient(new CustomLlmApiHandler(openAiConfiguration.Provider, openAiConfiguration.EndPoint));
_kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(openAiConfiguration.ModelId, openAiConfiguration.ApiKey, httpClient: openAiClient)
.Build();
_chatCompletion = _kernel.GetRequiredService<IChatCompletionService>();
_chatHistory = new ChatHistory();
_chatHistory.AddSystemMessage("You are one WorkOrder Assistant. You help users manage manufacturing work orders." );
}
接下来,注册 Functions 到 Kernel 中。这是让 LLM 拥有'手脚'的关键步骤。
_kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("WorkOrderHelperPlugin" ,
new List<KernelFunction>
{
_kernel.CreateFunctionFromMethod((string orderName) =>
{
var workOrderRepository = new WorkOrderService();
return workOrderRepository.GetWorkOrderInfo(orderName);
}, "GetWorkOrderInfo" , "Get WorkOrder's Detail Information" ),
_kernel.CreateFunctionFromMethod((string orderName, int newQuantity) =>
{
var workOrderRepository = new WorkOrderService();
return workOrderRepository.ReduceWorkOrderQuantity(orderName, newQuantity);
}, "ReduceWorkOrderQuantity" , "Reduce WorkOrder's Quantity to new Quantity" ),
_kernel.CreateFunctionFromMethod((string orderName, string newStatus) =>
{
var workOrderRepository = new WorkOrderService();
return workOrderRepository.UpdateWorkOrderStatus(orderName, newStatus);
}, "UpdateWorkOrderStatus" , "Update WorkOrder's Status to new Status" )
}));
开启自动调用 Function,告诉大模型可以自行决定调用相关 Functions,而且大模型会自行决定根据什么顺序来调用,这就是大模型作为 Agent 大脑的规划能力。当然,我们还可以通过定制化 Planner 来增强 agent 的规划能力。
_settings = new OpenAIPromptExecutionSettings
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
5. 发送用户提示词 最后,实现用户交互逻辑。区分是否启用 Function Calling 模式进行测试。
private void btnSend_Click (object sender, EventArgs e )
{
_chatHistory.AddUserMessage(tbxPrompt.Text);
ChatMessageContent chatResponse = null ;
tbxResponse.Clear();
if (cbxUseFunctionCalling.Checked)
{
Task.Run(() =>
{
ShowProcessMessage("AI is handling your request now..." );
try
{
chatResponse = _chatCompletion.GetChatMessageContentAsync(_chatHistory, _settings, _kernel)
.GetAwaiter()
.GetResult();
UpdateResponseContent(chatResponse.ToString());
ShowProcessMessage("AI Response:" );
}
catch (Exception ex)
{
UpdateResponseContent($"Error: {ex.Message} " );
}
});
}
else
{
Task.Run(() =>
{
ShowProcessMessage("AI is handling your request now..." );
try
{
chatResponse = _chatCompletion.GetChatMessageContentAsync(_chatHistory, null , _kernel)
.GetAwaiter()
.GetResult();
UpdateResponseContent(chatResponse.ToString());
ShowProcessMessage("AI Response:" );
}
catch (Exception ex)
{
UpdateResponseContent($"Error: {ex.Message} " );
}
});
}
}
最佳实践与安全建议 在将 Agent 投入生产环境之前,还需要考虑以下关键点:
1. 安全与权限控制
API Key 管理 :切勿将 API Key 硬编码在代码库中。应使用环境变量、Azure Key Vault 或 AWS Secrets Manager。
权限最小化 :Agent 调用的工具函数应遵循最小权限原则。例如,工单更新接口不应允许删除工单,除非有明确授权。
输入过滤 :对用户输入的 Prompt 进行安全检查,防止 Prompt Injection 攻击导致 Agent 执行恶意操作。
2. 错误处理与重试
网络异常 :LLM 调用和外部 API 调用都可能超时或失败。需要实现指数退避重试机制。
业务逻辑校验 :如示例代码所示,在 Function 内部进行严格的参数校验,防止脏数据写入。
日志记录 :详细记录 Agent 的思考过程(Thought)、工具调用参数及返回结果,便于问题排查和审计。
3. 性能优化
缓存策略 :对于相同的查询请求,可以在 Service 层增加缓存,减少 LLM 调用次数和延迟。
流式输出 :对于长文本回复,建议使用 Stream 模式,提升用户体验。
总结 本文简单介绍了 AI Agent 的基本概念和工作方式,对比了高代码手搓和低代码拖拉拽两种开发模式。最后,通过 C# + Semantic Kernel + 智谱 GLM-4 模型演示了如何快速开发一个简易的 AI Agent。
虽然这只是个 Demo,但希望对你快速了解 Agent 有所帮助。未来,随着 RAG(检索增强生成)技术的引入和更复杂的 Planner 设计,Agent 将在企业级应用中发挥更大的价值。开发者应关注如何平衡自动化程度与人工干预的边界,确保系统的安全可控。
扩展阅读
Microsoft Semantic Kernel 官方文档
OpenAI Function Calling 指南
LangChain 框架架构分析
大模型在企业内部署的最佳实践
相关免费在线工具 RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online