← 返回
AI技术

80 年前的数学书,怎么修好我的 AI 编程 Agent

✍️ zhirenhun 📅 2026/10/23 👁 151 阅读 ⏱ 37 分钟
80 年前的数学书,怎么修好我的 AI 编程 Agent

下面这个场景,过去一年里几乎所有读到这篇文章的开发者都亲身经历过。

深夜十一点半,你正在开发一个功能,比如给现有的电商服务加上实时订单追踪。你打开顺手的 AI 编程助手(Cursor、Claude Code、GitHub Copilot 或 Antigravity),输入一段自己觉得挺合理的提示词:

“用 WebSockets 和 Redis 加上实时订单追踪。”

回车一敲,助手毫不犹豫,三秒之内就开始疯狂输出代码。

它从零写了一个 WebSocket 网关,还临时发明了一个 Redis pub/sub 封装。它把一个全局状态变量直接塞进你的 React 布局,引入一个你从没听过的第三方重连库,顺手还把现有 Order 模型改了一半,连带搞挂了六个毫不相干的单元测试。

这 diff 看起来像案发现场。

想象一个满腔热忱的初级程序员入职第一周就干出这种事:改写领域模型、更换依赖库、修改数据库 schema,全程没有一个澄清问题。你不会夸他手快,而是会把他叫过来,认真聊聊需求、架构边界和范围。

然而换成 AI 助手,我们却对这种病态习以为常。我们把高速吐 token 当成“生产力”,然后花接下来三个小时修补断裂的架构接缝、排查隐藏的竞态条件、回滚那些过早的抽象。

问题不在于如今的大模型写不出代码。问题在于它们动手太早了。

说来也怪,这个问题的最佳解药,早在八十年前就由一位斯坦福数学家写出来了。


根源:自回归的短视

大模型从底层设计上就是自回归的贪心 token 生成器。收到提示词后,训练机制驱使它们立刻输出概率最高的续写内容。

它们没有内置的暂停键。不会呷一口咖啡,看看你现有的仓库结构,然后琢磨:

它们不会琢磨,而是一头扎进实现细节。

认知科学界几十年前就发现了这个陷阱。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.     │
└────────────────────────────────────────────────────────────────────────┘

波利亚并不关心事后补写的严密数学证明,他痴迷于发现的心理过程:人在不确定中究竟是如何摸索前进的。他把解题过程归纳为四个固定阶段:

  1. 理解问题:拆解未知量(我们要产出什么?)、已知数据(存在哪些输入和状态?)以及约束条件(哪些限制和业务规则必须成立?)。
  2. 拟定方案:找出数据与未知量之间的联系。考虑辅助问题。从结果倒推。换种方式复述问题。
  3. 执行方案:逐步检验每一步,边推进边验证正确性。
  4. 回顾反思:审视结果。能否用更简洁的方式推导出来?这个方法能否迁移到其他问题上?

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),而是设计纵向曳光弹:

第 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《代码整洁之道》的约束:

最后,/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就能把当前的结论压缩存档:

明天早上开始新会话时,Agent会先读这个文件。上下文零丢失,你也不用再重复自己。

2. 打地鼠式修bug的解药(/to-fix)

缺陷一旦出现,AI的默认表现就是闭眼打地鼠:修补一个症状,引入两个新的边界用例失败,然后陷入层层嵌套的hack泥潭。

通过/to-fix,Agent被严格禁止盲目乱改。它会回到第一性原理:

  1. 用二分查找(O(log n))追踪并隔离出确切出问题的架构接缝。
  2. 先写一个自动化复现测试,并且确保它因为预期的原因而失败。
  3. 在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)才追上来。


链接与资源

该你了

你是如何防止 AI 编程智能体一头扎进过早的意大利面条式代码的?你采用规范先行的工作流、自定义指令文件,还是手动审查关卡?

那么,AI助手偷偷塞进你代码库里最离谱的架构烂摊子是什么?欢迎在评论区分享你的踩坑经历和工作流,很想和大家交流切磋!

——

广告 广告
🧑‍💻

zhirenhun

一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。

ai webdev programming productivity