AI

Hello Vibe Coding

这个博客最初只是一个朴素的愿望:我想有一块真正属于自己的地方,记录正在做的项目、刚踩过的坑,以及那些还没想明白的问题。

它没有从完整的设计稿开始。我一边描述想要的感觉,一边与 Coding Agent 交互:看页面、改代码、淘汰不合适的尝试。首页的双栏、文章列表、深浅色主题、双语界面和打字动画,都是在这种高频迭代中慢慢演化出来的。

这很像现在常说的 Vibe Coding:先用自然语言表达意图,让 Agent 快速实现,再通过真实反馈持续收敛。但如果只有“感觉”,项目很快就会沦为一团能运行、却难以维护的代码。真正让这套方式可靠的,是把感觉放在前面,把架构分层Harness 校验手段接在后面。

我的 Harness 循环闭环

表达意图 → 架构边界约束 → 最小范围修改 → 静态检查 & Check 审查 → 视觉与 DOM 断言 → 证据驱动收敛

架构设计与职责分离

这个博客以 VitePress 为核心引擎。VitePress 将 Markdown 编译为静态页面,并支持在 Markdown 中嵌入 Vue 动态组件。我们通过清晰的分层解耦,让内容维护与主题表现完全分离。

技术层级架构中的职责分工
VitePress文件路由、静态站点生成、Markdown 解析与代码高亮
Vue 3 & TS自定义 Layout 表现层、动态页面组件与类型系统约束
Tailwind CSS 4基于 Vite 插件接入,统一管理响应式布局与设计 Token
Content Loader编译期抽取 Markdown Frontmatter 统一构建单向数据源
Playwright作为视觉与交互 Harness,在真实浏览器提供 E2E 校验断言

单向数据流与表现解耦

文章列表不维护任何额外的 JSON 或数据库。我们利用 VitePress 的 createContentLoader 建立单一数据源机制,在编译期对 Markdown Frontmatter 进行提取、分类与格式化:

ts
// 编译期单一数据源 Loader:提取 Markdown 元数据并转换为类型安全的数据流
export default createContentLoader("blog/**/*.md", {
  transform(pages: PageData[]): Post[] {
    return pages
      .map(({ frontmatter, url }) => ({
        url,
        title: frontmatter.title,
        date: formatArticleDate(frontmatter.date),
        kind: url.startsWith("/blog/AI/") ? "AI" : "articles",
        tags: frontmatter.tags || [],
      }))
      .filter((post) => post.title)
      .sort((a, b) => b.date.localeCompare(a.date));
  },
});

Vue 模板专注于交互与样式,全局 style.css 则收拢解析后的静态 HTML 表现。组件样式与文章渲染互不干扰。

目录分层架构

删掉依赖与构建产物后,清晰的目录分层确保 Agent 能精准定位修改点,避免在整个仓库盲目碰撞:

text
.
├── .vitepress/
│   ├── config.ts                 # 站点、Markdown 解析与 Vite 插件配置
│   ├── data/                     # 数据层:编译期文章索引 Loader
│   ├── utils/                    # 工具函数:日期格式化、i18n 等
│   └── theme/                    # 表现层:视图、组合式 Hook 与样式
│       ├── index.ts              # 主题注册入口
│       ├── Layout.vue            # 外壳布局与主题切换
│       ├── hooks/                # 组合式状态逻辑 (useThemeToggle, useLocaleSync)
│       └── components/           # 页面组件与原子 UI 组件
├── blog/                         # 内容层:纯 Markdown 文章库
├── pages/                        # 路由层:单页面入口 md
└── scripts/                      # 部署与环境构建脚本

明确两条核心分界:

  1. blog/ 只存纯内容,.vitepress/theme/ 负责所有视觉呈现与交互逻辑;
  2. pages/ 处理路由组合,components/ 保持低耦合的原子化组件划分。

Harness 质量守卫手段

AI 编码代理极擅长生成代码,但如果不加以护栏约束,容易引发隐式 Bug 或架构腐化。通过引入三层 Harness 机制,我们把工程校验转化为固定闭环。

1. 规则契约 Harness (AGENTS.md)

提示词适合描述单次需求,而项目级的架构契约必须固化在规则文档中(如 AGENTS.md)。这是 Agent 进入仓库后的第一行为守卫。

md
- 开发时优先使用本地开发服务地址测试,避免不必要的全量重新构建
- 使用 Tailwind CSS 时优先采用主题刻度工具类,维持设计 Token 一致性
- 视觉与 DOM 检查需遵循按需触发原则,测试完成后清理临时残留文件
- 不得未经明确授权执行任何修改 Git 暂存区或仓库状态的操作

规则的有效性取决于其是否具备明确的操作断言。清晰的契约规则可以防止 Agent 跨越项目架构边界。

2. 代码 review Harness (Check Skill)

代码写完并不代表任务完成。在修改结束后引入独立的 Check 审查环节,让模型离开“生成上下文”,按质量清单进行二次审计:

  • 类型健全度:检查是否有 any 类型逃逸或未定义的隐式强转;
  • 状态与清理:验证 Vue 组件的生命周期、事件监听与定时器是否完整卸载;
  • 架构一致性:检查是否打破了内容与视图分离的原则、是否存在冗余抽象;
  • 体验边界:无障碍支持 (a11y)、响应式断点与减少动画偏好 (reduced motion)。

审查的目标不是输出报告,而是强力收敛可能引发缺陷的隐患代码。

3. 端到端校验 Harness (Playwright & DOM Assertions)

视觉与交互改动不能止步于“看懂了源码”。Tailwind 类名看起来合理,但在浏览器中依然可能遭遇文本溢出、深色模式对比度不足或视口抖动。

在开发过程中,我们将真实浏览器交互接入测试 Harness 链路:

js
// 通过视口缩放、DOM 检查与 Snapshot 进行定量断言
await page.setViewportSize({ width: 390, height: 844 });
const isOverflowing = await page.evaluate(
  () =>
    document.documentElement.scrollWidth > document.documentElement.clientWidth,
);
console.assert(!isOverflowing, "移动端视口存在横向溢出");

通过“桌面/移动端视口适配”、“深浅色主题对比度”、“溢出计算与悬停位移”四项指标的定量校验,将视觉验证从主观感觉转化为确定性的测试结果。

总结

Vibe Coding 不是把工程判断全部交给 AI,也不是用一句话生成项目后就放弃代码把控。它是一种高频协作范式:

用 Vibe 快速探索方向,用架构解耦降低复杂度,用 Harness 工具守护工程质量。

只要这条反馈闭环保持运转,开发的高效率就不会牺牲系统的严谨性,Vibe Coding 也能在可控的工程轨道上稳定向前。