写 docstring 是程序员的基本功。给函数加个三引号,说明它做什么、参数是什么、返回什么。这事谁都会,ChatGPT 也能代劳。那 PyTorch 官方为什么还要专门出一个 skill 来讲它?
我第一次翻到 smithery.ai 上这个 pytorch/docstring,反应也差不多:写注释还用教?但读完它整份 SKILL.md,我发现一个之前忽略的事实。这个 skill 教的不是怎么写 docstring,是怎么写对 PyTorch 的 docstring。这是两码事。

PyTorch 的 docstring 有一套极其严格的约定,散落在 torch/_tensor_docs.py 和 torch/nn/functional.py 里,官方从来没集中文档化过。你按通用教程写出来的 docstring,十有八九会在 review 时被打回。
这个 skill 做的事,就是把那套隐式约定提炼成一份可复用的写作规范。它不生成代码,不调工具,本质上是一份高质量的 SKILL.md。但恰恰是这种小而精的定位,让它比那些大而全的 docstring 生成器更值钱。
值得提一句的是,这个 skill 的作者标识是 pytorch 组织,不是某个个人开发者。在 Smithery 平台十多万个技能里,带大厂组织背书的并不多。这一条就把它的可信度从社区平均水平往上一拉。
打过 PyTorch PR 的人都知道,第一次提交 docstring 基本要返工两轮才过得去。reviewer 不是故意挑刺,是 Sphinx 构建器对格式容错极低。一个冒号写错、默认值忘了标,整页文档就错位。这个 skill 存在的根本原因,就是提前堵住这些会被机器人打回的格式坑。
工作流拆解
这个 skill 把一条 docstring 拆成了十个组成部分,但真正要死记的只有几个硬约束。第一条就反常识:docstring 的第一行不是描述,是函数签名本身,带完整参数、默认值和返回类型注解,而且这行不能以句号结尾。
r"""conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) -> Tensor
Applies a 2D convolution over an input image composed of several input planes.
"""
为什么第一行要放签名?从 SKILL.md 的说明来看,这是给 Sphinx 渲染用的。签名单独成行,文档生成器才能正确解析参数列表。很多人写 docstring 习惯第一行写这个函数做 XX,在 PyTorch 里就是错的。
第二处硬约束是 raw string。所有 docstring 必须用 r"""...""" 开头。原因很具体:PyTorch 文档里大量用 LaTeX 数学公式写 tensor 的 shape,反斜杠是常客。不用 raw string,\text 这类转义会直接报错。这是个纯工程细节,但不知道就会踩坑。
再往下是 Args 段的格式规范。这块的硬约束列出来其实就四条:
-
参数名全部小写 -
类型用括号包裹,例如 (Tensor) -
可选参数额外标注 optional,并在末尾写 Default: \`None“` -
续行一律缩进两格
这些规则表面上是洁癖,实际保证了 PyTorch 文档站上千个函数页面的排版一致性。一个函数不遵守,整页排版可能就错位。
然后是用 Examples:: 双冒号开头、>>> 提示符写交互示例的约定。这个语法直接复用了 doctest,意味着文档里的示例理论上能被测试框架直接执行。示例不是摆着是能跑的真代码。
整个结构串起来,是一条固定的十段写作流水线:
-
函数签名 -
简述 -
数学公式 -
交叉引用 -
Notes 或 Warnings -
Args -
Keyword args -
Returns -
Examples -
外部引用
看起来繁琐,但每一段都有明确的构建目的,少写一段文档站就缺一块内容。
Keyword args 和 Args 分开写是 PyTorch 的一个历史遗留。一些函数用 positional 参数,文档归在 Args 段;另一些像 tensor.to() 这种接 kwargs 的函数,文档单独归在 Keyword args 段。区分清楚,文档站的交叉链接才能正确生成。

架构解析
搞懂这些格式约定之后,一个更根本的问题冒出来:PyTorch 为什么要把 docstring 管得这么死?答案藏在它的文档构建方式里。PyTorch 的官方文档不是人肉写的,是 Sphinx 从源码里的 docstring 自动生成的。
这意味着 docstring 不是注释,是文档的唯一真相源。torch.nn.functional.conv2d 在官网上的那一整页说明,就是从它的 docstring 渲染出来的。格式错了,文档就崩。这就是为什么 raw string、reST 语法、交叉引用这些形式主义在这里不是可选项。
交叉引用是这套系统里最体现设计功力的一环。:class:~torch.nn.Conv2d“ 这种语法,前面的 :class: 是 Sphinx 角色,后面的 ~ 前缀让渲染时只显示短名 Conv2d 而不是全路径 torch.nn.Conv2d。一个波浪号,解决了长路径把文档页撑爆的问题。
数学公式用的是 Sphinx 的 math 指令。tensor 的 shape 写成 :math:(\text{minibatch}, \text{in_channels}, iH, iW)“ 这样的 LaTeX。这也反过来解释了为什么 raw string 是刚需,反斜杠在普通字符串里就是转义灾难。
最特别的是 _add_docstr 注入机制。PyTorch 大量函数的核心实现写在 C++ 端,Python 层只是绑定壳子。源码里你翻不到 def conv1d 这种函数定义,docstring 是后期通过类似 _add_docstr(torch.conv1d, r"""...""") 的调用挂到绑定符号上的。
conv1d = _add_docstr(
torch.conv1d,
r"""
conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) -> Tensor
Applies a 1D convolution over an input signal composed of several input planes.
See :class:`~torch.nn.Conv1d` for details and output shape.
Args:
input: input tensor of shape :math:`(\text{minibatch} , \text{in\_channels} , iW)`
weight: filters of shape :math:`(\text{out\_channels} , kW)`
...
""",
)
这段代码是 PyTorch torch.nn.functional 模块的典型写法。函数实现是 C++,Python 这边一行 _add_docstr 把文档字符串挂上去。不理解这个机制,你翻遍 torch/ 目录都找不到 def conv1d,会以为文档是凭空冒出来的。

