在线 LaTeX 编辑器有个很现实的问题:论文刚开始写时,单人编辑、在线编译就够用了;等到导师、学生、合作者一起改稿,历史版本、评论、引用管理逐渐成为刚需,原本简单的写作流程也就复杂了起来。
Oleafly 试图把这些能力放到一个开源、本地优先的编辑环境里。它支持 LaTeX、Typst 和 Markdown,强调多人协作、版本历史、本地编译与 AI Agent 集成。不过,真正值得从工程角度研究的,并不是功能列表有多长,而是这些功能背后的数据同步、版本管理和执行隔离是怎么实现的。

一、多人协作最容易出问题的地方:离线修改与并发写入
假设实验室有两名研究生同时修改 main.tex。A 在本地把实验结果从 92% 改成 95%,B 离线期间也修改了同一段内容。等 B 联网同步之后,如果服务端直接采用最后一次上传的文件,A 的修改就可能被静默覆盖。
在 Java 后端,这类问题经常出现在文档编辑、配置管理、在线表格等场景中。最容易实现的方案是直接覆盖文件:
public void saveDocument(
Long documentId, String content) {
documentMapper.updateContent(
documentId, content);
}
这段代码在单人编辑时没有明显问题;但多人同时保存时,两个请求很可能都基于同一个旧版本做出修改,最终只会保留最后一次写入的内容。数据库事务也不能自动解决这个问题,因为两个事务即使都成功提交,也不代表业务层面的修改没有被覆盖。
所以我会先增加版本号,用乐观锁阻止旧版本覆盖新版本,而不是一上来就引入复杂的分布式协同编辑架构。
UPDATE document
SET content = #{content},
version = version + 1,
updated_at = CURRENT_TIMESTAMP
WHERE id = #{id}
AND version = #{expectedVersion};
Java 服务端需要检查更新行数:
@Transactional
public void save(DocumentCommand cmd) {
int updated = documentMapper.update(
cmd.getId(),
cmd.getContent(),
cmd.getExpectedVersion()
);
if (updated != 1) {
throw new DocumentConflictException(
"文档已被其他协作者修改,请重新合并");
}
historyMapper.insert(
cmd.getId(),
cmd.getExpectedVersion() + 1,
cmd.getContent()
);
}
这里有一个容易遗漏的坑:UPDATE 和历史记录写入必须处在同一个数据库事务里,否则可能出现正文已经更新、历史记录却没有保存下来的情况。这个方案能阻止静默覆盖,但还不能自动合并两个人修改的不同段落。它更适合先把数据安全性做起来,之后再逐步演进协作能力。
二、版本历史不能只靠定时备份
Oleafly 的项目说明提到,每个项目都保留普通文件和 Git 历史,并且成功编译后会创建检查点。
这个设计思路值得借鉴:编辑过程中的临时保存,和可以恢复的稳定版本,本来就应该被当作两个不同的概念。
比如论文修改到一半时,LaTeX 突然报错:
! Undefined control sequence.
l.128 \unknowncommand{result}
如果编译器直接替换掉当前可用的 PDF,原本可以正常阅读的版本就会消失。更稳妥的做法是先产出临时产物,只有编译成功后才替换正式预览。
public BuildResult compile(Path source) {
Path tempPdf = createTempPdf();
try {
compiler.compile(source, tempPdf);
if (!Files.exists(tempPdf)
|| Files.size(tempPdf) == 0) {
throw new IllegalStateException(
"编译未生成有效 PDF");
}
replaceLastGoodPdf(tempPdf);
checkpointService.save(source);
return BuildResult.success();
} catch (Exception e) {
log.error("Document compile failed", e);
return BuildResult.failure(
"编译失败,保留上一版 PDF");
} finally {
deleteTempIfExists(tempPdf);
}
}
这段代码展示的是基本流程,生产环境还需要处理编译进程超时、PDF 校验、原子替换以及并发编译。尤其不能在文件替换成功之前就把新版本标记为可用,否则失败恢复机制本身也会产生数据不一致。
三、AI Agent 修改代码,为什么也需要版本控制?
Oleafly 还强调了 Claude Code、Codex 等 Agent 的集成,以及对改动逐项确认和撤销的能力。
对技术文档而言,AI 不只是生成一段文字,它还可能修改引用文件、图片路径、公式和构建配置。因此必须把修改范围控制在可审查的边界内。
Java 服务端如果需要实现类似的自动化文档处理,可以为每次任务创建独立工作副本,完成修改后再检查差异,而不是让任务直接覆盖正在编辑的文件。
git worktree add ../paper-review \
-b agent/review-001 HEAD
cd ../paper-review
# 执行文档修改与编译检查
git diff --check
git diff --stat
git diff
这里还要区分两个问题:Git 能追踪文件变化,但不能保证文档语义正确;git diff --check 可以发现一部分空白字符问题,却不能判断引用是否真实、公式是否正确。投稿检查仍然需要结合编译器诊断、引用解析和目标期刊规则。

最后提醒:开源项目的功能宣传需要和实际发布版本区分开来。Oleafly 的 GitHub README 把项目标注为 Beta,当前文档也提示实时协作等功能存在版本限制,部署前应核对对应版本的实际能力。
对论文工具如此,对 Java 生产系统也是一样。GitHub 地址:https://github.com/Oleafly/Oleafly
在 云栈社区,很多开发者也会反复强调:功能能否使用,要以实际运行和验证结果为准。