<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Project on Armstrong Yan</title><link>https://yanqian.github.io/zh/tags/project/</link><description>Recent content in Project on Armstrong Yan</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Wed, 22 Jul 2026 00:18:29 +0800</lastBuildDate><atom:link href="https://yanqian.github.io/zh/tags/project/index.xml" rel="self" type="application/rss+xml"/><item><title>用 Obsidian 和 Hugo 搭建人工审核的双语发布流水线</title><link>https://yanqian.github.io/zh/posts/publish/building-a-human-gated-bilingual-publishing-pipeline-with-obsidian-and-hugo/</link><pubDate>Wed, 22 Jul 2026 00:18:29 +0800</pubDate><guid>https://yanqian.github.io/zh/posts/publish/building-a-human-gated-bilingual-publishing-pipeline-with-obsidian-and-hugo/</guid><description>&lt;p&gt;在&lt;a href="https://yanqian.github.io/posts/publish/building-a-personal-blog-with-obsidian-hugo-and-github-pages/" class="external-link" target="_blank" rel="noopener"&gt;用 Obsidian、Hugo 和 GitHub Pages 搭建从私有笔记到公开网站的发布流水线&lt;/a&gt;一文中，我介绍了如何划清边界，将私有仓库与公开网站分开。&lt;/p&gt;
&lt;p&gt;那套方案解决了文章应该存放在哪里，却留下了另一个问题：同一篇文章需要以两种语言发布时，该怎么办？&lt;/p&gt;
&lt;p&gt;起初，我以为双语发布无非是翻译：把 Markdown 交给模型，让它生成中文或英文，再将结果保存在原文旁边。真正动手后我才发现，翻译反而是整个问题中最简单的一环。&lt;/p&gt;
&lt;p&gt;真正棘手的是一系列架构问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;哪个版本才是唯一可信的原文？&lt;/li&gt;
&lt;li&gt;改写正文时，怎样确保代码块、链接、图片和 Hugo 元数据完好无损？&lt;/li&gt;
&lt;li&gt;一项耗时很长的任务究竟仍在运行、已经失败，还是根本没有启动，我该如何判断？&lt;/li&gt;
&lt;li&gt;生成的草稿由谁决定能否进入公开网站？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我最终搭建的系统没有把本地化做成一个翻译按钮，而是将它纳入一条受控的发布流水线。&lt;/p&gt;
&lt;p&gt;核心规则很简单：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;文章在 Obsidian 中写作，发布工具的代码在 Hugo 仓库中维护。生成的草稿未经人工批准，一律不得进入网站。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://yanqian.github.io/posts/publish/building-a-human-gated-bilingual-publishing-pipeline-with-obsidian-and-hugo/assets/bilingual-publishing-pipeline/human-gated-bilingual-pipeline.svg" alt="人工审核的双语发布流水线"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="原文始终是唯一可信版本"&gt;
 原文始终是唯一可信版本
 &lt;a class="heading-link" href="#%e5%8e%9f%e6%96%87%e5%a7%8b%e7%bb%88%e6%98%af%e5%94%af%e4%b8%80%e5%8f%af%e4%bf%a1%e7%89%88%e6%9c%ac"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;一篇文章可以先用英文写，也可以先用简体中文写。发布工具会识别原文语言，再生成另一种语言的版本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;英文原文 -&amp;gt; 中文本地化版本
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;中文原文 -&amp;gt; 英文本地化版本
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最初的 Obsidian 笔记始终是权威原文。本地化文章只是从中生成的派生版本，不是另一份需要独立维护的原稿。&lt;/p&gt;
&lt;p&gt;这一点很重要。两份都能独立编辑的原稿很快就会出现偏差：日期可能只在英文文章中得到修正，中文文章却没有同步；重写后的结论可能只出现在一种语言中，另一种语言仍沿用早先的论证。一旦把两个文件都视为原稿，之后的每次修改都会变成一道同步难题。&lt;/p&gt;
&lt;p&gt;原始笔记只需声明允许自己进入发布流水线：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系列文章还需要记录阅读顺序：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Remote Agent Workflow&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;seriesOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系统只根据 &lt;code&gt;seriesOrder&lt;/code&gt; 选择系列中的下一篇文章，绝不随机挑选。这看似只是一条不起眼的操作规则，却能避免自动化系统将内容本身没有问题的文章按错误的叙事顺序发布。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="为什么一次翻译远远不够"&gt;
 为什么一次翻译远远不够
 &lt;a class="heading-link" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%80%e6%ac%a1%e7%bf%bb%e8%af%91%e8%bf%9c%e8%bf%9c%e4%b8%8d%e5%a4%9f"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;如果要求一个提示词一次完成所有工作，它承担的任务就太多了：既要理解论证，又要用自然的目标语言写作，还要保留所有事实，并确保 Markdown 毫发无损。这些要求混在一起，产出的文章即使流畅，也可能出错；即使忠实，也可能满是翻译腔。&lt;/p&gt;
