现代开发者面临着信息爆炸的时代,浩如烟海的文档分散在各个网站,React、Stripe API、AWS 文档… IDE和浏览器标签页之间的频繁切换,让开发效率大打折扣。如何将这些文档整合起来,构建高效的知识库,并将其转化为LLM (大语言模型) 可用的数据,成为了亟待解决的问题。本文将介绍Markdocify,一款从个人需求出发,最终演变为生产级工具的文档抓取工具,它致力于解决文档碎片化的问题,并紧跟 llms.txt 规范,助力开发者构建自己的 大模型训练数据

文档碎片化:现代开发者的痛点

开发者每天都需要查阅大量的文档,例如 API 参考、框架教程等等。这些文档通常分散在不同的网站上,每个网站的结构和呈现方式都不同,这使得开发者在查找和使用文档时面临诸多挑战。传统方式比如复制粘贴,不仅效率低下,而且容易出错。文档碎片化导致的信息孤岛效应,严重阻碍了开发效率。据统计,开发者平均每天花费近20%的时间在查找和整合文档信息上。Markdocify 的出现,正是为了解决这个痛点,它旨在将散落在各处的文档整合起来,形成一个统一的、可搜索的知识库,从而提高开发效率。

Markdocify 的诞生:从个人需求到社区工具

Markdocify 最初只是作者 Vlad Kampov 为了解决个人文档查阅痛点而开发的一个 Homebrew 工具,目的是将文档网站解析为单页 Markdown 文件。但随着深入研究,他意识到这个工具的潜力远不止于此。它可以用于:

  • 创建高质量的 大模型训练数据,帮助开发者构建自己的 AI 助手。
  • 构建全面的离线知识库,让开发者随时随地访问所需的文档
  • 支持新兴的 llms.txt 标准,让网站能够以标准化的方式提供 LLM 可用的信息。
  • 文档网站发生变更或消失时,保存机构知识。

这个周末项目迅速演变成一个能够真正帮助成千上万开发者的工具。这使得 Markdocify 的定位从一个简单的个人工具转变为一个有潜力服务于整个开发社区的强大工具。

llms.txt:AI 文档的新标准

在 Markdocify 开发过程中,一件令人兴奋的事情发生了:Answer.AI 的联合创始人 Jeremy Howard 提出了 /llms.txt 文件格式,作为一种网站向 LLM 提供关键信息的标准化方式。 /llms.txt 规范旨在将复杂的 HTML 页面(包含导航、广告和 JavaScript)转换为 LLM 友好的纯文本。Stripe、Cloudflare、Anthropic 和 Zapier 等公司迅速采用了这一标准。Mintlify 在 2024 年 11 月在其文档平台中添加了 llms.txt 支持,使得数千个开发工具的文档在一夜之间变得 LLM 友好。

/llms.txt 的出现,使得 Markdocify 的价值更加凸显。它不再只是一个个人工具,而是一个能够完美支持这一新兴标准的工具,能够帮助开发者和企业更好地利用 AI 技术。

AI 驱动开发:加速工具的迭代

Markdocify 的快速开发和迭代离不开 AI 驱动的开发工具的帮助。通常需要数周或数月才能完成的项目,现在可以在一天内完成原型设计和迭代。Claude Code 和 v0.dev 等工具不仅提高了开发速度,还改变了整个创作过程。

  • Claude Code:Vlad Kampov 将 Claude Code 作为他的结对编程伙伴,帮助他快速搭建 Go 项目结构、生成全面的测试套件、调试复杂的正则表达式,并编写生产就绪的 CI/CD 配置。
  • v0.dev:v0.dev 帮助 Vlad Kampov 在不到一个小时内完成了一个精美的营销网站 markdocify.dev 的设计和开发。他可以将精力集中在信息传递和用户体验上,而无需在 CSS 布局和响应式设计上花费大量时间。

这些 AI 工具并没有取代工程师的判断,而是放大了工程师的能力。工程师仍然需要做出架构决策、理解安全含义和设计实际使用模式。AI 工具只是消除了繁琐的脚手架工作,使得好的想法能够更快地变为现实。

技术选型:为何选择 Go?

在选择实现语言时,Vlad Kampov 考虑了 Python(易于使用的抓取库)、Node.js(熟悉的生态系统)和 Go。最终,Go 以其以下优势胜出:

  • 单二进制分发: 非常适合 Homebrew 打包。
  • 内置并发: Goroutine 使得并行抓取变得优雅。
  • 跨平台构建: 一个代码库,六个平台。
  • 性能: 能够高效地处理大型文档网站。
  • 可靠性: 强类型和出色的错误处理。

