3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

みなさん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の作成

メッセージを作成する方法は以下のコードの通りである.

create_message.go
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をリストにして表示する方法は以下のコードの通りである.

list_message.go
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の詳細情報は以下の通りである.

retrieve_message.go
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の変更

メッセージの修正は実質的にメタデータの更新のみが可能で,メッセージの本文やその他の属性は変更できない.

modify_message.go
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から削除するコードは以下の通りである.

delete_message.go
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企画の今日のクリスマスツリーです.

詳しくはこちらの記事から

Wondershare Uniconverter 15_000006.GIF

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?