自动给文章术语加百科链接,这个方案一分钟搞定
Matrix精选 2026年06月30日 11 分钟阅读 自动给文章术语加百科链接,这个方案一分钟搞定 主作者<a href="/u/cgartlab/updates" target="_blank" class="ss__portrait__link" data-v-47e16848> </a> <a href="/u/cgartlab" target="_blank" data-v-ab4d8426></a> 关注 CG艺术实验室 少数派作者 探索设计美学,加速生产力 | 博客:cgartlab.com | 公众号:尘光造梦 <a href="/u/cgartlab/updates" target="_blank" terminal-type="pc" class="ss__user__nickname__wrapper nickname" data-v-4400de50 data-v-6856b745>CG艺术实验室 <a href="/u/cgartlab" target="_blank" data-v-ab4d8426></a> 关注 CG艺术实验室 少数派作者 探索设计美学,加速生产力 | 博客:cgartlab.com | 公众号:尘光造梦 </a>联合作者<a href="/u/cgartlab/updates" target="_blank" class="ss__portrait__link" data-v-47e16848> </a> <a href="/u/cgartlab" target="_blank" data-v-ab4d8426></a> 关注 CG艺术实验室 少数派作者 探索设计美学,加速生产力 | 博客:cgartlab.com | 公众号:尘光造梦 <a href="/u/cgartlab/updates" target="_blank" terminal-type="pc" class="ss__user__nickname__wrapper nickname" data-v-4400de50 data-v-6856b745>CG艺术实验室 <a href="/u/cgartlab" target="_blank" data-v-ab4d8426></a> 关注 CG艺术实验室 少数派作者 探索设计美学,加速生产力 | 博客:cgartlab.com | 公众号:尘光造梦 </a> 探索设计美学,加速生产力 | 博客:cgartlab.com | 公众号:尘光造梦 11 分钟阅读 微信扫码分享 以图片分享<a href="https://service.weibo.com/share/share.php?url=?ref=weibo&title=%E3%80%90%E8%87%AA%E5%8A%A8%E7%BB%99%E6%96%87%E7%AB%A0%E6%9C%AF%E8%AF%AD%E5%8A%A0%E7%99%BE%E7%A7%91%E9%93%BE%E6%8E%A5%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%A1%88%E4%B8%80%E5%88%86%E9%92%9F%E6%90%9E%E5%AE%9A%E3%80%91%E6%88%91%E7%BB%99%E5%8D%9A%E5%AE%A2%E5%81%9A%E4%BA%86%E4%B8%80%E4%B8%AA%E3%80%8C%E6%9C%AF%E8%AF%AD%E5%B0%8F%E5%8A%A9%E6%89%8B%E3%80%8D%EF%BC%8C%E8%AE%A9%E9%99%8C%E7%94%9F%E5%90%8D%E8%AF%8D%E4%B8%8D%E5%86%8D%E6%89%93%E6%96%AD%E9%98%85%E8%AF%BB%E3%80%82%EF%BC%88%E6%9D%A5%E8%87%AA%20%40%E5%B0%91%E6%95%B0%E6%B4%BEsspai%EF%BC%89%E5%85%A8%E6%96%87%EF%BC%9A&pic=https%3A%2F%2Frssfile.sspai.com%2F2026%2F06%2F29%2Fb991c3c17b009aa6fb1ef0d1fd6c0483.png%3FimageMogr2%2Fauto-orient%2Fignore-error%2F1&appkey=3196502474#" target="_blank" rel="noopener noreferrer">分享到微博</a> 点击下方按钮可复制链接 分享收藏举报<p style="margin-left:0px;"><strong>Matrix 首页推荐</strong></p><p style="margin-left:0px;"><a href="https://sspai.com/matrix">Matrix</a> 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。 </p><p style="margin-left:0px;">文章代表作者个人观点,少数派仅对标题和排版略作修改。</p><p style="margin-left:0px;"><strong>AI 辅助说明:</strong>本文所表述的前端视觉设计和文字内容为作者原创。代码部分由作者提供需求、创意思路和术语词库领域的范围和定义,<a href="opencode.ai" target="_blank">OpenCode</a> 负责具体代码编写,作者最终审核手动调整后提交上线。</p><h2>为什么要给术语加链接</h2><p>上周有位朋友在看完博客内某篇涉及自建服务器和 <a href="https://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E9%99%84%E5%8A%A0%E5%AD%98%E5%82%A8">NAS</a> 的文章之后发来一条反馈:</p><p><a href="https://zh.wikipedia.org/wiki/RSS">RSS</a>、<a href="https://zh.wikipedia.org/wiki/WebDAV">WebDAV</a>、<a href="https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E5%9F%9F%E5%90%8D%E7%B3%BB%E7%BB%9F">DDNS</a>、<a href="https://zh.wikipedia.org/wiki/NAT%E7%A9%BF%E9%80%8F">内网穿透</a>……一堆缩写和名词来回出现,看到后面得往上翻去回忆哪个是哪个。挨个用手机划词搜索又太打断阅读节奏。</p><p>这真是个好问题,值得解决。一方面,这位朋友其实已经算是深度读者了——愿意把整篇看完,还愿意花时间告诉我哪里不舒服。另一方面,我意识到一个很尴尬的事实:<strong>我的很多文章默认读者已经了解很多基础概念,但实际上每个人接触这些概念的路径完全不同。</strong>在我看来,读者了解概念的渠道要比知不知道这个概念更重要,对概念的认知本身出现偏差,会直接导致误读更多信息,以后只会更尴尬,这样的阅读体验或许比看不懂更加糟糕。</p><p>所谓「阅读体验」,有时候并不是排版好不好看、字间距舒不舒服这么表面的事情。<strong>阅读体验的核心,是读者能不能顺畅地把注意力集中在你想表达的内容上,而不是被迫反复切换到另一个上下文去查一个陌生名词。</strong>每一秒的切换和搜索,都是在消耗读者的耐心。</p><p>最终实现效果👇。</p>利用链接预览功能<p>另外,现在的手机浏览器通常也都附带按住链接可以预览的功能,这样也就并不需要完全跳转页面,快速了解一下概念后继续浏览当前页面,我觉得这个体验更好一些。</p><p>如果你是从<a href="cgartlab.com" target="_blank">博客</a>访问的这篇文章,细心的你应该已经发现很多看不懂的词都可以点了。</p><h2>现有工具的局限:读者需要主动搜索</h2><p>其实这个问题已经有了太多解决方案。无论是 <a href="https://zh.wikipedia.org/wiki/Safari">Safari</a> 的划词查询,还是 <a href="https://zh.wikipedia.org/wiki/Google_Chrome">Chrome</a> 的「搜索 XXX」,甚至现在 <a href="https://zh.wikipedia.org/wiki/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD">AI</a> 浏览器直接翻译成「人话」,都已经相当强大。</p><p>但问题在于:<strong>它们需要读者主动发起动作,且步骤太多。</strong>读者读到「DDNS」这个词,停下来,选中它,再等搜索出结果——这个过程哪怕只要两秒,累积在一篇有三五个陌生术语的文章里,阅读的沉浸感也已经被彻底打碎。</p><p>解法很简单,碰到一个关键概念,点一下这个词就能跳转到介绍这个概念的网站就行了。</p><p>那么问题来了,一篇长文可能涉及十几二十个术语,每次修改还要检查链接对不对、挂了没有。更麻烦的是,一个术语在文章里可能出现了好几次,我只想在第一次出现时挂链接,后面出现时保持朴素文本,不然整篇文章全是重点,也就没有重点了吧——但纯手工做这件事,基本是在跟自己过不去。</p><p>于是问题变成了,<strong>我需要一个帮我「写完文章、按下发布,链接自动生成」的智能机器人。</strong></p><h2>构建自动嵌入链接</h2><p>我的博客基于 <a href="https://zh.wikipedia.org/wiki/Astro_(software)">Astro</a> 构建,每篇文章发布之前,整个网站都会经过一次重新计算生成页面——所有的文章默认从 .md 文件变成静态 HTML 网页。这个过程恰好是给术语嵌入链接的最佳时机。</p><p>为什么不选择在浏览器端做这件事?</p><p>运行时方案意味着你每次页面加载时都要下载一个术语表、在你的设备跑一遍字符串匹配,对设备性能和网络带宽都是额外的负担。而且如果匹配逻辑有更新,你无法在第一时间看到最新的改进变化。</p><p>如果在构建的时候直接处理好这个过程,就干净得多:<strong>文章在编译成 HTML 的同时,术语链接就已经被嵌入进去。读者拿到的是一份已经处理好的、可以直接阅读的静态页面。</strong>总之,把所有的计算负担交给云端去处理就好。</p><p>确定了这个方向之后,剩下的问题就是:概念怎么匹配、关键词怎么跳过、怎么优雅地和 Astro 的 <a href="https://zh.wikipedia.org/wiki/Markdown">Markdown</a> 文档处理管线协作。</p><h2>用人话讲原理</h2><p>想象你正在看一本书(就是你们网站上的那些文章),和一堆标签(我提前准备的一本字典)。</p><p>每一张标签都写着一个名词和它的解释在哪里可以找到——比如「RSS」标签告诉你,戳它就能去维基百科看答案。</p><p>现在,不用你亲自一张一张去贴。<strong>有一个机器人,在书的每一页被印刷之前,先快速扫一遍全文,找到标签的名词,把第一张标签贴到这个词第一次出现的位置,然后换个地方继续找。</strong>它还很聪明,知道标题里、代码框里、已经贴过的位置不能贴。</p><p>全部贴完之后,书就印刷出版了。你拿到手的时候,看到不懂的词身上已经有一个可以点的小标签了。</p><p>几乎所有的概念来源我都用了维基百科,它是目前最全、最稳定、支持语言最多的公共知识库,下文也会进行详细说明。</p><p>附上整个运行机制的流程图如下👇:</p><p> </p><p>这就是全部过程,如果你对具体的技术细节毫无兴趣,看到这里就够了。</p><h2>实现解剖:两个插件的接力赛</h2><p>从专业角度看,说回代码层面,这套机制由两个插件完成,分别跑在 Astro Markdown 处理管线的不同阶段。</p><h3>第一阶段:remark-glossary</h3><p>remark-glossary 是一个 remark 插件(处理 Markdown AST 的阶段),它的任务极其简单:<strong>读取文章 </strong><strong>frontmatter</strong><strong> 里的 </strong><strong>lang</strong><strong> 字段,把它存到 </strong><strong>vfile.data.glossaryLang</strong><strong> 中。</strong></p><p>文章没有声明 lang 时默认中文( zh )。这个字段在后面会被第二个插件用到——中文文章用 zh.wikipedia.org ,英文文章用 en.wikipedia.org ,繁体中文保持 zh.wikipedia.org 。</p><p>为什么需要单独一个插件来做这件事?因为 Astro 的 Markdown 管线里,remark 阶段最先执行,此时 frontmatter 已经被解析好了。如果等到后面的 rehype 阶段再去拿 frontmatter ,虽然也能拿到,但让一个插件只做一件事,是清晰的工程习惯。</p><h3>第二阶段:rehype-glossary</h3><p>rehype-glossary 是核心引擎,运行在 rehype 阶段(此时 Markdown 已经被转为 HTML AST)。它做以下事情:</p><ol><li><strong>读取语言</strong> ——从 vfile.data.glossaryLang 拿到当前文章的语言</li><li><strong>检查标签</strong> ——如果文章 tags 包含「周刊」或「Weekly」,直接跳过整篇文章(周刊属于时效性内容,不适合做术语链接,而且周刊里经常拿术语开玩笑,链接过去反而不合适)</li><li><strong>遍历所有文本节点</strong> ——用 unist-util-visit 走一遍 HTML AST,找到每一个文本节点</li><li><strong>匹配术语</strong> ——用 findTermMatches 函数扫描文本,找出所有命中术语表的位置</li><li><strong>替换节点</strong> ——把文本节点拆成「文本片段 + <a> 链接片段」的混合序列,替换到原来的位置</li></ol>原始文本节点: "我每天都在使用 RSS 和 Git,还会用 Docker 部署服务" 匹配后拆分为: "我每天都在使用 " <a href="https://zh.wikipedia.org/wiki/RSS">RSS</a> " 和 " <a href="https://zh.wikipedia.org/wiki/Git">Git</a> ",还会用 " <a href="https://zh.wikipedia.org/wiki/Docker">Docker</a> " 部署服务"<h2>匹配规则:长词优先,一词一次</h2><p>术语匹配看着简单,实际落地时有很多细节需要打磨。</p><h3>长词优先</h3><p>如果一个术语同时匹配了「 <a href="https://zh.wikipedia.org/wiki/AppleScript">AppleScript</a> 」和「Script」,你肯定希望在文本中出现 AppleScript 时链接到 AppleScript,而不是被 Script 截胡。做法是:把所有候选词按长度降序排列,长的先匹配。匹配完后标记已用,不再参与后续节点的扫描。</p><h3>每篇文章只链接一次</h3><p>同一个术语在一篇文章里经常出现多次——比如「Docker」可能在文章开头、中间、末尾都出现过。如果每次出现都加上链接,视觉上会非常杂乱,而且没有任何意义。<strong>同一个术语 ID 在全文中只链接第一次出现的位置。</strong>这个逻辑用一个 usedIds: Set<string> 来追踪,遍历文本节点时全局共享。</p><h3>跳过哪些节点</h3><p>不是所有文本都适合做术语链接。我维护了一份跳过清单:</p><ul><li><code> 和 <pre> ——代码块里的名词是代码的一部分,不是自然语言</li><li><a> ——已经包裹在链接里的文本,不能再套一层链接(HTML 不允许嵌套 <a> )</li><li><h1> 到 <h6> ——标题区域文字有限,加链接显得冗余</li><li><script> 、 <style> ——非可见内容</li><li><input> 、 <button> 、 <select> 、 <textarea> ——表单控件里的文本</li></ul><h3>ASCII 术语的边界检查</h3><p>对于全英文的术语(比如 RSS 、 Git 、 AI ),还需要做单词边界检查——确保 RSS 匹配的是独立的 RSS ,而不是夹杂在 RSSFeed 这个字符串里。做法是检查匹配位置前后一个字符是否属于 [\w] (字母、数字、下划线),如果前后紧挨着其他单词字符,则跳过这次匹配。</p><h3>重叠匹配的处理</h3><p>多个术语可能在同一段文本中出现位置重叠。比如术语表中同时有「<a href="https://zh.wikipedia.org/wiki/GitHub">GitHub</a>」和「Git」,如果文本是「<a href="https://pages.github.com/">GitHub Pages</a>」,正确的行为应该是匹配「GitHub」而不是「Git」。我的做法是将所有候选匹配按起始位置排序,然后从前到后取不重叠的匹配——起始位置大于等于上一个匹配的结束位置时才纳入结果。</p><h3>URL 决策树</h3><p>匹配到术语之后,链接指向哪里?我设计了一个优先级递减的决策链:</p>1. langs[lang].url — 该语言下自定义 URL(如指向官方中文文档) 2. entry.url — 顶层自定义 URL(如产品官网) 3. 自动拼接 Wikipedia URL — 按语言选择子域名 + wikiPath<p>为什么需要自定义 URL?有些术语没有对应的 Wikipedia 页面(比如一些小众开源工具),或者 Wikipedia 页面内容过于简略,指向官方网站或文档是更好的选择。目前大约有 15% 的术语配置了自定义 URL,专门处理这类情况。</p><p>Wikipedia URL 的拼接规则也很直接:</p>语言生成的 URLzhhttps://zh.wikipedia.org/wiki/{wikiPath}zh-twhttps://zh.wikipedia.org/wiki/{wikiPath}enhttps://en.wikipedia.org/wiki/{wikiPath}<p>繁体中文和简体中文共用中文维基百科,只是 URL 编码后的路径可能不同(取决于词条本身的繁简体设置)。</p><p><strong>为什么大部分链接指向维基百科?</strong>因为维基百科具有以下优势:</p><ul><li><strong>覆盖面广</strong> ——绝大多数技术术语都有独立词条,无需手动维护;</li><li><strong>多语言支持</strong> ——根据文章语言自动匹配对应子域名,中文/英文/繁中读者都能看到母语解释;</li><li><strong>链接稳定</strong> ——维基词条 URL 受重定向保护,不会轻易失效。</li></ul><p>对于少数没有对应维基页面或维基词条过于简略的术语(约占 15%),我会通过自定义 URL 手动指定官网或更权威的文档。这样既保证了绝大多数场景的自动化,也保留了特殊情况的灵活处理空间。</p><h2>辅助工具:审计脚本与术语总览页</h2><p>除此之外,要维护一套术语表,需要工具来辅助发现「有哪些应该收录但还没收录的术语」。</p><h3>audit-glossary.ts</h3><p>这个脚本会扫遍所有文章正文,用正则找出高频出现的英文大写词组、缩写、混合大小写的产品名等候选词,然后对照现有术语表,输出一份「未注册高频术语」报告。</p><p>比如跑完后可能告诉你:「<a href="https://openai.com/dall-e-3">DALL-E</a> 出现了 6 次、Tailwind 出现了 3 次,都还没收录。」这样我就能快速判断是否要把它们加进术语表。</p><p>当然这套启发式规则并不完美——很多普通英文单词也会被当成候选(比如 What 、 This ),但作为发现遗漏的辅助工具,它已经足够有效。</p><h3>/glossary 术语总览页</h3><p>站点上还有一个 /glossary/ 页面(支持 /en/glossary/ 和 /zh-tw/glossary/ ),它会按字母分组展示所有已收录的术语及其简短描述。读者可以直接访问 <a href="https://cgartlab.com/glossary/">这个页面</a> 来浏览完整的百科链接索引。</p><p>这个页面本身也是一个很好的「站点内容地图」——从术语分布就能看出来这个博客主要聚焦在哪些领域。</p><h3>效果与局限</h3><p>目前术语表收录了 60 多条术语,覆盖技术基础(RSS、<a href="https://zh.wikipedia.org/wiki/XML">XML</a>、Git、Docker、<a href="https://zh.wikipedia.org/wiki/%E5%9F%9F%E5%90%8D%E7%B3%BB%E7%BB%9F">DNS</a>、<a href="https://zh.wikipedia.org/wiki/Secure_Shell">SSH</a>)、AI/大模型(AI、<a href="https://zh.wikipedia.org/wiki/Gemini_(%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B)">Gemini</a>、<a href="https://zh.wikipedia.org/wiki/ChatGPT">ChatGPT</a>、<a href="https://www.anthropic.com/claude">Claude</a>、<a href="https://ollama.com/">Ollama</a>、<a href="https://cursor.com/">Cursor</a>)、自托管工具(<a href="https://zh.wikipedia.org/wiki/WordP