d39b7614-f204-4987-ac3c-7803808dedfd.png

在本教程中,我们将介绍如何使用Go语言和Azure OpenAI服务创建一个简单的命令行聊天工具。这个项目展示了如何使用Azure的认知服务API在不构建复杂用户界面的情况下快速开发出AI驱动的应用程序。

项目概述

这个CLI聊天工具提供以下功能:

  • 基于Azure OpenAI服务(如GPT-3.5 Turbo或GPT-4)的AI对话
  • 支持保存对话历史,提供上下文连贯的交互
  • 简单的命令行界面
  • 配置灵活,通过环境变量管理API凭证

前提条件

在开始之前,您需要:

  • Go编程环境(建议1.16或更高版本)
  • Azure账户和有效的Azure OpenAI服务访问权限
  • Azure OpenAI资源部署和API密钥

技术架构

本项目依赖以下关键组件:

  1. Go标准库 - 处理输入/输出和环境变量
  2. Azure SDK for Go - 与Azure OpenAI服务交互
  3. Azure OpenAI API - 提供大型语言模型功能

代码解析

配置结构

首先,我们定义了配置和消息的数据结构:

// Azure OpenAI配置
type Config struct {
    Endpoint   string
    ApiKey     string
    Deployment string
    ApiVersion string
}

// 聊天消息结构
type Message struct {
    Role    string `json:"role"`
    Content string `json:"content"`
}

// 请求体结构
type RequestBody struct {
    Messages            []Message `json:"messages"`
    MaxCompletionTokens int       `json:"max_completion_tokens"`
    Temperature         float64   `json:"temperature"`
}

// 响应结构
type ResponseChoice struct {
    Message Message `json:"message"`
}

type Response struct {
    Choices []ResponseChoice `json:"choices"`
}

这些结构定义了与Azure OpenAI API交互所需的数据格式。

主函数流程

func main() {
    // 从环境变量获取配置
    azureOpenAIEndpoint := os.Getenv("AZURE_OPENAI_ENDPOINT")
    azureOpenAIKey := os.Getenv("AZURE_OPENAI_API_KEY")
    deploymentName := os.Getenv("AZURE_OPENAI_DEPLOYMENT")

    // 检查必要的环境变量
    if azureOpenAIEndpoint == "" || azureOpenAIKey == "" || deploymentName == "" {
        fmt.Println("请设置以下环境变量:")
        fmt.Println("AZURE_OPENAI_ENDPOINT - Azure OpenAI服务端点")
        fmt.Println("AZURE_OPENAI_API_KEY - Azure OpenAI API密钥")
        fmt.Println("AZURE_OPENAI_DEPLOYMENT - Azure OpenAI部署名称")
        return
    }
}

程序首先从环境变量获取必要的配置信息,并验证它们是否存在。

### 客户端初始化

```go
    // 使用基于API密钥的身份验证来初始化OpenAI客户端
    cred := azcore.NewKeyCredential(azureOpenAIKey)
    client, err := azopenai.NewClientWithKeyCredential(azureOpenAIEndpoint, cred, nil)
    if err != nil {
        log.Fatalf("初始化客户端错误: %s", err)
    }
}

这里我们使用Azure SDK初始化了OpenAI客户端,使用API密钥进行身份验证。

### 对话历史管理

```go
    // 存储对话历史
    var messages []azopenai.ChatRequestMessageClassification

    // 添加系统消息
    systemMessage := azopenai.ChatRequestSystemMessage{
        Content: azopenai.NewChatRequestSystemMessageContent("你是一个有用的AI助手,可以回答用户的问题。"),
    }
    messages = append(messages, &systemMessage)
}

初始化一个消息数组用于存储对话历史,并添加一个系统消息来定义AI助手的行为。

### 交互循环

