feat(runtime): 适配推理模式开关

This commit is contained in:
2026-07-06 02:03:03 +08:00
parent 797edeedf4
commit b7351f3b9b
10 changed files with 547 additions and 17 deletions
+184
View File
@@ -343,6 +343,190 @@ func TestOpenAIClientChatContract(t *testing.T) {
}
}
func TestOpenAIClientChatReasoningParamsByProvider(t *testing.T) {
cases := []struct {
name string
provider string
model string
baseURL string
body map[string]any
assertion func(t *testing.T, body map[string]any)
}{
{
name: "generic openai keeps openai reasoning effort",
provider: "openai",
model: "gpt-5.5",
body: map[string]any{
"reasoning_effort": "xhigh",
},
assertion: func(t *testing.T, body map[string]any) {
if body["reasoning_effort"] != "xhigh" {
t.Fatalf("generic openai should keep xhigh, got %+v", body)
}
if _, ok := body["thinking"]; ok {
t.Fatalf("generic openai should not receive thinking object: %+v", body)
}
},
},
{
name: "aliyun qwen enables thinking and maps budget",
provider: "aliyun-bailian-openai",
model: "qwen3.7-plus",
body: map[string]any{
"reasoning_effort": "high",
"thinking_budget_tokens": 4096,
},
assertion: func(t *testing.T, body map[string]any) {
if body["enable_thinking"] != true || body["thinking_budget"] != float64(4096) {
t.Fatalf("aliyun qwen should use enable_thinking/thinking_budget, got %+v", body)
}
if _, ok := body["reasoning_effort"]; ok {
t.Fatalf("aliyun qwen should not receive reasoning_effort: %+v", body)
}
if _, ok := body["thinking_budget_tokens"]; ok {
t.Fatalf("internal thinking_budget_tokens should be removed: %+v", body)
}
},
},
{
name: "aliyun qwen disables thinking for none",
provider: "aliyun-bailian-openai",
model: "qwen3.7-plus",
body: map[string]any{
"reasoning_effort": "none",
},
assertion: func(t *testing.T, body map[string]any) {
if body["enable_thinking"] != false {
t.Fatalf("aliyun qwen none should disable thinking, got %+v", body)
}
if _, ok := body["reasoning_effort"]; ok {
t.Fatalf("aliyun qwen none should remove reasoning_effort: %+v", body)
}
},
},
{
name: "same deepseek model on aliyun uses aliyun protocol",
provider: "aliyun-bailian-openai",
model: "deepseek-v4",
body: map[string]any{
"reasoning_effort": "xhigh",
},
assertion: func(t *testing.T, body map[string]any) {
if body["enable_thinking"] != true || body["reasoning_effort"] != "max" {
t.Fatalf("aliyun deepseek should use enable_thinking and max, got %+v", body)
}
},
},
{
name: "deepseek official uses thinking object and high max effort",
provider: "deepseek-openai",
model: "deepseek-v4",
body: map[string]any{
"reasoning_effort": "xhigh",
},
assertion: func(t *testing.T, body map[string]any) {
thinking, _ := body["thinking"].(map[string]any)
if thinking["type"] != "enabled" || body["reasoning_effort"] != "max" {
t.Fatalf("deepseek official should use thinking enabled and max, got %+v", body)
}
},
},
{
name: "volces seed none disables thinking",
provider: "volces-openai",
model: "doubao-seed-2-0-pro-260215",
body: map[string]any{
"reasoning_effort": "none",
},
assertion: func(t *testing.T, body map[string]any) {
thinking, _ := body["thinking"].(map[string]any)
if thinking["type"] != "disabled" {
t.Fatalf("volces seed none should disable thinking, got %+v", body)
}
if _, ok := body["reasoning_effort"]; ok {
t.Fatalf("volces seed none should remove reasoning_effort: %+v", body)
}
},
},
{
name: "volces seed enables thinking and maps xhigh",
provider: "volces-openai",
model: "doubao-seed-2-0-pro-260215",
body: map[string]any{
"reasoning_effort": "xhigh",
},
assertion: func(t *testing.T, body map[string]any) {
thinking, _ := body["thinking"].(map[string]any)
if thinking["type"] != "enabled" || body["reasoning_effort"] != "high" {
t.Fatalf("volces seed xhigh should enable thinking and map to high, got %+v", body)
}
},
},
{
name: "zhipu preserves xhigh for glm 5.2",
provider: "zhipu-openai",
model: "glm-5.2",
body: map[string]any{
"reasoning_effort": "xhigh",
},
assertion: func(t *testing.T, body map[string]any) {
thinking, _ := body["thinking"].(map[string]any)
if thinking["type"] != "enabled" || body["reasoning_effort"] != "xhigh" {
t.Fatalf("zhipu glm should use thinking enabled and preserve xhigh, got %+v", body)
}
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
var captured map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
t.Fatalf("decode request: %v", err)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"id": "chatcmpl-reasoning",
"object": "chat.completion",
"model": captured["model"],
"choices": []any{map[string]any{
"message": map[string]any{"role": "assistant", "content": "ok"},
}},
})
}))
defer server.Close()
body := map[string]any{
"messages": []any{map[string]any{"role": "user", "content": "ping"}},
}
for key, value := range tc.body {
body[key] = value
}
baseURL := tc.baseURL
if baseURL == "" {
baseURL = server.URL
}
_, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "chat.completions",
Model: tc.model,
Body: body,
Candidate: store.RuntimeModelCandidate{
Provider: tc.provider,
BaseURL: baseURL,
ProviderModelName: tc.model,
ModelName: tc.model,
Credentials: map[string]any{"apiKey": "test-key"},
},
})
if err != nil {
t.Fatalf("run openai client: %v", err)
}
tc.assertion(t, captured)
})
}
}
func TestUsageFromOpenAIUsageTracksKnownCachedInputZero(t *testing.T) {
knownZero := usageFromOpenAIUsage(map[string]any{
"prompt_tokens": 100,