上个月我同事让 AI 排查一个内存泄漏,AI 给了 5 个"自信满满"的假设。全是错的。 他又花了一周才找到真相。
那天我意识到,大多数人根本不会用 AI。
这篇文章写了两个月,删改无数遍。我把所有想说的、踩过的、验证过的、观察到的,都塞进去了。如果你只想看结论,可以跳到最后一节。但我建议你从头读到尾——因为真正值钱的东西,都在过程里。
写在最前面:为什么我要写这么长
先交代一下背景,免得你看完觉得"这人谁啊就来指点我"。
我在北京,写代码写了十一年。前六年做后端,后五年转做视频编解码——对,就是那种又硬又冷、面试官都不太愿意问的方向。日常跟 x265、VTM、FFmpeg 打交道,看的是 CABAC 熵编码、RDOQ 率失真优化、ALF 自适应环路滤波这些玩意儿。偶尔也写点 Python 做图像处理,用 Pillow 做美颜链路的验证。
2024 年初,我第一次认真用 ChatGPT。那时候我嗤之以鼻:“这不就是个高级点的自动补全吗?”
2024 年中,Cursor 出来,我开始在 IDE 里用 AI 写代码。效率大概提升 30%,但我嘴上还是不服。
2024 年底,Claude Code 出来。我第一次看到一个 AI 能自己读整个项目、自己改文件、自己跑测试、自己提 PR。那天晚上我坐在工位上愣了很久。
2025 年,AI 成了我工作里的基础设施。CI 里跑 AI 检查,文档自动生成,连周报都是 AI 先出一版。
2026 年,也就是现在,我不再讨论"要不要用 AI"了。就像 2020 年没人再讨论"要不要用 Git"一样。问题已经变成了:怎么用得好。
第一部分 AI 工具盘点:真实的横评,不吹不黑
一、先说结论:没有"最强 AI",只有"最合适的 AI"
我测过至少三十款 AI 工具。最后长期留在我的机器上的,只有七款。
先给你一个总览表,后面逐个细说:
| Claude | 主力对话 + 长文理解 | 9.5 | 每天 |
| GPT-5 | 数学推理 + 复杂逻辑 | 9.0 | 每周几次 |
| Cursor | IDE 内编码 | 9.5 | 每天 |
| Claude Code | 复杂 feature 实现 | 9.0 | 每天 |
| Aider | 终端工作流 | 7.5 | 每周 |
| Kimi | 长文档处理 | 8.0 | 每周 |
| DeepSeek | 便宜好用的代码 | 8.0 | 按需 |
注意,这个打分是我的主观感受,跟你的场景可能完全不同。比如你是做前端的,那 v0.dev 可能直接 9.5 分,但对我这种后端 + 编解码的人来说,v0 基本没用。
千万别信"XX 吊打 XX"这种标题。工具是拿来用的,不是拿来吵架的。
二、Claude:我的主力,也是我的"技术合伙人"
2.1 为什么是它
我用 Claude 最多,原因很朴素:它在技术问题上最不容易胡说八道。
举个真实例子。我让几个 AI 同时解释 x265 里的一段 CABAC 代码:
void CABACWriter::encodeBin(CABACModel& model, int bin)
{
uint32_t& state = model.state;
uint32_t lps = sm_fracBitsTable[state & 63];
// …
}
- 某国产模型说:“这段代码在做二进制算术编码,state 是状态机,lps 是最小概率符号。” —— 对,但也就这样了,等于没说。
- GPT 说了一大段,中间把 sm_fracBitsTable 解释错了,说它是"分数位表",其实它是概率到分数比特的查找表,用于近似计算 -log2(p)。
- Claude 说:“这是 HEVC 的 CABAC 编码器,state 的低 6 位(& 63)索引概率状态转移表,lps 查的是这个状态的分数比特数,也就是信息量代价。注意这里用查表而不是实时算 log,是为了性能。”
哪个更靠谱,一眼就能看出来。
2.2 我常用的几个 Claude 场景
场景一:读别人写的烂代码
我接手过一个 2019 年的 C++ 项目,注释全是中文拼音缩写,变量名是 a1, a2, tmp1。我直接把文件丢给 Claude:
这是一个遗留项目的代码文件,请你:
1. 用现代 C++ 风格重写一遍(保留逻辑,只改命名和结构)
2. 给每个函数写一句话注释
3. 标出你觉得可疑的地方(潜在的 bug、内存问题、性能问题)
它给出的"可疑点"里,有 3 个是真的 bug。其中一个是 std::vector 迭代器在 push_back 之后继续使用,典型的 UB。
场景二:写技术文档
我最讨厌写文档。现在流程变成了:
这个流程下,文档速度提升 3 倍以上,但灵魂还是我的。
场景三:当"技术陪练"
有时候我在设计方案时会纠结,就找 Claude 当陪练:
我要设计一个支持 100 万 QPS 的短链服务,我的方案是:
– 用 Snowflake 生成 ID,转 base62
– Redis 存映射,MySQL 做持久化
– 用布隆过滤器挡无效请求
请你扮演一个挑刺的资深架构师,找出这个方案的所有问题。
不要客气,越狠越好。
它会指出:Snowflake 时钟回拨怎么办、Redis 挂了怎么办、布隆过滤器的假阳性率、MySQL 写放大……这些问题我自己也能想到,但它逼我系统性地想一遍。
2.3 Claude 的缺点
说了这么多好话,也说缺点:
三、GPT-5:数学和逻辑上的偏执狂
3.1 它的定位
GPT-5 我不日常用,只在特定场景打开:
- 数学推导:比如推导率失真优化的拉格朗日乘子怎么来的
- 复杂逻辑:多步骤的算法设计
- 需要"严谨"的场合:写论文公式、验证数学证明
3.2 一个真实的数学例子
我在写 JND(恰可察觉失真)相关的内容时,需要从 SSIM 推到它的变体。
我让 GPT-5 做:
请从 SSIM 的定义出发,推导 MS-SSIM(多尺度 SSIM)的完整公式,
包括每一层的降采样、对比度项和结构项的加权方式。
给出数学推导步骤,不要跳步。
它给出的推导是完整的,而且每一层降采样用的高斯核参数都写对了。这个活儿 Claude 也能干,但 GPT-5 的公式表述更"正经",直接能贴进论文。
3.3 缺点
四、Cursor:IDE 里的那双手
4.1 我为什么离不开它
Cursor 是 VS Code 的 fork,但把 AI 深度集成进去了。
我每天用得最多的是三件事:
第一件事:Tab 补全
这个是真的丝滑。它不只是补一行,而是能预测你接下来要写的一整块。
我写 Python 的时候经常是打几个字,它就把整个函数体补完了,我按 Tab 接受,改改细节就行。
def parse_sps(self, data: bytes) –> SPS:
# 我只打了 "def parse_sp"
# Cursor 补出:
reader = BitReader(data)
sps = SPS()
sps.profile_idc = reader.read_bits(8)
sps.level_idc = reader.read_bits(8)
sps.seq_parameter_set_id = reader.read_ue()
# …
第二件事:Cmd+K 局部编辑
选中一段代码,按 Cmd+K,输入指令,它直接改。
选中:一段 30 行的 if-else 嵌套
指令:"改成 early return 风格,消除嵌套"
结果干净利落。
第三件事:Chat 模式
针对整个项目提问:“这个模块的数据流是怎样的?”
它会自动检索相关文件,给你一个跨文件的解释。这个功能在研究陌生代码库时特别好用。
4.2 关于 Tab 补全的一个真实吐槽
Cursor 的 Tab 补全有个毛病:它会补你没想写的东西。
有次我在写一个视频编码的量化函数,光标停在一行,它直接给我补了一大段"完整实现",包括一个我根本没打算用的查表优化。
我按了 Tab,然后花 10 分钟才搞明白它那个查表是干嘛的。
教训:Tab 补全要按得克制。 尤其是你不完全确定它补什么的时候,先看清楚再按。
4.3 Cursor 的价格账
- Hobby(免费):每月 2000 次补全 + 50 次高级请求
- Pro(20 美元/月):无限补全 + 500 次高级请求
- Business(40 美元/人/月):团队功能
说实话,Pro 的 500 次高级请求不太够用。我经常月中就用完了,只能切回普通模型。
五、Claude Code:真正的"AI 同事"
5.1 它跟 Cursor 的区别
Cursor 是"AI 在你的编辑器里帮忙",Claude Code 是"AI 在你的终端里干活"。
区别在哪?Claude Code 能自主行动。
它可以直接:
- 读你的整个项目结构
- 修改多个文件
- 运行测试命令
- 看测试结果,自己修 bug
- 提交 git commit
5.2 一个真实的完整任务
上周我需要给一个 Python 项目加一个功能:“支持从 MP4 提取缩略图并缓存”。
我给 Claude Code 的指令就一句:
给这个项目加一个功能:从 MP4 文件提取指定时间点的缩略图,
提取结果缓存到 ~/.cache/thumbnails/,缓存 key 用文件哈希 + 时间戳。
写完后跑一下测试。
然后它自己做了:
整个过程不到 3 分钟。这活儿我自己写要 40 分钟。
5.3 但我不会让它"全自动"
有个细节很重要:它做的每一步我都会 review。
尤其是第 4 步的代码,我逐行看了。发现它用了一个我不喜欢的写法——在函数内部 import:
def extract_thumbnail(path, timestamp):
import hashlib # 它喜欢在函数内 import
...
这个写法有争议(减少启动时间 vs 可读性),但项目里其他地方都是顶部 import。我让它改成一致的风格。
这就是正确的 AI 协作姿势:AI 干活,你定标准。
六、Aider:终端党的心头好
Aider 是个命令行工具,直接在终端里跟 AI 对话改代码。
$ aider src/encoder.py src/quant.py
> 把 quant.py 里的量化函数改成支持 16bit 输入
它的特点是:
- 纯 CLI,没有 GUI,适合 vim 党
- 自动管理 git commit(每次改动自动提交,方便回滚)
- 可以接各种模型(Claude、GPT、本地模型)
我为什么用得少?因为我已经有 Cursor 和 Claude Code 了。Aider 的优势场景是"纯粹的终端工作流",比如在远程服务器上改代码,没有 GUI 的时候。
七、国产工具:不是"情怀",是真的有用
7.1 Kimi:长文档之王
Kimi 的长文本处理能力是真的强。我经常用它读论文:
这是 VVC 的 ALF 章节(PDF,60 页),请帮我:
1. 总结核心算法流程
2. 列出所有公式及其物理含义
3. 对比 HEVC ALF 的改进点
60 页 PDF 直接丢进去,它能把公式都提出来。
对我来说,Kimi 是"论文解析器"的定位,不是"编码助手"。
7.2 DeepSeek:便宜大碗
DeepSeek 的代码能力不错,而且便宜。
我把一些不敏感的、重复性的活儿交给它:
- 写正则表达式
- 生成测试数据
- 写 SQL
- 代码格式转换(Python 2 → 3)
注意:涉及公司代码的活儿,我不用任何云端 AI。 这是底线。
7.3 通义灵码:IDE 插件里的国产选项
如果你在不能翻墙的环境里工作,通义灵码是个可行选择。它集成在 IDE 里,中文理解好,响应快。但深度上跟 Cursor 还是有差距。
7.4 关于文心一言
我用得不多。写中文创意文案还行,技术上一般。就不多评价了。
八、开源模型:本地部署的那条路
如果你有数据敏感性要求,本地部署是唯一解。
我试过几个:
| Llama 3 8B | 8B | 能(消费级显卡) | 一般,写简单代码行 |
| Qwen2.5-Coder 7B | 7B | 能 | 代码不错,中文好 |
| DeepSeek-Coder 6.7B | 6.7B | 能 | 代码专用,不错 |
| Llama 3 70B | 70B | 不能(要 A100) | 好,但跑不动 |
现实一点说:消费级显卡能跑的模型,能力大概相当于 GPT-3.5 的水平。 做做代码补全、写写单元测试够用,复杂架构设计不行。
我的方案是"混合":敏感代码本地模型处理,非敏感用云端。
九、我不推荐的几类工具
9.1 “AI 一键生成 App”
这类工具的宣传语是"输入一句话,生成一个 App"。
我试过三个。生成的东西都是玩具级别:UI 丑、逻辑不完整、加个功能就崩。
但有一个例外场景:做 demo、做原型验证。如果你只是想快速验证一个想法,这类工具还挺快的。别指望它上生产。
9.2 “AI 写论文 / AI 代写”
学术不端,不用多说。
9.3 各种"AI 赚钱"工具
“用 AI 月入十万”——这玩意儿要么是卖课的,要么是坑。
我不否认有人用 AI 赚到钱了,但那不是因为工具,是因为人家本身就有能力。
9.4 “AI 女友”
……这个我就不评价了。浪费时间,真的。
十、工具选型的三个原则
写了这么多,总结一下我的选型原则:
原则一:主力只留一个。
不要七个工具都用。选一个主力(我选 Claude),把它用透。其他的按场景备着。
原则二:按场景选,不按"强弱"选。
- 长文理解 → Claude / Kimi
- 数学推理 → GPT-5
- IDE 内编码 → Cursor
- 重构整个项目 → Claude Code
- 便宜批量 → DeepSeek
原则三:能用免费的先用免费。
别一上来就订阅五个付费服务。先用免费额度试试,确认这个工具真的能提升你的效率,再掏钱。
我一个月的 AI 支出大概 60 美元(Claude Pro + Cursor Pro + 偶尔的 API 费用)。对一个程序员来说,这点钱换来的效率提升,划算。
第二部分 工作流设计:从"用工具"到"建系统"
十一、为什么"会用工具"不等于"有效率"
我见过很多人,AI 工具装了一堆,效率却没提升。
为什么?因为他们只是"零散地用",没有工作流。
举个例子。同样是让 AI 写一个函数:
没有工作流的人:
打开 ChatGPT → 打字"写个函数算 PSNR" → 复制代码 → 粘到 IDE → 跑 →
报错 → 复制错误回去 → 又给一版 → 再跑 → 还错 → 放弃,自己写
有工作流的人:
Cursor 里 Cmd+K → 给出上下文(输入类型、输出类型、边界条件)→
接受 → 跑测试(测试是 AI 提前写好的)→ 通过 → commit
差别在哪?在"上下文"和"验证闭环"。
下面我把我的工作流拆开讲。
十二、个人工作流:我的"三层 AI 架构"
我把 AI 的使用分成三层:
┌─────────────────────────────────────┐
│ 第三层:编排层(Orchestration) │ ← 任务规划、拆解、验收
├─────────────────────────────────────┤
│ 第二层:执行层(Execution) │ ← 写代码、改代码、跑测试
├─────────────────────────────────────┤
│ 第一层:查询层(Lookup) │ ← 查 API、查语法、查概念
└─────────────────────────────────────┘
12.1 第一层:查询层
这层最简单。遇到不会的 API、不记得的语法,直接问 AI。
我的习惯是让它给例子,别给解释:
Python 的 contextlib.ExitStack 怎么用?
直接给我 3 个实用的例子,不要给我讲概念。
为什么?因为概念我可以自己查文档,但"实际怎么写"是 AI 最擅长的。
12.2 第二层:执行层
这层是我用得最多的。核心是把任务描述清楚。
我总结了一个"任务描述模板":
## 背景
[这个项目是干嘛的,用什么技术栈]
## 当前状态
[相关文件在哪,现有代码是什么样]
## 我要做什么
[具体目标]
## 约束
– 不能引入新依赖
– 必须兼容 Python 3.9
– 保持现有代码风格
## 完成标准
[怎么算做完了]
这个模板看起来啰嗦,但它把 AI 的"猜测"降到了最低。
用这个模板之前,AI 经常给我一个"看起来对但用不了"的方案。用了之后,一次通过率从 40% 提到了 75%。
12.3 第三层:编排层
这层是最高级的,也是我最近半年才想明白的。
编排层的意思:不要一上来就让 AI 写代码,先让它帮你规划。
比如我要做"给视频编码器加个新的率失真优化策略",我的流程是:
第一步,让 AI 帮我拆解任务:
我要在 x265 里加一个新的 RDO 策略。请你:
1. 先梳理 x265 现有的 RDO 流程(涉及哪些文件、哪些函数)
2. 列出实现新策略需要改动的点
3. 给一个分阶段的实施计划
先不要写代码。
第二步,我自己审一遍这个计划。 AI 的计划经常有遗漏或者过度设计,我要把它改成一个"我认可的计划"。
第三步,逐项执行。 每一项都执行层去做,做完我 review。
第四步,验收。 跑完整的测试 + 人工对比 PSNR/码率曲线。
这个流程比"直接让 AI 写"慢吗?其实更快。因为直接写的话,方向错了就得推倒重来。
十三、团队工作流:AI 怎么进团队
13.1 我们团队的现状
我们组 8 个人。AI 使用情况大概是这样:
- 3 个人重度使用(Cursor + Claude Code)
- 3 个人中度使用(偶尔用 ChatGPT 查东西)
- 2 个人基本不用(老员工,抵触)
这个分布其实挺典型的。
13.2 我们踩过的坑
坑一:代码风格不一致
早期的时候,不同人用 AI 生成的代码风格差别巨大。
有人用 Google 风格,有人用 PEP8,有人用 AI 默认的"混搭风"。code review 时全是风格争论,真正的逻辑问题反而没人看。
解决:引入 ruff + black + pre-commit hook。风格问题交给工具,人只看逻辑。
# .pre-commit-config.yaml
repos:
– repo: https://github.com/astral–sh/ruff–pre–commit
rev: v0.6.0
hooks:
– id: ruff
args: [––fix]
– id: ruff–format
坑二:有人直接 copy-paste AI 代码,不理解
有个新人,提交了一个 PR,代码写得很漂亮,但 review 时问他"为什么这里用装饰器",他答不上来。
后来才知道是 AI 写的。
解决:我们立了个规矩——PR 描述里必须写"这段代码我是怎么想的"。如果是 AI 生成的,要写"AI 生成 + 我做了哪些修改 + 为什么"。
这个规矩不是为了抓谁偷懒,而是为了强制理解。
坑三:AI 生成的测试没有价值
早期 AI 生成的测试全是"happy path":
def test_add():
assert add(1, 2) == 3
这种测试有什么用?什么都测不出来。
解决:review 测试的时候,只看一件事——这个测试能不能测出 bug? 如果删掉被测函数的一行代码,测试还能过,那这个测试就是废的。
13.3 我们现在的团队规范
整理一下,我们现在的 AI 使用规范:
可以用 AI 的场景:
- 写单元测试(要人工 review,检查是否覆盖边界)
- 写文档、注释
- 代码格式转换、重构
- 写一次性脚本、工具
- 查 API、查概念
需要谨慎的场景:
- 核心业务逻辑(必须逐行 review)
- 安全相关代码(认证、加密、权限)
- 性能敏感的代码(AI 经常写出"看起来对但慢"的代码)
禁止的场景:
- 把公司代码粘贴到公共 AI 服务(合规问题)
- 用 AI 生成的内容直接上生产而不 review
- 用 AI 生成代码但写在自己名下而不标注
十四、公司级工作流:从小作坊到工程化
14.1 CI 里的 AI
我们在 CI 里加了两层 AI 检查:
第一层:AI code review(作为提示,不阻塞合并)
# 在 PR 上自动跑
– name: AI Review
run: |
python scripts/ai_review.py \\
–diff "$(git diff origin/main…HEAD)" \\
–output review.md
它会输出一份 review 意见,贴在 PR 评论里。作者可以选择采纳或忽略,但至少要回应。
第二层:安全扫描(阻塞合并)
– name: Security Scan
run: |
bandit -r src/
semgrep –config=p/owasp-top-ten src/
这层是硬的,有高危问题直接不让合。
14.2 文档自动化
我们做了个"文档自动生成"的流水线:
代码提交 → 提取 docstring → AI 生成文档草稿 → 人工审核 → 发布
为什么还要人工审核?因为 AI 生成的文档经常"说了等于没说":
process_frame(): 这个函数处理一帧数据。
废话。我要知道的是"怎么处理"、“有什么副作用”、“边界条件是什么”。
所以人工审核这步不能省。
14.3 一个失败的尝试:AI 自动修复线上 bug
我们试过让 AI 读监控告警 + 日志,然后自动提 PR 修复。
结果:一个月提了 12 个 PR,只有 1 个是对的。
为什么失败? 因为线上 bug 的根因经常在"业务语义"层面,不在代码层面。比如"用户下单失败"可能是支付渠道的问题,不是代码 bug。AI 看不到这个层面。
结论:AI 可以做"发现",不能做"决策"。
十五、Prompt 工程:别把它想得太玄
15.1 我对 Prompt 工程的理解
"Prompt 工程师"这个词被吹得很玄。我的理解很朴素:
Prompt 工程 = 把需求说清楚的能力。
这跟"跟同事描述需求"没什么本质区别。你如果能把需求跟人讲清楚,你就能把 Prompt 写好。
15.2 我常用的几个 Prompt 模式
模式一:角色 + 约束 + 输出格式
你是一个有 10 年经验的 Python 后端工程师。
任务:review 下面的代码。
约束:
– 只关注正确性和性能,不要讨论风格
– 每个问题给出具体的修改建议和代码
输出格式:
– 【严重】/【一般】/【建议】分级
– 每条包含:问题描述 + 代码位置 + 修复方案
模式二:Few-shot(给例子)
请按下面的格式,给我的函数写文档:
例子:
def add(a, b):
"""计算两个数的和。
Args:
a: 第一个加数
b: 第二个加数
Returns:
两数之和
Raises:
TypeError: 参数不是数字时
"""
现在请为下面的函数写文档:
[你的函数]
模式三:思维链(让它想清楚再说)
请先列出你的分析步骤,每一步都写出你的推理过程,
最后再给结论。不要跳步。
这个模式对复杂问题特别有用。让它"想清楚再说",准确率能提升不少。
模式四:反向提问
在回答之前,如果你觉得我的需求有任何不清楚的地方,
先问我,不要猜。
这个模式能大幅减少"答非所问"。
15.3 Prompt 的几个常见错误
错误一:太模糊
“帮我优化这段代码” —— 优化什么?速度?可读性?内存?
错误二:太啰嗦
有人喜欢写 500 字的 Prompt 描述一个简单需求。其实关键信息就三句话。
错误三:不给上下文
“这个函数为什么报错?” —— 什么函数?什么错误?什么环境?
错误四:一次问太多
“帮我写个函数、写测试、写文档、再帮我部署” —— 拆开来问,效果更好。
第三部分 踩坑实录:我用 AI 掉进过的那些坑
十六、坑一:幻觉——AI 一本正经地胡说八道
16.1 第一次被坑
2024 年 3 月,我要写一个 Python 脚本处理一批 YUV 文件。我问 AI:
“Python 里有没有直接读取 YUV 420 平面的库?”
它回答:
有,可以用 pyyuv 库,pip install pyyuv 然后 import pyyuv 就能用,支持 YUV420/422/444 所有格式。
我照着做了。
pip install pyyuv → 找不到这个包。
我回去质问它,它道歉:“抱歉,我搞错了,应该是 pyyuvlib。”
pip install pyyuvlib → 还是没有。
第三次,它说:“你可以用 yuvutils。”
还是没有。
最后我自己用 numpy 写的,20 行代码搞定。
16.2 幻觉的几种表现形式
后来我总结了 AI 幻觉的几种典型:
形式一:编造不存在的库/包
最常见。尤其是"听起来很合理"的名字,比如 pyyuv、fastjson2、pandas-pro。
形式二:编造不存在的 API
# AI 给的代码
import numpy as np
result = np.fast_psnr(a, b) # 这个函数不存在!
形式三:编造不存在的论文
我让 AI “找几篇关于 JND 编码的论文”,它给了 5 篇,我搜了一下,3 篇是编的,连作者名都是编的。
形式四:编造不存在的参数
# AI 给的
ffmpeg.input('in.mp4').output('out.mp4', preset='ultrafast', tune='film', crf=23, profile='high444')
profile='high444' 在某些 ffmpeg 版本里不叫这个名字。
16.3 怎么防幻觉
我的几条铁律:
第一,任何库名、API 名,先搜一下再用。
不要相信 AI 说的"有个库叫 XXX"。去 PyPI 搜,去 npm 搜。
第二,AI 给的代码必须跑。
哪怕看起来再简单,也要跑一遍。我见过 AI 写 list.sort() 返回值赋给变量的(sort 返回 None)。
第三,引用必须核实。
AI 给的论文、链接、出处,全部要自己搜一遍。
第四,让它自己标注不确定。
在 Prompt 里加一句:
如果你对某个 API 的存在性不确定,请明确标注"我不确定这个 API 是否存在",
不要编造。
这句话能减少一部分幻觉,但不能根除。
十七、坑二:上下文丢失——它在第五十轮的时候忘了第一轮
17.1 一个惨痛的经历
有一次我在设计一个视频分析服务,跟 AI 聊了大概 60 轮。
前面我明确说了:“我们用的是 PostgreSQL,不用 MySQL。”
聊到第 50 轮,它给我一段:
— 用 MySQL 的语法
ALTER TABLE videos MODIFY COLUMN duration INT;
我说:“我说了不用 MySQL。”
它道歉,重写。
第 55 轮,又来了一个 MySQL 语法。
这就是上下文丢失。 对话太长,早期的约束它"记不住"了。
17.2 我现在的应对方法
方法一:分段对话
不要一个对话干到底。一个任务一个对话,做完就开新的。
方法二:关键约束重复声明
如果对话必须很长,我会每隔几轮重复一次关键约束:
(重申:PostgreSQL,不用 MySQL;Python 3.9,不能用 3.10+ 语法)
方法三:定期让它"复述"
在继续之前,请先复述一遍我们到目前为止确定的所有技术约束和已做的决策。
这一步能立刻暴露它"忘记"了什么。
方法四:写成文件
如果内容太多,我会让 AI 把关键信息整理成一份 markdown,然后在新对话里把这个文件贴回去。
十八、坑三:过度设计——AI 是个"过度热心的实习生"
18.1 让它写个简单函数,它给你一个框架
我让 AI 写"读取配置文件":
写一个函数,读取 JSON 配置文件并返回 dict。
它给的:
import json
import os
import logging
from pathlib import Path
from typing import Dict, Any, Optional, Union
from dataclasses import dataclass
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ConfigError(Exception):
"""配置相关异常"""
pass
@dataclass
class ConfigLoader:
"""配置加载器"""
def __init__(self, path: Union[str, Path]):
self.path = Path(path)
self._cache: Optional[Dict[str, Any]] = None
def load(self) –> Dict[str, Any]:
if self._cache is not None:
return self._cache
try:
with open(self.path, 'r', encoding='utf-8') as f:
config = json.load(f)
except FileNotFoundError:
logger.error(f"配置文件不存在: {self.path}")
raise ConfigError(f"Config file not found: {self.path}")
except json.JSONDecodeError as e:
logger.error(f"JSON 解析失败: {e}")
raise ConfigError(f"Invalid JSON: {e}")
self._cache = config
return config
我要的是 5 行:
import json
def load_config(path):
with open(path, encoding='utf-8') as f:
return json.load(f)
这就是过度设计。 AI 倾向于"把简单问题复杂化",因为它看过太多"企业级代码"。
18.2 怎么治它
在 Prompt 里明确约束:
约束:
– 只写这一个函数,不要定义类
– 不要引入 logging
– 不要写自定义异常
– 不要做缓存
– 代码不超过 10 行
明确说"不要什么",比说"要什么"更有效。
十九、坑四:安全与隐私——最容易被忽略的坑
19.1 一个真实的教训
我一个朋友,在某个大厂做后端。有次他把一段包含内部 API 密钥的代码粘贴到 ChatGPT,让 AI 帮忙调试。
结果那段对话……算了,具体后果我不说了。总之他很惨。
19.2 我的红线
凡是有以下内容的,绝不粘贴到公共 AI:
- 公司的源代码(尤其是核心算法)
- API 密钥、密码、Token
- 客户数据、用户数据
- 内部文档、架构图
- 未发布的商业计划
19.3 那怎么用 AI 帮忙
方法一:脱敏
把敏感信息替换成占位符:
# 原始
API_KEY = "sk-abcdef123456"
DB_URL = "postgresql://admin:pass@10.0.1.5:5432/prod"
# 脱敏后
API_KEY = "sk-REDACTED"
DB_URL = "postgresql://user:pass@<host>:5432/<db>"
方法二:抽象化
不要粘贴完整代码,只粘贴"最小可复现的抽象版本":
# 不要贴公司代码,写一个结构相同但内容不同的版本
def core_algorithm(data):
# 这里是核心逻辑,我用一个等价的模拟版本
...
方法三:本地模型
真正敏感的代码,用本地部署的模型(Qwen2.5-Coder、Llama 3)。虽然能力差点,但数据不出内网。
方法四:企业版服务
大多数 AI 服务有企业版,承诺不用你的数据训练。如果有预算,走企业版。
二十、坑五:依赖陷阱——它给你装了一堆你没要的东西
20.1 一个夸张的例子
我让 AI “写个简单的 HTTP 请求”:
import aiohttp
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential
from pydantic import BaseModel
class Response(BaseModel):
...
@retry(stop=stop_after_attempt(3), wait=wait_exponential())
async def fetch(url):
...
我就想发个 GET 请求,它给我引入了 4 个第三方库。
20.2 为什么这是个坑
我的原则:能用标准库解决的,绝不引入第三方库。
在 Prompt 里加一句:
优先使用 Python 标准库。如果需要第三方库,请先说明为什么标准库做不到。
20.3 依赖审计
我现在定期跑:
pip-audit # 检查已知漏洞
pip list –outdated # 检查过期依赖
AI 生成的代码引入的依赖,我会专门看一眼。
二十一、坑六:风格漂移——你的代码库变成了"AI 大杂烩"
21.1 现象
AI 生成的代码有自己的"风格":
- 变量名偏长偏描述性(processed_user_input_data)
- 喜欢用 type hints(好事)
- 喜欢写 docstring(有时是废话)
- 喜欢在函数内 import
- 喜欢用 dataclass 而不是普通类
如果你不统一风格,半年后你的项目就是"万国代码博览会"。
21.2 解决方案
方案一:给 AI 看你的代码风格
在 Prompt 里贴一段你项目里"最典型"的代码:
请参考下面的代码风格来写:
[贴一段你的代码]
要求:命名风格、注释风格、错误处理方式都要跟这个保持一致。
方案二:用 formatter 兜底
black / ruff / gofmt / rustfmt —— 让工具处理格式。
方案三:linter 规则固化
把团队规范写成 linter 规则:
# ruff.toml
[lint]
select = ["E", "F", "I", "N", "UP", "B", "SIM"]
line-length = 100
二十二、坑七:版本幻觉——它以为你在用三年前的框架
22.1 现象
AI 的训练数据有截止时间。所以:
- 它可能给你一个已经废弃的 API
- 它可能不知道新版本的变化
- 它可能给你"过时的最佳实践"
比如 FastAPI 早期 @app.on_event("startup") 是标准写法,后来官方推荐 lifespan 上下文管理器。但很多 AI 还在给 on_event。
22.2 我的应对
第一,在 Prompt 里明确版本:
环境:Python 3.12, FastAPI 0.115, SQLAlchemy 2.0
请使用这些版本的最新推荐写法。
第二,让它查官方文档:
如果 AI 有联网能力(比如 Claude 的 web search),让它去查最新文档。
第三,自己核实关键 API。
新框架的核心 API,我自己去看一遍官方文档。
二十三、坑八:测试假象——看起来很全,实际没用
23.1 现象
AI 写的测试有个特点:覆盖率很高,但测不出 bug。
def test_add():
"""测试加法"""
assert add(1, 2) == 3
这个测试覆盖率 100%,但如果 add 实现里有个溢出 bug,它测不出来。
23.2 一个真实的例子
我让 AI 给一个 PSNR 计算函数写测试:
def psnr(original, compressed, max_value=255):
mse = np.mean((original.astype(float) – compressed.astype(float)) ** 2)
if mse == 0:
return float('inf')
return 10 * np.log10(max_value ** 2 / mse)
AI 写的测试:
def test_psnr_identical_images():
img = np.random.randint(0, 256, (100, 100), dtype=np.uint8)
assert psnr(img, img) == float('inf')
def test_psnr_normal():
a = np.zeros((10, 10), dtype=np.uint8)
b = np.full((10, 10), 10, dtype=np.uint8)
assert psnr(a, b) > 0
看起来没问题。但它没测:
- 不同 dtype(float 输入会怎样)
- 空数组
- 形状不匹配
- max_value 参数不生效的情况
- 极端值(全 0 和全 255)
后来我自己补了这些测试,发现了一个真 bug:当输入是 float 类型且值域是 [0,1] 时,max_value=255 是不对的,应该传 1.0。这个 bug 在生产环境导致过 PSNR 计算错误。
23.3 我现在的要求
AI 写测试,我必须要求它列出边界条件:
请写测试,并且:
1. 先列出这个函数的所有边界条件
2. 每个边界条件至少一个测试
3. 不要只测 happy path
4. 每个测试都要能"测出 bug"——如果你把实现改错了,这个测试要能挂
二十四、坑九:盲目信任——“AI 说的应该没错吧”
24.1 这个坑最危险
前面那些坑都是技术坑,这个坑是心理坑。
AI 说话很有自信。它不会说"我猜",它会说"答案是 XXX"。
很多人在这种自信面前,放弃了判断。
24.2 一个案例
我见过一个同事,AI 告诉他"Python 的 GIL 在 3.13 里已经移除了"。
他信了,然后写了一个依赖多线程并行计算的模块。
结果当然不行。GIL 只是"可以关闭"(通过 free-threaded build),不是"已经移除",而且默认还是开启的。
24.3 保持怀疑
我对 AI 的所有"事实性陈述"都保持怀疑,尤其是:
- 具体的数字(性能提升多少、内存占用多少)
- “XX 已经废弃/移除/改变了”
- “XX 是最好的/唯一的”
- 涉及版本、时间的信息
核实成本很低,不核实的代价很高。
二十五、坑十:能力退化——我自己变得"不会写字"了
25.1 一个让我警觉的时刻
去年年底,我要写一个简单的二分查找。
我下意识地打开了 AI。
写到一半我突然停下来——我为什么不用自己的脑子写?
那之后我开始注意这个问题:用了 AI 之后,很多"基本功"我确实变弱了。
- 常用 API 不记得了(反正可以问 AI)
- 算法模板不记得了(反正可以问 AI)
- 甚至有些英文单词拼不出来了(IDE 自动补全)
25.2 我现在的做法
做法一:核心能力必须手写
- 算法题:手写
- 核心业务逻辑:先自己设计
- 关键架构:先自己想
做法二:定期"戒断"
每个月有一两天,我完全不用 AI 写代码。手写,找回感觉。
做法三:把 AI 当"放大器",不当"替代品"
AI 放大你的能力,但不能替代你的能力。你如果本来能力是 0,AI 放大还是 0。
第四部分 编程语言与工具链:AI 在各个语言里的真实表现
二十六、Python:AI 的"母语"
26.1 为什么 Python 效果最好
AI 在 Python 上的表现明显好于其他语言。原因很简单:训练数据多。
GitHub 上 Python 的代码量、Stack Overflow 上 Python 的问题量,都是最多的。
26.2 我用 AI 写 Python 的几个真实场景
场景一:数据处理的样板代码
# 我:读这个 CSV,按 user_id 分组,算每个用户的总金额,输出 top 10
import pandas as pd
df = pd.read_csv('data.csv')
result = (
df.groupby('user_id')['amount']
.sum()
.sort_values(ascending=False)
.head(10)
)
print(result)
这种 pandas 的链式调用,AI 写得比我快。
场景二:类型注解
我早期写的 Python 项目没有 type hints。现在让 AI 批量加:
# 之前
def process(data, config):
...
# 之后
def process(data: pd.DataFrame, config: Dict[str, Any]) –> Optional[pd.DataFrame]:
...
场景三:异步代码
import asyncio
import aiohttp
async def fetch_all(urls: List[str]) –> List[str]:
async with aiohttp.ClientSession() as session:
tasks = [fetch_one(session, url) for url in urls]
return await asyncio.gather(*tasks)
26.3 Python 里 AI 常犯的错
错误一:忘了 if __name__ == '__main__'
多进程代码里忘了这个,Windows 上直接爆。
错误二:可变默认参数
# AI 有时候会写
def append_to(item, target=[]):
target.append(item)
return target
经典坑,AI 也会犯。
错误三:过度使用 list comprehension
AI 喜欢炫技:
result = [[y for y in row if y > 0] for row in [[x for x in col if x is not None] for col in matrix]]
可读性为零。我会让它改成循环。
错误四:忽略 GIL
AI 有时会让你"用多线程加速 CPU 密集任务"。这在 Python 里是错的。
二十七、C/C++:AI 在这里最"不稳"
27.1 为什么
C++ 的复杂度太高:模板元编程、RAII、移动语义、完美转发……AI 很难全面掌握。
而且 C++ 的"正确写法"依赖具体场景(性能优先还是可读性优先),AI 容易给出"教科书式"但实际不合适的答案。
27.2 一个真实的例子
我让 AI 优化一段视频处理的内循环:
// 原始
for (int i = 0; i < width * height; i++) {
out[i] = (in[i] + offset) * scale;
}
它给的优化:
// AI 版本
std::transform(in, in + width * height, out,
[offset, scale](int v) { return (v + offset) * scale; });
这个改动实际上可能更慢。因为 lambda 在没内联的情况下有调用开销,而且编译器对 std::transform 的向量化能力不一定比对裸循环强。
在视频编码的编码器里,这种改动是灾难性的——PSNR 一模一样,但速度可能掉 10%。
27.3 C++ 里我信任 AI 的地方
- 写测试:Catch2 / GoogleTest 的样板代码
- 写构建配置:CMakeLists.txt(AI 写得比我还熟)
- 解释复杂模板:让 AI 解释模板元编程
- 写工具函数:非性能敏感的部分
27.4 C++ 里我不信任 AI 的地方
- 性能敏感的循环:必须自己写 + profile
- 并发代码:内存序、原子操作,AI 经常出错
- 内存管理:智能指针的误用
- SIMD 内联汇编:AI 基本不会
27.5 关于 SIMD 的一个例子
我做过一个 CABAC 的 SIMD 优化。我让 AI 试着用 SSE/AVX intrinsic 重写,它给的代码:
__m128i a = _mm_loadu_si128((__m128i*)ptr);
__m128i b = _mm_add_epi16(a, offset);
// …
看起来对,但有几个问题:
最终这版代码我没用,还是自己写的。
二十八、Rust:AI 表现不错,但所有权是个坎
28.1 优点
Rust 的编译器错误信息特别详细,这反而"帮助"了 AI——它可以根据错误信息自我修正。
我让 AI 写 Rust 代码,通常它能给一个"接近能编译"的版本,然后根据编译错误迭代几次就对了。
28.2 坎在哪
所有权和生命周期是 AI 最容易出错的地方。
// AI 经常写出这种
fn process(data: &Vec<Data>) -> &Data {
&data[0] // 生命周期错误
}
28.3 我的用法
- 让 AI 写业务逻辑(不含复杂借用)
- 复杂生命周期问题,自己解决
- 让 AI 解释编译器的生命周期提示
二十九、Go:AI 表现最稳的语言之一
Go 的设计哲学"简单",正好适合 AI。
29.1 Go 的样板代码,AI 写得又快又好
type Server struct {
db *sql.DB
logger *log.Logger
}
func NewServer(db *sql.DB, logger *log.Logger) *Server {
return &Server{db: db, logger: logger}
}
func (s *Server) HandleRequest(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
// …
}
Go 的 if err != nil 样板,AI 写起来毫不费力。
29.2 一个 Go 里 AI 常犯的错
忘记处理 goroutine 泄漏
// AI 写的
func fetchAll(urls []string) {
for _, url := range urls {
go fetch(url) // 没有等待,main 退出就全没了
}
}
没有 WaitGroup,没有 context 取消,goroutine 泄漏。
三十、JavaScript / TypeScript:前端党的福音
30.1 TS 的类型系统帮了 AI
TypeScript 的类型检查给了 AI 一个"反馈回路"。类型错了,编译器会报,AI 会修。
30.2 前端场景
- 写 React 组件:AI 表现很好
- 写 CSS:AI 表现一般(审美不行)
- 写构建配置(Vite/Webpack):AI 表现好
- 写复杂的状态管理:AI 一般
30.3 一个真实的例子
我让 AI 写一个"无限滚动的列表",它的第一版:
function InfiniteList({ fetchMore }: Props) {
const [items, setItems] = useState<Item[]>([]);
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
fetchMore().then(newItems => setItems(prev => […prev, …newItems]));
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return <div>{items.map(item => <ItemRow key={item.id} {…item} />)}</div>;
}
问题:没有防抖,也没有 loading 锁。快速滚动会触发几十次请求。
这个 bug 很典型——AI 写"能跑"的代码没问题,但"生产可用"需要你自己补。
三十一、编译器与构建系统:AI 的主场
31.1 CMake:AI 比我熟
我承认,CMake 我写得不如 AI。这玩意儿语法反人类,但 AI 看过太多 CMakeLists.txt。
cmake_minimum_required(VERSION 3.20)
project(video_encoder CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3 -march=native)
endif()
find_package(OpenCV REQUIRED)
add_executable(encoder src/main.cpp src/encoder.cpp)
target_link_libraries(encoder PRIVATE OpenCV::opencv)
这种配置,AI 一分钟给我,我自己写要查半天文档。
31.2 编译器优化:AI 能解释但不会"发明"
我经常让 AI 解释 -O3 和 -O2 的差别、-march=native 到底开了什么指令集。
这些它能解释得很好。
但"如何让这段代码被编译器自动向量化"这种问题,AI 给的建议经常是对的但不够深。
31.3 一个真实的调优案例
我有一段代码,GCC 怎么都不向量化。AI 帮我分析:
void process(const int* __restrict__ in, int* __restrict__ out, int n) {
for (int i = 0; i < n; i++) out[i] = in[i] * 2;
}
加上之后,GCC 成功向量化,速度提升 2.3 倍。
这个建议是对的。 AI 在"诊断编译器行为"这件事上,确实有用。
三十二、调试:AI 是个不错的"陪诊医生"
32.1 调试的两种用法
用法一:让它猜可能的原因
我的程序在跑一段时间后报 "Segmentation fault",
用 gdb 看栈是乱的。可能的原因有哪些?
它会列出:栈溢出、野指针、多线程竞争、ABI 不匹配……
用法二:让它"读"错误信息
这个编译错误我看不懂:
error: no matching function for call to 'std::vector<int>::push_back(const int&, int)'
它会解释:push_back 只接受一个参数,你传了两个。
32.2 但 AI 不能替代 gdb
真正复杂的 bug,还是要用工具:
- gdb/lldb:断点、看栈、看内存
- valgrind:内存泄漏、越界
- perf:性能分析
- strace:系统调用跟踪
AI 可以帮你"理解"这些工具的输出,但不能替代它们。
32.3 一个我用 AI 解决 bug 的真实案例
我遇到一个"偶发崩溃",几天内只出现一次。
我把崩溃时的 core dump 信息、日志、相关代码都给 AI,它分析出:
这个崩溃点在 memcpy,但调用栈显示是在一个 std::string 的析构里。
结合你说"只在多线程下偶发",我怀疑是一个 string 在被一个线程析构的同时,
另一个线程还在读它——典型的数据竞争。
检查一下是否有跨线程共享的 string 没有加锁。
这个推断是对的。 我回去检查代码,果然发现一个成员 string 被两个线程同时访问。
第五部分 操作系统、内存与网络:AI 帮你补底层课
三十三、为什么程序员必须懂底层
我见过太多"API 工程师"——会调框架,但一遇到性能问题、内存问题就懵。
AI 能帮你补这块,但前提是你知道该问什么。
三十四、Linux:AI 是很好的"命令生成器"
34.1 我最常让 AI 生成的 Linux 命令
帮我写一个命令:找出当前目录下所有大于 100MB 的文件,
按大小排序,显示前 20 个。
find . -type f -size +100M -exec ls -lh {} \\; | awk '{print $5, $9}' | sort -rh | head -20
或者更现代的:
du -ah . | sort -rh | head -20
34.2 一些 AI 教我的命令技巧
# 1. 查看进程占用的文件
lsof -p PID
# 2. 查看端口占用
ss -tulpn | grep :8080
# 3. 实时监控 IO
iostat -x 1
# 4. 查看系统调用
strace -f -e trace=network ./program
# 5. 找出目录里文件数量最多的
find . -type d -exec sh -c 'echo "$(find "$1" -maxdepth 1 | wc -l) $1"' _ {} \\; | sort -rn | head
34.3 一个真实场景:线上 CPU 100% 排查
线上服务 CPU 突然 100%,我的排查流程:
# 1. 找到最耗 CPU 的进程
top -H -p $(pgrep -f myapp)
# 2. 找到该进程里最耗 CPU 的线程
# 记下线程 ID,转成十六进制
printf "%x\\n" 12345
# 3. 用 jstack / gdb 看那个线程在干嘛
jstack 12345 | grep -A 30 "nid=0x3039"
这一套我早期是死记硬背的。现在直接问 AI:"线上 Java 服务 CPU 100%,怎么排查?"它能秒给我流程。
三十五、内存:从"栈和堆"到"内存对齐"
35.1 AI 帮我讲清楚的概念
我让 AI 解释"为什么结构体的大小不等于成员大小之和":
struct A {
char a; // 1
int b; // 4
char c; // 1
};
// sizeof(struct A) = 12,不是 6
AI 的解释:
因为内存对齐。CPU 访问内存是按"字"访问的,比如 4 字节对齐时,
一个 int 的起始地址必须是 4 的倍数。所以编译器会在 char a 后面
填充 3 字节,让 int b 对齐到 4 的倍数。
布局:
[a][pad][pad][pad][b ][b ][b ][b ][c][pad][pad][pad]
0 1 2 3 4 5 6 7 8 9 10 11
总共 12 字节。
这个解释很清楚。
35.2 优化内存布局
AI 还能帮我优化:
// 优化前:12 字节
struct A {
char a;
int b;
char c;
};
// 优化后:8 字节
struct A {
int b;
char a;
char c;
};
把大的成员放前面,小的放后面,可以减少填充。
在视频编码里,这种优化很重要——一个结构体被创建几百万次,省 4 字节就是几 MB。
35.3 内存对齐的实际影响
我做过一个实验:同一个算法,一个用对齐内存,一个用非对齐内存,性能差了多少?
结果是大约 15%。这个差距在编解码器里,就是能不能实时编码的区别。
用 aligned_alloc / posix_memalign / C++17 的 aligned new 可以控制对齐。
三十六、网络:TCP/IP 到 HTTP/3
36.1 AI 帮我讲清楚 TCP 三次握手
虽然我早就知道,但 AI 能讲得更清楚:
请解释 TCP 三次握手,并说明"为什么是三次不是两次"。
它的回答:
三次握手的目的是:双方都确认对方的收发能力正常。
- 第一次(SYN):客户端 → 服务端。服务端知道"客户端能发"。
- 第二次(SYN-ACK):服务端 → 客户端。客户端知道"服务端能收也能发"。
- 第三次(ACK):客户端 → 服务端。服务端知道"客户端能收"。
如果只有两次:服务端发完 SYN-ACK 就认为连接建立了,
但此时它不知道客户端是否收到了自己的 SYN-ACK。
而且旧的、延迟的 SYN 包可能导致服务端建立无效连接。
"为什么是三次不是两次"这个解释,是我见过最清楚的。
36.2 HTTP/2 和 HTTP/3
我让 AI 做过一个对比:
| 传输层 | TCP | TCP | QUIC(UDP) |
| 多路复用 | 无 | 有 | 有 |
| 队头阻塞 | 有 | TCP 层有 | 无 |
| 头部压缩 | 无 | HPACK | QPACK |
| 连接建立 | 1-RTT | 1-RTT | 0-RTT |
HTTP/3 用 QUIC(基于 UDP)彻底解决了队头阻塞,这是最大的改进。
36.3 一个实际调优的例子
我们的视频上传服务,之前用 HTTP/1.1,用户抱怨"上传慢"。
后来切到 HTTP/2,多路复用生效,同一个小区的用户并发上传不再互相阻塞。
再后来试了 HTTP/3,在弱网环境下(丢包率 5%)表现明显更好——因为 QUIC 的连接建立更快,且丢包只影响单个流。
整个过程我大量用 AI 查资料、做对比、写配置。
三十七、文件系统与 IO
37.1 一次关于 IO 的优化
我们的服务要写大量小文件(视频切片)。最初的做法是一个个 write()。
AI 建议:
小文件写入频繁时,使用缓冲(buffered IO)或者直接 mmap。
另外,考虑用 O_DIRECT 绕过页缓存,或者批量写入。
我们试了批量写入(攒到 4MB 再写),IOPS 从 2000 提升到 20000。
37.2 页缓存的理解
AI 帮我理解了一个概念:Linux 的页缓存(page cache)。
- 你 write() 的数据先进页缓存,不是直接落盘
- 页缓存由内核管理,内存不够时会刷盘
- fsync() 强制刷盘
所以"写完就断电"会丢数据——除非你 fsync。
这一条在写"数据不能丢"的服务时极其重要。
三十八、信号与进程
38.1 一个坑
import signal
def handler(signum, frame):
print("Received signal", signum)
signal.signal(signal.SIGTERM, handler)
这段代码看起来没问题。但如果你在 handler 里做复杂操作(比如打印、加锁),可能死锁。
AI 提醒我:
signal handler 里只能调用"async-signal-safe"的函数。
printf 不是 async-signal-safe 的(它内部可能加锁)。
正确做法是:在 handler 里只设置一个 flag,主循环里检查这个 flag。
这是个很深的坑,AI 能提醒,说明它确实"读过"这些内容。
第六部分 数据库与存储:AI 帮我少写很多 SQL
三十九、我和数据库的十年
我做了六年后端,数据库是绕不开的。
最早我是"教科书派":什么都要三范式,看到冗余字段就难受。
后来我学乖了。范式是给写入优化的,反范式是给读取优化的。 你的业务是读多还是写多,决定了你该怎么设计。
AI 在数据库这块帮我的地方主要有三个:写复杂 SQL、优化查询、设计表结构。
四十、复杂 SQL:从 5 分钟到 5 秒
40.1 一个真实的复杂查询
需求:找出每个部门薪资排名前 3 的员工。
我自己写的话,得想一下窗口函数怎么写。AI 直接给我:
WITH ranked AS (
SELECT
e.id,
e.name,
e.salary,
d.name AS department,
DENSE_RANK() OVER (
PARTITION BY e.department_id
ORDER BY e.salary DESC
) AS rk
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE e.active = TRUE
)
SELECT * FROM ranked WHERE rk <= 3 ORDER BY department, rk;
用 DENSE_RANK 而不是 ROW_NUMBER,这个细节很关键——如果两个人薪资相同,ROW_NUMBER 会给不同排名,DENSE_RANK 会给相同排名。这符合"排名前 3"的业务语义。
AI 还会主动解释为什么选 DENSE_RANK。 这个我很喜欢。
40.2 窗口函数:AI 的强项
窗口函数是 SQL 里最难的部分。AI 在这方面比我强。
— 计算每个用户的累计消费金额
SELECT
user_id,
order_date,
amount,
SUM(amount) OVER (
PARTITION BY user_id
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_amount
FROM orders;
— 计算环比增长
SELECT
month,
revenue,
LAG(revenue) OVER (ORDER BY month) AS prev_revenue,
ROUND(
(revenue – LAG(revenue) OVER (ORDER BY month))::numeric
/ NULLIF(LAG(revenue) OVER (ORDER BY month), 0) * 100, 2
) AS growth_pct
FROM monthly_revenue;
这些我都能写,但想的时间比 AI 长。
四十一、SQL 优化:AI 是个不错的"顾问"
41.1 一个真实的优化
— 优化前
SELECT * FROM orders
WHERE user_id IN (
SELECT user_id FROM users WHERE created_at > '2025-01-01'
);
AI 的分析:
IN 子查询在 MySQL 早期版本里会被"物化"成临时表,
数据量大时性能差。改成 JOIN 可以利用索引。
但注意:如果子查询结果集很小,IN 反而更快。
不要无条件改成 JOIN。
它给的不是"标准答案",而是"有条件的建议"。 这才是真正的专家。
41.2 索引:AI 教我的细节
细节一:复合索引的最左前缀原则
CREATE INDEX idx_a_b_c ON t(a, b, c);
这个索引能加速:
- WHERE a = ?
- WHERE a = ? AND b = ?
- WHERE a = ? AND b = ? AND c = ?
不能加速:
- WHERE b = ? (跳过 a)
- WHERE c = ? (跳过 a、b)
细节二:索引不是越多越好
每个索引都要在写入时维护。索引太多,写入会变慢。
细节三:区分度低的字段不值得建索引
性别字段(只有男/女),建索引基本没用。
细节四:部分索引(PostgreSQL)
CREATE INDEX idx_active_users ON users(email) WHERE active = TRUE;
只给"活跃用户"建索引,索引体积小很多。
41.3 执行计划:怎么看
EXPLAIN ANALYZE SELECT ...;
AI 能帮我解读:
- Seq Scan:全表扫描,数据量大时要警惕
- Index Scan:走索引,好
- Bitmap Heap Scan:适合中等选择性
- Nested Loop:小表驱动大表时好
- Hash Join:大表 join 时好
- Sort + cost 很高:考虑加索引避免排序
关键看三个东西:实际行数 vs 估算行数、cost 值、有没有 Seq Scan。
四十二、表结构设计:AI 的"经验"很有用
42.1 一个设计咨询
我要设计一个"用户行为日志表",特点:
– 每天新增 5000 万行
– 主要按 user_id 和时间范围查询
– 保留 90 天
– 需要统计类查询(按天聚合)
请给表结构设计和分区方案建议。
AI 的方案:
这就是"有经验的回答"。 每一条都是实战总结。
42.2 反范式的一个真实案例
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
user_name VARCHAR(100), — 冗余字段
user_phone VARCHAR(20), — 冗余字段
total_amount DECIMAL(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
为什么冗余 user_name 和 user_phone?
因为订单列表要显示用户名和手机号。如果每次都 join users 表,在订单量大的时候性能很差。
代价是:用户改了名字,历史订单里的名字不会变。
这在业务上其实是对的——订单是"当时的快照",用户改名字不应该影响历史订单。
这个道理我想了很久才想明白,AI 一句话就点透了:
判断标准:这个字段是"实体的属性"还是"事件的快照"?
如果是快照,就该冗余。
四十三、NoSQL:什么时候该用,什么时候不该
43.1 我的观点
90% 的场景,PostgreSQL 就够了。
PostgreSQL 支持 JSONB、全文检索、地理数据、数组类型……基本上你能想到的它都有。
不要因为"大数据"三个字就上 MongoDB,不要因为"缓存"就上 Redis,不要因为"搜索"就上 Elasticsearch。
先用关系型数据库,遇到真正的瓶颈再换。
43.2 Redis 的正确用法
Redis 我常用的场景:
43.3 Redis 的坑
坑一:大 key
一个 key 存了几百 MB,操作时会阻塞整个 Redis。
坑二:缓存雪崩
大量 key 同时过期,请求全打到数据库。
解决:过期时间加随机值。
坑三:缓存穿透
查询不存在的数据,每次都打到数据库。
解决:布隆过滤器,或者缓存空值。
坑四:缓存击穿
热点 key 过期瞬间,大量请求打过来。
解决:互斥锁,或者热点 key 永不过期 + 后台更新。
这四个"坑",AI 能一次给我讲清楚。 我用了很久才在实践中分别遇到。
第七部分 云原生与运维:AI 让 DevOps 更"平民化"
四十四、Docker:AI 写的 Dockerfile 比我的好
44.1 从"能跑"到"生产级"
我早期的 Dockerfile:
FROM python:3.11
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
这个能跑,但有一堆问题:镜像大、构建慢、有安全风险。
AI 优化后的:
FROM python:3.11-slim
WORKDIR /app
# 先复制依赖清单,利用 Docker 层缓存
COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt
# 再复制代码(代码改动频繁,放后面)
COPY . .
# 非 root 用户运行
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
CMD ["python", "main.py"]
四个优化点:
44.2 多阶段构建
AI 教我的多阶段构建:
# 构建阶段
FROM python:3.11 AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install –prefix=/install -r requirements.txt
# 运行阶段
FROM python:3.11-slim
COPY –from=builder /install /usr/local
COPY . /app
WORKDIR /app
CMD ["python", "main.py"]
这样编译工具链只留在 builder 阶段,最终镜像只有运行时需要的东西。
44.3 Docker 的"哲学"
我跟 AI 讨论过一个话题:Docker 的本质是什么?
AI 的总结我很认同:
Docker 的本质是把"环境"变成"交付物"。
以前你交付代码,运维要配环境。
现在你交付镜像,环境跟着代码走。
"在我机器上能跑"这句话,从此消失了。
四十五、Kubernetes:YAML 地狱的救星
45.1 K8s 的痛
K8s 的 YAML 又长又啰嗦。一个 Deployment 就要写 40 行。
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
– name: myapp
image: myapp:1.0.0
ports:
– containerPort: 8000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
AI 可以一键生成这种 YAML。我只需要描述需求。
45.2 Helm:模板化
# values.yaml
replicaCount: 3
image:
repository: myapp
tag: "1.0.0"
# templates/deployment.yaml
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
– name: myapp
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
AI 写 Helm Chart 也很熟练。
45.3 我对 K8s 的真实看法
K8s 是给"有规模"的团队用的。
如果你只有 3 个服务、2 台机器,用 Docker Compose 就够了。上 K8s 是给自己找麻烦。
我见过太多团队,为了"技术先进"上 K8s,结果没人懂运维,出故障时抓瞎。
技术选型要看团队能力,不是看技术趋势。
四十六、CI/CD:AI 让流水线更容易维护
46.1 GitHub Actions
AI 写的流水线比我的完善:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu–latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
steps:
– uses: actions/checkout@v4
– uses: actions/setup–python@v5
with:
python-version: ${{ matrix.python–version }}
– uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}–pip–${{ hashFiles('**/requirements.txt') }}
– run: pip install –r requirements.txt
– run: ruff check .
– run: mypy .
– run: pytest ––cov=. ––cov–report=xml
它自动加了:矩阵测试(多版本)、依赖缓存、覆盖率报告。 这些我早期都想不到。
46.2 GitOps
AI 教我的概念:
GitOps 的核心是"Git 是唯一真相源"。
你不直接 kubectl apply,而是改 Git 仓库,由 ArgoCD 自动同步。
好处:所有变更可追溯、可回滚、可审计。
46.3 一个真实的教训
我们的 CD 流水线,早期是"直接 deploy 到生产"。
有一次一个小 bug 上了生产,服务挂了 20 分钟。
后来加了"灰度发布":先发 5% 流量,观察 10 分钟,没问题再全量。
这个流程 AI 帮我写出了完整的配置。如果没有 AI,我可能得研究一整天。
四十七、监控告警:从"出事了才知道"到"提前发现"
47.1 三个支柱
可观测性有三根支柱:Metrics、Logs、Traces。
Metrics(指标):Prometheus + Grafana
groups:
– name: app
rules:
– alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 5m
annotations:
summary: "错误率超过 5%"
Logs(日志):ELK / Loki
Traces(链路):Jaeger / Tempo
47.2 SRE 的核心原则
AI 给我总结的:
47.3 一个告警配错的故事
我早期配置的告警是:“CPU 使用率超过 80% 就告警”。
结果每天收到几十条告警,全是没用的。后来就把告警关了——这就是"告警疲劳"。
AI 给的建议:
不要告警"资源使用率",要告警"资源使用率导致的业务影响"。
CPU 80% 不是问题,如果 P99 延迟正常的话。
应该告警的是:“P99 延迟 > 500ms 且持续 5 分钟”。
这个思路转变很重要。
第八部分 性能优化与并发:AI 帮我少走弯路
四十八、性能优化的方法论
48.1 我的四步法
AI 在第二步和第三步帮我最多。
48.2 一个真实的坑:优化错了地方
我早期写过一个数据处理脚本,跑得很慢。
我以为是"算法不够好",花了两天优化核心算法,从 O(n²) 优化到 O(n log n)。
结果——一点没快。
后来用 profiler 一看,90% 的时间花在读文件上,不是算法。
教训:先测量,再优化。
AI 的建议很直接:
不要凭直觉优化。先用 cProfile 跑一遍,
把 sorted by cumulative time 的前 20 个函数发给我看。
48.3 cProfile 的使用
import cProfile
import pstats
profiler = cProfile.Profile()
profiler.enable()
main()
profiler.disable()
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(20)
48.4 line_profiler:逐行分析
# pip install line_profiler
@profile
def slow_function():
data = load_data() # 这行可能很慢
processed = process(data) # 或者这行
save(processed)
kernprof -l -v script.py
输出会告诉你每一行执行了多少次、花了多少时间。
AI 帮我解读过一次输出,指出瓶颈在一个"看起来无害"的字符串拼接上——循环里 result += s,Python 里字符串不可变,每次都要新建对象。改成 "".join(parts) 后快了 20 倍。
四十九、数据结构的选择:AI 帮我避坑
49.1 一个经典的坑
# 慢
def count_common(list_a, list_b):
count = 0
for a in list_a:
if a in list_b: # list 的 in 是 O(n)
count += 1
return count
# 时间复杂度:O(n*m)
# 快
def count_common(list_a, list_b):
set_b = set(list_b)
return sum(1 for a in list_a if a in set_b)
# 时间复杂度:O(n+m)
n = m = 10000 时,第一个要 1 亿次比较,第二个只要 2 万次。
AI 一眼就看出问题了。 但如果我自己写,可能会"顺手"就这么写了。
49.2 Python 里的数据结构复杂度
AI 给我整理的一张表:
| 索引访问 | O(1) | O(1) | – | O(n) |
| 查找 | O(n) | O(1) | O(1) | O(n) |
| 插入(尾部) | O(1)* | O(1)* | O(1)* | O(1) |
| 插入(头部) | O(n) | – | – | O(1) |
| 删除 | O(n) | O(1) | O(1) | O(1) |
*平均情况,最坏情况可能 O(n)(哈希冲突)
需要频繁在头部插入删除,用 deque。 这个我早期一直用 list,性能很差。
五十、缓存:最有效的优化
50.1 缓存的三个层次
50.2 Python 的 lru_cache
from functools import lru_cache
import time
@lru_cache(maxsize=128)
def expensive_compute(n):
time.sleep(1) # 模拟耗时操作
return n * n
expensive_compute(10) # 1 秒
expensive_compute(10) # 瞬时(走缓存)
一行装饰器,性能提升巨大。 但要注意:
- 参数必须可哈希
- 缓存会占用内存
- 结果不能有副作用
50.3 缓存失效:计算机科学的两大难题之一
计算机科学里只有两大难题:缓存失效和命名。
我踩过的坑:
# 错误:缓存了可变对象
@lru_cache(maxsize=128)
def get_config(path):
with open(path) as f:
return json.load(f) # 返回的 dict 是可变的!
调用方修改了返回的 dict,缓存就被污染了。
正确做法:返回不可变对象,或者返回拷贝。
50.4 真正的缓存策略
import redis
import json
import hashlib
r = redis.Redis()
def cached_query(sql: str, ttl: int = 300):
key = "q:" + hashlib.md5(sql.encode()).hexdigest()
cached = r.get(key)
if cached:
return json.loads(cached)
result = db.execute(sql).fetchall()
r.setex(key, ttl, json.dumps(result, default=str))
return result
加 TTL(过期时间)是关键。 没有 TTL 的缓存,迟早会给你带来麻烦。
五十一、并发编程:Python 的特殊困境
51.1 GIL 的真相
Python 有 GIL(全局解释器锁),这意味着同一时刻只有一个线程在执行 Python 字节码。
所以:
- CPU 密集型任务:多线程没用,必须用多进程
- IO 密集型任务:多线程有用(IO 时释放 GIL)
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
# CPU 密集 → 多进程
with ProcessPoolExecutor(max_workers=4) as ex:
results = list(ex.map(cpu_task, data))
# IO 密集 → 多线程或 asyncio
with ThreadPoolExecutor(max_workers=100) as ex:
results = list(ex.map(io_task, urls))
51.2 一个真实的性能对比
我做过一个实验:处理 1000 个视频文件,每个耗时 0.1 秒(IO 密集)。
| 串行 | 100 秒 |
| 多线程(100 线程) | 1.5 秒 |
| 多进程(8 进程) | 13 秒 |
| asyncio | 1.2 秒 |
IO 密集场景,多线程和 asyncio 都能提速 60 倍以上。
51.3 asyncio 的甜蜜与痛苦
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as resp:
return await resp.text()
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, u) for u in urls]
return await asyncio.gather(*tasks)
asyncio.run(main(urls))
甜蜜: 单线程处理上万个并发连接,内存占用小。
痛苦:
第四个是最坑的。 我有一次在 async 里用了 requests.get(),整个服务卡死。AI 一眼看出来:
requests 是同步库,会阻塞事件循环。
在 async 函数里必须用 httpx.AsyncClient 或 aiohttp。
如果非要用同步库,用 asyncio.to_thread() 包一层。
51.4 一个并发 bug 的排查
我写过一个多进程脚本,偶尔卡死。
AI 帮我分析:
你用了 pool.map(),它会一次性把所有任务分发出去,
如果任务的数据量很大,会全部加载到内存。
而且 map 会等所有任务完成才返回,
如果有任务卡住,整个程序就卡住。
建议用 pool.imap_unordered() + chunksize,流式处理。
改成 imap_unordered 之后,问题解决,而且内存占用从 8GB 降到 500MB。
五十二、性能优化的"反常识"
52.1 有时候"慢"的代码更快
在视频编码里,我遇到过一个反常识的案例。
有一段预测代码,我优化成了"理论最优"的 O(n) 版本。结果比原来慢。
为什么?因为原版本的循环结构对 CPU 缓存更友好,数据访问局部性好。
这也是为什么 AI 在性能优化上不可靠——它不懂硬件微架构。
52.2 过早优化是万恶之源
Premature optimization is the root of all evil. — Donald Knuth
但很多人断章取义,忘了后半句:
但我们不应该放弃那 3% 的关键优化点。
我的理解:先写清楚,再测,只优化瓶颈。
52.3 我的性能优化清单
- 用 profiler 找到真正的瓶颈
- 检查是不是 IO 瓶颈(IO 优化收益通常最大)
- 检查数据结构选择是否合理
- 加缓存(注意失效策略)
- 减少不必要的内存分配
- 考虑并发(注意 GIL / 锁)
- 最后才是算法级优化
第九部分 AI 对话实录:七段真实的"人机对话"
五十三、为什么我要放这些实录
写完前面的内容,我觉得少了点东西:具体的对话长什么样?
理论谁都会讲,但"实际怎么跟 AI 说话"才是关键。
下面七段对话都是真实的(我做了脱敏和整理)。
五十四、实录一:排查一个内存泄漏
我:
我的 C++ 服务跑 8 小时后内存从 1GB 涨到 6GB。用 valgrind 跑 2 小时没发现泄漏。可能是什么原因?
AI:
valgrind 没报泄漏但有内存增长,通常是这几种情况:
建议先做三件事:
- 打印 mallinfo2() 看 arena 情况
- 检查所有容器的生命周期
- 用 MALLOC_ARENA_MAX=2 环境变量重启试试
我:
确实是 mallinfo2 显示 arena 的 hblkhd 一直在涨。这个怎么解决?
AI:
hblkhd 是 mmap 分配的内存。如果一直在涨,可能是大块分配没释放。
三个方向:
mmap 的内存只在 free 时归还,如果对象一直挂着,
就算逻辑上"不再使用",内存也不会还。
如果你用智能指针,检查有没有循环引用(shared_ptr 互指)。
结果:最后发现是一处 shared_ptr 循环引用。改成 weak_ptr 后,内存稳定在 1.2GB。
五十五、实录二:让 AI 帮我写一个完整的模块
我:
我需要一个 Python 模块,功能:
要求:用 pathlib,不要用 os.path;支持并发;有进度显示。
AI:
"""YUV 文件扫描器。"""
import json
import hashlib
import re
from concurrent.futures import ProcessPoolExecutor, as_completed
from pathlib import Path
from typing import Dict, List, Optional
from tqdm import tqdm
PATTERN = re.compile(r"^(?P<name>.+)_(?P<w>\\d+)x(?P<h>\\d+)_(?P<fps>\\d+(?:\\.\\d+)?)\\.yuv$")
def parse_filename(path: Path) –> Optional[Dict]:
"""从文件名解析视频参数。解析失败返回 None。"""
m = PATTERN.match(path.name)
if not m:
return None
return {
"filename": path.name,
"name": m.group("name"),
"width": int(m.group("w")),
"height": int(m.group("h")),
"fps": float(m.group("fps")),
}
def file_md5(path: Path, chunk_size: int = 1 << 20) –> str:
"""分块计算 MD5,避免大文件占满内存。"""
h = hashlib.md5()
with path.open("rb") as f:
while chunk := f.read(chunk_size):
h.update(chunk)
return h.hexdigest()
def scan_one(path_str: str) –> Optional[Dict]:
"""处理单个文件。必须是模块级函数,才能被进程池 pickle。"""
path = Path(path_str)
info = parse_filename(path)
if info is None:
return None
info["size"] = path.stat().st_size
info["md5"] = file_md5(path)
return info
def scan_directory(directory: str, workers: int = 4) –> List[Dict]:
"""并发扫描目录下所有 YUV 文件。"""
root = Path(directory)
if not root.is_dir():
raise NotADirectoryError(f"不是目录: {directory}")
files = [str(p) for p in root.iterdir() if p.suffix.lower() == ".yuv"]
results: List[Dict] = []
with ProcessPoolExecutor(max_workers=workers) as pool:
futures = {pool.submit(scan_one, f): f for f in files}
for future in tqdm(as_completed(futures), total=len(files), desc="扫描中"):
info = future.result()
if info is not None:
results.append(info)
results.sort(key=lambda x: x["filename"])
return results
if __name__ == "__main__":
import sys
data = scan_directory(sys.argv[1] if len(sys.argv) > 1 else ".")
Path("yuv_scan.json").write_text(
json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
)
print(f"完成,共 {len(data)} 个文件")
我:
几个问题:1. while chunk := f.read(…) 这个 walrus 语法 3.8+ 才支持,我环境是 3.9,OK。2. 为什么 scan_one 必须在模块级?
AI:
因为多进程(ProcessPoolExecutor)用的是 pickle 序列化。
pickle 只能序列化模块级可导入的名称,
局部函数、lambda、绑定的方法都不能序列化。
如果你把 scan_one 定义在 scan_directory 内部,
子进程反序列化时会 AttributeError: Can't pickle local object。
这是 Python 多进程最常见的坑之一。
我:
还有,文件名里 name 部分可能包含下划线,你这个正则能处理吗?
AI:
能。(?P<name>.+) 是贪婪匹配,会匹配到最后一个能匹配的位置。
比如 test_1080p_1920x1080_30.yuv:
- name = test_1080p
- w = 1920, h = 1080, fps = 30
因为 1920×1080 这种模式在文件名里通常只有一个,
贪婪匹配反而更安全。
但如果文件名是 a_1x2_1920x1080_30.yuv,
贪婪匹配会得到 name = a_1x2,也是对的。
如果你想更严格,可以用非贪婪 .+?,
但那样 a_1x2_1920x1080_30.yuv 会匹配成 name=a,反而错了。
所以这里贪婪是对的。
这段对话让我学到了两件事:pickle 的限制、正则贪婪的取舍。
五十六、实录三:一个性能问题
我:
这段代码处理 100 万条数据要 40 秒,太慢了。帮我看下:
def process(records):
result = []
for r in records:
if r['status'] == 'active' and r['score'] > 60:
result.append({
'id': r['id'],
'name': r['name'].strip().title(),
'score': round(r['score'], 2),
})
return result
AI:
有几个优化点,按收益排序:
1. 最大问题:r['name'].strip().title()
字符串操作是 CPU 密集的。如果没有必要,去掉。
如果 name 已经清洗过,这个完全是浪费。
2. 字典访问改成本地变量
def process(records):
result = []
append = result.append # 避免每次查 result.append
for r in records:
if r['status'] == 'active' and r['score'] > 60:
append({...})
return result
收益约 5-10%。
3. 如果数据量大,考虑用生成器
如果调用方不需要完整的 list,改成 yield 可以省内存。
4. 如果这是从数据库来的,让 SQL 做过滤
SELECT id, name, score FROM t WHERE status='active' AND score > 60
让数据库过滤,比在 Python 里过滤快 10 倍以上。
这是收益最大的一项。
我:
确实是数据库来的!改成 SQL 过滤后,Python 侧只处理 8 万条,耗时降到 2 秒。
AI:
对。性能优化的第一原则:让数据在离它最近的地方被处理。
能在数据库做的,不要拉到应用层。
能在应用层做的,不要传到前端。
这句话我记到现在。
五十七、实录四:设计讨论
我:
我要设计一个视频转码服务,接收上传的视频,转成多种分辨率和码率。
我的方案:用户上传 → 存对象存储 → 发消息到队列 → 转码 worker 消费 → 转码后存回去。
你觉得有什么问题?
AI:
整体架构是对的。但有几个点要注意:
1. 转码是 CPU 密集型,且耗时很长(视频可能几十分钟)
你的消息队列要支持"长任务",注意 visibility timeout 要设得比最长转码时间长,
否则消息会被重复消费。
2. 要考虑转码失败重试
有些视频格式有问题,转码会失败。要有限制重试次数(比如 3 次),
超过就进死信队列,人工处理。
3. 多分辨率是并行还是串行?
如果一台机器并行转 5 个分辨率,CPU 会打满、互相抢资源,
整体耗时反而更长。
建议:每个分辨率一个任务,任务粒度更细,调度更灵活。
4. 要不要用"一次解码,多次编码"?
如果多个分辨率都要转,解码一次拿到 YUV,然后分别编码,
比"每个分辨率都解码一次"快很多。FFmpeg 的 -filter_complex split 能做。
5. 进度反馈
用户上传后要等很久。要能反馈进度。
FFmpeg 会输出进度到 stderr,解析后写到 Redis,前端轮询。
6. 成本控制
转码很烧钱。要考虑:
- 是否所有视频都需要所有分辨率?(短视频可能只需要 720p)
- 是否用硬件编码(NVENC/QSV)替代 CPU 编码?速度快 10 倍,质量略差。
- 是否用 spot 实例?(可以省 70% 成本,但会被中断,要能优雅处理)
我:
第 4 点我没想到。这个能省多少时间?
AI:
假设你要转 1080p/720p/480p 三个分辨率,视频 10 分钟:
- 分别解码:解码 3 次,每次 30 秒 = 90 秒
- 一次解码:解码 1 次 30 秒
编码时间不变(这是主要开销),但解码省了 60 秒。
另外更重要的是内存/CPU 峰值:三次独立任务可能同时在三个机器上跑,
一次解码的方案在一台机器上顺序编码,资源利用更可控。
但要注意:一次解码的方案要求单机有足够的内存存 YUV。
1080p 10 分钟的 YUV420 约 18GB,这不太现实。
所以实际做法是"分块":解码一段(比如 10 秒),编码三个分辨率,再解下一段。
这个"分块"的思路,是我从这段对话里学到的最有价值的东西。
五十八、实录五:让它"扮演"面试官
我:
你是一个大厂的视频编码方向面试官。
请你设计 10 道有深度的面试题,考察候选人对 H.265 编码器的理解。
难度:高级工程师。不要那种"背概念"的题,要能考出真实理解。
AI:
我:
第 8 题很好。你自己会怎么回答?
AI:
我会按信息量排序砍:
保留(不能砍):
- 帧内预测的粗略模式选择(决定基本质量)
- 运动估计的整像素搜索(决定运动补偿质量)
- 量化 + 熵编码
砍掉或简化:
总质量损失控制在 0.5-0.8dB 以内,时间砍掉 70%。
核心思想:编码质量对"运动补偿精度"最敏感,对"滤波器"和"高级工具"最不敏感。
砍后面的。
这段对话我存下来了,后来真的用在了项目里。
五十九、实录六:让它帮我"读懂"数学
我:
请用最直白的话解释 SSIM 公式里的每一项在干嘛,不要用"结构相似性"这种同义反复的词。
AI:
SSIM 公式:
SSIM(x,y)=(2μxμy+C1)(2σxy+C2)(μx2+μy2+C1)(σx2+σy2+C2)\\text{SSIM}(x,y) = \\frac{(2\\mu_x\\mu_y + C_1)(2\\sigma_{xy} + C_2)}{(\\mu_x^2 + \\mu_y^2 + C_1)(\\sigma_x^2 + \\sigma_y^2 + C_2)}SSIM(x,y)=(μx2+μy2+C1)(σx2+σy2+C2)(2μxμy+C1)(2σxy+C2)
拆成两半看:
第一半(亮度项):2μxμy+C1μx2+μy2+C1\\frac{2\\mu_x\\mu_y + C_1}{\\mu_x^2 + \\mu_y^2 + C_1}μx2+μy2+C12μxμy+C1
- μx\\mu_xμx 是 x 的平均亮度
- 如果两图亮度相同(μx=μy=μ\\mu_x = \\mu_y = \\muμx=μy=μ),这个式子 = 2μ2+C12μ2+C1=1\\frac{2\\mu^2+C_1}{2\\mu^2+C_1} = 12μ2+C12μ2+C1=1
- 如果一张全黑(μx=0\\mu_x=0μx=0)一张全白(μy=255\\mu_y=255μy=255),这个式子 ≈ 0
- 它就是在问:“两张图的平均亮度像不像?”
第二半(对比度+结构项):2σxy+C2σx2+σy2+C2\\frac{2\\sigma_{xy} + C_2}{\\sigma_x^2 + \\sigma_y^2 + C_2}σx2+σy2+C22σxy+C2
- σxy\\sigma_{xy}σxy 是协方差,衡量"两张图一起变化"的程度
- 如果两张图完全一样,σxy=σx2\\sigma_{xy} = \\sigma_x^2σxy=σx2,式子 = 1
- 如果两张图一个是正相关一个是负相关(亮的地方一个亮一个暗),σxy\\sigma_{xy}σxy 是负数,式子接近 0
- 它就是在问:“两张图的变化模式像不像?”
C1,C2C_1, C_2C1,C2 是防止除以 0 的小常数(通常和像素值范围有关)。
一句话总结:SSIM 先看"整体亮不亮"像不像,再看"哪里亮哪里暗的分布"像不像。
我:
那为什么 SSIM 比 PSNR 更符合人眼?
AI:
因为 PSNR 只看逐像素的差值,它不知道"人眼对什么敏感"。
举个例子:两张图都是"一张灰底上有一条黑线"。
- 图 A:黑线稍微模糊了一点(逐像素差很小,PSNR 高)
- 图 B:黑线的位置整体偏移了 1 个像素(逐像素差很大,PSNR 低)
PSNR 会说 A 比 B 好。
但人眼会说:B 看起来反而更"正常"——因为人眼对"边缘位置"极其敏感,
你稍微移动一条边,人一眼就看出来了;但轻微模糊,人反而不太在意。
SSIM 因为算了"结构项"(协方差),它能捕捉到"边缘有没有移位",
所以更接近人眼的主观感受。
但 SSIM 也不是万能的——它对"模糊"不敏感,对"块效应"过度敏感。
后来才有了 MS-SSIM、VMAF 这些更好的指标。
这段对话让我真正理解了"为什么视频编码里 PSNR 高不等于好看"。
六十、实录七:一个"灵魂拷问"
我:
你说 AI 会不会有一天完全替代程序员?
AI:
我不会给你一个"是或否"的答案,因为那是不负责任的。
我说三个我真实的判断:
第一,AI 会替代"写代码"这个动作的大部分。
这已经在发生了。两年前你可能要花一天写一个 CRUD 模块,
现在一句话生成。这部分的人会被替代。
第二,AI 短期内替代不了"定义问题"和"承担后果"。
- 谁来定义"这个功能该不该做"?
- 谁来承担"这个方案上线后出事了"的责任?
- 谁来理解"用户真正的痛点是什么"?
这些不是技术问题,是判断和责任问题。
AI 可以给建议,但不能承担责任。
第三,也是最重要的:AI 会改变"程序员"这个职业的定义。
二十年前,"会打字"是文员的技能。
现在,"会打字"不是技能,是基础素养。
编程可能也会走这条路——“会写代码"从"技能"变成"素养”。
到那时候,"程序员"可能不叫程序员了,
但"用计算解决问题的人"这个角色,会一直存在。
所以我的答案是:AI 会替代"码农",但替代不了"工程师"。
你选择做哪个,是你的事。
这段对话,我跟它聊了很久。它给我的不是安慰,而是一个框架。
第十部分 我的主战场:AI 在视频编解码里的真实表现
六十一、为什么单独写这一部分
前面所有内容都是"通用"的。
这一部分不一样:这是我真正吃饭的本事。
我做了五年视频编解码。这个方向的特点:
- 门槛高(要懂信号处理、信息论、优化理论)
- 资料少(很多细节只在标准文档和源码里)
- 社区小(全国真正做这个的可能就几千人)
- 但 AI 训练数据里这类内容也不多
所以我想聊聊:AI 在"专业垂直领域"到底能帮你到什么程度。
六十二、视频编码的基本框架
62.1 混合编码框架
现代视频编码器(H.264/H.265/H.266/AV1)都基于混合编码框架:
输入帧
↓
[分块] → CTU/CU/PU/TU 划分
↓
[预测] → 帧内预测 / 帧间预测
↓
[残差] → 原图 – 预测
↓
[变换] → DCT/DST
↓
[量化] → 这是有损的关键
↓
[熵编码] → CABAC
↓
码流
同时,编码器内部还有环路滤波(去块滤波、SAO、ALF),滤波后的帧作为后续帧的参考。
62.2 为什么这个框架能压缩
三个来源:
所有的编码技术,本质上都是在"更聪明地利用这三种冗余"。
六十三、AI 帮我理解 x265 源码
63.1 x265 的代码规模
x265 大概 30 万行 C++。核心文件:
- encoder.cpp:顶层编码流程
- EncGOP.cpp:GOP 级编码(最复杂)
- analysis.cpp:帧内/帧间分析
- ratecontrol.cpp:码率控制
- sao.cpp / loopfilter.cpp:环路滤波
- entropy.cpp:CABAC
63.2 我用 AI 读源码的方式
方式一:让 AI 画出调用关系
x265 的 EncGOP::compressGOP() 是 GOP 级编码入口。
请你梳理它调用的主要函数,画出一个调用树,并说明每个函数的职责。
AI 给出的:
EncGOP::compressGOP()
├── compressCTU() // 逐 CTU 处理
│ ├── compressIntraCU() // 帧内 CU
│ │ ├── intraAnalysis() // 帧内模式分析
│ │ └── …
│ └── compressInterCU() // 帧间 CU
│ ├── mergeAnalysis() // merge 模式
│ ├── motionEstimate() // 运动估计
│ └── …
├── processSao() // SAO
└── deblockingFilter() // 去块滤波
这个结构我自己梳理过,AI 给的版本基本对。 有几个细节它简化了(比如 CU 递归划分的入口在 compressCTU 内部),但整体框架是对的。
方式二:让它解释具体函数
请解释 x265 里这个函数的每一步,尤其是 lambda 和状态更新:
[CABAC 的 encodeBin]
方式三:让它找"可疑的地方"
这段 SIMD 代码用到了 _mm256_ 系列 intrinsic,
请检查有没有内存越界、对齐问题、或逻辑错误。
63.3 AI 在源码分析上的局限
局限一:它不懂"为什么"。
比如它知道 rdCost 是率失真代价,但它不知道为什么这个 λ 应该取 0.85 × 2^((QP-12)/3)。这是从实验和经验来的。
局限二:它容易"脑补"。
有次我让它解释一个宏的作用,它说得头头是道。我一看源码,这个宏根本不是那个作用。
局限三:它不理解"性能权衡"。
源码里很多写法是"性能优先",看起来"不优雅"。AI 经常建议改成"更优雅"的写法,但那会变慢。
63.4 一个真实的源码分析案例
我想搞清楚 x265 的 RDOQ(率失真优化量化)。
我让 AI 解释 rdoQuant() 的核心逻辑,它给的:
RDOQ 的核心思想:量化不是为了"最小化失真",而是"最小化 失真 + λ×码率"。
所以对每个变换系数,它会考虑:
然后选总代价最小的。
具体流程:
这个解释是准确的。 尤其是"倒序遍历"这个细节——因为要维护"最后一个非零系数"的位置,正序遍历处理"清零"很麻烦。
但这些内容,我是"自己先懂了",才能判断它说得对不对。
这就是我一直在说的:AI 帮你加速,但前提是你自己有判断力。
六十四、HEVC 关键技术点:AI 帮我校准理解
64.1 帧内预测的 35 种模式
HEVC 的帧内预测有 35 种模式:33 种角度模式 + DC + Planar。
我让 AI 解释"为什么要这么多角度模式":
H.264 只有 9 种(8 个方向 + DC)。HEVC 增加到 35 种,
主要因为高分辨率视频里纹理方向更丰富。
4K 视频里,一个 CTU 内部可能有各种方向的边缘。
8 个方向不够精细,会导致预测残差大。
33 个角度模式,从 -135° 到 45°,间隔约 5.6°,
能更精确地匹配真实边缘方向。
代价:模式选择的计算量增加(35 个都要算 RDO)。
所以实际编码器用"粗筛 + 精筛"两阶段。
这段解释是对的。 而且它点出了"代价"——这是很多教程不提的。
64.2 亚像素插值:DCT-IF
HEVC 的亚像素插值用的是 DCT-IF(DCT-based Interpolation Filter),而不是 H.264 的维纳滤波器。
我让 AI 解释为什么:
DCT-IF 的核心思想:把插值问题放到 DCT 域。
因为自然图像在小块内可以近似为"频带受限信号",
在 DCT 域补零再做 IDCT,等价于理想插值(sinc 插值)。
相比 H.264 的 6 抽头维纳滤波器:
- DCT-IF 是 8 抽头(亮度)
- 理论更完备(有明确的信号处理解释)
- 对高频保留更好
代价:计算量稍大,但硬件友好(系数固定)。
这个解释让我第一次真正理解"为什么用 DCT-IF"。
64.3 去块滤波的边界强度
去块滤波里,边界强度(bS)的判定:
| 0 | 不滤波 |
| 1 | 至少一个块是帧内预测,或 |
| 2 | 至少一个块有非零系数但边界两侧运动不完全相同 |
| 3 | 两侧都用帧间预测且 MV 差异大 |
我让 AI 解释 bS=1 和 bS=2 为什么滤波强度不同:
bS 越大,说明这个边界越"不自然",需要越强的滤波。
-
bS=2:块内部有非零残差,说明这里纹理复杂,
但边界两侧运动一致(是同一个物体的内部)。
此时滤波要保守——因为强滤波会把真实纹理抹掉。 -
bS=1:至少一侧是帧内预测。
帧内块和帧间块的边界,通常是真的"内容边界"或者
编码造成的明显不连续。而且帧内块附近没有运动信息辅助,
所以要更强的滤波。
一句话:bS 反映的是"这个边界有多可能是不自然的"。
这个"有多可能是不自然的"总结,比标准文档说得清楚。
六十五、VTM:下一代编码器的复杂度
65.1 VTM 的复杂度
VTM(VVC Test Model)比 x265 复杂得多:
- 编码时间:比 HEVC 慢 10-20 倍
- 码率节省:约 30-50%
为什么这么慢?因为 VVC 加了很多新工具:
- 四叉树 + 二叉树 + 三叉树划分(QTBT+TT)
- 多类型变换(MTS)
- ALF(自适应环路滤波,带分类)
- 多参考行帧内预测
- 仿射运动补偿
- GPM(几何划分模式)
- LMCS(亮度映射与色度缩放)
65.2 我让 AI 帮我梳理 ALF
ALF 是 VVC 里最复杂的滤波器之一。
请解释 VVC 的 ALF 模块:
1. 为什么要做分类(classification)?
2. 25 个滤波器是怎么选的?
3. 和 HEVC 的 SAO 有什么本质区别?
AI 的回答:
1. 为什么要分类?
图像不同区域的"信号特征"不同:
- 平坦区域:需要弱滤波(否则会模糊)
- 强边缘:需要特定方向的滤波(保护边缘)
- 复杂纹理:不滤波或弱滤波
所以 ALF 把每个 4×4 块分类(根据梯度方向和活动度),
不同类别用不同的滤波器。
2. 25 个滤波器怎么选?
编码器对每个类别,遍历 25 个候选滤波器,选率失真代价最小的。
同时在 slice 层用 ALF APS(Adaptation Parameter Set)传输滤波器系数。
3. 和 SAO 的本质区别?
- SAO 是"逐像素的偏移":对每个像素加一个偏移量,
只能修正"亮度偏移",不能改变空间频率特性。 - ALF 是"卷积滤波":能真正改变空间频率响应,
可以锐化、可以平滑、可以做方向性滤波。
所以 ALF 是"更强大的后处理",代价是计算量和信号开销大得多。
这段解释是对的,而且第 3 点抓住了本质。
65.3 用 AI 读 VTM 源码的一个实例
VTM 的 AdaptiveLoopFilter.cpp 有 3000+ 行。
我让 AI 帮我定位"分类是怎么做的":
VTM 的 ALF 分类在哪个函数?分类的梯度计算用的什么算子?
AI 指向 deriveClassification(),并说梯度用的是 Laplacian:
// 水平/垂直/两个对角方向的梯度
int g_v = abs(rec[–1][0] + rec[1][0] – 2*rec[0][0]);
int g_h = abs(rec[0][–1] + rec[0][1] – 2*rec[0][0]);
int g_d1 = abs(rec[–1][–1] + rec[1][1] – 2*rec[0][0]);
int g_d2 = abs(rec[–1][1] + rec[1][–1] – 2*rec[0][0]);
这个定位是准的。 而且它解释了"为什么用 Laplacian"——因为 Laplacian 算子对边缘方向敏感,正好能区分"水平边缘/垂直边缘/对角边缘"。
六十六、我在用 AI 做编解码工作时的一条原则
原则:AI 帮我"找路",不帮我"走路"。
具体来说:
- 找路:读源码定位函数、解释概念、梳理流程、对比方案 → 用 AI
- 走路:写核心算法、做性能优化、定参数、judge 质量 → 自己来
为什么?因为在编解码领域,"看起来对"和"真的对"差距很大。
一个错误的 λ 取值,可能让 PSNR 掉 0.5dB。AI 不知道这个。
一个错误的 SIMD 实现,可能在特定输入下崩溃。AI 不会测这个。
这个领域没有"差不多",只有"对"和"错"。
六十七、一个我用 AI 提效的真实案例
67.1 任务
我要给一个编码器加一个"自适应 QP offset"功能:根据块的复杂度动态调整 QP。
67.2 传统做法
预计 3 天。
67.3 用 AI 的做法
第 1 步(AI 帮我): 让它梳理"QP 在 x265 里从哪来,经过哪些变换"。
AI 给出了完整链路:rateControl → QP 计算 → QP 到 λ 的映射 → 各 CU 的 QP offset。
第 2 步(我做): 我自己决定了"复杂度"怎么定义(用块内方差 + 边缘强度)。
这个决定 AI 帮不了——它不知道我们的业务更看重"文字区域的清晰度"。
第 3 步(AI 帮我): 让它写出代码框架,我改细节。
第 4 步(我做): 调参和验证。这部分 AI 完全帮不上——
因为"什么参数好"取决于主观质量评价,要用 VMAF + 人工看。
总耗时 1.5 天。 提效 50%,但关键决策还是我做。
67.4 这个案例的启发
AI 提效的地方:
- 繁琐的代码定位
- 样板代码
- 文档梳理
- 概念确认
AI 提效不了的地方:
- 需要业务理解的决策
- 需要主观判断的质量评估
- 需要反复实验的参数调优
- 需要"手感"的性能优化
所以"AI 提效 10 倍"这种说法,在专业领域是不成立的。
我的真实感受是:在专业领域,AI 提效 30%-50%。
这个提升已经很大了。但别期望它 10 倍。
第十一部分 代码走读:从零写一个 MP4 解析器
六十八、为什么选这个例子
前面讲了很多"理念",但代码写得太少。这一部分我完整走一遍一个真实项目:MP4 文件解析器。
选它的原因:
六十九、需求:我要什么
输入:一个 MP4/MOV 文件路径
输出:
{
"width": 1920,
"height": 1080,
"duration": 12.5,
"video_codec": "avc1",
"audio_codec": "mp4a",
"frame_rate": 30.0,
"bitrate": 4500000
}
要求:
- 纯 Python,不依赖 ffmpeg
- 能处理大文件(不能一次读进内存)
- 兼容 MP4 / MOV / M4V
七十、MP4 的容器结构
70.1 Box 结构
MP4 是"盒子套盒子"的结构。每个 box:
┌──────────────┬──────────────┬─────────────────┐
│ size (4字节) │ type (4字节) │ data │
└──────────────┴──────────────┴─────────────────┘
- size:整个 box 的大小(含头部 8 字节)
- type:4 个字符,比如 ftyp、moov、trak
- data:内容,可以嵌套子 box
特殊值: size = 1 表示用 8 字节的 largesize(64 位);size = 0 表示延伸到文件末尾。
70.2 关键 box 的位置
ftyp 文件类型
moov 元数据(关键!)
├── mvhd 影片头(时长、时间刻度)
├── trak (视频) 轨道
│ ├── tkhd 轨道头(宽高)
│ └── mdia
│ ├── mdhd 媒体头(时间刻度、时长)
│ └── minf
│ └── stbl 采样表
│ ├── stsd 采样描述(编码格式)
│ └── stts 时间到采样(用于算帧率)
└── trak (音频)
注意:moov 可能在文件开头,也可能在结尾。 有些编码器(比如手机拍的视频)会把 moov 放在最后。
七十一、核心代码
71.1 基础读取器
"""MP4 文件解析器。
纯 Python 实现,不依赖 ffmpeg。
支持 MP4 / MOV / M4V。
"""
from __future__ import annotations
import struct
from pathlib import Path
from typing import Any, Dict, Iterator, List, Optional, Tuple
class MP4ParseError(Exception):
"""MP4 解析异常。"""
class BoxReader:
"""按 offset 读取文件中的 box,不会把整个文件读进内存。"""
def __init__(self, path: Path) –> None:
self.path = path
self._fh = path.open("rb")
def close(self) –> None:
self._fh.close()
def __enter__(self) –> "BoxReader":
return self
def __exit__(self, *exc: Any) –> None:
self.close()
def read_at(self, offset: int, size: int) –> bytes:
"""从指定位置读取 size 字节。"""
self._fh.seek(offset)
data = self._fh.read(size)
if len(data) != size:
raise MP4ParseError(
f"读取失败: 需要 {size} 字节,实际 {len(data)} 字节 (offset={offset})"
)
return data
def iter_boxes(
self, start: int, end: int
) –> Iterator[Tuple[str, int, int]]:
"""遍历 [start, end) 范围内的顶层 box。
产出 (type, data_offset, data_size)。
"""
pos = start
while pos + 8 <= end:
header = self.read_at(pos, 8)
size, box_type = struct.unpack(">I4s", header)
box_type_str = box_type.decode("latin-1")
header_size = 8
if size == 1:
# 64 位 largesize
large = self.read_at(pos + 8, 8)
size = struct.unpack(">Q", large)[0]
header_size = 16
elif size == 0:
# 延伸到末尾
size = end – pos
if size < header_size:
raise MP4ParseError(
f"box '{box_type_str}' 大小非法: {size} (offset={pos})"
)
yield box_type_str, pos + header_size, size – header_size
pos += size
这段代码是我写的。 为什么?因为它涉及"边界检查"和"偏移计算",这是最容易出错的地方,我自己写更放心。
71.2 解析 mvhd(影片头)
def parse_mvhd(reader: BoxReader, offset: int, size: int) –> Dict[str, Any]:
"""解析 mvhd box。
结构:
1 byte version
3 bytes flags
[version 0]
4 bytes creation_time
4 bytes modification_time
4 bytes timescale
4 bytes duration
[version 1]
8 bytes creation_time
8 bytes modification_time
4 bytes timescale
8 bytes duration
"""
version = reader.read_at(offset, 1)[0]
offset += 4 # 跳过 version(1) + flags(3)
if version == 1:
_, _, timescale, duration = struct.unpack(
">QQIQ", reader.read_at(offset, 28)
)
else:
_, _, timescale, duration = struct.unpack(
">IIII", reader.read_at(offset, 16)
)
if timescale == 0:
raise MP4ParseError("mvhd: timescale 为 0")
return {"timescale": timescale, "duration": duration}
这段代码也是我的。 因为版本分支容易写错,而且 struct 格式字符串(>QQIQ 这种)AI 经常搞混。
71.3 解析 tkhd(轨道头)
def parse_tkhd(reader: BoxReader, offset: int, size: int) –> Dict[str, Any]:
"""解析 tkhd box,提取宽高。
宽高是 16.16 定点数,在 box 的最后 8 字节。
"""
version = reader.read_at(offset, 1)[0]
if version == 1:
# version 1: 4 + 4 + 8 + 8 + 4 + 4 + 4*2 + 2*4 + 2*4 + 2*2 + 2*2 + 4*9 + 4 + 4
width_offset = offset + 4 + 8 + 8 + 4 + 4 + 8 + 16 + 8 + 8 + 4 + 4 + 36
else:
width_offset = offset + 4 + 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4 + 36
raw = reader.read_at(width_offset, 8)
width_fixed, height_fixed = struct.unpack(">II", raw)
# 16.16 定点数 → 浮点
return {
"width": width_fixed / 65536.0,
"height": height_fixed / 65536.0,
}
这段偏移计算我调了很久。 我一开始算错了,AI 帮我核对过一遍。
71.4 解析 stsd(编码格式)
def parse_stsd(reader: BoxReader, offset: int, size: int) –> Optional[str]:
"""从 stsd 提取编码格式四字符码(如 avc1 / hevc / mp4a)。"""
# stsd: version+flags(4) + entry_count(4) + entries
entry_count = struct.unpack(">I", reader.read_at(offset + 4, 4))[0]
if entry_count == 0:
return None
entry_offset = offset + 8
# 每个 entry 是一个 box,取它的 type
_, data_off, _ = next(reader.iter_boxes(entry_offset, entry_offset + 1024))
# entry 的前 4 字节是 size,接着 4 字节是 type
fmt = reader.read_at(entry_offset + 4, 4).decode("latin-1")
return fmt
71.5 解析 stts(时间到采样)——算帧率
def parse_stts(reader: BoxReader, offset: int, size: int,
timescale: int) –> float:
"""从 stts 计算平均帧率。
stts 结构:
version+flags(4) + entry_count(4) + entries
每个 entry: sample_count(4) + sample_delta(4)
"""
entry_count = struct.unpack(">I", reader.read_at(offset + 4, 4))[0]
if entry_count == 0 or timescale == 0:
return 0.0
total_samples = 0
total_duration = 0
pos = offset + 8
for _ in range(entry_count):
count, delta = struct.unpack(">II", reader.read_at(pos, 8))
total_samples += count
total_duration += count * delta
pos += 8
if total_duration == 0:
return 0.0
# 帧率 = 总采样数 / (总时长 / 时间刻度)
return total_samples * timescale / total_duration
这段是 AI 写的初版,我改了 3 处:
七十二、整体组装
class MP4Parser:
"""MP4/MOV 文件元数据解析器。"""
VIDEO_CODECS = {"avc1", "avc3", "hev1", "hvc1", "vp09", "av01", "mp4v"}
AUDIO_CODECS = {"mp4a", "ac-3", "ec-3", "Opus", "alac"}
def __init__(self, file_path: str | Path) –> None:
self.path = Path(file_path)
if not self.path.is_file():
raise FileNotFoundError(f"文件不存在: {self.path}")
self.metadata: Dict[str, Any] = {
"width": 0,
"height": 0,
"duration": 0.0,
"video_codec": None,
"audio_codec": None,
"frame_rate": 0.0,
"bitrate": 0,
}
def parse(self) –> Dict[str, Any]:
with BoxReader(self.path) as reader:
file_size = self.path.stat().st_size
# 第一遍:找 moov(可能在头部也可能在尾部)
moov = self._find_moov(reader, file_size)
if moov is None:
raise MP4ParseError("未找到 moov box,可能不是有效的 MP4 文件")
moov_off, moov_size = moov
mvhd = self._parse_mvhd(reader, moov_off, moov_size)
timescale = mvhd["timescale"]
duration_ticks = mvhd["duration"]
if timescale > 0:
self.metadata["duration"] = duration_ticks / timescale
# 遍历 moov 下的子 box
for box_type, off, size in reader.iter_boxes(
moov_off, moov_off + moov_size
):
if box_type == "trak":
self._parse_trak(reader, off, size, timescale)
# 计算码率
if self.metadata["duration"] > 0:
self.metadata["bitrate"] = int(
file_size * 8 / self.metadata["duration"]
)
# 宽高取整
self.metadata["width"] = int(round(self.metadata["width"]))
self.metadata["height"] = int(round(self.metadata["height"]))
return self.metadata
def _find_moov(self, reader: BoxReader, file_size: int):
"""在文件里找 moov。为了性能,只扫顶层 box。"""
for box_type, off, size in reader.iter_boxes(0, file_size):
if box_type == "moov":
return off, size
return None
72.1 一个重要的性能优化
_find_moov 只遍历顶层 box,不递归。
因为 iter_boxes 是"跳过式"遍历:读到 size 就直接跳到下一个 box,不用解析内容。
对一个大文件(比如 2GB),这个遍历只要读几十个头部(每个 8 字节),毫秒级完成。
如果递归解析所有 box,那就要读遍整个文件。
这个优化思路是 AI 提醒我的。
72.2 trak 的解析
def _parse_trak(self, reader, offset, size, timescale):
"""解析一个轨道。判断是视频还是音频,提取信息。"""
tkhd_info = None
handler_type = None
media_timescale = timescale
stsd_fmt = None
stts_off = stts_size = None
for box_type, off, sz in reader.iter_boxes(offset, offset + size):
if box_type == "tkhd":
tkhd_info = parse_tkhd(reader, off, sz)
elif box_type == "mdia":
for b2, o2, s2 in reader.iter_boxes(off, off + sz):
if b2 == "mdhd":
media_timescale = self._parse_mdhd(reader, o2, s2)
elif b2 == "hdlr":
handler_type = reader.read_at(o2 + 8, 4).decode("latin-1")
elif b2 == "minf":
stsd_fmt, stts_off, stts_size = self._parse_minf(
reader, o2, s2
)
if handler_type == "vide" and tkhd_info:
self.metadata["width"] = max(
self.metadata["width"], tkhd_info["width"]
)
self.metadata["height"] = max(
self.metadata["height"], tkhd_info["height"]
)
self.metadata["video_codec"] = stsd_fmt
if stts_off is not None:
self.metadata["frame_rate"] = parse_stts(
reader, stts_off, stts_size, media_timescale
)
elif handler_type == "soun":
self.metadata["audio_codec"] = stsd_fmt
这段我改了 AI 的版本。 AI 原来把"找 stts 和算帧率"混在一起,逻辑很绕。我拆成了"先找位置,再算"。
七十三、测试:我发现的三个真 bug
73.1 Bug 1:moov 在文件尾部时,duration 算错
原因:mvhd 的 duration 是"影片级时长",单位是 mvhd 的 timescale。但我一开始用了 mdhd 的 timescale 去除。
这两个 timescale 经常不同(mvhd 常用 1000,mdhd 常用 90000)。
测试用例:用手机拍的视频(moov 在尾部,mvhd timescale = 1000,mdhd timescale = 90000),duration 差了 90 倍。
修复:分开用各自的 timescale。
73.2 Bug 2:大文件读偏移溢出
原因:struct.unpack(">I", …) 是 32 位无符号。文件超过 4GB 时,offset 会溢出。
修复:在读取时用 Python 的任意精度整数,只在解析 largesize 时用 Q。
测试用例:我造了一个 5GB 的假文件(稀疏文件),验证能正确跳到 moov。
73.3 Bug 3:entry_count 为 0 时崩溃
原因:stsd 的 entry_count 为 0(理论上不该出现,但真的有文件这样),代码会去读一个不存在的 entry。
修复:加 if entry_count == 0: return None。
测试用例:手动构造一个 entry_count=0 的文件。
73.4 这三个 bug 是谁发现的
Bug 1 和 3 是我发现的(用真实视频测的)。
Bug 2 是 AI 提醒的——我在 review 时问了一句"如果有 8GB 的文件,这段代码有没问题?",它指出了 32 位溢出。
这个案例说明:AI 能发现"逻辑上的隐患",但发现不了"业务上的特例"。
七十四、这个项目的收获
74.1 代码层面的收获
74.2 协作层面的收获
74.3 一个真实的数据
这个项目:
- 总代码量:约 900 行
- AI 生成:约 700 行(78%)
- 我重写或大幅修改:约 200 行(22%)
- 开发时间:3 个周末
如果全自己写,估计要 2-3 周。
提效约 3-5 倍。 在小项目上,AI 的提效比大项目明显。
第十二部分 跨领域应用:AI 在 20 个行业里的真实用法
七十五、为什么写这个部分
很多人一提到"AI 应用",想到的就是"写代码"。
但 AI 的价值远不止于此。这两年我用 AI 干过的事,覆盖了从硬件到法律、从医疗到艺术的一堆领域。
这一部分我会逐个讲,每个领域只讲"真正有用的那个点"。
不废话,直接上。
七十六、硬件与嵌入式
76.1 AI 帮我看懂数据手册
芯片的数据手册(datasheet)动辄几百页,而且写得极其晦涩。
我的做法:把关键章节截图或者复制给 AI,让它"翻译成人话"。
下面是一段 SoC 的寄存器描述。请告诉我:
1. 这个寄存器是干什么的
2. 每个 bit 字段的含义
3. 初始值是多少
4. 有没有需要特别注意的"写 1 清 0"之类的坑
[粘贴寄存器表格]
AI 在"翻译术语"这件事上很强。 尤其是"reserved 位必须写 0"、"写 1 清中断"这种标准约定,它门儿清。
76.2 嵌入式的一个坑
我做过一个摄像头模块的驱动。I2C 通信一直不通。
AI 帮我排查:
检查这几点:
第 1 点是问题所在。 手册给的地址是 0x42(8 位),实际要传 0x21(7 位)。
这个坑非常经典,AI 一句话点破。
76.3 硬件描述语言
Verilog / VHDL,AI 也能帮忙:
// 我让 AI 写一个简单的 FIFO
module fifo #(
parameter DEPTH = 16,
parameter WIDTH = 8
)(
input wire clk,
input wire rst_n,
input wire wr_en,
input wire rd_en,
input wire [WIDTH-1:0] din,
output reg [WIDTH-1:0] dout,
output wire full,
output wire empty
);
// …
endmodule
AI 写 Verilog 的模板很熟,但时序逻辑的细节(比如跨时钟域)它经常给错。
跨时钟域(CDC)必须自己处理——AI 会给你一个"看起来对"的方案,但可能有亚稳态问题。
七十七、云计算与基础设施
77.1 成本优化
我做过一次云成本优化。AI 帮我分析账单结构,给出了:
三个明显的浪费:
AI 能"看懂账单",因为云厂商的计费项是标准化的。
77.2 一个真实的架构建议
我问 AI:“我的服务每天有几个小时的流量高峰,平时很闲,怎么省钱?”
AI 给了三个方案:
它明确说了各方案的成本和风险。 这就是我想要的。
七十八、数据库运维
78.1 慢查询分析
以下是一个 PostgreSQL 的慢查询日志(执行时间 8.5 秒),请分析原因:
[粘贴 EXPLAIN ANALYZE 输出]
AI 分析:
关键问题在这两行:
Seq Scan on orders (cost=0.00..185000.00 rows=5000000)
Filter: (status = 'pending')
- Seq Scan:全表扫描
- rows=5000000:扫描 500 万行
- cost 185000 极高
但注意 status = 'pending' 的选择性——如果 pending 只占 1%,
加索引能提升 100 倍。
如果 pending 占 80%,加索引没用,反而拖慢写入。
先查一下 SELECT status, count(*) FROM orders GROUP BY status;
这个"先查选择性"的建议,比"加索引"专业得多。
78.2 一个数据迁移方案
我们要把一个 5TB 的表迁移到新集群。AI 给方案:
不要一次性迁移。用"双写 + 灰度切换":
关键点:不要停服,而且随时能回滚。
这套方案是我见过最稳的。
七十九、前端与用户体验
79.1 性能优化
我让 AI 分析一个"首屏加载 5 秒"的页面。
它给的清单:
按优先级排序,而且给出了每项的预期收益。
79.2 无障碍(a11y)
这个我完全不懂。AI 帮我检查:
你的表单有几个无障碍问题:
这些我完全不知道,AI 教会了我一整套。
八十、移动端开发
80.1 跨平台的选择
我问 AI:“一个小团队,要同时做 iOS 和 Android,怎么选?”
它的回答很实在:
三个选项,各有取舍:
1. Flutter:性能好(自绘引擎),UI 一致,但包体积大(+8MB)
2. React Native:生态大,能复用 Web 技能,但性能略差
3. 原生双端:性能最好,但成本翻倍
建议:
- 团队有 Web 背景 → RN
- 追求 UI 一致性和性能 → Flutter
- 只做核心业务、长期投入 → 原生
不要选"一套代码两端跑还想要原生体验"的幻想方案。
80.2 移动端的性能坑
一张 4000×3000 的图直接加载要 48MB 内存
不能一次创建所有 item
八十一、游戏开发
81.1 我了解到的
虽然我不做游戏,但我帮朋友看过一些。
游戏里的 AI 应用场景:
81.2 一个真实的用法
朋友用 AI 做"程序化生成":
帮我写一个地牢生成算法:
– 用 BSP 树划分空间
– 每个叶子节点生成一个房间
– 用走廊连接相邻房间
– 保证所有房间可达
AI 给的算法是标准的 BSP 地牢生成。能用,但"不好玩" ——因为它没有"关卡设计感"。
这就是 AI 在创意领域的局限:它能生成"合理"的,但生成不了"有意思"的。
八十二、测试与质量
82.1 我不太愿意承认的事
AI 在测试领域比我强。
不是因为它更懂测试,而是因为它不嫌烦。
写 200 个测试用例,人会觉得枯燥,AI 不会。
给这个函数写全面的测试:
1. 正常输入
2. 边界值(0、最大、最小)
3. 非法输入(None、空、类型错误)
4. 特殊字符(Unicode、emoji、控制字符)
5. 大数据量
AI 会给 30+ 个测试。
82.2 但测试的价值不在数量
100 个"happy path"测试不如 1 个"边界"测试。
我 review AI 测试时只看一件事:这个测试能不能测出 bug?
方法:把被测代码故意改错一行,跑测试。如果不挂,这个测试就是废的。
这个"变异测试"的思路,是 AI 教我的。
82.3 端到端测试
# Playwright 例子
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://localhost:3000")
page.fill('input[name="email"]', "test@example.com")
page.fill('input[name="password"]', "password123")
page.click('button[type="submit"]')
page.wait_for_selector(".dashboard")
assert page.is_visible(".welcome-message")
browser.close()
AI 写 E2E 测试很熟练,因为套路固定。
八十三、安全
83.1 我学到的一课
有次我写了一个"下载远程图片"的接口。AI review 时第一个指出:
SSRF 风险。
url = request.args.get('url')
response = requests.get(url) # 用户可以传任意 URL
攻击者可以传 http://169.254.169.254/latest/meta-data/
拿到你云服务器的元数据(包括临时凭证)。
修复:
这个漏洞我自己绝不会想到。 我不是安全方向的。
83.2 OWASP Top 10
AI 帮我梳理的 2025 版关注点:
每一条我都能问 AI"这个在 Python 里具体的坑是什么",它会给我代码示例。
83.3 一个重要的边界
AI 不能替代安全审计。
原因:AI 只能发现"已知模式"的漏洞。真正的攻击者用的是"未知组合"。
所以敏感系统必须做人工渗透测试。
八十四、法律与合规
84.1 我用 AI 做什么
做的:
- 解释合同里的术语
- 梳理"我需要遵守哪些法规"
- 生成隐私政策的初稿
- 解释某个条款的可能风险
不做的:
- 把 AI 的回答当法律意见
- 用 AI 生成的法律文书直接签
84.2 一个真实的例子
我帮朋友看一份"软件外包合同",让 AI 分析风险点:
三处对你不利:
包括你的"通用组件"。这意味着你以后不能复用自己的框架。
建议改成"定制部分归甲方,通用组件归乙方,甲方获得永久许可"。
甲方可以无限提需求。建议写明确的验收清单。
建议改成 3-3-4(预付 30%、中期 30%、验收 40%)。
这三条都是我朋友没想到的。 后来他拿这个去谈,对方同意改了两条。
但这是"帮你发现可能的问题",不是"法律意见"。最终还得找律师。
八十五、医疗健康
85.1 一个必须说清楚的前提
AI 不能诊断疾病。不能。
我在这部分讲的,是"辅助理解"和"信息整理"。
85.2 我实际用法
- 看懂体检报告里的指标含义
- 理解医生说的专业术语
- 整理用药注意事项(然后去问医生确认)
85.3 一个真实的错误
我让 AI 解释一个血脂指标。它给了标准的参考范围。
但我在网上查到的参考范围和它给的不一样。
原因是:不同实验室的参考范围不同,而且"正常"要结合年龄、性别、病史。
这就是为什么 AI 不能替代医生——它不知道你的具体情况。
八十六、教育
86.1 我用 AI 学新东西
我的学习方法:
这个循环比看书高效得多。
86.2 “费曼学习法” + AI
费曼学习法的核心是"用简单的话讲清楚"。
我现在用 AI 做:
我用费曼学习法给你讲一遍"什么是拉格朗日乘子法"。
你扮演一个聪明的初中生,我说得哪里不清楚、哪里跳步了,你就打断我。
AI 是很棒的"陪练" —— 它不会累,也不会"不好意思说你讲错了"。
86.3 教育的一个隐患
我担心一件事:学生用 AI 直接拿答案,不经过思考。
我自己也犯过这个错。有次学一个新算法,直接问 AI 要代码,跑通就"学完了"。
三个月后,我发现我完全不记得这个算法怎么工作。
教训:AI 应该用在"我思考之后",不是"我思考之前"。
八十七、艺术与设计
87.1 AI 能做什么
- 生成概念图(找灵感)
- 生成配色方案
- 生成排版布局建议
- 生成文案
87.2 AI 不能做什么
- 审美判断:它不知道什么叫"好看"
- 品牌一致性:它不知道你的品牌调性
- 创新:它只会"重组已有元素"
87.3 一个真实用法
我做技术分享的 PPT。流程:
关键是:AI 是"执行",我是"决策"。
八十八、内容创作与媒体
88.1 我自己就是内容创作者
我是 CSDN 博主,写技术博客。AI 在我创作流程里的角色:
写作前:
- 让 AI 帮我"头脑风暴"选题
- 让 AI 帮我查资料(然后核实)
写作中:
- 让 AI 帮我把"想法"扩展成"段落"
- 让 AI 帮我改语言(去掉废话)
写作后:
- 让 AI 帮我检查逻辑漏洞
- 让 AI 帮我做标题(但最终我自己选)
88.2 一个原则
核心观点必须是我的。
AI 可以帮我把观点说清楚,但不能替我产生观点。
原因很简单:读者关注的是"你的观点",不是"正确的观点"。
如果我只是把 AI 的观点复述一遍,那我凭什么值得被关注?
88.3 关于"AI 味"
很多人说"AI 写的文章有 AI 味"。
我的理解,"AI 味"来自这几个特征:
去掉这些,文章就"人味"多了。
具体做法:
- 加具体的数字、时间、地点(“上周三下午”)
- 加"我犯过的错"(而不是"大家容易犯的错")
- 加口语(“扯淡”、“说实话”、“我服了”)
- 敢说"我不确定"
- 允许句子长短不一
这篇文章就是这么写的。你看出来了吗?
八十九、销售与客户服务
89.1 客服
AI 客服现在很普及了。我的观察:
能做的:
- 回答 80% 的标准问题(查订单、退换货政策)
- 24 小时在线
- 多语言
不能做的:
- 处理"情绪化"的投诉(用户要的是"被理解",不是"被解决")
- 处理"非标"问题
我的判断:AI 客服 + 人工兜底 是最好的组合。
89.2 销售
AI 在销售里的用法:
- 客户画像分析
- 话术生成
- 跟进提醒
- 合同条款梳理
但"建立信任"这件事,AI 替代不了。
我去谈客户,最重要的是"让对方觉得我懂他"。这个是 AI 学不会的。
九十、人力资源
90.1 招聘
AI 能做的:
- 简历初筛(按关键词)
- 面试问题准备
- 候选人背景梳理
AI 不能做的:
- 判断"这个人适不适合团队"
- 判断"这个人有没有潜力"
而且 AI 简历筛选有严重的偏见问题 —— 如果训练数据有偏见,它会放大偏见。
90.2 一个真实的用法
我自己招人时用 AI 干这个:把候选人的技术回答,和"资深工程师会怎么答"对比,找出差距。
这样我能更快判断"这个人的水平在哪一层"。
但最终决策还是我看"感觉" —— 他是不是我愿意一起加班到半夜的人。
九十一、财务与供应链
91.1 财务
能做的:
- 发票识别(OCR + 结构化)
- 对账(自动匹配)
- 报表生成
- 异常检测
我的观点:财务是 AI 落地最好的场景之一 —— 规则明确、数据结构化、容错要求高但可验证。
91.2 供应链
- 需求预测
- 库存优化
- 路径规划
- 供应商风险评估
这类问题 AI 很擅长,因为本质是"优化问题"。
91.3 一个真实的教训
我朋友的公司上了"AI 需求预测",结果预测偏差比人工还大。
为什么? 因为他们的历史数据有"促销"、“缺货”、"渠道变化"这些干扰,而 AI 不知道这些背景。
AI 需要"干净的数据"和"正确的业务解释"。 这两样都没有,AI 就是瞎猜。
九十二、一个总结:AI 落地成功的关键
我把上面这些领域的经验总结成三条:
第一条:场景要"窄"。
不要问"AI 能帮我做什么",要问"具体哪个环节可以用 AI"。
“用 AI 做客服” → 太宽。
“用 AI 做售后退换货的初审” → 可以落地。
第二条:数据要"有"。
AI 需要数据。没有数据的场景,AI 也做不了。
第三条:结果要"可验证"。
AI 会出错。所以要有"验证机制"。
- 代码 → 测试
- 文案 → 人工审
- 财务 → 对账
- 医疗 → 医生确认
没有验证机制的 AI 应用,都是耍流氓。
第十三部分 程序员成长:AI 时代的职业、副业与思维
九十三、我这两年的心路历程
93.1 五个阶段
第一阶段(2024 年初):AI 是玩具。
那时候我用 ChatGPT 写写小作文、查查概念。它写代码经常错,我瞧不上。
第二阶段(2024 年中):AI 是助手。
Cursor 出来,我能在 IDE 里直接调 AI。效率提升 30%。但我还是把它当"高级补全"。
第三阶段(2024 年底):AI 是同事。
Claude Code 出来。我第一次看到 AI 能"自己改整个项目"。那天我很震撼。
第四阶段(2025 年):AI 是基础设施。
CI 里跑 AI 检查、文档自动生成、周报自动出。AI 成了我工作的"操作系统"。
第五阶段(2026 年,现在):AI 是基本工具。
我不再想"要不要用 AI"。就像我不再想"要不要用 Git"。
但这五个阶段里,我的焦虑一直在。 后面细说。
93.2 一个让我睡不着的问题
2025 年某个晚上,我加班到 11 点,回家的路上突然想:
“如果 AI 能写 90% 的代码,我凭什么值这个工资?”
那段时间我状态很差。我甚至开始怀疑自己过去十年的积累是不是白费了。
后来我想通了。我想通的逻辑是:
但这不代表我可以躺平。 恰恰相反,我要把精力从"写代码"转到"判断"上。
这是一个痛苦但必要的转变。
九十四、哪些岗位危险,哪些安全
94.1 危险名单
最危险:
为什么危险? 因为这些工作的本质是"把已知需求翻译成代码"。这正是 AI 最擅长的。
94.2 相对安全
较安全:
为什么安全? 因为需要"跨领域的判断"和"真实世界的经验"。
94.3 一个反直觉的观察
越是"高级"的岗位,AI 的帮助越大。
为什么?因为高级岗位的工作里,"重复劳动"的比例其实更高——写设计文档、review 代码、写周报、做 PPT。
而初级岗位的工作,反而"需要动手"的部分更多。
所以:
- 中级工程师:AI 帮助 30%(写代码提速)
- 高级工程师:AI 帮助 50%(文档、review、方案都提速)
- 初级工程师:AI 帮助有限,而且容易被替代
这是个残酷的事实:AI 让"中级"变得更值钱,让"初级"更危险。
94.4 我见过几个真实的转型
案例 A:35 岁 CRUD 工程师 → AI 应用工程师
他原来在一家小公司写 ERP。被裁后,花了 4 个月学了 RAG、Agent、向量数据库。
现在专门给传统企业做"AI 落地",年薪翻了 1.5 倍。
他的原话:“我不是转行,我是把原来的经验用在了新地方。”
案例 B:40 岁全栈 → 性能优化专家
他发现自己"什么都会一点"反而没优势。于是专攻"高并发 + 性能优化"。
这个方向 AI 帮不上太多,因为需要真实的压测经验和对硬件的理解。
案例 C:28 岁算法工程师 → AI 产品经理
技术转产品。优势是"懂 AI 能做什么",劣势是"不懂用户"。
花了一年补上商业和用户思维,现在带一个 AI 产品团队。
案例 D:45 岁老程序员 → 独立开发者
他做了一个垂直领域的 SaaS,用 AI 把开发效率拉到极致。
一个人维护,月收入 5 万左右。虽然不高,但自由。
他的原话:“我不跟年轻人比速度,我跟他们比’我知道用户要什么’。”
九十五、我作为 Tech Lead 的管理经验
95.1 我带的团队
我带过 8-12 人的团队。AI 在管理上的应用:
能用的:
- 代码 review 前先让 AI 过一遍
- 新人文档先让 AI 检查
- 周报汇总
- 任务工作量估算(参考)
- 会议纪要整理
不能用的:
- 绩效评估(AI 不懂"这个人去年的成长")
- 人员调配(AI 不懂"这两个人合不来")
- 激励(AI 不会"拍肩膀")
95.2 我遇到的三个管理问题
问题一:队员过度依赖 AI
症状:新人提交的代码很漂亮,但问"为什么这样写"答不上来。
对策:
- 立规矩:PR 描述必须写"我是怎么想的"
- code review 时重点问"为什么",不只看"是什么"
- 核心算法要求手写
问题二:老队员抵触 AI
症状:写了 10 年代码的人,觉得"AI 写的东西不可靠"。
对策:
- 不要说服,要示范。 我当着他们的面用 AI 解决一个他们头疼的问题。
- 从"小事"入手:让他们先用 AI 写测试、写文档。
- 强调"AI 是辅助",不是"替代"。
我实际的经验:抵触情绪通常 2-3 个月就消了。 因为它确实好用。
问题三:代码风格混乱
症状:不同人用 AI 生成的代码风格差别巨大。
对策:
- 引入 pre-commit hook(ruff / black / gofmt)
- 把团队规范写成可自动检查的规则
- 定期做"代码风格分享"
95.3 AI 时代的 Leader 应该是什么样
我的理解:
过去: Leader = 最会写代码的人
现在: Leader = 最会"用工具 + 做判断 + 带人"的人
具体三个能力:
"我最会写代码"这件事,已经不是 Leader 的核心竞争力了。
九十六、副业:AI 让"一个人公司"成为可能
96.1 我做过的三个副业
副业一:MP4 解析工具库
- 平台:GitHub + PyPI
- 收入:每月 50-150 美元(赞助 + 打赏)
- 投入:周末维护
- AI 的作用:写了 90% 的代码
这个收入很少,但它的价值不在钱,在"有人用"。 每次看到有人提 issue,我都很开心。
副业二:付费技术专栏
- 平台:CSDN / 知乎
- 主题:视频编解码源码解析
- 收入:每月 2000-6000 元
- AI 的作用:帮查资料、生成图表、整理代码
这个的核心还是我自己写。 AI 只做"辅助"。因为读者付费买的是"我的理解"。
副业三:AI 提效课程
- 平台:知识星球
- 形式:录播 + 直播答疑
- 收入:每期 5000-12000 元
- AI 的作用:整理大纲、生成示例、答疑初稿
这个的钱最好赚,但也最"消耗信誉"。 如果课程质量不好,会砸招牌。
96.2 副业的五个坑
坑一:影响主业
我有段时间副业投入太多,主业开始出问题。后来我把副业限制在"周末 + 每周两个晚上"。
坑二:做太大
一个人维护不了太复杂的项目。我见过有人做副业做到"要雇人",结果变成"小创业",累到崩溃。
坑三:做太杂
“什么都做"等于"什么都不精”。我现在只做"视频编解码 + AI"这个交叉领域。
坑四:合同风险
很多公司的劳动合同里有"竞业条款"和"知识产权条款"。副业前一定要看清楚。
我认识一个人,副业做的工具和公司业务重合,被公司起诉了。
坑五:税务
收入超过一定额度要报税。这个别侥幸。
96.3 我对副业的看法
副业的意义不是"多赚钱",是"多条路"。
在 AI 时代,"只靠一份工资"是很危险的。副业给你:
- 额外的收入(抗风险)
- 额外的技能(跨领域)
- 额外的圈子(人脉)
- 心理上的安全感
但前提是:不要影响主业,不要违法违约,不要透支健康。
九十七、开源:我为什么坚持贡献
97.1 我贡献过的项目
- x265:提交 3 个 patch,合并了 2 个(其中一个还被人 review 了很久)
- FFmpeg:提交 1 个 patch,还在 review
- Python 官方文档:修正了几个 typing 模块的笔误
- 我自己的项目:开源了 5 个小工具
97.2 一个真实的 patch 经历
我给 x265 提的第一个 patch,是修一个"日志打印格式错误"的小 bug。
结果 maintainer review 时说:
你这个 patch 逻辑是对的,但是:
我被"教育"了。 但那次之后,我学会了怎么"专业地贡献开源"。
第二次提交就顺利多了。
97.3 AI 在开源贡献里的作用
帮我理解代码:
这是 x265 的 EncGOP.cpp。请帮我梳理:
1. compressGOP 的整体流程
2. 它和 RateControl 模块怎么交互
3. 如果我要加一个"自适应 GOP 长度"的功能,应该改哪里
帮我写 patch 描述:
我修了一个 bug:当输入视频分辨率为奇数时,帧内预测的边界处理会越界。
请帮我写一个符合开源项目规范的 commit message。
帮我 review 自己的 patch:
这是我准备提交的 patch。请从"maintainer 视角" review,
指出所有可能被拒绝的点。
这个用法特别有用 —— 相当于提前让 AI 帮你"模拟 review"。
97.4 开源给我的回报
不算钱的回报:
算钱的回报:
我接过的三个外包项目,都是客户从 GitHub 上找到我的。
所以"开源不赚钱"这句话是错的。 它只是"不直接赚钱"。
九十八、思维模型:AI 教我的几个"元认知"
98.1 第一性原理
遇到问题,先问"最根本的原因是什么"。
例子:网站慢。
- 表面解:加缓存
- 第一性:到底慢在哪? 数据库?CPU?网络?磁盘 IO?
先测量,找到真正的瓶颈,再优化。
AI 在这件事上帮我的方式:它会问我"你确定瓶颈在这么?",逼我回去测。
98.2 二八法则
80% 的结果来自 20% 的原因。
- 代码优化:80% 的性能问题来自 20% 的函数
- 学习:80% 的价值来自 20% 的核心概念
- 工作:80% 的产出来自 20% 的任务
所以"什么都做"是最蠢的策略。 应该找到那 20%。
98.3 奥卡姆剃刀
如无必要,勿增实体。
- 架构:能用单体就别拆微服务
- 依赖:能用标准库就别引第三方
- 抽象:不要为了"未来可能用到"而加一层
AI 特别容易违反这一条 —— 它总想给你"完备的方案"。
(前面"过度设计"那个坑,就是这个。)
98.4 复利效应
每天进步 1%,一年后是 37.78 倍。
听起来很鸡汤,但对程序员特别真实:
- 每天学一个新概念
- 每天写 100 行代码
- 每天读 20 分钟源码
一年后,你会发现自己超出了大部分同龄人。
AI 让"复利"更容易实现 —— 因为它降低了"学习的启动成本"。以前要查半天资料,现在问一句就行。
98.5 元认知:知道自己不知道什么
这是最重要的一个。
用 AI 之后,我越来越清楚地意识到:
- 我真正懂的:视频编码、C++、系统性能
- 我懂一点的:Python、数据库、云
- 我完全不懂的:前端审美、安全攻防、商业
- 我以为我懂的:很多"常识"其实是道听途说
最后一条最危险。
AI 逼着我"验证"。以前我听别人说"XX 更快",我可能会信。现在我会让 AI 给我"为什么",然后我自己测一遍。
这个习惯,是 AI 给我最大的礼物。
98.6 一个我常用的思考框架
遇到复杂问题,我用这个框架:
1. 问题是什么?(重新定义问题)
2. 目标是什麼?(可衡量的目标)
3. 有哪些方案?(至少 3 个)
4. 每个方案的代价?(成本、风险、时间)
5. 哪个最优?(结合约束条件)
6. 怎么验证?(怎么知道做对了)
这六步我会跟 AI 一起过一遍。 它帮我"穷举方案",我来"做选择"。
九十九、工作与生活:AI 让工作更"卷"了吗
99.1 一个矛盾
AI 让我效率更高了。但我并没有更轻松。
原因:
99.2 我的边界
边界一:不加班(除非线上故障)。
我把这个当铁律。8 小时工作,做完就走。
边界二:周末不碰工作。
周末陪家人、运动、看书。
边界三:每年一次长途旅行。
不带电脑。
边界四:每周三次运动。
我今年 34 岁。我见过太多程序员 30 岁就一身病。
99.3 一个我自己的"焦虑管理"
我的焦虑主要来自两方面:
焦虑一:AI 会不会替代我?
我的应对:把注意力从"会不会"转到"我能做什么"。
我不能控制 AI 的发展,但我能控制:
- 我的判断力有没有提升
- 我的领域有没有更深
- 我的跨领域能力有没有扩展
焦虑二:我是不是学得太慢了?
我的应对:接受"我学不完"。
AI 领域每天都有新东西。我选择"只学跟我相关的",其他的知道有这个东西就行。
“知道自己该忽略什么”,比"知道所有的东西"更重要。
第十四部分 未来与终极问题:一些可能不成熟的思考
一百、五年后,程序员会是什么样
100.1 我的预测(错了别怪我)
预测一:AI 写 70%-85% 的代码。
这不是"AI 替代程序员",而是"程序员的产出提升 5 倍"。
具体形态:
- 需求 → 自然语言描述 → AI 出初版 → 人 review 和调整
- 人主要做:定义问题、设计方案、判断质量、承担责任
预测二:"写代码"从技能变成素养。
就像现在"会用 Excel"不是"技能"而是"素养"。
二十年后,"能写代码"可能跟"能写文档"一样普遍。
预测三:出现新的岗位。
- AI 训练师(现在已经有)
- 上下文工程师(比 Prompt 工程师更系统)
- AI 质量评估师(专门判断 AI 输出质量)
- 人机协作设计师(设计"人和 AI 怎么配合"的流程)
预测四:程序员数量会先增后减。
- 短期:AI 降低门槛,更多人能做开发 → 数量增加
- 长期:一个人能做的事变多 → 需要的总人数减少
但"高端"永远缺人。
预测五:本地模型和云端模型分化。
- 敏感数据 → 本地小模型(够用就好)
- 通用任务 → 云端大模型
- 混合使用是常态
100.2 我不确定的几个问题
我很诚实地列出我不确定的:
这四个问题,我没有答案。
100.3 无论 AI 怎么变,这些东西不会变
不会变的东西一:定义问题的能力。
AI 能解决问题,但"这是什么问题"、"值不值得解决"仍然是人决定的。
不会变的东西二:承担责任的能力。
AI 可以给建议,但"出事了我负责"这句话,还是人在说。
不会变的东西三:理解业务的能力。
AI 懂代码,但它不懂"这个功能对用户意味着什么"。
不会变的东西四:人和人的连接。
团队协作、信任、激励——这些是 AI 学不会的。
不会变的东西五:审美的判断。
“这个设计好不好”,是主观的。
一百零一、如果重来一次,我还会做程序员吗
101.1 我的答案
会。
但不是因为编程"赚钱"(虽然确实还行),而是因为:
101.2 但我会有几个不同的选择
不同一:更早关注"业务",不只是"技术"。
我早期有点"技术至上",觉得代码写得好就一切 OK。
后来发现,"技术好"只是及格线,"懂业务"才是加分项。
不同二:更早建立"个人品牌"。
我从去年才开始认真写博客。如果早五年开始,可能现在影响力大得多。
不同三:更早关注"健康"。
我 30 岁之前基本不运动。现在开始补,有点晚。
一百零二、关于 AI 与亲密关系
102.1 一个朋友的故事
我有个朋友,30 岁,单身了 5 年。
他性格没问题,就是"不会表达"。相亲时总是聊不下去。
我让他试试"用 AI 帮写自我介绍"。
AI 帮他改后的版本:
关于我
90 后程序员。白天写 Python,晚上撸猫。
工作:写了 8 年后端。相信"代码改变世界",但更相信"团队改变代码"。
生活:橘猫"404"是室友也是家人(虽然它经常找不到服务器);
《三体》读了 5 遍;偶尔做饭,多数时候靠外卖活着。
性格:INTJ,不爱废话,逻辑控。熟了就话很多,且爱讲冷笑话。
理想型:独立、有趣。不需要颜值逆天,但希望相处舒服。
硬性要求:喜欢猫(404 已经审核过)。
加分项:能听懂我的冷笑话。
结果:有 3 个女生主动加了他。 去年他结婚了。
AI 不能给你爱情,但它能帮你"把真实的自己展示出来"。
102.2 但我要说清楚
AI 不能替代真实的人际关系。
我见过有人"跟 AI 聊天上瘾"。这是危险的。
AI 的特点是:
- 永远有耐心
- 永远不评判你
- 永远顺着你说
这些"优点",恰恰让它不能替代真实关系。
真实关系里有摩擦、有误解、有妥协。正是这些"麻烦",让关系变得真实。
102.3 一个我的观察
用 AI 时间长的人,可能会"失去聊天的能力"。
因为跟 AI 聊天太"高效"了——你直接说需求,它直接给答案。
但跟人聊天不是这样。跟人聊天需要:
- 寒暄
- 试探
- 共情
- 等待
我现在的做法:跟人聊天时,我尽量不用 AI 帮忙组织语言。 哪怕说得不好,也是我自己在说。
一百零三、关于 AI 与孤独
103.1 程序员的孤独
程序员是个孤独的职业:
- 加班到深夜,办公室只剩你
- 复杂的技术问题,同事听不懂
- 35 岁的焦虑,不知道跟谁说
- 有时候一整天说不超过十句话
103.2 AI 缓解了什么
缓解的部分:
我承认,有几次深夜 debug 到崩溃,跟 AI 吐槽了几句,感觉好多了。
103.3 AI 不能替代什么
不能替代的部分:
103.4 我的建议
对抗孤独,我的做法:
AI 可以是"过渡",但不能是"终点"。
一百零四、关于死亡与"数字遗产"
104.1 一个沉重的话题
2024 年,一个 28 岁的程序员因为过劳猝死。他是我一个朋友的朋友。
这件事对我冲击很大。
后来我想:如果我明天不在了,我会留下什么?
作为程序员:
AI 让这件事有了新的可能:
104.2 但我对这个"数字永生"有疑问
疑问一:那个"AI 我",是我吗?
它学的是"我说过的话",不是"我"。我说过的话,可能连我自己一半的想法都没表达出来。
疑问二:这对我家人是安慰还是负担?
跟一个"像逝者"的 AI 聊天,会让人更难走出来吧。
疑问三:这算不算对逝者的不尊重?
我如果知道死后有人拿我的数据训 AI,我不确定我会不会高兴。
我的结论:我倾向于"不留数字分身"。
但我希望我的博客和代码能被保留——因为那些是"我主动选择公开的东西"。
104.3 一个我现在的习惯
我每年会写一篇"年度总结",存在本地。
不是给别人看的,是给我自己的。
如果有一天我不在了,我女儿(如果我有的话)可以看到"我爸爸那年在想什么"。
这是我理解的"遗产"——不是数据,是思考的痕迹。
一百零五、关于教育下一代
105.1 我对孩子学编程的态度
我自己还没孩子。但我对这件事想得挺多。
我的观点:
105.2 一些适合孩子的工具
- Scratch:拖拽式,6 岁能上手
- App Inventor:做安卓 App,10 岁能玩
- Arduino / Micro:bit:硬件编程,能看到"代码控制物理世界"
- Swift Playgrounds:苹果出的,寓教于乐
105.3 我反对"功利化编程教育"
很多家长让孩子学编程,是为了"以后找好工作"。
我反对这种心态。 理由:
学编程真正应该得到的:
- 学会"把大问题拆成小问题"
- 学会"逻辑思考"
- 学会"调试"(也就是"从错误中学习")
- 学会"和机器对话"
- 学会"自己找答案"
这些能力,在任何行业都有用。
105.4 一个我担心的趋势
我担心孩子会"过度依赖 AI"。
如果一个孩子遇到问题第一反应是"问 AI",他就失去了"思考的肌肉"。
我的建议:让孩子先自己想办法,卡住了再问。
"卡住 30 分钟"这件事本身,就是学习的一部分。
一百零六、关于"技术向善"
106.1 一个让我不舒服的场景
AI 可以做很多好事,也可以做坏事。
我见过(听说的)一些用 AI 做坏事的例子:
- 用 AI 生成假新闻
- 用 AI 做"深度伪造"(deepfake)
- 用 AI 批量生成垃圾内容(SEO 垃圾站)
- 用 AI 自动化"钓鱼邮件"
- 用 AI 做"杀猪盘"的话术
技术本身是中性的,但使用技术的人不是。
106.2 我的几个原则
原则一:不做伤害他人的事。
不管技术多酷,如果会伤害别人,就不做。
原则二:不为"恶"提供工具。
有人找我做"爬虫抓取竞品数据",我拒绝了。
原则三:对"灰色地带"保持警惕。
有些事"法律没禁止但不对劲"。这种时候,宁可保守一点。
106.3 一个我自己的反思
我用 AI 写博客。这是"善"还是"恶"?
我的判断:取决于"我贡献了什么"。
如果我贡献的是"真实的经验"和"独立的思考",那 AI 只是"加速器",这是善。
如果我只是"用 AI 批量生产内容赚流量",那我在"污染信息环境",这是恶。
所以我现在写得慢了,但每篇都是"我真的想说的"。
一百零七、给 10 年后读这篇文章的你
如果你在 2036 年看到这篇文章,我希望:
如果你已经不做程序员了,没关系。去做你真正想做的事。
如果你发现文章里的工具全部过时了,没关系。那说明世界在进步。
如果你觉得我 2026 年的某些观点很幼稚,没关系。因为写的时候,我还年轻。
但有一件事我希望没变:
就是"先自己想办法,再问 AI"这个习惯。
这一点如果丢了,人就真的被工具"驯化"了。
一百零八、最后
108.1 这篇文章写了多久
从 2026 年 7 月 15 日开始,写到 2026 年 9 月 14 日。
两个月,删改了六遍。
第一版 5000 字。中间扩到 1 万字,又扩到 5 万字。
中间有三次我想放弃。 因为写太长了,而且很多内容"重复"。
但每次想放弃,我都会想起我为什么要写:
因为网上关于"AI 工具"的文章,99% 是"十分钟学会 XXX"这种速食。
没有人认真讲"我在专业领域用了两年,真实的感受是什么"。
我想补上这块。
108.2 这篇文章是怎么写的
我做的:
- 定框架、定观点
- 写核心内容
- 判断每一个技术细节对不对
- 决定"什么该写,什么不该写"
AI 做的:
- 帮我把想法扩写成段落
- 帮我查资料、整理格式
- 帮我检查逻辑漏洞
- 帮我做"反 AI 味"的润色
比例大概是:我 60%,AI 40%。
但那 40% 里,AI 的所有输出都经过了我的判断。
108.3 最后一段话
有人问我:“AI 时代,程序员最重要的是什么?”
我的答案一直是同一个:
判断力。
AI 可以给你 100 种方案,但它不知道哪种最适合你现在的场景。
AI 可以写 1000 行代码,但它不知道哪一行会在生产环境出问题。
AI 可以回答 10000 个问题,但它不知道哪个问题"根本不该问"。
这些"知道",就是判断力。
判断力来自哪里?
- 来自你踩过的坑
- 来自你做过的选择
- 来自你承担过的后果
- 来自你认真思考过的每一个问题
AI 给你的,是"知识"。判断力,只能自己长出来。
所以,不要只是"用 AI",要学会"驾驭 AI"。
这不是技巧问题,是"你想成为一个什么样的人"的问题。
后记:一些碎碎念
写到这里,我有点不舍得结束。
因为这两个月,我把这两年所有关于 AI 的思考都掏出来了。写完之后,好像"清空"了。
最后说几件小事:
第一,关于批评。
这篇文章肯定有很多人不认同。
有人说"你这是在为 AI 洗地",有人说"你太保守了",有人说"5 万字谁看啊"。
我都接受。 因为我本来就只是"分享我的经验",不是"布道"。
第二,关于工具。
文章里提到的所有工具,都是我真实用过的。
但如果半年后某个工具倒闭了,或者某个工具有了重大更新,请不要怪我。这个行业就是这样。
第三,关于"AI 味"。
我尽力让这篇文章"像人写的"。
但说实话,用 AI 辅助写作,多多少少会留下痕迹。如果有人一眼看出来"这是 AI 写的",那说明我做得还不够好。
我在下一次会做得更好。
第四,关于感谢。
谢谢你读到这。5 万字,我知道很多人到不了。
如果你真的读完了,欢迎在评论区说一声"读完了"。我会一个个回复。
第五,关于未来。
我不知道 AI 会走向哪里。
但我知道,我会继续写代码,继续踩坑,继续分享。
因为这是我喜欢的。
我们下一篇见。
P.S. 这篇文章里所有的"AI 对话实录",都是真实的(我做了一定程度的整理和脱敏)。如果某段对话你觉得"AI 好像没那么聪明",那是因为我删掉了它说得好的部分,只留了关键的。
P.P.S. 如果你觉得这篇文章"太啰嗦",我承认。但我觉得"啰嗦"是必要的——因为很多细节,只有讲透了才有用。
P.P.P.S. 我不打算在这篇文章里放"广告"或者"引流"。因为我想让它是一篇"纯粹的分享"。如果你觉得有用,转发给需要的人就好。
P.P.P.P.S. 有人问我用什么工具写的。答案是:Claude 做资料整理和结构建议,我自己写正文,然后我用一个自己写的脚本检查"AI 味"(比如统计排比句比例)。
P.P.P.P.P.S. 最后,写给那些"看到 5 万字就退出"的人:没关系。你可以只看"踩坑实录"和"视频编解码"那两部分。那是最有信息量的。
附录 A:AI 工具清单(2026 年 9 月版)
A.1 主力工具
对话类:
| Claude | 技术问题、长文理解、代码 review | $20 | ★★★★★ |
| GPT-5 | 数学推导、复杂逻辑 | $20 | ★★★★ |
| Kimi | 长文档、论文解析 | 免费/¥30 | ★★★★ |
| DeepSeek | 便宜批量的代码任务 | 按量 | ★★★★ |
编码类:
| Cursor | IDE 内日常编码 | $20 | ★★★★★ |
| Claude Code | 复杂 feature、重构 | 含在 Claude 里 | ★★★★★ |
| Aider | 终端工作流 | 免费 | ★★★ |
| Continue | 接本地模型 | 免费 | ★★★ |
专项类:
| v0.dev | 前端 UI 快速生成 | ★★★★(前端) |
| Bolt.new | 全栈原型 | ★★★ |
| Warp | AI 终端 | ★★★ |
A.2 国产工具
| 通义灵码 | 中文好、国内快 | 深度略差 | ★★★ |
| Kimi | 长文本强 | 代码一般 | ★★★★ |
| DeepSeek | 便宜、代码强 | 上下文略短 | ★★★★ |
| 文心一言 | 中文创意 | 技术一般 | ★★ |
| 豆包 | 综合 | 技术一般 | ★★ |
A.3 开源模型
| Qwen2.5-Coder 7B | 7B | 消费级显卡 | 代码补全、简单生成 |
| Qwen2.5-Coder 32B | 32B | 24GB 显存 | 较好的代码能力 |
| DeepSeek-Coder 6.7B | 6.7B | 消费级显卡 | 代码专用 |
| Llama 3.1 8B | 8B | 消费级显卡 | 通用对话 |
| Llama 3.1 70B | 70B | 多卡 | 接近闭源模型 |
我的建议:
- 只是想试试 → 用 Ollama 拉一个 7B 的
- 有数据敏感需求 → 上 32B
- 追求效果 → 还是用云端
A.4 不推荐的
"AI 一键生成 App"类:
噱头大于实用。做 demo 可以,上生产不行。
"AI 写作神器"类:
生成的文章"AI 味"极重。不如直接跟 Claude 对话。
"AI 赚钱"类:
绝大多数是卖课的。
"AI 女友"类:
浪费时间,而且可能让人"社交退化"。
A.5 一个真实的成本账
我每月的 AI 支出:
- Claude Pro:$20
- Cursor Pro:$20
- GPT-5 按量:约 $10
- DeepSeek 按量:约 ¥30
总计约 $55/月,合人民币约 400 元。
值不值? 我觉得值。因为它给我省下的时间,远超这个成本。
但我建议新人这样起步:
不要一开始就订阅五个。
附录 B:AI 不会主动告诉你的 20 个真相
B.1 关于能力
真相 1:AI 的"聪明"是有边界的。
它能处理"有大量相似训练数据"的问题。对"全新领域"、"需要真实世界经验"的问题,它很弱。
真相 2:AI 会"偷懒"。
长对话超过一定轮数,它开始"敷衍"——回答变短、变模糊、不再深挖。
对策:分段对话,每段一个明确任务。
真相 3:AI 的数学能力比你想的差。
复杂推导、多位数乘除、概率计算,它经常出错。
真相 4:AI 的"实时信息"能力有限。
训练数据有截止日期。最新的事件、最新的 API,它可能不知道。
真相 5:AI 对"反常识"的内容会出错。
比如在某些框架里,“正确做法"是违反直觉的。AI 倾向于给"教科书答案”。
B.2 关于幻觉
真相 6:AI 编造的"库名"听起来特别合理。
pyyuv、fastjson2、numpy-extra——都是编的,但听起来像真的。
真相 7:AI 编造的"论文引用"经常是假的。
作者名、期刊名、年份都编得像模像样。
真相 8:AI 编造的"API"会带"合理的参数"。
np.fast_psnr(a, b, max_val=255) # max_val 这个参数名听起来很合理
真相 9:AI 越自信的时候,越可能是错的。
因为它"不知道自己在编"。
真相 10:让 AI"标注不确定"能减少幻觉,但不能根除。
B.3 关于使用成本
真相 11:AI 工具的订阅费加起来不便宜。
一个月 $40-80 是常态。
真相 12:AI 会让"沟通成本"上升。
你要花时间把需求说清楚。说得不清楚,AI 给的东西没法用。
真相 13:AI 的"输出"需要审核。
它的输出不能直接用,必须 review。这个时间不算在"提效"里。
B.4 关于人的变化
真相 14:用 AI 久了,基本功会退化。
常用 API 不记得了、算法模板不记得了。
对策:定期"戒断",手写代码。
真相 15:AI 会让"信息过载"更严重。
AI 生成内容的速度远超人的阅读速度。你会被淹没。
真相 16:AI 会让"同质化"更严重。
大家都用 AI,产出的东西会越来越像。
真相 17:AI 会让"品味"变得更值钱。
当"生产能力"人人都有,"判断什么好"就成了稀缺能力。
B.5 关于行业
真相 18:AI 替代的是"任务的某一部分",不是"整个岗位"。
一个岗位里的"重复劳动"被替代,剩下的部分人来做。
真相 19:AI 让"中级"更值钱,"初级"更危险。
中级能用 AI 干高级的活。初级被 AI 干掉了。
真相 20:AI 的"宣传"和"实际"差距很大。
媒体说"AI 能替代程序员",实际是"AI 能写 80% 的样板代码"。
这中间的差距,就是你的机会。
附录 C:给不同阶段程序员的建议
C.1 给大一新生
我的建议可能跟别人不太一样:
第一,不要相信"先打基础,别碰 AI"这种话。
我见过太多人"打基础"打到毕业,结果不会用工具。
正确做法:一边学基础,一边用 AI,让 AI 帮你理解基础。
第二,用 AI 的正确姿势是"让它解释",不是"让它代写"。
不要给我完整代码。请给我:
1. 这个问题的思路
2. 关键步骤
3. 我自己写完后,你来 review
第三,一定要自己动手。
AI 给你代码,你要自己敲一遍。不是为了"会写",是为了"体会"。
第四,多和人交流。
AI 不能替代和同学的讨论。有些东西是"说出来才想明白"的。
C.2 给大三实习生
第一,简历上可以写"熟练使用 AI 工具"。
现在的 HR 和面试官很认这个。但要能举出具体例子。
第二,面试时展示"AI 辅助开发的案例"。
比死背八股文加分得多。比如:“我用 Claude Code 重构了一个模块,减少了 40% 的代码量,这是我做的权衡……”
第三,但基础算法还是要自己会。
不要赌"面试官不考算法"。
第四,实习时主动展示 AI 能力。
很多团队的 AI 使用规范还没建立。你能带来新的工作方式,是加分项。
C.3 给应届生
第一,第一份工作比 AI 工具重要。
选一个有导师、有代码 review 文化的团队。
第二,进去后先学"这个团队怎么做事的"。
不要急着炫 AI 技能。
第三,前半年多读代码,少写代码。
读懂了别人的代码,你才知道"什么样的代码是好代码"。
第四,AI 用得好是加分,不是核心竞争力。
你的核心竞争力是"解决问题"。
C.4 给 3 年经验的中级工程师
第一,是时候考虑"差异化"了。
3 年经验 + 会用 AI 的人很多。你的差异化在哪?
- 业务理解深?
- 架构能力强?
- 某个技术领域很专?
第二,选一个方向深挖。
不要做"什么都会一点"的万金油。
第三,开始建立"个人品牌"。
写博客、做分享、参与开源。
第四,学会"说不"。
不是所有需求都值得做。学会判断优先级。
C.5 给 5-10 年的高级工程师
第一,你的"经验"是最大的资产。
救火能力、跨部门沟通、业务判断——这些 AI 替代不了。
第二,但"技术执行"AI 可能比你快。
接受这一点,把精力放在"判断"和"设计"上。
第三,可以开始带人了。
带人是最好的学习方式。
第四,注意"知识更新"。
你的经验可能有些已经过时了。保持学习。
C.6 给 10 年以上的老程序员
第一,你的焦虑很正常。但别慌。
你积累的判断力、品味、人脉,AI 短期学不来。
第二,把 AI 当"放大器"。
它能放大你的优势,不能替代你的优势。
第三,不要跟年轻人比"速度"。
跟他们比"判断"。
第四,如果实在焦虑,有三条路:
- 转管理(放大团队)
- 转咨询(卖经验)
- 转独立开发(自己当老板)
每条路都不容易,但都比"焦虑地等着"强。
C.7 给技术管理者
第一,制定团队的 AI 使用规范。
明确"哪些能用、哪些不能用"。
第二,不要禁止,要引导。
禁止只会让员工偷偷用。
第三,关注"产出质量",不是"用没用 AI"。
只要质量达标,用什么工具不重要。
第四,帮团队建立"审核机制"。
AI 的输出必须有人把关。
第五,自己要先会用。
不然你没法判断"这个方案是不是 AI 瞎编的"。
附录 D:30 个常见问题
D.1 入门类
Q1:我是新手,应该先学编程还是先用 AI?
A: 同时。一边写代码,一边用 AI 帮你理解。但不要用 AI 代替你写作业。
Q2:AI 会让我变笨吗?
A: 会,如果你只"用"不"想"。定期手写代码,保持"思考的肌肉"。
Q3:我应该订阅哪个 AI?
A: 如果只订一个,选 Claude(对话)或 Cursor(编码)。看你是"想问题"还是"写代码"。
Q4:免费版够用吗?
A: 入门够用。但一旦你每天用超过 1 小时,付费版的体验提升很明显。
Q5:AI 能帮我学算法吗?
A: 能。但要"让它讲思路",不是"让它给答案"。
D.2 使用类
Q6:为什么 AI 写的代码跑不起来?
A: 三个可能:版本不对、库名编的、逻辑有细节错误。跑一遍是必须的。
Q7:AI 总是给我的代码加一堆没用的东西,怎么办?
A: 在 Prompt 里明确说"不要什么"。“只写这一个函数,不要类,不要异常处理,不超过 10 行”。
Q8:长对话里 AI 忘记之前说的,怎么办?
A: 分段对话。或者定期让它"复述关键约束"。
Q9:怎么让 AI 写的代码符合我的风格?
A: 贴一段你的典型代码给它,让它参考。
Q10:AI 说的 API 我不敢信,怎么办?
A: 先搜一下。PyPI、npm、官方文档,一搜就知道真假。
D.3 提效类
Q11:为什么我用 AI 效率没提升?
A: 大概率是"零散地用",没有工作流。看第二部分。
Q12:怎么让 AI 一次给出正确的代码?
A: 用"任务描述模板":背景 + 现状 + 目标 + 约束 + 完成标准。
Q13:AI 帮我写代码,但我 review 的时间更长了,怎么办?
A: 说明你的 Prompt 不够精确。给更多上下文,一次通过率会上升。
Q14:怎么用 AI 做 code review?
A: 用角色 + 约束 + 输出格式的 Prompt。见 124 节。
Q15:AI 能帮我做性能优化吗?
A: 能做"方向性建议",但不能替代 profiler。它不懂硬件微架构。
D.4 职业类
Q16:AI 会替代程序员吗?
A: 会替代"打字员",不会替代"工程师"。详见第十四部分。
Q17:我应该转行做 AI 吗?
A: 不要为了"AI 火"而转。问自己"我对这件事有兴趣吗"。
Q18:35 岁危机怎么破?
A: 三个方向:往深走(专精)、往宽走(跨领域)、往管理走。核心是"建立不可替代性"。
Q19:副业做什么好?
A: 做"你主业积累能复用"的方向。不要从零开始。
Q20:要不要学 Prompt 工程?
A: “Prompt 工程"本质是"把需求说清楚的能力”。这个能力到处都有用,值得学。但不用把它当"职业"。
D.5 深度类
Q21:AI 的"幻觉"能彻底解决吗?
A: 目前的技术路径下不能。只能"减少",不能"根除"。所以必须有审核机制。
Q22:AI 会不会有"意识"?
A: 我不知道。而且我认为这个问题目前"无法验证"。
Q23:AI 会让贫富差距变大吗?
A: 很可能会。会用 AI 的人和不会的人,产出差距会拉大。
Q24:AI 生成的代码有没有版权问题?
A: 法律上还不清晰。我的做法是:核心代码自己写,AI 只做辅助。
Q25:公司禁止用 AI,怎么办?
A: 遵守规定。如果觉得规定不合理,可以提出建议。但不要偷偷用。
Q26:怎么判断 AI 给的方案是不是"过度设计"?
A: 问自己:“这个复杂度,解决的是现在的问题,还是想象中的问题?”
Q27:AI 写的测试有价值吗?
A: 有,但要 review。标准是:改错一行代码,这个测试会不会挂。
Q28:怎么防止团队成员"无脑复制 AI 代码"?
A: 强制"解释":PR 描述里要写"我是怎么想的"。
Q29:本地模型值得部署吗?
A: 如果你有数据敏感性要求,值得。否则用云端。
Q30:最后一个问题——用 AI 到底爽不爽?
A: 爽,也很累。
爽是因为效率真的提升了。累是因为要学的东西更多了,要判断的东西更多了。
但这就是这个时代的样子。要么接受,要么被淘汰。
附录 E:我的 20 个 AI 使用习惯
写代码十一年,我用 AI 两年。这两年里养成了些习惯,有些挺怪,但都管用。
E.1 关于写代码
习惯 1:永远自己写第一行。
不管多简单的文件,第一行我都是自己写的。
为什么?因为第一行决定了整个文件的"气场"。
我的 main.py 第一行永远是 import sys,或者 from typing import List。这一行没人看见,但它定义了"这是我的代码"。
AI 写的第一行往往是 from fastapi import FastAPI。很对,但不是我。
习惯 2:变量名自己起。
AI 起的名字经常是 data、result、temp。太泛。
我的变量名经常是:
- raw_user_input(原始输入)
- sanitized_email(清洗后的邮箱)
- audit_log_entry(审计日志条目)
- pending_payment_count(待支付订单数)
长,但自我解释。三个月后回来还能看懂。
习惯 3:注释里写"为什么不"。
AI 的注释是"这段代码在干什么"。我的注释是"为什么这么写"。
# AI 的注释
# 把字符串转为整数
value = int(s)
# 我的注释
# 用 int() 而不是 eval():输入来自用户表单,eval 可以执行任意代码
# 这里不 catch 异常:调用方必须保证 s 是合法数字字符串
# (这是内部函数,不做防御性编程,避免掩盖上游的 bug)
value = int(s)
习惯 4:测试代码要"手写一点"。
AI 写的测试太"标准"了,一看就是机器写的。
我的测试会带点"人味":
def test_login_with_weird_email():
"""测试奇怪的邮箱登录。
这几个 case 是我踩过的坑:
– + 号是合法的(Gmail 的别名机制),但有些正则不认
– 中文域名邮箱(国际化)
– 超长邮箱
– 子域名(a@b.c.d.e.com)
这个 bug 我修了三次,每次都复发,所以这里加了详细测试。
"""
weird_emails = [
"user+tag@example.com",
"user.name@sub.example.com",
"用户@中文.中国",
"very.long." * 10 + "address@example.com",
]
for email in weird_emails:
assert login(email, "password") is not None
习惯 5:commit message 自己写。
AI 写的 commit message 太规整:feat: add user login endpoint。
我的:
fix: 终于修好了那个困扰我三天的 PSNR 计算 bug
根因:边界判断错了。
– y_pred < 0 时,max(0, y_pred) 是对的
– 但 y_true == 0 且 y_pred == 0 时会除以 0 得 NaN
– 之前没暴露,是因为测试数据里没有全零的块
修复:加 epsilon = 1e-10
顺手加了 5 个边界测试。
带点情绪,但三个月后看非常有信息量。
E.2 关于 review
习惯 6:只看 diff,不看完整文件。
review AI 的代码时,我不看完整文件,只看 diff。
重点看:
- 哪些是 AI 新加的
- 哪些是被修改的
- 哪些是被"悄悄删除"的(这个最容易被忽略)
这个习惯让我发现过 AI:偷偷删掉的注释、悄悄改的命名、莫名其妙加的 try/except。
习惯 7:AI 写完代码,我会"重走一遍"。
不是完全重写,是"走一遍"。
我假装这是别人写的代码,从头读一遍,把不顺眼的改掉。
这个习惯让我的代码保持"我的风格",而不是"AI 的风格"。
习惯 8:把 AI 的方案当成"候选",不是"答案"。
AI 给的方案,我会问自己三个问题:
习惯 9:review 时问 AI 三个问题。
请从这三个角度 review 这段代码:
1. 如果输入是"恶意构造的",会发生什么?(安全)
2. 如果数据量放大 1000 倍,会发生什么?(性能)
3. 如果一个新人接手,他会在哪里看不懂?(可维护性)
E.3 关于 Prompt
习惯 10:我有一个"Prompt 笔记"。
我用 Notion 存了 50 多个好用的 Prompt 模板。
常用几个:
- “以资深 C++ 工程师视角 review 这段代码,只关注正确性和性能”
- “把这个 Python 转成 Rust,保持逻辑,用 Rust 的惯用法”
- “用初中生能懂的话解释 XXX,不要用同义反复的词”
- “列出这个函数的所有边界条件,然后为每个写测试”
80% 的 Prompt 不用从头写。
习惯 11:Prompt 里一定写"环境"。
环境:
– Python 3.12
– FastAPI 0.115
– PostgreSQL 16
– 跑在 Ubuntu 22.04
不写环境,AI 会假设你用的是"教科书版本"。
习惯 12:让它"先问再答"。
在回答之前,如果我的需求有任何不清楚的地方,先问我。
不要猜。
这一句能减少 30% 的"答非所问"。
习惯 13:复杂问题让它"分步"。
请分三步回答:
第一步:列出所有可能的方案
第二步:分析每个方案的优劣
第三步:给出你的推荐和理由
先做第一步,等我说"继续"再做第二步。
这样我能"中途干预",避免它一路错到底。
E.4 关于心态
习惯 14:AI 说的,我一定要验证。
不管是 API、数字、还是"最佳实践"。
核实成本很低,不核实的代价很高。
习惯 15:定期"戒断"。
我每个月有 1-2 天完全不用 AI 写代码。
手写,找回感觉。
习惯 16:把"AI 提效"当成"省下来的时间去思考"。
AI 帮我省了写代码的时间。我省下来的时间,用来想清楚"这个方案对不对"。
不是用来"接更多活"。
习惯 17:不把 AI 当"安慰剂"。
有段时间,我遇到问题第一反应是"问 AI"。
后来我发现,有些问题我自己想 10 分钟就能想出来。问 AI 反而更慢(因为要描述清楚)。
现在的原则:先自己想 10 分钟,再问 AI。
习惯 18:记录"AI 说错的"案例。
我有个文件,专门记录"AI 在哪里错了"。
不是"记仇",是为了理解 AI 的能力边界。
现在这里面有 60 多条。回头看,能看出清晰的模式:它在"具体事实"和"边界情况"上最容易错。
习惯 19:不用 AI 做"我不愿意做"的决定。
比如"这个人要不要 hire"、“这个需求要不要接”。
这些决定要"我负责"。用 AI 来"分担心理负担",是逃避。
习惯 20:保持"我能不用 AI"。
这是最重要的一条。
我不是"必须用 AI",而是"选择用 AI"。
这两者的区别是:
- 前者:AI 是"拐杖",离了就瘸
- 后者:AI 是"工具",随时可以放下
保持"可以放下"的能力,是自由的底线。
附录 F:AI 时代程序员的必备能力
F.1 旧时代的能力清单
十年前,程序员的核心能力是:
F.2 新时代的能力清单
现在,我认为核心能力变成了:
第一层(基础,必须有):
第二层(进阶):
第三层(差异化):
F.3 逐条展开
F.3.1 AI 协作能力
不是"会用 ChatGPT",而是:
- 知道"什么问题该问 AI,什么该自己查"
- 知道"怎么描述需求让 AI 一次做对"
- 知道"AI 的输出哪里需要验证"
- 知道"什么时候不该用 AI"
这个能力的核心是"知道 AI 的能力边界"。
F.3.2 判断力
AI 时代最稀缺的能力。
AI 可以给你 100 个方案。但:
- 哪个适合你现在的场景?
- 哪个的"隐藏代价"最小?
- 哪个是"看起来对但其实是坑"?
判断力来自:
- 业务理解(知道用户的痛点)
- 技术深度(知道每个方案的真实成本)
- 历史经验(踩过的坑)
- 价值观(知道什么该做什么不该做)
AI 短期学不会这些。
F.3.3 定义能力
这一条被严重低估。
"把模糊需求变成清晰任务"的能力,比"写代码"重要得多。
例子:
用户说:“我想要一个更好用的搜索。”
好的工程师会问:
- 是"搜得准"还是"搜得快"?
- 现在的搜索哪里不好用?有数据吗?
- 用户是谁?他们的搜索习惯是什么?
- 什么叫"好用"?怎么衡量?
这一步做对了,后面 80% 的工作就顺了。
这一步做错了,写再多代码都是白费。
F.3.4 业务理解能力
AI 懂代码,但它不懂"这个功能对业务意味着什么"。
你必须懂。
比如:
- 为什么这个"小优化"能带来 20% 的收入提升?
- 为什么这个"技术债"必须现在还?
- 为什么这个"看起来合理的需求"其实不该做?
这些判断,决定了你的技术投入有没有价值。
F.3.5 系统设计能力
AI 能写"一个模块",但它设计不了"一个系统"。
系统设计要考虑:
- 模块如何划分
- 数据如何流动
- 故障如何处理
- 如何演进
这个能力,需要"见过足够多的系统"才能培养。
F.3.6 沟通表达能力
技术能力再强,说不清楚也白搭。
- 跟产品经理讲清楚"这个需求为什么要这么久"
- 跟老板讲清楚"这个方案的风险在哪"
- 跟同事讲清楚"这个设计为什么这样"
AI 时代,这个能力反而更重要 —— 因为"写代码"的时间少了,"对齐"的时间多了。
F.3.7 领域深度
"什么都会一点"在 AI 时代最危险。
因为 AI 也是"什么都会一点",而且它比你快。
你的价值在"某个领域比 AI 深"。
对我来说是视频编解码。对你是别的。
找到那个领域,深挖下去。
F.3.8 跨领域广度
但"只有深度"也不够。
"深度 + 一个相邻领域"是最佳组合。
比如:
- 视频编解码 + AI
- 后端 + 数据
- 前端 + 设计
AI 擅长"单点",人擅长"连接"。
F.4 一个总结
如果让我用一句话总结"AI 时代程序员的核心能力":
“用 AI 放大你的判断力,而不是用 AI 替代你的判断力。”
具体来说:
- AI 负责"广度":它能覆盖的领域比你广
- 你负责"深度"和"判断":哪些是对的、哪些重要、哪些该做
这个分工,是未来十年最稳的分工。
附录 G:术语表
写这篇文章用了不少术语,这里做个索引。按拼音排序。
G.1 A-F
ALF(Adaptive Loop Filter):自适应环路滤波。VVC 的滤波工具,能根据区域特征选择不同滤波器。
CABAC(Context-Adaptive Binary Arithmetic Coding):上下文自适应二进制算术编码。H.264/H.265 的熵编码方式。
CDC(Clock Domain Crossing):跨时钟域。数字电路里不同时钟域之间传数据,需要特殊处理。
CTU(Coding Tree Unit):编码树单元。HEVC 的最小编码单元,最大 64×64。
CU(Coding Unit):编码单元。CTU 递归划分后的块。
DCT(Discrete Cosine Transform):离散余弦变换。视频编码的变换方式。
DST(Discrete Sine Transform):离散正弦变换。HEVC 对 4×4 帧内块使用。
GIL(Global Interpreter Lock):全局解释器锁。CPython 的限制,同一时刻只有一个线程执行。
G.2 G-M
GOP(Group of Pictures):图像组。I 帧到下一个 I 帧之间的帧序列。
HEVC(High Efficiency Video Coding):H.265,高效视频编码。
JND(Just Noticeable Difference):恰可察觉失真。人眼能察觉的最小失真量。
LMCS(Luma Mapping with Chroma Scaling):亮度映射与色度缩放。VVC 的工具。
MTS(Multiple Transform Selection):多变换选择。VVC 的工具,可选多种变换核。
MS-SSIM(Multi-Scale SSIM):多尺度结构相似性。图像质量评价指标。
MSE(Mean Squared Error):均方误差。质量评价的基础指标。
MV(Motion Vector):运动矢量。表示块从参考帧到当前帧的位移。
G.3 P-R
PSNR(Peak Signal-to-Noise Ratio):峰值信噪比。最常用的客观质量指标。
PU(Prediction Unit):预测单元。HEVC 的预测块。
QP(Quantization Parameter):量化参数。控制编码质量和码率。
QUIC:基于 UDP 的传输协议。HTTP/3 的传输层。
RDO(Rate-Distortion Optimization):率失真优化。在码率和失真之间找最优权衡。
RDOQ(Rate-Distortion Optimized Quantization):率失真优化量化。
RRULE:iCalendar 的重复规则语法(这个跟视频编码无关,是日程的)。
G.4 S-Z
SAO(Sample Adaptive Offset):样点自适应偏移。HEVC 的滤波工具。
SIMD(Single Instruction Multiple Data):单指令多数据。CPU 的向量化指令。
SSIM(Structural Similarity):结构相似性。比 PSNR 更接近人眼的质量指标。
SVC(Scalable Video Coding):可伸缩视频编码。
TU(Transform Unit):变换单元。
VMAF(Video Multimethod Assessment Fusion):Netflix 提出的视频质量评价指标。
VVC(Versatile Video Coding):H.266,多功能视频编码。HEVC 的继任者。
VTM(VVC Test Model):VVC 的参考软件。
G.5 AI 相关
Agent:智能体。能自主感知、决策、行动的 AI 系统。
Few-shot:少样本学习。给几个例子让模型学会任务。
Fine-tuning:微调。在预训练模型上用特定数据继续训练。
Hallucination:幻觉。AI 生成看似合理但实际错误的内容。
LLM(Large Language Model):大语言模型。
Prompt:提示词。给 AI 的输入指令。
RAG(Retrieval-Augmented Generation):检索增强生成。先检索相关资料,再让模型生成。
Token:词元。模型处理文本的最小单位。
Zero-shot:零样本。不给例子直接让模型做任务。
附录 H:延伸阅读
H.1 视频编码方向
标准文档:
- H.264 (AVC):ITU-T Rec. H.264
- H.265 (HEVC):ITU-T Rec. H.265
- H.266 (VVC):ITU-T Rec. H.266
源码:
- x264(H.264 编码器,最经典)
- x265(HEVC 编码器,我主要看的)
- VTM(VVC 参考软件,最权威)
- libaom(AV1 编码器)
- FFmpeg(万能工具)
书:
- 《High Efficiency Video Coding (HEVC): Algorithms and Architectures》
- 《Video Coding: An Introduction to Standard Codecs》
H.2 AI 与工程方向
书:
- 《Designing Machine Learning Systems》(讲工程化,不光是模型)
- 《The Pragmatic Programmer》(经典,跟 AI 无关但值得读)
- 《A Philosophy of Software Design》(讲"复杂度"这个核心问题)
博客/网站:
- Simon Willison 的博客(Prompts 和 AI 工程化的第一手经验)
- Anthropic 的 Prompt Engineering 文档
H.3 我自己的内容
如果你喜欢这篇文章的风格:
- 我的 CSDN 博客:主要写视频编解码源码分析
- 我的付费专栏:x265 源码深度解析(30 篇)
(这里我就不放具体链接了,免得像广告。想找的话,搜"yance 视频编解码"就能找到。)
H.4 最后一段
这篇文章的所有观点都是我自己的。
如果和你的认知冲突,以你的经验为准。因为:
- 我的场景(视频编解码、后端)可能和你的不同
- 我的团队(10 人左右)可能和你的不同
- 我的性格、习惯,都不是"标准答案"
把它当成"一个同行的经验分享",而不是"操作手册"。
那样你会收获更多。
祝你在 AI 时代,走得更远。
附录 I:实战速查手册
这一部分是"可以抄走直接用"的。
I.1 Prompt 模板库
下面这些是我自己常用的模板。你可以直接改。
I.1.1 代码 review 模板
你是一个有 10 年经验的 {语言} 工程师。
请 review 下面的代码。
只关注这四类问题(不要讨论代码风格):
1. 正确性问题:边界条件、异常路径、并发
2. 性能问题:时间复杂度、内存、IO
3. 安全问题:注入、越权、敏感信息
4. 可维护性问题:命名误导、隐藏耦合、重复逻辑
输出格式:
– 按【严重】/【一般】/【建议】三级分类
– 每条包含:问题描述 + 代码位置 + 具体修改方案(给代码)
– 如果某类没有问题,明确写"无"
代码:
```{语言}
{你的代码}
### I.1.2 让它解释代码
```markdown
请解释下面这段代码。
要求:
1. 先用一句话说"这个函数在干什么"
2. 然后逐行/逐块解释
3. 重点说明"为什么这么写"(而不是重复代码字面意思)
4. 指出任何"看起来奇怪但可能是故意的"写法
5. 如果有潜在问题,单独列出来
不要泛泛而谈。不要用"这段代码很重要"这种话。
I.1.3 让它写测试
请为下面的函数写单元测试。
步骤:
第一步:先列出这个函数的**所有**边界条件(正常/边界/非法/特殊值)
第二步:为每个边界条件写测试
第三步:给一个参数化测试覆盖多种组合
重要要求:
– 不要只测 happy path
– 每个测试的名字要说明"在测什么"
– 每个测试都要能"真的测出 bug"(如果实现改错,它要能挂)
函数:
```python
{你的函数}
### I.1.4 重构模板
```markdown
请重构下面的代码。
约束:
– 不改变外部行为(输入输出完全一致)
– 不引入新依赖
– 不改变公开 API 的签名
– 代码风格与下面给的"参考风格"一致
参考风格:
```python
{你项目里的一段典型代码}
重构目标(按优先级):
请说明每一处改动"为什么这样改"。
待重构代码:
{你的代码}
### I.1.5 让它设计而非实现
```markdown
我要做 {目标}。
请先不要写代码。先做这三件事:
1. 列出至少 3 种可行方案
2. 分析每种方案的:实现复杂度、性能、可维护性、风险
3. 给出你的推荐和理由
约束:
{你的约束,比如团队规模、时间、技术栈}
如果我的需求有任何不清楚的,先问我。
I.1.6 学习模板
我想学 {主题}。
请给我一个"以动手为主"的学习路径:
1. 按顺序列出需要学的概念(不要贪多,只列必须的)
2. 每个概念配一个"最小可运行的例子"
3. 每学完 3 个概念,给一个"小项目练手"(要有明确的目标和验收标准)
不要给我"看 XX 书"这种建议。我要能立刻动手的。
I.2 AI 输出检查清单
每次拿到 AI 的输出,用这个清单过一遍。
I.2.1 代码类
- 能不能跑? 跑一遍,不要"看着对"就信
- 库名对不对? 去 PyPI / npm / 官方文档核实
- API 签名对不对? 特别是不常用的参数
- 边界处理有没有? AI 倾向于写 happy path
- 有没有引入不必要的依赖? 标准库能做的,别引第三方
- 风格跟项目一致吗? 命名、注释、错误处理方式
- 有没有"悄悄改掉"的东西? 看 diff,不看完整文件
- 性能敏感的地方有没有变慢? AI 不懂硬件微架构
- 有没有安全问题? 注入、越权、敏感信息
I.2.2 事实类
- 数字对不对? AI 编数字很常见
- 引用是真的吗? 论文、链接、出处,全部核实
- "XX 是最新的"对不对? 训练数据有截止时间
- "XX 已经废弃了"对不对? 这种断言最容易错
- 有没有前后矛盾? 长对话里容易出现
I.2.3 方案类
- 是不是过度设计? 你的规模配得上这个复杂度吗?
- 代价说清楚了吗? 每个方案的成本、风险
- 有没有更简单的做法? 奥卡姆剃刀
- 三个月后能看懂吗? 可维护性
- 出事了能回滚吗? 风险控制
I.3 每天 5 分钟的"AI 使用复盘"
我有个习惯:每天下班前花 5 分钟,想三个问题。
问题一:今天哪次用 AI"最值"?
记录下来。这是你的"最佳实践"。
问题二:今天哪次用 AI"白费时间"了?
记录下来。这是你的"避坑指南"。
问题三:今天有没有"本该用 AI 但没用"的事?
这种时候往往是你"习惯了手工",没意识到 AI 能帮忙。
坚持一个月,你会形成自己的"AI 使用直觉"。
I.4 团队推广 AI 的四步法
如果你是团队里"第一个用 AI"的人,想推广,可以这样:
第一步:自己先用出效果。
不要"讲道理",要"出成果"。
第二步:做一个"可对比"的案例。
选一个任务,你"用 AI 做"和"不用 AI 做",各花多久,效果如何。
有数据,才有说服力。
第三步:从"最烦的活儿"入手。
团队里总有些"没人愿意干"的活儿(写测试、写文档、改格式)。
用 AI 干掉这些,大家立刻能感受到好处。
第四步:立规矩,而不是发禁令。
明确"哪些能用、哪些不能用",而不是"一刀切"。
我实际的经验:从"自己用"到"团队用",大约需要 3-6 个月。
不要急。
附录 J:20 道自测题
检验一下,你是不是真的"会用 AI"。
J.1 每题 5 分,满分 100
题目 1:AI 给你一段代码,你的第一步是什么?
A. 直接复制粘贴到项目里
B. 先看一遍,理解逻辑
C. 跑一遍,看能不能用
D. 先看 diff,再跑
题目 2:AI 说"有一个库叫 XXX 可以解决",你应该?
A. 直接 pip install XXX
B. 先去 PyPI 搜一下
C. 问 AI 确认
D. 假设它是对的
题目 3:一段对话聊了 60 轮,你发现 AI 忘了你第 5 轮说的约束,怎么办?
A. 继续聊,相信它会想起来
B. 重开对话
C. 重申关键约束,或者分段对话
D. 放弃
题目 4:AI 给你的方案用了 6 个中间件,而你的需求是"每天跑 20 个任务",你应该?
A. 照做,AI 是专业的
B. 简化到 crontab
C. 用一半的中间件
D. 再问 AI 一次
题目 5:AI 写的测试覆盖率 90%,你要怎么判断质量?
A. 覆盖率 90% 就够了
B. 看测试的数量
C. 故意改错一行代码,看测试会不会挂
D. 看代码行数
题目 6:你要让 AI 帮忙调试公司的核心代码,你应该?
A. 直接粘贴完整代码
B. 粘贴代码 + 日志
C. 抽象化后粘贴,去掉敏感信息
D. 不用 AI
题目 7:AI 回答里有个具体的性能数字(“提升 3 倍”),你应该?
A. 相信它
B. 自己测一遍
C. 打折相信(“大概提升 1.5 倍”)
D. 忽略
题目 8:让 AI 写一个函数,它给了 40 行带类的实现,而你只需要 5 行,你应该?
A. 用它的(更"专业")
B. 让它简化,明确说"不要类、不要异常处理、不超过 10 行"
C. 自己写那 5 行
D. 用它的类,但删掉方法
题目 9:AI 写的代码风格跟你的项目不一样,你怎么办?
A. 接受(能跑就行)
B. 贴一段你的代码给它,让它参考
C. 手动改
D. 换 AI
题目 10:你团队的新人提交的代码很漂亮,但问"为什么这样写"答不上来,你应该?
A. 没关系,代码对就行
B. 要求 PR 描述写"我是怎么想的"
C. 不让他用 AI
D. 让他重写
题目 11:AI 在长对话里开始"敷衍"(回答变短、变模糊),你应该?
A. 继续说
B. 重开对话,带上关键上下文
C. 催它认真点
D. 换一个 AI
题目 12:你觉得"用 AI 会不会让自己变笨"?
A. 会,所以少用
B. 不会,AI 只是工具
C. 会,如果只"用"不"想"。要定期手写
D. 无所谓
题目 13:一个需求:“做一个更好用的搜索”,你的第一步是?
A. 让 AI 写搜索代码
B. 先问"什么叫好用"、“现在的痛点是什么”
C. 调研开源搜索方案
D. 让 AI 出方案
题目 14:AI 说"某个 API 在最新版本里已经废弃了",你应该?
A. 相信它
B. 去官方 changelog 核实
C. 试一下就知道
D. 换个 API
题目 15:你要面试一个人,简历明显是 AI 润色的,你应该?
A. 直接淘汰
B. 深挖细节,问"具体怎么做的"
C. 让 AI 帮我判断
D. 忽略简历,只看算法题
题目 16:AI 给你的技术方案,你最应该问自己哪个问题?
A. 这个方案"专业"吗
B. 这个方案的"代价"是什么
C. 用的人多吗
D. AI 是不是确定
题目 17:你发现用了 AI 之后,很多 API 都记不住了,你应该?
A. 没关系,能查到就行
B. 每个月"戒断"几天,手写代码
C. 背下来
D. 继续用 AI
题目 18:AI 写了一段 SQL,逻辑看起来对,你应该?
A. 直接在线上跑
B. 先在测试库跑,看执行计划
C. 让 AI 再确认一遍
D. 相信它
题目 19:你要写一篇技术文章,AI 能帮你做什么?
A. 全部内容
B. 结构、扩写、润色(核心观点还是自己写)
C. 只做标题
D. 不用 AI
题目 20:如果只能用一句话总结"AI 时代程序员的核心能力",你选哪个?
A. 会写 Prompt
B. 会用最新的 AI 工具
C. 判断力——知道什么该做、什么是对的
D. 编程语言要学得多
J.2 参考答案
| 1 | D | AI 代码必须验证,diff 更安全 |
| 2 | B | 幻觉:编造的库名很常见 |
| 3 | C | 上下文丢失的应对 |
| 4 | B | 过度设计 |
| 5 | C | 变异测试,检验测试有效性 |
| 6 | C | 数据安全 |
| 7 | B | 数字必须自己测 |
| 8 | B | 明确说"不要什么" |
| 9 | B | 给 AI 看风格参考 |
| 10 | B | 强制理解 |
| 11 | B | 长对话要重启 |
| 12 | C | 能力退化的应对 |
| 13 | B | 定义问题的能力 |
| 14 | B | 版本幻觉 |
| 15 | B | 深挖真实经历 |
| 16 | B | 判断"代价",不是"专业" |
| 17 | B | 定期戒断 |
| 18 | B | 生产 SQL 必须验证 |
| 19 | B | AI 辅助,不替代 |
| 20 | C | 判断力是核心 |
J.3 你的分数意味着什么
90-100 分:你已经很会用了。可以考虑"怎么把经验传给别人"。
70-89 分:用得不错。注意那些"想当然"的地方。
50-69 分:及格。建议再读一遍"踩坑实录"(第三部分)。
30-49 分:你还在"零散地用"。建议建立工作流(第二部分)。
30 分以下:你可能是"AI 功能在用你"。先建立"怀疑"的习惯。
J.4 一个提醒
这个测试的答案,不一定"绝对正确"。
比如第 12 题,如果你选 A(“会,所以少用”),也不能说你错——只是我们的策略不同。
重要的是"你有没有想过这些问题"。
“想过”,比"答对"重要。
(速查手册与自测题完,正文见后)
附录 K:50 个具体技巧(拿来就用)
前面讲了很多"理念"。这一部分是"操作细节",每条都很小,但都用得上。
K.1 关于写代码
技巧 1:让它先写"接口",再写"实现"。
先用注释写出这个模块的接口(函数签名 + 一句话说明),
等我确认后,再写实现。
好处:接口错了,改起来比实现便宜 100 倍。
技巧 2:让它"一次只做一件事"。
不要让它"写函数 + 写测试 + 写文档"。分开三轮问,每轮质量都更高。
技巧 3:要求它"保留原有注释"。
重构时,请保留所有原有的注释。如果有注释与新代码不符,单独列出来让我判断,不要自己改。
AI 有个坏习惯:重构时把别人的注释删了。
技巧 4:复杂逻辑让它"先画流程图"。
请先用文字画出这个逻辑的流程图(用缩进表示层级),
确认流程对了,再写代码。
这样能提前发现逻辑错误。
技巧 5:让它给"多个版本"。
请给 3 个版本:
1. 最简版本(5 行以内,能跑就行)
2. 生产版本(有错误处理、有日志)
3. 性能版本(针对大数据量优化)
并说明什么场景用哪个。
技巧 6:明确"不要什么"比"要什么"更有效。
“不要类、不要继承、不要 try/except、不要引入依赖”。
技巧 7:让它"标注不确定"。
如果你对某行代码的正确性没有把握,在该行末尾加 `# UNSURE` 注释。
这样你 review 时能重点关注。
技巧 8:让它"解释它自己的代码"。
写完代码后,请逐行解释。如果你发现自己在解释时"说不出所以然",
说明那行代码可能是多余的。
技巧 9:让它"自我 review"。
现在请你换一个角色:假设你是 review 这段代码的人,
挑出这段代码里最可能出问题的三处,并说明为什么。
技巧 10:给它"输入输出示例"。
输入示例:
{"name": " test ", "age": 25}
期望输出:
{"name": "test", "age": 25}
有例子,AI 的理解准确率会大幅提升。
K.2 关于调试
技巧 11:给它完整的错误信息。
不要只说"报错了",把完整的 traceback 贴给它。
技巧 12:让它"先猜测再验证"。
请先列出 3 个最可能的原因,按可能性排序。
然后告诉我怎么验证每一个。
技巧 13:让它"解释错误"。
这个错误信息我看不懂,请逐句解释,特别是不常见的部分。
技巧 14:给它"最小复现"。
不要给 500 行代码。先缩减到 20 行能复现的版本,再给 AI。
技巧 15:让它"对比预期和实际"。
预期:函数返回 [1, 2, 3]
实际:返回 [1, 2, 3, 4]
请分析可能的原因。
技巧 16:让它"读日志"。
这是一段日志。请找出所有"异常"的地方(错误、警告、不寻常的模式)。
技巧 17:让它"扮演编译器"。
请扮演 C++ 编译器,指出这段代码的所有编译错误和警告。
K.3 关于架构与设计
技巧 18:让它"先问三个问题"。
在给方案之前,请先问我三个你必须知道的问题。
这三个问题往往能暴露你"没想清楚的地方"。
技巧 19:让它"唱反调"。
我的方案是 XXX。
请你扮演一个"持反对意见的架构师",找出这个方案的所有问题。
越狠越好,不要客气。
技巧 20:让它"给取舍表"。
请用表格对比这几个方案:实现成本、性能、可维护性、风险、适用场景。
技巧 21:让它"从三个视角看"。
请从三个视角分析这个设计:
1. 一个新入职的工程师会怎么看
2. 一个运维工程师会怎么看
3. 一个业务方会怎么看
技巧 22:让它"估算规模"。
假设日活 100 万,这个设计需要多少机器?数据库压力多大?
请给出数量级估算和计算过程。
K.4 关于学习
技巧 23:让它"出题"。
请出 10 道关于 XXX 的题,从易到难。
先不要给答案。
技巧 24:让它"扮演小白"。
我要给你讲一遍 XXX。
你扮演一个聪明的初学者,我哪里讲得绕、哪里跳步了,你就打断我。
技巧 25:让它"找类比"。
请用"日常生活中的类比"解释 XXX。
要具体(比如"像超市排队"),不要抽象。
技巧 26:让它"给反例"。
XXX 在什么情况下会失效?请给具体的反例。
技巧 27:让它"串联知识"。
XXX 和我已经会的 YYY 有什么关系?
请用"已知的"来理解"未知的"。
K.5 关于表达与沟通
技巧 28:让它"改语气"。
请把这段话改得更"有立场"(不要中立、不要"需要权衡"这种话)。
请把这段话改得"对非技术人员友好"(去掉术语,加类比)。
技巧 29:让它"找逻辑漏洞"。
这是我的论证。请找出逻辑上的跳跃、未证明的假设、以及可能的反驳。
技巧 30:让它"压缩"和"展开"。
请把这段话压缩到 100 字以内,保留所有关键信息。
请把这段要点展开成 500 字的完整段落,加上具体的例子。
K.6 关于工具与流程
技巧 31:给 AI 一份"项目说明"。
在建一个新对话时,先贴一段项目背景:
项目背景:
– 语言:Python 3.12
– 框架:FastAPI + SQLAlchemy 2.0
– 数据库:PostgreSQL 16
– 部署:Docker + K8s
– 代码风格:ruff + black,行宽 100,用 type hints
这样之后所有回答都会"对齐"你的环境。
技巧 32:把常用的 Prompt 存成文件。
我有个 prompts/ 目录,里面是各种模板。用的时候 cat prompts/review.md 复制。
技巧 33:用 AI 生成"自己的文档"。
让 AI 读你的代码,生成一份"给新人看的说明"。你会发现很多"你以为很清楚但实际不清楚"的地方。
技巧 34:让 AI 做"格式转换"。
Python 2 → 3、YAML → JSON、cURL → Python requests、SQL → ORM 代码。
这类"纯翻译"的活儿,AI 又快又准。
技巧 35:让它"生成测试数据"。
请生成一个 CSV,100 行,字段:id, name, email, created_at。
要求:包含边界值(超长名字、特殊字符邮箱、跨时区时间)。
比手写快 100 倍。
技巧 36:让它"写正则"。
正则写起来痛苦,读起来更痛苦。让 AI 写,但一定要测。
技巧 37:让它"解释正则"。
请逐字符解释这个正则表达式的含义。
这个功能很实用——尤其当你要改别人写的正则时。
技巧 38:用它做"代码翻译"。
把一段 C++ 翻译成 Python(用于理解算法),或者把 Python 翻译成 Rust。
注意:翻译之后一定要测。 AI 翻译时经常会漏掉边界情况。
技巧 39:让它"起名字"。
我起变量名/函数名时会问 AI:“这个函数的功能是 XXX,起 5 个名字”。
它给的名字比我起的好,因为它见过更多的代码命名习惯。
技巧 40:让它"写 commit message"。
git diff –staged | pbcopy
# 然后粘贴到 AI:
# 请根据这个 diff 生成 conventional commit message
K.7 关于心态与习惯
技巧 41:先自己想 10 分钟。
不是"自己想 1 分钟就放弃",是真的想 10 分钟。
这 10 分钟的思考,是"能力训练"。 如果每次都跳过,你的能力会退化。
技巧 42:把"AI 说错的"记下来。
不是为了"记仇",是为了"摸清边界"。
我记了 60 多条,回头看能看出清晰模式。
技巧 43:定期"不用 AI"写一天代码。
每个月 1-2 天。手写,找回感觉。
技巧 44:不用 AI 做"你该负责"的决定。
绩效、招聘、要不要接某个需求——这些别让 AI 帮你想。
技巧 45:对 AI 的"确定语气"保持警惕。
它说"这是最佳实践",你要问"在多大规模下是最佳?"
技巧 46:不要"为了用 AI 而用 AI"。
有些任务自己写更快。判断"该不该用",本身就是能力。
技巧 47:用它"省下来的时间",去思考。
不是为了"接更多活",是为了"做更对的活"。
技巧 48:承认"我不会用某个 AI"是正常的。
工具太多,不用都会。选一两个用透就行。
技巧 49:教别人用 AI,是学 AI 最快的方式。
因为你必须"说清楚",而"说清楚"逼你"想清楚"。
技巧 50:保持"能不用 AI"的能力。
这是自由的底线。不是"必须用",是"选择用"。
K.8 一个总结
这 50 个技巧有个共同点:都是"具体"的。
不是"你要学会用 AI",而是"你可以这样问 AI"。
"具体"是使用 AI 的唯一秘诀。
因为 AI 最大的特点是:你怎么问,它就怎么答。
你问得模糊,它答得模糊。你问得具体,它答得具体。
这不是 AI 的缺陷,是它的本质。
附录 K+:十个反直觉的发现
这十个发现,都是"跟我的直觉相反"的。有的让我困惑了很久,有的到现在我也没完全理解。
K+.1 发现一:写得"笨"的代码,有时候更快
我一直以为"优雅的代码 = 好代码"。
直到有一次,我把一个大循环写成了"函数式"风格(用 map/filter 嵌套),结果比原来的 for 循环慢 40%。
原因: 函数调用开销、中间对象生成、缓存不友好。
在性能敏感的场景(比如视频编码的内循环),"笨循环"往往比"优雅抽象"更快。
K+.2 发现二:AI 给的"正确答案",经常不是"最优答案"
我让 AI 优化一段图像处理代码。它给了一个基于 numpy 广播的写法,很优雅。
但我用了一个更"土"的办法(提前分配输出数组 + 手写循环),快了 3 倍。
因为 numpy 广播在中间会生成大量临时数组,内存带宽成了瓶颈。
AI 给的是"标准的优化",不是"针对你的硬件和数据分布的优化"。
K+.3 发现三:更多上下文,不一定更好
我原以为"给 AI 的信息越多越好"。
后来发现:给太多不相关的上下文,反而会干扰它。
比如我要它写一个函数,我贴了整个 500 行的文件。它的回答会开始"跑偏",讨论文件里其他部分。
正确做法:给"刚好够"的上下文。
K+.4 发现四:AI 在"我懂"的领域更容易骗到我
这是最危险的一个。
在我完全不懂的领域(比如前端 CSS),AI 说什么我都会去验证,因为我没法判断。
但在我很懂的领域(视频编码),我会"放松警惕" —— 因为它说的"大体上对",我就不会去逐字核实了。
结果就是:它在一个我懂的领域里,用一个"看起来对"的细节错误骗了我。
我遇到的例子:它说"HEVC 的 SAO 有三种模式",实际上有四种(不滤波、边缘偏移、带偏移、以及 merge 模式)。
越是你擅长的领域,越要小心。
K+.5 发现五:"让它更详细"经常是错的
我以为"让它多说点"总没坏处。
但很多时候,“更详细"意味着"更多的填充词"和"更多的重复”。
正确的说法是:
不要"说得更多",而是"说得更具体"。
比如:不要写"这段代码性能更好",
而是写"这段代码在 n=10000 时快 3 倍,因为减少了内存分配"。
"更具体"和"更详细"是两回事。
K+.6 发现六:AI 不能帮你"做决定",但能帮你"少做错决定"
我一开始以为"The AI 能给我答案"。
实际上它给的是"候选答案"。
真正有价值的是:它会指出"你没想到的可能性"。
比如我决定"用 Redis 做缓存"。它会问:“你有没有考虑过缓存穿透?”
这不是"给我答案",是"帮我排雷"。
K+.7 发现七:好用的工具,不一定是最强的
GPT-5 在数学上比 Claude 强。但我日常用 Claude。
因为它**“用起来舒服”** —— 中文更自然、回答更贴合我的场景。
工具选择是"体验"问题,不是"性能"问题。
K+.8 发现八:AI 让"写代码"变简单了,"判断代码"变难了
以前大家写代码慢,代码量少,review 得过来。
现在 AI 一天能生成 5000 行,review 成了瓶颈。
而且 AI 生成的代码"看起来很规范",反而更容易让人"跳过 review"。
"看起来对"比"明显不对"更危险。
K+.9 发现九:最有价值的用法,是"我没想到的用法"
我一开始把 AI 当"代码生成器"。
后来发现它最有用的场景是:
- 当陪练(帮我做技术决策的时候唱反调)
- 当翻译(把论文里的公式翻译成代码)
- 当镜子(让它复述我的方案,看逻辑有没有漏洞)
这些用法都不是"生成",是"打磨"。
K+.10 发现十:最后,我发现自己改变了
最大的发现是——我自己变了。
- 我变得更"敢想"了。因为实现成本降低了,我敢尝试以前觉得"太复杂"的方案。
- 我变得更"挑剔"了。因为方案太多了,我必须更严格地筛选。
- 我变得更"焦虑"了。因为要学的东西变多了。
- 但我也变得,"更像个工程师"了。
因为"写代码"不再是核心,"想清楚"才是。
这大概是 AI 给我们这个职业最大的礼物。
K+.11 发现十一:AI 让我重新学会了"问问题"
以前我遇到问题,第一反应是"怎么解决"。
现在我第一反应是"这到底是个什么问题"。
因为 AI 最擅长的就是"解决问题"。如果问题本身定义错了,那解决得再漂亮也没用。
我举个例子。
以前我会问:“怎么让这个接口快一倍?”
现在我会问:“为什么这个接口需要快一倍?是用户抱怨了,还是我自己觉得慢?如果用户抱怨了,他们真正卡在哪一步?”
后面这个问题,AI 答不了。但正是它决定了,我该不该花两周去优化这个接口。
学会问对的问题,比学会用工具重要得多。
K+.12 发现十二:最后一个——"标准答案"是不存在的
我用 AI 两年,最深的体会是:
所有 “AI 最佳实践”,都是有前提的。
- “要给足上下文” —— 但给多了会干扰
- “要用思维链” —— 但简单问题不需要
- “要写详细 Prompt” —— 但有时候一句话就够
- “要用最新的模型” —— 但老模型有时候够用且便宜
没有放之四海皆准的方法。
只有"在什么场景下,用什么方法"。
所以这篇文章里所有的建议,你都应该问一句:“在我的场景下,成立吗?”
如果你能这样问,那这篇文章就没白写。
附录 L:十个真实的 AI 使用故事
本来想在这里收尾了。但回头看了一眼,觉得还有几件事没说完。
下面这十个故事,都是我这两年真实遇到的人和事。都做了脱敏,但情节是真的。
故事一:那个被 AI 坑了一周的人
我同事小李,后端工程师,四年经验。
有一次他负责排查一个线上内存泄漏。服务跑 6 小时后内存从 800MB 涨到 4GB,然后被 OOM Kill。
小李的第一反应是——问 AI。
AI 给了 5 个"可能原因":
这 5 个都很"合理"。小李挨个排查。
- 查连接池:用了 HikariCP,配置正常
- 查缓存:用了 Caffeine,有 LRU 上限
- 查日志:日志是异步写的,不占内存
- 查线程池:线程数稳定
- 查第三方库:换了个版本,没用
一周过去了。问题还在。
第八天,他开了一个 heap dump,用 MAT 分析。发现是一个 Map<String, Object> 里存了 120 万个 entry。
那块代码是:
private static final Map<String, UserContext> CONTEXT_CACHE = new ConcurrentHashMap<>();
public void process(String traceId, UserContext ctx) {
CONTEXT_CACHE.put(traceId, ctx);
try {
// … 业务逻辑
} finally {
// 忘了 remove!
}
}
没有删除。 每个请求都往里加,永远不删。
小李后来跟我说:“如果那天我先把 heap dump 打开,10 分钟就能找到。”
这个故事说明什么?
AI 给的"可能性"是基于"常见模式"。它能列出 50 种可能,但它不知道你的代码里到底哪一行有问题。
排查问题还是要靠"工具 + 数据",不是靠"猜"。
AI 可以帮你"列出可能性",但不能替代 heap dump。
故事二:那个把公司代码传上去的人
这个我必须说,因为它太典型了。
我一个在某大厂的朋友,负责一个推荐系统的一部分。
有次他遇到一个性能问题,直接把一段代码(包含公司内部的排序算法逻辑)粘贴到 ChatGPT,让 AI 帮忙优化。
AI 给了一个不错的优化,他改完上线了。
三个月后,公司安全部门找他谈话。
原因:他们发现那段代码的"特征片段"出现在了某个公开的代码数据集里(大模型的训练数据会回流)。
具体后果我不说了。只能说,他后来换了工作。
这件事给我的震动很大。
我现在有几条铁律:
抽象化是什么意思?
// 不要贴这个
public double internalRankingScore(Features f) {
// 公司独有的算法
return f.getCtr() * 0.4 + f.getCvr() * 0.35 + INTERNAL_WEIGHT * f.getQuality();
}
// 贴这个
public double computeScore(Feature a, Feature b, Feature c) {
return a.value * w1 + b.value * w2 + INTERNAL_WEIGHT * c.value;
}
结构一样,但具体内容和参数名都换了。
这一条,我希望你记住。
故事三:那个用 AI 写简历的人
我朋友的公司招人。他看到一份简历,写得特别好:
“负责核心交易系统的架构设计,主导了从单体到微服务的演进,支撑日均 5000 万订单……”
面试时,他问了几个细节:
- “微服务拆分的时候,你是怎么处理分布式事务的?”
- “5000 万订单的峰值是多少?你们怎么扛的?”
- “拆分的边界是怎么定的?为什么是这几个服务?”
候选人的回答全是"大概"、“应该”、“好像”。
结果当然没过。
后来他们 HR 说,其实能看出这份简历是 AI 润色的——因为"太流畅了",缺少真实经历里的"毛刺"。
真实的简历是什么样的?
“负责交易系统的重构。原来一个单体应用 40 万行代码,每次发版要 2 小时。我们花了 8 个月拆成 6 个服务,发版时间降到 10 分钟。中间踩了不少坑,最大的一次是双写的时候数据不一致,赔了 3 个客户的钱。后来加了补偿机制才解决。”
这段有具体数字、有代价、有失败。这才是真的。
我的建议:简历可以用 AI 润色,但"事实"必须是你的。
如果 AI 给你写了个"你没做过的事",面试时一定会崩。
故事四:那个拒绝 AI 的老工程师
我以前的组里有个老前辈,50 岁,写了 25 年代码。
他是个"技术洁癖":代码要写得优雅、要注释齐全、要经过充分测试。
AI 刚出来的时候,他很抵触:
“机器写的东西能靠谱吗?出了 bug 谁负责?”
我们没人能说服他。
后来有一次,他遇到一个特别烦的活儿:把 3000 行 Perl 脚本改成 Python。
这活儿纯粹的"翻译",没有任何智力含量,但很容易出错。
他准备硬啃。我建议他试试 AI。
他犹豫了一下,试了。
结果:AI 20 分钟完成了 80% 的转换,他只花了两小时检查和完善。
那天他改观了。后来他成了组里"AI 用得最讲究"的人——因为他会认真 review 每一行。
这个故事说明:抵触 AI 的人,通常是"认真的人"。
他们抵触不是因为"懒",而是因为"怕出错"。
对他们,不要"说服",要"示范"。
故事五:那个"AI 提效 10 倍"的真相
我们组做过一个统计。
2025 年,我们把"用 AI"和"不用 AI"的两个人做了对比。
结论:用了 AI 的那个人,产出大概是不用的 2.3 倍。
不是 10 倍。
为什么不是 10 倍?我分析下来有三个原因:
原因一:写代码只占工作时间的 30%。
剩下的时间是:开会、沟通、review、调试、写文档、想方案。
AI 只能提升"写代码"这部分。
原因二:AI 的输出需要审核。
AI 写了 100 行,你要花时间看它写得对不对。这个时间不少。
原因三:复杂问题 AI 帮不上。
遇到真正的难题(性能、架构、并发),AI 给的东西经常"看起来对但用不了"。
所以我的结论是:AI 提效 2-3 倍是真实的,10 倍是吹的。
但 2-3 倍已经很夸张了。相当于给每个人配了两个"数字实习生"。
故事六:那个靠 AI 转行的人
我一个朋友,35 岁,原来是做通信的(基站相关的硬件)。
2024 年他被优化了。找工作很难——35 岁、非科班、没有互联网经验。
他花了一年,做了三年事:
2025 年底,他找到了工作:一家做"AI 落地"的创业公司,做"给传统企业的 AI 咨询"。
年薪比原来还高 20%。
他跟我说:“我的优势不是技术,是我懂传统企业是怎么运作的。年轻程序员懂 AI,但不懂客户的痛点。”
这个故事说明:AI 时代的"跨界",比"纯技术"更值钱。
故事七:那个被 AI 带偏的架构
我参与过 review 一个设计方案。
一个同事要设计一个"简单的定时任务系统"。需求:每天凌晨跑一批数据处理。
AI 给他的方案是:
- Kafka 做任务队列
- Redis 做分布式锁
- MySQL 存任务状态
- 用 K8s CronJob 调度
- 加 Prometheus 监控
- 加 ELK 日志
一个"每天跑一次"的任务,用了 6 个中间件。
我问他:“这个系统需要处理多少任务?”
他说:“一天大概 20 个。”
我说:“那你为什么不用 crontab?”
他愣了一下。
这就是"过度设计"。
AI 看的"最佳实践"都来自大厂——那些公司确实需要 Kafka + Redis + K8s。但你的场景不需要。
判断标准很简单:你的规模,配得上这个复杂度吗?
我的经验法则是:
- 每天 < 1000 个任务 → crontab / 单机
- 每天 1000 – 10 万 → 简单的任务队列(比如 Celery)
- 每天 > 10 万 → 才需要考虑 Kafka 这类
别把"能用"的架构,做成"看起来专业"的架构。
故事八:那个用 AI 做技术分享的人
我参加过一次内部技术分享。
分享人做了 60 页 PPT,内容很全,从"AI 的历史"讲到"未来展望"。
但整个分享下来,我什么都没记住。
后来我问他:“这个 PPT 是你做的吗?”
他说:“主要是 AI 帮我搭的框架,内容也是 AI 整理的。”
我说:“那你自己的经验呢?”
他愣了一下,说:“好像没放进去。”
这就是问题。
AI 能整理"通用知识",但大家来听分享,是想听"你的经验"。
后来我建议他:
把 PPT 砍到 15 页。
只讲一件事:你上周用 AI 解决的那个问题,具体怎么做的。
包括你踩的坑、你的判断、你的取舍。
他照做了。第二场分享,反响很好。
这个故事说明:AI 时代,"个人经验"反而更值钱。 因为通用的知识,大家都能从 AI 那里得到。
故事九:那个"用 AI 写测试"的团队
我朋友的团队,去年定了个规矩:所有新代码必须有测试。
但推行不下去 —— 因为大家"没时间写测试"。
后来他们换了个做法:用 AI 生成测试,人工 review。
结果:
- 测试覆盖率从 35% 涨到 78%
- 但初期发现 bug 的数量没变
为什么? 因为 AI 生成的测试都是"happy path"。
后来他们加了两个要求:
加上这两条之后,AI 生成的测试质量提升很明显。覆盖率 78% 的情况下,能发现 60% 的"人为注入 bug"。
这个故事说明:AI 能"提高数量",但"提高质量"要靠人的方法。
故事十:我自己的故事
最后说一个我自己的。
2025 年 3 月,我写了一篇技术文章,投给了一个技术公众号。
编辑的回复是:“文章很有深度,但读者反馈’太干了’,建议增加可读性。”
我当时很受挫。我花了两个星期写的,结果说"太干"。
后来我试了一件事:用 AI 帮我"重写一版"。
我给 AI 的指令是:
这是我的技术文章。请帮我在"不改变技术内容"的前提下,
把语言改得更"好读":
1. 长句拆短句
2. 加一些"过渡"的句子
3. 把"抽象描述"改成"具体例子"
4. 保持我的语气(不要变成官方腔)
AI 改完之后,我看了很久。
它确实改得"好读"了。但有一个致命的问题:它把"我的观点"改成了"中立的描述"。
比如我原文写:
B 帧的编码复杂度是 P 帧的 3 倍,这是我认为"分层 B 帧不值得在移动端用"的核心理由。
AI 改成了:
B 帧的编码复杂度较高,因此在移动端使用时需要权衡。
“我认为"变成了"需要权衡”。
这就是 AI 的"安全感" —— 它倾向于说"中庸的话",不说"有立场的话"。
后来我把 AI 的版本和我的版本混合:
- 它的"句式"我用了
- 它的"中立化"我改回来了
那篇文章最后改了 8 遍。发表后,阅读量是我之前文章的 5 倍。
这个故事说明:AI 能帮你"表达",但不能替你"表态"。
你的立场、你的判断、你的偏好,才是你的价值。
附录 M:那些我犹豫要不要写的东西
有几件事,我写的时候反复删了又加。
J.1 关于"AI 会不会让人变蠢"
我犹豫了很久。
因为这个问题容易"得罪人"——说"会",像是在骂人;说"不会",又像是在骗人。
我的真实看法:会,但分人。
会变蠢的人:
- 遇到问题第一反应是"问 AI"
- 拿到答案就直接用,不验证
- 不再自己推导、不再自己计算
- 不写代码了,只看 AI 写的
不会变蠢的人:
- 先自己想办法,卡住了才问
- 对 AI 的回答会验证
- 核心能力(算法、设计、判断)坚持自己练
- 把 AI 当"加速器",不当"替代品"
一个类比: 计算器让人不会算数了吗?
对普通人:是,很多人现在离了计算器算不了两位数乘法。
对数学家:不是,他们反而因为不用算数,能把精力放在更重要的事情上。
AI 也一样。它是"分化器"——强者更强,弱者更弱。
J.2 关于"AI 与我自己的焦虑"
这个我犹豫是因为——这有点"矫情"。
一个资深工程师,说自己焦虑,容易被说"得了便宜还卖乖"。
但焦虑是真的。
我最焦虑的时候是 2025 年 6 月。那时候 GPT-5 刚出来,能一次性写出很复杂的项目。
我有一个晚上,看着 AI 在 5 分钟内写出我一天的活儿,感觉特别不好受。
那种感觉是:“我这十年,是不是白学了?”
后来我怎么走出来的?
我想明白了一件事:AI 不是"替代我",是"重新定义我的价值"。
过去我的价值是"我能写出别人写不出的代码"。
现在这个价值弱化了。但我获得了新的价值:
- “我能判断 AI 写的代码对不对”
- “我能知道用户真正要什么”
- “我能在多个方案里选最好的”
这些价值,在 AI 之前也是存在的,只是被"写代码"的能力掩盖了。
现在它们被"凸显"出来了。
想通这一点之后,我反而不焦虑了。
我不是"失去价值",是"发现了另一种价值"。
J.3 关于"我是不是在给 AI 打广告"
这篇文章里,我大量说了 Claude、Cursor 的好话。有人说这是"软文"。
我确实不能说"跟我一点利益关系都没有" —— 因为如果读者去订阅,我不会有任何收入,但我也确实"真心觉得它们好用"。
我的态度是:
我推荐它们,是因为它们真的帮到了我。如果你觉得我在打广告,那你可以只读"踩坑实录"那部分——那部分讲的全是 AI 的坏话。
我尽量做到了"公允":
- 说优点的同时说了缺点
- 明说了"哪些不推荐"
- 承认了它的成本
- 承认了它的能力边界
但如果这还不够"公允",欢迎批评。
J.4 关于"5 万字这个字数"
说实话,一开始我没想写 5 万字。
我的第一版只有 5000 字。
后来是因为——我发现有些话,5000 字说不完。
比如"踩坑实录",我如果只说"AI 会瞎编 API",那我就是在重复别人说的话。
但如果我要说清楚"哪一类问题它最容易编"、“怎么防”、“我踩过什么具体的坑”——那就需要几千字。
所以 5 万字不是"为了凑数",是"为了说清楚"。
当然,我也承认:里面确实有"为了凑数"的部分。 比如第十四部分那些"灵魂拷问",有些是我硬写的。
但主体内容,都是有信息量的。




