系列 · 产品思维 · 第 3 篇

产品思维(三):用户体验与设计系统 — Token、暗色与双语

从 CSS Token 到暗色模式到双语内容的设计系统构建——以及为什么一致性比创意更重要。

“好看就行"的问题#

每个写过 CSS 的工程师都经历过这种感觉:打开半年前的样式表,发现四十七种灰色、十二种毫无规律的字号、以及一个靠 filter: invert(1) 实现的暗色模式。代码能跑,页面能渲染。但每次加新功能都需要考古——翻遍层层即兴决策,搞清楚"正确的"淡灰文字到底该用哪个色值。

设计 Token 的级联——tokens.css 这一份事实源传播到每个组件。

我做了两个产品,被迫在不同尺度上面对这个问题。一个是 chenk.top,一个有 738 篇文章的中英双语技术博客,服务对排版和长文可读性有要求的读者。另一个是 AI4Marketing,一个支持九种语言的 SaaS 平台,几十条生成工作流,界面要在曼谷的手机和旧金山的宽屏显示器上同样好用。

两个产品教会我同一件事:设计系统不是表达创意的工具,而是说"不"的工具——持续地、系统性地、坚定到让未来的自己无法轻易推翻约束。本文追溯这个信念如何通过五个问题形成:Token 架构、暗色模式、双语内容、响应式布局、以及约束本身的哲学。


Token 驱动设计:唯一的真实来源#

问题#

chenk.top 最初的 CSS 是典型的混乱:颜色内联定义、字号凭感觉选、间距在我 14 寸 MacBook 上"看着对"但其他设备全崩。新增一个内容系列意味着从已有系列复制色值然后手动调色相。暗色模式是后补的,用 @media 覆盖半个样式表。

根本问题不是审美——是架构。没有唯一的真实来源,每个设计决策都是局部的。局部决策积累成全局的不一致。

原则:语义化 Token 即 API#

我采用了借鉴自 Material Design 但去掉企业冗余的方式:一组扁平的 CSS 自定义属性写在 tokens.css 里,作为设计系统的公开 API。下游一切——组件、页面、暗色模式——只引用 Token,绝不直接使用原始值。Token 文件分三层。

原语层——原始色板和尺度值:

1
2
3
4
5
--hue-0: #c0392b;   /* 暖红 — RL / PAI / linux / ml-math */
--hue-1: #1f6feb;   /* 靛蓝 — bailian / 时间序列 / transfer */
--hue-2: #1f8a70;   /* 深翠 — 推荐 / pde-ml / 云 */
--hue-3: #b45309;   /* 琥珀铜 — terraform / ode / cs-fundamentals */
--hue-4: #6d28d9;   /* 皇家紫 — nlp / linear / leetcode */

五种强调色。不是四种,不是七种——五种,恰好足以区分每个内容系列又不至于记不住。映射不随机:它反映了我对内容的心智分类。红色对应强化学习和系统,靛蓝对应 AI 平台和时间序列,翠绿对应推荐和云基础设施,琥珀对应经典算法和微分方程,紫色对应 NLP 和线性代数。分配新系列时,选的不是颜色——是在分类体系里定位这个系列。

尺度层——基于大三度比例(1.250)的模块化字号:

1
2
3
4
5
--fs-base: 1.0625rem;
--fs-md: 1.1875rem;
--fs-lg: 1.4rem;
--fs-xl: 1.85rem;
--fs-2xl: 2.5rem;

没有像素值,没有魔法数字。每个尺寸都是尺度上的一级台阶。如果我需要 --fs-lg--fs-xl 之间的值,答案是:我不需要。这条约束的存在就是为了防止"再大 2px"这种长期侵蚀视觉节奏的漂移。

语义层——按功能命名的颜色,不是按外观:

1
2
3
4
5
6
7
--paper: #fdfcf9;
--ink: #181821;
--ink-soft: #2c2c38;
--ink-mute: #5a5a68;
--ink-faint: #8a8a96;
--rule: #e8e4dc;
--tint: #f3efe7;

注意 --paper--ink,不是 --white--black。这不是审美考量——这是一份契约。暗色模式激活时,--paper 变成 #0f1117--ink 变成 #ecedef。每个引用 --paper 的组件自动适配。引用 --white 的组件则需要手动覆盖——这些覆盖正是设计系统积累债务的方式。

