大語言模型,像 ChatGPT, Llama 等已經席卷全球,從上圖的數據可以看出,ChatGPT 花了 5 天時間就達到了 100 萬用戶。而 Netflix 則花了近 4 年的時間。本文將使用 Gin 和 Langchain 教你快速構建一套 LLM API。

Gin

Gin[1]?是一個用于使用GoLang構建API的現代、快速的Web框架。它被設計為易于使用、高效且性能出色,利用了GoLang并發的強大能力,以實現極高的吞吐量。

LangChain

LangChain[2]?是一個用于開發由語言模型驅動的應用程序的框架。它旨在讓開發者輕松地連接到一個 LLM,并使用戶能夠為 LLM 提供額外的上下文。簡單來說,Langchain使LLM模型能夠基于在線、文檔或其他數據源中最新的信息生成響應。

準備工作

首先確保已經安裝了 Golang 的開發環境,其次需要下面幾個依賴包:

$ go get github.com/gin-gonic/gin
$ go get github.com/tmc/langchaingo
$ go get github.com/google/uuid
$ go get golang.org/x/exp@v0.0.0-20230713183714-613f0c0eb8a1

構建 API

Request 和 Response (routes/structs.go)

GenerateVacationIdeaRequest 是用戶將提供給我們的內容,以便我們為他們創建 vacation idea。我們希望用戶告訴我們他們喜歡的季節、他們可能有的任何愛好,以及他們的度假預算是多少。我們可以在后面將這些輸入提供給 LLM。

GenerateVacationIdeaResponse 是我們將返回給用戶的內容,表示想法正在生成中。Langchain 可能需要一些時間來生成響應,我們不希望用戶永遠等待他們的HTTP調用返回。因此,我們將使用 goroutines(稍后會詳細介紹!),用戶可以在幾秒鐘后檢查想法是否已完成。

GenerateVacationIdeaResponse 反映了這一點,包含兩個字段:

GetVacationIdeaResponse 是當用戶查詢想法或其狀態時我們將返回給用戶的內容。幾秒鐘后,用戶會說 “嗯,想法已經完成了嗎?”然后可以查詢我們的API。GetVacationIdeaResponse 具有與 GenerateVacationIdeaResponse 相同的字段,但添加了一個想法字段,當生成完成時 LLM 將填寫該字段。

type GenerateVacationIdeaRequest struct {
FavoriteSeason string json:"favorite_season" Hobbies []string json:"hobbies" Budget int json:"budget" } type GenerateVacationIdeaResponse struct { Id uuid.UUID json:"id" Completed bool json:"completed" } type GetVacationIdeaResponse struct { Id uuid.UUID json:"id" Completed bool json:"completed" Idea string json:"idea" }

API Routing (routes/vacation.go

現在我們的請求和響應模式已經確定,我們可以寫路由了。

GetVacationRouter 函數接受一個gin路由器作為輸入,并為其添加一個新的路由器組,路徑前綴為 /vacation。因此,我們添加到路由器的任何端點都將具有 /vacation前綴。然后我們添加兩個端點:

/create?端點將啟動一個goroutine,調用 langchain 和 openAI。它將返回一個?GenerateVacationIdeaResponse?給調用者,以便他們稍后可以檢查其狀態。他們可以通過?/:id?端點來檢查該想法的狀態。這將返回一個?GetVacationIdeaResponse。如果想法已經完成生成,它將包含一個id、一個想法,并且?completed?標志將設置為true。否則,它將包含一個id、一個空想法,并且?completed?標志將設置為 false。

package routes

import (
"net/http"

"github.com/afoley587/52-weeks-of-projects/07-golang-gin-langchain/chains"
"github.com/google/uuid"

"github.com/gin-gonic/gin"
)

func generateVacation(r GenerateVacationIdeaRequest) GenerateVacationIdeaResponse {
// First, generate a new UUID for the idea
id := uuid.New()

// Then invoke the GeneateVacationIdeaChange method of the chains package
// passing through all of the parameters from the user
go chains.GeneateVacationIdeaChange(id, r.Budget, r.FavoriteSeason, r.Hobbies)
return GenerateVacationIdeaResponse{Id: id, Completed: false}
}

func getVacation(id uuid.UUID) (GetVacationIdeaResponse, error) {
// Search the chains database for the ID requested by the user
v, err := chains.GetVacationFromDb(id)

// If the ID didn't exist, handle the error
if err != nil {
return GetVacationIdeaResponse{}, err
}

// Otherwise, return the vacation idea to the caller
return GetVacationIdeaResponse{Id: v.Id, Completed: v.Completed, Idea: v.Idea}, nil
}

func GetVacationRouter(router *gin.Engine) *gin.Engine {

// Add a new router group to the gin router
registrationRoutes := router.Group("/vacation")

// Handle the POST to /create
registrationRoutes.POST("/create", func(c *gin.Context) {
var req GenerateVacationIdeaRequest
err := c.BindJSON(&req)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "Bad Request",
})
} else {
c.JSON(http.StatusOK, generateVacation(req))
}
})

