获取Moonshot API key并配置到环境变量#
登录Moonshot AI开放平台, 在API管理 -> 新建 -> 输入key名, 确定-> 复制密钥sk-HL...Ehvcn
.
将以下环境变量写入系统环境变量
1
2
3
| GPT_BASE_URL=https://api.moonshot.cn/v1
GPT_API_KEY=sk-HLdyzmmUgXQnM5RbhyOBJs0Y5nvPlEdSBa8lWJGZ0GcEhvcn
GPT_MODEL=moonshot-v1-8k
|
或者写入项目下的.env文件并用github.com/joho/godotenv
之类的库进行读取
读取环境变量代码:
1
2
3
4
5
6
| // 如果有.env文件, 则导入库 go get -u github.com/joho/godotenv
godotenv.Load()
apiKey := os.Getenv("GPT_API_KEY")
baseUrl := os.Getenv("GPT_BASE_URL")
model := os.Getenv("GPT_MODEL")
|
使用go-gpt3构建Client#
获取go-gpt3库 go get -u github.com/PullRequestInc/go-gpt3
, go-gpt3是一个兼容OPEN-AI GPT3 API的开源库. 支持stream和non stream的completion请求.
单轮对话示例#
构建gpt3.Client实例
1
| client := gpt3.NewClient(apiKey, gpt3.WithBaseURL(baseUrl))
|
初始化一个对话, 这里使用moonshot文档提供的prompt
1
2
3
4
5
6
| var history []gpt3.ChatCompletionRequestMessage = []gpt3.ChatCompletionRequestMessage{
{
Role: "system",
Content: "你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。",
},
}
|
添加一个问题到对话中, moonshoot ai支持的对话Role为system, user, assistant, tool
1
2
3
4
5
6
| history = append(history, gpt3.ChatCompletionRequestMessage{
Role: "user",
// Content: "How much water should I drink per day?",
Content: "我每天喝多少水合适?",
Name: "Me",
})
|
构建一个non stream的ChatCompletionRequest实例, 该实例包含了向Moonshot-AI API发生的消息, 包括使用的模型,对话内容,以及是否使用stream等参数.
1
2
3
4
| request := gpt3.ChatCompletionRequest{
Model: model,
Messages: history,
}
|
发起单轮对话, 打印响应内容
1
2
3
4
5
6
| response, err := client.ChatCompletion(ctx, request)
if err != nil {
log.Fatal("err: ", err.Error())
} else {
fmt.Print("Answer:\n\t", response.Choices[0].Message.Content)
}
|
此时可以运行项目查看终端中ai的回复.
继续修改代码, 构建一个stream的ChatCompletionRequest实例, 指定Stream参数为true.
1
2
3
4
5
| streamRequest := gpt3.ChatCompletionRequest{
Model: "moonshot-v1-8k",
Messages: history,
Stream: true,
}
|
由于stream式的对话内容是分段处理, 因此使用相对于的ChatCompletionStream函数进行处理
1
2
3
4
5
6
7
8
9
| client.ChatCompletionStream(ctx, streamRequest, func(ccsr *gpt3.ChatCompletionStreamResponse) error {
// 整段内容分别一个字符一个字符输出
for _, c := range ccsr.Choices[0].Delta.Content {
fmt.Print(string(c))
}
// 直接输出整段内容
//fmt.Print(ccsr.Choices[0].Delta.Content)
return nil
})
|
运行项目,查看终端中的文字消息是否符合我们的预期
多轮对话示例#
多轮对话的实现比较简单, 只需要将模型给出的回答再加入到对话中.
简单修改发起对话的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| var result strings.Builder
err := client.ChatCompletionStream(ctx, streamRequest, func(ccsr *gpt3.ChatCompletionStreamResponse) error {
for _, c := range ccsr.Choices[0].Delta.Content {
fmt.Print(string(c))
}
//fmt.Print(ccsr.Choices[0].Delta.Content)
result.WriteString(ccsr.Choices[0].Delta.Content)
return nil
})
if err != nil {
log.Fatal("err: client.ChatCompletionStream: ", err.Error())
}
// 将模型回答再加入对话中
history = append(history, gpt3.ChatCompletionRequestMessage{
Role: "assistant",
Content: result.String(),
})
|
最后达成的效果如图
最终完整代码#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
| package main
import (
"bufio"
"context"
"fmt"
"log"
"os"
"strings"
"github.com/PullRequestInc/go-gpt3"
"github.com/joho/godotenv"
)
var history []gpt3.ChatCompletionRequestMessage = []gpt3.ChatCompletionRequestMessage{
{
Role: "system",
Content: "你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。",
},
}
var (
apiKey, baseUrl, model string
)
func main() {
// load the GPT key from file
godotenv.Load()
apiKey = os.Getenv("GPT_API_KEY")
baseUrl = os.Getenv("GPT_BASE_URL")
model = os.Getenv("GPT_MODEL")
if apiKey == "" {
log.Fatal("Missing GPT_API_KEY.")
}
if model == "" {
log.Fatal("Missing GPT_MODEL.")
}
// instantiate a gpt3.CompletionRequest using github.com/PullRequestInc/go-gpt3
client := gpt3.NewClient(apiKey, gpt3.WithBaseURL(baseUrl))
// create a Context for the execution of requests.
ctx := context.Background()
// send the prompt questions and receive the repsonse via client.
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("\n> ")
line, err := reader.ReadString('\n')
if err != nil {
log.Fatal("err: reader.ReadString: ", err.Error())
}
complete(ctx, client, line)
}
}
func complete(ctx context.Context, client gpt3.Client, question string) {
// send a stream request and receive a stream response via client
streamRequest := makeQuestion(question)
fmt.Print("assistant: \n ")
var result strings.Builder
err := client.ChatCompletionStream(ctx, streamRequest, func(ccsr *gpt3.ChatCompletionStreamResponse) error {
for _, c := range ccsr.Choices[0].Delta.Content {
fmt.Print(string(c))
}
//fmt.Print(ccsr.Choices[0].Delta.Content)
result.WriteString(ccsr.Choices[0].Delta.Content)
return nil
})
if err != nil {
log.Fatal("err: client.ChatCompletionStream: ", err.Error())
}
history = append(history, gpt3.ChatCompletionRequestMessage{
Role: "assistant",
Content: result.String(),
})
}
func makeQuestion(question string) gpt3.ChatCompletionRequest {
// 加入历史对话
history = append(history, gpt3.ChatCompletionRequestMessage{
Role: "user",
// Content: "How much water should I drink per day?",
Content: question,
Name: "Me",
})
return gpt3.ChatCompletionRequest{
Model: model,
Messages: history,
Stream: true,
}
}
|
原来是打算使用OPEN AI API进行实现, 但由于各种客观原因现在OPEN AI的API key不宜获得. 不过得益于当前各个大模型AI厂商之间的竞争, 他们的API开放文档已经相当完善, 而且都兼容OPEN AI的API格式, 所以我选用moonshot ai的API作为替换, 注册用户会获得15元的余额,这足够我完成实验.
这篇文章我只是完成一个简单GPT的示例, 希望对大模型的应用方式有更多了解. 更多的多轮对话细节可以参考moonshot ai文档, 在其中可以获取可用的模型列表, 以及多轮对话的性能优化方法.
参考文档: