本文记录了一次真实的 AI 辅助重构:一个最初只有 JSON 格式化单页的 Next.js 项目,如何在 Claude 与 Harness Engineering 思想的帮助下,演变成拥有 80+ 在线工具、双语支持、自动化 SEO 和可持续架构的工具箱。更重要的是,这个过程展示了工程规则如何逐步替代开发者记忆。
起点:一个典型的“人肉驱动”项目
改造前,项目只有一个 /json-format 页面。UI 状态、JSON 解析、格式化算法、错误处理和树形展示全部耦合在同一个页面组件中。
app/
page.tsx
json-format/
page.tsx
components/
Header.tsx
Footer.tsx如果要增加第二个工具,例如 JSON 对比,就需要复制页面、手动增加首页卡片、补导航链接、更新面包屑、编辑 sitemap,再单独配置 SEO。
每增加一个功能,都要靠人记住需要修改哪些文件、修改多少处。这是典型的认知债务:架构依赖开发者的记忆,而不是代码自身的约束。国际化和 SEO 同样需要反复手工同步。项目能运行,却明显无法稳定扩展。
什么是 Harness Engineering
围绕 AI 建立一层控制与验证系统,让软件开发变得稳定、可重复、可检查。
Harness 不是 AI 本身,而是连接开发者、AI、代码库与开发工具的工程基础设施。它持续提供上下文、调用工具、执行代码、验证输出、修复错误并把质量门槛固化到工作流里。
| Prompt Engineering | Harness Engineering |
|---|---|
| 优化一次输入 | 设计完整的 AI 工作流 |
| 追求更好的提示词 | 追求更可靠的系统 |
| 一次性生成 | 多步骤执行与反馈 |
| AI 输出是终点 | AI 输出是验证的起点 |
| 依赖人工检查 | 自动化验证 |
它不是某个单一设计模式,而是一种架构哲学:让项目在约束下增长,不依赖个人纪律。凡是重复、容易遗漏或纯机械的工作,都应该被自动化。
Claude 对项目做了哪些改造
1. 建立注册中心:单一事实来源
第一步是建立 lib/tools/registry.ts,让它成为所有工具元数据的唯一真相来源。
export const toolRegistry: ToolMeta[] = [
{
id: 'json-format',
name: 'JSON 格式化',
path: '/json-format',
icon: '{}',
category: 'format',
featured: true,
},
// 新增工具只需在这里追加
];从这一刻起,首页工具卡片、分类分组、导航、面包屑、推荐工具、sitemap 和 SEO metadata 都从 registry 自动派生。新增工具只注册一次,其余入口自动更新。
这次还需要改哪些文件?
这个过去每次扩展都会出现的问题,被架构本身消除了。
2. 引入统一的 ToolLayout
过去每个页面都要重复维护标题、描述、面包屑、JSON-LD、SEO metadata 和响应式布局。改造后,工具页统一使用 ToolLayout:
export default function JsonFormatPage() {
return (
<ToolLayout toolId="json-format">
<JsonFormatClient />
</ToolLayout>
);
}ToolLayout 负责所有跨页面的共同结构,具体工具只需要实现自己的交互。页面骨架不再随着工具数量增长而复制。
3. 强制分层,把业务逻辑变成纯函数
Claude 将项目整理为职责清晰的分层结构:
lib/utils/ ← 纯函数层(零副作用,禁止 import React)
lib/tools/ ← 工具元数据与跨切面逻辑
components/ui/ ← 无业务逻辑的原子组件
components/ ← ToolLayout 等复合组件
app/[locale]/ ← 只负责状态、事件和渲染的页面层页面只管理 state、事件和渲染;复杂解析与转换逻辑进入 lib/utils;组件专注展示;工具元数据和 SEO 跨切面能力集中在 lib/tools。
以 JSON 格式化为例,逻辑被提取成纯函数,页面只消费返回结果。这样可以独立测试,不依赖 React 或 DOM,也能复用于 CLI 和 Worker。业务逻辑因此脱离了具体框架。
4. 用语义设计 Token 替代原始颜色
原先组件直接使用 text-gray-500、bg-gray-100 等原始 Tailwind 颜色类。修改品牌色需要全局搜索替换,深色模式也难以维护。
:root {
--surface: #f9fafb;
--content-muted: #6b7280;
--action: #1f2937;
}
@media (prefers-color-scheme: dark) {
:root {
--surface: #111827;
--content-muted: #9ca3af;
}
}
@theme inline {
--color-surface: var(--surface);
--color-content-muted: var(--content-muted);
}现在组件只表达语义,例如 bg-surface、text-content-muted、border-border-input,而不关心最终颜色值。深色模式、品牌调整和主题扩展都只需要修改第一层变量。
5. 把 SEO 工程化,而不是手工维护
SEO 同样属于容易遗漏的重复工作。改造后,lib/tools/seo.ts 成为 metadata、canonical、hreflang、Open Graph 和 JSON-LD 的统一生成入口。
export function createToolMetadata(toolId: ToolMessageId, locale: string): Metadata {
const messages = getLocaleMessages(locale);
const tool = messages.tools[toolId];
// title、description、Open Graph、canonical 与 hreflang 统一生成
}sitemap.xml、robots.txt、llms.txt 与 llms-full.txt 也从 registry 和博客文章注册表生成。新增工具或文章后,发现入口随构建自动更新,不需要再复制一套 SEO 配置。
6. 把响应式体验沉淀为约定
- 编辑器自动填满剩余空间
- 双栏布局在宽屏并排、窄屏堆叠
- 避免固定 40vh 之类的死高度
- 移动端不溢出、不遮挡
- 所有工具保持一致的间距与信息密度
单看每一条都很小,但当工具数量达到几十个时,一致性本身就是产品能力。
7. 把经验写进 AGENTS.md 与 CLAUDE.md
AGENTS.md
CLAUDE.md这些文档明确项目架构、开发流程、命名约定、新增工具的步骤,以及 AI 编码时必须遵守的边界。最有价值的资产不只是一份当前可运行的代码,更是能持续指导后续演进的规则。
最终形成的 Harness Engineering 规则
规则一:单一事实来源
所有工具定义只存在于 lib/tools/registry.ts。会被多个地方使用的信息不得复制配置。
规则二:所有发现入口都由 Registry 驱动
首页、分类、推荐、面包屑、sitemap、JSON-LD 与 AI 检索文档必须自动生成,不允许手动同步。
规则三:新增工具有固定流程
registry.ts 注册工具
→ messages/zh.json 与 messages/en.json 补充文案
→ lib/utils/ 实现纯函数逻辑
→ app/[locale]/<id>/page.tsx 实现交互
→ app/[locale]/<id>/layout.tsx 接入统一 metadata如果增加工具还需要第六个手工同步的发现步骤,就应该继续改造 Harness,把它收回到框架里。
规则四:保持页面薄化
页面只包含 state、事件和渲染,不能把 JSON 解析、格式转换、Schema 校验、Diff 算法或文件处理直接写进页面。
规则五:优先使用纯函数
lib/utils 中的逻辑不依赖 React、不依赖 DOM、没有副作用,也不把未处理异常直接抛给页面。输入与输出必须清晰、可测试。
规则六:所有工具使用统一布局
每个工具页都通过 ToolLayout 获得面包屑、标题、描述、分类、结构化数据和页面宽度。统一性成为默认结果。
规则七:SEO 必须自动生成
新工具自动获得 metadata、canonical、hreflang、Open Graph、JSON-LD、sitemap 与 llms 文档入口。SEO 是框架层,不是功能层的补丁。
规则八:只使用语义 Token
避免:
text-gray-500
bg-red-100
推荐:
text-content-muted
bg-surface组件表达用途,主题系统决定颜色。这样主题与组件可以独立演进。
规则九:404 也属于系统
404 页面同样支持中英文、返回真实 HTTP 404,并从 registry 推荐常用工具,不能成为孤立例外。
规则十:验证是开发的一部分
npm run lint
npx tsc --noEmit
npm run build结构性改动必须经过 lint、TypeScript 与生产构建,再用真实浏览器检查页面、交互、控制台、错误路径和 SEO 标签。
最终架构一览
lib/tools/registry.ts
│
├─► 首页工具卡片
├─► 分类与面包屑
├─► SEO metadata 与 JSON-LD
├─► Sitemap
├─► 404 推荐工具
└─► llms.txt / llms-full.txt
lib/utils/*.ts ← 可独立测试的纯函数工具库
components/ToolLayout.tsx ← 统一工具页骨架
messages/*.json ← 双语文案
app/globals.css ← 双层语义主题 token这套结构把重复的发现逻辑、页面骨架、主题规则与验证门槛全部收进 Harness。开发者与 AI 都只需要在明确的扩展点工作。
为什么 Harness Engineering 特别适合 AI 协作
AI 生成代码的常见风险是遗漏分散在项目各处的同步修改。传统架构增加一个工具可能要改八处,AI 只完成五处,剩下三处就会变成难以察觉的“幽灵 bug”。
在 Harness 架构下,扩展点数量固定,而且每一步都有可复用的模式。其余变化由框架自动派生,遗漏会更容易转化为编译错误、类型错误或验证失败,而不是上线后的运行时问题。
把正确的架构决策编码进框架约束,让正确的做法成为最省力的做法。
改造结果
项目从一个 JSON 格式化页面扩展为拥有 80+ 在线工具的双语工具箱。增加新工具从一组分散的人工操作,变成了稳定、可重复、可验证的工作流。
- 维护成本不再随工具数量线性增长
- SEO 与 AI 检索入口自动继承
- 导航与分类自动更新
- 国际化按固定契约扩展
- 业务逻辑保持可复用与可测试
- AI 遵循项目规则,而不是每次重新猜测结构
结语
Harness Engineering 不是为了让架构看起来更漂亮,而是为了让项目在持续增长时仍然保持一致、可维护和可扩展。
先铺好轨道,再让新功能沿着轨道生长。
轨道建立后,开发者不必再记住所有同步文件,不必担心漏掉 SEO,也不必追逐页面之间的样式偏差。让系统记住重复工作,把人的注意力留给真正需要判断的问题。