Absorb PR 11's final Para compatibility surface as an opt-in OpenAI serving layer rather than hard-coding business defaults into protocol models. The change adds server args for Para chat defaults, Kimi/GLM compatibility, tool-choice normalization, tool-role text flattening, and streaming first-chunk error preflight while preserving default upstream behavior unless explicitly enabled. Reasoning token usage is also propagated through chat/completion usage paths, with GLM compatibility emitting completion_tokens_details.reasoning_tokens. Low-risk protocol fixes accept string image_url content parts and preserve GLM function-call argument value whitespace. Constraint: Online Para-compatible deployments require request/response semantics that differ from default OpenAI serving behavior. Constraint: Current CP/HiCache/bs>1 work must not be coupled to OpenAI serving compatibility changes. Rejected: Merge PR 11 history directly | intermediate commits briefly hard-code chat max_tokens=32768 before later gating it by server args. Rejected: Enable Para compatibility by default | would change non-Para OpenAI-compatible deployments. Confidence: high Scope-risk: moderate Directive: Keep Para-specific serving policies behind explicit server args unless the business contract changes globally. Tested: PYTHONPATH=python:. python -m unittest discover -s test/registered/unit/entrypoints/openai -p 'test_para_serving_protocol.py' -v (19 tests OK) Tested: python -m py_compile modified OpenAI serving, tokenizer manager, server_args, function-call detector, and test files Not-tested: Live router/prefill/decode OpenAI serving E2E after enabling Para flags. Co-authored-by: OmX <omx@oh-my-codex.dev>
6.1 KiB
6.1 KiB
Para OpenAI Serving 对齐说明
本文总结当前分支对 sglang-para OpenAI API / serving 相关行为的对齐范围、默认策略和启用方式。
总体策略
本分支已经实现 Para 侧高风险 serving 行为,但为了降低耦合,默认不启用 Para 兼容策略。需要对齐 Para 业务行为时,通过 server args 显式打开。
默认保持上游/本分支原行为:
- chat 请求不自动填
max_tokens=32768。 - 不强制把
tool_choice改为auto。 - 不按模型路径自动启用 Kimi / GLM 特化逻辑。
- 不默认 flatten tool role 的 content list。
- streaming 不默认预拉首 chunk 做 HTTP error 转换。
启用 Para 兼容的参数
完整启用 Para OpenAI serving 对齐时,可在启动参数中加入:
--openai-chat-default-max-tokens 32768 \
--openai-force-tool-choice-auto \
--openai-kimi-compat \
--openai-glm-compat \
--openai-flatten-tool-role-text-content \
--openai-streaming-error-preflight
参数含义:
| 参数 | 默认值 | 启用后行为 |
|---|---|---|
--openai-chat-default-max-tokens 32768 |
0 |
chat 请求未传 max_tokens/max_completion_tokens 时,在 serving 层补默认输出上限。 |
--openai-force-tool-choice-auto |
False |
将显式非 auto 的 chat tool_choice 按 auto 服务。 |
--openai-kimi-compat |
False |
根据 model_path 识别 Kimi,启用 Kimi thinking 映射和固定采样参数。 |
--openai-glm-compat |
False |
根据 model_path 识别 GLM,启用 GLM tool choice 降级、413 超长错误和 GLM usage details。 |
--openai-flatten-tool-role-text-content |
False |
将 tool role 的纯 text content parts list flatten 成字符串后交给 chat template。 |
--openai-streaming-error-preflight |
False |
streaming 先预拉首 chunk;若首 chunk 是错误,转成普通 HTTP error,而不是 SSE 内报错。 |
已对齐的功能点
1. Chat 默认输出长度
Para 行为:未传 max_tokens/max_completion_tokens 时默认 32768。
当前实现:
ChatCompletionRequest.max_tokens仍保持None,避免协议模型硬编码业务默认值。- serving 层读取
openai_chat_default_max_tokens。 - 传
--openai-chat-default-max-tokens 32768后,效果与 Para 一致。
2. Kimi 兼容
启用 --openai-kimi-compat 后:
- 支持 chat 请求中的
thinking字段。 - Kimi 模型下将
thinking.type != "disabled"映射到chat_template_kwargs["thinking"]。 - 对 Kimi 应用 Para 固定采样参数:
top_p=0.95presence_penalty=0.0frequency_penalty=0.0n=1
3. GLM 兼容
启用 --openai-glm-compat 后:
- 根据
model_path包含glm识别 GLM。 - GLM 下
tool_choice="required"降级为"auto"。 - GLM input token 已超过 context length 时,抛
PayloadTooLargeError,OpenAI serving 返回 HTTP413。 - GLM chat usage 使用
completion_tokens_details.reasoning_tokens。
未启用时,GLM 超长输入仍走普通 ValueError -> HTTP 400 路径。
4. Tool choice 全局兼容
启用 --openai-force-tool-choice-auto 后:
- chat 请求中显式非
auto的tool_choice会在 serving 层转为auto。 - 协议层不再改写
tool_choice,便于关闭该行为并降低耦合。
5. Tool role content flatten
启用 --openai-flatten-tool-role-text-content 后:
- 对
role="tool"且 content 是纯 text parts list 的消息,将内容拼成字符串。 - 仅 flatten 纯 text parts;包含其他结构字段的 list 保持原样,避免破坏依赖结构化 tool content 的模板。
6. GLM function call 参数保留空格
无条件对齐 Para:
glm4_moe_detector.pyglm47_moe_detector.py
两处 detector 不再对参数值执行 strip(),只 strip 参数 key。这样可以保留模型输出或客户端参数值里的前后空格。
7. image_url 字符串兼容
无条件对齐 Para:
- 支持 OpenAI multimodal content part 中
image_url直接传字符串。 - Pydantic validator 自动转成
{ "url": ... }。
8. Streaming 首包错误转换
启用 --openai-streaming-error-preflight 后:
- chat streaming 会先拉取首个 chunk。
- 如果首 chunk 是 SSE error payload,会转成普通 HTTP error response。
- 如果首 chunk 正常,会 prepend 回 stream,不影响正常 streaming。
9. Usage / reasoning tokens
已对齐 Para usage 聚合能力:
UsageInfo增加completion_tokens_details。UsageProcessor聚合reasoning_tokens。- Chat/Completion serving 都向 usage processor 传递 reasoning token 计数。
- 启用 GLM compat 后,GLM chat 使用
completion_tokens_details.reasoning_tokens。
主要改动文件
python/sglang/srt/server_args.pypython/sglang/srt/entrypoints/openai/protocol.pypython/sglang/srt/entrypoints/openai/serving_chat.pypython/sglang/srt/entrypoints/openai/serving_base.pypython/sglang/srt/entrypoints/openai/usage_processor.pypython/sglang/srt/entrypoints/openai/serving_completions.pypython/sglang/srt/managers/tokenizer_manager.pypython/sglang/srt/function_call/glm4_moe_detector.pypython/sglang/srt/function_call/glm47_moe_detector.pytest/registered/unit/entrypoints/openai/test_para_serving_protocol.py
验证
本地 macOS 使用 uv 虚拟环境完成轻量单测验证:
VIRTUAL_ENV=/private/tmp/sglang-para-test-venv \
PATH=/private/tmp/sglang-para-test-venv/bin:$PATH \
UV_CACHE_DIR=/private/tmp/uv-cache \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONPATH=python:. \
uv run --active --no-sync python -m unittest discover \
-s test/registered/unit/entrypoints/openai \
-p 'test_para_serving_protocol.py' -v
结果:Ran 19 tests ... OK。
同时执行:
govctl check
结果:通过。