Markdown 数学公式渲染规则与排查
触发链路:三条保险,避免技能不执行
本技能通过三条链路保证在写公式时被执行:
- 前置触发:本条 description 声明「写任何数学公式之前」即触发,不等渲染失败才补救。
- 工作流挂载:仓库主技能
math-question-skill(D:\math_question\SKILL.md)的强制规则中引用本技能——做题、讲解、每日一题都经过这条链路。 - 发布前自检:含公式的输出定稿前运行
scripts/check_inline_math.py扫描;发现行内$...$必须改成行间公式或纯文本后才可发送/写入。
核心规则(Codex App 内强制)
Codex 桌面 App 只渲染独立成行的行间公式 $$...$$,不渲染行内 $...$(官方 issue #14985 确认)。公式本身没错,是定界符用错了:
❌ $f(x)=\sqrt[3]{x}$ ← 行内 $...$,App 不渲染
❌ $\dfrac{f(x_0+h)-f(x_0)}{h}$ ← 行内 $...$,App 不渲染
修法——公式独立成行,用 $$...$$:
✅ 由
$$
f'(x_0)=\lim_{h\to0}\dfrac{f(x_0+h)-f(x_0)}{h}
$$
可导 ⟺ 该极限存在且有限
行内短表达式用 Unicode 数学符号美化,观感接近渲染结果:
- 上标/下标:
xˣ(U+02E3)、10⁶、2ⁿ、x₀、x₁ - 根号:
√x(U+221A)、∛x(U+221B 三次根号) - 分数上标式:
x¹⁄³(¹ U+00B9 + ⁄ U+2044 + ³ U+00B3) - 导数撇号:
f′(x)(U+2032,不要用直撇') - 运算/关系符:
·、−、±、∞、≠、≤、≥、∈
⚠️ 不要用 ^(...) 编程式写法:x^(1/3) 观感像源码;改 ∛x 或 x¹⁄³。
复杂的行内式子(分数、根号、极限)拆成块级 $$...$$,不要硬塞成纯文本。
用户要求「保留行内公式」时怎么办(硬规则不变)
对话中用户可能说「行内公式保留 $...$、只修空格粘连」——这不改变 App 的渲染行为。行内 $...$ 在 Codex App 一律不渲染,补空格只是「源码+空格」,观感更差,仍算失败(历史教训:修完粘连后用户仍反馈「这些地方仍然有问题」,根因就是行内 $...$ 未 Unicode 化)。因此:
- 定稿前仍按硬规则执行:行内短式改 Unicode,复杂式拆独立成行的
$$...$$; - 若用户明确坚持保留行内
$...$,先说明后果(App 显示源码),并在输出末尾附「渲染提醒」; - 不要因用户要求保留而跳过
check_inline_math.py自检;[FAIL]必须清零才算完成。
行内公式 → Unicode 速查表
| 场景 | 行内 LaTeX(禁止) | Unicode 修法 |
|---|---|---|
| 单字母变量 | $f$、$g$、$A$ | f、g、A(纯文本) |
| 上标/下标 | $x^n$、$x_0$、$a_n$ | xⁿ、x₀、aₙ |
| 根式 | $\sqrt{x}$、$\sqrt[3]{x}$ | √x、∛x |
| 分数 | $\frac1n$、$\frac{x^n}{1+x}$ | 短式 1/n;复杂式拆 $$...$$ 块 |
| 极限 | $\lim_{n\to\infty}a_n$ | lim(n→∞) aₙ(Unicode 无下标箭头,趋近条件用括号并入 lim;复杂式拆块) |
| 积分 | $\int_0^1 f(x)\,dx$ | 复杂式拆 $$...$$ 块,不硬塞行内 |
| 绝对值 | $\lvert x\rvert$ | ` |
| 集合/关系 | $x\in[0,1]$、$f\le g$ | x∈[0,1]、f ≤ g |
| 箭头 | $x\to0$、$n\to\infty$ | x→0、n→∞ |
| 省略号 | $a_1+\cdots+a_k$ | a₁+…+aₖ |
表格里的公式(Codex App 第二高发场景)
表格单元格内 $...$ 不渲染;而 $$...$$ 独立成行会拆散表格行。表格单元格里一律不放公式定界符:
| 做法 | 说明 |
|---|---|
❌ 单元格写 $x^{1/3}$ | 行内不渲染,显示成源码 |
❌ 单元格写 $$x^{1/3}$$ | 多行定界符拆散表格 |
| ✅ 单元格只放纯文本/Unicode | ∛x、` |
| ✅ 公式放表格下方 | 每个公式独立成行 $$...$$,跟在表格后 |
| ✅ 内容以公式为主 | 改用结构化列表(小标题 + $$...$$),不用表格 |
示例——三个不可导例子:
| 函数 | x = 0 处失败模式 |
|---|---|
| ∛x | 竖直切线,差商 → +∞ |
| x·sin(1/x) | 剧烈振荡,极限不存在 |
表格下方放公式:
$$ \lim_{h\to0}\frac{h^{1/3}}{h}=+\infty $$
发布前自检(30 秒,定稿必做)
⚠️ 先设控制台编码为 UTF-8:Windows 默认控制台是 GBK,脚本输出含中文或 emoji(如 ✅)时会报 UnicodeEncodeError 或乱码。跑校验前先执行:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$env:PYTHONIOENCODING = 'utf-8'
聊天回复草稿:
python "D:\math_question\.agents\skills\markdown-math-render\scripts\check_inline_math.py" - < 草稿.txt
检查已写入的文件:
python "D:\math_question\.agents\skills\markdown-math-render\scripts\check_inline_math.py" "D:\math_question\目标文件.md"
- 退出码 0(输出
[OK])→ 干净,可发送/写入 - 退出码 0 +
[STYLE]提示 → 有^(...)源码式上标(如x^(1/3)),观感像代码,建议改∛x/x¹⁄³或块级公式(风格建议,不阻塞) - 退出码 1(输出
[FAIL]及行号)→ 两类问题:行内$...$(改成独立成行的$$...$$或 Unicode 纯文本);$$...$$未独立成行(把$$所在行行首/行尾的文本挪走)。按行号改完重跑直到无[FAIL]
确认公式本身没坏(30 秒)
仓库自带 KaTeX CLI,验证 TeX 语法:
@'
\dfrac{f(x_0+h)-f(x_0)}{h}
'@ | node scripts/node_modules/katex/cli.js
- 输出含
<annotation ...>且退出码 0 → 公式没问题,是定界符/渲染器问题 - 抛 ParseError → TeX 语法错,先改公式
一句话原则
在 Codex App 里,公式一律独立成行用
$$...$$;行内短式用 Unicode 上/下标美化(xˣ、f′(x));表格单元格里不放公式,公式放表格下方;定稿前跑check_inline_math.py兜底,禁止行内$...$。