2023 年,你需要写一个爬虫:requests 发请求 → 正则解析 HTML → 异常处理 + 重试,300 行代码,每行都是你写的。
2025 年,你告诉 Agent:「把某网站上最近 100 篇文章的标题和链接存到 CSV 里」,它自己写代码、调试、跑通、交付结果。
问题来了:到底哪一段代码是你「写」的?
这不是编程工具的升级,而是软件开发范式的根本性转移。Karpathy 在 2017 年提出「Software 2.0」时说:神经网络是程序员用数据写出的程序。但八年后的今天,2.0 已经不够用了——因为系统不再只是「被训练」,它们开始「自己决定怎么做」。
我把这个演进分为四个阶段:
软件 1.0:人写规则,机器执行
这是我们最熟悉的世界。程序员把业务逻辑翻译成代码,计算机逐行执行。
def extract_articles(html: str) -> list[dict]:
"""从 HTML 中提取文章标题和链接"""
soup = BeautifulSoup(html, "html.parser")
articles = []
for article in soup.select("article.post"):
title = article.select_one("h2").get_text(strip=True)
link = article.select_one("a")["href"]
articles.append({"title": title, "link": link})
return articles
# generated by hugo AI
核心特征:
- 确定性:同样的输入永远得到同样的输出
- 可解释:出了 bug,你能一行一行地找到原因
- 人定义过程:程序员知道每一步为什么这样写
局限性也很明显: 遇到开放世界问题——比如理解自然语言意图、识别图片中的猫、或者从海量内容中做个性化推荐——规则会指数级爆炸。你写不完所有 if-else。
一句话总结:「程序员知道每一步为什么。」
软件 2.0:数据定义规则,人定义结构
Karpathy 的经典定义:程序员不再写逻辑,而是设计网络结构,用数据优化参数,让模型自己「长」出逻辑。
# 程序员只定义结构,参数由数据决定
model = VisionTransformer(
image_size=224,
patch_size=16,
num_layers=12,
num_heads=12,
hidden_dim=768,
)
# 训练后,model 内部 86M 参数构成的「逻辑」没人能读懂
# generated by hugo AI
核心特征:
- 端到端:输入→输出,中间是黑盒
- 泛化能力:没见过的图片也能识别
- 人定义结构,数据定义参数
但 2.0 的边界也很清晰: 模型能做「感知」的事——分类、翻译、生成——但它不能「行动」。它不能调 API、不能操作文件、不能替你做决策。它是一个超级大脑,但没有手和脚。
一句话总结:「程序员知道模型长什么样,但不知道它学到了什么。」
软件 2.5:固定框架下的策略优化
这一代最容易被忽略,也最重要——它是 2.0 到 3.0 的过渡态。
核心区别:架构不进化,只有参数在优化。
典型例子:
- 推荐系统:召回 → 粗排 → 精排 → 重排,pipeline 固定不变,但每个阶段的模型参数在持续迭代
- LLM 微调:LoRA、SFT、DPO,模型架构不动,权重在变
- A/B 测试驱动的策略迭代:推荐算法的特征组合在搜索空间里优化,但搜索空间本身是人定的
┌──────────────────────────────────────────────────────┐
│ 2.5: 固定架构 + 参数优化 │
│ │
│ 用户请求 ──→ [召回模型 θ₁] ──→ [精排模型 θ₂] ──→ 结果 │
│ ↑ ↑ │
│ 参数在变 参数在变 │
│ (架构不变) (架构不变) │
└──────────────────────────────────────────────────────┘
# generated by hugo AI
核心特征:
- 迭代而非进化:系统在优化,但优化的空间是人画好的
- 参数空间搜索:搜索的是连续空间中的权重矩阵
- 人知道模型要做什么,但不确定它做得好不好
2.5 很强大,但它有一个天花板:搜索空间是封闭的。模型只能在你允许的空间里找最优解,它不能跳出这个空间去发现你根本没想到的策略。
一句话总结:「程序员知道模型要做什么,但不确定它做得好不好。」
软件 3.0:目标驱动的策略自进化
这是质变的一代。
核心变化:系统不再只是优化参数,它在发现、验证、迭代「怎么做」的策略本身。
软件 3.0 有三个基本要素:
┌─────────────────────────────────────────────────────────┐
│ 3.0: 目标驱动 + 策略自进化 │
│ │
│ ┌──────────┐ │
│ │ 目标定义 │ ← 程序员:「完成这个任务,满足这些约束」 │
│ └────┬─────┘ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 策略探索 │───→│ 行动执行 │───→│ 结果验证 │ │
│ └──────────┘ └──────────┘ └────┬─────┘ │
│ ▲ │ │
│ └────────── 反馈闭环 ←──────────┘ │
│ │
│ 系统自己发现「怎么做」,并对结果负责 │
└─────────────────────────────────────────────────────────┘
# generated by hugo AI
要素一:目标函数(Goal)
程序员不再写过程,而是定义「什么算成功」。
# 3.0 时代的「编程」:定义目标 + 约束
task = Task(
goal="获取目标网站最近 100 篇文章的标题和链接,存为 CSV",
constraints=[
"不得访问非公开页面",
"请求间隔 >= 1s",
"输出文件 < 1MB",
],
tools=["browser", "file_write", "web_search"],
)
# generated by hugo AI
要素二:策略空间(Strategy)
系统自己探索行动序列:先搜索 → 打开页面 → 解析 → 存文件。如果失败了,它会反思、换策略、重试。
关键区别:
| 维度 | 2.5(参数优化) | 3.0(策略进化) |
|---|---|---|
| 搜索空间 | 连续的权重矩阵 | 离散的行动序列 + 连续参数 |
| 搜索对象 | 「权重是多少」 | 「该做什么、按什么顺序做」 |
| 反馈来源 | 损失函数梯度 | 任务结果验证 + 环境反馈 |
| 人类介入 | 设计架构 + 标注数据 | 定义目标 + 设定约束 |
| 能力边界 | 架构决定的上界 | 工具集 + 验证机制决定的上界 |
从 optimization 到 planning 的跃迁。 2.5 在已知空间里找最优,3.0 在未知空间里探索可能。
要素三:可验证机制(Verification)
这是 3.0 最关键、也最容易被忽视的要素。
2.0 的不可解释性我们还能接受——输出是分类或回归,有 ground truth 可以评估。但 3.0 系统在「做事」:调 API、写文件、删数据库。出错的代价从「预测不准」变成了「数据丢了」。
没有可验证性的 3.0,只是更花哨的自动化。
验证机制需要三件事:
┌──────────────────────────────────────────┐
│ 3.0 验证机制三要素 │
│ │
│ 1. Sandbox(沙盒) │
│ 行动边界:文件系统只读、API 权限隔离 │
│ → 系统不能做超出边界的事 │
│ │
│ 2. Ground Truth(验证标准) │
│ 怎么判断「做得好不好」: │
│ 单元测试 / 人工评估 / 形式化验证 │
│ → 结果必须有可度量的标准 │
│ │
│ 3. Feedback Loop(反馈闭环) │
│ 验证结果如何反哺策略更新: │
│ 成功 → 强化该策略 │
│ 失败 → 反思 → 新策略 → 再验证 │
│ → 系统能从错误中学习 │
└──────────────────────────────────────────┘
# generated by hugo AI
数据飞轮:用户轨迹如何成为 3.0 的燃料
上面说了三个要素,但还缺一个关键问题:策略从哪里进化?
答案不是更多训练数据,也不是更大的模型,而是用户使用 Agent 的真实轨迹。
但这里有一个常被误解的前提:
用户使用 Agent 的轨迹,天然不等于优化数据。只有当它被转化为「带结果标签的决策序列数据」,它才是软件 3.0 的燃料。
这句话值得展开。
轨迹 ≠ 数据
一个 Agent 帮用户完成了 100 次任务,产生了 100 段交互记录:用户说了什么、Agent 想了什么、调了哪些工具、最终输出了什么。
这些只是日志,不是训练数据。
要变成 3.0 的燃料,需要三步转化:
┌─────────────────────────────────────────────────────────────┐
│ 轨迹 → 燃料的转化链路 │
│ │
│ 原始轨迹 结构化 带标签的决策序列 │
│ (raw log) (decision seq) (labeled training) │
│ │
│ 用户: 帮我... Step 1: 调用搜索 ✓ 成功 → 正样本 │
│ Agent: 好的... Step 2: 解析结果 ✗ 失败 → 负样本 │
│ Agent: 调 API Step 3: 写入文件 ⚠ 部分成功 → 弱信号 │
│ Agent: 完成! Step 4: 返回结果 + 用户满意度评分 │
│ ↓ │
│ 决策序列 = [(s₁,a₁), (s₂,a₂), ...] │
│ 标签 = 结果验证 + 用户反馈 │
└─────────────────────────────────────────────────────────────┘
# generated by hugo AI
为什么「带结果标签」这么关键?
因为 3.0 的策略进化依赖有监督的策略优化,而不只是行为克隆(behavior cloning)。
- 行为克隆(只学「做了什么」):Agent 模仿用户的操作序列。问题:用户的选择未必是最优的,你只是在复制人类的 suboptimal 策略。
- 带结果标签的策略学习(学「做了什么 + 结果如何」):Agent 知道自己的每一步行动最终导致了什么结果,成功的路径被强化,失败的路径被削弱。
这就是 2.5 和 3.0 在数据层面的本质区别:
| 2.5 的训练数据 | 3.0 的训练数据 | |
|---|---|---|
| 数据来源 | 人工标注 / 合成数据 | 用户 Agent 交互轨迹 |
| 数据结构 | (输入, 标签) 对 | (状态序列, 行动序列, 结果标签) |
| 优化目标 | 预测准确率 | 任务成功率 + 效率 |
| 数据规模 | 有限、昂贵 | 持续产生、天然规模化 |
3.0 的 data flywheel 是这样的:
用户用 Agent 完成任务
↓
轨迹自动记录 → 转化为 (决策序列, 结果标签)
↓
策略模型离线/近线更新
↓
下一代 Agent 策略更强 → 更多用户愿意用 → 更多轨迹
↖_______________________________↗
这个 flywheel 一旦转起来,3.0 系统就不再依赖人工标注数据,而是从真实使用场景中持续进化。这也解释了为什么先拥有大规模 Agent 用户的产品,会在 3.0 时代形成结构性优势——他们积累的不是用户数,而是带标签的策略优化数据。
但这里有个陷阱
轨迹数据的价值密度远不如想象的高。原因有三:
- 大多数轨迹是平凡的:用户每天都在做类似的事(写邮件、查资料、改代码),大量轨迹在策略空间里高度重合,边际信息量递减。
- 结果标签难获取:Agent 完成任务后,用户很少主动反馈「好」或「不好」。隐式信号(是否采纳、是否修改、是否重新执行)比显式反馈更可靠,但也更难解析。
- 分布偏移问题:Agent 策略更新后,用户行为模式也会改变,导致历史轨迹的分布和当前场景不匹配。
所以 3.0 时代的另一个核心能力是:轨迹数据的筛选、标注和课程学习(curriculum learning)。 不是所有轨迹都值得学,系统需要知道「哪些经验值得记住,哪些应该忽略」。
对工程师意味着什么
如果你的工作从「写逻辑」变成了「定义目标」,那核心能力也需要重构。
未来的 code review,review 的不是代码,而是:
- 目标函数是否合理 —— 你定义的「成功」是不是真正想要的?有没有激励系统走偏?(Goodhart’s Law:当一个指标变成目标,它就不再是好指标。)
- 约束边界是否充分 —— sandbox 够不够严?有没有遗漏的 edge case?
- 验证标准是否可靠 —— 你怎么知道系统做对了?评估指标有没有被 exploit 的可能?
- 失败回退是否安全 —— 系统出错时,有没有 graceful degradation?会不会产生级联故障?
工程师的新核心能力:
- 目标函数设计:奖励 shaping、约束建模、避免对齐陷阱
- 评估体系构建:设计无法被 exploit 的验证机制
- 安全边界设计:guardrails、fail-safe、最小权限原则
- 轨迹数据工程:从原始交互日志中提取 (决策序列, 结果标签),设计隐式信号解析和课程学习策略
结语
回到开头的问题:Agent 自己写的那段爬虫代码,到底算不算你「写」的?
答案是:你写了更重要的部分——你定义了做什么和不能做什么。而具体的怎么做,系统自己学会了。
这不是程序员的末日,而是程序员角色的升级。从「写每一行代码的人」到「定义目标、设定边界、设计验证的人」——你从工人变成了建筑师。
唯一不同的是,这次你设计的建筑,会自己长出来。