关注我们
(本文阅读时间:24分钟)
第一章 问题分类
我会把问题设定放在首位,也就是我们的第一章。毕竟所有生成式的 AI 都是需要基于问题给出答案。所以我一直不认同人工智能会取代人类,没有人类哪来问题呢?
ChatGPT 的神奇之处在于它可以根据你的问题去完成不同的工作,如归纳、翻译、分类等。我们的问题多种多样,除了问日常生活、通用知识外,还会遇到不同的时效性的问题和针对特定行业的问题。这个时候交给 ChatGPT,你往往会发现有时候它在胡说八道。这时我们需要去纠正这些错误。你可以用 Prompt 提示语,去设定一些规则让 ChatGPT 回答 “不太清楚”,“没法解答”,“我在努力学习”等等。这也是 Prompt 工程师工作的关键。其实在我们早期的对话机器人里,就有非常多针对实时问题和行业专有问题的解答。也许我们可以把这些语料重新添加到我们的 GPT 模型,让它变得更强大。也许把问题分类是一个最根本的做法。
举个例子,我们用了 OpenAI 的 davinci-03 模型去解答 “今天天气”,你会没法找到答案。也许你会说 ChatGPT 很笨,但实际上在 API 主导的年代,这不是一个困难的事情。
对问题进行分类,我们有两种方式。通过机器学习进行问题的分类是我们过往经常用的,除了分类外,还可以快速地提取不同的语义实体,基于问题进行更细致的划分,找到更符合的答案。现在还可以基于 OpenAI 去完成分类,这对于不熟悉机器学习的人来说是较好的选择。
针对 .NET 我们有很好的 Machine Learning 工具 ML.NET。通过 ML.NET 你可以快速对文本进行分类。
-
ML.NET 2.x 虽然支持了 NLP 的文本分类,但是现阶段还不支持中文,所以我用到 Jieba,如果你是用英语的话,可以直接采用 BERT 来完成。 -
在 Notebook 没办法加载 ML.NET 生成的模型,只能在传统程序中调用。 -
现在没办法转换为 ONNX。
你也可以通过 Azure OpenAI Service 对问题进行分类,这是更多开发者希望见到的,也是最傻瓜的方法。


-
请帮我针对问题进行分类,包括天气,课程,生成式
问: 会下雨吗?类别:天气
问: 今天温度?类别:天气
问: 温度多少?类别:天气
问: 什么是新能源车?类别: 课程
问: 新能源车的特点?类别: 课程
问: 概念是什么?类别: 课程
问: 写一首诗歌?类别: 生成式
问: 翻译一下 类别: 生成式
问: 计算结果 类别: 生成式
问: 电动车特点 类别:


传统机器学习的文本分类优势是模型可以离线使用,但语料不足的情况下,难以获得准确的分类结果,而且技术要求较高。如果你处在需要隔离内部和外部业务数据的场景,可以选择传统机器学习文本分类。而 Azure OpenAI Service 可以在 Prompt 上设置少量样例来完成分类,但比较依赖网络。现在是网络通行的年代,Azure OpenAI Service 有更高的价值。而且 Azure OpenAI Service 的成本还非常低。请记住一句话,场景很重要,但 Azure OpenAI Service 并不是让你抛弃原有的技术。你需要结合众多的人工智能知识来打造智能化的解决方案。
OpenAI 是新物种,很多人希望除了能通过 Azure OpenAI Service 访问到 API 完成企业级的应用外,更希望能有一个好的架构来管理好基于 OpenAI 的项目。如果单纯从 REST 的角度看,作为 .NET 开发者已经熟能生巧。但实际上如果你深入了解 OpenAI 的应用,你会发现基于 OpenAI 的应用更多的集中在进行 Prompt 管理上。这与我们传统意义上的架构有所不同。首先它不再以代码为主导,更多是以 Prompt 为代表的文本。你可以通过 Prompt 去描述一段要求,让 OpenAI 完成。当我们希望结合 OpenAI 来构建智能系统的时候就会发现,我们需要非常多的 Prompt 来完成不同的业务。如何去管理 Prompt,以及如何优化好我们不同业务流的智能化工作,是架构一个好的 OpenAI 所必需的。综上所述,Semantic Kernel 是帮我们管理各式各样 Prompt (也就是 Skill )的框架。也许我们可以先用 Semantic Kernel 来做一个文本分类来进行学习。
-
创建一行 Cell, 引入 Microsoft.SemanticKernel 的 .NET 库:
-
#r "nuget: Microsoft.SemanticKernel, *-*"
-
引入 Microsoft.SemanticKernel 的命名空间:
-
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.SemanticFunctions;
-
创建 SK 内核实例:
-
IKernel kernel = Kernel.Builder.Build();
-
kernel.Config.AddAzureOpenAITextCompletionService(
"GPT3",
"text-davinci-003",
"Your Endpoint",
"Your Key"
);
-
设置和文本分类相关的 Prompt:
-
string skPrompt = """
请帮我把 {{$input}} 进行类别确认,类别包括天气,课程,生成式,如果不太清楚,请回答没法确认,分类参考如下:
问: 会下雨吗?类别:天气
问: 今天温度?类别:天气
问: 温度多少?类别:天气
问: 什么是新能源车?类别: 课程
问: 电动车的特点 类别: 课程
问: 概念是什么?类别: 课程
问: 课程相关的内容有哪些?类别: 课程
问: 写一首诗歌?类别: 生成式
问: 翻译一下 类别: 生成式
问: 计算结果 类别: 生成式
如果能确认类别,天气相关请只输出 1 , 课程相关请只输出 2 , 生成式相关请只输出 3 ,没法确认相关请只输出 0,并把{{$input}}和它的类别参考以下 json 格式输出
{""question"":""{{$input}}"",""label"":""{{$label}}""}
""";
-
和模型相关的配置:
-
var promptConfig = new PromptTemplateConfig
{
Completion =
{
MaxTokens = 60,
FrequencyPenalty = (float)0,
PresencePenalty = (float)0
}
};
var promptTemplate = new PromptTemplate(
skPrompt,
promptConfig,
kernel
);
-
创建一个 SemanticFunctionConfig,绑定 promptConfig。promptTemplate,为内核添加一个具备文本分类功能的函数做准备:
-
var functionConfig = new SemanticFunctionConfig(promptConfig, promptTemplate);
-
通过内核注册技能和能力:
-
var classificationFunction = kernel.RegisterSemanticFunction("TextSkill", "TextClassification", functionConfig);
-
现在你可以设置输入来尝试看看是否能满足要求:
-
var input = """
今天广州天气怎么样?
""";
var classification = await kernel.RunAsync(input, classificationFunction);
Console.WriteLine(classification);
-
{"question": "今天广州天气怎么样?", "label": "1"}
本章正式进入 Azure OpenAI Service 的应用学习,基于文本分类,我们用传统的 ML.NET,Azure OpenAI .NET SDK,以及 Semantic Kernel .NET SDK 三种方法完成了相关的操作。对于开发者来说,可以体验基于传统的机器学习方式以及人工智能方式来完成文本分类的任务。希望大家能有所收获!
第二章 技能使用大全
▍常规能力
这些都是生成式 AI 模型带来的常规能力。写好 Prompt 来描述你需要的能力是很重要的。
▍时效性能力
生成式 AI 最大的问题之一是时效性缺失,当然现在 GPT-4 也开始具备一定的这种能力,但还是有局限的。例如一些日常、新闻、政策、查询实时天气等,都属于时效性的问题。这时候,我们需要结合搜索引擎,以及企业内部数据库的配合来赋予生成式 AI 一定的时效性能力。
▍专业性能力
▍SK 的重要概念

