如何用 golang 从 OpenAI,Ollama 和 Claude 获取可靠的结构化输出?

OpenAI 大火后有许多开发者正在活想要基于 OpenAI 做很多上层应用的开发,这方面在 Python 的生态确实比较完善,但对于 Gopher 来说要获得结构化的结果还需要额外的工作,没有既定的最佳实践。
在 golang 世界中,还没有这样的协议。但有一种非常成熟、稳定、广泛使用的协议可以实现我们想要的大部分功能:protobufs 和 protojson(用于将结构化内存中的结构转换为 JSON)。

在本文中,我们将通过代码来实现这种组合:OpenAI(包括 ollama + open weights)+ protobufs + golang。

实现

我们希望创建一个 POC,对输入和输出进行稳健的类型化验证:
输入应为国家名称,输出应为国家名称和其他统计数据。

如何在 Golang 中使用 OpenAI

这里我们使用 Sasha Baranov 开发的非官方 Golang OpenAI 客户端

设计协议

创建 protobuf 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3";

package countryinfo;
option go_package = "./protobuf";


message CountryRequest {
string country = 1;
}

message CountryResponse {
string country = 1;
int32 country_population = 2;
string capital = 3;
int32 capital_population = 4;
int64 gdp_usd = 5;
}

现在创建 go 对应程序(需要安装 protoc 才能使用):

1
protoc --go_out=. countryinfo.proto

这将为我们在 main.go 文件中使用的内容创建一个 go 原生类型验证。我们的包含文件需要包含 protobuf,我们还需要 protojson 来解析 LLM 的输入和输出:

1
2
"countryinfo/protobuf"
"google.golang.org/protobuf/encoding/protojson"

system prompt

我们需要让 OpenAI 与 protobuf 对话。我们可以通过系统提示完成这项工作:

  • 我们验证输出(以及输入)
  • 在系统提示中包含了一份原生数据库的文本副本,显然每次重新生成原生数据库时都需要手动同步。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    systemPrompt := `You are a programmatic country information API used software applications. 
    All input messages provided MUST adhere to the CountryRequest schema: validate them and throw an error if not.
    Your responses MUST adhere to the CountryResponse schema ONLY with no additional narrative or markup, backquotes or anything.
    message CountryRequest {
    string country = 1;
    }

    message CountryResponse {
    string country = 1;
    int32 country_population = 2;
    string capital = 3;
    int32 capital_population = 4;
    int64 gdp_usd = 5;
    }

创建类型安全请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
req := openai.ChatCompletionRequest{
Model: openai.GPT3Dot5Turbo,
MaxTokens: 1000, // Increased max tokens to 1000
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: systemPrompt,
},
{
Role: openai.ChatMessageRoleUser,
Content: encodeCountryRequest(*country),
},
},
}

这是方法定义。看一下我们是如何使用自动生成的 protobuf 来验证内容的:

1
2
3
4
5
6
7
8
9
10
11
12
func encodeCountryRequest(country string) string {
req := &protobuf.CountryRequest{
Country: country,
}
data, err := protojson.Marshal(req)
if err != nil {
log.Fatalf("Protobuf JSON encoding error: %v\n", err)
}
resultStr := string(data)
fmt.Println("Encoded Protobuf JSON Message: ", resultStr)
return resultStr
}

处理 response

1
2
3
4
5
6
7
8
func decodeCountryResponse(data string) (*protobuf.CountryResponse, error) {
resp := &protobuf.CountryResponse{}
err := protojson.Unmarshal([]byte(data), resp)
if err != nil {
return nil, err
}
return resp, nil
}

兼容性

上面的代码默认使用 GPT 3.5,但如果你有足够的预算,也可以重写模型使用 GPT 4,还可以重写主机网址指向 ollama(因为它与 OpenAI-API 兼容)。

下面是成功测试过的模型:

  • GPT 3.5
  • GPT 4
  • 本地安装的 llama3-instruct
  • Claude Haiku claude-3-haiku-20240307 (最便宜的型号)

-------------The End-------------

本文标题:如何用 golang 从 OpenAI,Ollama 和 Claude 获取可靠的结构化输出?

文章作者:cloud sjhan

发布时间:2024年06月03日 - 08:06

最后更新:2024年06月03日 - 09:06

原始链接:https://cloudsjhan.github.io/2024/06/03/如何用-golang-从-OpenAI-Ollama-和-Claude-获取可靠的结构化输出/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

cloud sjhan wechat
subscribe to my blog by scanning my public wechat account
坚持原创技术分享,您的支持将鼓励我继续创作!
0%
;