// Handle the GET to /:id
registrationRoutes.GET("/:id", func(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "Bad Request",
})
} else {
resp, err := getVacation(id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{
"message": "Id Not Found",
})
} else {
c.JSON(http.StatusOK, resp)
}
}
})

// Return the updated router
return router
}

現在我們可以將路由添加到我們的 API 中了。我們只需要實例化一個 Gin engine,將我們的路由添加到其中,然后運行即可。

import (
"github.com/afoley587/52-weeks-of-projects/07-golang-gin-langchain/routes"
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
routes.GetVacationRouter(r)
r.Run()
}

構建 Chain

現在我們已經為 API 設置了場景。現在,我們需要一種與我們的 LLM 進行交流的方法(或者至少向它提問)。

讓我們定義一個“數據庫”來存儲所有生成的想法。Vacations 是我們的度假“數據庫”。我在數據庫中加了引號,因為這只是一個在整個包中共享的切片。理想情況下,這應該是一種更持久、更穩定、更可擴展的存儲形式,但是本文僅做演示,切片就夠用了。Vacations 是一個Vacation 結構體的切片。我們的 Vacation 結構體只是一個數據持有者。它保存了正在進行和最終的度假對象。它具有我們之前討論過的GetVacationIdeaResponse相同的字段,但我更喜歡將它們分開,這樣可以更容易地解耦這些代碼片段。

我們需要向想要使用這個包的人提供兩種方法:

  1. 提供一種方式,讓調用者從我們的“數據庫”中檢索度假信息
  2. 提供一種方式,讓調用者請求生成新的度假想法 為了解決第一點,我們將編寫GetVacationFromDb(id uuid.UUID)函數。該函數將獲取度假的ID。然后它嘗試在地圖中找到度假,并且如果存在,它將返回度假對象。否則,如果ID不存在于數據庫中,則返回錯誤。

接下來,我們需要一些實際創建想法并將它們存儲到我們的數據庫中的東西。

GeneateVacationIdeaChange是我們最終開始調用langchain的地方。它接受幾個參數:

首先,我們需要實例化我們的 LLM 模型(這里我們使用 openai )。然后我們需要創建一些 prompts。我們創建一個系統提示以傳遞給 LLM。系統提示是應用程序或系統提供的指令或信息,用于指導對話。系統提示有助于設置上下文和指導 LLM 如何響應人類提示。

一個人類消息和模板遵循著相同的思路。我們可以把它想象成一個聊天應用程序。系統提示有助于設置聊天機器人。人類提示是用戶會問它的內容。

現在模板已經建立,我們可以通過首先創建聊天提示模板來創建聊天提示。為此,我們使用 FormatMessages 方法將用戶提供的值插入到我們的模板中。現在所有內容都以字符串格式進行了模板化。我們將創建LLM消息內容,這是我們的LLM將期望作為輸入的內容。最后,我們可以使用 GenerateContent 調用我們的 LLM。GenerateContent 的輸出將是從 OpenAI API 返回的結果,但我們只關心 LLM 生成的內容。內容是 LLM 生成的字符串響應,類似于 ChatGPT 窗口中返回的響應。

package chains

import (
"context"
"errors"
"log"
"strings"

"github.com/google/uuid"
"github.com/tmc/langchaingo/llms"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/prompts"
"golang.org/x/exp/slices"
)