使用场景
三类 method type 是这个 skill 最实用、也最容易被低估的部分。很多人以为 docstring 就是写在 def 下面,但在 PyTorch 里,你的函数属于哪一类,决定了 docstring 该放哪、怎么写。
| 函数类型 | docstring 位置 | 典型写法 |
|---|---|---|
| 原生 Python 函数 | def 下方 |
常规三引号 r"""...""" |
| C-bound 函数 | _add_docstr 注入 |
绑定符号 + 独立 docstring |
| in-place 或 alias | add_docstr_all |
只写一行,引用原函数 |
in-place 变体和 alias 的处理尤其聪明。abs_ 这种函数不重复写参数说明,就一行说这是 abs 的 in-place 版本。既省事,又保证了文档的一致性。
最实用的场景是给 PyTorch 贡献代码。比如你给 torch.nn.functional 加一个新函数,reviewer 会盯着 docstring 看几个硬指标:
-
签名行有没有以句号结尾 -
Args 段参数类型有没有标 -
可选参数有没有写 Default -
Examples 段有没有至少一个 >>>示例 -
交叉引用是不是用了 :class:带~前缀
这个 skill 就是现成的 checklist,对照着过一遍再发 PR,能少一轮 review 往返。
另一个场景是写自定义扩展。很多人写 custom autograd Function 或自定义 nn.Module 时,想复用 PyTorch 的文档质感,却不知道那些交叉引用和数学公式的语法。这个 skill 正好是一份拿来即用的参考,特别是 raw string 和 Args 格式这两条最容易踩坑。
洞察与反思
把它和市面上那些 docstring 工具放一起看,定位差异就出来了。VS Code 的 autoDocstring、sphinx 的自动扩展,这些是帮你生成,自动插入模板。这个 skill 是教你写对,给的是规范和判断,不是模板。
这两类东西解决的是不同问题。生成器解决写得多快,这个 skill 解决写得对不对。在 PyTorch 这种约定极其特殊的项目里,生成器吐出来的通用模板恰恰是错的,所以规范比自动化更值钱。
它的局限也得说清楚。这不是自动生成工具,你还是得自己写,它只保证你写对格式。而且它完全绑定 Sphinx 和 reST 生态,配合英文文档使用。如果你做的是中文团队、或者压根不用 Sphinx 的项目,参考价值要打个折。
但换个角度看,这个 skill 的价值模型值得所有 skill 作者学习。它没有试图穷尽 docstring 的所有知识,只聚焦最容易被打回的那部分约定。一个 skill 不是知识越全越好,是越精准越好。
从 SKILL.md 的写法本身,也能看出它是从真实源码约定里长出来的。gumbel_softmax 的完整示例、tf32_note 的模板插入、parse_kwargs 的参数复用,这些都是 PyTorch 真实代码里的用法,不是凭空编的教学案例。
它最有意思的一点是做了减法:只讲 PyTorch 特有,不讲通用 docstring。通用写法网上一搜一大把,但 PyTorch 源码里那些具体的 _add_docstr 调用细节,搜是搜不到的。这种取舍才是好 skill 该有的样子。
再看一个平台层面的趋势。Smithery 在 2026 年上半年借着 Anthropic 大力推广 Skills 概念的东风,流量涨了七成左右。这个 pytorch/docstring 就在它首页 Skills 目录里,位置并不算深。这种被官方组织维护、又被生态入口推荐的技能,正是 Skills 生态从单纯跑量走向分层成熟的一个缩影。
这种做减法的 skill 比那种大而全的教程更难写。它要求作者先分辨哪些是常识、哪些才是真正的项目约定,然后把后者讲透。PyTorch 自己的源码就是答案库,skill 只是把它从源码里抄出来摆在你面前。

资源地址
| 资源 | 地址 |
|---|---|
| Smithery 页面 | https://smithery.ai/skills/pytorch/docstring |
| PyTorch 官方文档 | https://pytorch.org/docs/ |
| PyTorch 源码仓库 | https://github.com/pytorch/pytorch |
| Sphinx 文档 | https://www.sphinx-doc.org/ |
总结
pytorch/docstring 这个 skill,本质上做了一件事:把 PyTorch 源码里那套没人明说的 docstring 约定,显式化、清单化。
它最值得借鉴的不是内容本身,是定位。在一个写注释这种人人都以为会的领域里,找到了真正有门槛的那部分,然后把它讲透。这是好 skill 该有的样子。
如果你在给 PyTorch 贡献代码,或者想让自己写的自定义层有官方文档的质感,花十分钟过一遍这个 skill 绝对不亏。它不会替你写一个字,但它能让你写出来的每一个字都不返工。