结果#

新增一个内容系列只需做一个决策:分配五种色相中的哪一种。其他一切——卡片渐变、悬停强调色、目录指示器——自动派生。Token 文件 85 行。整个网站的视觉身份就活在这 85 行里。

AI4Marketing 用同一原则但在不同尺度运作。平台用 Tailwind CSS 加底层 CSS 变量,ThemeProvider 向文档根节点写 data-theme。Token 词汇不同——--bg-primary--text-primary--accent--border——但架构一致:语义命名、唯一来源、组件代码零原始值。给平台新增一张暗色感知支付卡不需要任何暗色专属工作,它继承自 Token。


暗色模式做对#

问题#

暗色模式的天真做法是颜色反转:取亮色板、翻转明度通道、完事。这产出的界面充满敌意——浅淡的强调色在或太深(纯黑导致视觉疲劳)或太浅(灰色看着像加载错误)的背景上显得苍白。在奶油背景上效果漂亮的渐变,切到暗底后变得浑浊。阴影要么看不见,要么产生怪异光晕。

更隐蔽的失败是在两种模式中复用相同饱和度。亮底上的沉稳 #c0392b 有视觉重量。同样的值放在 #0f1117 上会消失。

原则:暗色模式是新色板,不是变换#

dark.css 不做反转——它重新创作。每个语义 Token 都有经过深思的暗色对应值:

1
2
3
4
5
6
7
8
9
:root[data-theme="dark"] {
  --paper: #0f1117;
  --ink: #ecedef;
  --ink-soft: #c9ccd1;
  --ink-mute: #8b929c;
  --ink-faint: #5c636e;
  --rule: #1f242c;
  --tint: #181d25;
}

背景是 #0f1117——深蓝灰,读起来暗但没有纯黑的刺目。强调色有意向上偏移亮度和饱和度,因为暗底需要更高的明度才能达到同等视觉重量:

1
2
3
4
5
6
/* 亮色 → 暗色 */
--hue-0: #c0392b    #f87171;   /* 沉稳红 → 珊瑚 */
--hue-1: #1f6feb    #60a5fa;   /* 靛蓝 → 天蓝 */
--hue-2: #1f8a70    #34d399;   /* 深翠 → 薄荷 */
--hue-3: #b45309    #fbbf24;   /* 琥珀铜 → 金 */
--hue-4: #6d28d9    #a78bfa;   /* 皇家紫 → 薰衣草 */

这不是计算出来的变换——每个偏移都对着暗底逐色相肉眼评估过。公式能产出数学上正确但视觉上错误的值;逐色相决策产出看起来对的值。

渐变同样重新创作:

