前段时间,DeepSeek作为国产人工智能大型语言模型,在全世界大火了一把。它的出现,很大程度上解决卡脖子的问题,追平美国OpenAI的ChatGPT大模型,甚至某些领域超越了ChatGPT。
如果体验过DeepSeek的同学,应该感受到了它的强大和便捷,但是有没有发现,如果只是单单使用DeepSeek的对话功能,它的作用好像也就只能和我们聊聊天,帮写写文案,分析下表格文件。
这些事情没有办法和我们使用的系统和工具集成起来,真正意义上帮我们减轻工作,更不用说帮我们自动完成工作。
那有没有办法呢?答案是有的!
我们可以引入AI Agent(智能工作体),AI Agent 可被定义为一种目标驱动的自主智能体,它通过 “感知→决策→行动” 的闭环流程来运作。在这个过程中,Agent 首先借助各类传感器对所处环境进行感知,收集相关信息;接着,依据内置的算法和策略对感知到的信息进行分析与决策,确定下一步行动方案;最后,通过执行器将决策转化为实际行动,作用于环境。
那这个AI Agent和LLM(大模型语言,如ChatGPT,DeepSeek)它们两是什么关系呢,下面我们来看一张图。
简单说,LLM是一个无所不知的大脑,而AI Agent就是躯体,LLM负责构想和理论指导,AI Agent就将这些构想和理论落实到具体智能场景中,替代人工,提升效率。
下面,我将使用微软提供的AI Agent框架SemanticKernel,使用DeepSeek大模型语言,来模拟实现在ERP系统中自动创建一个采购订单。
1.创建一个控制台项目
SemanticKernel只支持.net 6及以上版本,这里需要注意以下,然后我们在项目中引入Nuget包:
项目结果如下:
2.替换Program文件
DeepSeek通过api调用是收费的,我们需要在deepseek官网: https://www.deepseek.com上进行注册,获取我们的apikey
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Mozhi.Agent.DeepSeek.Plugins;
// Create a kernel with deepseek
var builder = Kernel.CreateBuilder();
Kernel kernel = builder.Build();
var chatCompletionService = new OpenAIChatCompletionService("deepseek-chat", new Uri("https://api.deepseek.com"), "deepseek给你的apikey");
// Add a plugin
kernel.Plugins.AddFromType<ProductPlugin>("Products");
kernel.Plugins.AddFromType<SupplierPlugin>("Suppliers");
kernel.Plugins.AddFromType<PurchaseOrderPlugin>("PurchaseOrders");
// Enable planning
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
// Create a history store the conversation
var history = new ChatHistory();
// Initiate a back-and-forth chat
string? userInput;
do
{
// Collect user input
Console.Write("User > ");
userInput = Console.ReadLine();
// Add user input
history.AddUserMessage(userInput);
// Get the response from the AI
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// Print the results
Console.WriteLine("Assistant > " + result);
// Add the message from the agent to the chat history
history.AddMessage(result.Role, result.Content ?? string.Empty);
} while (userInput is not null);
3. 编写Plugin
一个标准的采购订单,最基本的应该包括单据号,采购日期,供应商和若干条分录。
分录应该包含产品,价格,数量,金额的等字段。
所以我们定义三个Plugin
ProductPlugin:
定义了我们需要传给deepseek的产品数据,包括id,名称,价格信息,以及DeepSeek可以调用的函数方法。
using Microsoft.SemanticKernel;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace Mozhi.Agent.DeepSeek.Plugins
{
public class ProductPlugin
{
private readonly List<Product> products = new()
{
new Product { Id = Guid.Parse("482565ec-8e27-fa3b-04a9-a0295e898a88"), Name = "哇哈哈", Price = 5.69M },
new Product { Id = Guid.Parse("edf50f80-e02c-ab4d-1628-c88f5f2bbfab"), Name = "旺仔牛奶", Price = 3.50M },
};
[KernelFunction("get_products")]
[Description("Gets a list of products and their price")]
public async Task<List<Product>> GetProductsAsync()
{
return products;
}
}
public class Product
{
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("price")]
public decimal Price { get; set; }
}
}
SupplierPlugin
定义供应商的数据以及DeepSeek可以调用的方法。
using Microsoft.SemanticKernel;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace Mozhi.Agent.DeepSeek.Plugins
{
public class SupplierPlugin
{
private readonly List<Supplier> suppliers = new()
{
new Supplier { Id = Guid.Parse("00b7187e-fd0f-32e8-5568-bf86ffc9016a"), Name = "杭州哇哈哈饮料有限公司" },
new Supplier { Id = Guid.Parse("fecb4326-f426-8fce-1e6a-7b166b3570a1"), Name = "长沙旺旺食品有限公司" },
};
[KernelFunction("get_suppliers")]
[Description("Gets a list of supplier")]
public async Task<List<Supplier>> GetSuppliersAsync()
{
return suppliers;
}
}
public class Supplier
{
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
}
PurchaseOrderPlugin
定义了采购订单的基本模型和生成的方法,DeepSeek会根据我们的模型,生成一个Json的结果返回给我们。
从代码中可以看出,大模型生成的结果,其实并不能完全满足系统的需求,我们还是需要对数据进行一些加工处理。
using Microsoft.SemanticKernel;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace Mozhi.Agent.DeepSeek.Plugins
{
public class PurchaseOrderPlugin
{
[KernelFunction("create_purchase_order")]
[Description("create purchase order")]
public async Task<PuchaseOrder> CreatePurchaseOrder(string result)
{
var purchaseOrder = JsonConvert.DeserializeObject<PuchaseOrder>(result);
if (purchaseOrder.Items.Count == 0)
throw new Exception("item is required");
if(string.IsNullOrEmpty(purchaseOrder.Supplier) && !purchaseOrder.SupplierId.HasValue)
throw new Exception("supplier is required");
if(!string.IsNullOrEmpty(purchaseOrder.Supplier) && !purchaseOrder.SupplierId.HasValue)
purchaseOrder.SupplierId = (await new SupplierPlugin().GetSuppliersAsync()).FirstOrDefault(x=>x.Name == purchaseOrder.Supplier)?.Id;
foreach(var item in purchaseOrder.Items)
{
if (string.IsNullOrEmpty(item.Product) && !item.ProductId.HasValue)
throw new Exception("productId is required");
if(item.Price<=0)
throw new Exception("item price is required");
if (!string.IsNullOrEmpty(item.Product) && !item.ProductId.HasValue)
item.ProductId = (await new ProductPlugin().GetProductsAsync()).FirstOrDefault(x => x.Name == item.Product)?.Id;
if(item.Quantity<=0)
throw new Exception("item quantity is required");
item.Amount = item.Amount == 0 ? item.Price * item.Quantity : item.Amount;
item.Id = item.Id ?? Guid.NewGuid();
}
purchaseOrder.Number = "PO-" + DateTime.Now.ToString("yyyyMMddHHmmss");
purchaseOrder.Id = purchaseOrder.Id ?? Guid.NewGuid();
return purchaseOrder;
}
}
public class PuchaseOrder
{
[JsonPropertyName("id")]
public Guid? Id { get; set; }
[JsonPropertyName("number")]
public string Number { get; set; }
[JsonPropertyName("date")]
public DateTime Date { get; set; }
[JsonPropertyName("supplierId")]
public Guid? SupplierId { get; set; }
[JsonPropertyName("supplier")]
public string Supplier { get; set; }
[JsonPropertyName("items")]
public List<PurchaseOrderItem> Items { get; set; }
}
public class PurchaseOrderItem
{
[JsonPropertyName("id")]
public Guid? Id { get; set; }
[JsonPropertyName("productId")]
public Guid? ProductId { get; set; }
[JsonPropertyName("product")]
public string Product { get; set; }
[JsonPropertyName("price")]
public decimal Price { get; set; }
[JsonPropertyName("quantity")]
public decimal Quantity { get; set; }
[JsonPropertyName("amount")]
public decimal Amount { get; set; }
}
}
4.测试
我们启动项目,在console对话框中输入以下内容:帮我生成一张采购订单,日期为今天,供应商为旺旺,商品明细为旺仔牛奶,数量100,哇哈哈,数量20
我们在PurchaseOrderPlugin打个断点,看下DeepSeek给我们返回的消息:
从结果来说,deepseek很智能的帮我们补充了供应商的名称,返回的结果基本正确。但是在items里面,返回的产品名称字段是name,而我们需要的是Prodct或者ProductId,我们抛出了一个异常。
这个时候,AI Agent并不会使整个程序退出,而是再次帮我们发送请求给了DeepSeek,直到DeepSeek返回的结果信息符合我们的预期,能正常生成采购订单。
这是最终的结果
从上面的案例中,我们只是定义了输入数据和函数方法,AI Agent如何和deepseek进行沟通,以及在DeepSeek分析有偏差时,如何进行纠正,我们实际上并没有进行代码编码,这一切都是在智能的处理下完成。非常的nice!
当然,上面的案例,我们还不能真正的使用到生产中,但是我们只需要把plugin方法和我们ERP系统进行对接,再加上语音识别,就能真正的获得一个AI助手,应用到我们实际生产中。