首页 > 其他分享 >大模型应用开发初探 : 手搓一个简易Agent

大模型应用开发初探 : 手搓一个简易Agent

时间:2024-09-14 17:49:01浏览次数:10  
标签:string AI Agent 简易 API LLM 初探 new

大家好,我是Edison。

今天是中秋节前最后一个工作日,加油挺住,马上就放假了!

近期我一直在学习和了解LLM的相关知识,听到大家都在谈论AI Agent,说它是接下来几年大模型应用开发的新范式,那么什么是AI Agent,如何快速开发一个AI Agent呢?

AI Agent:可以帮你执行任务的助手

学术界和工业界对术语“AI Agent”提出了各种定义。其中,OpenAI将AI Agent定义为“以大语言模型为大脑驱动的系统,具备自主理解、感知、规划、记忆和使用工具的能力,能够自动化执行完成复杂任务的系统。”

说人话就是:大多数时候你给它一个最终你想要达成的目标,它能直接交付结果,过程你啥都不用管

NOTE:如果说人和动物的区别是人会使用各种工具,那么Agent和大模型的区别亦然。

我们可以把Agent与LLM形象地比作生物体与其大脑,Agent有手有脚,可以自己干活自己执行,而LLM呢,就是它的大脑。比如,如果你使用LLM大模型,它可能只能给你输出一份食谱,告诉你需要哪些食材和步骤来制作。但如果你使用Agent,它可能就是不仅提供食谱和步骤,还会根据你的需求,帮你选择合适的食材甚至自动下单购买,监控烹饪过程,确保食物口感,最终为你呈上一份佳肴。

AI Agent如何工作?

AI Agent的架构是其智能行为的基础,它通常包括感知、规划、记忆、工具使用和行动等关键组件,这些组件协同工作以实现高效的智能行为。

AI Agent的工作流程其实就是一个连续的循环过程

它从感知环境开始,经过信息处理、规划和决策,然后执行行动。最后,根据执行结果和环境反馈进行调整,以优化未来的行动和决策。

通过这种结构化和层次化的方式,AI Agent能够有效地处理信息,做出决策,并在复杂环境中执行任务。

如何开发AI Agent?

目前业界开发AI Agent主要有两种模式:

一种是基于Python或C#等编程语言,结合LangChain或Semantic Kernel等大模型应用开发框架,集成某个大模型API 和 企业内部的业务API能力,来完成具体领域的Agent。

另一种是基于Coze、Dify、AutoGen等Agent开发管理平台,拖过拖拉拽的方式快速生成一个Agent,与其说是开发,不如说是Workflow一样的配置。当然,也需要给这些平台注册封装好的企业内部API平台提供的能力供配置好的Agent去实现工具调用。

使用Semantic Kernel开发AI Agent

这里我们快速使用Semantic Kernel开发一个简易的WorkOrder Agent(MES工单助手),重点关注如何给LLM添加Function Calling能力,直观了解Agent规划任务 和 执行任务 的效果,而至于其他更加具体的,等待后续了解深入后再交流,这里我们就先来个感性认识即可。

以终为始,先看效果吧:

(1)没有实现Function Calling的效果,它就只是个Chatbot

(2)实现了Function Calling的效果,它就可以称为Agent

可以看到,我的需求其实包含两个步骤:第一步是更新工单的Quantity,第二步是查询更新后的工单信息。而这两个步骤我们假设其实都是需要去调用MES WorkOrderService API才能获得的,而这就需要我们给LLM加入Function Calling的能力,当然LLM自己得知道如何规划执行的步骤,哪个步骤先执行,哪个后执行。

示例代码的结构如下所示:

关键部分代码:

(1)Shared

OpenAiConfiguration.cs

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; // Default OpenAI-Compatible LLM API Provider
        ModelId = modelId;
        EndPoint = endPoint;
        ApiKey = apiKey;
    }

    public OpenAiConfiguration(string provider, string modelId, string endPoint, string apiKey)
    {
        Provider = provider;
        ModelId = modelId;
        EndPoint = endPoint;
        ApiKey = apiKey;
    }
}

CustomLLMApiHandler.cs

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: // Default: OpenAI-Compatible API Providers
                        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

这里我直接模拟的API的逻辑,你可以使用HttpClient去实际调用某个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!";
        // Update status if it is valid
        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!";

        // Some business checking logic like this
        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!";
        // Update quantity if it is valid
        workOrder.Quantity = newQuantity;
        return "Operate Succeed!";
    }
}

(3)Form

appsetting.json

{
  "LLM_API_PROVIDER": "ZhiPuAI",
  "LLM_API_MODEL": "glm-4",
  "LLM_API_BASE_URL": "https://open.bigmodel.cn",
  "LLM_API_KEY": "***********" // Update this value to yours
}

AgentForm.cs

初始化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.ZhiPu.json");
        var config = configuration.Build();
        var openAiConfiguration = new OpenAiConfiguration(
            config.GetSection("LLM_API_PROVIDER").Value,
            config.GetSection("LLM_API_MODEL").Value,
            config.GetSection("LLM_API_BASE_URL").Value,
            config.GetSection("LLM_API_KEY").Value);
        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.");
    }

注册Functions

_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
};

发送用户的提示词给大模型:

_chatHistory.AddUserMessage(tbxPrompt.Text);
        ChatMessageContent chatResponse = null;
        tbxResponse.Clear();

