关于 LaTeX Look
LaTeX Look 面向 Agent 和 LaTeX 作者,可查看编译页面并核验编辑效果。它在一次调用中整合页面渲染、源码行定位和构建对比,也提供 CLI 与 MCP 服务。
主要功能
- 01编译并渲染 LaTeX 页面
- 02将 PDF 坐标映射到源码行
- 03对比页面与先前构建
- 04审查文档中的编辑变化
- 05用于手动检查的 CLI
适用场景
- 01发现编译未报错的版式问题
- 02定位页面区域对应的源码
- 03通过前后差异核验编辑
MCP 相关
MCP 服务向 MCP 客户端提供 `latex_look` 工具。它返回页面图像,并支持选择页面、文本定位、坐标到源码映射、对比和审查选项。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
1收录的工具列表 · 更新于 3 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| dpi | number | 否 | 渲染分辨率,范围为 50-300。默认值为 120。 |
| file | string | 是 | 主 .tex 文件的路径(绝对路径,或相对于当前目录的路径)。 |
| page | number | 否 | 要渲染的 PDF 页面,从 1 开始计数。使用 `text` 时省略,此时会自动查找页面。 |
| text | string | 否 | 页面上可见的短字符串(标题文字、标题或独特短语)。解析为其源文件:行号和页码。 |
| audit | boolean | 否 | 审查每一页相对于此文档上一次审查的布局回归:页面内容提前结束、页面内容从较低位置开始、几乎空白的页面,但仅检查由本次编辑引入的问题。对整类页面进行更改(如标题文字、页眉、间距)后运行。 |
| fresh | boolean | 否 | 忽略构建缓存,从头开始编译。仅在怀疑缓存已过期时使用。 |
| engine | string | 否 | auto | xelatex | lualatex | pdflatex | latexmk | tectonic。默认值为 auto,它会根据文档使用的引擎进行选择。 |
| pointX | number | 否 | 页面上某个点的 X 坐标,需与 pointY 一起提供。可传入先前差异结果的 bbox,以检查发生了什么变化。 |
| pointY | number | 否 | 同一点的 Y 坐标,单位为 PDF 点,原点为页面左上角。 |
| compare | string | 否 | 同一文档较早版本的 PDF 路径。系统会将页面与其进行差异比较,并渲染一张修改前图像。 |
| sequence | string | 否 | 检查以此前缀开头的编号标签的阅读顺序(例如 '图' 或 'Figure')。图形变成浮动体而相邻内容仍保持行内时会导致顺序颠倒:读者翻页后先看到图 3-4,再看到图 3-3。 |
| auditBlankMm | number | 否 | 页面底部的空白达到多少毫米时,审查才将其判定为页面空洞。默认值为 30。 |
详细介绍
latex-look — 教会 Agent 看懂你的 LaTeX
English · 简体中文

