From f269ee9739ae148cb38229024c43931beafb0a0e Mon Sep 17 00:00:00 2001 From: Jin Hai Date: Mon, 20 Apr 2026 21:53:27 +0800 Subject: [PATCH] Go: add thinking features to zhipu-ai (#14234) ### What problem does this PR solve? ``` RAGFlow(user)> list models from 'zhipu-ai'; +------------+------------+---------------+----------------+ | features | max_tokens | model_types | name | +------------+------------+---------------+----------------+ | [thinking] | 128000 | [chat] | glm-4.7 | | [thinking] | 128000 | [chat] | glm-4.5 | | [thinking] | 128000 | [chat vision] | glm-4.6v-Flash | | [thinking] | 128000 | [chat] | glm-4.5-x | | [thinking] | 128000 | [chat] | glm-4.5-air | | [thinking] | 128000 | [chat] | glm-4.5-airx | | [thinking] | 128000 | [chat] | glm-4.5-flash | | [thinking] | 64000 | [vision] | glm-4.5v | | | 128000 | [chat] | glm-4-plus | | | 128000 | [chat] | glm-4-0520 | | | 128000 | [chat] | glm-4 | | | 8000 | [chat] | glm-4-airx | | | 128000 | [chat] | glm-4-air | | | 128000 | [chat] | glm-4-flash | | | 128000 | [chat] | glm-4-flashx | | | 1000000 | [chat] | glm-4-long | | | 128000 | [chat] | glm-3-turbo | | | 2000 | [vision] | glm-4v | | | 8192 | [chat] | glm-4-9b | | | 512 | [embedding] | embedding-2 | | | 512 | [embedding] | embedding-3 | | | 4096 | [asr] | glm-asr | | | 0 | [tts] | glm-tts | | | 0 | [ocr] | glm-ocr | | | 0 | [rerank] | glm-rerank | +------------+------------+---------------+----------------+ ``` ### Type of change - [x] New Feature (non-breaking change which adds functionality) Signed-off-by: Jin Hai --- conf/models/zhipu-ai.json | 20 +++++++- internal/entity/model.go | 98 ++++++++++++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/conf/models/zhipu-ai.json b/conf/models/zhipu-ai.json index f41166acae..910c675fae 100644 --- a/conf/models/zhipu-ai.json +++ b/conf/models/zhipu-ai.json @@ -209,5 +209,23 @@ ], "features": {} } - ] + ], + "features": { + "thinking": { + "default_value": true, + "supported_models": [ + "glm-5.1", + "glm-5", + "glm-5v-turbo", + "glm-4.7", + "glm-4.6", + "glm-4.6v", + "glm-4.5", + "glm-4.5v" + ], + "clear": { + "default_value": true + } + } + } } \ No newline at end of file diff --git a/internal/entity/model.go b/internal/entity/model.go index 93125807a4..e60af28a58 100644 --- a/internal/entity/model.go +++ b/internal/entity/model.go @@ -59,6 +59,18 @@ type Reasoning struct { RawType string `json:"type"` } +// Reasoning represents the reasoning capability (can be one of three types) +type ClearReasoningContent struct { + DefaultValue bool `json:"default_value"` +} + +// Reasoning represents the reasoning capability (can be one of three types) +type Thinking struct { + DefaultValue bool `json:"default_value"` + SupportedModels []string `json:"supported_models"` + Clear ClearReasoningContent `json:"clear"` +} + // UnmarshalJSON custom unmarshal for Reasoning func (r *Reasoning) UnmarshalJSON(data []byte) error { var temp map[string]interface{} @@ -132,14 +144,20 @@ type Multimodal struct { type Features struct { Multimodal *Multimodal `json:"multimodal,omitempty"` Reasoning *Reasoning `json:"reasoning,omitempty"` + Thinking *Thinking `json:"thinking,omitempty"` +} + +type ModelThinking struct { + DefaultValue bool `json:"default_value"` + ClearContent bool `json:"clear_content"` } // Model represents a single LLM model type Model struct { - Name string `json:"name"` - MaxTokens int `json:"max_tokens"` - ModelTypes []string `json:"model_types"` - Features Features `json:"features"` + Name string `json:"name"` + MaxTokens int `json:"max_tokens"` + ModelTypes []string `json:"model_types"` + Thinking *ModelThinking `json:"thinking"` ModelTypeMap map[string]bool } @@ -149,6 +167,7 @@ type Provider struct { URL map[string]string `json:"url"` URLSuffix models.URLSuffix `json:"url_suffix"` Models []*Model `json:"models"` + Features Features `json:"features"` ModelDriver models.ModelDriver } @@ -204,7 +223,24 @@ func NewProviderManager(dirPath string) (*ProviderManager, error) { return nil, fmt.Errorf("error parsing JSON from file %s: %w", filePath, err) } + // Get support thinking models + modelSupportThinking := make(map[string]bool) + if provider.Features.Thinking != nil { + for _, modelName := range provider.Features.Thinking.SupportedModels { + modelSupportThinking[modelName] = true + } + } + for _, model := range provider.Models { + // if the prefix of mode.Name is matched with keys of modelSupportThinking + for modelPrefix, _ := range modelSupportThinking { + if strings.HasPrefix(model.Name, modelPrefix) { + model.Thinking = &ModelThinking{ + DefaultValue: provider.Features.Thinking.DefaultValue, + ClearContent: provider.Features.Thinking.Clear.DefaultValue, + } + } + } model.ModelTypeMap = make(map[string]bool) for _, modelType := range model.ModelTypes { model.ModelTypeMap[modelType] = true @@ -294,7 +330,7 @@ func (pm *ProviderManager) ListModels(providerName string) ([]map[string]interfa "name": model.Name, "max_tokens": model.MaxTokens, "model_types": model.ModelTypes, - "features": getFeaturesMap(model.Features), + "features": GetFeatures(model), } models = append(models, modelData) } @@ -402,7 +438,7 @@ func (pm *ProviderManager) SearchModelInfo(providerName, modelName string, filte "name": model.Name, "max_tokens": model.MaxTokens, "model_types": model.ModelTypes, - "features": getFeaturesMap(model.Features), + //"features": getFeaturesMap(model.Features), } if filterBy != "" && filterValue != nil { @@ -426,20 +462,20 @@ func (pm *ProviderManager) SearchByFeature(featureType string) ModelResponse { Message: "success", } - for _, provider := range pm.Providers { - for _, model := range provider.Models { - if modelHasFeature(model.Features, featureType) { - modelData := map[string]interface{}{ - "provider": provider.Name, - "name": model.Name, - "max_tokens": model.MaxTokens, - "model_types": model.ModelTypes, - "features": getFeaturesMap(model.Features), - } - resp.Data = append(resp.Data, modelData) - } - } - } + //for _, provider := range pm.Providers { + // for _, model := range provider.Models { + // if modelHasFeature(model.Features, featureType) { + // modelData := map[string]interface{}{ + // "provider": provider.Name, + // "name": model.Name, + // "max_tokens": model.MaxTokens, + // "model_types": model.ModelTypes, + // "features": getFeaturesMap(model.Features), + // } + // resp.Data = append(resp.Data, modelData) + // } + // } + //} if len(resp.Data) == 0 { resp.Code = 404 @@ -465,7 +501,7 @@ func (pm *ProviderManager) SearchByType(modelType string) ModelResponse { "name": model.Name, "max_tokens": model.MaxTokens, "model_types": model.ModelTypes, - "features": getFeaturesMap(model.Features), + //"features": getFeaturesMap(model.Features), } resp.Data = append(resp.Data, modelData) } @@ -480,6 +516,26 @@ func (pm *ProviderManager) SearchByType(modelType string) ModelResponse { return resp } +func GetFeatures(model *Model) []string { + var features []string + if model.Thinking != nil { + features = append(features, "thinking") + } + return features +} + +func ConvertToFeaturesMap(model *Model) map[string]interface{} { + featuresMap := make(map[string]interface{}) + if model.Thinking != nil { + thinkingMap := map[string]interface{}{ + "default_value": model.Thinking.DefaultValue, + "clear_reasoning": model.Thinking.ClearContent, + } + featuresMap["thinking"] = thinkingMap + } + return featuresMap +} + // Helper: Get features map for response func getFeaturesMap(features Features) map[string]interface{} { featuresMap := make(map[string]interface{})