跳转至

文档编写指南

编写模型教程文档指南

docs/source/_templates/Model-Deployment-Tutorial-Template.md 是编写模型部署教程的模板。您可以复制并修改它以创建新文档。

可测试文档代码块生成(model-code

  • 面向**文档作者**:如何在文档中插入可测试的命令块
  • 面向**开发者**:如何添加新的转换器

内置支持的 converter_tag 值:

converter_tag 渲染结果 YAML 源
single_node 单节点的环境导出 + vllm serve 脚本 test_cases[case_index]
multi_node 一个主机的环境导出 + vllm serve 脚本 deployment[host_index]
external_dp_template 一个外部 DP 节点的环境导出 + vllm serve 命令 templates[host_index]
external_dp_launch 每个节点一行 launch_online_dp.py config[]
external_dp_proxy 负载均衡代理的启动命令 config[] + routing

面向作者:添加块

Warning

默认情况下,生成器仅扫描 .md 下的 docs/source/tutorials/models/ 文件并生成产物。 如果您将 model-code 块放在其他目录中,Sphinx 构建将不会自动生成相应的脚本。

所有 model-code 块需要:

选项 是否必需 描述
block_name 块名称;在当前文档内必须唯一
converter_tag 选择一个内置转换器
test_case_path 仓库相对路径的 YAML 路径,必须在仓库内;文件必须存在

使用块的主体添加 shell 包装行,例如 set -eux。始终将 {{ generated }} 占位符放置在应插入转换器输出的位置。

converter_tag: single_node

single_nodetest_cases 中读取一个条目。可选的 case_index 元数据用于选择条目;省略时默认为 0

仅此转换器读取的字段会在下面展开。其他测试元数据可以保留在 YAML 中,此转换器会忽略它们。

test_cases:
  - name: qwen3-8b-single
    model: Qwen/Qwen3-8B
    envs:
      HCCL_BUFFSIZE: "1024"
      SERVER_PORT: DEFAULT_PORT
    server_cmd:
      - --tensor-parallel-size
      - "1"
      - --port
      - $SERVER_PORT
      - --trust-remote-code
    server_cmd_extra:
      - --enable-expert-parallel
    benchmarks: ...

envs 被渲染为 export 行。SERVER_PORT: DEFAULT_PORT 被解析为默认单节点端口 8000model 变为 vllm serve <model>server_cmd 加上可选的 server_cmd_extra 变为命令参数。两个命令字段都可以是 shell 字符串或扁平令牌列表。

请按如下方式编写文档块:

```model-code
:block_name: qwen3_8b_single_node
:converter_tag: single_node
:test_case_path: tests/e2e/nightly/single_node/models/configs/your_model.yaml
:case_index: 0

set -eux
{{ generated }}
```

Generated shell script:

set -eux
export HCCL_BUFFSIZE=1024
export SERVER_PORT=8000

vllm serve Qwen/Qwen3-8B \
  --tensor-parallel-size 1 \
  --port $SERVER_PORT \
  --trust-remote-code \
  --enable-expert-parallel

converter_tag: multi_node

multi_nodedeployment 中读取一个条目。必需的 host_index 元数据选择要渲染哪个主机。

deployment:
  - envs:
      SERVER_PORT: "8000"
    server_cmd: >
      vllm serve Qwen/Qwen3-235B-A22B
      --host 0.0.0.0
      --port $SERVER_PORT
      --data-parallel-size 2
      --tensor-parallel-size 8
      --data-parallel-address $LOCAL_IP
  - envs:
      SERVER_PORT: "8000"
    server_cmd: >
      vllm serve Qwen/Qwen3-235B-A22B
      --headless
      --port $SERVER_PORT
      --data-parallel-size 2
      --tensor-parallel-size 8
      --data-parallel-start-rank 1
      --data-parallel-address $MASTER_IP
benchmarks: ...

server_cmd 必须是一个以 vllm serve <model> 开头的完整命令。它可以写成 shell 字符串或扁平令牌列表。

请按如下方式编写文档块:

```model-code
:block_name: qwen3_235b_worker_1
:converter_tag: multi_node
:test_case_path: tests/e2e/nightly/multi_node/internal_dp/config/your_model.yaml
:host_index: 1

set -eux
{{ generated }}
```

Generated shell script for host_index: 1:

set -eux
export MASTER_IP=192.168.1.10
export SERVER_PORT=8000

vllm serve Qwen/Qwen3-235B-A22B \
  --headless \
  --port $SERVER_PORT \
  --data-parallel-size 2 \
  --tensor-parallel-size 8 \
  --data-parallel-start-rank 1 \
  --data-parallel-address $MASTER_IP

converter_tag: external_dp_template

external_dp_templatetemplates 中读取一个条目。必需的 host_index 元数据选择要渲染哪个模板。顶级 model 字段也是必需的,因为转换器会构建 vllm serve <model>

model: Eco-Tech/GLM-Test
templates:
  - node_index: 0
    envs:
      HCCL_BUFFSIZE: "1024"
      ASCEND_RT_VISIBLE_DEVICES: "${VISIBLE_DEVICES}"
    server_cmd_template:
      - --host
      - 0.0.0.0
      - --port
      - ${PORT}
      - --data-parallel-size
      - ${DP_SIZE}
      - --data-parallel-rank
      - ${DP_RANK}
      - --data-parallel-address
      - ${DP_ADDRESS}
      - --data-parallel-rpc-port
      - ${DP_RPC_PORT}
      - --tensor-parallel-size
      - ${TP_SIZE}
      - --trust-remote-code
config: ...
routing: ...

已知的花括号模板变量会被重写为 run_dp_template.shlaunch_online_dp.py 接收的位置 shell 参数:

模板变量 渲染后的位置
${VISIBLE_DEVICES} $1
${PORT} $2
${DP_SIZE} $3
${DP_RANK} $4
${DP_ADDRESS} $5
${DP_RPC_PORT} $6
${TP_SIZE} $7

未知的花括号变量和无花括号的 shell 引用(例如 $SERVER_PORT)保持不变。

请按如下方式编写文档块:

```model-code
:block_name: glm_external_dp_template_node0
:converter_tag: external_dp_template
:test_case_path: tests/e2e/nightly/multi_node/external_dp/config/your_model.yaml
:host_index: 0

set -eux
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name

{{ generated }}
```

Generated shell script for host_index: 0:

set -eux
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name

export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES=$1

vllm serve Eco-Tech/GLM-Test \
  --host 0.0.0.0 \
  --port $2 \
  --data-parallel-size $3 \
  --data-parallel-rank $4 \
  --data-parallel-address $5 \
  --data-parallel-rpc-port $6 \
  --tensor-parallel-size $7 \
  --trust-remote-code

converter_tag: external_dp_launch

external_dp_launch 读取完整的 config 列表,并为每个节点渲染一条 launch_online_dp.py 命令。它不接受索引选项。

config:
  - node_index: 0
    port_start: 7100
    dp_rpc_port: 12321
    dp_size: 2
    dp_size_local: 2
    dp_rank_start: 0
    tp_size: 8
    dp_address: "${NODE_0_IP}"
  - node_index: 1
    port_start: 7200
    dp_rpc_port: 12321
    dp_size: 4
    dp_size_local: 4
    dp_rank_start: 0
    tp_size: 4
    dp_address: "${NODE_1_IP}"
templates: ...
routing: ...

请按如下方式编写文档块:

```model-code
:block_name: glm_external_dp_launch
:converter_tag: external_dp_launch
:test_case_path: tests/e2e/nightly/multi_node/external_dp/config/your_model.yaml

set -eux
{{ generated }}
```

Generated shell script:

set -eux
python launch_online_dp.py --dp-size 2 --tp-size 8 --dp-size-local 2 --dp-rank-start 0 --dp-address ${NODE_0_IP} --dp-rpc-port 12321 --vllm-start-port 7100

python launch_online_dp.py --dp-size 4 --tp-size 4 --dp-size-local 4 --dp-rank-start 0 --dp-address ${NODE_1_IP} --dp-rpc-port 12321 --vllm-start-port 7200

converter_tag: external_dp_proxy

external_dp_proxy 读取 configrouting。它为 load_balance_proxy_server_example.py 渲染

routing:
  type: disaggregated_prefill
  groups:
    prefiller: [0]
    decoder: [1]
config:
  - node_index: 0
    port_start: 7100
    dp_size_local: 2
    dp_rpc_port: 12321
    dp_size: 2
    dp_rank_start: 0
    tp_size: 8
    dp_address: "${NODE_0_IP}"
  - node_index: 1
    port_start: 7200
    dp_size_local: 4
    dp_rpc_port: 12321
    dp_size: 4
    dp_rank_start: 0
    tp_size: 4
    dp_address: "${NODE_1_IP}"
templates: ...

routing.groups.prefillerrouting.groups.decoder 包含指向 config 的索引。 每个被引用的节点会展开为 dp_size_local 个主机和端口条目。 代理本身运行在 ${NODE_0_IP}:1999 上。

请按如下方式编写文档块:

```model-code
:block_name: glm_external_dp_proxy
:converter_tag: external_dp_proxy
:test_case_path: tests/e2e/nightly/multi_node/external_dp/config/your_model.yaml

set -eux
{{ generated }}
```

Generated shell script:

set -eux
python load_balance_proxy_server_example.py \
  --host ${NODE_0_IP} \
  --port 1999 \
  --prefiller-hosts \
    ${NODE_0_IP} \
    ${NODE_0_IP} \
  --prefiller-ports \
    7100 \
    7101 \
  --decoder-hosts \
    ${NODE_1_IP} \
    ${NODE_1_IP} \
    ${NODE_1_IP} \
    ${NODE_1_IP} \
  --decoder-ports \
    7200 \
    7201 \
    7202 \
    7203

本地调试与生成

仅生成(不构建完整站点)

# Generate all model-code artifacts under docs/source/tutorials/models/
python3 tools/docs_codegen/cli.py

# Generate artifacts for a single document
python3 tools/docs_codegen/cli.py --doc docs/source/tutorials/models/Kimi-K2-Thinking.md

# Generate a single block and print it (no files written)
python3 tools/docs_codegen/cli.py \
  --block docs/source/tutorials/models/Kimi-K2-Thinking.md::kimi_k2_thinking_single_node \
  --dry-run --stdout

默认情况下,生成物会写入:docs/_build/doc_codegen/<doc_stem>/<block_name>.sh

Note

脚本生成后,请务必检查生成内容是否可运行,特别是环境变量和命令行参数等关键部分。

构建站点并在本地预览

# Install documentation build dependencies
python3 -m pip install -r docs/requirements-docs.txt

# (Optional) Clean previous builds
make -C docs clean

# Build the English site
make -C docs html

# (Optional) Build the Chinese site
make -C docs intl

# Preview locally
python3 -m http.server -d docs/_build/html 8000

# Then open in a browser:
# http://localhost:8000

面向开发者:添加新的转换器

转换器将一个已加载的 YAML 文件和一个解析后的 ModelCodeBlock 转换为 GeneratedScript。当前的流程如下:

  1. BlockScanner 解析 model-code 围栏,仅接受 MODEL_CODE_OPTION_NAMESYamlLoaderYamlLoadertest_case_pathtest_case_pathget_converter()get_converter()build_default_converters()block.converter_tagblock.converter_tagbuild_default_converters()GeneratedScript(content=..., language="shell")GeneratedScript(content=..., language="shell")GeneratorServiceGeneratorService}{{ generated }}docs/_build/doc_codegen//.shdocs/_build/doc_codegen/<doc_stem>/<block_name>.shtools/docs_codegen/converters.pytools/docs_codegen/converters.pyBaseConverterBaseConverternamename:converter_tag::converter_tag:convert(self, loaded_yaml, *, block) -> GeneratedScriptconvert(self, loaded_yaml, *, block) -> GeneratedScriptmake_docs_codegen_error(..., block=block)make_docs_codegen_error(..., block=block)tools/docs_codegen/utils.pytools/docs_codegen/utils.pyrequire_mappingrequire_mappingrequire_mapping_listrequire_mapping_listrequire_scalar_mappingrequire_scalar_mappingrequire_indexed_mappingrequire_indexed_mappingrequire_node_fieldrequire_node_fieldparse_command_tokensparse_command_tokenssubstitute_template_positionalssubstitute_template_positionalsrender_cli_commandrender_cli_commandbuild_default_converters()build_default_converters()get_converter()get_converter()converter_tagconverter_tagtools/docs_codegen/scanner.pyMODEL_CODE_OPTION_NAMESMODEL_CODE_OPTION_NAMEStools/docs_codegen/scanner.pytools/docs_codegen/sphinx_extension.pyModelCodeDirective.option_specModelCodeDirective.option_spectools/docs_codegen/sphinx_extension.pyblock.get_option("")block.get_option("<option_name>")tests/ut/tools/test_docs_codegen.pytests/ut/tools/test_docs_codegen.pymodel-code`model-codedocs/source/tutorials/models/docs/source/tutorials/models/tests/` 下已有的 YAML 文件。
  2. 使用 CLI 进行验证:
python3 tools/docs_codegen/cli.py --doc <your_doc> --dry-run
python3 tools/docs_codegen/cli.py --block <your_doc>::<block_name> --dry-run --stdout

如果转换器应渲染非 Shell 的内容,请相应地设置 GeneratedScript.language,以便 Sphinx 能够正确高亮生成的文字块。