mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-29 23:41:12 +08:00
Go: implement Rerank in Aliyun driver (#14676)
### What problem does this PR solve? The Aliyun Go driver has a stub `Rerank` method that always returns `"Aliyun, Rerank not implemented"`. DashScope exposes an OpenAI-compatible rerank endpoint (`compatible-mode/v1/rerank`) and hosts dedicated bilingual rerankers (`gte-rerank-v2`, `gte-rerank`) that are a natural pairing with the embedding models already in `aliyun.json`. Without this, Aliyun users cannot use reranking within RAGFlow. Closes #14675 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
"url_suffix": {
|
||||
"chat": "compatible-mode/v1/chat/completions",
|
||||
"embedding": "compatible-mode/v1/embeddings",
|
||||
"rerank": "compatible-api/v1/reranks",
|
||||
"models": "api/v1/deployments/models"
|
||||
},
|
||||
"models": [
|
||||
@@ -31,6 +32,13 @@
|
||||
"model_types": [
|
||||
"embedding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "qwen3-rerank",
|
||||
"max_tokens": 8192,
|
||||
"model_types": [
|
||||
"rerank"
|
||||
]
|
||||
}
|
||||
],
|
||||
"features": {
|
||||
|
||||
@@ -458,9 +458,108 @@ func (z *AliyunModel) Encode(modelName *string, texts []string, apiConfig *APICo
|
||||
return embeddings, nil
|
||||
}
|
||||
|
||||
// Rerank calculates similarity scores between query and texts
|
||||
type aliyunRerankRequest struct {
|
||||
Model string `json:"model"`
|
||||
Query string `json:"query"`
|
||||
Documents []string `json:"documents"`
|
||||
TopN int `json:"top_n"`
|
||||
ReturnDocuments bool `json:"return_documents"`
|
||||
}
|
||||
|
||||
type aliyunRerankResponse struct {
|
||||
Results []struct {
|
||||
Index int `json:"index"`
|
||||
RelevanceScore float64 `json:"relevance_score"`
|
||||
} `json:"results"`
|
||||
}
|
||||
|
||||
func (z *AliyunModel) Rerank(modelName *string, query string, texts []string, apiConfig *APIConfig) ([]float64, error) {
|
||||
return nil, fmt.Errorf("%s, Rerank not implemented", z.Name())
|
||||
if len(texts) == 0 {
|
||||
return []float64{}, nil
|
||||
}
|
||||
if apiConfig == nil || apiConfig.ApiKey == nil || *apiConfig.ApiKey == "" {
|
||||
return nil, fmt.Errorf("api key is required")
|
||||
}
|
||||
if modelName == nil || *modelName == "" {
|
||||
return nil, fmt.Errorf("model name is required")
|
||||
}
|
||||
|
||||
region := "default"
|
||||
if apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
baseURL := z.BaseURL["default"]
|
||||
if region != "default" {
|
||||
if regional, ok := z.BaseURL[region]; ok && regional != "" {
|
||||
baseURL = regional
|
||||
}
|
||||
}
|
||||
if baseURL == "" {
|
||||
return nil, fmt.Errorf("aliyun: no base URL configured for default region")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", strings.TrimSuffix(baseURL, "/"), z.URLSuffix.Rerank)
|
||||
|
||||
reqBody := aliyunRerankRequest{
|
||||
Model: *modelName,
|
||||
Query: query,
|
||||
Documents: texts,
|
||||
TopN: len(texts),
|
||||
ReturnDocuments: false,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
|
||||
resp, err := z.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Aliyun rerank API error: %s, body: %s", resp.Status, string(body))
|
||||
}
|
||||
|
||||
var rerankResp aliyunRerankResponse
|
||||
if err = json.Unmarshal(body, &rerankResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse response: %w", err)
|
||||
}
|
||||
|
||||
scores := make([]float64, len(texts))
|
||||
seen := make([]bool, len(texts))
|
||||
for _, r := range rerankResp.Results {
|
||||
if r.Index < 0 || r.Index >= len(texts) {
|
||||
return nil, fmt.Errorf("aliyun rerank: result index %d out of range for %d documents", r.Index, len(texts))
|
||||
}
|
||||
if seen[r.Index] {
|
||||
return nil, fmt.Errorf("aliyun rerank: duplicate result index %d", r.Index)
|
||||
}
|
||||
scores[r.Index] = r.RelevanceScore
|
||||
seen[r.Index] = true
|
||||
}
|
||||
|
||||
if len(rerankResp.Results) != len(texts) {
|
||||
return nil, fmt.Errorf("aliyun rerank: expected %d results, got %d", len(texts), len(rerankResp.Results))
|
||||
}
|
||||
|
||||
return scores, nil
|
||||
}
|
||||
|
||||
type AliyunModelItem struct {
|
||||
|
||||
Reference in New Issue
Block a user