openai-go
openai-go 是 OpenAI 官方推出的 Go 语言 SDK,让开发者能轻松调用 OpenAI 的强大 AI 能力,比如生成文本、对话交互、多轮问答等。它封装了复杂的 HTTP 请求和数据结构,让你只需几行代码就能接入 GPT 等模型,省去手动拼接 API 请求的麻烦。
它主要解决的是 Go 开发者在项目中集成 AI 功能时“从零造轮子”的痛点——无需自己处理认证、参数序列化或错误重试,直接使用清晰的接口即可完成复杂任务。无论是构建聊天机器人、智能客服,还是自动化内容生成,都能快速落地。
适合熟悉 Go 语言的后端工程师、全栈开发者或技术型创业者使用,尤其推荐正在用 Go 构建服务并希望加入 AI 能力的团队。普通用户或非技术人员不建议直接使用。
技术亮点包括:支持流式响应(实时获取生成结果)、会话状态管理(自动维护上下文)、多轮对话追踪,以及类型安全的参数构造。要求 Go 1.22 或更高版本,安装简单,文档齐全,是目前 Go 生态中最权威的 OpenAI 接入方案。
使用场景
一家跨境电商公司的后端团队正在用 Go 语言开发智能客服系统,需要在用户咨询时实时调用 OpenAI 的 GPT 模型生成自然语言回复。
没有 openai-go 时
- 团队必须手动封装 HTTP 请求,处理认证头、JSON 序列化和错误码映射,代码冗长且容易出错。
- 每次模型升级或 API 变更都要重新调整请求结构,缺乏类型安全,调试成本高。
- 多轮对话需自行维护上下文 ID 和会话状态,逻辑分散在多个服务中,难以统一管理。
- 流式响应需从零实现 SSE(Server-Sent Events)解析,增加网络层复杂度和内存开销。
- 缺乏官方支持的 SDK,遇到问题只能查阅原始 API 文档,排查效率低,新人上手慢。
使用 openai-go 后
- 直接调用
client.Responses.New()方法即可发起请求,内置 API Key 管理和结构体参数校验,代码简洁可靠。 - 所有参数和返回值均有强类型定义,配合 Go 1.22+ 的泛型支持,编译期就能发现接口不匹配问题。
- 通过
PreviousResponseID或Conversation.ID轻松维持对话状态,会话历史自动关联,业务逻辑清晰集中。 - 使用内置流式响应支持,一行代码开启
Stream: true即可逐字返回,降低延迟并提升用户体验。 - 官方维护的库持续同步最新 API,附带完整示例和 changelog,团队能快速适配新功能,减少技术负债。
openai-go 让 Go 开发者以最小成本接入 OpenAI 能力,把精力从底层通信转移到真正的业务创新上。
运行环境要求
未说明
未说明