左图:编译时零错误。右图:只需五句话,读者就能大声指出问题——“删掉标题周围的横线”“这张表是网格表,改成 booktabs 表”“这个链接超出页面了”“这张图太宽了”。在 examples/broken-layout 中亲自试试。
一个 DeepSeek Harness 插件,只添加一个工具:latex_look。
只读取 .tex 源码的 Agent 就像盲人:文档可以零错误地编译成功,但外观仍然有问题。latex_look 会编译文档、将页面渲染为图像、把页面上的任意位置映射回确切的源代码行,并对比上次编辑所造成的变化——一次调用即可完成。
┌─────────────┐ latex_look ┌──────────────┐
│ agent │ ─────────────► │ pdf → png │
│ (edits .tex)│ │ synctex │
└─────────────┘ ◄───────────── │ pixel diff │
▲ image + line └──────────────┘
└─────────────── verification ───────────┘
阅读案例研究:一本 215 页的 LaTeX 书籍,按读者的方式阅读——163 张图、129 个公式,以及六类能顺利编译通过的问题。
为什么只用一个工具,而不是三个
渲染、定位和对比是实现细节。Agent 需要一个连贯的动词——“看看这一页”——就像人一样。latex_look 会在一次调用中完成编译、渲染、解析和对比,因此工作循环是:
look → diagnose → edit .tex → look again → confirm the change → report
安装
需要 Node ≥ 18、TeX 引擎(xelatex/lualatex/pdflatex/latexmk 或 tectonic)、synctex 和 ghostscript。
本仓库就是这个程序包:package.json 声明了 dsh.bundle.patch,而 cordis.patch.yml 会插入一行。
git clone https://github.com/fangchenghao/latex-look
然后将其安装到当前配置中(在 Harness 中通过插件管理器安装):
plugin_manager action: install_bundle target: /absolute/path/to/latex-look
这会添加 latex-look 这一行并注册 latex_look 工具。替换已安装程序包的源代码后,需要重启 Harness 才能加载新一代模块。
该程序包已发布到 npm,名称为 @fffangchenghao/dsh-latex-look,因此也可以直接从注册表安装同一行:
plugin_manager action: install_bundle target: @fffangchenghao/dsh-latex-look
更新
插件会在后台每天检查一次注册表;如果有较新版本,只会在工具回复中追加一行——不会反复提醒,离线机器也不会收到任何提示。要升级,只需再次安装同一程序包:
plugin_manager action: install_bundle target: @fffangchenghao/dsh-latex-look
在运行中的配置中,升级会立即生效;Harness 会在下次启动时重新加载新一代模块,因为 core.mjs(与 index.js 不同)不会热重载。
在检出目录中,也可以直接执行检查:
npx latex-look --version
npx latex-look --check-update
发布
打上 v* 标签后,会在安装了 TeX 和 Ghostscript 的 Ubuntu 上运行测试套件,验证标签与 package.json 相符,并发布到 npm。令牌来自仓库密钥 NPM_TOKEN。
可选:知识技能
这个工具让 Agent 拥有双眼。SKILL.md 为其提供 LaTeX 知识,帮助它根据所见采取行动——其中包含“症状 → 原因 → 修复”操作手册(你想去掉的横线通常来自 \pagestyle/fancyhdr,而不是多余的 \hline)。将它复制或符号链接到技能根目录:
mkdir -p ~/.dsh/skills/latex-look
ln -sf "$PWD/SKILL.md" ~/.dsh/skills/latex-look/SKILL.md
CLI,供人类使用和测试
node bin/latex-look.mjs book.tex --page 37
node bin/latex-look.mjs book.tex --text "表3.1"
node bin/latex-look.mjs book.tex --page 12 --compare previous --json
node bin/latex-look.mjs book.tex --page 1 --audit # what did the last edit break, anywhere?
CLI 与插件使用相同的引擎,且不需要 Harness,因此无需重新加载任何内容,就能快速检查修改。
面向 Claude Desktop、Cursor 和 Codex 的 MCP 服务
同一引擎也以 Model Context Protocol 服务的形式提供,因此不了解 DSH 的客户端也能使用它。它使用相同的 look(),回复中的文字也相同——插件采用 Harness 形式,而这是通用形式。
{
"mcpServers": {
"latex-look": {
"command": "npx",
"args": ["-y", "@fffangchenghao/dsh-latex-look", "mcp"]
}
}
}
将其放入 claude_desktop_config.json(Claude Desktop)、~/.cursor/mcp.json
(Cursor),或作为 TOML 代码块放入 ~/.codex/config.toml:
[mcp_servers.latex-look]
command = "npx"
args = ["-y", "@fffangchenghao/dsh-latex-look", "mcp"]
它提供一个工具 latex_look,参数与其他地方相同:
file、page、text、pointX/pointY、compare、audit、sequence、dpi。
页面会以图像内容块的形式返回,因此模型能看到页面本身。
要求与通常一样——需要一个 TeX 引擎,并且 ghostscript 位于 PATH 中:
brew install --cask mactex-no-gui ghostscript # macOS
sudo apt install texlive-xetex ghostscript # Debian/Ubuntu
winget install MiKTeX.MiKTeX ArtifexSoftware.GhostScript # Windows
在 Windows 上无需将任何内容添加到 PATH:插件会查找 gswin64c
(这是 Ghostscript 在 Windows 上的实际名称);找不到时,会在
C:\Program Files\gs\gs*\bin 以及 TeX Live、MiKTeX 和 TinyTeX 的安装目录中查找。
如果你更希望明确指定,可以将 PATH 指向
C:\Program Files\gs\gs10.05.1\bin,它会优先使用该路径。
不会上传任何内容:每次调用都会编译你磁盘上已有的文档。
它已列入官方 MCP Registry,名称为 io.github.fangchenghao/latex-look,因此搜索 Registry 的客户端可以按名称安装;它也收录于 awesome-mcp-servers。
测试
在干净的检出环境中会运行三个测试套件——它们会创建自己的测试文件并编译真实文档,因此需要几分钟:
node test/smoke.mjs # unit level: problem parsing, PPM, raster diff, aux detection
node test/scenarios.mjs # 52 end-to-end cases driven through index.js
node test/scenarios-deep.mjs # 29 cases: multi-file papers, beamer, twocolumn, images,
# engine switching, the build cache, hostile inputs
node test/book-scenarios.mjs # 15 cases against a real 208-page book (164 .tex files)
node test/book-tasks.mjs # 18 real editing tasks on the same book (see below)
LATEX_LOOK_BOOK=/pristine/copy node test/book-tasks.mjs # point it at an unedited copy
书籍测试套件需要一本真实的书,除非你指定一本,否则会跳过:
LATEX_LOOK_BOOK=/path/to/book node test/book-scenarios.mjs
这两个测试套件最重要,因为真实书籍的结构是根文件 → \input{main} →
\input{chap1},并使用自定义的 .sty、181 张插图、术语表和 fancyhdr 页面装饰。
book-scenarios 会在这本书上检查相关机制。book-tasks 会检查
请求:每个案例都是用户可能说的一句话,会应用到副本上,然后按 Agent 验证的方式进行验证——查看、与上一次构建进行差异比较,并确认改动出现在编辑所影响的位置:
| 用户提出的要求 | 测量结果 |
|---|---|
| 把页眉那条横线去掉 | 0.09%,bbox y=52 h=1(顶部的一条细带) |
| 页眉的线太细,加粗到 2pt | 0.27%,bbox y=52 h=3 |
| 链接的蓝色去掉 | 0.29%,bbox 位于目录页 |
| 行距调大一点 | 10.53%,208 → 248 页 |
| 表格行距加大 | 9.07% |
| chap2 那个总结框太窄,放宽 | 7.39% |
| chap1 那个图太小,放大 | 10.57% |
| chap4 那组图对齐时右边空着 | 8.81% |
| 段落首行不要缩进 | 14.07% |
| 页边距太窄 | 13.32%,208 → 226 页 |
| 正文字号改成 12pt | 11.63%,208 → 226 页 |
| 目录只显示到章 | 2.19%,208 → 207 页 |
这些案例都不会断言改动看起来如何——这要看图像。断言检查的是:构建成功、存在差异,并且差异的边界框位于编辑所影响的区域。
两个端到端测试套件只对 @deepseek-ai/dsh-tools 进行模拟(它仅存在于 Harness 内部),并使用真实参数调用真实的 execute,因此它们会测试参数处理以及模型实际读取的确切文本,而不只是 lib/core.mjs。这很重要:通过这种方式发现的几个错误只存在于格式处理层。
SyncTeX 指定的页面不一定是它所在的页面
SyncTeX 记录的是框构建时所在的页面。TeX 将浮动体移到下一页时,它会保留上一页的页码,因此 text: "Version 0.5" 过去会为实际位于第 206 页的表格返回“第 205 页”——而第 205 页属于另一个章节。现在,工具会检查 PDF 自带的文本层(gs -sDEVICE=txtwrite,每页约 0.12 秒),并向前后各查找一页和两页;如果结果与 SyncTeX 不同,它会说明这一点。
一张图,而不是两张
一次 compare 调用会写入三张图片,但要展示给用户的是
images.sideBySide:左侧是修改前的页面,右侧是修改后的页面,合成一张
PNG。对于无法阅读源文件的人来说,最难的部分就是对照两个独立文件,凭肉眼找出差异。
写入 PNG 不需要依赖项——文件签名、IHDR、一个 zlib IDAT,再加上
node:zlib 提供的压缩功能即可。在 140 dpi 下,合成一张 A4 页面约需 0.3 秒,而且只有在有内容可供比较时才会运行。
性能
验证编辑始终需要实际编译,这无法绕开。但浏览同一构建的页面不应如此:
| 操作 | 208 页的书 |
|---|---|
| 首次查看(3 次编译 + 词汇表) | ~17 s |
| 此后每次查看,源文件未变 | ~0.2 s |
当文档、它 \input/\include 的所有文件(三层)、它的 \includegraphics 文件以及 aux 文件均未变化(mtime 和大小)时,就会复用构建。失败的构建绝不会被复用。传入 fresh: true 可跳过复用。
有两点值得了解:
- 修改前的快照属于构建,而不是调用。 编辑后,第一次查看会记录页面修改前的样子;之后查看同一构建时都会复用同一份快照,因此 Agent 检查自己修改的三个页面时,第二和第三个页面仍能看到差异。(以前快照会在第一次调用时被消耗掉,恰好完全反了。)
- 每个文档同一时间只进行一次构建。 对同一文件进行两次编译会共用其
.aux/.toc文件并互相破坏——在 208 页的书上同时运行两个进程时,其中一个进程直接退出,连错误消息都没有。现在,进程内通过 promise 队列串行化构建,跨进程则通过包含所有者 PID 的锁文件串行化,因此被终止的运行不会让文档一直卡住。
经测试后,我们决定不在中间编译阶段使用 -draftmode:它只能节省约 2%,因为耗时在排版,而不在写入 PDF。约 16 秒都花在 TeX 本身。
工具
latex_look({
"file": "book.tex", // main .tex (required)
"page": 37, // optional, defaults to 1
"text": "表3.1", // optional: locate this string, show its page
"pointX": 240, // optional, with pointY: PDF points → source line
"pointY": 610,
"compare": "previous.pdf",// optional: diff against an earlier PDF
"dpi": 200, // optional, 50-300
"engine": "xelatex", // optional
"maxPasses": 3, // optional
"timeoutSeconds": 300, // optional
"fresh": false, // optional: ignore the build cache
"audit": false, // optional: whole-document layout audit vs the last run
"auditBlankMm": 30 // optional: how deep a bottom hole must be to count,
"sequence": "图" // optional: check that numbered labels stay in reading order
})
返回:
- 编译状态、编译次数、页数,以及结构化的
problems——每项包含file、line、message warnings:LaTeX/Package/Class 警告,以及 Overfull/Underfull 盒子(页面难看的常见原因)toc:文档是否声明了\tableofcontents,以及实际生成了多少个条目(空目录会报告为问题,而非成功)。声明会在\input/\include的文件中查找,因此用一行根文件包装\input{main}的情况也能正常处理aux:运行过的外部工具——makeglossaries、makeindex、biber、bibtex——根据第一次编译生成的产物选择,而非根据根文件的文本选择,因此也能处理把\makeglossaries放在所包含的前言中的多文件项目- 渲染页面的 PNG 路径——将这些路径交给图像读取器
located:文本锚点或所询问点的位置{ file, line, page }diff:changedRatio以及变化的边界框,单位为 PDF 点,可直接反馈到pointX/pointYsequence:以行首标签开头的内容的阅读顺序(“图 1-1”、“Figure 3.2”等)。浮动体的放置位置晚于源码中跟在它后面的行内对象,因此,将编号序列中的一个元素设为浮动体会让编号倒退——这是逐页差异永远无法显示的唯一缺陷audit:页面级布局问题——正文底部未达到全书最深位置的页面、起始位置偏低的页面、几乎空白的页面——与上次审计留下的基线进行比较,因此newFindings正好表示最新构建破坏的内容。系统会先检测并排除页眉、横线和页码;否则页码就会成为“全书中墨迹最靠下的位置”,导致每一页看起来都有问题
定位原理
latex_look 使用 -synctex=1 编译,因此每个字形都会带有指向其源代码行的链接。然后:
- 点 → 源代码:
synctex edit -o page:x:y:file.pdf - 文本 → 源代码:在
.tex源文件中搜索字符串,然后对每个匹配项运行synctex view,以获取其页码和坐标 - 差异边界框 → 源代码:将边界框中心作为
pointX/pointY传入
坐标以 PDF 点为单位(72 点/英寸),原点位于页面的左上角。
需要注意的限制
page是 PDF 页索引,不是页面上印刷的页码。 在测试书籍中,两者相差 10(印刷页码 130 = 索引 140);罗马数字编号的前置部分偏移量又不同。PDF 页面标签可以让工具进行转换,但 LaTeX 只有在明确要求时才会写入这些标签,因此,Agent 使用用户提供的页码时,必须先对照渲染后的页面进行确认。- SyncTeX 会定位到最近的文本位置。页面样式绘制的装饰线条(如
\pagestyle{headings}、fancyhdr)本身没有字形,因此会定位到附近的文本。请结合坐标和 LaTeX 知识进行判断——这正是SKILL.md的用途。 - 系统会通过对
.aux/.toc/.out/… 文件进行哈希来检查多轮编译是否收敛——包含\tableofcontents的文档至少需要编译 2 轮;如果目录为空,latex_look会报告问题。 - 多文件检测会向下追踪三层
\input/\include。工具无法识别\import/\subfile、特殊的自定义.latexmkrc构建规则,以及\includeonly。 - 不可能保证跨引擎的像素一致性:TeX 与 Word,或两个不同的 TeX 引擎,都有不同的断行引擎。此工具验证的是当前引擎的输出,而非其他格式的输出。
- 文件名中包含
%会导致 TeX 引擎本身出错(! Emergency stop.),因此任何工具都无法提供帮助。目录名中包含%则没有问题。 - 如果编译失败且没有写入新 PDF,磁盘上的旧 PDF 不会被渲染,也不会报告差异——工具会明确说明这一点。否则,未更改的文件会显示为“更改了 0%”,也就是“你的编辑没有效果”。
engine仅接受此工具列表中的引擎(auto或已知名称);未经检查的值绝不会传给spawn。- 渲染后的 PNG 会保留在
TMPDIR/latex-look-<pid>/中,因为 Agent 会在调用返回后打开这些文件。没有任何机制会清理该目录。 - 构建缓存会跟踪文档、其
\input/\include目标、\includegraphics文件及其辅助文件。缓存不会跟踪发生更改的.sty文件,也不会跟踪通过宏而非字面量\input{...}引入的文件——如果怀疑构建缓存过期,请传入fresh: true。 - 对包含
\tableofcontents的文档设置maxPasses: 1时,如果之前不存在.toc文件,会报告错误;否则会报告警告:.toc文件是在目录页排版之后写入的,因此只编译一轮必定会生成空白目录页。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。