Message Types and Conversation History

Message Types and Conversation History

Welcome back! In the previous lessons, you learned how to send a simple message to OpenAI's language model and explored various model parameters to customize the AI's responses. Now, we will delve into the concept of message types and the importance of maintaining conversation history. These elements are crucial for creating dynamic and context-aware interactions with the AI, allowing your chatbot to engage in more meaningful conversations.

Understanding Message Types

Before we dive into building and managing conversation history, it’s important to understand the concept of message types and how a conversation history is structured. In a chatbot interaction, messages are typically categorized by roles officially recognized by OpenAI: system, user, and assistant. While we’ll explore system prompts more thoroughly in a later lesson, remember that these primary roles help define the flow of dialogue and ensure the AI understands who is speaking at any given time. You can technically specify other roles, but doing so may produce unpredictable results because they are not officially supported by OpenAI’s chat completion API.

In Go, we represent the conversation history using slices and structs. Here’s an example of what a simple conversation history might look like:

type Message struct {
    Role    string
    Content string
}

var conversation = []Message{
    {Role: "user", Content: "Can you recommend a good book?"},
    {Role: "assistant", Content: "I recommend 'To Kill a Mockingbird' by Harper Lee."},
    {Role: "user", Content: "What's it about?"},
    {Role: "assistant", Content: "It's a novel about racial injustice and moral growth in the American South."},
}

In this example, the conversation history consists of alternating messages between the user (the person interacting with the AI) and the assistant (the AI itself). Each message is stored with its respective role, providing context for the AI to generate appropriate responses. Understanding this structure is key to effectively managing conversations and ensuring that the AI can engage in more meaningful interactions.

Creating a Function to Handle Conversations

To manage conversations effectively, we will create a function called sendMessage. This function will send messages to the AI and receive responses, allowing us to handle multiple interactions seamlessly. Here's how the function is structured using the openai-go library:

package main

import (
    "context"
    "fmt"
    "github.com/openai/openai-go"
    "github.com/openai/openai-go/option"
    "os"
)

func sendMessage(client *openai.Client, messages []openai.ChatCompletionMessageParamUnion) (string, error) {
    req := openai.ChatCompletionNewParams{
        Messages: messages,
        Model:    openai.ChatModelGPT4,
    }

    response, err := client.Chat.Completions.New(context.TODO(), req)
    if err != nil {
        return "", err
    }

    if len(response.Choices) == 0 {
        return "", fmt.Errorf("no response choices were returned by the OpenAI API")
    }

    return response.Choices[0].Message.Content, nil
}

In this function, we use the Chat.Completions.New method to send a list of messages to the AI. The messages parameter contains the conversation history, which provides context for the AI's response. The function returns the AI's response, which is extracted from the API result.

Building and Managing Conversation History

Maintaining a conversation history is crucial for providing context to the AI. This allows the AI to generate responses that are relevant to the ongoing dialogue. Let's see how we can build and manage conversation history:

func main() {
    apiKey := os.Getenv("OPENAI_API_KEY")
    baseURL := os.Getenv("OPENAI_BASE_URL")

    if apiKey == "" {
        fmt.Println("Please set the OPENAI_API_KEY environment variable.")
        return
    }
    if baseURL == "" {
        baseURL = "https://api.openai.com/v1"
    }

    client := openai.NewClient(
        option.WithAPIKey(apiKey),
        option.WithBaseURL(baseURL),
    )

    // Start a conversation history with an initial message
    conversation := []openai.ChatCompletionMessageParamUnion{
        openai.UserMessage("What's the capital of France?"),
    }

    // Get first response
    reply, err := sendMessage(&client, conversation)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Assistant:", reply)

    // Add the assistant's response to conversation history
    conversation = append(conversation, openai.AssistantMessage(reply))

    // Add a follow-up question
    conversation = append(conversation, openai.UserMessage("Is it a large city?"))

    // Get response with conversation context
    followUpReply, err := sendMessage(&client, conversation)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Assistant follow-up:", followUpReply)
}

With the conversation history maintained, the AI provides a contextually relevant follow-up response, confirming the size of the city.

Visualizing the Conversation History

To better understand how the conversation has evolved, we can print the entire conversation history:

// Print the entire conversation history
for _, message := range conversation {
    if message.OfUser != nil {
        fmt.Println("User: ", message.OfUser.Content.OfString)    
    }
    if message.OfAssistant != nil {
        fmt.Println("Assistant: ", message.OfAssistant.Content.OfString)    
    }
}

This will output the complete dialogue, showing both user inputs and AI responses. It might look something like this:

User: What is the main ingredient in guacamole?
Assistant: Avocado
User: Can you name a popular dish that uses guacamole?
Assistant: Nachos

Summary and Preparation for Practice

In this lesson, you learned about message types and the importance of maintaining conversation history in chatbot interactions. We explored how to set up your environment, initialize the OpenAI client, and create a function to handle conversations. You also saw how to build and manage conversation history, enabling the AI to generate contextually relevant responses.

As you move on to the practice exercises, I encourage you to experiment with different conversation scenarios and observe how the AI's responses change based on the context provided. This hands-on practice will reinforce what you've learned and prepare you for the next unit, where we'll continue to build on these concepts. Keep up the great work, and enjoy the journey of creating your chatbot with OpenAI!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal