使用Go调用OpenAI兼容API模型

 更新时间:2026年05月17日 15:00:03   作者:传说之后  
本文介绍了使用Go语言调用兼容OpenAI API的模型(LMStudio/Ollama)的方法,主要涵盖了非流式对话、流式打字机效果、多轮上下文对话以及图片交互等内容,文章详细解释了如何准备环境,实现非流式对话的特点,需要的朋友可以参考下

摘要:用 Go 调用兼容 OpenAI API 的模型(LM Studio / Ollama),覆盖非流式对话、流式打字机效果、多轮上下文和图片交互。

一、环境准备

go get github.com/sashabaranov/go-openai

LM Studio / Ollama 提供与 OpenAI 兼容的 API 端点(默认 http://localhost:1234/v1)。

二、非流式对话

package main
import (
    "context"
    "fmt"
    openai "github.com/sashabaranov/go-openai"
)
func main() {
    config := openai.DefaultConfig("api")//填入ApiKey,得到一个"客户端默认配置"
    config.BaseURL = "http://localhost:1234/v1"//服务器地址
    client := openai.NewClientWithConfig(config)
    resp, err := client.CreateChatCompletion(
        context.Background(),
        openai.ChatCompletionRequest{
            Model: "local-model",  // 本地模型可任意命名
            Messages: []openai.ChatCompletionMessage{
                {Role: openai.ChatMessageRoleUser, Content: "你好,世界!"},
            },
        },
    )
    if err != nil {
        fmt.Printf("错误: %v\n", err)
        return
    }
    fmt.Println(resp.Choices[0].Message.Content)
}

特点:请求发出去后等待全部生成完才返回,适合短回复。

三、流式响应(打字机效果)

sequenceDiagram
    participant Go
    participant AI API

    Go->>AI API: CreateChatCompletionStream
    loop 逐字生成
        AI API-->>Go: Delta.Content = "你"
        AI API-->>Go: Delta.Content = "好"
        AI API-->>Go: Delta.Content = "!"
    end
    AI API-->>Go: io.EOF
func main() {
    client := openai.NewClientWithConfig(config)

    stream, err := client.CreateChatCompletionStream(
        context.Background(),
        openai.ChatCompletionRequest{
            Model: "local-model",
            Messages: []openai.ChatCompletionMessage{
                {Role: openai.ChatMessageRoleUser, Content: "写一首诗"},
            },
            Stream: true,  // 核心开关
        },
    )
    if err != nil {
        fmt.Printf("错误: %v\n", err)
        return
    }
    defer stream.Close()

    fmt.Print("AI: ")
    for {
        response, err := stream.Recv()
        if err != nil {
            break  // io.EOF 表示流结束
        }
        fmt.Print(response.Choices[0].Delta.Content)
    }
    fmt.Println()
}

四、多轮上下文对话

func main() {
    client := openai.NewClientWithConfig(config)
    messages := []openai.ChatCompletionMessage{}
    reader := bufio.NewReader(os.Stdin)

    fmt.Println("聊天开始(输入 quit 退出,new 新对话)")

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

        if input == "quit" { break }
        if input == "new" {
            messages = []openai.ChatCompletionMessage{}
            fmt.Println("已开始新对话")
            continue
        }

        // 追加用户消息
        messages = append(messages, openai.ChatCompletionMessage{
            Role:    openai.ChatMessageRoleUser,
            Content: input,
        })

        // 发送完整历史
        stream, err := client.CreateChatCompletionStream(
            context.Background(),
            openai.ChatCompletionRequest{
                Model:    "local-model",
                Messages: messages,
                Stream:   true,
            },
        )
        if err != nil {
            fmt.Printf("错误: %v\n", err)
            continue
        }

        fmt.Print("AI: ")
        var full strings.Builder
        for {
            resp, err := stream.Recv()
            if err != nil { break }
            chunk := resp.Choices[0].Delta.Content
            fmt.Print(chunk)
            full.WriteString(chunk)
        }
        fmt.Println()
        stream.Close()

        // 追加 AI 回复到历史
        messages = append(messages, openai.ChatCompletionMessage{
            Role:    openai.ChatMessageRoleAssistant,
            Content: full.String(),
        })

        // 可选:清理过长历史
        // if len(messages) > 20 { messages = messages[len(messages)-20:] }
    }
}

核心要点

  • 每次请求把完整 messages 历史发给 API
  • AI 的回复也要加入历史
  • 注意 token 上限,旧消息要定期裁剪

五、图片交互

package main

import (
	"context"
	"encoding/base64"
	"fmt"
	"io"
	"os"

	"github.com/sashabaranov/go-openai"
)

// 编码本地图片为Base64字符串
func encodeImage(path string) (string, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(data), nil
}

