下面这个场景,过去一年里几乎所有读到这篇文章的开发者都亲身经历过。
深夜十一点半,你正在开发一个功能,比如给现有的电商服务加上实时订单追踪。你打开顺手的 AI 编程助手(Cursor、Claude Code、GitHub Copilot 或 Antigravity),输入一段自己觉得挺合理的提示词:
“用 WebSockets 和 Redis 加上实时订单追踪。”
回车一敲,助手毫不犹豫,三秒之内就开始疯狂输出代码。
它从零写了一个 WebSocket 网关,还临时发明了一个 Redis pub/sub 封装。它把一个全局状态变量直接塞进你的 React 布局,引入一个你从没听过的第三方重连库,顺手还把现有 Order 模型改了一半,连带搞挂了六个毫不相干的单元测试。
这 diff 看起来像案发现场。
想象一个满腔热忱的初级程序员入职第一周就干出这种事:改写领域模型、更换依赖库、修改数据库 schema,全程没有一个澄清问题。你不会夸他手快,而是会把他叫过来,认真聊聊需求、架构边界和范围。
然而换成 AI 助手,我们却对这种病态习以为常。我们把高速吐 token 当成“生产力”,然后花接下来三个小时修补断裂的架构接缝、排查隐藏的竞态条件、回滚那些过早的抽象。
问题不在于如今的大模型写不出代码。问题在于它们动手太早了。
说来也怪,这个问题的最佳解药,早在八十年前就由一位斯坦福数学家写出来了。
根源:自回归的短视
大模型从底层设计上就是自回归的贪心 token 生成器。收到提示词后,训练机制驱使它们立刻输出概率最高的续写内容。
它们没有内置的暂停键。不会呷一口咖啡,看看你现有的仓库结构,然后琢磨:
- 这里已经有哪些领域实体?
- 延迟和重连的 SLA 是多少?
- 如果 Redis 挂了重启,会出哪些异常路径?
- WebSockets 在这里真是合适的架构取舍吗?还是说 Server-Sent Events(SSE)能少写 50 行代码解决问题?
它们不会琢磨,而是一头扎进实现细节。
认知科学界几十年前就发现了这个陷阱。1985 年,加州大学伯克利分校的研究者Alan H. Schoenfeld出版了《数学问题解决》(Mathematical Problem Solving)一书,研究学生和数学家如何攻克难题。他发现,新手解题者几乎不花时间分析问题,上来就直接动笔计算,结果沿着一条走不通的路撞进死胡同,再把所有时间耗在回溯返工上。
专家的做法恰恰相反。他们在动笔计算之前,会花掉绝大部分时间分析约束条件、画图梳理思路、并及时否决那些走不通的方向。
Schoenfeld 证明,缺少他所说的元认知监控能力(metacognitive supervisory control),任何解题策略都会失效——这种能力指的是能有意识地停下来评估进展,拒绝在未经验证的假设上继续推进。
如今的 AI 编程 Agent 就是一群彻头彻尾的新手。他们拥有百科全书式的语法知识,元认知控制能力却为零。
George Pólya 登场(1945)
1945 年,匈牙利裔美国数学家George Pólya在普林斯顿大学出版社出版了一本仅 250 页的小书——《怎样解题》(How to Solve It)。这本书后来卖出上百万册,被翻译成 17 种语言。
┌────────────────────────────────────────────────────────────────────────┐
│ GEORGE PÓLYA'S 4-STAGE HEURISTIC (1945) │
├────────────────────────────────────────────────────────────────────────┤
│ 1. UNDERSTAND THE PROBLEM ➔ What is the unknown? What are the data? │
│ What is the condition? Can it be met? │
│ 2. DEVISE A PLAN ➔ Find connections between data & unknown. │
│ Isolate auxiliary problems. Restate it. │
│ 3. CARRY OUT THE PLAN ➔ Check each step. Can you prove that each │
│ individual step is sound and correct? │
│ 4. LOOK BACK (EXAMINE) ➔ Check the result. Derive it differently. │
│ Promote reusable patterns to memory. │
└────────────────────────────────────────────────────────────────────────┘
波利亚并不关心事后补写的严密数学证明,他痴迷于发现的心理过程:人在不确定中究竟是如何摸索前进的。他把解题过程归纳为四个固定阶段:
- 理解问题:拆解未知量(我们要产出什么?)、已知数据(存在哪些输入和状态?)以及约束条件(哪些限制和业务规则必须成立?)。
- 拟定方案:找出数据与未知量之间的联系。考虑辅助问题。从结果倒推。换种方式复述问题。
- 执行方案:逐步检验每一步,边推进边验证正确性。
- 回顾反思:审视结果。能否用更简洁的方式推导出来?这个方法能否迁移到其他问题上?
1961年,人工智能先驱马文·明斯基在其里程碑论文Steps Toward Artificial Intelligence中引用了波利亚,并写道:"每个人都应该了解乔治·波利亚关于如何解决问题的研究。"1982年,计算机科学家R. Geoff Dromey将波利亚的方法改造为算法设计方法论,写成How to Solve It by Computer一书。
几个月前,我在跟一个总是幻觉出数据库字段的 AI Agent 较劲时,突然灵光一闪:
AI Agent 比人类开发者更需要波利亚的这套纪律。
把波利亚与 Uncle Bob 的整洁架构结合起来
数学启发法提供了认知上的脚手架,但软件工程还需要具体而坚实的物理边界。
我们将波利亚的四个阶段与Robert C. Martin("Uncle Bob")的整洁架构原则相结合:严格的依赖倒置、解耦的领域实体、用接口(端口)把业务逻辑与基础设施适配器隔离开,以及意图清晰的整洁代码。
最终成果就是Pólya SDLC Coder:一套开源工具,包含 15 个模块化的 Agent 技能,组织在严谨的 6 阶段生命周期中。
下面展示波利亚1945年提出的启发式方法如何一一对应到现代软件工匠技艺的全部15项技能:
| 波利亚启发式方法(1945) | 软件工匠技艺对应环节 | Agent技能命令 |
|---|---|---|
| “了解情况” | 代码库侦察与全貌地图 |
/to-ask-help、/to-map和/to-init
|
| “理解问题” | 需求探索、PRD、DTO与接缝映射 |
/to-explore、/to-prd和/to-spec
|
| “质疑前提” | 苏格拉底式交锋与具体的A/B权衡 | /to-grill-me |
| “审视条件” | 五轴假设检查与0-100就绪度门槛 | /to-clarify |
| “拟定计划” | 纵向曳光弹开发与Plan B应急预案 | /to-plan |
| “动手前的犹豫” | 显式的人工对齐关卡 | 🛑 强制暂停规则 |
| “执行计划” | 整洁代码、不超过25行的函数与微TDD |
/to-code和/to-quick-fix
|
| “回顾与追根溯源” | SOLID五原则审计、第一性原理修复与Diátaxis文档 |
/to-review、/to-fix和/to-docs
|
| “两个黄金提问” | 跨会话的架构记忆 | /to-memory |
实战效果
让我们回到之前那个实时订单追踪功能,这次用波利亚工作流来跑一遍。
第一步:自主分诊(/to-ask-help)
在一个已有代码的仓库里,/to-map 会先扫描你的目录结构,并在 docs/ARCHITECTURE.md 中维护一份实时更新的架构地图。这样 Agent 就能准确掌握你的分层边界,不必在每次收到提示词时重新阅读上千个文件。
接下来,与其直接把一个原始的功能命令丢给 Agent,你应该运行:
/to-ask-help Add real-time order tracking using WebSockets and Redis
Agent 不写代码,而是检查你的代码仓库,定位已有的领域模型,确认你使用的 HTTP 框架,然后返回一张Pólya 分诊卡:
+-----------------------------------------------------------------------+
| POLYA TRIAGE CARD |
+-----------------------------------------------------------------------+
| The Unknown : Real-time WebSocket order tracking stream |
| The Data : Order entity, Redis Pub/Sub adapter, React UI hook |
| The Condition : Sub-100ms latency, automatic reconnection, JWT auth |
| Seams Found : Domain (Order), Adapters (RedisStream), UI (Hook) |
| Recommended : /to-explore or /to-spec |
+-----------------------------------------------------------------------+
如果问题空间还很宽泛,/to-explore 会借助波利亚的发明者悖论进行架构探索,而 /to-prd 则会在敲定技术契约之前,先梳理用户故事并明确列出非目标。
第 2 步:苏格拉底式对练(/to-grill-me)
在撰写规格说明之前,先让这个想法和陪练过过招:
/to-grill-me "Should we use WebSockets or Server-Sent Events (SSE) for order tracking?"
通用助手会甩给你一篇十段长的回复,说什么“两者都不错,看你的需求!”。而 Pólya 对练技能则强制执行“一问规则”和“资深工程师式明确推荐”:
[方案 A:Server-Sent Events(SSE)]
基于标准 HTTP/2 的单向流。复用现有的鉴权请求头,不需要自建心跳机制,还能通过浏览器原生的 EventSource API 自动重连。[方案 B:WebSockets]
双向全双工 socket。需要专门管理连接生命周期,自行实现 JWT 握手校验,还要手动做心跳 ping/pong 来检测失效的 TCP 连接。资深工程师的推荐:
我推荐方案 A(SSE)。订单追踪的数据流是 100% 从服务端到客户端的(客户端从不通过这条通道回传坐标信息)。WebSockets 带来的有状态连接维护开销,对这个问题来说纯属多余——HTTP/2 流式传输天生就能解决。唯一的问题:你预计在 V1 版本中,骑手或客户会通过这条流发送实时消息吗?还是说客户端到服务端的交互完全由标准 REST 接口处理?
一个犀利的问题,直指真正的架构取舍。30 秒内定夺,省下几小时不必要的 WebSocket 基础设施搭建。
第 3 步:纵向曳光弹(/to-plan)
取舍敲定后,/to-spec 会把数据契约和架构接缝固化到 docs/spec/ 中,并用明确的 [ASSUMPTION] 标签标记所有未经验证的假设。开始规划之前,/to-clarify 会从五个维度审计规格文档,并强制执行客观的0-100 就绪度门禁(低于 80 分的流水线会被拦截,直到歧义全部解决)。
通过门禁后,/to-plan 不再采用横向切片(先写完所有数据库表,再写完所有控制器,最后写完所有 UI),而是设计纵向曳光弹:
- 曳光弹 1:领域事件 + SSE 发射端口 + 集成测试 mock。
- 曳光弹 2:带 JWT 鉴权校验的 HTTP 接口。
- 曳光弹 3:前端 UI 订阅 hook,附带连接状态徽标。
- 应急方案 B:如果 HTTP 流断开,优雅降级为 5 秒轮询。
第 4 步:🛑 强制暂停规则
这是整个系统中最关键的一道护栏。
计划一生成,Agent 就戛然而止。它被严格禁止编写任何一行业务代码。
它会打印输出:
🛑 MANDATORY GATE: THE PAUSE RULE
The implementation plan is staged at docs/plan/order-tracking-plan.md.
Execution is halted. Awaiting explicit user confirmation before writing code.
这就落实了 Alan Schoenfeld 所说的监督控制。你检查这些"曳光弹",一旦发现某个假设有问题,只需 10 秒就能在 markdown 里改掉。
只有当你明确输入:
"计划已审核并批准,开始实现。"
……Agent 才会进入 /to-code 阶段。
第 5 步:实现与审计(/to-code 与 /to-review)
在 /to-code 阶段,Agent 受到 Uncle Bob《代码整洁之道》的约束:
- 函数不得超过 25 行。
- 每个函数只处理一个抽象层级。
- 命名要能直接表达意图。
-
反作弊底线:严禁使用
@ts-ignore、跳过测试,或留下// TODO之类的空壳。 -
双层测试:每颗"曳光弹"都必须通过快速类型检查(
check:fast)和任务单元测试(check:task),任务才能标记完成。
最后,/to-review 会依据5 条 SOLID 原则和14 类防御性安全向量(OWASP、租户隔离、输入净化)审计代码 diff,并给出明确的发布结论(GO 或 NO-GO)。审核通过后,/to-docs 会按 Diátaxis 框架编写结构化文档,让团队在收获整洁代码的同时,也收获清晰的指南。
前后对比:代码究竟长什么样
想看实际效果,可以观察这样一个场景:骑手更新订单实时位置并通过我们的流广播出去,此时代码层面会发生什么。
不使用 Pólya 流程时(AI 默认的"一把梭"模式):
AI 会把所有东西一股脑塞进一个临时控制器,裸写的 Redis socket、直接的 SQL 查询、未处理的 Promise 拒绝混作一团:
// The typical AI hallucination: business logic tangled directly with transport
app.post('/api/orders/:id/location', async (req, res) => {
const redis = new Redis(process.env.REDIS_URL); // New connection on every HTTP request!
const order = await db.query('SELECT * FROM orders WHERE id = $1', [req.params.id]);
if (!order.rows[0]) return res.status(404).send('Not found');
await db.query('UPDATE orders SET lat = $1, lng = $2 WHERE id = $3', [
req.body.lat, req.body.lng, req.params.id
]);
redis.publish(`order-stream:${req.params.id}`, JSON.stringify(req.body));
// No domain validation, zero port abstractions, connection leaks in production
res.json({ updated: true });
});
结合Pólya方法与整洁架构(/to-code):
由于/to-spec已提前划分好模块边界,Agent输出的领域端口和意图清晰的用例不到25行,且完全解耦:
// Clean Architecture: Pure Use Case decoupled from HTTP, SQL, and SSE/Redis transport
export class PublishOrderLocationUseCase {
constructor(
private readonly orderRepo: OrderRepositoryPort,
private readonly streamPublisher: OrderStreamPublisherPort
) {}
async execute(input: UpdateOrderLocationDto): Promise<Result<void, OrderDomainError>> {
const order = await this.orderRepo.findById(input.orderId);
if (!order) {
return Result.fail(new OrderNotFoundError(input.orderId));
}
const moveResult = order.recordLocation(input.coordinates);
if (moveResult.isFailure) {
return Result.fail(moveResult.error);
}
await this.orderRepo.save(order);
await this.streamPublisher.publish(order.toTrackingEvent());
return Result.ok();
}
}
无论外层的OrderStreamPublisherPort适配器是通过Server-Sent Events推送(也就是/to-grill-me阶段选定的方案),还是借助Redis Pub/Sub扇出分发,核心领域的用例都毫不在意。没有连接泄漏,领域逻辑与传输方式彻底解耦,单元测试还能100%用mock独立运行。
跳出理想路径:Day-2阶段的工程现实
交付初始功能只是成功了一半。大多数AI工作流在Day 2就会掉链子:聊天上下文窗口重置、生产环境冒出bug,或者你只想随手改个配置却被流程绊住。
1. 治好“AI失忆症”(/to-memory)
用AI编程Agent的开发者都体会过会话重置的痛苦。你花两个小时对齐了一种架构模式,然后上下文窗口满了,只好开个新会话,结果Agent把之前做过的每一条设计决策忘得一干二净。
Pólya SDLC的解法是把会话记忆持久化到memory.instructions.md里。每当完成一个里程碑,或者敲定一个复杂的架构权衡,运行/to-memory就能把当前的结论压缩存档:
- 正在推进的tracer bullet及其完成状态
/to-grill-me阶段敲定的架构决策记录(ADR)- 已知的代码库坑点和负面约束
明天早上开始新会话时,Agent会先读这个文件。上下文零丢失,你也不用再重复自己。
2. 打地鼠式修bug的解药(/to-fix)
缺陷一旦出现,AI的默认表现就是闭眼打地鼠:修补一个症状,引入两个新的边界用例失败,然后陷入层层嵌套的hack泥潭。
通过/to-fix,Agent被严格禁止盲目乱改。它会回到第一性原理:
- 用二分查找(
O(log n))追踪并隔离出确切出问题的架构接缝。 - 先写一个自动化复现测试,并且确保它因为预期的原因而失败。
- 在
docs/bug-reports/中锁定根因修复方案,然后才把执行交给/to-code。
不靠猜,不打补丁循环,也不会引发回归雪崩。
3. 快速通道编辑:迂腐与精通之别(/to-quick-fix)
乔治·波利亚在1945年留下一句名言,告诫人们不要陷入教条主义:
“一字不差、僵化刻板、不加思考地套用规则……那是迂腐。运用自如、带着判断力去使用规则,并清楚它适用于哪些场景……那才是精通。”
如果你只是要修一个配置文件里的错别字,或者调整按钮的 CSS 边距,还走完整个包含规格文档和苏格拉底式辩论的六阶段 SDLC,那就太荒唐了。
对于只影响一两个文件的常规小改动,波利亚 SDLC 提供了一条快速通道:
/to-quick-fix Fix typo in redis timeout config and increase retry limit to 5
它省去了繁琐的正式文档,同时保留了类型检查、整洁的代码格式和原子化的 git 提交。
在你的代码库中试用
Pólya SDLC Coder 是开源项目(MIT 许可证),支持所有具备 Agent 技能或指令规则功能的平台,包括Cursor、Claude Code、GitHub Copilot、Google Antigravity 和 ChatGPT Codex。
用 npx skills 快速安装
无需克隆庞大的仓库,也不用安装沉重的 npm 依赖。借助通用的 npx skills 命令行工具即可直接安装:
# Option A: Install the lightweight bootstrapper skill
npx skills add GulajavaMinistudio/polya-sdlc-coder/skills/to-init
# Option B: Or install the entire 15-skill suite directly
npx skills add GulajavaMinistudio/polya-sdlc-coder
然后在AI助手的聊天窗口里,直接输入:
/to-init setup this project
引导程序会自动检查你的仓库,搭建.agents/目录、配置AGENTS.md,并接好整套 15 个技能。
(如果你更喜欢一行命令搞定,可以看看这个交互式网页配置器,支持 macOS、Linux 和 Windows。)
结语
AI 编程工具不会消失。但“看,这个大模型吐 500 行没人审查的代码多快”的蜜月期正在结束。工程团队也开始尝到 AI 生成的意大利面条式代码带来的维护苦果。
用 AI 构建可靠软件的秘诀,不在于更快的模型或更大的上下文窗口。
而在于以工程上的谦逊态度停下来,理解问题、审视我们的前提、验证方案,然后再写下第一行代码。
George Pólya 在 1945 年就想明白了这一点。我们花了八十年(外加几百万个产生幻觉的 token)才追上来。
链接与资源
- 📐 GitHub 仓库:GulajavaMinistudio/polya-sdlc-coder
- 🌐 交互式网页文档与技能目录:gulajavaministudio.github.io/polya-sdlc-coder
- 📖 1945 年的起源故事:为什么是 Pólya?(深度解析)
该你了
你是如何防止 AI 编程智能体一头扎进过早的意大利面条式代码的?你采用规范先行的工作流、自定义指令文件,还是手动审查关卡?
那么,AI助手偷偷塞进你代码库里最离谱的架构烂摊子是什么?欢迎在评论区分享你的踩坑经历和工作流,很想和大家交流切磋!