1
2
3
4
5
/* 亮色:平静绽放 */
--grad-1: linear-gradient(135deg, #1f6feb 0%, #4f8ef7 55%, #82b6ff 100%);

/* 暗色:更深基底、更通透的绽放 */
--grad-1: linear-gradient(135deg, #1e40af 0%, #3b82f6 55%, #93c5fd 100%);

最有辨识度的决策是环境光照。暗色 body 背景不是平面色——它带有三个模拟彩色光源的径向渐变:

1
2
3
4
5
6
7
:root[data-theme="dark"] body {
  background:
    radial-gradient(1200px 700px at 8% -10%, rgba(96,165,250,0.10), transparent 60%),
    radial-gradient(900px 600px at 92% 0%, rgba(167,139,250,0.08), transparent 60%),
    radial-gradient(800px 500px at 50% 100%, rgba(52,211,153,0.06), transparent 55%),
    var(--paper);
}

左上靛蓝、右上紫罗兰、底部中央翠绿,不透明度 6-10%。效果几乎是潜意识的:页面感觉有生命、有纵深,而非扁平。悬停时,暗色模式的系列卡片发出与其色相匹配的彩色辉光:

1
2
3
4
5
6
:root[data-theme="dark"] .series-card:hover {
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.06),
    0 20px 50px -20px color-mix(in srgb, var(--card-color, var(--hue-1)) 35%, transparent),
    var(--shadow-2);
}

切换逻辑以 prefers-color-scheme 作为初始状态,接受手动覆盖并持久化到 localStorage。AI4Marketing 在 06:00 和 18:00 自动更新,匹配典型的屏幕使用节律。这两个功能都不需要改动任何具体组件。

结果#

暗色模式是同一内容的不同体验,不是仓促改编的亮色版本。夜间访问的读者看到的是一个为弱光阅读精心设计的空间。逐色相饱和度偏移让各内容系列在两种模式下都保持视觉辨识度——靛蓝主题的时间序列文章,在亮色和暗色下都清晰地是靛蓝,只是分别调校过的不同版本。


双语挑战#

问题#

chenk.top 维护 738 篇中英镜像文章。不是机器翻译——每个版本都为其受众原生撰写。英文版使用直接的技术语言。中文版假设共享文化语境,正确使用领域中文术语——不是 MT 系统那种生硬输出。

挑战是结构性的,不是语言学的。如何维护 738 对并行文档?如何在一篇更新后保持同步?如何提供无缝的语言切换?如何正确处理两种语言变体的 SEO?

原则:translationKey 作为绑定契约#

Hugo 的多语言系统用内容目录(content/en/content/zh/),通过 frontmatter 中的 translationKey 绑定对应文章:

1
2
3
4
5
# en/some-article.md 中
translationKey: "reinforcement-learning-policy-gradient"

# zh/some-article.md 中
translationKey: "reinforcement-learning-policy-gradient"

Key 是语义标识符,不是文件名。这将 URL slug(可以为 SEO 各语言单独优化)与绑定关系解耦。每种语言有自己的 slug,同时共享逻辑身份。这一点很重要:包含英文技术术语音译的中文 URL 在百度搜索的表现,远不如使用同一概念惯用中文表达的 URL。

有一个容易踩的坑:Hugo 模板里检测语言的条件是 eq .Language.Lang "zh",不是 "zh-cn"。frontmatter 里的 lang key 必须与 config.yaml 里配置的一致。配错会静默破坏语言切换器——按钮显示但导航出错,因为绑定关系失效了。

模板层面,<head> 中的 hreflang 标签向搜索引擎声明关系:

1
2
3
4
<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}">
{{ if .IsTranslated }}
<link rel="alternate" hreflang="x-default" href="{{ .Permalink }}">
{{ end }}

语言切换器 UI 刻意简单:头部一个文字切换按钮,跳转到当前页面的译文版本,不是另一语言的首页。如果不存在译文,切换器隐藏。绝不提供无法兑现的承诺——把读者丢到无关页面比没有切换按钮更损害信任。

扩展到九种语言:AI4Marketing#

AI4Marketing 把双语推向更远——九种语言(zh-CNen-USja-JPko-KRes-ESth-THvi-VNpt-BRar-SA)。理念与 chenk.top 不同:这不是人工撰写的并行内容,而是 AI 辅助的本地化。

本地化模块的核心洞察是翻译与本地化的区别:

“你的任务不是翻译——是本地化:让内容读起来像目标市场的母语营销人员写的。”

系统用 Qwen 按格式定制提示词来适配营销内容。每种格式有不同的本地化优先级:社交笔记需要适配目标平台的标签惯例(泰国 LINE 的标签规范、韩国 Naver Blog 的惯例);视频脚本需要根据目标语言的音节密度调整节奏(日语和韩语每个呼吸组携带的语义信息比西班牙语或葡萄牙语更密集);文章需要本地化的 SEO 关键词,不是英文搜索词的字面翻译。

表格结构内容需要一个防御性修复。Qwen 本地化 Markdown 表格时,偶尔会误读管道结构导致列合并。解决方案是写入前的断言:校验 len(localized_rows) == len(source_rows),且每行列数符合预期。结构不匹配时触发重试并附上明确的 schema 提醒,而不是静默写入损坏的内容。

UI 把这一切呈现为单一的"本地化"操作——将心智模型从"我需要翻译八次"简化为"我可以触达八个市场”。渐进披露处理其余部分:点击"本地化"显示一个按钮;展开面板后才显示逐语言开关,给需要精细控制的用户使用。

结果#

chenk.top 上,每种语言 36 个内容目录,translationKey 确保每篇文章有对应版本。审计流水线(scripts/audit/)捕获孤儿翻译和中文文章中的残留英文片段。AI4Marketing 上,本地化是一等公民管线阶段,不是事后补丁——它与主内容并行生成,增加约两秒延迟,产出八个额外的市场就绪版本。


响应式但不陷入断点地狱#