快速开始
OpenAI Go API 库
OpenAI Go 库为使用 Go 语言编写的应用程序提供了便捷访问 OpenAI REST API 的能力。
[!WARNING] 此包的最新版本包含少量且有限的破坏性变更。 详情请参阅 变更日志。
安装
import (
"github.com/openai/openai-go/v3" // 导入后别名为 openai
)
或指定固定版本:
go get -u 'github.com/openai/openai-go/v3@v3.30.0'
要求
本库要求 Go 1.22 或更高版本。
使用方法
本库完整的 API 文档请参见 api.md。
与 OpenAI 模型交互的主要接口是 Responses API。你可以使用以下代码从模型生成文本。
package main
import (
"context"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/option"
"github.com/openai/openai-go/v3/responses"
)
func main() {
ctx := context.Background()
client := openai.NewClient(
option.WithAPIKey("My API Key"), // 默认从 os.LookupEnv("OPENAI_API_KEY") 获取
)
question := "写一首关于计算机的俳句"
resp, err := client.Responses.New(ctx, responses.ResponseNewParams{
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(question)},
Model: openai.ChatModelGPT5_2,
})
if err != nil {
panic(err)
}
println(resp.OutputText())
}
多轮对话响应
response, err := client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("法国的首都是哪里?"),
},
})
if err != nil {
panic(err)
}
fmt.Println("第一轮响应:", response.OutputText())
// 使用 PreviousResponseID 继续对话
response, err = client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
PreviousResponseID: openai.String(response.ID),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("那座城市的人口是多少?"),
},
})
if err != nil {
panic(err)
}
fmt.Println("第二轮响应:", response.OutputText())
会话(Conversations)
conv, err := client.Conversations.New(ctx, conversations.ConversationNewParams{})
if err != nil {
panic(err)
}
fmt.Println("已创建会话:", conv.ID)
response, err := client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("你好!记住我最喜欢的颜色是蓝色。"),
},
Conversation: responses.ResponseNewParamsConversationUnion{
OfConversationObject: &responses.ResponseConversationParam{
ID: conv.ID,
},
},
})
if err != nil {
panic(err)
}
fmt.Println("第一轮响应:", response.OutputText())
// 继续会话
response, err = client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("我最喜欢的颜色是什么?"),
},
Conversation: responses.ResponseNewParamsConversationUnion{
OfConversationObject: &responses.ResponseConversationParam{
ID: conv.ID,
},
},
})
if err != nil {
panic(err)
}
fmt.Println("第二轮响应:", response.OutputText())
items, err := client.Conversations.Items.List(ctx, conv.ID, conversations.ItemListParams{})
if err != nil {
panic(err)
}
fmt.Println("会话包含", len(items.Data), "条记录")
流式响应
ctx := context.Background()
stream := client.Responses.NewStreaming(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("写一首关于编程的俳句"),
},
})
for stream.Next() {
event := stream.Current()
print(event.Delta)
}
if stream.Err() != nil {
panic(stream.Err())
}
查看完整流式示例
工具调用(Tool calling)
ctx := context.Background()
params := responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("纽约市的天气如何?"),
},
Tools: []responses.ToolUnionParam{{
OfFunction: &responses.FunctionToolParam{
Name: "get_weather",
Description: openai.String("获取指定位置的天气"),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"location": map[string]string{
"type": "string",
},
},
"required": []string{"location"},
},
},
}},
}
response, _ := client.Responses.New(ctx, params)
// 检查响应输出中的函数调用
for _, item := range response.Output {
if item.Type == "function_call" {
toolCall := item.AsFunctionCall()
if toolCall.Name == "get_weather" {
// 提取参数并调用你的函数
var args map[string]any
json.Unmarshal([]byte(toolCall.Arguments), &args)
location := args["location"].(string)
// 模拟获取天气数据
weatherData := getWeather(location)
fmt.Printf("地点 %s 的天气:%s\n", location, weatherData)
// 使用函数结果继续对话
response, _ = client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
PreviousResponseID: openai.String(response.ID),
Input: responses.ResponseNewParamsInputUnion{
OfInputItemList: []responses.ResponseInputItemUnionParam{{
OfFunctionCallOutput: &responses.ResponseInputItemFunctionCallOutputParam{
CallID: toolCall.CallID,
Output: responses.ResponseInputItemFunctionCallOutputOutputUnionParam{
OfString: openai.String(weatherData),
},
},
}},
},
})
}
}
}
结构化输出(Structured outputs)
import (
"encoding/json"
"github.com/invopop/jsonschema"
// ...
)
```go
// 一个将被转换为结构化输出(Structured Outputs)响应模式的结构体
type HistoricalComputer struct {
Origin Origin `json:"origin" jsonschema_description:"计算机的起源"`
Name string `json:"full_name" jsonschema_description:"设备型号的名称"`
Legacy string `json:"legacy" jsonschema:"enum=positive,enum=neutral,enum=negative" jsonschema_description:"其对计算领域的影响"`
NotableFacts []string `json:"notable_facts" jsonschema_description:"关于该计算机的一些关键事实"`
}
type Origin struct {
YearBuilt int64 `json:"year_of_construction" jsonschema_description:"制造年份"`
Organization string `json:"organization" jsonschema_description:"负责其开发的组织"`
}
// 结构化输出使用 JSON 模式的一个子集
// 这些标志是符合该子集所必需的
func GenerateSchema[T any]() map[string]any {
reflector := jsonschema.Reflector{
AllowAdditionalProperties: false,
DoNotReference: true,
}
var v T
schema := reflector.Reflect(v)
data, _ := json.Marshal(schema)
var result map[string]any
json.Unmarshal(data, &result)
return result
}
// 在初始化时生成 JSON 模式
var HistoricalComputerSchema = GenerateSchema[HistoricalComputer]()
func main() {
client := openai.NewClient()
ctx := context.Background()
response, err := client.Responses.New(ctx, responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("什么计算机运行了第一个神经网络?"),
},
Text: responses.ResponseTextConfigParam{
Format: responses.ResponseFormatTextConfigParamOfJSONSchema(
"historical_computer",
HistoricalComputerSchema,
),
},
})
if err != nil {
panic(err)
}
// 提取到一个类型安全的结构体中
var historicalComputer HistoricalComputer
_ = json.Unmarshal([]byte(response.OutputText()), &historicalComputer)
historicalComputer.Name
historicalComputer.Origin.YearBuilt
historicalComputer.Origin.Organization
for i, fact := range historicalComputer.NotableFacts {
// ...
}
}
查看 完整的结构化输出示例
聊天补全 API
此前的标准(将无限期支持)文本生成接口是 聊天补全 API。你可以使用以下代码通过该 API 从模型生成文本。
package main
import (
"context"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
chatCompletion, err := client.Chat.Completions.New(context.TODO(), openai.ChatCompletionNewParams{
Messages: []openai.ChatCompletionMessageParamUnion{
openai.DeveloperMessage("你是一个说话像海盗的编程助手。"),
openai.UserMessage("我如何在 Go 中检查切片是否为空?"),
},
Model: openai.ChatModelGPT5_2,
})
if err != nil {
panic(err)
}
println(chatCompletion.Choices[0].Message.Content)
}
请求字段
openai 库对请求字段使用 Go 1.24+ encoding/json 发布版中的 omitzero 语义。
必需的基本类型字段(int64、string 等)带有标签 `json:"...,required"`。这些字段即使为零值也会始终序列化。
可选的基本类型被包装在 param.Opt[T] 中。这些字段可通过提供的构造函数设置,如 openai.String(string)、openai.Int(int64) 等。
任何 param.Opt[T]、map、slice、struct 或字符串枚举均使用标签 `json:"...,omitzero"`。其零值被视为省略。
param.IsOmitted(any) 函数可用于确认任意 omitzero 字段是否存在。
p := openai.ExampleParams{
ID: "id_xxx", // 必需属性
Name: openai.String("..."), // 可选属性
Point: openai.Point{
X: 0, // 必需字段,序列化为 0
Y: openai.Int(1), // 可选字段,序列化为 1
// ... 省略的非必需字段不会被序列化
},
Origin: openai.Origin{}, // [Origin] 的零值被视为省略
}
若要发送 null 而非 param.Opt[T],请使用 param.Null[T]()。
若要发送 null 而非结构体 T,请使用 param.NullStruct[T]()。
p.Name = param.Null[string]() // 发送 'null' 而非字符串
p.Point = param.NullStruct[Point]() // 发送 'null' 而非结构体
param.IsNull(p.Name) // true
param.IsNull(p.Point) // true
请求结构体包含 .SetExtraFields(map[string]any) 方法,可用于在请求体中发送不符合规范的字段。额外字段会覆盖具有相同键的结构体字段。出于安全考虑,请仅对可信数据使用 SetExtraFields。
若要发送自定义值而非结构体,请使用 param.Override[T](value)。
// 当 API 指定某种类型,但你想发送其他内容时,使用 [SetExtraFields]:
p.SetExtraFields(map[string]any{
"x": 0.01, // 将 "x" 作为浮点数发送,而非整数
})
// 发送数字而非对象
custom := param.Override[openai.FooParams](12)
请求联合类型(Unions)
联合类型表示为一个结构体,其每个变体字段前缀为 "Of", 仅允许一个字段非零。非零字段将被序列化。
联合类型的子属性可通过联合结构体上的方法访问。 这些方法返回指向底层数据的可变指针(如果存在)。
// 仅允许一个字段非零,使用 param.IsOmitted() 检查字段是否已设置
type AnimalUnionParam struct {
OfCat *Cat `json:",omitzero,inline`
OfDog *Dog `json:",omitzero,inline`
}
animal := AnimalUnionParam{
OfCat: &Cat{
Name: "Whiskers",
Owner: PersonParam{
Address: AddressParam{Street: "3333 Coyote Hill Rd", Zip: 0},
},
},
}
// 修改字段
if address := animal.GetOwner().GetAddress(); address != nil {
address.ZipCode = 94304
}
响应对象(Response objects)
响应结构体中的所有字段均为普通值类型(非指针或包装器)。
响应结构体还包含一个特殊的 JSON 字段,用于存储每个属性的元数据。
type Animal struct {
Name string `json:"name,nullable"`
Owners int `json:"owners"`
Age int `json:"age"`
JSON struct {
Name respjson.Field
Owner respjson.Field
Age respjson.Field
ExtraFields map[string]respjson.Field
} `json:"-"`
}
要处理可选数据,请使用 JSON 字段上的 .Valid() 方法。.Valid() 在字段不为 null、不存在或无法被序列化时返回 true。
若 .Valid() 为 false,则对应字段将为其零值。
raw := `{"owners": 1, "name": null}`
var res Animal
json.Unmarshal([]byte(raw), &res)
// 访问常规字段
res.Owners // 1
res.Name // ""
res.Age // 0
// 可选字段检查
res.JSON.Owners.Valid() // true
res.JSON.Name.Valid() // false
res.JSON.Age.Valid() // false
// 原始 JSON 值
res.JSON.Owners.Raw() // "1"
res.JSON.Name.Raw() == "null" // true
res.JSON.Name.Raw() == respjson.Null // true
res.JSON.Age.Raw() == "" // true
res.JSON.Age.Raw() == respjson.Omitted // true
这些 .JSON 结构体还包含一个 ExtraFields 映射,其中包含 JSON 响应中未在结构体中定义的任何属性。
这对于 SDK 尚未支持的 API 功能非常有用。
body := res.JSON.ExtraFields["my_unexpected_field"].Raw()
响应联合类型(Response Unions)
在响应中,联合类型(union)由一个扁平化的结构体表示,该结构体包含每个对象变体的所有可能字段。
要将其转换为具体变体,请使用 .AsFooVariant() 方法;如果存在,也可使用 .AsAny() 方法。
如果响应值联合类型包含基本类型(primitive values),则基本类型字段将与属性并列,但会以 Of 为前缀,并带有标签 json:"...,inline"。
type AnimalUnion struct {
// 来自变体 [Dog], [Cat]
Owner Person `json:"owner"`
// 来自变体 [Dog]
DogBreed string `json:"dog_breed"`
// 来自变体 [Cat]
CatBreed string `json:"cat_breed"`
// ...
JSON struct {
Owner respjson.Field
// ...
} `json:"-"`
}
// 如果是 animal 变体
if animal.Owner.Address.ZipCode == "" {
panic("missing zip code")
}
// 根据变体进行切换
switch variant := animal.AsAny().(type) {
case Dog:
case Cat:
default:
panic("unexpected type")
}
请求选项(RequestOptions)
本库使用函数式选项模式(functional options pattern)。option 包中定义的函数返回一个 RequestOption,它是一个修改 RequestConfig 的闭包。
这些选项可以提供给客户端,也可以在单个请求中指定。例如:
client := openai.NewClient(
// 为客户端发起的每个请求添加一个头部
option.WithHeader("X-Some-Header", "custom_header_info"),
)
client.Responses.New(context.TODO(), responses.ResponseNewParams{...},
// 覆盖头部
option.WithHeader("X-Some-Header", "some_other_custom_header_info"),
// 使用 sjson 语法向请求体添加未文档化的字段
option.WithJSONSet("some.json.path", map[string]string{"my": "object"}),
)
调试时,请求选项 option.WithDebugLog(nil) 可能会有帮助。
请参阅完整的请求选项列表。
分页(Pagination)
本库为处理分页列表端点提供了一些便利功能。
你可以使用 .ListAutoPaging() 方法遍历所有页面中的项目:
iter := client.FineTuning.Jobs.ListAutoPaging(context.TODO(), openai.FineTuningJobListParams{
Limit: openai.Int(20),
})
// 根据需要自动获取更多页面。
for iter.Next() {
fineTuningJob := iter.Current()
fmt.Printf("%+v\n", fineTuningJob)
}
if err := iter.Err(); err != nil {
panic(err.Error())
}
或者,你也可以使用简单的 .List() 方法获取单个页面,并接收一个标准响应对象,该对象包含如 .GetNextPage() 等辅助方法,例如:
page, err := client.FineTuning.Jobs.List(context.TODO(), openai.FineTuningJobListParams{
Limit: openai.Int(20),
})
for page != nil {
for _, job := range page.Data {
fmt.Printf("%+v\n", job)
}
page, err = page.GetNextPage()
}
if err != nil {
panic(err.Error())
}
错误(Errors)
当 API 返回非成功状态码时,我们会返回一个类型为 *openai.Error 的错误。
该错误包含请求的 StatusCode、*http.Request 和 *http.Response 值,以及错误体的 JSON 数据(类似于 SDK 中的其他响应对象)。
我们建议你使用 errors.As 模式来处理错误:
_, err := client.FineTuning.Jobs.New(context.TODO(), openai.FineTuningJobNewParams{
Model: openai.FineTuningJobNewParamsModel("gpt-4o"),
TrainingFile: "file-abc123",
})
if err != nil {
var apierr *openai.Error
if errors.As(err, &apierr) {
println(string(apierr.DumpRequest(true))) // 打印序列化的 HTTP 请求
println(string(apierr.DumpResponse(true))) // 打印序列化的 HTTP 响应
}
panic(err.Error()) // GET "/fine_tuning/jobs": 400 Bad Request { ... }
}
当发生其他错误时,它们将以未包装形式返回;例如,
如果 HTTP 传输失败,你可能会收到一个包装了 *net.OpError 的 *url.Error。
超时(Timeouts)
默认情况下,请求不会超时;请使用 context 配置请求生命周期的超时时间。
注意:如果请求被重试,context 超时不会重新计时。
要设置每次重试的超时时间,请使用 option.WithRequestTimeout()。
// 此处设置的是整个请求(包括所有重试)的超时时间。
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
client.Responses.New(
ctx,
responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("How can I list all files in a directory using Python?"),
},
},
// 此处设置的是每次重试的超时时间
option.WithRequestTimeout(20*time.Second),
)
文件上传
在 multipart 请求中,对应文件上传的请求参数类型为 io.Reader。默认情况下,io.Reader 的内容将以文件名为 "anonymous_file"、内容类型(content-type)为 "application/octet-stream" 的 multipart 表单部分发送。
可以通过在 io.Reader 的运行时类型上实现 Name() string 或 ContentType() string 方法来自定义文件名和内容类型。注意:os.File 已实现 Name() string,因此通过 os.Open 返回的文件将使用磁盘上的实际文件名发送。
我们还提供了一个辅助函数 openai.File(reader io.Reader, filename string, contentType string),可用于为任意 io.Reader 包装指定的文件名和内容类型。
// 来自文件系统的文件
file, err := os.Open("input.jsonl")
openai.FileNewParams{
File: file,
Purpose: openai.FilePurposeFineTune,
}
// 来自字符串的文件
openai.FileNewParams{
File: strings.NewReader("my file contents"),
Purpose: openai.FilePurposeFineTune,
}
// 自定义文件名和 contentType
openai.FileNewParams{
File: openai.File(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"),
Purpose: openai.FilePurposeFineTune,
}
Webhook 验证
验证 webhook 签名是_可选但推荐的_。
有关 webhook 的更多信息,请参阅 API 文档。
解析 webhook 负载
在大多数使用场景中,你可能希望同时验证 webhook 并解析其负载。为此,我们提供了方法 client.Webhooks.Unwrap(),该方法会解析 webhook 请求并验证其确实由 OpenAI 发送。如果签名无效,此方法将返回错误。
请注意,body 参数应为服务器发送的原始 JSON 字节(不要先解析它)。Unwrap() 方法将在确认 webhook 来自 OpenAI 后,为你将此 JSON 解析为事件对象。
package main
import (
"io"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/option"
"github.com/openai/openai-go/v3/webhooks"
)
func main() {
client := openai.NewClient(
option.WithWebhookSecret(os.Getenv("OPENAI_WEBHOOK_SECRET")), // 默认使用环境变量;此处显式指定。
)
r := gin.Default()
r.POST("/webhook", func(c *gin.Context) {
body, err := io.ReadAll(c.Request.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "读取请求体失败"})
return
}
defer c.Request.Body.Close()
webhookEvent, err := client.Webhooks.Unwrap(body, c.Request.Header)
if err != nil {
log.Printf("无效的 webhook 签名: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "签名无效"})
return
}
switch event := webhookEvent.AsAny().(type) {
case webhooks.ResponseCompletedWebhookEvent:
log.Printf("响应完成: %+v", event.Data)
case webhooks.ResponseFailedWebhookEvent:
log.Printf("响应失败: %+v", event.Data)
default:
log.Printf("未处理的事件类型: %T", event)
}
c.JSON(http.StatusOK, gin.H{"message": "ok"})
})
r.Run(":8000")
}
直接验证 webhook 负载
在某些情况下,你可能希望在解析负载之前单独验证 webhook。如果你倾向于分别处理这两个步骤,我们提供了 client.Webhooks.VerifySignature() 方法,仅用于验证 webhook 请求的签名。与 Unwrap() 类似,如果签名无效,此方法将返回错误。
请注意,body 参数应为服务器发送的原始 JSON 字节(不要先解析它)。你需要在验证签名后再自行解析 body。
package main
import (
"encoding/json"
"io"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/option"
)
func main() {
client := openai.NewClient(
option.WithWebhookSecret(os.Getenv("OPENAI_WEBHOOK_SECRET")), // 默认使用环境变量;此处显式指定。
)
r := gin.Default()
r.POST("/webhook", func(c *gin.Context) {
body, err := io.ReadAll(c.Request.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "读取请求体失败"})
return
}
defer c.Request.Body.Close()
err = client.Webhooks.VerifySignature(body, c.Request.Header)
if err != nil {
log.Printf("无效的 webhook 签名: %v", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "签名无效"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "ok"})
})
r.Run(":8000")
}
重试机制
默认情况下,某些错误会自动重试 2 次,并采用短指数退避策略。 默认重试所有连接错误、408 请求超时、409 冲突、429 速率限制以及 >=500 的内部错误。
你可以使用 WithMaxRetries 选项来配置或禁用此行为:
// 为所有请求配置默认值:
client := openai.NewClient(
option.WithMaxRetries(0), // 默认值为 2
)
// 为单个请求覆盖设置:
client.Responses.New(
context.TODO(),
responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("如何在 JavaScript 中获取当前星期几的名称?"),
},
},
option.WithMaxRetries(5),
)
访问原始响应数据(如响应头)
你可以使用 option.WithResponseInto() 请求选项访问原始 HTTP 响应数据。当你需要检查响应头、状态码或其他详细信息时,这非常有用。
// 创建一个变量用于存储 HTTP 响应
var httpResp *http.Response
response, err := client.Responses.New(
context.TODO(),
responses.ResponseNewParams{
Model: openai.ChatModelGPT5_2,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("说这是一次测试"),
},
},
option.WithResponseInto(&httpResp),
)
if err != nil {
// 处理错误
}
fmt.Printf("%+v\n", response)
fmt.Printf("状态码: %d\n", httpResp.StatusCode)
fmt.Printf("响应头: %+#v\n", httpResp.Header)
发起自定义/未文档化的请求
本库为方便访问已文档化的 API 而进行了类型标注。若您需要访问未文档化的端点(endpoints)、参数(params)或响应属性(response properties),仍可使用本库。
未文档化的端点
要向未文档化的端点发起请求,您可以使用 client.Get、client.Post 及其他 HTTP 动词方法。客户端上的 RequestOptions(如重试机制)在发起此类请求时仍将生效。
var (
// params 可以是 io.Reader、[]byte、可被 encoding/json 序列化的对象,
// 或本库中定义的“…Params”结构体。
params map[string]any
// result 可以是 []byte、*http.Response、可被 encoding/json 反序列化的对象,
// 或本库中定义的模型。
result *http.Response
)
err := client.Post(context.Background(), "/unspecified", params, &result)
if err != nil {
…
}
未文档化的请求参数
若需使用未文档化的参数发起请求,您可以使用 option.WithQuerySet() 或 option.WithJSONSet() 方法。
params := FooNewParams{
ID: "id_xxxx",
Data: FooNewParamsData{
FirstName: openai.String("John"),
},
}
client.Foo.New(context.Background(), params, option.WithJSONSet("data.last_name", "Doe"))
未文档化的响应属性
要访问未文档化的响应属性,您可以通过 result.JSON.RawJSON() 获取响应的原始 JSON 字符串,或通过 result.JSON.Foo.Raw() 获取结果中特定字段的原始 JSON。
任何未在响应结构体中声明的字段都会被保存,并可通过 result.JSON.ExtraFields() 访问,该方法返回一个 map[string]Field 类型的额外字段集合。
中间件(Middleware)
我们提供 option.WithMiddleware,用于将指定的中间件应用于请求。
func Logger(req *http.Request, next option.MiddlewareNext) (res *http.Response, err error) {
// 请求前处理
start := time.Now()
LogReq(req)
// 将请求转发给下一个处理器
res, err = next(req)
// 请求后处理
end := time.Now()
LogRes(res, err, start - end)
return res, err
}
client := openai.NewClient(
option.WithMiddleware(Logger),
)
当以变长参数形式提供多个中间件时,中间件将从左到右依次应用。如果多次调用 option.WithMiddleware(例如先在客户端设置,再在方法中设置),则客户端设置的中间件会先执行,方法中设置的中间件随后执行。
您也可以使用 option.WithHTTPClient(client) 替换默认的 http.Client。仅接受一个 HTTP 客户端(这会覆盖之前设置的客户端),且该客户端将在所有中间件处理完毕后接收请求。
Microsoft Azure OpenAI
要在 Azure OpenAI 上使用本库,请使用 azure 包中的 option.RequestOption 函数。
package main
import (
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/azure"
)
func main() {
const azureOpenAIEndpoint = "https://<azure-openai-resource>.openai.azure.com"
// 最新的 API 版本(包括预览版)可在此处找到:
// https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versionng
const azureOpenAIAPIVersion = "2024-06-01"
tokenCredential, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
fmt.Printf("Failed to create the DefaultAzureCredential: %s", err)
os.Exit(1)
}
client := openai.NewClient(
azure.WithEndpoint(azureOpenAIEndpoint, azureOpenAIAPIVersion),
// 选择使用 TokenCredential 或 API Key 进行身份验证
azure.WithTokenCredential(tokenCredential),
// 或 azure.WithAPIKey(azureOpenAIAPIKey),
)
}
语义化版本控制(Semantic versioning)
本包通常遵循 SemVer 规范,但某些不兼容的变更可能会作为次要版本发布:
- 对库内部实现的更改,这些部分虽技术上公开,但并非为外部使用而设计或文档化。(若您依赖此类内部实现,请提交 GitHub Issue 告知我们。)
- 我们认为在实践中不会影响绝大多数用户的变更。
我们高度重视向后兼容性,并努力确保您能获得顺畅的升级体验。
我们非常期待您的反馈;请通过 Issue 提交问题、错误或建议。
贡献指南
详见 贡献文档。
版本历史
v3.30.02026/03/25v3.29.02026/03/17v3.28.02026/03/14v3.27.02026/03/13v3.26.02026/03/05v3.25.02026/03/05v3.24.02026/02/24v3.23.02026/02/24v3.22.12026/02/23v3.22.02026/02/14v3.21.02026/02/10v3.20.02026/02/10v3.19.02026/02/09v3.18.02026/02/05v3.17.02026/01/27v3.16.02026/01/09v3.15.02025/12/19v3.14.02025/12/16v3.13.02025/12/15v3.12.02025/12/11常见问题
相似工具推荐
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
NextChat
NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。
ML-For-Beginners
ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。
ragflow
RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。
PaddleOCR
PaddleOCR 是一款基于百度飞桨框架开发的高性能开源光学字符识别工具包。它的核心能力是将图片、PDF 等文档中的文字提取出来,转换成计算机可读取的结构化数据,让机器真正“看懂”图文内容。 面对海量纸质或电子文档,PaddleOCR 解决了人工录入效率低、数字化成本高的问题。尤其在人工智能领域,它扮演着连接图像与大型语言模型(LLM)的桥梁角色,能将视觉信息直接转化为文本输入,助力智能问答、文档分析等应用场景落地。 PaddleOCR 适合开发者、算法研究人员以及有文档自动化需求的普通用户。其技术优势十分明显:不仅支持全球 100 多种语言的识别,还能在 Windows、Linux、macOS 等多个系统上运行,并灵活适配 CPU、GPU、NPU 等各类硬件。作为一个轻量级且社区活跃的开源项目,PaddleOCR 既能满足快速集成的需求,也能支撑前沿的视觉语言研究,是处理文字识别任务的理想选择。
OpenHands
OpenHands 是一个专注于 AI 驱动开发的开源平台,旨在让智能体(Agent)像人类开发者一样理解、编写和调试代码。它解决了传统编程中重复性劳动多、环境配置复杂以及人机协作效率低等痛点,通过自动化流程显著提升开发速度。 无论是希望提升编码效率的软件工程师、探索智能体技术的研究人员,还是需要快速原型验证的技术团队,都能从中受益。OpenHands 提供了灵活多样的使用方式:既可以通过命令行(CLI)或本地图形界面在个人电脑上轻松上手,体验类似 Devin 的流畅交互;也能利用其强大的 Python SDK 自定义智能体逻辑,甚至在云端大规模部署上千个智能体并行工作。 其核心技术亮点在于模块化的软件智能体 SDK,这不仅构成了平台的引擎,还支持高度可组合的开发模式。此外,OpenHands 在 SWE-bench 基准测试中取得了 77.6% 的优异成绩,证明了其解决真实世界软件工程问题的能力。平台还具备完善的企业级功能,支持与 Slack、Jira 等工具集成,并提供细粒度的权限管理,适合从个人开发者到大型企业的各类用户场景。