这是一个兼容OpenAI风格的统一AI客户端,支持多个AI服务商,包括DeepSeek、OpenAI、阿里云等。
本项目参考了 go-deepseek/deepseek 项目的设计和实现。
- 🌐 多服务商支持: DeepSeek、OpenAI、阿里云通义千问等
- 🔄 OpenAI兼容: 使用标准的OpenAI API格式
- 🚀 统一接口: 相同的代码可以切换不同的AI服务商
- �� 流式响应: 支持实时流式聊天,支持迭代器模式
- 🔧 灵活配置: 支持自定义API端点和请求头
- 🔒 向后兼容: 保持与原有DeepSeek客户端的兼容性
go get github.com/yu1ec/go-anyllmpackage main
import (
"context"
"fmt"
"log"
"github.com/yu1ec/go-anyllm"
"github.com/yu1ec/go-anyllm/providers"
"github.com/yu1ec/go-anyllm/types"
// 导入服务商包
_ "github.com/yu1ec/go-anyllm/providers/deepseek"
_ "github.com/yu1ec/go-anyllm/providers/openai"
_ "github.com/yu1ec/go-anyllm/providers/alicloud"
)
func main() {
// 方式1: 使用便捷函数
client, err := deepseek.NewDeepSeekClient("your-api-key")
if err != nil {
log.Fatal(err)
}
// 方式2: 使用统一配置
client, err = deepseek.NewClientWithProvider(
providers.ProviderOpenAI,
"your-openai-api-key",
)
if err != nil {
log.Fatal(err)
}
// 创建聊天请求
req := &types.ChatCompletionRequest{
Model: "gpt-3.5-turbo", // 或 "deepseek-chat", "qwen-turbo"
Messages: []types.ChatCompletionMessage{
{
Role: types.RoleUser,
Content: "你好!",
},
},
MaxTokens: types.ToPtr(100),
Temperature: types.ToPtr(float32(0.7)),
}
// 发送请求
resp, err := client.CreateChatCompletion(context.Background(), req)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Choices[0].Message.Content)
}client, err := deepseek.NewDeepSeekClient("your-deepseek-api-key")
// 支持的模型
req := &types.ChatCompletionRequest{
Model: "deepseek-chat", // 或 "deepseek-reasoner"
// ...
}client, err := deepseek.NewOpenAIClient("your-openai-api-key", "org-id")
// 支持的模型
req := &types.ChatCompletionRequest{
Model: "gpt-3.5-turbo", // 或 "gpt-4", "gpt-4-turbo"
// ...
}client, err := deepseek.NewAliCloudClient("your-dashscope-api-key")
// 支持的模型
req := &types.ChatCompletionRequest{
Model: "qwen-turbo", // 或 "qwen-plus", "qwen-max"
// ...
}config := &deepseek.ClientConfig{
Provider: providers.ProviderOpenAI,
APIKey: "your-api-key",
BaseURL: "https://custom-api-endpoint.com/v1",
Timeout: 60,
ExtraHeaders: map[string]string{
"Custom-Header": "value",
},
OpenAIOrgID: "your-org-id", // OpenAI专用
}
client, err := deepseek.NewUnifiedClient(config)新版本的 StreamReader 支持两种使用模式:
新增的迭代器模式提供了更直观和灵活的流处理方式:
Next() bool: 移动到下一个响应,如果有下一个响应返回true,否则返回falseCurrent() *ChatCompletionsResponse: 返回当前的响应,需要先调用Next()Error() error: 返回最后一次操作的错误
req := &types.ChatCompletionRequest{
Model: "deepseek-chat",
Stream: true,
Messages: []types.ChatCompletionMessage{
{
Role: types.RoleUser,
Content: "请写一首关于春天的诗",
},
},
}
stream, err := client.CreateChatCompletionStream(context.Background(), req)
if err != nil {
log.Fatal(err)
}
defer stream.Close()
// 使用迭代器模式处理流式响应
fmt.Print("AI回复:")
for stream.Next() {
chunk := stream.Current()
if chunk != nil && len(chunk.Choices) > 0 && chunk.Choices[0].Delta != nil {
content := chunk.Choices[0].Delta.Content
fmt.Print(content)
}
}
// 检查是否有错误
if err := stream.Error(); err != nil {
log.Printf("流处理错误: %v", err)
}
fmt.Println("\n\n流式响应完成")func collectStreamResponse(stream response.StreamReader) (string, error) {
var fullContent strings.Builder
for stream.Next() {
chunk := stream.Current()
if chunk != nil && len(chunk.Choices) > 0 && chunk.Choices[0].Delta != nil {
content := chunk.Choices[0].Delta.Content
fullContent.WriteString(content)
}
}
if err := stream.Error(); err != nil {
return "", err
}
return fullContent.String(), nil
}func handleToolCalls(stream response.StreamReader) error {
for stream.Next() {
chunk := stream.Current()
if chunk != nil && len(chunk.Choices) > 0 {
choice := chunk.Choices[0]
// 处理delta内容
if choice.Delta != nil {
if choice.Delta.Content != "" {
fmt.Print(choice.Delta.Content)
}
// 处理工具调用(流式响应中的增量工具调用)
if len(choice.Delta.ToolCalls) > 0 {
for _, toolCall := range choice.Delta.ToolCalls {
fmt.Printf("工具调用: %s\n", toolCall.Function.Name)
}
}
}
// 处理完整的工具调用信息(通常在Message中)
if choice.Message != nil && len(choice.Message.ToolCalls) > 0 {
for _, toolCall := range choice.Message.ToolCalls {
fmt.Printf("完整工具调用: %s\n", toolCall.Function.Name)
}
}
// 检查完成原因
if choice.FinishReason != "" {
fmt.Printf("\n完成原因: %s\n", choice.FinishReason)
}
}
}
return stream.Error()
}原有的 Read() 方法仍然可用,保持向后兼容:
req := &types.ChatCompletionRequest{
Model: "deepseek-chat",
Stream: true,
Messages: []types.ChatCompletionMessage{
{
Role: types.RoleUser,
Content: "请写一首诗",
},
},
}
stream, err := client.CreateChatCompletionStream(context.Background(), req)
if err != nil {
log.Fatal(err)
}
defer stream.Close()
// 传统方式仍然有效
for {
response, err := stream.Read()
if err != nil {
if err == io.EOF {
break // 正常结束
}
log.Printf("错误: %v", err)
break
}
// 处理响应
if len(response.Choices) > 0 && response.Choices[0].Delta != nil {
fmt.Print(response.Choices[0].Delta.Content)
}
}- 不要混合使用:不要在同一个流上同时使用
Next()/Current()和Read()方法 - 先调用Next():必须先调用
Next()才能调用Current() - 错误检查:在迭代结束后记得检查
Error()方法 - 一次性使用:每个流只能被消费一次,不能重复迭代
- 更直观:类似于其他语言中的迭代器模式
- 更安全:自动处理EOF和错误状态
- 更灵活:可以在循环中更容易地添加条件判断和错误处理
- 更清晰:代码结构更清晰,易于理解和维护
type UnifiedClient interface {
CreateChatCompletion(ctx context.Context, req *types.ChatCompletionRequest) (*types.ChatCompletionResponse, error)
CreateChatCompletionStream(ctx context.Context, req *types.ChatCompletionRequest) (*StreamReader, error)
GetProvider() providers.Provider
GetProviderName() string
}type ChatCompletionRequest struct {
Model string `json:"model"`
Messages []ChatCompletionMessage `json:"messages"`
MaxTokens *int `json:"max_tokens,omitempty"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
Stream bool `json:"stream,omitempty"`
Stop []string `json:"stop,omitempty"`
// ... 更多字段
}type ChatCompletionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []ChatCompletionChoice `json:"choices"`
Usage *Usage `json:"usage,omitempty"`
}设置相应的API密钥环境变量:
export DEEPSEEK_API_KEY="your-deepseek-api-key"
export OPENAI_API_KEY="your-openai-api-key"
export ALICLOUD_API_KEY="your-dashscope-api-key"原有的DeepSeek客户端代码无需修改即可继续使用:
// 原有代码仍然有效
client, err := deepseek.NewClient("your-api-key")
resp, err := client.CallChatCompletionsChat(ctx, req)要添加新的AI服务商支持:
- 实现
providers.Provider接口 - 注册服务商创建函数
- 添加到工厂方法中
// 实现Provider接口
type CustomProvider struct {
// ...
}
func (p *CustomProvider) CreateChatCompletion(ctx context.Context, req *types.ChatCompletionRequest) (*types.ChatCompletionResponse, error) {
// 实现逻辑
}
// 注册服务商
func init() {
providers.RegisterCustomProvider(func(config providers.ProviderConfig) (providers.Provider, error) {
return NewCustomProvider(config)
})
}MIT License
欢迎提交Issue和Pull Request!