openai-go通过SOCKS5代理调用外网大模型

97 阅读2分钟

首先通过Shadowscoks配置代理成功科学上网

(具体方式自己查找)

使用curl进行测试

Gemini示例

# !/bin/bash
curl --socks5 127.0.0.1:1080 "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent" \
  -H 'Content-Type: application/json' \
  -H 'X-goog-api-key: GEMINI_API_KEY' \
  -X POST \
  -d '{
    "contents": [
      {
        "parts": [
          {
            "text": "Introduce yourself"
          }
        ]
      }
    ]
  }'

Gork示例

# !/bin/bash
curl --socks5 127.0.0.1:1080 "https://api.x.ai/v1/chat/completions" \
   -H "Content-Type: application/json" \
   -H "Authorization: Bearer X_API_KEY" \
   -d '{
     "messages": [
       {
         "role": "system",
         "content": "You are a test assistant."
       },
       {
         "role": "user",
         "content": "Testing. Just say hi and hello world and nothing else."
       }
     ],
     "model": "grok-2-latest",
     "stream": false,
     "temperature": 0
   }'

使用go语言和openai官方库openai/openai-go

库完整地址:github.com/openai/open…

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"golang.org/x/net/proxy"
)

// newHTTPClientWithSocks5 创建一个走 SOCKS5 代理的 http.Client
func newHTTPClientWithSocks5(proxyAddr string) (*http.Client, error) {
	dialer, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
	if err != nil {
		return nil, fmt.Errorf("create socks5 dialer: %w", err)
	}

	transport := &http.Transport{
		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
			// 注意:dialer.Dial 的签名是不带 context 的,因此忽略 ctx 并直接调用它。
			return dialer.Dial(network, addr)
		},
	}

	return &http.Client{Transport: transport}, nil
}

func main() {
	// 1) 安全:不要在代码中硬编码 API Key。优先从环境变量读取。
	apiKey := "GEMINI_API_KEY" // 填写实际的GEMINI_API_KEY
	baseUrl := "https://generativelanguage.googleapis.com/v1beta"
	model := "gemini-2.0-flash"
        
	// apiKey := "X_API_KEY" // 填写实际的X_API_KEY
	// baseUrl := "https://api.x.ai/v1"
	// model := "grok-2-latest"
        
	// 2) SOCKS5 代理地址,也可从环境变量或配置文件读取
	socks5Addr := "127.0.0.1:1080"
	httpClient, err := newHTTPClientWithSocks5(socks5Addr)
	if err != nil {
		log.Fatalf("failed to create http client with socks5: %v", err)
	}

	client := openai.NewClient(
		option.WithAPIKey(apiKey),
		option.WithBaseURL(baseUrl),
		option.WithHTTPClient(httpClient),
	)

	// =============== 发起请求 ===============
	// 使用带超时的 context,避免网络请求无限期挂起
	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	chatCompletion, err := client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
		Model: model,
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("请详细介绍一下你自己"),
		},
	})
	if err != nil {
		// 更友好的错误处理:记录并退出
		log.Fatalf("chat completion request failed: %v", err)
	}

	fmt.Println("Gemini Response:")
	if len(chatCompletion.Choices) == 0 {
		fmt.Println("no choices returned")
		return
	}
	fmt.Println(chatCompletion.Choices[0].Message.Content)
}

使用go语言和最流行的golang库sashabaranov/go-openai

库完整地址:github.com/sashabarano…

package main

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"strings"

	openai "github.com/sashabaranov/go-openai"
	"golang.org/x/net/proxy"
)

// newHTTPClientWithSocks5 返回一个可选走 SOCKS5 代理的 http.Client。
// 如果 proxyAddr 为空,则返回默认的 http.Client。
func newHTTPClientWithSocks5(proxyAddr string) (*http.Client, error) {
	if proxyAddr == "" {
		return &http.Client{}, nil
	}

	// 支持带或不带 scheme 的地址,例如 "socks5://127.0.0.1:1080" 或 "127.0.0.1:1080"
	if after, ok := strings.CutPrefix(proxyAddr, "socks5://"); ok {
		proxyAddr = after
	}

	dialer, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
	if err != nil {
		return nil, fmt.Errorf("create socks5 dialer: %w", err)
	}

	transport := &http.Transport{
		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
			return dialer.Dial(network, addr)
		},
	}

	return &http.Client{Transport: transport}, nil
}

func main() {
	// 优先从环境变量读取 API Key,回退到示例 token(仅用于本地测试)。
	apiKey := "GEMINI_API_KEY"

	// "socks5://127.0.0.1:1080"
	socks5Addr := "127.0.0.1:1080"

	httpClient, err := newHTTPClientWithSocks5(socks5Addr)
	if err != nil {
		fmt.Printf("failed to create http client with socks5: %v\n", err)
		return
	}

	// 使用库的 ClientConfig 注入自定义的 HTTP client
	cfg := openai.DefaultConfig(apiKey)
	cfg.BaseURL = "https://generativelanguage.googleapis.com/v1beta"
	cfg.HTTPClient = httpClient
	client := openai.NewClientWithConfig(cfg)

	resp, err := client.CreateChatCompletion(
		context.Background(),
		openai.ChatCompletionRequest{
			Model: "gemini-2.0-flash",
			Messages: []openai.ChatCompletionMessage{
				{
					Role:    openai.ChatMessageRoleUser,
					Content: "详细讲讲相对论中的双生子佯谬问题",
				},
			},
		},
	)

	if err != nil {
		fmt.Printf("ChatCompletion error: %v\n", err)
		return
	}

	fmt.Println(resp.Choices[0].Message.Content)
}