使用 Go 构建流式输出 ChatGPT CLI 工具

## 背景介绍

开发过程中,我们经常需要和 GPT 模型打交道。网页版 ChatGPT 那种内容逐字冒出来的体验确实很爽,但用 API 调用时,默认是等模型生成完整个回复才给你。这就有问题了——等一个几千字的长回答,那段时间只能盯着空白屏幕干等。

流式输出(Server-Sent Events,简称 SSE)能解决这个问题。服务器边生成边发,客户端不用傻等,可以第一时间看到内容慢慢出现。这不仅是快,交互体验也更接近真人对聊。

本文用 Go 语言调用 OpenAI API,实现流式输出,顺手做个命令行工具出来。

## 问题描述

用 OpenAI API 调用 GPT 模型,默认行为是等完整响应生成完才返回。这会造成几个麻烦:

**体验差。** 发个复杂问题出去,模型要生成几千字的内容。流式输出时内容一段段出来,好歹能早点看到有用信息。阻塞模式下,用户只能坐着干等。

**没有实时感。** 流式输出有个好处是能显示进度,响应一部分就展示一部分。构建交互式工具时这个能力很关键。

**超时问题。** 响应内容太长的话,超时时间得设很长。流式输出不存在这个问题,边收边处理就行。

所以流式输出是个很实际的需求。下面来看看 Go 怎么实现。

## 详细步骤

### 1. 环境准备

你需要:

– Go 1.21 或更高版本
– OpenAI API Key(去 https://platform.openai.com 申请)
– 能正常访问 OpenAI API 的网络

### 2. 创建项目

建个新项目:

“`bash
mkdir gpt-stream-cli && cd gpt-stream-cli
go mod init gpt-stream-cli
“`

### 3. 安装依赖

OpenAI 官方提供了 Go 客户端库,装一下:

“`bash
go get github.com/openai/openai-go
“`

### 4. 编写代码

新建 main.go,把流式输出逻辑放进去:

“`go
package main

import (
“context”
“fmt”
“io”
“log”
“os”

“github.com/openai/openai-go”
“github.com/openai/openai-go/option”
)

func main() {
apiKey := os.Getenv(“OPENAI_API_KEY”)
if apiKey == “” {
log.Fatal(“请设置 OPENAI_API_KEY 环境变量”)
}

client := openai.NewClient(
option.WithAPIKey(apiKey),
)

ctx := context.Background()

// 没有参数时进入交互模式
if len(os.Args) < 2 { runInteractive(ctx, client) return } // 处理单次查询 prompt := os.Args[1] streamResponse(ctx, client, prompt) } func runInteractive(ctx context.Context, client *openai.Client) { fmt.Println("ChatGPT CLI 工具 (流式输出版)") fmt.Println("输入你的问题,按回车发送,输入 exit 退出") fmt.Println("---") for { fmt.Print("\n你: ") var input string fmt.Scanln(&input) if input == "exit" || input == "quit" { fmt.Println("再见!") break } if input == "" { continue } fmt.Print("\nAI: ") streamResponse(ctx, client, input) } } func streamResponse(ctx context.Context, client *openai.Client, prompt string) { stream, err := client.Chat.Completions.NewStreaming(ctx, openai.ChatCompletionNewParams{ Model: openai.F(openai.GPT4oMini), Messages: openai.F([]openai.ChatCompletionMessageParamUnion{ openai.UserMessage(prompt), }), Temperature: openai.F(0.7), }) if err != nil { log.Printf("请求错误: %v", err) return } defer stream.Close() // 流式读取响应 for { choice, err := stream.Recv() if err != nil { if err == io.EOF { break } log.Printf("读取错误: %v", err) break } if len(choice.Choices) > 0 && choice.Choices[0].Delta.Content != “” {
fmt.Print(choice.Choices[0].Delta.Content)
}
}
fmt.Println()
}
“`

### 5. 运行程序

先设置 API Key:

“`bash
export OPENAI_API_KEY=”your-api-key-here”
“`

跑起来:

“`bash
go run main.go “用 Go 语言实现快速排序”
“`

或者进交互模式:

“`bash
go run main.go
“`

### 6. 打包成可执行文件

“`bash
go build -o gpt-cli main.go
“`

之后直接 `./gpt-cli` 就能用,不用每次都现编译。

## 运行结果

跑起来后,输入问题,你会看到类似这样的输出:

“`
你: 解释一下什么是流式输出

AI: 流式输出(Streaming Output)是一种数据传输技术,允许服务器在生成完整响应之前就开始向客户端发送数据…

(内容一个字一个字地冒出来,不用等全部生成完)
“`

交互模式下的完整流程:

“`
ChatGPT CLI 工具 (流式输出版)
输入你的问题,按回车发送,输入 exit 退出

你: 什么是 Go 语言的 defer 关键字?

AI: defer 是 Go 语言的一个关键字,用于延迟函数的执行。当你在一个函数中使用 defer 时,被 defer 修饰的函数会在该函数返回之前执行…

你: 它有什么实际用途?

AI: defer 的常见用途包括:
1. 资源清理 – 关闭文件、网络连接等
2. 释放锁 – 在解锁之前确保锁被释放
3. 打印调试信息 – 在函数退出时打印执行时间

你: exit
再见!
“`

内容是一段段显示的,用户能立刻看到 AI 的回复,不用等完整响应生成完。这体验和网页版 ChatGPT 挺像的。

## 总结

本文展示了用 Go 调用 OpenAI API 实现流式输出的方法,顺便做了个能用的命令行工具。流式输出让用户能早点看到 AI 的回复,体验比干等好太多。

核心就这几个要点:

1. 调用 `client.Chat.Completions.NewStreaming` 而非 `New`,创建流式请求
2. 循环调用 `stream.Recv()` 逐块接收内容
3. 每收到一块就立刻打印,实现逐字显示的效果
4. 处理 `io.EOF`——这是流结束的正常信号,别当错误处理

这是个基础版本,你可以接着扩展:

– 支持切换不同模型
– 加系统提示词
– 流式输出 JSON 数据
– 错误处理做得更完善
– 加上下文记忆,能记住对话历史

流式输出这技术很实用,Web 应用、移动端都能用,用户体验提升很明显。希望这篇文章对你有帮助!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