iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
AI & Data

OpenAI 從提示工程(Prompt Engineering)到語義核心(Semantic Kernel)的實踐系列 第 19

Semantic Kernel的實踐:Semantic Kernel - Plugins開發篇 native functions

  • 分享至 

  • xImage
  •  

前言

前面二篇談論如何建立與使用 semantic functions,接下來要談的就是Plugins的另一種function型態 - native functions,簡單來說native functions就是一般日常開發者悉熟用傳統程式語言所寫的的function,以Semantic Kernel來說目前支援 C#/Python/Java/TypeScript(coming soon)。

範例採用C#程式語言,並以主控台應用程式做為示範,使用的是.net 7.0。
此外GPT模型使用的是Azure OpenAI GPT-4,事實也可以依需求改用OpenAI服務,而模型也可以改用GPT-3.5。

native functions

native functions 以傳統程式語言所撰寫,像是讀寫檔案/發送API/時間日期運算/數學運算等,舉凡LLM模型自已無法做到的,都可以用native function來解決,也等同於增強LLM模型的能力,這取決於你的LLM應用場景。雖然native functions實際內容是傳統程式語言的程式碼,但是為了要讓Kernel載入Plugins後,可以知道這是一個function,因此必須使用 SKFunction decorator來定義這個function並且使用語義描述這個function的作用。結構上大致會是這個樣子的

public class MyPlugin
{
    [SKFunction, Description("描述這個function的用途")]
    public string NatvieFunSample()
    {
        return "SK Natvie Function Sample"; //do something
    }
}

直接來操作演練試試,假設想建立一個可以取得客戶姓名的native function,那麼我們可以這麼做

  • 首先跟semantic functions一樣,在Plugins目錄(不一定要叫做Plugins,可以自由命名)下建立專用目錄

https://ithelp.ithome.com.tw/upload/images/20231004/20126569veccyCaPiO.png

  • 接著新增一個Customer類別,然後撰寫邏輯
 public class Customer
{
    public string GetCustomerContact(string cusCode)
    {
        //撰寫從CRM DataBase 取得客戶連絡人資料邏輯
        //do something
        return $"居匹踢";
    }
}
  • 最後要讓LLM模型理解這個function,所以必須給予適當的描述(會影響Planner機制的效果,後面文章再談),加入SKFunction與Description修飾
public class Customer
{
    [SKFunction, Description("取得客戶連絡人")]
    public string GetCustomerContact(string cusCode)
    {
        //撰寫從CRM DataBase 取得客戶連絡人資料邏輯
        //do something
        return $"居匹踢";
    }
}
  • 至此就完成了一個native function,接著就是Kernel要如何使用它,這裡透過ImportSkill方法,new一個Customer物件傳入,並且給它一個Plugin名稱就行
 // Import the Plugin .
var crmPlugin = kernel.ImportSkill(new Plugins.CrmPlugin.Customer(), "CrmPlugin");
           
  • 調用native function
// 經由Native Function取得指定客戶編號的連絡人姓名
var cusContactName = await kernel.RunAsync("C2023001", crmPlugin["GetCustomerContact"]);

  • 取得結果
    https://ithelp.ithome.com.tw/upload/images/20231004/20126569be91LshmcB.png

Prompt呢?

上述的範例,不知道大家有沒有發現,結果看起來就是一個普通function,然後有回傳值這樣而已,那跟LLM應用的關係是?對的,沒錯,如果只是這樣做,其實完全沒有動用到LLM模型,那native function到底怎麼用?

讓我們再回想一下,實作LLM應用一切的源頭應來自於Prompt,對吧?那麼場景應該是轉變成LLM模型在處理Prompt時能夠意識到,在必要時刻時能夠調用native function。

那要怎麼改?直接來看

  • 建立一個寫電子郵件的 semantic function (不知道什麼是semantic function請往前文章看)
    https://ithelp.ithome.com.tw/upload/images/20231004/20126569Jj9w0VGj9q.png

  • skpromp.txt 給予以下內容

你是一位行政助理,負責處理我所交辧的文書作業任務
現在,請幫我寫一封信給
"""
{{$input}}
"""
內容是下星期1開始我將休假1個月,有任何緊急事項,可以連繫公司代理人
  • config.json 給予以下內容
{
  "schema": 1,
  "type": "completion",
  "description": "產生Email",
  "completion": {
    "max_tokens": 2000,
    "temperature": 0.2,
    "top_p": 0.0,
    "presence_penalty": 0.0,
    "frequency_penalty": 0.0
  },
  "input": {
    "parameters": [
      {
        "name": "Input",
        "description": "客戶姓名",
        "defaultValue": ""
      }
    ]
  }
}
  • 到這裡我們專案內具有2個Plugin,一個是native function,一個是semantic function
    native function (CrmPlugin)負責從CRM系統取客戶姓名
    semantic function(WriterPlugin) 負責寫email內容

  • 調用function,工作流程上是先調用CrmPlugin拿到客戶姓名,再調用WriterPlugin寫email內容

// Import the Plugin .
var crmPlugin = kernel.ImportSkill(new Plugins.CrmPlugin.Customer(), "CrmPlugin");

// Import the Plugin from the plugins directory.
var pluginsDirectory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Plugins");
var plugin = kernel.ImportSemanticSkillFromDirectory(pluginsDirectory, "WriterPlugin");

//調用CrmPlugin/GetCustomerContact function拿到客戶姓名
var getCusContact = kernel.Skills.GetFunction("CrmPlugin", "GetCustomerContact");
string cusContact = (await kernel.RunAsync("C2023001", getCusContact)).Result;

//調用WriterPlugin/Email function寫email內容
var writeEmail = kernel.Skills.GetFunction("WriterPlugin", "Email");
string email = (await kernel.RunAsync(cusContact, writeEmail)).Result;

Console.WriteLine(email);
  • 生成結果
    https://ithelp.ithome.com.tw/upload/images/20231004/20126569SuAitN94v7.png

範例原始碼 : https://github.com/iangithub/sklearn/tree/main/NativeFunctionSample

結語

本篇內容說明如何實作natvie function,並且結合semantic function產生生成結果。然而,上述的做法並不夠好,不夠聰明,可以看到程式仍然以傳統思維的方式,按步就班手動調用Plugins,理想上應該一個prompt輸入後,自動調用Plugins,然後取得結果即可。下一篇我們將再進一步做調整。

嗨,我是Ian,我喜歡分享與討論,今年跟2位朋友合著了一本ChatGPT主題書,如果你是一位開發者,這本書或許會有些幫助,https://www.tenlong.com.tw/products/9786263335189
這次的鐵人賽文章也會同時發佈於個人blog,歡迎關注我的blog : https://medium.com/@ianchen_27500


上一篇
Semantic Kernel的實踐:Semantic Kernel - Plugins開發篇 Semantic functions (Part 2)
下一篇
Semantic Kernel的實踐:Semantic Kernel - Plugins開發篇 Semantic Function調用Native Function
系列文
OpenAI 從提示工程(Prompt Engineering)到語義核心(Semantic Kernel)的實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言