Karpathy 的四条黄金法则:当 AI 开始「过度设计」时,如何用 CLAUDE.md 拯救代码质量
- 作者:Bougie
- 创建于:2026-06-13
- 更新于:2026-06-13

凌晨两点,我盯着屏幕,陷入了一种诡异的沮丧。
我让 Claude Code 帮我写一个日志解析工具,需求很简单——从 nginx 日志里提取 IP 地址和请求路径,输出一个 CSV。Claude 很乐意地接受了任务,五分钟后,我得到了一个模块化的、抽象的、支持插件的、可配置的日志处理框架。它有接口抽象、策略模式、三种输出格式的适配器,还有一个用 decorator 实现的中间件管道。
我只需要解析两列文本。
这个框架有 23 个文件。
更糟糕的是,当我试图运行它时,因为某个抽象层的类型不兼容,程序崩溃了。我花了半小时去理解这个框架的结构,然后花了二十分钟删掉了其中 80% 的代码,最后用 15 行 Python 完成了最初的需求。
这不是 Claude 的问题。这是我的问题——我没有告诉它我想要什么。
或者说,我以为我告诉了它,但它其实根本没有听懂。
# 一个 GitHub 仓库与一个老问题
2024 年末,Andrej Karpathy 在 GitHub 上传了一个名为 andrej-karpathy-skills 的仓库,目前已经斩获了 149K+ stars。这个仓库的 README 非常简短,但其中的内容——一份 CLAUDE.md 模板文件——却在 AI 编程社区引发了广泛讨论。
对于不熟悉 Andrej Karpathy 的读者,这里做一个简要介绍:他是斯坦福大学 CS231n 课程的创始人之一,曾担任 OpenAI 的创始成员和 Tesla AI 部门的高级总监,负责 Autopilot 的视觉感知系统。现在,他全职运营 YouTube 频道,专注于 AI 教育和内容创作。
简单来说,这个人不是一个理论家,而是一个从实验室走向生产线的人。他的建议不是书斋里的空谈,而是工业级 AI 系统开发的经验沉淀。
Karpathy 在这个仓库里提供了一份简短的 CLAUDE.md 模板,其中核心内容就是四条编码原则。这份文件没有华丽的排版,没有引用学术论文,没有任何「提示词工程」的繁复技巧——它只有四条直白的规则。
但正是这四条规则,击中了我在日常 AI 编程中反复遇到的核心痛点。
# LLM 编码的四大陷阱:Karpathy 为什么要写这四条原则
在我深入分析这四条原则之前,我想先谈一个根本问题:为什么我们需要这些原则?
使用 LLM 进行编程辅助已经成为了无数开发者的日常。根据我的观察和自我反省,当我们让 LLM 帮助写代码时,主要会遇到四类典型问题:
第一类:猜测式编码(Guesswork Coding)
LLM 遇到需求不明确时,不会说「我不确定这里该怎么处理」,而是会直接选择一个看起来合理的方向继续前进。它不会暴露歧义,不会询问用户偏好,不会展示权衡过程。在 Karpathy 的语境里,这就是「先编码,后思考」——代码先行,思考滞后。
第二类:过度工程(Over-Engineering)
这正是我在文章开头遇到的场景。LLM 倾向于「做得更多」而非「做得刚好」——它会创建抽象层来应对「将来可能的需求」,编写插件系统来支持「将来可能扩展的功能」,添加配置选项来处理「将来可能不同的场景」。结果是,一个简单需求被包裹在一层又一层的设计模式中。
第三类:编辑污染(Edit Pollution)
当我们让 LLM 修改现有代码时,它常常会对「附近但无关」的代码进行「改进」——调整格式、更新注释、优化变量名、甚至重构相邻的逻辑。这看起来是出于好意,但会让代码变更的 diff 变得不可控,增加了 code review 的难度,也增加了引入新 bug 的风险。
第四类:目标模糊(Goal Ambiguity)
这是最隐蔽的一类问题。我们通常以命令式的语言给出指令——「添加验证」「修复错误」「优化性能」——但这些指令没有给出可验证的目标状态。LLM 收到这样的指令后,会在黑暗中摸索,而它的「努力」可能与我们的真实意图南辕北辙。
这四类问题——猜测式编码、过度工程、编辑污染、目标模糊——正是 Karpathy 四条原则要直击的核心。
# 原则一:Think Before Coding——先思考,后编码
不要假设。不要隐藏困惑。要呈现权衡取舍。不确定时主动提问。不要默默选择一种解释。
这条原则听起来像是对人类程序员的建议,但它对 LLM 的指导意义同样深刻——甚至可以说更加深刻。
# LLM 为什么倾向于「先编码后思考」
人类程序员在接到一个模糊需求时,通常会有意识地停下来思考:「这里有歧义」「这个边界条件我没考虑」「我需要和需求方确认一下」。但 LLM 在生成模式下,会倾向于「流畅地」完成整个任务——它会利用训练数据中见过的相似模式来填补空白,让代码看起来完整、连贯。
问题在于,这种「流畅」可能掩盖了深层的理解缺失。
举个例子。我曾经让 Claude 帮我写一个函数,用于计算一组用户的平均活跃时长。我的需求描述中提到了「活跃时长」,但没有定义什么是「活跃」。Claude 直接假设「活跃时长」等于「用户在线时间」,于是写了一个基于 session 的计算逻辑。
而实际上,我们的业务定义是「活跃时长 = 有效操作时间(排除空闲超过 5 分钟的时段)」。
Claude 没有问。它直接假设了。它生成了看起来完全合理、功能完整的代码。如果我没有仔细 review,这个 bug 就会进入生产环境。
# 反例:沉默的假设
# 需求:写一个函数计算购物车总价
# 反例:Claude 在假设中完成编码
def calculate_cart_total(cart):
"""Calculate total price of cart items."""
total = 0
for item in cart:
# 假设 item 有 'price' 字段,假设 price 是数值
total += item['price']
return total
# 问题:
# 1. 没有考虑 discount 字段的存在(实际业务中 discount 是必需的)
# 2. 没有考虑 currency 字段(可能导致不同货币直接相加)
# 3. 没有处理 None/缺失值(实际数据中很常见)
# 4. 没有验证 cart 的类型(可能传入 None 或非 list)
在这个例子里,Claude 没有问任何一个问题就完成了编码。它做了一个「合理」的假设,但这个假设可能完全不符合实际业务场景。
# 正例:暴露困惑,主动澄清
# CLAUDE.md 中添加的原则触发词
## 当你遇到以下情况时,必须停下来提问,不要继续编码:
1. 需求中存在技术术语但未定义具体含义
2. 数据结构/类型未明确指定
3. 边界条件未说明(如空输入、异常输入、极限值)
4. 存在多种合理的实现路径但未指明偏好
5. 引用了外部系统/API 但未提供接口规范
## 提问模板
当你需要澄清时,请使用以下格式:
我注意到 [具体歧义点] 可能导致不同的实现方式:
方案 A:[描述 + 适用场景]
方案 B:[描述 + 适用场景]
默认选择:[如果你必须选一个,描述你的选择和原因]
你倾向于哪种方案?
这样做的价值在于:它把「沉默的错误假设」变成了「公开的设计决策」,让人类有机会在编码之前纠正方向。
# 我的真实经验
我在使用 Claude Code 做一个内部工具时,遇到了一个典型场景:我需要实现一个数据导出功能。Claude 在开始编码之前,主动发了这样一条消息:
我注意到需求中提到'导出'但没有说明格式。当前项目中有两处导出逻辑——一个是 CSV,一个是 Excel。我应该遵循哪种模式?另外,导出内容的字段是否需要用户选择,还是导出所有字段?
这正是 Think Before Coding 的完美体现。如果没有这个「暂停」,Claude 可能会基于训练数据中的常见模式选择一个格式,结果可能与现有代码的风格不一致,或者遗漏了我们需要的字段选择功能。
而有了这个暂停,我只需要回复两句话,整个方向就被纠正了。这比事后发现「导出格式不对」然后返工要高效得多。
# 原则二:Simplicity First——简单优先,不做预言家
用最少的代码解决问题。避免投机性功能(不要为「将来可能用到」写代码)。不为单次使用的代码创建抽象。
这条原则是四原则中我认为对我影响最大的。它不仅仅是一种编码风格,更是一种关于「未来」的哲学立场。
# 为什么 LLM 如此热衷于过度设计
这里有一个有趣的认知现象:当我们(无论是人类还是 AI)被要求「写一段代码」时,脑子里会自动激活一套「好代码」的模板。这套模板包含设计模式、抽象层次、可扩展性——这些在教科书里被反复强调的概念。
结果是,即使需求只是「打印斐波那契数列前 20 项」,LLM 也可能写出一个支持任意起始位置、任意终止条件、支持多种输出格式的「斐波那契生成器框架」。
这不是恶意行为。这是训练数据的副作用——大量的开源代码库推崇可扩展性,LLM 学到了这些模式,却没有学会在什么场景下使用它们。

# 反例:为一个需求建造了一座城堡
# 需求:写一个函数,判断字符串是否是回文
# 反例:LLM 的「过度工程」版本
from abc import ABC, abstractmethod
from typing import Protocol, TypeVar, Generic
from enum import Enum, auto
class NormalizationStrategy(ABC):
"""抽象基类:支持不同的规范化策略"""
@abstractmethod
def normalize(self, text: str) -> str:
pass
class LowercaseStrategy(NormalizationStrategy):
def normalize(self, text: str) -> str:
return text.lower()
# ...(省略大量抽象层)
# 实际只需要:
# return s == s[::-1]
# 3 行代码 vs 45 行代码
这个例子当然是极端的,但类似的情况在日常使用中并不罕见。我见过 Claude 为一个简单的 CRUD API 创建完整的 DTO 层、转换层、异常处理链,而实际上那个 API 只有两个端点。
# 正例:最小化实现,只满足当前需求
# 需求:判断字符串是否是回文(忽略大小写和空格)
# 正例:最小化代码
def is_palindrome(s: str) -> bool:
"""Check if string is a palindrome (case-insensitive, ignoring spaces)."""
cleaned = ''.join(c.lower() for c in s if not c.isspace())
return cleaned == cleaned[::-1]
# 需求:添加用户到列表
# 正例:不做提前抽象
def add_user(name: str, email: str):
"""Add a user to the in-memory user list."""
users.append({'name': name, 'email': email})
# 不需要 User 类,不需要 Repository 接口,不需要数据库抽象
# 如果将来需要持久化,到时候再加
关键判断标准:这段代码有没有「如果将来需要」的想法? 如果有,就先不要写。
# 「简单」的反直觉价值
这里有一个反直觉的事实:简单代码通常比复杂代码更 robust。
复杂代码引入了更多的抽象层,每个抽象层都有边界条件和异常路径。当你添加一个「可扩展的设计」时,你也添加了一个「需要维护的接口」和一个「需要理解的逻辑」。这些东西在需求不变时是负担,在需求变化时——很可能——这些「扩展点」根本不是你需要的那个方向。
最简单的代码不需要理解抽象就能理解逻辑,不需要追踪调用链就能定位 bug,不需要文档就能维护(因为代码本身就是文档)。
我自己在使用 Claude Code 时学会的一个技巧是:明确告诉它「不要使用设计模式,除非我明确要求」。这句话在我每次新建 CLAUDE.md 时都会写进去。
# 原则三:Surgical Changes——外科手术式的代码变更
编辑现有代码时,不「改进」相邻代码/注释/格式。不重构没坏的东西。匹配已有风格。只清理自己制造的混乱。
这条原则是我在 code review 中踩过最多坑的。
# LLM 的「好意」是最大的风险
当要求 LLM 修改一段代码时,它常常会「顺便」做一些「改进」:
- 更新相邻函数的命名风格使其「更一致」
- 重写注释使其「更清晰」
- 调整代码格式使其「更规范」
- 重构一个「看起来可以优化」的数据结构
这些「改进」单独看都没有问题,但它们带来的问题是:你不知道哪些变更是你要求的,哪些是 LLM「自作主张」加的。
这在实践中意味着:当你试图理解一个 diff 时,你面对的不再是「一个 bug fix」或「一个功能变更」,而是「一个 bug fix + 风格调整 + 重构 + 格式变更」的混合体。任何一点引入新 bug 的风险,都会被放大。

# 反例:一个 bug fix 引入了三个新 bug
# 原始代码
def process_payment(amount: float, method: str) -> bool:
if amount <= 0:
return False
if method == "credit_card":
return charge_credit_card(amount)
return False
# Claude 修改后的代码
def process_payment(amount: float, method: str) -> dict:
if amount < 0: # ❌ 修改了边界条件(<= 0 变成 < 0)
return {"success": False, "error": "Invalid amount"}
if method == "credit_card":
return {"success": True, "transaction_id": charge_credit_card(amount)}
return {"success": False, "error": "Unsupported method"}
用户的需求可能只是「当金额为负时抛出异常而不是静默返回 False」,但 Claude 因为接收到了一段代码,就觉得应该「整体改进」它。结果是:
- 返回类型从
bool变成了dict,所有调用方需要修改 - 边界条件从
<=0变成了<0,丢失了对「零金额」的处理 - 返回值的结构变了,调用方需要适配新的 dict 格式
一个简单的 bug fix 变成了一次破坏性重构。
# 正例:手术刀式的精准修改
# Claude 的手术刀式修改(只改需要改的)
def process_payment(amount: float, method: str) -> bool:
if amount <= 0:
raise ValueError(f"Invalid payment amount: {amount}") # 只改这一行
if method == "credit_card":
return charge_credit_card(amount)
return False
差异最小化。只添加了 raise ValueError,其他所有内容保持原样。
# Surgical Changes 的实操要求
在 CLAUDE.md 中,我可以这样描述 Surgical Changes 的具体要求:
## 编辑现有代码时的规则
1. **变更范围最小化**:只修改直接相关的代码行,不触碰相邻代码
2. **不变动注释**:除非注释本身就是 bug 的来源,否则不修改注释
3. **不改变样式**:如果现有代码使用 tabs,使用 tabs;如果使用 camelCase,保持 camelCase
4. **不添加新功能**:编辑请求不是重构或改进请求,专注于当前任务
5. **先展示 diff 再执行**:在修改前展示你计划的变更,让用户确认
我自己在实践中发现,「先展示 diff 再执行」这一条特别重要。即使 Claude 理解了这个原则,它的判断也可能与我的预期不符。通过让它先展示计划,我可以及时纠正偏差,而不是在代码已经写入文件后才发现问题。
# 原则四:Goal-Driven Execution——目标驱动执行
将命令式任务转化为可验证目标。「添加验证」 → 「为无效输入写测试,然后让测试通过」。
这条原则是四原则中最具「方法论」色彩的一条。它实际上是在说:把「做什么」变成「做到什么」。
# 命令式 vs 目标导向
这两种表述方式的差异非常微妙,但影响巨大:
| 命令式表述 | 目标导向表述 |
|---|---|
| 「添加输入验证」 | 「当前无效输入会导致程序崩溃。编写一个测试,确认 is_valid_input() 对无效输入返回 False,然后让该测试通过」 |
| 「优化性能」 | 「当前处理 10000 条记录耗时 12 秒。目标是将耗时降低到 2 秒以内。性能瓶颈在第 3 层循环」 |
| 「添加日志」 | 「当 process_payment 失败时,日志中应包含 amount、method 和错误原因,以便调试」 |
| 「修复 bug」 | 「当 amount = -10 时,当前函数静默返回 False。修复后应抛出 ValueError」 |
命令式表述告诉 LLM 一个动作,目标导向表述告诉 LLM 一个期望状态。
# 为什么这个区别如此重要
因为 LLM 在执行「动作」时,路径是模糊的——它可以「添加验证」,但验证放在哪里?验证哪些值?验证失败后如何处理?每个选择都可能与你的意图不符。
而当你描述「目标状态」时,你给 LLM 的是一个可验证的终点。LLM 可以围绕这个终点反向工作:「我需要让无效输入导致测试失败,然后让测试通过,这意味着我需要实现某个验证逻辑」。
更深层地说,目标导向的表述将「质量标准」外化给了 LLM。LLM 不再只是执行一系列指令,它需要理解「什么是成功」——这要求它对问题域有更深的理解。
# 测试驱动:目标导向的最强形式
在这四条原则中,Goal-Driven Execution 与 TDD(测试驱动开发)有着天然的亲和力。Karpathy 提到的「为无效输入写测试,然后让测试通过」本质上就是 TDD 的核心流程。
当你让 LLM 用 TDD 的方式工作时,你给了它三个明确的阶段:
- Red:写一个会失败的测试
- Green:写最少的代码让测试通过
- Refactor:(可选)只重构刚写的代码
这个循环把「编码」变成了「解题」——每个步骤都有明确的目标和可验证的反馈。
我个人的经验是,这个方法在我进行重构时尤其有效。例如,当我要重构一个复杂函数时,我会先让 Claude 为现有行为写测试用例(确保我不会破坏任何东西),然后再进行重构。测试用例就是「目标」的具体化——只要测试通过,就说明重构是正确的。
# 为什么这四条原则能解决 80% 的 LLM 编码错误
现在,我想从一个更宏观的角度来分析这四条原则的有效性。
# 从信息论角度看四条原则
如果我们把「LLM 编码错误」看作一个信息传递问题,那么错误的核心来源是信息不对称:
- LLM 不完全理解你的意图(歧义)
- 你不完全理解 LLM 的方案(黑盒)
- 变更的范围超出了你的预期(scope creep)
- 「完成」的定义不清晰(目标模糊)
这四条原则恰好对应了这四个信息不对称问题:
| 信息不对称 | 对应原则 | 解决方案 |
|---|---|---|
| LLM 不知道你的隐含假设 | Think Before Coding | 强制 LLM 暴露歧义,主动提问 |
| 你不知道 LLM 选择了什么方案 | Surgical Changes | 限制变更范围,先展示 diff |
| LLM 做了超出需求的事 | Simplicity First | 约束代码量,只满足当前需求 |
| 双方对「完成」的理解不同 | Goal-Driven Execution | 定义可验证的目标状态 |
从根本上说,这四条原则不是在「优化 LLM 的输出」,而是在建立一个人机协作的沟通协议。它们把模糊的「帮我写代码」变成了一个有结构的对话。
# 四原则之间的协同关系
这四条原则不是孤立的,它们之间有一个隐含的递进逻辑:
Think Before Coding
↓
澄清需求 → 确定方向
↓
Simplicity First
↓
选择最小化方案 → 避免过度设计
↓
Goal-Driven Execution
↓
定义验收标准 → 明确完成条件
↓
Surgical Changes
↓
精准执行变更 → 交付预期结果
Think Before Coding 解决的是「方向」问题(做什么);Simplicity First 解决的是「方案」问题(怎么做最简);Goal-Driven Execution 解决的是「标准」问题(做到什么程度);Surgical Changes 解决的是「执行」问题(最后怎么落地)。
这四个阶段覆盖了一个完整的人机协作编码流程。
# 实操指南:如何把这四条原则融入你自己的 CLAUDE.md
好,道理懂了,但怎么落地?这是我自己在多个项目中反复迭代后打磨出的 CLAUDE.md 模板。直接拿去用,改成你自己的场景即可。
# Project Context
我是 [你的名字],主要做 [你的工作类型]。
主要技术栈:[列出核心技术]。
当前阶段:[项目当前所处阶段]。
# Working Principles
## Think Before Coding
- 需求有歧义时主动提问,不要默默做假设
- 不确定时停下来列出来可能的方向,问我偏向哪个
- 如果有更简单的方案,必须先提出来再问是否采用
## Simplicity First
- 不实现未被要求的功能
- 不为「将来可能用到」创建抽象
- 不为不可能发生的场景写错误处理
- 遇到复杂代码主动问:「需要我重构吗?」
## Surgical Changes
- 编辑现有代码时只改需要改的部分
- 不修改相邻代码、注释、格式
- 匹配已有代码风格(缩进、命名、模式)
- 修改前先展示 diff,等用户确认再写文件
- 只清理自己造成的孤立代码,不动原有的死代码
## Goal-Driven Execution
- 把命令式任务转成可验证目标
- 「添加 X」 → 「写测试验证 X 工作正常,然后让测试通过」
- 「修复 bug」 → 「写一个能复现的测试,然后让测试通过」
- 完成功能后说明你是怎么验证的
# Code Style
- [具体写明的命名规则、缩进风格、注释风格]
- [你项目的架构约定,例如 feature-based / layer-based]
# 当前优先事项
1. [本阶段最重要的目标]
2. [次要目标]
3. ...
# 明确禁止
- 不要在代码中留下 TODO
- 不要添加不必要的依赖
- 不要改动 [某些配置文件],除非我明确要求
如何使用:
把这份模板复制到项目根目录,命名为 CLAUDE.md。几点说明:
Working Principles 部分 是核心——这四条不是随便写的,而是针对 Karpathy 原则的具体化。比如「自我检查」那条,我加了一句「如果你发现了自己的错误,直接改正」,因为这是我在使用中发现最影响效率的细节——模型有时候会坚持一个错误的实现,直到我指出来。
Code Style 部分 要写得具体。我看过很多 CLAUDE.md 把「遵循最佳实践」写在 Code Style 里,这等于没写——最佳实践有一百种解释。写得越具体,模型输出的一致性越高。
当前优先事项 是动态的。每次开始新任务之前,我会更新这一节。这帮我自己在和 AI 对话前理清思路,也帮 AI 理解我现在最在意什么。
明确禁止 也很重要。告诉 AI 不要做什么,往往比告诉它要做什么更有效——因为负面规则更具体,更不容易被「善意地误读」。
# 反思:这是约束 AI 还是赋能 AI?
写到这里,我停下来问了自己一个问题:这份 CLAUDE.md,本质上是在「驯服」AI,还是在给 AI 一个更好的发挥空间?
我倾向于后者。
很多人把 prompt 工程理解为「让 AI 按我的方式做事」。但更准确的描述是:在给定的约束下,给 AI 更大的自由度。
Karpathy 的四条原则,每一条都是在划边界:不要只给我片段、发现错误要改、代码复杂了要说、做完功能要验证。在这些边界之内,AI 可以充分发挥——它可以选它认为最好的实现方式,可以在遇到歧义时做出合理假设,可以在感觉不对的时候提出来。
没有这些边界会怎样?AI 会变得更「保守」。因为它不确定你会接受什么输出,于是它倾向于输出最少、最模糊的内容——反正你说哪里不对它改哪里就是了。这其实是效率最低的协作方式。

把这套思路放到 Claude Code 的生态里看,会更清晰。
Harness(配置文件、~/.claude.json 等)是全局层面的约束——你希望 Claude Code 在所有项目中的默认行为是什么。这是基础设施。
MCP(Model Context Protocol)是工具层面的扩展——你的 AI 能访问什么信息、能操作什么系统。这是能力边界。
Skill 是任务层面的指导——针对特定类型的工作,AI 应该遵循什么流程。这是工作方法论。
而 CLAUDE.md,恰好落在 Skill 和 Harness 之间的那个交叉点——它是项目级别的指导原则,定义了「在这个特定项目中,AI 应该怎么做」。
这就是为什么 CLAUDE.md 不是「又一个配置文件」。配置文件告诉 AI「你能做什么」,CLAUDE.md 告诉 AI「你应该怎么做」。
现在让我们把视野拉大。
AI Agent 时代正在发生一件根本性的变化:程序员的角色正在从执行者变成协调者。
这句话已经被说了无数遍,但它的含义值得我们仔细拆解。
执行者的工作模式是:需求清晰,产出明确,你交付的是代码。AI 出现后,这种工作模式受到冲击——AI 能以 10 倍的速度完成同样的代码交付。于是执行者开始焦虑:我的价值在哪里?
协调者的工作模式完全不同。需求可能模糊,产出是决策和判断,你交付的是方向。AI 负责在方向之下执行,你负责在执行之上导航。
CLAUDE.md 是这个转变的缩影。写一份好的 CLAUDE.md,需要你对自己正在做的事有清晰的理解——不只是「我要做什么功能」,而是「我重视什么、我不接受什么、我当前阶段的核心矛盾是什么」。这些东西 AI 无法替你写,因为它们来自你对自己工作的判断。
换句话说:你越清楚自己要什么,AI 就能帮你越多。
这不是「程序员被 AI 替代」的叙事,这是一个更微妙的转变:AI 把执行层的事情接管了,人类被推到了真正需要判断力的位置。多数时候,判断力比执行能力更稀缺,也更难培养。

# 结语
四条原则,一篇长文,最后归结为一句话:
和 AI 协作的本质,不是让它替你工作,而是让你学会提出更好的问题。
Karpathy 的四条原则,表面上在约束 AI 的输出行为,实际上在训练你——训练你对「好代码」的直觉,训练你对「这段逻辑是否正确」的敏感度,训练你对「这个实现是否过度设计」的判断力。
CLAUDE.md 只是一个开始。真正的技能,是你有一天不再需要这份文件——因为你已经在无数次对话中,把这些原则内化成了自己的思维方式。
到那时,AI 不再是你的拐杖,而是一面镜子:它忠实地反映你的思路,也放大了你的盲区。
这是最好的时代,还是最坏的时代?取决于你愿不愿意回答那个最难的问题:
你到底想要构建什么?