みなさんOpenAIのAPIは使用したことがありますか??このシリーズのチートシートではOpenAIのAssistantsAPIの紹介をします.これでPart 3です.
従来のCompletion APIは1問1答で答える方式です.つまり,1回聞いて答えが返ってきたらOpenAI CompletionAPIは話していた内容を忘れてしまうのです.つまり,chatgptのように会話履歴を保持してくれません.そのため毎回どのような会話をしたいかを指定しないといけません.そこでAssistants APIを使えば会話を続けたい場合に活用できます!Part 1ではAssistantの作成,Part 2ではThreadの作成の説明をしました.本記事ではOpenAI Assistants API チートシート Part 3としてMessageの作成方法を紹介します.
参考
OpenAI APIのドキュメント
シリーズ OpenAI AssistantsAPI チートシート
Part 1 Assistant編
Part 2 Thread編
Part 4 Run編
他のチートシート
git/gh コマンド(gitコマンド以外にもgitの概念も書いてあります)
lazygit
Docker コマンド(dockerコマンド以外にもdockerの概念の記事へのリンクもあります)
ステータスコード
TypeScript
Go/Gorm
SQL
Vim
プルリクエスト・マークダウン記法チートシート
ファイル操作コマンドチートシート
VSCode Github Copilot拡張機能
他のシリーズ記事
TypeScriptで学ぶプログラミングの世界
プログラミング言語を根本的に理解するシリーズです.
情報処理技術者試験合格への道[IP・SG・FE・AP]
情報処理技術者試験の単語集です.
IAM AWS User クラウドサービスをフル活用しよう!
AWSのサービスを例にしてバックエンドとインフラ開発の手法を説明するシリーズです.
Assistants APIでの実装の流れ
Assistant作成(Part 1で紹介) → Thread作成(Part 2で紹介) → メッセージ追加(Part 3で紹介) → Run実行(Part 4で紹介) → 応答取得
典型的な使用パターンは以下のようである.
// 1. アシスタント作成
assistant, _ := client.CreateAssistant(ctx, openai.AssistantRequest{
Name: "Math Tutor",
Model: "gpt-4",
})
// 2. スレッド作成
thread, _ := client.CreateThread(ctx, openai.ThreadRequest{})
// 3. メッセージ追加
message, _ := client.CreateMessage(ctx, thread.ID, openai.MessageRequest{
Content: "Help with math",
})
// 4. スレッド実行
run, _ := client.CreateRun(ctx, thread.ID, openai.RunRequest{
AssistantID: assistant.ID,
})
// 5. 結果取得
messages, _ := client.ListMessages(ctx, thread.ID, nil)
MessageとAssistantとThreadの関係
-
Assistant(アシスタント)
AIアシスタントの設定や性格を定義
特定の目的や機能に特化させることが可能
複数のThreadで同じAssistantを使用可能 -
Thread(スレッド)
会話の文脈を保持するコンテナ
一連の会話をグループ化
1つのThreadに1つ以上のMessageが含まれる
同じAssistantと複数の会話を分けて管理可能 -
Message(メッセージ)
Thread内での各発言を表現
ユーザーとアシスタントの発言を記録
必ず特定のThreadに属する
会話作成までの流れ
Assistant作成(Part 1で紹介)
Assistantの作成
Thread作成(Part 2で紹介)
新しい会話の器(Thread)を作成
↓
ThreadIDが発行される
Message追加(本記事Part 3で紹介)
ThreadIDに対してユーザーメッセージを追加
↓
MessageIDが発行される
ここから下はPart 4で紹介します
Assistant実行
ThreadIDに対してAssistantを実行(Run作成)
↓
RunIDが発行される
↓
Runのステータスを監視
↓
完了を待機
結果取得
ThreadIDに対してメッセージ一覧を取得
↓
Assistantの応答を含む全メッセージを取得
Messageの作成
メッセージを作成する方法は以下のコードの通りである.
package main
import (
"context"
"log"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
ctx := context.Background()
threadId := "thread_abc123" // thread_idを適宜変更
message, err := client.CreateMessage(
ctx,
threadId,
openai.MessageRequest{
Role: "user",
Content: "How does AI work? Explain it in simple terms.",
},
)
if err != nil {
log.Fatal(err)
}
jsonData, err := json.MarshalIndent(message, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Message created:\n%s\n", string(jsonData))
}
実行
go run create_message.go
成功すると以下のようなレスポンスになる.
{
"id": "msg_abc123", # メッセージの一意のID
"object": "thread.message", # オブジェクトタイプを示す固定値
"created_at": 1713226573, # 作成日時(UNIXタイムスタンプ)
"thread_id": "thread_abc123", # 所属するスレッドID
"role": "user", # メッセージの送信者(user/assistant)
"content": [
{
"type": "text", # コンテンツのタイプ
"text": { # テキストメッセージの内容
"value": "Hello, world!", # 実際のメッセージテキスト
"annotations": [] # テキストの注釈(空配列)
}
}
],
"attachments": [], # 添付ファイル(空配列)
"assistant_id": null, # アシスタントID(ない場合はnull)
"run_id": null, # 実行ID(ない場合はnull)
"metadata": {} # カスタムメタデータ(空オブジェクト)
}
Messageの内容をリスト表示
あるthread内でのmessageをリストにして表示する方法は以下のコードの通りである.
package main
import (
"context"
"github.com/joho/godotenv"
"log"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
log.Fatal("環境変数 OPENAI_API_KEY が設定されていません")
}
client := openai.NewClient(apiKey)
ctx := context.Background()
threadId := "thread_abc123" // threadIdを適宜変更
messages, err := client.ListMessage(
ctx,
threadId, //threadIdは必須
nil, // オプションパラメータはnil
nil,
nil,
nil,
nil,
)
if err != nil {
log.Fatal(err)
}
// メッセージ内容を表示
for _, msg := range messages.Messages {
for _, content := range msg.Content {
if content.Type == "text" {
log.Printf("Message ID: %s, Role: %s, Content: %s",
msg.ID,
msg.Role,
content.Text)
}
}
}
}
実行
go run list_message.go
成功すると以下のレスポンスになる
2024/12/10 09:32:59 Message ID: msg_abc123, Role: user, Content: &{Integrate x^2 []}
2024/12/10 09:32:59 Message ID: msg_abc123, Role: user, Content: &{Hello, I'm looking for a tutor to help me with my math homework. []}
Messageの詳細情報取得
Messageの詳細情報は以下の通りである.
package main
import (
"context"
"github.com/joho/godotenv"
"log"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
log.Fatal("環境変数 OPENAI_API_KEY が設定されていません")
}
client := openai.NewClient(apiKey)
ctx := context.Background()
threadId := "thread_abc123" // 必須パラメータ:スレッドID
messageId := "msg_abc123" // 必須パラメータ:メッセージID
message, err := client.RetrieveMessage(
ctx,
threadId,
messageId,
)
if err != nil {
log.Fatal(err)
}
jsonData, err := json.MarshalIndent(message, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Retrieved message:\n%s\n", string(jsonData))
}
実行
go run retrieve_message.go
成功すると以下のようなレスポンスになる
{
"id": "msg_abc123", # メッセージの一意のID
"object": "thread.message", # オブジェクトタイプ
"created_at": 1733790190, # 作成日時(UNIXタイムスタンプ)
"thread_id": "thread_xyz789", # メッセージが属するスレッドID
"role": "user", # 送信者の役割(user/assistant)
"content": [
{
"type": "text", # コンテンツタイプ
"text": { # テキストコンテンツ
"value": "Hello world", # メッセージの実際の内容
"annotations": [] # テキストの注釈
}
}
],
"attachments": [], # 添付ファイル
"assistant_id": null, # アシスタントID
"run_id": null, # 実行ID
"metadata": {} # メタデータ
}
Messageの構造体はどうなっているのか?
type Message struct {
// メッセージの一意識別子
ID string `json:"id"`
// オブジェクトタイプ(通常は "thread.message")
Object string `json:"object"`
// メッセージ作成時のUNIXタイムスタンプ
CreatedAt int `json:"created_at"`
// このメッセージが属するスレッドのID
ThreadID string `json:"thread_id"`
// メッセージの送信者の役割("user" または "assistant")
Role string `json:"role"`
// メッセージの内容(テキストや他の型のコンテンツを含む配列)
Content []MessageContent `json:"content"`
// 添付ファイルのID配列
// nolintコメントは後方互換性のために維持されていることを示す
FileIds []string `json:"file_ids"`
// メッセージに関連付けられたアシスタントのID(オプション)
// ポインタ型なのでnullable
AssistantID *string `json:"assistant_id,omitempty"`
// メッセージに関連付けられた実行ID(オプション)
// ポインタ型なのでnullable
RunID *string `json:"run_id,omitempty"`
// カスタムメタデータを格納できるマップ
Metadata map[string]any `json:"metadata"`
// HTTPレスポンスヘッダー情報を含む埋め込みフィールド
httpHeader
}
Messageのmetadataの変更
メッセージの修正は実質的にメタデータの更新のみが可能で,メッセージの本文やその他の属性は変更できない.
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/joho/godotenv"
"log"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
log.Fatal("環境変数 OPENAI_API_KEY が設定されていません")
}
client := openai.NewClient(apiKey)
ctx := context.Background()
threadId := "thread_puC1Mp2TYUuvZYtMc7sNT5Az" // 必須パラメータ:スレッドID
messageId := "msg_5Oqh2yIsBCu6mE66Rav7nS4K" // 必須パラメータ:メッセージID
// メッセージ修正のためのリクエスト作成
request := map[string]string{
"modified": "true",
"timestamp": "2024-12-10",
}
modifiedMessage, err := client.ModifyMessage(
ctx,
threadId,
messageId,
request, // 修正内容を含むリクエストを追加
)
if err != nil {
log.Fatal(err)
}
// 修正されたメッセージを整形して表示
jsonData, err := json.MarshalIndent(modifiedMessage, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Modified message:\n%s\n", string(jsonData))
}
実行
go run modify_messae.go
成功するとこのようなレスポンスになる.
{
"id": "msg_abc123", # メッセージID
"object": "thread.message", # オブジェクトタイプ
"created_at": 1733790190, # 作成日時(UNIXタイムスタンプ)
"thread_id": "thread_xyz789", # スレッドID
"role": "user", # ユーザーロール(user/assistant)
"content": [
{
"type": "text",
"text": {
"value": "Sample message text", # メッセージ内容
"annotations": [] # 注釈(空配列)
}
}
],
"file_ids": [], # 添付ファイルID(空配列)
"metadata": { # 更新されたメタデータ
"modified": "true", # 修正フラグ
"timestamp": "2024-12-10" # タイムスタンプ
}
}
Messageの削除
MessageをThreadから削除するコードは以下の通りである.
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/joho/godotenv"
"log"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
apiKey := os.Getenv("OPENAI_API_KEY")
if apiKey == "" {
log.Fatal("環境変数 OPENAI_API_KEY が設定されていません")
}
client := openai.NewClient(apiKey)
ctx := context.Background()
threadId := "thread_abc123" // 必須パラメータ:スレッドID
messageId := "msg_abc123" // 必須パラメータ:メッセージID
deletionStatus, err := client.DeleteMessage(
ctx,
threadId,
messageId,
)
if err != nil {
log.Fatal(err)
}
jsonData, err := json.MarshalIndent(deletionStatus, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deletion status:\n%s\n", string(jsonData))
}
実行 & レスポンス
❯ go run delete_message.go
Deletion status:
{
"id": "msg_5Oqh2yIsBCu6mE66Rav7nS4K",
"object": "thread.message.deleted",
"deleted": true
}
❯ go run list_message.go #実際に削除されたことがわかりますね
2024/12/10 10:21:09 Message ID: msg_Iswpuv6raCtPFHwf9PGi55WO, Role: user, Content: &{Hello, I'm looking for a tutor to help me with my math homework. []}
これでメッセージを作成したり,作成したメッセージの情報を取得することができる.次のpartで作成したスレッドで,会話をする準備をしましょう.
Part 4 OpenAI Assistants APIチートシート [Run 編]
[鋭意作成中]
それではQiitaアドカレ.24企画の今日のクリスマスツリーです.
詳しくはこちらの記事から