Claude Code不是编程助手,而是可调校的协作操作系统
2026/7/15 9:26:05 网站建设 项目流程

1. 这不是聊天机器人,而是一套需要你亲手调校的协作操作系统

Claude Code 给我的第一印象,和很多人一样,是“一个特别聪明的编程助手”。但用了不到两周,我就意识到这个理解错得离谱——它根本不是 ChatBot,而是一套需要你亲自设计、调试、维护的协作操作系统。就像你不会把一辆没装刹车、没调悬挂、连轮胎气压都没检查过的赛车直接开上赛道,你也不能把 Claude Code 当成开箱即用的对话框来用。它更像一台精密的 CNC 加工中心:主轴转速、进给量、冷却液压力、刀具补偿值……每一个参数都得根据你要加工的材料(你的项目)、你要达到的精度(你的业务目标)、你手头的夹具(你的技术栈)来反复校准。我最初那几周踩的坑,几乎全是因为把它当成了“高级版 Copilot”,结果发现它在没有明确指令时,会本能地选择最省力、最顺从、最符合通用范式的路径,而不是最适合你这个具体项目的路径。

关键词里提到的“Claude3.5”、“编程软件”,恰恰是最大的认知陷阱。Claude3.5 是模型底座,是引擎;而 Claude Code 是整套传动系统、控制系统和人机交互界面。引擎再强,如果变速箱打滑、转向系统失灵、仪表盘全是乱码,车也跑不快、更跑不远。我后来在芬兰做会计事务所的项目时,彻底放弃了“用模型写代码”的想法,转而专注构建一套“让模型无法写错代码”的系统。这听起来很反直觉,但正是这种思路的转变,让我这个连console.log都要查文档的人,最终交付了一个包含 1000+ 文件、159 次数据库迁移、覆盖中英芬三语的完整会计操作系统。它不依赖模型的“顿悟”,而是依赖我设计的规则、工具和验证闭环的“确定性”。

“广告”这个词在这里,其实是个绝妙的隐喻。市面上所有关于 AI 编程工具的宣传,都在强调“它能帮你做什么”——生成代码、解释错误、写测试。但 Claude Code 的真实价值,恰恰在于它暴露了你项目里那些被长期掩盖的“广告”:那些没人敢碰、文档早已过时的配置文件;那些靠口口相传、从未写进文档的业务逻辑;那些因为“一直这么用,所以应该没问题”的技术债。当你第一次让 Claude 去修改一个核心模块时,它问出的那个看似愚蠢的问题——“这个函数名里的draft是指草稿状态,还是指只对内部用户可见?”——往往就是你整个系统里最脆弱、最模糊、最危险的那个“广告”。它逼着你把所有心照不宣的约定,全部摊在阳光下,一条条写进 CLAUDE.md,变成机器可执行、可验证的契约。这不是在增加工作量,而是在为整个项目建立一份不可篡改的“数字宪法”。所以,如果你正打算开始用 Claude Code,别急着打开编辑器,先问问自己:我的项目里,有哪些“广告”是时候该撕掉了?哪些“心照不宣”是时候该写成白纸黑字了?这才是你真正要启动的第一个任务。

2. 六层架构:为什么单点优化永远治标不治本

把 Claude Code 看作一个单点工具,是绝大多数人陷入困境的起点。它真正的力量,来自于其精巧的六层架构设计。这六层不是并列关系,而是一个环环相扣、彼此制约的反馈闭环。任何一层的缺失或失衡,都会导致整个系统失稳。我花了整整三个月,才真正吃透这个结构,并把它从理论变成了我日常工作的肌肉记忆。下面我将逐层拆解,告诉你每一层的核心作用、常见误区,以及它们之间如何相互咬合。

2.1 第一层:CLAUDE.md —— 你和 AI 之间的“数字宪法”

CLAUDE.md 不是“使用说明书”,也不是“知识库”,它是你和 Claude 之间签署的一份具有法律效力的协作契约。它的核心原则只有一条:每次会话都必须成立的事,才配写进去。这意味着,它里面不应该有“建议”、“最好”、“通常”,而只能有“必须”、“禁止”、“当……时,必须……”。我见过太多人把 CLAUDE.md 写成了一篇冗长的散文,里面堆满了各种最佳实践和美好愿望,结果 Claude 在实际执行时,把这些内容当成了背景噪音,完全无视。

一个典型的、经过实战检验的 CLAUDE.md 片段如下:

# 项目宪法:Kaku Terminal ## 核心不变量 - 所有 Rust 代码必须通过 `cargo clippy --fix` 自动修复后才能提交。 - 所有 Lua 配置文件必须以 `-- @config` 注释块开头,声明其作用域(global / user / project)。 - 任何修改 `src/config/` 下文件的操作,必须同步更新 `docs/config-reference.md`。 ## 安全红线(违反即阻断) - 禁止向 `supabase/config.toml` 写入任何内容。此文件由 `doctor` 命令统一管理。 - 禁止在 `migrations/` 目录外创建 `.sql` 文件。所有数据库变更必须通过 `db:migrate` Skill 触发。 - 禁止在 `src/` 目录下直接 `git add .`。必须使用 `git add -p` 逐块确认。 ## 术语定义(消除歧义) - “重启” = `cargo run --bin kaku -- --reload` - “重置” = `rm -rf ~/.kaku && kaku doctor --init` - “用户配置” = `~/.config/kaku/init.lua`;“项目配置” = `./.kaku/init.lua`

这段内容的价值,不在于它写了什么,而在于它没有写什么。它没有说“你应该学习 Rust 最佳实践”,没有说“建议你多写注释”,它只规定了机器在每一次操作中,必须遵守的、不可协商的底线。这就是“宪法”的力量——它不负责教你怎么做,只负责确保你做的每一步,都在安全的轨道上。我自己的 CLAUDE.md 从最初的 3 行,增长到现在的 87 行,每一条都是一个血泪教训换来的。比如那条关于supabase/config.toml的禁令,就源于一次惨痛的事故:Claude 为了“快速修复”一个连接问题,直接修改了这个文件,导致整个生产环境的数据库凭据泄露。那次之后,这条规则就被加了deny标签,任何试图写入该路径的工具调用,都会被 Hook 层直接拦截,连日志都不会留下。

2.2 第二层:Rules —— 针对特定路径的“地方法规”

如果说 CLAUDE.md 是国家宪法,那么 Rules 就是针对不同省份、不同城市的地方法规。它的存在,是为了处理那些“只在特定目录下才生效”的约束。例如,在一个 Next.js 项目中,你可能希望app/目录下的所有路由组件,都必须遵循一套严格的 React Server Components 规范,而lib/目录下的工具函数,则可以使用任意的 JavaScript 特性。这种差异化的治理,无法也不应该塞进全局的 CLAUDE.md。

Rules 的实现,通常是通过一个.rules文件夹,里面按路径存放 JSON 或 YAML 文件。一个典型的app/.rules文件可能长这样:

{ "path": "app/", "enforce": [ { "rule": "all-server-components", "description": "所有 app/ 下的 .tsx 文件必须是 'use client' 或 'use server' 明确标记的 Server Component", "check": "grep -q 'use client\\|use server' {}" }, { "rule": "no-direct-fetch", "description": "禁止在 app/ 下的组件中直接调用 fetch(),必须使用封装好的 data hooks", "check": "grep -n 'fetch(' {} | grep -v 'data-hook'" } ] }

关键在于,Rules 的触发是路径感知的。当 Claude 开始编辑app/dashboard/page.tsx时,系统会自动加载app/.rules,并将其中的约束注入到当前会话的上下文中。这比在 CLAUDE.md 里写一堆“如果路径匹配 app/,则……”要清晰、高效、且不易出错得多。我曾经尝试过把所有规则都塞进 CLAUDE.md,结果导致文件臃肿不堪,每次加载都慢得像蜗牛,而且一旦某条规则需要修改,就得通读全文,生怕误伤其他部分。分而治之,才是工程化的正道。

2.3 第三层:Skills —— 可复用的“工作流仪式”

Skills 是 Claude Code 中最具生产力的部分,它把多步、重复、易出错的手动操作,封装成一个原子化的、可复用的“仪式”。一个 Skill 不是一个简单的 Prompt,而是一个完整的、带有输入输出契约、错误处理机制和验证步骤的工作流。官方文档里说 Skills 是“按需加载的知识与工作流”,这个描述非常准确,但容易让人误解为“就是个保存的 Prompt”。实际上,一个成熟的 Skill,其复杂度堪比一个小型 CLI 工具。

以我项目中一个最常用的/implementSkill 为例,它的完整流程是:

  1. 接收自然语言需求:例如,“为用户添加一个导出 CSV 的按钮,数据来自getCustomers()API”。
  2. 自动解析与规划:Claude 会分析需求,识别出需要修改的文件(app/customers/page.tsx,lib/api/customers.ts),并生成一个初步的 Plan。
  3. 调用 Subagent 进行影响分析:派一个只读的 Subagent 去扫描整个代码库,检查getCustomers()的所有调用点、返回类型、以及相关的权限控制(RLS 策略),生成一份影响报告。
  4. 执行修改:在主线程中,根据 Plan 和影响报告,依次修改前端组件和 API 调用。
  5. 自动验证:修改完成后,立即调用vitest运行相关测试,并用tsc检查 TypeScript 类型。
  6. 生成 PRD:最后,自动生成一份简短的 PRD 文档,描述本次改动的目的、范围、影响和测试结果。

整个过程,用户只需要输入一行/implement ...,剩下的全部由 Skill 自动完成。这背后,是几十次迭代、上百次失败后沉淀下来的稳定模式。我最初写的/implement,只是一个简单的 Prompt,效果极不稳定。后来我意识到,问题不在于 Prompt 写得不够好,而在于整个流程缺乏“仪式感”——没有明确的开始、中间检查点和结束验证。于是我把每个环节都拆解出来,用 Hooks 去保证每一步的执行,用 Subagent 去隔离风险,最终才形成了今天这个坚如磐石的 Skill。它不再是一个“功能”,而是一个“承诺”:只要你调用它,它就一定会按照既定的、可验证的方式,完成这项工作。

2.4 第四层:Subagents —— 你的“影子工程师”

Subagent 是 Claude Code 中最被低估、也最强大的特性之一。很多人把它简单理解为“并行执行”,这是巨大的误解。Subagent 的核心价值,是隔离。它为你创造了一个与主会话完全独立的、干净的、受控的执行环境。你可以把它想象成你请来的一位“影子工程师”,他只听你一个人的指令,只用你指定的工具,干完活就立刻汇报,绝不把他的工作笔记、草稿、甚至他的情绪,污染到你的主工作区。

在我处理数据库迁移时,Subagent 的价值体现得淋漓尽致。一个典型的db:migrateSkill 流程是:

  • 主线程:接收用户指令,生成迁移脚本的初步草案。
  • Subagent (Explore):被派去扫描整个migrations/目录,分析历史迁移的顺序、依赖关系、以及所有已应用的变更,生成一份“迁移图谱”。
  • Subagent (Plan):基于图谱,规划本次迁移的精确步骤,包括CREATE TABLEADD COLUMNUPDATE数据填充等,并生成对应的 SQL 语句。
  • Subagent (Verify):在内存中的 SQLite 数据库里,执行这些 SQL 语句,验证其语法正确性和逻辑一致性。
  • 主线程:汇总所有 Subagent 的报告,生成最终的.sql文件,并将其提交到 Git。

整个过程中,主会话的上下文窗口里,只有清晰的指令、简洁的摘要和最终的产物。那些海量的、嘈杂的、充满不确定性的中间过程——扫描日志、SQL 解析错误、数据验证细节——全部被隔离在 Subagent 的独立空间里。这不仅极大地节省了宝贵的上下文 Token,更重要的是,它让主会话的推理过程变得无比清晰和可控。你再也不用担心 Claude 因为看到了几百行的扫描日志,而偏离了最初的设计目标。它就像一个高效的工厂流水线,每个工位(Subagent)只负责一道工序,产出标准化的半成品,最终由总装线(主线程)组装成最终产品。

2.5 第五层:Hooks —— 系统的“神经系统”

如果把整个 Claude Code 系统比作一个人体,那么 Hooks 就是它的神经系统。它不负责思考(那是模型的事),也不负责执行(那是 Tools 的事),它负责的是感知、判断和反射。它在每一次工具调用的前后,自动触发,进行实时的、确定性的干预。这是整个 Harness Engineering 的基石,也是我从“信任 AI”走向“不信任 AI”的关键转折点。

一个 Hook 的典型结构,包含三个部分:

  • Trigger:在什么事件发生时激活?(例如:on_tool_call: edit_file,on_tool_response: bash_output
  • Condition:满足什么条件才执行?(例如:file_path matches "^supabase/config.toml$",command contains "rm -rf"
  • Action:执行什么动作?(例如:deny,warn,inject_context,run_command

我项目中最关键的几个 Hooks:

  • boundary-jit:在任何edit_file工具被调用前,检查目标路径是否在allowed_paths白名单内。不在白名单?直接deny,连日志都不记录。
  • post-edit-verify:在edit_file工具成功返回后,自动调用tscvitest对修改的文件进行秒级验证。如果失败,自动触发failure-recoveryHook。
  • semantic-check:在bash_output工具返回后,对输出内容进行语义分析。例如,如果输出中包含error:failedsegmentation fault等关键词,则认为命令执行失败,并启动回滚流程。

Hooks 的威力,在于它的强制性无感性。它不需要 Claude “记住”要做什么,也不需要你在 Prompt 里一遍遍地提醒。它就像空气一样,无处不在,却又无声无息。当boundary-jit第一次成功拦截了一个对.env文件的非法写入时,我感受到的不是技术的炫酷,而是一种前所未有的安心。我知道,无论我多么疲惫、多么疏忽,这套系统都会像一个不知疲倦的哨兵,替我守住那条最重要的安全红线。这,才是真正的“缰绳”。

2.6 第六层:Plugins & MCP —— 与外部世界的“标准接口”

Plugins 和 MCP(Model Context Protocol)是 Claude Code 的“四肢”,是它与真实世界交互的物理接口。它们定义了 Claude 如何与你的本地 shell、Git、数据库、甚至是你的自定义 CLI 工具进行通信。这里最大的误区,是把它们当成“越多越好”的功能列表。事实上,一个设计不良的 Plugin,其危害远大于它的价值。它会像一个不稳定的传感器,向系统注入错误的信号,导致整个决策链路崩溃。

我早期犯过一个经典错误:为了“功能齐全”,我接入了十几个 MCP Server,涵盖了 GitHub、GitLab、Jira、Slack 等所有我能想到的平台。结果呢?每次会话启动,光是加载这些 Server 的工具定义,就占用了超过 25,000 个 Tokens(占 200K 上下文的 12.5%)。更糟糕的是,这些工具中,90% 的时间都处于闲置状态,却持续消耗着宝贵的上下文资源和计算成本。后来我彻底重构了这一层,奉行“最小必要原则”:

  • 只接入真正需要的:我的项目只用 Git 和本地 Shell,那就只接入这两个。
  • 使用 Stub 模式:对于不常用的工具,只在 CLAUDE.md 中声明一个轻量级的 stub(只有工具名和简短描述),完整的 Schema 只在 Claude 通过ToolSearch明确表示需要时,才动态加载。这完美地解决了缓存污染问题。
  • 统一抽象层:我编写了一个cli-toolPlugin,它不直接对接某个具体命令,而是提供一个通用的run_command接口。所有具体的 CLI 命令(如kaku doctor,npm run check:standard)都被封装在这个接口之下。这样,当我要更换底层实现时,只需修改cli-tool的一个函数,而无需改动任何 Skill 或 Hook。

这套分层架构,不是为了炫技,而是为了应对一个残酷的现实:AI 的不确定性,是永恒的;而工程的确定性,是我们唯一能抓住的锚点。CLAUDE.md 提供了规则的确定性,Rules 提供了路径的确定性,Skills 提供了流程的确定性,Subagents 提供了环境的确定性,Hooks 提供了行为的确定性,Plugins 提供了接口的确定性。当这六层确定性叠加在一起时,它们共同构成了一道坚固的堤坝,将 AI 那汹涌澎湃、不可预测的“智能”洪流,引导到我们预设的、安全的河道之中。这,就是 Harness Engineering 的全部意义。

3. 上下文治理:不是容量问题,而是信息信噪比问题

“上下文太短了”——这是我听到最多、也最错误的抱怨。Claude Code 的 200K 上下文,对于绝大多数项目来说,是绰绰有余的。真正卡住你的,从来不是“不够长”,而是“太吵了”。你的上下文窗口,本质上是一个信息信噪比(SNR)极低的战场。有用的信息(你的项目架构、核心约定、当前任务)被淹没在海量的、低价值的、甚至是干扰性的噪音(历史对话的碎片、工具输出的冗长日志、被压缩算法随意丢弃的中间结论)之中。治理上下文,不是在想办法塞进更多内容,而是在想方设法地提纯,把信噪比提升到一个能让 Claude 稳定、可靠、高效工作的水平。

3.1 压缩算法的真相:它不是你的朋友,而是你的对手

Claude Code 的上下文压缩算法,其设计哲学是“可重新读取优先”。这意味着,当上下文即将满载时,系统会启动一个 fork 进程,将整个对话历史喂给模型,让它生成一个摘要。而这个摘要的生成逻辑,是优先删除那些“模型认为可以随时重新读取”的内容。听起来很合理,对吧?但问题在于,模型眼中的“可重新读取”,和你眼中的“绝对不能丢”,往往是两回事。

一个典型的灾难场景是这样的:

  1. 你和 Claude 讨论了一个复杂的数据库迁移方案,花了 30 轮对话,最终敲定了migrations/001_add_customers_table.sql的具体内容,并详细讨论了为什么id字段要用UUID而不是SERIAL,以及created_at的默认值为何必须是now()
  2. 几个小时后,你需要修改这个表,添加一个新字段。你开了一个新的会话,把migrations/001_add_customers_table.sql的路径发了过去。
  3. Claude 开始工作,但它已经不记得几小时前那个长达 30 轮的、关于UUIDnow()的深度讨论了。压缩算法在上一个会话的末尾,把那段“高价值、低可读性”的架构决策,当作“可以随时重新读取的中间产物”,毫不留情地删掉了。

结果就是,Claude 在新会话中,可能会建议你用SERIAL作为主键,或者把created_at的默认值设为NULL。它不是变笨了,而是它赖以生存的“记忆”被系统自己清除了。这就像你让一个经验丰富的老工程师去修一台机器,却在他开工前,把他过去三天的所有会议记录、设计草图和决策笔记,全部烧掉了。他当然还能修,但修出来的,大概率不是你想要的那台机器。

3.2 HANDOFF.md:主动接管上下文的“交接仪式”

认识到压缩算法的不可靠性后,我放弃了所有被动等待系统“聪明”起来的幻想,转而设计了一套完全由我主导的、主动的上下文交接仪式——HANDOFF.md。它的核心思想极其朴素:不要指望系统能记住,要让你自己把最重要的东西,亲手交到下一个 Claude 实例的手里

HANDOFF.md 的结构非常简单,但它承载了整个项目最关键的“状态快照”:

# HANDOFF: [项目名称] - [日期时间] ## 当前进度 - ✅ 已完成:`migrations/001_add_customers_table.sql` 已创建并验证。 - ⏳ 进行中:正在设计 `customers` 表的 RLS 策略,以支持多租户隔离。 - ❌ 已放弃:方案 A(基于 `tenant_id` 列)因性能问题被否决。 ## 关键决策与理由 - **主键类型**:`UUID`。理由:避免分布式环境下 ID 冲突,且便于客户端生成。 - **created_at 默认值**:`now()`。理由:确保时间戳由数据库服务器统一生成,避免客户端时钟不一致。 - **RLS 策略**:采用 `USING (auth.uid() = tenant_id)`。理由:最简洁,且能被 Supabase 的查询优化器有效利用。 ## 下一步行动 - [ ] 编写 `rls/001_customers_policy.sql`。 - [ ] 为 `customers` 表创建 3 个负面测试用例(确保租户 A 无法看到租户 B 的数据)。 - [ ] 运行 `supabase db reset` 并验证策略有效性。

这个文件的生成,是我每个会话结束前的固定仪式。我会明确告诉 Claude:“请为当前会话生成一份 HANDOFF.md,总结以上几点。” 它会认真地、一丝不苟地完成这项任务。然后,我会快速扫一眼,如果发现遗漏或错误,就直接让它补充或修正。最后,我关闭这个会话,开启一个全新的会话,并把HANDOFF.md的路径作为第一条消息发过去。

这个看似简单的动作,带来了质的飞跃。它把上下文管理的权力,从不可控的、黑盒的压缩算法,转移到了完全可控的、白盒的、由我定义的文件上。HANDOFF.md里写的每一个字,都是我精心挑选、反复确认过的“黄金信息”。它没有废话,没有冗余,只有最纯粹、最核心的项目状态。Claude 在新会话中读到的,不再是被算法蹂躏过的残缺摘要,而是我亲手递过去的、完整、清晰、权威的“项目护照”。这从根本上解决了上下文漂移的问题,让跨会话的协作,变得像同一个大脑在连续思考一样流畅。

3.3 Plan Mode:把“探索”和“执行”物理隔离

Plan Mode 是另一个被严重低估的、用于治理上下文的利器。它的核心价值,不在于“计划”本身,而在于它提供了一种物理隔离的机制,将高噪音、高不确定性的“探索阶段”,与高确定性、高价值的“执行阶段”,彻底分开。

在没有 Plan Mode 时,Claude 的工作流是混沌的:

  • 你提出一个需求:“重构用户认证模块,使其支持 OAuth2 和 Email/Password 双模式。”
  • Claude 开始工作,它可能会先去src/auth/目录下扫描所有文件,生成一份长长的文件列表(噪音1)。
  • 然后它开始阅读每个文件,分析现有逻辑,这个过程会产生大量中间结论和假设(噪音2)。
  • 接着它开始构思新架构,画出类图、流程图,这些草稿充满了不确定性(噪音3)。
  • 最后,它才开始动手写代码。但此时,它的上下文里,已经塞满了前面所有的噪音,它的决策,不可避免地会受到这些噪音的干扰。

Plan Mode 强制性地改变了这个流程:

  1. Enter Plan Mode:你输入/plan,Claude 进入一个只读的、探索性的会话。它被严格限制只能使用read_filelist_filessearch_code等只读工具。它不能修改任何一行代码,不能运行任何命令。它的唯一任务,是搞清楚“现状是什么”和“可能的方案有哪些”。
  2. 生成 Plan:Claude 输出一份结构化的 Plan,包含:现状分析、方案对比(A/B/C)、每种方案的优缺点、推荐方案及理由、详细的执行步骤清单。
  3. Exit Plan Mode:你审阅这份 Plan。如果满意,你输入/execute,Claude 会开启一个全新的、干净的会话,并将 Plan 作为唯一的上下文,开始执行。

这个过程的精妙之处在于,它把所有高噪音的探索活动,都限制在一个独立的、可丢弃的会话里。执行会话的上下文,干净得像一张白纸,上面只写着一份经过深思熟虑、达成共识的作战地图。这不仅极大地提升了执行的准确率,更重要的是,它让“探索”本身变成了一项可审计、可复盘、可改进的工作。你可以把每一次 Plan 的输出,都存档下来,形成一份宝贵的“项目决策日志”。半年后,当你再回看当初为什么选择了方案 B 而不是方案 C 时,那份 Plan 就是最好的答案。这,就是专业工程实践与业余爱好者的根本区别。

4. 实操心法:从“写代码”到“建系统”的思维跃迁

使用 Claude Code 的半年,对我而言,是一场彻底的认知革命。它把我从一个“如何写出正确代码”的思考者,重塑为一个“如何构建一个让代码必然正确的系统”的架构师。这个转变,不是一蹴而就的,而是由无数个微小的、痛苦的、顿悟的瞬间堆砌而成。下面分享几个最核心、也最实用的实操心法,它们不是技巧,而是思维方式的切换。

4.1 “验证标准”先行:一个任务,必须先定义“什么才算做完”

这是我学到的最重要、也最颠覆的一课。在传统开发中,我们习惯于先定义“做什么”,再定义“怎么做”。但在 AI 协作中,这个顺序必须颠倒过来。在你向 Claude 提出任何任务之前,你必须先和它,以及和你自己,共同定义清楚:什么状态,才意味着这个任务“真正完成了”?

这个“完成标准”,必须是可观测、可验证、无歧义的。它不能是“看起来不错”、“应该可以了”、“我觉得差不多了”这种主观感受。它必须是像下面这样,可以用机器或人眼直接判定的客观事实:

  • 完成标准npm run check:standard命令返回0,且git status显示工作区干净。
  • 无效标准:“代码写好了”、“功能实现了”、“页面能打开了”。

我曾经让 Claude 去“优化一个缓慢的数据库查询”。它花了两个小时,修改了十几处 SQL,最终告诉我“完成了”。我运行了一下,查询时间从 2.3 秒降到了 1.8 秒。我问它:“你说的‘优化’,是指降到 1 秒以内吗?” 它沉默了。那一刻我明白了,我没有给它一个“靶心”,它只是在漫无目的地射箭。后来,我重新定义了任务:“请将get_user_orders查询的执行时间,从当前的 2.3 秒,优化到 0.8 秒以内。完成后,请运行EXPLAIN ANALYZE并截图,证明时间确实达标。” 结果,它在 15 分钟内就找到了一个索引优化方案,将时间降到了 0.3 秒。

这个心法的本质,是把“结果导向”变成了“标准导向”。你不是在指挥一个工人干活,而是在设定一个 KPI。Claude 的强大,恰恰在于它能穷尽一切手段,去达成你设定的那个冰冷、坚硬、不容置疑的标准。你给它的标准越清晰,它达成的速度就越快,质量就越高。所以,下次开口前,请先问自己:如果我不懂代码,我该如何用一句话,向一个完全不懂技术的人,解释清楚“这件事做完”是什么样子?

4.2 “Harness”思维:不追求“更聪明”,而追求“更确定”

“Harness”这个词,在英文里是“挽具”、“缰绳”的意思。它精准地概括了我在芬兰项目中摸索出的核心方法论。Harness Engineering 的终极目标,不是让 Claude 变得更聪明(它已经足够聪明了),而是构建一套“缰绳系统”,让它在任何情况下,都无法脱离你设定的安全轨道。

这套系统的构建,遵循三个铁律:

  1. Deny > Warn:对于任何可能危及系统安全、数据完整或业务连续性的操作,必须使用deny(阻断),而不是warn(警告)。AI 不会“记住”一个警告,但它无法绕过一个阻断。我项目中所有关于.envsupabase/config.tomlmigrations/目录的保护,全部是deny。这看起来很“粗暴”,但正是这种粗暴,构筑了最坚实的信任基础。
  2. 事故驱动:每一条规则、每一个 Hook、每一个 Skill,都应该能追溯到一个真实的、让你夜不能寐的事故。那条关于RLS策略中列名引用的验证规则,就源于一次差点导致客户数据泄露的线上事故。规则不是凭空设计的,而是从血泪中长出来的。因此,我有一个error-journal.md,它自动记录每一次失败、每一次阻断、每一次警告。当某条警告规则被触发超过 10 次,系统就会自动建议我将其升级为deny规则。这是一个自我进化、自我强化的闭环。
  3. 人在回路的位置要对:你不需要审查每一行代码(你也看不懂),但你必须审批每一个战略决策。例如:“要不要加这张新表?”、“这个功能,是用 Server Component 还是 Client Component 实现?”、“这次数据库迁移,是否需要停机?” 这些问题的答案,决定了整个项目的成败。而具体的战术执行——“怎么写这个 SQL”、“怎么写这个 React 组件”——则完全交给 AI。这是一种职责的物理隔离,就像一家公司里,CEO 决定战略方向,而工程师负责具体实现。

Harness 思维,是一种深刻的谦卑。它承认人类的局限性(我确实看不懂代码),但也坚信人类的智慧(我懂得如何设计一个系统来弥补这个局限)。它不试图去对抗 AI 的不确定性,而是用工程的确定性,去拥抱、引导、约束它。这,才是普通人驾驭超级智能的唯一可行之道。

4.3 “渐进式披露”:给 AI 知识,而不是信息

“Progressive disclosure”(渐进式披露)是 Claude Code 团队内部反复强调的设计哲学,它深刻地影响了我对知识管理的理解。我们过去习惯于把所有可能用到的知识,一股脑儿地塞进 Prompt 或 CLAUDE.md,以为“给得越多,AI 就越懂”。但事实恰恰相反。信息过载会让 AI 的注意力涣散,导致它抓不住重点,甚至产生幻觉。

渐进式披露的核心,是先给索引,再给详情。它模仿了人类专家的学习和工作方式:一个资深律师,不会在接到案子的第一分钟,就把整部《民法典》背给你听。他会先告诉你:“这个案子,主要涉及《合同编》第 500 条到第 520 条,以及最高法的一个司法解释。” 然后,当你需要了解具体条款时,他才会翻开书,逐条为你讲解。

在 Claude Code 中,这表现为:

  • CLAUDE.md 中只放“索引”:例如,“所有数据库表结构,详见/tmp/db-schema.json”;“所有 UI 设计规范,详见docs/ui-guidelines.md”。
  • Skill 中定义“拉取”逻辑:当 Skill 需要访问数据库结构时,它会自动调用read_file工具,去读取/tmp/db-schema.json。这个动作,是按需发生的,只在真正需要时才加载。
  • Subagent 承担“发现”工作:当需要了解一个陌生模块时,我会派一个ExploreSubagent 去扫描,它会生成一份精炼的“模块概览”,而不是把整个模块的源码都 dump 出来。

我项目中的patterns-cache.json就是这一思想的完美体现。它不是一个庞大的规则库,而是一个只有 22 条 regex 的、高度凝练的“问题模式索引”。每一条规则,都对应一个曾经真实发生过的、代价高昂的 Bug。当 Claude 在编辑代码时,系统会根据文件类型,自动从这个索引中筛选出最相关的几条规则,并将它们注入上下文。它不会看到全部 22 条,只会看到此刻最需要的 3-5 条。这种“少即是多”的精准供给,让 Claude 的推理,始终聚焦在最关键的问题上,效率和准确性都得到了质的提升。

5. 常见问题与避坑指南:那些没人告诉你的“血泪教训”

在过去的半年里,我踩过的坑,可能比很多团队一年踩的都多。这些坑,有些源于对 Claude Code 机制的误解,有些源于对自身项目复杂度的低估,还有一些,则纯粹是人性的弱点——比如急于求成、害怕麻烦、或者过度自信。下面,我将这些最典型、最痛的教训,整理成一份“避坑指南”,希望能帮你绕开那些我曾深陷其中的泥潭。

5.1 问题:Claude 总是“顺从”,我说什么它就做什么,哪怕我说错了

现象:你提出一个明显有缺陷的方案,比如“把所有密码明文存储在数据库里”,Claude 不会质疑,而是立刻开始写代码,实现这个方案。

根源:这不是 Claude 的“缺陷

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询