此外,Go 的生态系统拥有 Vlad Kampov 所需的一切:Colly 用于网络抓取,bluemonday 用于安全,以及蓬勃发展的 CLI 生态系统。这使得 Go 成为 Markdocify 的理想选择。

设计中的安全考量:亡羊补牢,为时未晚

在 Markdocify 的开发过程中,安全性是一个重要的考量因素。Vlad Kampov 意识到,如果盲目地跟踪链接和处理不受信任的 HTML,可能会带来安全风险。例如,如果某个文档网站受到攻击,恶意 JavaScript 可能会利用抓取工具进行攻击。

为了解决这个问题,Vlad Kampov 采取了以下措施:

  • 使用 bluemonday 实施严格的 HTML 清理。
  • 使用域名白名单,限制抓取工具只能访问受信任的网站。
  • 遵守 robots.txt 协议,尊重网站的抓取规则。

这些安全措施确保了 Markdocify 在抓取文档时不会受到恶意攻击,从而保证了用户的安全。

内存管理:避免“下载整个互联网”

在测试 Next.js 文档时,Vlad Kampov 遇到了一个内存问题。抓取工具会跟踪所有链接,包括分页、编辑链接和翻译变体,导致内存消耗过大,甚至可能导致崩溃。

为了解决这个问题,Vlad Kampov 实施了以下措施:

  • 实施智能过滤,只抓取相关的文档内容。
  • 使用 SHA256 哈希进行内容去重,避免重复抓取相同的内容。
  • 实施内存管理警告,在接近内存限制时发出警告。

这些内存管理措施确保了 Markdocify 能够高效地抓取大型文档网站,而不会导致内存问题。

解决 JavaScript 问题:支持现代文档

现代文档网站越来越多地使用 React、Vue 等框架构建。Vlad Kampov 最初的 HTML-only 方法无法抓取这些网站的内容,因为它们的内容是通过 JavaScript 动态渲染的。

为了解决这个问题,Vlad Kampov 集成了 ChromeDP,用于支持 JavaScript 渲染的网站。现在,Markdocify 支持两种抓取引擎:

  • 静态 HTML 抓取: 快速且轻量级,适用于传统的文档网站。
  • 浏览器自动化: 适用于 SPA 和 JavaScript 密集型网站。

用户可以根据目标文档的类型配置要使用的引擎。这种双引擎方法使得 Markdocify 能够与传统的文档网站和现代 SPA 应用程序(如 Vue.js 或 React 应用程序)一起使用。

配置的灵活性:兼顾易用性和强大功能

在设计 Markdocify 时,最大的挑战是如何在简单性和强大功能之间取得平衡。Vlad Kampov 希望该工具能够“开箱即用”,但也要为复杂场景提供深度定制。

为了实现这一目标,Vlad Kampov 构建了一个智能模式检测系统。如果用户提供一个包含“/docs”的 URL,该工具会自动生成模式,用于跟踪文档链接,同时避免隐私页面、登录表单和其他非文档内容。

对于复杂的网站,Vlad Kampov 创建了一个全面的 YAML 配置系统:

name: "Stripe API Documentation"
base_url: "https://docs.stripe.com"
start_urls:
  - "https://docs.stripe.com/api"
follow_patterns:
  - "^https://docs\\.stripe\\.com/api/.*"
processing:
  max_depth: 4
  concurrency: 2
  delay: 2.0  # Be respectful to Stripe's servers

这个配置系统允许用户自定义抓取规则,以满足各种复杂的需求。

测试驱动开发:构建信心

测试对于 Markdocify 的开发至关重要。Vlad Kampov 并没有一开始就进行全面的测试,而是在遇到实际问题时才添加测试。

  • 在配置解析器在边缘情况下失败后,添加了配置解析器的单元测试。
  • 在发现速率限制问题后,添加了与模拟 HTTP 服务器的集成测试。
  • 在意识到域验证存在边缘情况后,添加了安全测试。

这种测试驱动开发的方法确保了 Markdocify 的稳定性和可靠性。

开源之旅:社区协作

