ツール実行結果のストリーミング配信の実装方法
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)
}
}