最近,马斯克 X 公司旗下的 x.ai 推出了自家大模型 Grok,并向新用户开放了免费额度(25 美元)。本文将介绍如何使用 Go 语言构建一个基于 x.ai Grok API 的聊天机器人,名为 ChatGo,实现终端交互功能。
项目概述
我们将编写一个基于 Go 语言的命令行程序,允许用户通过终端输入问题,程序通过调用 Grok API 获取回答并展示结果。ChatGo 的基本工作流程如下:
- 用户在终端输入问题。
- 程序构造 API 请求并发送到 Grok 服务器。
- 接收并解析 Grok 的响应。
- 显示助手的回复。
代码结构
导入必要的包
程序将用到以下标准库的包:
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})
}
}
关键点:
- 安全性:从环境变量中读取 API 密钥,避免硬编码。
- 交互性:通过终端读取用户输入,用户可输入多轮问题。
- 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 未返回任何结果")
}
功能解析:
- 构造请求体并 JSON 序列化。
- 创建 HTTP 请求,设置内容类型和授权头。
- 发送请求并验证响应状态。
- 解析 API 返回的 JSON 数据并提取助手回复。
安全性考虑
避免硬编码 API 密钥
ChatGo 从环境变量中获取 API 密钥:
apiKey := os.Getenv("API_KEY")
建议将 API 密钥存储在安全的环境中,例如环境变量、配置文件或加密存储服务。
完善错误处理
程序在序列化、网络请求和解析响应等过程中均进行了错误处理,避免因异常导致程序崩溃,同时提升用户体验。
使用说明
-
设置 API 密钥:在终端中设置环境变量
API_KEY:export API_KEY="X_AI_KEY" -
运行程序:
go run main.go -
交互体验:
欢迎使用 ChatGo!请输入您的问题(输入 'exit' 退出): > 你好,Grok! 助手:你好!很高兴为您服务。
实际效果如图片所示,可以非常好的回答中英文问题:
总结
通过本文,我们学习了如何用 Go 语言编写一个名为 ChatGo 的终端聊天程序与 x.ai 的 Grok 模型交互。涉及的主要知识点包括:
- JSON 的处理:如何序列化和反序列化数据。
- HTTP 请求与响应:构建请求体、设置头信息、发送请求以及解析响应。
- 安全实践:如何避免敏感信息泄露。
- 用户交互:实现流畅的多轮对话体验。
通过这些步骤,ChatGo 实现了便捷、易用的终端聊天功能,是 Go 项目中的一个优秀实践。