type Vacation struct {
Id uuid.UUID json:"id" Completed bool json:"completed" Idea string json:"idea" } var Vacations []*Vacation func GetVacationFromDb(id uuid.UUID) (Vacation, error) { // Use the slices package to find the index of the object with // matching ID in the database. If it does not exist, this will return // -1 idx := slices.IndexFunc(Vacations, func(v *Vacation) bool { return v.Id == id }) // If the ID didn't exist, return an error and let the caller // handle it if idx < 0 { return Vacation{}, errors.New("ID Not Found") } // Otherwise, return the Vacation object return *Vacations[idx], nil } func GeneateVacationIdeaChange(id uuid.UUID, budget int, season string, hobbies []string) { log.Printf("Generating new vacation with ID: %s", id) // Create a new vacation object and add it to our database. Initially, // the idea field will be empty and the completed flag will be false v := &Vacation{Id: id, Completed: false, Idea: ""} Vacations = append(Vacations, v) // Create a new OpenAI LLM Object ctx := context.Background() llm, err := openai.New() if err != nil { log.Printf("Error: %v", err) return } // Create a system prompt with the season, hobbies, and budget parameters // Helps tell the LLM how to act / respond to queries system_message_prompt_string := "You are an AI travel agent that will help me create a vacation idea.\n" + "My favorite season is {{.season}}.\n" + "My hobbies include {{.hobbies}}.\n" + "My budget is {{.budget}} dollars.\n" system_message_prompt := prompts.NewSystemMessagePromptTemplate(system_message_prompt_string, []string{"season", "hobbies", "dollars"}) // Create a human prompt with the request that a human would have human_message_prompt_string := "write a travel itinerary for me" human_message_prompt := prompts.NewHumanMessagePromptTemplate(human_message_prompt_string, []string{}) // Create a chat prompt consisting of the system messages and human messages // At this point, we will also inject the values into the prompts // and turn them into message content objects which we can feed through // to our LLM chat_prompt := prompts.NewChatPromptTemplate([]prompts.MessageFormatter{system_message_prompt, human_message_prompt}) vals := map[string]any{ "season": season, "budget": budget, "hobbies": strings.Join(hobbies, ","), } msgs, err := chat_prompt.FormatMessages(vals) if err != nil { log.Printf("Error: %v", err) return } content := []llms.MessageContent{ llms.TextParts(msgs[0].GetType(), msgs[0].GetContent()), llms.TextParts(msgs[1].GetType(), msgs[1].GetContent()), } // Invoke the LLM with the messages which completion, err := llm.GenerateContent(ctx, content) if err != nil { log.Printf("Error: %v", err) return } v.Idea = completion.Choices[0].Content v.Completed = true log.Printf("Generation for %s is done!", v.Id) }

Running And Testing

所有的組件都已經構建好了,讓我們運行它吧!讓我們打開兩個終端:

# 導入你的 openAI API Key
$ export OPENAI_API_KEY=sk...
$ go run main.go

然后測試:

$ curl -X POST -H"Content-type: application/json" \
-d'{"favorite_season": "summer", "hobbies": ["surfing","running"], "budget":1000}' \
http://localhost:8080/vacation/create

可以看到接口輸出:

參考資料[1]

Gin: https://github.com/gin-gonic/gin[2]

LangChain: https://www.langchain.com/

文章轉自微信公眾號@Go Official Blog

熱門推薦
一個賬號試用1000+ API
助力AI無縫鏈接物理世界 · 無需多次注冊
3000+提示詞助力AI大模型
和專業工程師共享工作效率翻倍的秘密
返回頂部
上一篇
Python+ChatGPT?API,搭建專屬你的智能聊天機器人
下一篇
LLM實戰?|?使用ChatGPT?API提取文本topic
国内精品久久久久影院日本,日本中文字幕视频,99久久精品99999久久,又粗又大又黄又硬又爽毛片
亚洲三级在线播放| 欧美日韩电影在线| 国产精品性做久久久久久| 亚洲成人免费电影| 欧美日韩电影在线| 久久国产综合精品| 欧美自拍丝袜亚洲| 一区二区三区日韩| 欧美在线小视频| 青青草国产成人99久久| 久久综合色婷婷| 懂色av一区二区三区免费观看| 久久综合丝袜日本网| 久久成人av少妇免费| 一二三四区精品视频| xnxx国产精品| 精品国内二区三区| 麻豆91在线看| 亚洲成人免费观看| 亚洲va在线va天堂| 亚洲精品久久久久久国产精华液| 欧美在线制服丝袜| 精品视频在线免费看| 国产精品一区二区不卡| 美国三级日本三级久久99| 欧美aaa在线| 国产一区在线精品| 成人爱爱电影网址| 91在线免费播放| 日本韩国欧美一区| 亚洲成年人影院| 视频一区视频二区中文字幕| 日本视频免费一区| 亚洲美女区一区| 亚洲成人午夜电影| 99久久综合99久久综合网站| 蜜臀va亚洲va欧美va天堂| 久久99精品一区二区三区三区| 理论电影国产精品| 成人国产精品免费观看视频| 成人18视频在线播放| 欧美疯狂做受xxxx富婆| 91精彩视频在线观看| 精品日韩成人av| 午夜精品影院在线观看| 成熟亚洲日本毛茸茸凸凹| 欧美在线免费视屏| 欧美系列在线观看| 亚洲精品videosex极品| 风流少妇一区二区| 日韩视频免费观看高清完整版在线观看| 日韩一级免费一区| 亚洲欧美另类久久久精品| 亚洲私人影院在线观看| 久久综合九色综合欧美亚洲| 免费精品视频在线| 色婷婷综合中文久久一本| 欧美一区二区视频在线观看2022 | 4438x亚洲最大成人网| 亚洲一区二区四区蜜桃| 色猫猫国产区一区二在线视频| 久久久久久电影| 国产ts人妖一区二区| 国产精品乱码人人做人人爱| 国产中文字幕精品| 1024国产精品| 欧美日韩国产乱码电影| 久久99这里只有精品| 欧美经典一区二区| www.欧美日韩| 国产成人精品www牛牛影视| 中文字幕一区二区三区精华液| 99国产精品国产精品毛片| 91视频一区二区三区| 91麻豆精品国产无毒不卡在线观看| 欧美成人官网二区| 久久综合九色综合久久久精品综合| 91精品免费在线| 56国语精品自产拍在线观看| 欧美精品黑人性xxxx| 精品国产乱子伦一区| 久久久久久久综合| 午夜亚洲福利老司机| 成人午夜电影小说| 成人av电影免费观看| 欧美一区二区三区思思人| 精品国产乱子伦一区| 日韩一区在线看| 国产一区视频导航| 91丨porny丨首页| www.欧美精品一二区| 日本一区二区综合亚洲| 人人狠狠综合久久亚洲| 91在线国产福利| 欧美一区二区三区四区视频| 久久久国产午夜精品| 亚洲综合一区二区| 不卡的av电影在线观看| 欧美成人激情免费网| 亚洲成人免费影院| 欧美久久久久中文字幕| 亚洲色图欧美偷拍| 高清免费成人av| 中文字幕第一区二区| 日韩伦理av电影| 欧美日韩黄色一区二区| 国产午夜亚洲精品羞羞网站| 欧洲视频一区二区| 一区二区三区不卡在线观看| 91美女精品福利| 成人中文字幕合集| 中文字幕国产一区| 成人午夜伦理影院| 国产偷v国产偷v亚洲高清| 蓝色福利精品导航| 26uuu亚洲| 玖玖九九国产精品| 精品国产乱子伦一区| 精品无人码麻豆乱码1区2区 | 精品一区二区三区免费视频| 欧美综合天天夜夜久久| 亚洲高清视频在线| 欧美三级电影在线看| 热久久国产精品| 日韩一区欧美一区| 欧美色倩网站大全免费| 国产一区中文字幕| 一区二区三区成人| 日韩欧美一区中文| 91热门视频在线观看| 香蕉久久夜色精品国产使用方法| 精品剧情在线观看| 色妹子一区二区| 秋霞午夜av一区二区三区| 欧美激情在线一区二区三区| 欧美性色黄大片手机版| av一区二区三区黑人| 日本女人一区二区三区| ...av二区三区久久精品| 久久99精品视频| 日本女优在线视频一区二区| 亚洲国产精品久久一线不卡| 亚洲综合久久久| 538在线一区二区精品国产| 视频一区欧美日韩| 亚洲最大成人网4388xx| 国产日韩一级二级三级| 欧美一级生活片| 国产亚洲欧美一区在线观看| 欧美日韩国产不卡| 国产精品自拍一区| 激情久久五月天| 成人动漫av在线| 91美女在线视频| 欧美午夜视频网站| 欧美欧美午夜aⅴ在线观看| 久久嫩草精品久久久久| 日韩精品一区二区三区四区视频 | 久久一留热品黄| 中文字幕一区二区在线观看| 亚洲一区二区精品3399| 国产精品欧美久久久久一区二区| 国产农村妇女精品| 视频一区二区三区在线| 欧美在线你懂得| 综合久久久久综合| 久久99精品一区二区三区三区| 国产一区二区伦理片| 久久婷婷国产综合精品青草| 亚洲视频一二三区| 高清不卡一二三区| 久久久一区二区| 日韩高清电影一区| 在线观看区一区二| 亚洲一区在线免费观看| 欧美性感一区二区三区| 日本一区二区三区视频视频| 看电视剧不卡顿的网站| 欧美福利视频一区| 国产69精品久久99不卡| 久久久久久久久一| 成人毛片视频在线观看| 国产精品毛片久久久久久久| 在线观看视频一区| 天堂久久久久va久久久久| 日韩视频免费观看高清在线视频| 午夜精品爽啪视频| 国产精品人人做人人爽人人添 | 久久国产视频网| 国产精品久久久久久妇女6080| 欧美日韩国产美| 国产成人在线观看| 久久女同精品一区二区| 国产精品成人网| 天天操天天综合网| 99久久婷婷国产综合精品| 精品一区二区av| 日本道色综合久久| 欧美日韩欧美一区二区| 欧美日韩一区在线观看|