跳到正文
Hacker News· edelind·· 8 天前AI 评分58

Tutor:把书籍或文档变成课程的自托管 LLM 辅导工具

Show HN: Tutor, a self-hosted LLM tutor that teaches you your books or docs

AI 导读

作者发布自托管 LLM 辅导工具 Tutor,可把 EPUB、PDF、在线书籍或在线文档转成课程,先提取概念并检查你已掌握的部分,再逐个讲解并测试。工具在本地运行,使用 Anthropic、OpenAI 或 OpenRouter 的模型,需要 Node.js 22 及以上和对应 API key,通过 npm run ingest 导入书籍、npm start 在浏览器中学习。

正文 · AI 翻译

另见我的另一个项目 Tapas Habit & Goal Tracker,一个功能齐全的 iPhone 和 Android 习惯追踪器。此外,我正在寻找一份全职工作,担任软件开发人员。请在 LinkedIn 上联系我。

一个私人导师,从你的书籍或在线文档中教你学习。你创建一个学习主题,例如“SQL”,并向其中添加书籍。一本书可以是 EPUB 文件、PDF 文件、在线书籍或在线文档。导师会在书中找到概念,并检查你已掌握哪些概念。然后它会一次一个地教授其余概念,并引用书中的内容,对每个概念进行测试。

导师在你的电脑上运行。它使用来自 Anthropic、OpenAI 或 OpenRouter 的一个大型语言模型(LLM)。由你选择模型。

概念图 课程 测试
The concept map of the subject C. The color of each row shows the status of the concept. A lesson about the address-of operator in C. It has an explanation with numbered references to the book, an example, common mistakes, and a box for questions. The test for the address-of operator. It has one question and an answer to check.

为什么不直接与你的书籍聊天?

与书籍聊天会回答你想到的问题。导师则将你的书籍变成一门课程:

  • 结构。导师将某个主题的概念放入概念图中的模块里。它从学习队列中一次一个地教授它们。
  • 所有概念。导入功能会找出每一章中的概念。然后它确保这些概念涵盖书中的粗体和斜体术语。
  • 可见的进度。概念图和复习板显示每个概念的状态,例如已知、学习中或已掌握。
  • 你的控制权。你选择要测试、学习和跳过的概念。你还设置学习队列的顺序。导师只提供建议。

快速开始

你需要 Node.js 22 或更高版本,以及 Anthropic、OpenAI 或 OpenRouter 的 API 密钥。我们在 macOS 上测试导师。

git clone https://github.com/demetrius-edelin/tutor.git
cd tutor
npm install
cp .env.example .env                       # then set the provider, the model, and the API key
npm run llm:check                          # optional: send 3 small test requests to the model
npm run ingest -- SQL /path/to/book.epub   # add a book to the subject "SQL"
npm run fetch -- https://doc.rust-lang.org/book/   # optional: download an online book into an EPUB file
npm start                                  # then open http://localhost:3000

在 Windows 命令提示符中,使用 copy 而不是 cp。

ingest 命令会显示模型请求的数量,并在开始前询问。若只想从书中的某些章节开始,请参阅使用指南的第 3 步。

工作原理

你分四步使用导师。第 1 步到第 3 步是终端中的命令。第 4 步是浏览器中的应用。

flowchart LR
    S1["1. Set up<br/>npm install<br/>.env"] --> S2["2. Check (optional)<br/>npm run llm:check<br/>npm run parse"]
    S2 --> S3["3. Add a book<br/>or some chapters<br/>npm run ingest"]
    S3 --> S4["4. Study<br/>npm start"]
    S3 -->|"more chapters or books"| S3
    style S2 stroke-dasharray: 5 5

加载中

  1. 设置导师。只需执行一次。
  2. 检查模型和书籍。此步骤是可选的。它不会保存任何数据。
  3. 向主题添加一本书。添加整本书,或只添加你现在想学习的章节。只有这一步会将书籍放入导师中。对于在线书籍,请先下载它。
  4. 在浏览器中学习。启动应用并开始学习。应用会在每个阶段显示下一步操作。

使用指南解释了每个步骤和每条命令。

在应用中

在应用中,你打开一个主题并经历以下阶段:

  • 选择:在概念图上,对每个概念进行测试、学习或跳过。若要一次性对多个概念执行此操作,请选中它们的复选框,并使用页面底部的栏。
  • 诊断:导师会针对你选择测试的每个概念提出 2 个问题。要开始,请点击概念旁边的“测试它”,或选择概念并点击“测试它们”。
  • 学习队列:要学习的概念,其顺序你可以更改。
  • 课程和测试:导师从你的书籍中教授一个概念,并附有引用。然后它用适合该概念的问题来测试它:简单概念一个问题,较大概念最多 5 个。要通过,需正确回答每个问题。通过后该概念即被掌握。
  • 复习板:所有概念的列表,包含它们的状态和星级。

模型负责出题并批改开放题答案。如果你认为评分有误,请使用“对评分提出异议”。被提出异议的答案计为正确。

命令

命令 用途 使用模型 写入内容
npm run llm:check 可选。在修改 .env 之后使用。 是,3 个小型请求。 无。
npm run parse -- <book> 可选。用于检查一本书并查找 --chapters 的章节编号。 否。 一份 data/parse/<book>/ 格式的报告,供你阅读。
npm run fetch -- <url> 用于学习在线书籍或在线文档。然后把 EPUB 文件当作书籍使用。 仅适用于没有 llms.txt 文件的网站:1 个小型请求。 一个 data/web/ 格式的 EPUB 文件。
npm run ingest -- <subject> <book> --chapters <list> --preview 推荐。在保存某些章节之前检查其概念。 是。 预览书籍文件夹中的文件。数据库不会改变。
npm run ingest -- <subject> <book> --chapters <list> 用于学习一本书的某些章节。 是。 书籍文件夹和数据库。
npm run ingest -- <subject> <book> 用于学习一本书的所有章节。 是。 书籍文件夹和数据库。
npm start 每次你想学习时。 是,用于诊断、课程和测试。 你在数据库中的进度。
npm run refresh -- <subject> <book> 仅在导师更新且更改了解析器之后。 仅用于新图片。 书籍的章节文件。

书籍文件夹是 data/subjects/<subject>/books/<book>/。数据库是 data/tutor.db。

配置

导师从 .env 文件读取其配置。将 .env.example 复制为 .env。该文件解释了每个值。

变量 值
LLM_PROVIDER anthropic、openai 或 openrouter。
LLM_MODEL 模型名称,与提供商所写的完全一致。对于 OpenRouter,使用 vendor/model 形式。
LLM_REASONING 可选。none、minimal、low、medium、high、xhigh 或 max。留空表示使用模型的默认值。
OPENROUTER_PROVIDERS 可选,仅适用于 OpenRouter。可以服务该模型的提供商,按顺序排列。
ANTHROPIC_API_KEY、OPENAI_API_KEY、OPENROUTER_API_KEY 所选提供商的 API 密钥。

导师没有默认模型。在修改 .env 之后,运行 npm run llm:check。

使用哪个模型

我们用不同的模型测试了导师。OpenAI 的 GPT-6 Luna,在推理级别 high 下,给出了最好的结果。它也是我们测试中最便宜的模型,而且对于其价格区间的模型来说非常聪明。 更新,2026 年 10 月:Anthropic 的 Claude Haiku 5.5 现在与 GPT-6 Luna 价格相同,但给出的结果好得多!

LLM_PROVIDER=anthropic
LLM_MODEL=claude-haiku-5-5
LLM_REASONING=high

如果你使用 OpenAI,请使用这些值:

LLM_PROVIDER=openai
LLM_MODEL=gpt-6-luna
LLM_REASONING=high

费用

导师使用你的 API 密钥,因此你的提供商会为每个请求向你收费。

  • Ingest 发出的请求最多,因为模型会读取书籍的每一章和每一张图片。该命令会显示请求数量,并在开始前询问。
  • 导师将每一章和每一张图片的模型结果保存在缓存中。之后运行时不会为缓存中的章节再次付费。
  • 在应用中,诊断、课程、关于课程的问题以及测试都会使用模型。
  • 高推理级别会使每个请求变慢。

端口

应用使用端口 3000。要使用其他端口,请在 shell 中设置 PORT。导师不会从 .env 读取 PORT。

PORT=8080 npm start

书籍

  • EPUB 文件效果最好。解析器会读取出版商的 CSS 以处理标题、粗体和斜体。
  • PDF 文件必须带有标签。Word 和许多出版工具都能生成带标签的 PDF 文件。对于未加标签或扫描的 PDF,解析器会停止并给出明确消息。
  • 有些书籍将代码或表格显示为图片。Ingest 使用模型来读取它们。如果模型不接受图片,图片将保留为占位符。
  • 在线书籍和在线文档:npm run fetch 会将页面下载到一个 EPUB 文件中。该命令无法读取登录后的页面,或仅在 JavaScript 运行后才显示文本的页面。参见 添加在线书籍。

