feat: 优化 Model 连接测试,支持阿里云 DashScope

- 添加阿里云 provider 支持
- 添加连接超时 (10s)
- 优化 URL 构建逻辑
- 默认状态改为 inactive
- 添加详细日志

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 16:21:29 +08:00
parent 9908ba7237
commit 25d3781f06
3 changed files with 44 additions and 8 deletions

View File

@@ -170,11 +170,11 @@ func main() {
modelGroup := r.Group("/model") modelGroup := r.Group("/model")
{ {
modelGroup.GET("/list", modelHandler.List) modelGroup.GET("/list", modelHandler.List)
modelGroup.GET("/:id", modelHandler.GetByID) modelGroup.POST("/test", modelHandler.Test)
modelGroup.POST("/add", modelHandler.Create) modelGroup.POST("/add", modelHandler.Create)
modelGroup.GET("/:id", modelHandler.GetByID)
modelGroup.PUT("/:id", modelHandler.Update) modelGroup.PUT("/:id", modelHandler.Update)
modelGroup.DELETE("/:id", modelHandler.Delete) modelGroup.DELETE("/:id", modelHandler.Delete)
modelGroup.POST("/test", modelHandler.Test)
} }
// 系统信息模块 // 系统信息模块

View File

@@ -39,6 +39,7 @@ type CreateModelRequest struct {
APIKey string `json:"api_key" binding:"required"` APIKey string `json:"api_key" binding:"required"`
BaseURL string `json:"base_url" binding:"required"` BaseURL string `json:"base_url" binding:"required"`
APIEndpoint string `json:"api_endpoint"` APIEndpoint string `json:"api_endpoint"`
Status string `json:"status"`
} }
// UpdateModelRequest 更新模型请求 // UpdateModelRequest 更新模型请求

View File

@@ -5,7 +5,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"strings"
"time"
"x-agents/server/internal/model" "x-agents/server/internal/model"
"x-agents/server/internal/repository" "x-agents/server/internal/repository"
@@ -33,6 +36,12 @@ func (s *ModelService) GetByID(id string) (*model.ModelInfo, error) {
// Create 创建模型 // Create 创建模型
func (s *ModelService) Create(req model.CreateModelRequest) (*model.ModelInfo, error) { func (s *ModelService) Create(req model.CreateModelRequest) (*model.ModelInfo, error) {
// 如果没有提供状态,默认设置为 inactive
status := req.Status
if status == "" {
status = "inactive"
}
info := &model.ModelInfo{ info := &model.ModelInfo{
ID: uuid.New().String(), ID: uuid.New().String(),
Name: req.Name, Name: req.Name,
@@ -42,7 +51,7 @@ func (s *ModelService) Create(req model.CreateModelRequest) (*model.ModelInfo, e
APIKey: req.APIKey, APIKey: req.APIKey,
BaseURL: req.BaseURL, BaseURL: req.BaseURL,
APIEndpoint: req.APIEndpoint, APIEndpoint: req.APIEndpoint,
Status: "active", Status: status,
} }
if err := s.repo.Create(info); err != nil { if err := s.repo.Create(info); err != nil {
@@ -105,20 +114,36 @@ func (s *ModelService) Delete(id string) error {
// TestConnection 测试模型连接 // TestConnection 测试模型连接
func (s *ModelService) TestConnection(req model.TestModelRequest) (*model.TestModelResponse, error) { func (s *ModelService) TestConnection(req model.TestModelRequest) (*model.TestModelResponse, error) {
log.Printf("[TestConnection] 开始测试连接: provider=%s, model=%s, base_url=%s, api_endpoint=%s", req.Provider, req.Model, req.BaseURL, req.APIEndpoint)
// 构建请求 URL // 构建请求 URL
baseURL := req.BaseURL baseURL := req.BaseURL
// 去掉 base_url 末尾的斜杠
baseURL = strings.TrimRight(baseURL, "/")
if req.APIEndpoint != "" { if req.APIEndpoint != "" {
baseURL = baseURL + req.APIEndpoint // 去掉 api_endpoint 开头的斜杠
apiEndpoint := strings.TrimLeft(req.APIEndpoint, "/")
baseURL = baseURL + "/" + apiEndpoint
} else { } else {
// 默认端点 // 默认端点 - 根据不同 provider 设置
switch req.Provider { switch req.Provider {
case "OpenAI": case "OpenAI":
baseURL = baseURL + "/v1/chat/completions" baseURL = baseURL + "/v1/chat/completions"
case "Ollama": case "Ollama":
baseURL = baseURL + "/api/chat" baseURL = baseURL + "/api/chat"
case "ali", "Ali", "aliyun", "Aliyun":
// 阿里云 DashScope 兼容 OpenAI 格式,需要添加 /chat/completions
// base_url 格式: https://dashscope.aliyuncs.com/compatible-mode/v1
baseURL = baseURL + "/chat/completions"
default:
// 默认使用 OpenAI 兼容格式
baseURL = baseURL + "/v1/chat/completions"
} }
} }
log.Printf("[TestConnection] 请求 URL: %s", baseURL)
// 构建请求体 // 构建请求体
requestBody := map[string]interface{}{ requestBody := map[string]interface{}{
"model": req.Model, "model": req.Model,
@@ -141,11 +166,19 @@ func (s *ModelService) TestConnection(req model.TestModelRequest) (*model.TestMo
httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("Content-Type", "application/json")
if req.APIKey != "" { if req.APIKey != "" {
httpReq.Header.Set("Authorization", "Bearer "+req.APIKey) // 根据不同 provider 使用不同的认证方式
switch req.Provider {
case "ali", "Ali", "aliyun", "Aliyun":
// 阿里云使用 x-api-key 头部
httpReq.Header.Set("Authorization", "Bearer "+req.APIKey)
httpReq.Header.Set("x-api-key", req.APIKey)
default:
httpReq.Header.Set("Authorization", "Bearer "+req.APIKey)
}
} }
// 发送请求 // 发送请求,设置 10 秒超时
client := &http.Client{} client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(httpReq) resp, err := client.Do(httpReq)
if err != nil { if err != nil {
return &model.TestModelResponse{Success: false, Message: err.Error()}, nil return &model.TestModelResponse{Success: false, Message: err.Error()}, nil
@@ -158,6 +191,8 @@ func (s *ModelService) TestConnection(req model.TestModelRequest) (*model.TestMo
return &model.TestModelResponse{Success: false, Message: err.Error()}, nil return &model.TestModelResponse{Success: false, Message: err.Error()}, nil
} }
log.Printf("[TestConnection] 响应状态码: %d, 响应体: %s", resp.StatusCode, string(respBody))
if resp.StatusCode >= 200 && resp.StatusCode < 300 { if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return &model.TestModelResponse{Success: true, Message: "Connection successful"}, nil return &model.TestModelResponse{Success: true, Message: "Connection successful"}, nil
} }