问题#

传统响应式方法创建断点与组件状态的矩阵,增长是组合级的。一个卡片组件可能有手机、平板、桌面三种变体;乘以二十种组件类型就是六十种布局状态要维护。后面的 @media 块以意料之外的方式覆盖前面的,特异性战争升级,移动端测试变成打地鼠。

原则:独立文件中的增量式修复#

我的做法反转了通常的方法论。基础 CSS 为桌面可读性设计。移动端适配集中在 mobile-fixes.css 里——针对具体渲染问题的增量补丁,而非布局重写。

文件以自己的作用域声明开头:

1
/* ===== Mobile-friendly fixes (audit pass 2026-05-07) ===== */

这是一次审计遍历,不是设计遍历。逻辑如下:

1. 全局溢出防护先行。 html/body 上 overflow-x: hidden,加上每个包含文章内容的 flex/grid 子元素 min-width: 0。这两条配合预防了 80% 的移动端布局 bug——flex 子元素拒绝收缩到小于固有宽度,导致元素撑破视口。

2. 代码块是主要挑战。 启用行号时,Hugo 语法高亮输出表格结构标记:div.highlight > div.chroma > table.lntabletd.lntd:first-child 是行号列,td.lntd:last-child 是代码列。表格结构对普通溢出容器有免疫力。修复方法是将其转换为 flex 行:

