ユーザーアイコン

mizuko

9日前

0
0

ツール実行結果のストリーミング配信の実装方法

Go
バックエンド
AI
Gemini

// ストリーミングレスポンスの型定義 type AIChatStreamResponse struct { Content string SessionID uint } // ツール実行を含むメッセージ送信 func SendMessageWithTools(ctx context.Context, userID uint, sessionID uint, message string) (chan *AIChatStreamResponse, error) { // AIツール定義を取得 aiToolDefs := aiTools.GetToolDefinitions() // レスポンス用のチャンネル作成 responseChan := make(chan *AIChatStreamResponse, 100) // 非同期でツール実行とレスポンス生成 go handleGeminiWithTools(ctx, userID, sessionID, message, aiToolDefs, responseChan) return responseChan, nil } // Geminiでのツール実行とストリーミング func handleGeminiWithTools(ctx context.Context, userID uint, sessionID uint, message string, aiToolDefs []aitool.ToolDefinition, responseChan chan *AIChatStreamResponse) { defer close(responseChan) // ツール実行を含む処理(非ストリーミング) fullResponse, err := geminiService.ExecuteToolsNonStreaming( ctx, systemPrompt, message, history, geminiTools, toolExecutor, ) if err != nil { responseChan <- &AIChatStreamResponse{ Content: fmt.Sprintf("エラーが発生しました: %v", err), SessionID: sessionID, } return } // レスポンスをチャンクに分割してストリーミング送信 const chunkSize = 100 runes := []rune(fullResponse) for i := 0; i < len(runes); i += chunkSize { end := min(i + chunkSize, len(runes)) chunk := string(runes[i:end]) responseChan <- &AIChatStreamResponse{ Content: chunk, SessionID: sessionID, } } } // クライアント側での受信例 func receiveStreamingResponse(responseChan chan *AIChatStreamResponse) { for response := range responseChan { // チャンクごとに表示を更新 fmt.Print(response.Content) } }