-
CustomSkill - 自定义技能(我们会在函数/方法中讨论它)。 -
EmailSkill - 电子邮件技能有申请相关的邮件 ApplyMail,有商业相关的邮件 BizMail,也有天气相关的邮件 WeatherMail 的能力。 -
WriteSkill - 书写技能有文本分类 Classification,归纳 Summary,翻译 Translate 等能力。
-
请帮我把 {{$input}} 进行类别确认,类别包括天气,课程,生成式,如果不太清楚,请回答没法确认,分类参考如下:
问: 会下雨吗?类别:天气
问: 今天温度?类别:天气
问: 温度多少?类别:天气
问: 什么是新能源车?类别: 课程
问: 电动车的特点 类别: 课程
问: 概念是什么?类别: 课程
问: 课程相关的内容有哪些?类别: 课程
问: 写一首诗歌?类别: 生成式
问: 翻译一下 类别: 生成式
问: 计算结果 类别: 生成式
如果能确认类别,天气相关请只输出 1 , 课程相关请只输出 2 , 生成式相关请只输出 3 ,没法确认相关请只输出 0,并把{{$input}}和它的类别参考以下 json 格式输出
{""question"":""{{$input}}"",""label"":""{{$label}}""}
-
{
"schema": 1,
"type": "completion",
"description": "文本分类",
"completion": {
"max_tokens": 60,
"presence_penalty": 0.0,
"frequency_penalty": 0.0
}
}
-
var skillsDirectory = System.IO.Directory.GetCurrentDirectory() + "/Skills";
var write_skill = kernel.ImportSemanticSkillFromDirectory(skillsDirectory,"WriteSkill");
var questionLabel = await kernel.RunAsync("今天天气好吗", write_skill["Classification"]);
-
语意技能函数 - 通过封装 Prompt 提示语和模型设置来定义函数,这在第一章里已经提及。 -
原生技能函数 - 用于结合时效性技能和业务技能的函数封装,可以非常快速地定义不同的技能,如我需要查询一些入职相关的内容以及实时天气状况,我们都可以通过原生函数定义这些技能并赋予系统答案,再让生成式 AI 完成接下来的工作,这是我们定义原生技能函数的一个例子:
-
using Microsoft.SemanticKernel.SkillDefinition;
using Microsoft.SemanticKernel.Orchestration;
public class CompanySearchSkill
{
[SKFunction("search employee infomation")]
public string EmployeeSearch(string input)
{
return "欢迎了解社保相关内容";
}
[SKFunction("search weather")]
public string WeatherSearch(string text)
{
return "欢迎搜索天气";
}
}
-
CompanySearchSkill companySearchSkill = new CompanySearchSkill();
var customSkill = kernel.ImportSkill (companySearchSkill, "CompanySearchSkill");
-
var weatherOutput = await kernel.RunAsync("天气",customSkill["WeatherSearch"]);
var employeeOutput = await kernel.RunAsync("社保如何购买",customSkill["EmployeeSearch"]);
-
var planner = new SequentialPlanner(kernel);
-
var plan = await planner.CreatePlanAsync("查找广州天气把结果翻译成中文后根据天气情况生成穿衣提示,并结合天气结果和穿衣提示写一封邮件");
-
plan.Steps

-
var result = await kernel.RunAsync(plan);
result.Result
用好 Prompt 能让生成式 AI 给出更准确的答案。管理好 Prompt 的集合对于企业来说是非常重要的。通过 Semantic Kernel 我们可以快速地完成各种 Prompt 的整合,通过本章你可以学习管理不同的 Prompt,完成不同的企业工作流程。
相关资料
-
关于 ML.NET: https://dotnet.microsoft.com/en-us/apps/machinelearning-ai/ml-dotnet -
关于 Semantic Kernel: https://github.com/microsoft/semantic-kernel


评论留言