mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-01 05:17:51 +08:00
fix(go): wire CheckConnection to ListModels in ollama, lm-studio, and vllm (#14614)
### What problem does this PR solve?
Three Go drivers had `CheckConnection` returning a hardcoded `no such
method` error, even though each one already has a working `ListModels`
that hits the configured base URL with the configured API key. So the
"Check connection" button in the model provider UI always failed for
these three providers, even when the underlying setup was fine.
Affected drivers:
- `internal/entity/models/ollama.go`
- `internal/entity/models/lmstudio.go`
- `internal/entity/models/vllm.go`
This is a real user-facing gap because Ollama and LM Studio are two of
the most popular local LLM runners, and vLLM is widely used for
self-hosted deployments.
### What this PR includes
For each of the three drivers, replace the stub with a small
implementation that calls `ListModels` and returns its error:
```go
func (o *OllamaModel) CheckConnection(apiConfig *APIConfig) error {
_, err := o.ListModels(apiConfig)
return err
}
```
This is the exact pattern that xai, moonshot, deepseek, aliyun, and
gitee already use for the same method.
No JSON change. No factory change. No interface change.
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
### How was this tested?
- `go build ./internal/entity/models/...` in a clean go 1.25 image (the
go.mod minimum) returns exit 0.
- The full ModelDriver interface still resolves on each driver
(NewInstance, Name, ChatWithMessages, ChatStreamlyWithSender, Encode,
Rerank, ListModels, Balance, CheckConnection).
- Pattern parity with the existing xai, moonshot, deepseek, aliyun, and
gitee CheckConnection methods.
Closes #14609
This commit is contained in:
@ -363,11 +363,19 @@ func (l *LmStudioModel) Rerank(modelName *string, query string, texts []string,
|
||||
// ListModels list supported models
|
||||
func (l *LmStudioModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
var region = "default"
|
||||
if apiConfig.Region != nil {
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", l.BaseURL[region], l.URLSuffix.Models)
|
||||
baseURL := l.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = l.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return nil, fmt.Errorf("missing base URL: please configure the local access address for LM Studio (e.g., http://127.0.0.1:1234/v1)")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", baseURL, l.URLSuffix.Models)
|
||||
|
||||
reqBody := map[string]interface{}{}
|
||||
|
||||
@ -382,7 +390,12 @@ func (l *LmStudioModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
// LM Studio is a local provider and the API key is optional. Only
|
||||
// set the Authorization header when a non-empty key was supplied.
|
||||
// This also avoids a nil-pointer dereference on apiConfig or ApiKey.
|
||||
if apiConfig != nil && apiConfig.ApiKey != nil && *apiConfig.ApiKey != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
}
|
||||
|
||||
resp, err := l.httpClient.Do(req)
|
||||
if err != nil {
|
||||
@ -420,6 +433,27 @@ func (l *LmStudioModel) Balance(apiConfig *APIConfig) (map[string]interface{}, e
|
||||
return nil, fmt.Errorf("no such method")
|
||||
}
|
||||
|
||||
// CheckConnection verifies that the configured LM Studio base URL
|
||||
// is reachable and that the API key (if any) is accepted, by issuing
|
||||
// a lightweight ListModels call. The empty-URL guard runs first so
|
||||
// a user who has not yet set the local access address gets a clear,
|
||||
// actionable error instead of a low-level transport message.
|
||||
func (l *LmStudioModel) CheckConnection(apiConfig *APIConfig) error {
|
||||
return fmt.Errorf("no such method")
|
||||
var region = "default"
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
baseURL := l.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = l.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return fmt.Errorf("missing base URL: please configure the local access address for LM Studio (e.g., http://127.0.0.1:1234/v1)")
|
||||
}
|
||||
|
||||
if _, err := l.ListModels(apiConfig); err != nil {
|
||||
return fmt.Errorf("connection check failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -361,11 +361,19 @@ func (o *OllamaModel) Rerank(modelName *string, query string, texts []string, ap
|
||||
func (o *OllamaModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
var region = "default"
|
||||
|
||||
if apiConfig.Region != nil {
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", o.BaseURL[region], o.URLSuffix.Models)
|
||||
baseURL := o.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = o.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return nil, fmt.Errorf("missing base URL: please configure the local access address for Ollama (e.g., http://127.0.0.1:11434/v1)")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", baseURL, o.URLSuffix.Models)
|
||||
|
||||
reqBody := map[string]interface{}{}
|
||||
|
||||
@ -380,7 +388,12 @@ func (o *OllamaModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
// Ollama is a local provider and the API key is optional. Only set
|
||||
// the Authorization header when a non-empty key was supplied. This
|
||||
// also avoids a nil-pointer dereference on apiConfig or ApiKey.
|
||||
if apiConfig != nil && apiConfig.ApiKey != nil && *apiConfig.ApiKey != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
}
|
||||
|
||||
resp, err := o.httpClient.Do(req)
|
||||
if err != nil {
|
||||
@ -418,6 +431,27 @@ func (o *OllamaModel) Balance(apiConfig *APIConfig) (map[string]interface{}, err
|
||||
return nil, fmt.Errorf("no such method")
|
||||
}
|
||||
|
||||
// CheckConnection verifies that the configured Ollama base URL is
|
||||
// reachable and that the API key (if any) is accepted, by issuing a
|
||||
// lightweight ListModels call. The empty-URL guard runs first so a
|
||||
// user who has not yet set the local access address gets a clear,
|
||||
// actionable error instead of a low-level transport message.
|
||||
func (o *OllamaModel) CheckConnection(apiConfig *APIConfig) error {
|
||||
return fmt.Errorf("no such method")
|
||||
var region = "default"
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
baseURL := o.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = o.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return fmt.Errorf("missing base URL: please configure the local access address for Ollama (e.g., http://127.0.0.1:11434/v1)")
|
||||
}
|
||||
|
||||
if _, err := o.ListModels(apiConfig); err != nil {
|
||||
return fmt.Errorf("connection check failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -376,11 +376,19 @@ func (z *VllmModel) Encode(modelName *string, texts []string, apiConfig *APIConf
|
||||
func (z *VllmModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
var region = "default"
|
||||
|
||||
if apiConfig.Region != nil {
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", z.BaseURL[region], z.URLSuffix.Models)
|
||||
baseURL := z.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = z.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return nil, fmt.Errorf("missing base URL: please configure the local access address for vLLM (e.g., http://127.0.0.1:8000/v1)")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", baseURL, z.URLSuffix.Models)
|
||||
|
||||
reqBody := map[string]interface{}{}
|
||||
|
||||
@ -395,7 +403,12 @@ func (z *VllmModel) ListModels(apiConfig *APIConfig) ([]string, error) {
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
// vLLM is a local provider and the API key is optional. Only set
|
||||
// the Authorization header when a non-empty key was supplied. This
|
||||
// also avoids a nil-pointer dereference on apiConfig or ApiKey.
|
||||
if apiConfig != nil && apiConfig.ApiKey != nil && *apiConfig.ApiKey != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *apiConfig.ApiKey))
|
||||
}
|
||||
|
||||
resp, err := z.httpClient.Do(req)
|
||||
if err != nil {
|
||||
@ -433,8 +446,29 @@ func (z *VllmModel) Balance(apiConfig *APIConfig) (map[string]interface{}, error
|
||||
return nil, fmt.Errorf("no such method")
|
||||
}
|
||||
|
||||
// CheckConnection verifies that the configured vLLM base URL is
|
||||
// reachable and that the API key (if any) is accepted, by issuing a
|
||||
// lightweight ListModels call. The empty-URL guard runs first so a
|
||||
// user who has not yet set the local access address gets a clear,
|
||||
// actionable error instead of a low-level transport message.
|
||||
func (z *VllmModel) CheckConnection(apiConfig *APIConfig) error {
|
||||
return fmt.Errorf("no such method")
|
||||
var region = "default"
|
||||
if apiConfig != nil && apiConfig.Region != nil && *apiConfig.Region != "" {
|
||||
region = *apiConfig.Region
|
||||
}
|
||||
|
||||
baseURL := z.BaseURL[region]
|
||||
if baseURL == "" {
|
||||
baseURL = z.BaseURL["default"]
|
||||
}
|
||||
if baseURL == "" {
|
||||
return fmt.Errorf("missing base URL: please configure the local access address for vLLM (e.g., http://127.0.0.1:8000/v1)")
|
||||
}
|
||||
|
||||
if _, err := z.ListModels(apiConfig); err != nil {
|
||||
return fmt.Errorf("connection check failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rerank calculates similarity scores between query and texts
|
||||
|
||||
Reference in New Issue
Block a user