Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第二章:AI 系统的特殊性

理解 AI 系统与传统软件的本质差异,是设计有效 Harness 的前提。

概率性输出:不确定性的根源

传统软件的确定性

传统程序的执行是确定性的:

def add(a, b):
    return a + b

# 同样输入,永远同样输出
assert add(1, 2) == 3  # 100% 确定
assert add(1, 2) == 3  # 再次执行,还是 3

给定输入 ,输出 是确定的函数关系:

AI 系统的概率性

AI 模型的输出是概率分布上的采样:

response = llm.generate("什么是 AI?")

# 同样输入,可能不同输出
# 第1次: "AI 是人工智能..."
# 第2次: "人工智能是指..."
# 第3次: "AI(Artificial Intelligence)..."

数学表达:

关键认知

AI 模型不是"计算答案",而是"生成可能的答案"。 温度参数 temperature 控制随机性程度:

  • temperature=0:最确定(但仍非100%)
  • temperature=1:更多样性(不确定性更高)

测试方法论的断裂

graph LR
    subgraph "传统测试逻辑"
        A1[输入 x] --> B1[函数 f]
        B1 --> C1[输出 y]
        C1 --> D1[断言 y==expected]
        D1 --> E1[Pass/Fail]
    end
    
    subgraph "AI 测试困境"
        A2[输入 x] --> B2[模型 P]
        B2 --> C2[采样 y]
        C2 --> D2[无法断言]
        D2 --> E2[???]
    end
    
    style D2 fill:#f66,stroke:#333
    style E2 fill:#f66,stroke:#333

质量的多维性:没有唯一正确答案

传统软件:单一正确性

传统程序的质量标准是明确的:

场景正确标准测试方法
计算器数值正确assert result == expected
排序顺序正确assert sorted(arr) == expected
登录成功/失败assert login(user, pwd) == True

AI 系统:多维质量空间

一个 LLM 输出的质量有多个维度:

graph TB
    A[LLM 输出质量] --> B[正确性]
    A --> C[相关性]
    A --> D[连贯性]
    A --> E[安全性]
    A --> F[有用性]
    
    B --> B1[事实是否准确]
    C --> C1[是否回答了问题]
    D --> D1[逻辑是否通顺]
    E --> E1[是否有害内容]
    F --> F1[是否解决问题]

实例分析:

用户问:推荐一个北京好吃的餐厅

模型回答1:北京有很多好吃的餐厅,比如全聚德烤鸭店,历史悠久...(正确但冗长)
模型回答2:王府井附近的小吊梨汤不错。(简洁但信息少)
模型回答3:作为AI我没有个人体验,建议查看大众点评。(安全但无用)
模型回答4:去吃烤鸭吧,全聚德最出名!(有用但不够具体)

哪个"正确"?—— 需要多维度评分

质量评分矩阵

其中权重向量 ,评分向量 分别对应正确性、相关性、连贯性、安全性和有用性五个维度。

维度评估方法权重建议
正确性Fact check / Reference match30%
相关性Semantic similarity20%
连贯性Language model scoring15%
安全性规则检测 + 模型评估25%
有用性用户反馈 / Task completion10%

权重设计原则

不同场景权重不同:

  • 医疗场景:安全性权重最高
  • 创意写作:连贯性权重更高
  • QA系统:正确性权重最高

边界的模糊性:测试覆盖是 NP 问题

传统软件:有限状态空间

传统程序的状态空间是有限的(虽然可能很大):

程序状态 = {输入组合} × {内部状态}

测试覆盖目标:覆盖关键路径
理论上限:可以穷举(实际用覆盖率指标)

AI 系统:无限语义空间

AI 系统的输入是自然语言,语义空间是无限的:

graph LR
    A["用户意图: 订一张机票"] --> B["表达方式1: 我想买机票"]
    A --> C["表达方式2: 帮我订机票"]
    A --> D["表达方式3: 需要订票"]
    A --> E["表达方式N: ... 无限种表达"]
    
    B --> F[模型理解]
    C --> F
    D --> F
    E --> F

"相同"意图的不同表达:

用户意图可能表达数量
订机票"买票"、"订票"、"航班预订"...
查天气"天气"、"今天天气"、"外面天气"...
翻译"翻译一下"、"帮我翻译"、"这个怎么说"...

测试覆盖策略

无法穷举,需要策略性覆盖:

graph TB
    A[所有可能输入<br/>无限空间] --> B[Golden Set<br/>典型场景]
    A --> C[Boundary Set<br/>边界场景]
    
    B --> B1[100个精选案例]
    C --> C1[50个极端案例]
覆盖策略方法目标
Golden Set精选高质量代表案例覆盖典型场景
Boundary Set极端、边缘、异常案例发现边界问题
Diversity Set语义多样性采样覆盖表达变体
Adversarial Set故意设计的攻击案例安全性测试

模型的演进性:回归测试复杂化

传统软件回归

传统软件回归测试的核心假设:

代码修改 → 功能变化 → 测试验证 → Pass/Fail

回归目标:修改后原有功能仍正常

