阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈

現在,您可以在回答提示時授予 OpenAI 對應用程式 API 的存取權限。這意味著,只需幾行程式碼,您就可以讓使用者使用自然語言提示與您的 API 進行交互,而不是使用複雜的 API 呼叫鏈。

在本文中,我們將解釋它的工作原理、何時可能與使用相關,並逐步介紹如何使用Encore建立一個簡單的實作。

它是如何運作的

除了向 OpenAI API 發送文字提示(用於與支援 ChatGPT 的 LLM 模型互動)之外,現在您還可以發送系統中定義的可以使用的函數清單。 AI會自動決定是呼叫一個還是多個函數來回答提示。

值得一提的是,人工智慧本身並沒有執行這些功能。相反,模型只是產生可用於呼叫函數的參數,然後您的程式碼可以選擇如何處理這些參數,可能是透過呼叫指定的函數。這是一件好事,因為您的應用程式始終處於完全控制之中。

函數呼叫的生命週期流程:

函數呼叫生命週期流程圖

什麼時候會使用它?

  1. 從各種服務獲取資料:人工智慧助理現在可以回答諸如「我最近的訂單是什麼?」之類的問題。透過從內部系統獲取最新的客戶資料。

  2. 採取行動:人工智慧助理現在可以代表使用者採取行動,例如透過存取日曆 API 安排會議。現在只需幾行程式碼即可將類似 Siri 的行為加入到您自己的應用程式中。

  3. 自然語言 API 呼叫:將用自然語言表達的使用者查詢轉換為複雜的 API 呼叫鏈。讓 LLM 建立從您自己的資料庫取得資料所需的 SQL 查詢。

  4. 提取結構化資料:建立一個獲取原始文字、然後將其轉換為結構化資料並將其保存在資料庫中的管道現在非常容易組裝。不再需要將相同類型的資料複製並貼上到 ChatGPT 中。

我們來試試吧

在這個簡單的範例中,我們正在建立一個會話助手,它可以幫助使用者瀏覽書籍資料庫。為了讓助手變得有用,我們希望它能夠在我們的資料庫中找到書籍。

我們將使用Encore.ts快速建立與我們的應用程式互動所需的端點,並且 OpenAI API 將使用這些端點來回答使用者的提示。

您可以在此處查看範例的完整程式碼:https://github.com/encoredev/examples/tree/main/ts/gpt-functions

1. 安裝 Encore 並建立您的應用程式

若要自行執行該範例,請先安裝 Encore:

  • macOS: brew install encoredev/tap/encore

  • Linux: curl -L https://encore.dev/install.sh | bash

  • Windows: iwr https://encore.dev/install.ps1 | iex

接下來,使用以下命令使用範例程式碼建立一個新的 Encore 應用程式:

encore app create gpt-functions-example --example=ts/gpt-functions

您還需要一個OpenAI API 金鑰並透過執行以下命令進行設定:

encore secret set OpenAIAPIKey

之後您就可以執行該應用程式了:

encore run

2. 建立一些函數

函數呼叫的起點是在您自己的程式碼庫中選擇您希望模型能夠為其產生參數的函數。

對於此範例,我們希望允許模型呼叫我們的listgetsearch端點:

import { api } from "encore.dev/api";

export interface Book {
  id: string;
  name: string;
  genre: Genre;
  description: string;
}

export enum Genre {
  mystery = "mystery",
  nonfiction = "nonfiction",
  memoir = "memoir",
  romance = "romance",
  historical = "historical",
}

// Using a hardcoded database for convenience of this example
const db: Book[] = [
  {
    id: "a1",
    name: "To Kill a Mockingbird",
    genre: Genre.historical,
    description: `Compassionate, dramatic, and deeply moving, "To Kill A Mockingbird" takes readers to the roots of human behavior - to innocence and experience, kindness and cruelty, love and hatred, humor and pathos. Now with over 18 million copies in print and translated into forty languages, this regional story by a young Alabama woman claims universal appeal. Harper Lee always considered her book to be a simple love story. Today it is regarded as a masterpiece of American literature.`,
  },
  ...
];

export const list = api(
  {expose: true, method: 'GET', path: '/book'},
  async ({genre}: { genre: string }): Promise<{ books: { name: string; id: string }[] }> => {
    const books = db.filter((item) => item.genre === genre).map((item) => ({name: item.name, id: item.id}));
    return {books}
  },
);

export const get = api(
  {expose: true, method: 'GET', path: '/book/:id'},
  async ({id}: { id: string }): Promise<{ book: Book }> => {
    const book = db.find((item) => item.id === id)!;
    return {book}
  },
);

export const search = api(
  {expose: true, method: 'GET', path: '/book/search'},
  async ({name}: { name: string }): Promise<{ books: { name: string; id: string }[] }> => {
    const books = db.filter((item) => item.name.includes(name)).map((item) => ({name: item.name, id: item.id}));
    return {books}
  },
);

這裡值得注意的是,這些是我們在常規 CRUD 服務中可能擁有的端點,而我們的業務邏輯中沒有任何內容適合 LLM。