if (cbxUseFunctionCalling.Checked)
{
            Task.Run(() =>
            {
                ShowProcessMessage("AI is handling your request now...");
                chatResponse = _chatCompletion.GetChatMessageContentAsync(_chatHistory, _settings, _kernel)
                    .GetAwaiter()
                    .GetResult();
                UpdateResponseContent(chatResponse.ToString());
                ShowProcessMessage("AI Response:");
            });
        }
else
{
            Task.Run(() =>
            {
                ShowProcessMessage("AI is handling your request now...");
                chatResponse = _chatCompletion.GetChatMessageContentAsync(_chatHistory, null, _kernel)
                    .GetAwaiter()
                    .GetResult();
                UpdateResponseContent(chatResponse.ToString());
                ShowProcessMessage("AI Response:");
            });
}

小结

本文简单介绍了AI Agent的基本概念 和 工作方式,目前主要有两种开发Agent的模式,一种是高代码手搓,另一种是低代码拖拉拽。

最后,本文通过C# + Semantic Kernel + 智谱LLM模型 演示了如何快速开发一个简易的AI Agent,虽然它只是个Demo,但希望对你快速了解Agent有所帮助!

示例源码

本文示例:https://github.com/Coder-EdisonZhou/EDT.WorkOrderAgent

本文大模型:智谱 GLM-4 模型

推荐学习

Microsoft Learn, 《Semantic Kernel 学习之路

 

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

标签:string,AI,Agent,简易,API,LLM,初探,new
From: https://www.cnblogs.com/edisonchou/p/-/quick-start-on-ai-agent-by-sk

相关文章

  • 初探CTF-WEB挑战
    一、作业内容1.准备各种工具,并且能够使用2.完成新手题,找到flag二、操作步骤1.EzLogin2.Canyouaccess3.Chopper4.cookie5.Employeeswork6.Ezinclude7.Ezsearch8.Robots9.Vim10.Wtfbutton三、作业总结作业内容准备各种工具,并且......
  • 经典前端+后端+表头+表身的开发实战参考简易模板【珍藏】
    前端部分(Vue3+ElementPlus)1.修改MPS002HList.vue(主生产计划列表)a.添加查询表单在模板中添加查询表单,包含产品料号、品名、规格和年月的输入项。<template><div><!--查询表单--><el-form:inline="true":model="filters"class="demo-form-inline&qu......
  • 简易贪吃蛇js
    functionsta(){varshe=[{x:0,y:0,s:0}];//身体varshenti='';//当前前进方向varzou='';//下次前进方向vardan={x:0,y:0}//蛋坐标functionadddan(){//生成一个蛋varsy=[];......
  • ELK 8.15 启用Fleet Server和安装Agent
    注意,这里的URL,使用端口8220,不是443curl-L-Ohttps://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.15.1-linux-x86_64.tar.gztarxzvfelastic-agent-8.15.1-linux-x86_64.tar.gzcdelastic-agent-8.15.1-linux-x86_64可以将如下这一段存为一个sh文件,......
  • WebRTC 初探
    背景我正在实现一个FC游戏网站,PC用户仅需要配置键盘便能实现小伙伴们一起玩,但是手机用户就比较麻烦了传统的网页游戏都是通过HTTP/WS的方式实现联机,对于服务器的负担还是比较重的.实际上需要一起玩的小伙伴一般都在一块,也没必要使用远端的服务器转发.任意一个小......
  • NATAPP实现内网穿透简易教程
    NATAPP是什么NATAPP是一个十分容易上手的内网穿透工具,可以把本机的ip和端口映射到公网,将本机暴露在公网中供他人访问。这在进行一些回调接口的本地测试(如支付宝微信支付的回调接口)时十分好用,同时也可以用来搭建服务器私服,和朋友一起畅快联机。NETAPP提供了两条免费隧道供注册用......
  • 终于有人说清楚了基于大模型的Agent进行任务规划的10种方式(附代码和论文)
    在OpenAIAI应用研究主管LilianWeng的博客**《大语言模型(LLM)支持的自主式代理》**[1]中,将规划能力视为关键的组件之一,用于将任务拆解为更小可管理的子任务,这对有效可控的处理好更复杂的任务效果显著。基于大语言模型(LLM)的自主代理组成人是如何做事的?在日常工作中,我......
  • (5-1)绘制饼状图:绘制基本的饼状图(绘制简易的饼状图+修饰饼状图+突出显示某个饼状图的部
    饼状图常用于数据统计和分析领域,通常分为2D与3D饼状图。饼状图显示一个数据系列(数据系列:在图表中绘制的相关数据点,这些数据源自数据表的行或列。在现实应用中,经常使用饼状图来展示数据分析的结果,这样可以更加直观的展示数据分析结果。在本节的内容中,将详细讲解使用Python绘制......
  • wangeditor——cdn引入的形式创建一个简易版编辑器——js技能提升
    昨天同事那边有个需求,就是要实现聊天功能,需要用到一个富文本编辑器,参考如下:上面的这个效果图是博客园的评论输入框最终使用wangEditor编辑器实现的效果如下:只保留了个别的菜单:默认模式的wangEditor编辑器如下:下面直接上代码:解决步骤1:cdn引入head头部标签引入css<......
  • 基于Java Swing的简易人事信息管理系统设计与实现1.0
    目录概述数据库设计创建数据库创建表登录表 land员工信息表 empinfoJava代码实现连接数据库的类 Connect登录界面 Login功能对话框 MyDialog主界面 System运行效果截图:结论 概述在软件开发过程中,利用JavaSwing框架构建图形用户界面(GUI)是一种常见的做......