fix perforence

This commit is contained in:
root
2026-07-14 13:11:21 +00:00
parent 1902c81fdd
commit d0585b4a17
9 changed files with 2414 additions and 49 deletions

View File

@@ -1,5 +1,6 @@
# Adapted from
# https://github.com/lm-sys/FastChat/blob/168ccc29d3f7edc50823016105c024fe2282732a/fastchat/protocol/openai_api_protocol.py
import json
import time
from argparse import Namespace
from typing import Any, Dict, List, Literal, Optional, Union
@@ -254,6 +255,15 @@ class ChatCompletionRequest(OpenAIBaseModel):
description=("Additional kwargs to pass to the template renderer. "
"Will be accessible by the chat template."),
)
thinking: Optional[Any] = Field(
default=None,
description=(
"Per-request thinking switch (OpenAI-style top-level). Accepts: "
"{'type':'disabled'} / {'type':'enabled'} / bool true/false. "
"Translated to chat_template_kwargs.enable_thinking (bool) so the "
"Qwen3.6 template's enable_thinking branch controls reasoning. "
"Null/absent = server default (thinking on via --reasoning-parser)."),
)
guided_json: Optional[Union[str, dict, BaseModel]] = Field(
default=None,
description=("If specified, the output will follow the JSON schema."),
@@ -411,6 +421,26 @@ class ChatCompletionRequest(OpenAIBaseModel):
"Each message must have at least one of 'content' or "
"'reasoning_content'.")
msg = {**msg, "content": ""}
# tool_calls arguments: dict -> JSON string.
# Many clients/datasets send function.arguments as a dict (e.g.
# {"cmd":"ls"}), but upstream ChatCompletionMessageParam strictly
# requires a JSON string. Convert here so validation passes (matches
# OpenAI's lenient acceptance of both forms). Without this, dataset
# requests with tool messages 4xx with
# "function.arguments: Input should be a valid string".
tool_calls = msg.get("tool_calls")
if isinstance(tool_calls, list):
new_tc = []
for tc in tool_calls:
if isinstance(tc, dict) and isinstance(tc.get("function"), dict):
fn = tc["function"]
args = fn.get("arguments")
if isinstance(args, dict):
fn = {**fn, "arguments": json.dumps(
args, ensure_ascii=False)}
tc = {**tc, "function": fn}
new_tc.append(tc)
msg = {**msg, "tool_calls": new_tc}
normalized.append(msg)
data = {**data, "messages": normalized}
return data
@@ -424,6 +454,48 @@ class ChatCompletionRequest(OpenAIBaseModel):
return data
@model_validator(mode="before")
@classmethod
def validate_thinking(cls, data):
"""Translate top-level `thinking` → chat_template_kwargs.enable_thinking.
Accepts {'type':'disabled'|'enabled'} or bool. The Qwen3.6 template's
`enable_thinking is false` branch (chat_template.jinja:149) gates the
reasoning prefix, so a bool is what actually controls it. Merged into
chat_template_kwargs (request-level value wins over any pre-existing
enable_thinking). Without this, top-level `thinking` 4xx with
extra_forbidden (OpenAIBaseModel has extra="forbid").
"""
thinking = data.get("thinking")
if thinking is None:
return data
# Normalize to a bool.
enable: Optional[bool]
if isinstance(thinking, bool):
enable = thinking
elif isinstance(thinking, dict):
t = str(thinking.get("type", "")).lower()
if t == "disabled":
enable = False
elif t == "enabled" or t == "auto":
enable = True
elif t == "":
enable = None
else:
raise ValueError(
f"thinking.type must be 'enabled'/'disabled'/'auto', "
f"got {thinking.get('type')!r}")
else:
raise ValueError(
f"thinking must be bool or {{'type':'disabled'|'enabled'}}, "
f"got {type(thinking).__name__}")
if enable is not None:
ctk = dict(data.get("chat_template_kwargs") or {})
ctk["enable_thinking"] = enable
data["chat_template_kwargs"] = ctk
data.pop("thinking", None)
return data
@model_validator(mode="before")
@classmethod
def check_logprobs(cls, data):