常见问题

  • 我必须先运行 parse 再运行 ingest 吗? 不需要。Ingest 会自行解析书籍。parse 命令只是在终端打印一份报告,不产生任何费用。参见 检查一本书。
  • 如何找到 --chapters 所需的章节编号? 运行 npm run parse 并查看 # 列。这个编号可能与章节标题中的编号不同。
  • 如何找到 --sections 所需的节 id? 运行 npm run parse 并查看 data/parse/<book>/sections/ 中的文件名。文件 01-10-pointers.md 就是节 1.10。
  • 我必须摄取整本书吗? 不需要。使用 --chapters 或 --sections,你可以一次学习书的一部分。之后,你可以添加更多部分。
  • ingest 总是保存到数据库吗? 是的。只有 --preview 会保持数据库原样。使用 --chapters 时,应用会立即显示这些章节的概念。
  • 预览的章节我需要付费两次吗? 不需要。导师会保留每次运行的模型结果,因此之后的运行不会为这些章节再次付费。
  • 之后如何添加更多章节? 再次运行 ingest,并附上新章节或节的列表。参见 之后添加更多章节。
  • 摄取后我可以移动或删除书籍文件吗? 可以。Ingest 会在书籍的文件夹中保留一份书籍文件的副本。
  • 导师可以从在线文档进行教学吗? 可以。使用文档的地址运行 npm run fetch。然后摄取 EPUB 文件。参见 添加一本在线书籍。
  • 如何为一个主题添加第二本书? 使用相同的主题名称再次运行 npm run ingest。导师会将新书的概念添加到该主题的概念图中。
  • 如何创建一个新主题? 使用新的主题名称运行 npm run ingest。第一本书会创建该主题。
  • 如何删除一个主题? 在主题列表中,点击主题下方的“Delete”。然后点击打开的面板中的红色按钮。导师会删除书籍、概念、你的进度以及该主题的文件夹。此操作无法撤销。
  • 我可以删除 data/parse/ 吗? 可以。没有其他东西使用它。

状态与路线图

导师目前是 0.1.0 版本。本 README 和使用指南中的所有命令和应用阶段均可正常工作。导师供一个人在单台电脑上使用。

计划中:

  • 从应用中添加书籍,并显示摄取进度。目前你需要在终端中用命令添加书籍。
  • 一个容器镜像,用于在你自己的服务器上运行导师。

开发

命令 作用
npm run dev:server 和 npm run dev:app 以实时重载运行服务器和应用。使用两个终端。
npm test 运行测试。测试使用假的模型客户端,因此不会调用模型。
npm run test:watch 每次更改后再次运行测试。
npm run typecheck 检查服务器和应用的 TypeScript 类型。

技术栈

部分 工具
语言 TypeScript,运行于 Node.js 22。
服务器 Fastify。
应用 React 19 和 Vite。
数据库 SQLite,配合 better-sqlite3。
书籍解析器 用于 EPUB 的 JSZip 和 cheerio,用于 PDF 的 pdf.js,以及用于 Markdown 的 Turndown。
在线书籍 Node.js 的 fetch 函数、cheerio、用于 Markdown 页面的 marked,以及用于 EPUB 文件的 JSZip。
模型客户端 Anthropic SDK 和 OpenAI SDK。OpenRouter 使用 OpenAI SDK。
测试 Vitest。

项目结构

src/
  cli/          command-line scripts
  config.ts     reads .env
  db/           SQLite schema
  ingest/
    core/       blocks, sections, Markdown, checklist (all formats)
    epub/       EPUB reader
    pdf/        tagged PDF reader
    stages/     extract, review, and merge (the model stages)
    web/        online books: table of contents, pages, and the EPUB writer
  llm/          model client for Anthropic, OpenAI, and OpenRouter
  tutor/        diagnosis, lessons, questions, grader, and study queue
  server/       HTTP API
  app/          browser app (React)
docs/           usage guide
test/           tests, a fake model client, and a builder for test EPUB files
data/           your books, the results, and the database (not in git)

AI 辅助

我用 Claude Code 构建了 Tutor。所有产品和设计决策都由我做出,并且我用真实的书籍仔细测试了每个里程碑。Claude 编写了代码和大部分文档。

贡献

欢迎提交拉取请求。对于较大的更改,请先开一个 issue,以便我们就方案达成一致。

在发送拉取请求之前,请执行以下步骤:

  1. 运行 npm test。所有测试必须通过。
  2. 运行 npm run typecheck。它必须不显示任何错误。

隐私与版权

  • 不要提交 data/ 或 .env。Git 会忽略它们。
  • data/ 文件夹包含你购买的书籍以及你下载的在线书籍的文本。
  • fetch 命令遵循 robots.txt,并在两次请求之间等待一秒。
  • 仓库中不包含任何书籍文本。测试会在代码中构建自己的小型 EPUB 文件。
  • 当导师发送请求时,它会将书籍文本发送给你所选择的提供商。使用 OpenRouter 时,文本会发送给所选模型的供应商。

许可证

MIT

来源:Hacker News · github.com