```go
    scanner := bufio.NewScanner(os.Stdin)

    for {
        fmt.Print("用户: ")
        if !scanner.Scan() {
            break
        }

        userInput := scanner.Text()
        if userInput == "exit" || userInput == "quit" {
            break
        }

        // 添加用户消息到历史
        userMessage := azopenai.ChatRequestUserMessage{
            Content: azopenai.NewChatRequestUserMessageContent(userInput),
        }
        messages = append(messages, &userMessage)
    }
}

程序使用`bufio.Scanner`从标准输入读取用户输入,并将用户消息添加到对话历史中。

### 发送请求和处理响应

```go
        // 设置最大令牌数;这里可以自由调整,根据模型不同限制是不同的
        maxTokens := int32(800)

        // 发出聊天完成请求
        resp, err := client.GetChatCompletions(
            context.TODO(),
            azopenai.ChatCompletionsOptions{
                Messages:            messages,
                DeploymentName:      &deploymentName,
                MaxCompletionTokens: &maxTokens,
            },
            nil,
        )
        if err != nil {
            fmt.Printf("错误: %v\n", err)
            continue
        }

        // 处理响应
        if len(resp.Choices) > 0 && resp.Choices[0].Message != nil && resp.Choices[0].Message.Content != nil {
            assistantContent := *resp.Choices[0].Message.Content
            fmt.Printf("AI: %s\n", assistantContent)

            // 添加助手回复到历史
            assistantMessage := azopenai.ChatRequestAssistantMessage{
                Content: azopenai.NewChatRequestAssistantMessageContent(assistantContent),
            }
            messages = append(messages, &assistantMessage)
        } else {
            fmt.Println("AI: 抱歉,我无法生成回复。")
        }
    }
}

程序向Azure OpenAI服务发送请求,包含整个对话历史和配置参数,然后处理响应并将AI助手的回复添加到对话历史中。

## 运行项目的步骤

### 1. 环境设置

首先克隆项目并设置环境变量:

```bash
# 克隆项目(如果适用)
git clone <repository-url>
cd <project-directory>/ai

# 设置环境变量
# Linux/Mac
export AZURE_OPENAI_ENDPOINT="https://your-resource-name.openai.azure.com"
export AZURE_OPENAI_API_KEY="your-api-key"
export AZURE_OPENAI_DEPLOYMENT="your-deployment-name"

# Windows PowerShell
$env:AZURE_OPENAI_ENDPOINT = "https://your-resource-name.openai.azure.com"
$env:AZURE_OPENAI_API_KEY = "your-api-key"
$env:AZURE_OPENAI_DEPLOYMENT = "your-deployment-name"

或者,您可以复制.env.example文件到.env并填写您的凭证(需要额外的代码来加载.env文件)。

2. 编译和运行

# 构建项目
go build -o aichat

# 运行
./aichat

或者直接使用go run

go run main.go

3. 使用应用程序

启动后,应用程序会提示您输入问题。输入您的问题并按回车发送。AI将处理您的问题并返回回答。

要退出应用程序,只需输入exitquit

技术细节深入

Azure OpenAI SDK的使用

该项目使用官方的Azure SDK for Go,特别是github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai包。这个SDK提供了与Azure OpenAI服务交互的高级接口。

主要类型和方法包括:

  • azopenai.NewClientWithKeyCredential - 创建新的OpenAI客户端
  • azopenai.ChatCompletionsOptions - 配置聊天完成请求
  • azopenai.ChatRequestMessageClassification - 聊天消息的通用接口
  • 具体消息类型:ChatRequestSystemMessageChatRequestUserMessageChatRequestAssistantMessage

对话上下文管理

该应用程序通过维护一个消息数组来管理对话上下文。每个新的用户输入和AI响应都被添加到这个数组中,然后作为下一个请求的一部分发送给API。这使得AI能够记住之前的对话内容,提供连贯的回复。

令牌限制

应用程序设置了800的最大完成令牌数。这个值可以根据您使用的特定模型和需求进行调整。较小的值可能会限制AI生成的回复长度,而较大的值可能会增加API调用的成本。

潜在的改进空间

  1. 配置文件支持 - 添加对.env文件的支持,使配置更加灵活
  2. 多模型支持 - 允许用户在不同的Azure OpenAI部署之间切换
  3. 对话保存 - 实现将对话保存到文件的功能
  4. Markdown渲染 - 改进终端中AI回复的显示,支持Markdown格式
  5. 流式响应 - 实现流式API响应,使AI回复逐步显示,而不是等待完整响应

结论

这个简单的CLI聊天工具展示了如何利用Azure OpenAI服务构建交互式AI应用程序。通过Go和Azure SDK的结合,我们能够创建一个轻量级但功能强大的应用程序,无需复杂的用户界面或后端架构。

这个项目可以作为更复杂应用程序的起点,或者作为学习如何与Azure AI服务集成的教学工具。随着大型语言模型的不断发展,这种简单的接口将使开发者能够快速实验和构建基于AI的解决方案。

资源链接