&lt;p&gt;因此，我把整个过程拆成四个阶段。&lt;/p&gt;
&lt;h3 id="0-理解文章"&gt;
 0. 理解文章
 &lt;a class="heading-link" href="#0-%e7%90%86%e8%a7%a3%e6%96%87%e7%ab%a0"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;第一轮不做翻译，只提取文章的核心主张、目标读者、推理链、事实、术语、语气和结构元素。&lt;/p&gt;</description></item><item><title>用 Obsidian、Hugo 和 GitHub Pages 搭建从私密笔记到公开网站的发布流程</title><link>https://yanqian.github.io/zh/posts/publish/building-a-personal-blog-with-obsidian-hugo-and-github-pages/</link><pubDate>Tue, 21 Jul 2026 09:11:29 +0800</pubDate><guid>https://yanqian.github.io/zh/posts/publish/building-a-personal-blog-with-obsidian-hugo-and-github-pages/</guid><description>&lt;p&gt;最近，我重新搭建了个人网站。出发点很简单：&lt;/p&gt;
&lt;p&gt;继续把 Obsidian 作为私密内容的唯一可信来源，只从中挑选适合公开的笔记，发布到一个干净的个人网站上。&lt;/p&gt;
&lt;p&gt;这篇文章与其说是 Hugo 教程，不如说是在讨论一个问题：私密知识库与公开网站之间的发布边界，究竟该怎么划定。&lt;/p&gt;
&lt;p&gt;下面记录的是我最终采用的架构、做过的取舍，以及实际的发布流程。&lt;/p&gt;
&lt;p&gt;文中的仓库名、URL 和网站页面都来自我自己的配置。如果你也想采用这套方案，请换成自己的 GitHub 用户名、仓库名、域名和导航结构。&lt;/p&gt;
&lt;p&gt;最终，我搭出了一条从私密内容通往公开网站的发布管线：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yanqian.github.io/posts/publish/building-a-personal-blog-with-obsidian-hugo-and-github-pages/assets/blog-publishing-pipeline/01-publishing-architecture.svg" alt="从私密内容到公开网站的发布管线"&gt;&lt;/p&gt;
&lt;p&gt;它实现了这些效果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我仍然可以在 Obsidian 里自由地写笔记。&lt;/li&gt;
&lt;li&gt;私密目录结构永远不会暴露在公开网站上。&lt;/li&gt;
&lt;li&gt;公开笔记可以用一条命令发布。&lt;/li&gt;
&lt;li&gt;GitHub Pages 会自动完成部署。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="为什么我没有直接从-obsidian-发布"&gt;
 为什么我没有直接从 Obsidian 发布
 &lt;a class="heading-link" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e6%88%91%e6%b2%a1%e6%9c%89%e7%9b%b4%e6%8e%a5%e4%bb%8e-obsidian-%e5%8f%91%e5%b8%83"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;很多教程都建议直接发布 Obsidian 仓库里的内容。&lt;/p&gt;
&lt;p&gt;但我没有这么做。&lt;/p&gt;
&lt;p&gt;因为我的 Obsidian 仓库不只是写作空间，还是我的私密知识系统。&lt;/p&gt;
&lt;p&gt;里面有这样的目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;00-Inbox/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Projects/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Career/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内部笔记/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;随想/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果直接从仓库发布，就会带来边界问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;私密目录结构会出现在公开 URL 中&lt;/li&gt;
&lt;li&gt;内部笔记的组织方式会随之暴露&lt;/li&gt;
&lt;li&gt;写作时还要顾及发布要求，反过来限制笔记的组织方式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如这篇笔记：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;00-Inbox/Kafka 设计.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最终可能对应这样的公开路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/posts/00-inbox/kafka-design/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我不希望公开网站照搬自己梳理思路时使用的内部结构。&lt;/p&gt;
&lt;p&gt;因此，我加了一层中间边界：&lt;code&gt;Publish/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这个目录是可公开内容的一份干净投影。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yanqian.github.io/posts/publish/building-a-personal-blog-with-obsidian-hugo-and-github-pages/assets/blog-publishing-pipeline/02-vault-boundary-before-after.svg" alt="引入发布边界前后的仓库结构"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="最终架构"&gt;
 最终架构
 &lt;a class="heading-link" href="#%e6%9c%80%e7%bb%88%e6%9e%b6%e6%9e%84"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;最终的架构将写作结构与发布结构分开了。&lt;/p&gt;
&lt;p&gt;事实证明，这是整套方案中最关键的设计决定：私密仓库仍然可以围绕思考与整理来组织，公开网站接收到的则只有干净、适合发布的 Markdown。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="第-1-步--创建-hugo-网站"&gt;
 第 1 步 — 创建 Hugo 网站
 &lt;a class="heading-link" href="#%e7%ac%ac-1-%e6%ad%a5--%e5%88%9b%e5%bb%ba-hugo-%e7%bd%91%e7%ab%99"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="链接到标题"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;链接到标题&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;先安装 Hugo。&lt;/p&gt;</description></item></channel></rss>