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 <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-04-20 21:53:27 +08:00
committed by GitHub
parent c43367eca3
commit f269ee9739
2 changed files with 96 additions and 22 deletions

View File

@@ -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
}
}
}
}

View File

@@ -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{})