文档编写指南¶
编写模型教程文档指南¶
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_node 从 test_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 被解析为默认单节点端口 8000。model 变为 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_node 从 deployment 中读取一个条目。必需的 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_template 从 templates 中读取一个条目。必需的 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.sh 从 launch_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 读取 config 和 routing。它为 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.prefiller 和 routing.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。当前的流程如下:
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// .sh docs/_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 文件。- 使用 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 能够正确高亮生成的文字块。