LLM API GroqをGoで叩いてみる
はじめ
こんにちは!テンプル大学CS専攻のかいとです!
個人開発でLLM APIを叩きたくなり、無料で使えるGroqのAPIをGoで叩いてる情報がなかったので本記事を書くことにしました!
ちなみにPythonやJavaScriptは既に公式からライブラリが出てるので楽にAPIを叩けますが、今回は勉強がてらにGoで叩いてみます。
APIキーの発行
ここからAPIキーを作成してください。APIキーは1回しか表示されないので注意!
GROQ_API_KEY=<ここにAPIキー>
Goのセットアップ
Goが既にインストールされている前提で進めていきます。
go mod init <モジュール名>
今回はgodotenvパッケージを使うのでこちらもインストールします。
go install github.com/joho/godotenv/cmd/godotenv@latest
go mod tidy
main.goも作っておきましょう。
touch main.go
いざAPIを叩く!
今回は標準入力で好きな質問を投げかけて、そのまま返答を出力するようなものを実装していきます。
構造体
ドキュメントを見ると、Request Bodyはこんな感じだそうなので、これを元に構造体を作っていきます。
{
"messages": [
{
"role": "user",
"content": "Explain the importance of fast language models"
}
],
"model": "mixtral-8x7b-32768"
}
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type Payload struct {
Messages []Message `json:"messages"`
Model string `json:"model"`
}
今回は返答を表示したいのでレスポンスの中のchoicesのmessageだけを取ってくることにします。
type Choice struct {
Message Message `json:"message"`
}
type Response struct {
Choices []Choice `json:"choices"`
}
標準入力
標準入力はbufioパッケージを使っていきます。
const URL = "https://api.groq.com/openai/v1/chat/completions"
func main() {
// APIキーの読み込み
err := godotenv.Load()
if err != nil {
log.Fatal("Error when loading .env")
}
key := os.Getenv("GROQ_API_KEY")
// 標準入力
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Q: ")
scanner.Scan()
input := scanner.Text()
if err != nil {
log.Fatal("Failed to read your input")
}
}
リクエスト作成
今回モデルは Llama 3 Groq 70B Tool Use (Preview) を使いますが、他にもいろいろあるので試してみてください!
func main() {
// 省略
msg := Message{
Role: "user",
Content: input,
}
payload := Payload{
Messages: []Message{msg},
Model: "llama3-groq-70b-8192-tool-use-preview",
}
data, err := json.Marshal(payload)
if err != nil {
log.Fatal("Failed to marshal json")
}
// リクエスト作成
req, err := http.NewRequest("POST", URL, bytes.NewBuffer(data))
if err != nil {
log.Fatal("Failed to create a request")
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", key))
}
レスポンスを出力
func main() {
// 省略
// クライアント作成して、リクエストを送信する
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("Failed to send a request")
}
defer resp.Body.Close()
// レスポンスを受け取る
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal("Failed to read a response")
}
if resp.StatusCode != http.StatusOK {
log.Fatal("Unexpected status code")
}
// パース
var res Response
err = json.Unmarshal(body, &res)
if err != nil {
log.Fatal("Failed to parse a response")
}
fmt.Printf("A: %s", res.Choices[0].Message.Content)
}
全体のコード
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"github.com/joho/godotenv"
)
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type Payload struct {
Messages []Message `json:"messages"`
Model string `json:"model"`
}
type Choice struct {
Message Message `json:"message"`
}
type Response struct {
Choices []Choice `json:"choices"`
}
const URL = "https://api.groq.com/openai/v1/chat/completions"
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error when loading .env")
}
key := os.Getenv("GROQ_API_KEY")
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Q: ")
scanner.Scan()
input := scanner.Text()
if err != nil {
log.Fatal("Failed to read your input")
}
msg := Message{
Role: "user",
Content: input,
}
payload := Payload{
Messages: []Message{msg},
Model: "llama3-groq-70b-8192-tool-use-preview",
}
data, err := json.Marshal(payload)
if err != nil {
log.Fatal("Failed to marshal json")
}
req, err := http.NewRequest("POST", URL, bytes.NewBuffer(data))
if err != nil {
log.Fatal("Failed to create a request")
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", key))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("Failed to send a request")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal("Failed to read a response")
}
if resp.StatusCode != http.StatusOK {
log.Fatal("Unexpected status code")
}
var res Response
err = json.Unmarshal(body, &res)
if err != nil {
log.Fatal("Failed to parse a response")
}
fmt.Printf("A: %s", res.Choices[0].Message.Content)
}
完成!
実際に動くか確認してみましょう!
go run main.go
実行してみて、質問を投げかけると…
Q: What is the highest mountain in Japan?
A: The highest mountain in Japan is Mount Fuji, which stands at 3,776 meters (12,388 feet) above sea level.
お、いい感じに答えてくれてますね!
しかも日本語もいけそうな感じです!
Q: 日本で一番長い川は何ですか?
A: 日本で一番長い川は信濃川です。長さは367kmです。
さいごに
今回はGoでGroq APIを叩いてみたかったのでやってみましたが、正直断然PythonかJavaScriptで書く方が楽なのでライブラリを使うのをおすすめします(笑)
Groqが提供しているライブラリはPythonとJavaScriptだけなのですが、どうやら他の開発者がC#、Dart、PHP、Ruby向けのライブラリも開発されてるみたいなので要チェックですね!
Goのライブラリも出てきたら良いなぁ…
ですが、もしGoでやってみたいと思う方がいるなら参考になれば幸いです。また、もっと簡単に書く方法や修正点等ありましたら、優しく指摘してください🙏
Discussion