将 Markdocify 开源是 Vlad Kampov 做出的最佳决定之一。虽然目前还没有吸引到贡献者,但他对未来的潜力感到兴奋。该项目从一开始就为协作而构建,包括全面的文档、清晰的贡献指南和维护者友好的实践,例如:

  • 包含安装和使用示例的详细 README。
  • 解释代码库结构的 CONTRIBUTING.md。
  • 用于错误报告和功能请求的问题模板。
  • 使 PR 更易于审查的全面测试套件。
  • 自动验证贡献的 CI/CD 管道。

这些措施确保了当贡献者到来时,他们会发现一个准备好协作的项目,而不是一个难以理解的个人脚本。

应用场景:超越最初的想象

Markdocify 的开发为 Vlad Kampov 打开了许多他最初没有想到的可能性:

  • 大模型训练数据: 开发者可以使用 Markdocify 创建干净、全面的数据集,用于在特定领域的文档上微调语言模型。例如,可以训练一个专门的编码助手,使其能够理解 Python 文档的完整语料库。
  • 合规性和审计: 公司可以使用它来创建第三方 API 文档的时间戳快照,以用于合规性目的。当供应商更改其 API 时,拥有历史文档对于理解重大更改至关重要。
  • 知识保留: 开源项目可以在主要版本更改之前存档文档。当 React 从类组件迁移到 Hooks 时,拥有完整的历史文档对于管理遗留代码库的团队来说将是宝贵的。
  • llms.txt 生成: 团队可以使用 Markdocify 创建符合新兴 llms.txt 标准的结构化内容,使他们的文档无需手动管理即可被 AI 访问。

Markdocify 的未来:构建 AI 就绪的文档生态

Markdocify 的发展前景广阔,未来将朝着以下方向发展:

  • 短期:
    • 增强的内容选择器,以支持更多文档框架。
    • 遵循新兴标准的原生 llms.txt 生成。
    • 针对非常大的文档网站的性能优化。
  • 中期:
    • 通过更改检测进行增量更新,以保持文档的最新状态。
    • 用于 CI/CD 管道中进行编程使用的 API 访问。
    • 用于自定义内容处理器的插件生态系统。
  • 长期:
    • 面向喜欢 GUI 的非技术用户的 Web 界面。
    • 文档托管平台集成。
    • AI 驱动的内容增强和摘要。

Markdocify 的目标是构建一个 AI 就绪的文档生态系统,帮助开发者和企业更好地利用 AI 技术。

经验总结:构建卓越工具的秘诀

Vlad Kampov 在开发 Markdocify 的过程中学到了很多关于构建工具的知识:

  1. 开发者体验至关重要: 一个工具能否被使用,往往取决于最初的 30 秒。Vlad Kampov 非常注重:清晰、有帮助的错误消息、开箱即用的明智默认值、包含示例的全面文档、通过熟悉包管理器轻松安装。
  2. 安全不能是事后诸葛亮: 从一开始就构建安全比以后进行改造要容易得多。每个功能在设计时都考虑了安全含义,这避免了整个类别的漏洞。
  3. 测试使无畏开发成为可能: 高测试覆盖率意味着可以积极重构和快速添加功能。对测试基础设施的投资得到了多次回报。
  4. 文档即代码: Vlad Kampov 像对待代码一样认真对待文档,采用相同的审查流程和质量标准。全面的指南和示例是用户实际采用该工具的原因。
  5. 从一开始就具有可观察性: 内置的日志记录、进度报告和指标使得调试用户问题变得更加容易。当有人报告问题时,详细的日志有助于快速识别根本原因。

Markdocify 的故事告诉我们,构建一个成功的工具需要注重用户体验、安全性、测试和文档,并且要从一开始就考虑到可观察性。只有这样,才能构建出一个能够真正帮助用户解决问题的工具。

结语:从周末项目到生产级工具

Markdocify 的旅程证明了,即使是一个简单的想法,也可以通过不断的迭代和改进,最终演变成一个有价值的工具。通过支持新兴标准(如 llms.txt),Markdocify 将自己定位在传统文档和 AI 优先开发工作流程的交叉点。希望 Markdocify 能够帮助更多的开发者和企业解决 文档碎片化 的问题,并构建自己的 大模型训练数据

现在就开始使用 Markdocify 吧:

# Install via Homebrew
brew install vladkampov/tap/markdocify

# Scrape your favorite documentation
markdocify https://react.dev/docs

# Create comprehensive knowledge bases
markdocify -c custom-config.yml

你希望在你的下一个编码会话中立即获得哪些文档