大模型应用:基于Golang实现GPT模型API调用

1.背景

当前OpenAI提供了开放接口,支持通过api的方式调用LLM进行文本推理、图片生成等能力,但目前官方只提供了Python SDK。为了后续更方便集成和应用,可以采用Golang对核心推理调用接口进行封装,提供模型调用能力。

2.相关准备

官方OpenAPI文档:https://platform.openai.com/docs/overview

  1. 首先需要注册OpenAI账号,并且创建OpenAPI Key:https://platform.openai.com/api-keys,账号内需要充值5美元用于API调用计费。充值需要有美联储值卡,可以选择找代充,也可以直接买已有的账号,链接:https://eylink.cn/
  2. OpenAPI官方调用域名为:https://api.openai.com,国内需要开启全局科学上网才可调用,可以用代理域名:https://api.openai-proxy.com
  3. OpenAPI调用模型计费规则以消耗的Tokens计费:https://openai.com/api/pricing/
    1. gpt-3.5-turbo:2美元/百万Tokens
    2. gpt-4-turbo:40美元/百万Tokens
    3. gpt-4o:20美元/百万Tokens

3.实现代码

代码地址已上传:https://github.com/pbrong/llm_hub/blob/master/pkg/llm_caller/gpt_caller.go

  • helper.go
go 复制代码
package llm_caller

import "context"

var (
   _ LLMCaller = &gptLLMCaller{}
)

type LLMCaller interface {
   Call(ctx context.Context, userPrompt string) (completions string, err error)
}

type Message struct {
   Role    string `json:"role"`
   Content string `json:"content"`
}

type GptCompletion struct {
   Created int `json:"created"`
   Usage   struct {
      CompletionTokens int `json:"completion_tokens"`
      PromptTokens     int `json:"prompt_tokens"`
      TotalTokens      int `json:"total_tokens"`
   } `json:"usage"`
   Model   string `json:"model"`
   ID      string `json:"id"`
   Choices []struct {
      FinishReason string `json:"finish_reason"`
      Index        int    `json:"index"`
      Message      struct {
         Role    string `json:"role"`
         Content string `json:"content"`
      } `json:"message"`
   } `json:"choices"`
   SystemFingerprint interface{} `json:"system_fingerprint"`
   Object            string      `json:"object"`
}
  • gpt_caller.go
go 复制代码
package llm_caller

import (
   "context"
   "encoding/json"
   "fmt"
   "llm_hub/conf"
   "llm_hub/pkg/http"
)

const (
   // 请求路径
   CompletionsURL = "/v1/chat/completions"

   // 可用模型
   Gpt35TurboModel = "gpt-3.5-turbo"
)

type gptLLMCaller struct {
   openAiKey   string
   systemText  string
   temperature float64
   maxTokens   int64
}

func NewGptLLMCaller(ctx context.Context, systemText string, temperature float64, maxTokens int64) (*gptLLMCaller, error) {
   return &gptLLMCaller{
      openAiKey:   conf.LLMHubConfig.Openai.Key,
      systemText:  systemText,
      temperature: temperature,
      maxTokens:   maxTokens,
   }, nil
}

func (caller *gptLLMCaller) Call(ctx context.Context, userPrompt string) (completion string, err error) {
   reqURL := conf.LLMHubConfig.Openai.Host + CompletionsURL
   body := map[string]interface{}{
      "model":       Gpt35TurboModel,
      "temperature": caller.temperature,
      "stream":      false,
      "max_tokens":  caller.maxTokens,
      "messages":    nil,
   }
   body["messages"] = buildPromptMessages(caller.systemText, userPrompt)
   headers := buildAuthHeaders(caller.openAiKey)
   resp, err := http.PostWithHeader(reqURL, body, headers)
   if err != nil {
      return "", fmt.Errorf("GPT调用失败, err = %v", err)
   }
   var gptCompletion GptCompletion
   _ = json.Unmarshal(resp, &gptCompletion)
   if len(gptCompletion.Choices) > 0 {
      completion = gptCompletion.Choices[0].Message.Content
   }

   return completion, nil
}

func buildAuthHeaders(key string) map[string]string {
   headers := map[string]string{
      "Authorization": "Bearer " + key,
   }
   return headers
}

func buildPromptMessages(system string, user string) []*Message {
   var messages []*Message
   messages = append(messages, &Message{
      Role:    "system",
      Content: system,
   })
   messages = append(messages, &Message{
      Role:    "user",
      Content: user,
   })
   return messages
}
  • 测试:gpt_caller_test.go
go 复制代码
package llm_caller

import (
   "context"
   "github.com/stretchr/testify/assert"
   "llm_hub/conf"
   "testing"
)

func Test_gptLLMCaller_Call(t *testing.T) {
   conf.Init()
   ctx := context.Background()
   caller, err := NewGptLLMCaller(ctx, "hello gpt-3.5-turbo", 0.5, 128)
   assert.Nil(t, err)
   completion, err := caller.Call(ctx, "hello world")
   assert.Nil(t, err)
   t.Logf("gpt call success, completion = %v", completion)
}

成功实现gpt-3.5.turbo模型调用:

2024/05/26 22:17:11 post with header, url = https://api.openai-proxy.com/v1/chat/completions, request = {
    "max_tokens": 128,
    "messages": [
        {
            "role": "system",
            "content": "hello gpt-3.5-turbo"
        },
        {
            "role": "user",
            "content": "hello world"
        }
    ],
    "model": "gpt-3.5-turbo",
    "stream": false,
    "temperature": 0.5
}, response = {
  "id": "chatcmpl-9T8yMDeJDEHKyN70Skk3prHvHZBkz",
  "object": "chat.completion",
  "created": 1716733030,
  "model": "gpt-3.5-turbo-0125",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I assist you today?"
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 23,
    "completion_tokens": 9,
    "total_tokens": 32
  },
  "system_fingerprint": null
}
    gpt_caller_test.go:17: gpt call success, completion = Hello! How can I assist you today?
--- PASS: Test_gptLLMCaller_Call (1.31s)
PASS