3. 向模型描述你的功能

我們現在可以建立一個「函數定義」來描述模型的函數。這個定義描述了函數的作用(以及何時呼叫)以及呼叫每個函數需要哪些參數。

您可以透過在系統訊息中提供清晰的指導、使用直覺的函數名稱以及函數和參數的詳細描述來確保模型呼叫正確的函數。

import {api} from "encore.dev/api";
import {book} from "~encore/clients";
import OpenAI from "openai";
import {secret} from "encore.dev/config";

// Getting API from from Encore secrets
const apiKey = secret("OpenAIAPIKey");

const openai = new OpenAI({
  apiKey: apiKey(),
});

// Encore endpoint the receives a text prompt as a query param and returns a message as a response
export const gpt = api(
  {expose: true, method: "GET", path: "/gpt"},
  async ({prompt}: { prompt: string }): Promise<{ message: string | null }> => {

    // Using the runTools method on the Chat Completions API
    const runner = openai.beta.chat.completions
      .runTools({
        model: "gpt-3.5-turbo",
        messages: [
          {
            role: "system",
            content:
              "Please use our book database, which you can access using functions to answer the following questions.",
          },
          {
            role: "user",
            content: prompt,
          },
        ],
        // The tools array contains the functions you are exposing
        tools: [
          {
            type: "function",
            function: {
              name: "list",
              strict: true,
              description:
                "list queries books by genre, and returns a list of names of books",
              // The model will use this information to generate
              // arguments according to your provided schema.  
              parameters: {
                type: "object",
                properties: {
                  genre: {
                    type: "string",
                    enum: [
                      "mystery",
                      "nonfiction",
                      "memoir",
                      "romance",
                      "historical",
                    ],
                  },
                },
                additionalProperties: false,
                required: ["genre"],
              },
              // Calling the list endpoint in our book service 
              function: async (args: { genre: string }) => await book.list(args),
              parse: JSON.parse,
            },
          },

          ...

        ],
      })

    // Get the final message and return the message content
    const result = await runner.finalChatCompletion();
    const message = result.choices[0].message.content;
    return {message};
  },
);

在上面的程式碼中,我們定義了 LLM 應如何以及何時呼叫我們的list端點。我們指定端點採用五種預定義流派之一作為輸入,且genre參數是必需的。

4. 呼叫範例

讓我們利用 Encore 附帶的 Local Development Dashboard 並嘗試呼叫我們的助手並提示Recommend me a book that is similar to Kill a Mockingbird看看它會做出什麼反應。

{% youtube PpAbLAJQeTs %}

助理回覆:

我建議您查看以下與《殺死一隻知更鳥》類似的歷史書籍:

  1. 所有我們看不見的光

  2. 小龍蝦唱歌的地方

這些書與《殺死一隻知更鳥》有一些相似之處,值得探索

這似乎是一個合適的答案,因為這兩本書也存在於我們的資料庫中,並且與《殺死一隻知更鳥》屬於同一類型。

Encore 在呼叫gpt端點時為我們產生了追蹤。在追蹤詳細資料中,我們可以準確地看到 LLM 呼叫了哪些函數來產生最終回應:

  1. LLM 從提示中提取了“To Kill a Mockingbird”,並使用它來呼叫search端點。

  2. search端點傳回「To Kill a Mockingbird」的 ID。

  3. LLM 使用 ID 來呼叫get端點。

  4. get端點返回書籍的描述和類型。

  5. LLM 使用流派來呼叫list端點。

  6. list端點傳回所請求類型的書籍清單。

  7. 法學碩士推薦兩本與《殺死一隻知更鳥》同一類型的書。

法學碩士召集了我們所有三個職能部門來提出建議,令人印象深刻!

使用結構化輸出進行函數呼叫

預設情況下,當您使用函數呼叫時,API 將為您的參數提供盡力匹配,這表示在使用複雜模式時模型有時可能會遺失參數或獲得錯誤的類型。

2024 年 8 月,OpenAI 推出了Structured Outputs 。當您透過在函數定義中設定strict: true來開啟它時(請參閱上面的程式碼範例)。結構化輸出可確保模型為函數呼叫產生的參數與您在函數定義中提供的 JSON 架構完全匹配。

函數呼叫的陷阱

使用函數呼叫時需要注意的一些事項:

  • LLM 會讀取從函數傳回的資料以確定下一步(傳回回應或繼續呼叫函數)。如果您的函數傳回大量有效負載,那麼您可能會為每個提交的提示發送大量資金。解決此問題的一種方法是限制從函數傳回的資料。您也可以指定每個提示允許的max_tokens ,如果達到限制,模型將切斷回應。

  • 與您可能的想法相反,在單一工具呼叫中發送大量函數將降低模型選擇正確工具的能力。 OpenAI 建議將單一工具呼叫中的函數數量限制為不超過 20 個。

總結

現在您已經知道如何使用 OpenAI 的函數呼叫功能將 ChatGPT 連接到外部工具了。


原文出處:https://dev.to/encore/how-to-let-chatgpt-call-functions-in-your-app-27j8


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。

阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