1
2
3
4
5
6
7
8
9
.highlight .lntable tr { display: flex; max-width: 100%; min-width: 0; }
.highlight .lntable td.lntd:first-child { flex: 0 0 auto; }
.highlight .lntable td.lntd:last-child {
  flex: 1 1 0;
  min-width: 0;
  width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

行号成为固定宽度的 flex 项;代码列成为可收缩、可横向滚动的 flex 项。行号固定在左边,代码在下方横向滚动——这才是长行代码的正确阅读体验。

3. KaTeX 公式块。 窄屏上,展示模式的数学公式(\displaystyle 分数、对齐环境)会溢出容器。修复是两条规则:

1
2
3
4
5
6
7
8
9
.katex-display {
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}
@media (max-width: 720px) {
  .katex-display { font-size: 0.92em; }
}

外层规则给展示公式一个滚动容器。媒体查询在移动端稍微缩小字号,让常见展示公式不需要滚动就能放下。iPhone SE(320px 逻辑宽度)上,这能在保持可读性的同时防止绝大多数方程导致的横向页面滚动。

4. 抽屉 transform 溢出。 移动端导航抽屉用 CSS transform 实现滑入动画。早期版本产生持续的横向溢出——抽屉的初始屏外位置泄漏进 body 的滚动宽度。修复是两个属性配合:

1
2
3
4
5
/* 抽屉元素上 */
visibility: hidden; /* 不是 display:none——保留 transition */

/* 抽屉打开时的 body 上 */
overflow-x: clip; /* clip 不是 hidden——允许 position:fixed 后代 */

body 上 overflow-x: hidden 会破坏 position: fixed 的子元素(头部、搜索覆盖层)。overflow-x: clip 在不创建新层叠上下文的情况下限制溢出,fixed 后代因此不受影响。

5. 渐进缩小尺寸,不改布局。 小手机上,hero 标题从基础的 clamp(2.4rem, 6.4vw, 4.6rem) 调整为显式的 1.7rem。布局不变,只是比例收缩。这让模板逻辑保持简单——一套布局,按视口尺寸调校。

移动修复文件共 438 行。相当可观,但每一行都针对一个具体的移动端渲染问题。没有布局逻辑,没有组件定义。移动端行为的审计只需读一个文件,而不是在二十个样式表的零散 @media 块中搜寻。

代码块复制按钮事故。 移动端审计时发现某些代码块出现了两个"复制"按钮。JavaScript 选择器是 .highlight, .highlight pre——外层包装器和内层 pre 都在接收按钮。修复方法:以 el.closest(".highlight") 作为去重锚点。每个 .highlight 包装器最多只有一个按钮,不管内部嵌套了多少 pre 元素。

结果#

站点在测试过的所有设备(iPhone SE 320px 到 27 寸 iMac 2560px)上用单一布局架构运行。移动修复适配桌面设计而不对抗它。新增组件只需回答一个问题:320px 宽度下会溢出吗?如果是,在 mobile-fixes.css 加一条规则。如果不是,继续。


设计即约束#

按钮规则#

AI4Marketing UI 中,一条规则统治每个操作行:一个填充主按钮,其余全部描边。这不是指南——是通过组件设计强制执行的硬规则。

原因是认知层面的。用户看到多个填充按钮时,必须阅读每个标签才能判断该做什么。只有一个填充按钮时,主操作在前注意力阶段就能识别——在意识阅读之前。描边的次要按钮可被发现,但不争夺注意力。

实现上的级联:

  • 主按钮使用 var(--accent),绝不硬编码颜色
  • 次要按钮用 border: 1px solid var(--border) 加透明背景
  • 暗色背景上主按钮必须仍用主题变量——亮色背景上好用的硬编码灰阶在 #0f1117 上要么看不见要么出错
  • 破坏性操作(删除、取消订阅)用源自 --hue-0 的红色变体,但单主操作规则依然成立——那行里红色按钮是唯一填充按钮

触发这条规则的失败案例:支付卡早期版本同一行里"升级"和"联系销售"都是填充按钮。用户测试里,人们反复先点"联系销售",因为两个按钮视觉权重相同。改成填充/描边组合后,无需改任何文案就解决了问题。

“无表情符号"规则#

chenk.top 不在标题、导航或正文中使用 emoji。这是对"友好型"技术写作潮流(到处撒火箭和灯泡)的有意抵抗。

Emoji 有文化负载,跨平台渲染不一致,破坏衬线标题的排版节奏,增加噪声而不带信息。写着”## 性能优化"的标题与加了符号的版本传达完全相同的内容——emoji 增加的只是读者需要过滤的视觉杂讯。

这延伸到 AI 生成内容:Claude 为博客产出内容时,系统指令明确——除非用户特别要求,否则不加 emoji。约束保护声音的一致性。一旦允许 AI 输出带 emoji,标题里迟早会出现 emoji,积累的例外会比任何有意的设计变更更快侵蚀系统。

字体栈#

1
2
3
--font-serif: "Source Serif Pro", "Lora", Georgia, "Songti SC", "STSong", serif;
--font-sans: "Inter", "IBM Plex Sans", -apple-system, "PingFang SC", "Hiragino Sans GB", sans-serif;
--font-mono: "JetBrains Mono", "IBM Plex Mono", "SFMono-Regular", Menlo, monospace;

在技术博客用 Source Serif Pro 做标题是刻意逆潮流的。大多数开发者博客全站用几何无衬线(Inter、Geist、Space Grotesk)。我选择衬线标题基于两个相互强化的理由。

第一,字体对比比尺寸更高效地建立视觉层级。正文是 --font-sans(Inter)。衬线 H2 与无衬线 H2 同样大小,因为形式感的转换而读起来更重要——这意味着尺度层级可以保持紧凑,不需要夸张的字号差。

第二,站点追求长文可读性,不是文档密度。衬线标题唤起编辑设计感——The Atlantic、Stripe 的文字——而非 API 参考页。字体栈里的 宋体 SC华文宋体 延续了这种感觉:宋体是 CJK 排版中衬线的对应物,在中文文本里维持了同样的编辑气质。

JetBrains Mono 只用于代码块和键盘快捷键指示器,绝不用于正文或 UI 标签。正是这种排他性让它起作用——读者把等宽字体识别为"这里是代码或系统字面量"的一致信号。


渐进披露:少即是多#

搜索覆盖层#

搜索功能直到被调用才可见。没有持久搜索栏占据头部空间。按 /(或 Cmd+K)打开全屏覆盖层:聚焦的输入框、毛玻璃背景、即时结果。

1
2
3
4
5
6
7
8
.search-overlay {
  position: fixed;
  inset: 0;
  background: rgba(20, 20, 30, 0.5);
  backdrop-filter: blur(6px);
  display: none;
  padding-top: 12vh;
}

结果随打字实时出现——无提交按钮、无单独结果页。按 Escape 或点击背景关闭。交互模型借鉴 Spotlight/Alfred:呼出、输入、选择、关闭。搜索覆盖层贯穿亮色和暗色模式都无需额外样式,因为它全程引用 --paper--ink

抽屉导航#

移动端,导航从水平头部栏变为侧边抽屉。抽屉包含与桌面导航相同的链接加语言切换器,以触摸优化的布局呈现:

1
.drawer nav a { font-size: 1.08rem; padding: 12px 4px; }

12px 垂直内边距产生 44px 以上的触摸目标——Apple HIG 的最小推荐值。抽屉本身 padding: 20px 22px,确保内容绝不触及视口边缘。响应式章节描述的 visibility/clip 技术让抽屉不产生横向溢出。

向导 vs. 长表单#

AI4Marketing 的生成功能用渐进披露向导,而不是单一长表单。向导每次只呈现一个决策:选内容类型,填内容细节,选本地化目标。每步在推进前校验,错误在发生处附近被捕获,而不是提交时一次性爆出一堆错误列表。

视觉语言强化进度感:步进组件用对勾标记已完成步骤,当前步骤用 var(--accent) 高亮,未来步骤用 --ink-faint。步进组件不是纯装饰——它也是导航,允许用户跳回已完成步骤修改而不丢失后续工作。

对比原始单页长表单,这降低了表单放弃率。看到长表单时,用户先滚到底部估算总工作量再决定是否开始;向导让进入成本看起来更低,因为每次只看到当前步骤。

键盘快捷键面板#

为高级用户准备,右下角一个 36px 半透明圆形浮动按钮展开键盘快捷键参考。快捷键使用拟物按键渲染:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#shortcut-help kbd {
  background: linear-gradient(180deg, #fafaf8 0%, #ececea 100%);
  border: 1px solid #d8d6d2;
  border-bottom-color: #b7b3ad;
  border-radius: 5px;
  box-shadow:
    inset 0 -2px 0 rgba(180,176,168,.55),
    inset 0 1px 0 rgba(255,255,255,.7),
    0 1px 2px rgba(0,0,0,.06);
}

斜切边缘、底部阴影模拟厚度、悬停时微妙的按压动画。微交互奖赏发现它的用户:他们得到精美渲染的参考卡片,不是扁平文字列表。720px 以下移动端,FAB 完全隐藏——触屏用户没有键盘,这个功能暗示是无关的,不浪费视口空间。


教训:设计系统的本质是一致地说"不"#

上面描述的每个设计决策本质上都是一种约束。五种色相,不是无限的。每行一个主按钮。绝不用 emoji。衬线只在标题,不在别处。移动修复集中一个文件。这些在当下感觉限制重重。

压力永远来自创建例外。“这张卡片配第六种色相会很棒。” “这个对话框真的需要两个主操作。” “这个标题加个闪烁符号会更亲切。” 答案永远是不——不是因为单个例外会丑(它大概看着还行),而是因为每个例外都在侵蚀系统。一种额外色相变成三种。一个额外的主按钮变成别人复制的模式。一个 emoji 变成一打,博客的视觉一致性就沦为 Notion 模板的水平。

设计系统的力量不在于它能做什么——CSS 什么都能做。力量在于它阻止什么。打开新文件需要给组件写样式时,我不做设计决策。我引用 Token。决策只在一个地方做一次,然后传播到所有地方。Token 层吸收所有创意决策;下游代码是机械性的。

在生产中,这体现为速度。给新组件加暗色模式无需额外工作——它继承自语义 Token。AI4Marketing 加一种新语言只需一条数据库记录和一个提示词配置,无需重新设计 UI。让页面响应式意味着检查一个文件,不是审计整个布局。公式很简单:在约束层(Token、原则、规则)上一次性重投入,然后在每个下游决策上花近乎零的精力。能用的设计系统用起来无聊。这就是重点。


本系列下一篇:让这一切可靠上线的构建工具与部署管线——从 Hugo 亚秒级构建到 PM2 零停机重启。


本文是 产品思维 系列的第 3 篇,共 5 篇。 上一篇:第 2 篇 — 安全工程 · 下一篇:第 4 篇 — 自愈系统

本系列

产品思维 5 篇

  1. 01 产品思维(一):架构设计 — 从单体到自治 Agent
  2. 02 产品思维(二):安全工程 — 不偏执的纵深防御
  3. 03 产品思维(三):用户体验与设计系统 — Token、暗色与双语 当前
  4. 04 产品思维(四):自愈系统 — 教机器自己修自己
  5. 05 产品思维(五):抽象思维 — 从数学到系统

读有所得?

GitHub 关注我 → 新文周更

GitHub