ChatGo:基于Grok API的智能机器人

433 阅读4分钟

最近,马斯克 X 公司旗下的 x.ai 推出了自家大模型 Grok,并向新用户开放了免费额度(25 美元)。本文将介绍如何使用 Go 语言构建一个基于 x.ai Grok API 的聊天机器人,名为 ChatGo,实现终端交互功能。

项目概述

我们将编写一个基于 Go 语言的命令行程序,允许用户通过终端输入问题,程序通过调用 Grok API 获取回答并展示结果。ChatGo 的基本工作流程如下:

  1. 用户在终端输入问题。
  2. 程序构造 API 请求并发送到 Grok 服务器。
  3. 接收并解析 Grok 的响应。
  4. 显示助手的回复。

代码结构

导入必要的包

程序将用到以下标准库的包:

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"
)

定义常量和数据结构

在 ChatGo 中,定义了以下常量和数据结构:

const apiURL = "https://api.x.ai/v1/chat/completions"
const model = "grok-beta"
  • apiURL:Grok 聊天 API 的接口地址。
  • model:指定使用的模型名称。

定义与请求和响应相关的结构体:

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type ChatRequest struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type Choice struct {
	Message Message `json:"message"`
}

type ChatResponse struct {
	Choices []Choice `json:"choices"`
}

这些结构体用于序列化请求体和解析返回的 JSON 数据。


主函数

以下是 ChatGo 的主逻辑实现:

func main() {
	apiKey := os.Getenv("API_KEY")
	if apiKey == "" {
		fmt.Println("API 密钥未设置,请将 API_KEY 设置为环境变量。")
		return
	}

	reader := bufio.NewReader(os.Stdin)
	fmt.Println("欢迎使用 ChatGo!请输入您的问题(输入 'exit' 退出):")
	messages := []Message{}

	for {
		fmt.Print("> ")
		input, _ := reader.ReadString('\n')
		input = strings.TrimSpace(input)

		if strings.ToLower(input) == "exit" {
			fmt.Println("感谢使用 ChatGo,再见!")
			break
		}

		// 用户输入添加到消息列表
		messages = append(messages, Message{Role: "user", Content: input})

		// 调用 API 获取响应
		responseContent, err := getResponse(apiKey, messages)
		if err != nil {
			fmt.Printf("错误:%v\n", err)
			continue
		}

		fmt.Println("助手:", responseContent)
		// 将助手的回复添加到消息列表
		messages = append(messages, Message{Role: "assistant", Content: responseContent})
	}
}

关键点

  1. 安全性:从环境变量中读取 API 密钥,避免硬编码。
  2. 交互性:通过终端读取用户输入,用户可输入多轮问题。
  3. API 调用:调用 getResponse 函数向 Grok 请求数据。

发送请求并处理响应

以下是与 Grok API 的交互逻辑:

func getResponse(apiKey string, messages []Message) (string, error) {
	reqBody := ChatRequest{
		Model:    model,
		Messages: messages,
	}

	reqBytes, err := json.Marshal(reqBody)
	if err != nil {
		return "", fmt.Errorf("请求体序列化失败:%v", err)
	}

	req, err := http.NewRequest("POST", apiURL, strings.NewReader(string(reqBytes)))
	if err != nil {
		return "", fmt.Errorf("创建请求失败:%v", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+apiKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", fmt.Errorf("请求失败:%v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("API 响应状态:%s", resp.Status)
	}

	var chatResponse ChatResponse
	if err := json.NewDecoder(resp.Body).Decode(&chatResponse); err != nil {
		return "", fmt.Errorf("响应解析失败:%v", err)
	}

	if len(chatResponse.Choices) > 0 {
		return chatResponse.Choices[0].Message.Content, nil
	}

	return "", fmt.Errorf("API 未返回任何结果")
}

功能解析

  1. 构造请求体并 JSON 序列化。
  2. 创建 HTTP 请求,设置内容类型和授权头。
  3. 发送请求并验证响应状态。
  4. 解析 API 返回的 JSON 数据并提取助手回复。

安全性考虑

避免硬编码 API 密钥

ChatGo 从环境变量中获取 API 密钥:

apiKey := os.Getenv("API_KEY")

建议将 API 密钥存储在安全的环境中,例如环境变量、配置文件或加密存储服务。

完善错误处理

程序在序列化、网络请求和解析响应等过程中均进行了错误处理,避免因异常导致程序崩溃,同时提升用户体验。


使用说明

  1. 设置 API 密钥:在终端中设置环境变量 API_KEY

    export API_KEY="X_AI_KEY"
    
  2. 运行程序

    go run main.go
    
  3. 交互体验

    欢迎使用 ChatGo!请输入您的问题(输入 'exit' 退出):
    > 你好,Grok!
    助手:你好!很高兴为您服务。
    

实际效果如图片所示,可以非常好的回答中英文问题:

image.png


总结

通过本文,我们学习了如何用 Go 语言编写一个名为 ChatGo 的终端聊天程序与 x.ai 的 Grok 模型交互。涉及的主要知识点包括:

  1. JSON 的处理:如何序列化和反序列化数据。
  2. HTTP 请求与响应:构建请求体、设置头信息、发送请求以及解析响应。
  3. 安全实践:如何避免敏感信息泄露。
  4. 用户交互:实现流畅的多轮对话体验。

通过这些步骤,ChatGo 实现了便捷、易用的终端聊天功能,是 Go 项目中的一个优秀实践。