从写代码到定义目标:软件 1.0 到 3.0 的进化论

From Code Writing to Goal Setting: The Evolution from Software 1.0 to 3.0

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 时代形成结构性优势——他们积累的不是用户数,而是带标签的策略优化数据

但这里有个陷阱

轨迹数据的价值密度远不如想象的高。原因有三:

  1. 大多数轨迹是平凡的:用户每天都在做类似的事(写邮件、查资料、改代码),大量轨迹在策略空间里高度重合,边际信息量递减。
  2. 结果标签难获取:Agent 完成任务后,用户很少主动反馈「好」或「不好」。隐式信号(是否采纳、是否修改、是否重新执行)比显式反馈更可靠,但也更难解析。
  3. 分布偏移问题:Agent 策略更新后,用户行为模式也会改变,导致历史轨迹的分布和当前场景不匹配。

所以 3.0 时代的另一个核心能力是:轨迹数据的筛选、标注和课程学习(curriculum learning)。 不是所有轨迹都值得学,系统需要知道「哪些经验值得记住,哪些应该忽略」。

对工程师意味着什么

如果你的工作从「写逻辑」变成了「定义目标」,那核心能力也需要重构。

未来的 code review,review 的不是代码,而是:

  1. 目标函数是否合理 —— 你定义的「成功」是不是真正想要的?有没有激励系统走偏?(Goodhart’s Law:当一个指标变成目标,它就不再是好指标。)
  2. 约束边界是否充分 —— sandbox 够不够严?有没有遗漏的 edge case?
  3. 验证标准是否可靠 —— 你怎么知道系统做对了?评估指标有没有被 exploit 的可能?
  4. 失败回退是否安全 —— 系统出错时,有没有 graceful degradation?会不会产生级联故障?

工程师的新核心能力:

  • 目标函数设计:奖励 shaping、约束建模、避免对齐陷阱
  • 评估体系构建:设计无法被 exploit 的验证机制
  • 安全边界设计:guardrails、fail-safe、最小权限原则
  • 轨迹数据工程:从原始交互日志中提取 (决策序列, 结果标签),设计隐式信号解析和课程学习策略

结语

回到开头的问题:Agent 自己写的那段爬虫代码,到底算不算你「写」的?

答案是:你写了更重要的部分——你定义了做什么不能做什么。而具体的怎么做,系统自己学会了。

这不是程序员的末日,而是程序员角色的升级。从「写每一行代码的人」到「定义目标、设定边界、设计验证的人」——你从工人变成了建筑师。

唯一不同的是,这次你设计的建筑,会自己长出来。


See also