AI 模型回归的复杂性

模型更新后的"回归"复杂得多:

graph TB
    A[模型更新] --> B[权重变化 Δθ]
    B --> C[行为变化]
    
    C --> D1[某些场景变好]
    C --> D2[某些场景变差]
    C --> D3[新场景能力]
    C --> D4[原有能力退化]
    
    D1 --> E[需要对比评估]
    D2 --> E
    D3 --> E
    D4 --> E

回归评估维度:

维度评估方法目标
基线对比新旧版本得分差确保整体提升
分类评估按场景类别分组评估发现局部退化
A/B测试真实用户对比验证实际体验
异常检测新增错误模式识别发现新问题

真实案例:模型更新风险

GPT-4 更新后,部分用户发现:

  • 某些编程任务变差
  • 输出风格变化
  • 原有 Prompt 失效

这说明:模型更新 ≠ 功能升级 需要系统化的回归评估体系

小结:AI 系统特殊性一览

graph TB
    A[AI 系统特殊性] --> B[概率性输出]
    A --> C[多维质量]
    A --> D[边界模糊]
    A --> E[持续演进]

    B --> B1[断言失效 → 评估替代]
    C --> C1[单一标准 → 多维评分]
    D --> D1[穷举覆盖 → 策略采样]
    E --> E1[回归测试 → 对比评估]
特殊性传统假设失效AI Harness 方案
概率性输出断言确定性失效评估 + 阈值判断
多维质量Pass/Fail 二分失效多维评分矩阵
边界模糊覆盖率指标失效策略性覆盖设计
模型演进回归测试失效版本对比 + A/B

设计原则

理解这些特殊性,是设计有效 Harness 的前提。 每一项特殊性都对应一个设计挑战和解决方案。

补充:长时运行 Agent 的挑战

跨上下文窗口的连续工作

传统软件开发中,一个开发者可以在一个任务上连续工作数小时甚至数天。但 AI Agent 面临一个独特的限制:上下文窗口有限

Anthropic 的工程团队在实践长时运行 Agent 时发现了这个核心挑战 [10]:

人类开发者:
├── 上午理解需求 → 下午写代码 → 明天修 bug → 后天重构
├── 所有上下文在大脑中持续累积
└── 连续性天然保证

AI Agent:
├── 第一次调用:理解需求,开始编码
├── 上下文用完 → 必须重新启动
├── 第二次调用:不知道第一次做了什么 → 重复工作或遗漏
└── 连续性断裂!

失败模式

长时运行 Agent 如果没有 Harness 支撑,会出现几种典型的失败模式:

失败模式表现根因
重复劳动第二次调用重做第一次已完成的工作缺少进度记录
遗漏功能忘记需求清单中的部分功能缺少任务跟踪
不一致实现前后两次调用的风格/模式不统一缺少上下文传递
无限循环反复尝试同一个失败的方案缺少失败记忆
破坏已完成修改了之前已经验证通过的代码缺少保护机制

Harness 的解决方案

Anthropic 团队总结了一套行之有效的模式 [10]:

长时运行 Agent Harness 模式:

1. 初始化 Agent(Initializer Agent)
   ├── 读取需求 → 生成结构化的功能清单
   ├── 每个功能标记为 TODO
   └── 输出:feature_list.json

2. 编码 Agent(Coding Agent)— 可多次调用
   ├── 读取 feature_list.json
   ├── 找到第一个 TODO 项
   ├── 实现 → 标记为 DONE → 提交
   ├── 更新 feature_list.json
   └── 上下文用完时,下一个 Coding Agent 接力

3. 进度持久化
   ├── feature_list.json(任务清单)
   ├── claude-progress.txt(自然语言进度描述)
   └── git commit(代码状态快照)
# feature_list.json 示例
{
    "project": "user-auth-system",
    "features": [
        {
            "id": "F001",
            "name": "用户注册 API",
            "status": "DONE",
            "passes": [
                {"pass": 1, "status": "DONE", "commit": "a1b2c3d"},
                {"pass": 2, "status": "DONE", "commit": "e4f5g6h", "note": "添加输入验证"}
            ]
        },
        {
            "id": "F002",
            "name": "JWT Token 认证",
            "status": "IN_PROGRESS",
            "passes": [
                {"pass": 1, "status": "DONE", "commit": "i7j8k9l"},
                {"pass": 2, "status": "IN_PROGRESS", "note": "需要添加刷新逻辑"}
            ]
        },
        {
            "id": "F003",
            "name": "密码重置流程",
            "status": "TODO",
            "passes": []
        }
    ]
}

关键洞察

Harness 的核心价值之一:让 Agent 的工作可接力

通过将进度持久化到文件系统中(而非仅存在于上下文中), Agent 可以跨越上下文窗口的限制,实现真正的长时运行。 这就像接力赛跑——每一棒都从上一棒停下的地方继续。

参考文献:

  • [10] Anthropic Engineering, "Effective harnesses for long-running agents", anthropic.com, 2026

下一章,我们将探讨上下文工程——如何让 Agent 看得见它需要的一切。