func main() {
	// 配置OpenAI兼容客户端(适配本地模型如Ollama、LocalAI等)
	config := openai.DefaultConfig("api")   //填入ApiKey
	config.BaseURL = "http://localhost:1234/v1" // 示例:Ollama的OpenAI兼容端点,请根据实际修改
	client := openai.NewClientWithConfig(config)

	// 图像描述(视觉模型)
	b64Img, err := encodeImage("path")//输入图片的路径
	if err != nil {
		fmt.Printf("读取/编码图片失败: %v\n", err)
		return
	}

	messages := []openai.ChatCompletionMessage{
		{
			Role: openai.ChatMessageRoleUser,
			MultiContent: []openai.ChatMessagePart{
				{Type: openai.ChatMessagePartTypeText, Text: "描述这张图片"},
				{Type: openai.ChatMessagePartTypeImageURL,
					ImageURL: &openai.ChatMessageImageURL{
						URL: "data:image/jpeg;base64," + b64Img, // Data URI scheme 的标准格式以及图片的Base64编码,如果格式不正确会导致无法被正确识别
					},
				},
			},
		},
	}
	/*// 常见格式
	  // JPEG 格式
	  url := "data:image/jpeg;base64," + jpegBase64

	  // PNG 格式
	  url := "data:image/png;base64," + pngBase64

	  // GIF 格式
	  url := "data:image/gif;base64," + gifBase64

	  // WebP 格式
	  url := "data:image/webp;base64," + webpBase64

	  // 通用方式(让模型自动检测)
	  url := "data:image/*;base64," + base64Data
	*/
	// 发起视觉流式请求
	stream, err := client.CreateChatCompletionStream(
		context.Background(),
		openai.ChatCompletionRequest{
			Model:    "qwen/qwen3.5-9b", // 替换为你实际部署的视觉模型名称,如 llava, bakllava
			Messages: messages,
			Stream:   true,
		},
	)
	if err != nil {
		fmt.Printf("创建流式请求失败: %v\n", err)
		return
	}
	defer stream.Close()

	fmt.Println("=== 图像描述结果 ===")
	for {
		response, err := stream.Recv()
		if err == io.EOF {
			fmt.Println("\n[流式响应结束]")
			break
		}
		if err != nil {
			fmt.Printf("\n流式接收错误: %v\n", err)
			break
		}
		// 打印增量内容
		fmt.Print(response.Choices[0].Delta.Content)
	}
}

六、总结

场景方法
简单问答CreateChatCompletion(非流式)
打字机效果CreateChatCompletionStreamStream: true
多轮对话维护 messages 切片,每次全量发送
图片分析MultiContent + base64 编码
上下文管理超过 token 限制时裁剪旧消息

Go 调用 AI 模型的核心就是三件事:构建 message 列表、选择流式/非流式、管理对话历史。go-openai 库让这一切变得简单。

以上就是使用Go调用OpenAI兼容API模型的详细内容,更多关于Go调用OpenAI兼容API的资料请关注脚本之家其它相关文章!

相关文章

  • 一文教你如何封装安全的go

    一文教你如何封装安全的go

    这篇文章主要给大家介绍了关于如何封装安全go的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-02-02
  • go语言接口的定义和实现简单分享

    go语言接口的定义和实现简单分享

    这篇文章主要介绍了go语言接口的定义和实现简单分享的相关资料,需要的朋友可以参考下
    2023-08-08
  • Golang设计模式之组合模式讲解

    Golang设计模式之组合模式讲解

    这篇文章主要介绍了Golang设计模式之组合模式,组合模式针对于特定场景,如文件管理、组织管理等,使用该模式能简化管理,使代码变得非常简洁
    2023-01-01
  • 使用go读取gzip格式的压缩包的操作

    使用go读取gzip格式的压缩包的操作

    这篇文章主要介绍了使用go读取gzip格式的压缩包的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang结构体与json格式串实例代码

    golang结构体与json格式串实例代码

    本文通过实例代码给大家介绍了golang结构体与json格式串的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-10-10
  • Go语言学习教程之指针的示例详解

    Go语言学习教程之指针的示例详解

    这篇文章主要通过简单的练习来让大家对Go语言中的指针有所了解,文中的示例代码讲解详细,对我们学习Go语言有一定帮助,需要的可以参考一下
    2022-09-09
  • Go Web后台管理系统项目实现

    Go Web后台管理系统项目实现

    本文主要介绍了Go Web后台管理系统项目实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • 解决panic: assignment to entry in nil map问题

    解决panic: assignment to entry in nil

    这篇文章主要介绍了解决panic: assignment to entry in nil map问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2008-01-01
  • Golang Gin框架实现多种数据格式返回结果详解

    Golang Gin框架实现多种数据格式返回结果详解

    这篇文章主要介绍了Golang Gin框架实现多种数据格式返回结果,我们都知道,一个完整的请求包含请求和处理请求以及结果返回三个步骤,在服务器端对请求处理完成以后,会将结果返回给客户端,在gin框架中,支持返回多种请求数据格式,下面我们一起来看看
    2023-05-05
  • Go处理包含多种引号的字符串的几种方法

    Go处理包含多种引号的字符串的几种方法

    在Go中,有几种方式可以处理包含多种引号的字符串,以确保代码的可读性和正确性,本文将给大家详细介绍了这几种处理方式,并通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-04-04

最新评论