## 从一句话需求到可执行任务

用户说：“帮我把这个项目整理一下。”

人类听到这句话，会结合语气、当前目录和过往对话猜出大概意思。但 Agent 如果直接开始行动，可能会遇到一连串问题：整理是格式化代码，还是重构目录？允许修改多少文件？能不能删除废弃代码？需要运行测试吗？什么状态才算完成？

这就是 Harness 第一个核心部分存在的原因：**任务入口与契约**。

它的工作不是把自然语言改写得更漂亮，而是把一个可能含糊的请求，转换成一份能够执行、能够约束、也能够验收的任务说明。

如果把 Agent 团队比作装修队，模型像负责现场判断的工长，任务契约则是施工单：要改哪个房间、预算是多少、哪些墙不能动、做完按什么标准验收。没有施工单，能力越强的队伍反而可能拆得越多。

本文是《[把 Harness 讲清楚：Agent 背后的运行系统](https://www.ittt.cc/articles/15)》八个核心部分的第一篇。

## 任务入口不只是一个输入框

很多 Agent 原型把任务入口理解成聊天框：拿到一段字符串，原样交给模型。这适合问答，却不足以承载真实操作。

一个工程化任务入口至少要接收五类信息：

| 信息 | 要回答的问题 | 示例 |
| --- | --- | --- |
| 目标 | 最终要得到什么 | 修复登录超时问题 |
| 范围 | 可以操作哪些对象 | 仅修改当前仓库 |
| 边界 | 明确禁止什么 | 不改数据库结构，不发送外部消息 |
| 完成标准 | 怎样才算完成 | 测试通过，说明根因和改动 |
| 证据 | 用什么证明完成 | 测试输出、文件路径、接口回执 |

此外还可能有截止时间、成本预算、目标环境、数据敏感级别和审批人。这些内容不一定都由用户手工填写，可以从当前项目、组织策略和会话上下文中补充，但最终应形成一份清楚的内部契约。

## 为什么不能把所有歧义都交给模型猜

合理推断是 Agent 提高效率的重要能力，但不是所有问题都适合猜。

可以采用一个简单判断：**如果猜错后容易发现、容易撤销、影响范围小，就可以先做合理假设；如果猜错会造成外部影响、数据损失或昂贵返工，就必须询问或审批。**

例如：

- 用户没指定 Markdown 文件名，选择语义清楚的文件名，通常可以合理假设；
- 用户说“清理无用数据”，但没有说明范围，不应该自行删除；
- 用户让分析邮件内容，可以读取已授权邮件；如果要代替用户回复，则是新的外部写入；
- 用户让修复代码，可以修改相关文件；是否顺便升级所有依赖，则通常超出任务范围。

所以，任务入口需要做的不只是“理解意图”，还要判断不确定性的风险。

## 一份任务契约应该长什么样

任务契约不必是一份复杂文档。对多数开发任务，一个结构化对象已经足够：

```json
{
  "objective": "修复登录页在会话过期后无限刷新问题",
  "scope": {
    "repositories": ["web-admin"],
    "paths": ["src/auth", "tests/auth"]
  },
  "allowed_actions": ["read_files", "edit_files", "run_tests"],
  "forbidden_actions": ["deploy", "change_database", "send_message"],
  "completion_criteria": [
    "复现并说明根因",
    "新增回归测试",
    "相关测试全部通过"
  ],
  "required_evidence": ["changed_files", "test_result"],
  "budgets": {
    "max_minutes": 30,
    "max_tool_calls": 80
  }
}
```

这份对象不一定直接展示给用户，却应该成为后续上下文、工具权限、停止条件和结果验证的共同依据。

## 契约是怎样形成的

完整流程可以画成下面这样：

```text
用户请求
   ↓
识别目标与对象
   ↓
合并项目规则和组织策略
   ↓
检查歧义与风险
   ├─ 低风险、可撤销 → 记录假设
   └─ 高风险、不可逆 → 询问或审批
   ↓
生成任务契约
   ↓
交给上下文引擎、Agent Loop 和工具网关
```

这里有一个关键点：任务契约不是只给 Agent Loop 看。工具网关要根据它决定暴露哪些工具，策略层要根据它判断是否需要审批，评估模块也要依据同一份完成标准验收结果。

## 自主程度应该随动作变化

同一个用户对同一个 Agent 的授权，也不应该在整场任务里保持一个模糊的“全自动”开关。

更实用的方法是把动作分层：

| 动作等级 | 典型操作 | 默认策略 |
| --- | --- | --- |
| 只读分析 | 搜索、读取、计算 | 可自动执行 |
| 本地可逆修改 | 编辑工作区文件 | 在明确范围内自动执行 |
| 外部写入 | 发消息、建工单、发布内容 | 需要明确任务授权 |
| 破坏性操作 | 删除、覆盖、生产变更 | 精确确认目标与后果 |

用户说“帮我看看为什么构建失败”，这授权了读取和诊断，并不自然包含提交代码、推送分支或发布生产环境。Harness 必须保留这种语义差别。

## 最小契约生成器

下面是一段接近 Python 的伪代码，展示任务入口的基本职责：

```python
def build_contract(user_request, project_rules, identity):
    intent = understand(user_request)

    contract = {
        "objective": intent.objective,
        "scope": infer_scope(intent, project_rules),
        "allowed_actions": allowed_by(identity, intent),
        "forbidden_actions": project_rules.forbidden_actions,
        "completion_criteria": infer_acceptance(intent),
        "required_evidence": infer_evidence(intent),
    }

    risks = find_ambiguities(contract)

    for risk in risks:
        if risk.is_reversible and risk.impact == "low":
            contract["assumptions"].append(risk.safe_default)
        else:
            contract["questions"].append(risk.question)

    return contract
```

真实系统中，`allowed_by` 不应只依赖模型判断，而要读取经过认证的用户身份、令牌权限和组织策略。

## 契约在执行期间也会变化

任务开始后，Agent 可能发现实际问题比预期更大。例如用户让修改一个前端错误，调查后发现根因在数据库迁移。

此时不应该悄悄扩大范围。正确流程是：

```text
发现新情况
   ↓
判断是否仍在原契约内
   ├─ 是 → 继续执行并记录证据
   └─ 否 → 提出范围变更
              ↓
        用户确认或策略批准
              ↓
          生成新契约版本
```

契约最好带版本号。这样审计时能解释：某个写操作为什么在开始时不允许，后来却被执行——因为用户在第二版契约中明确扩大了范围。

## 常见的失败方式

### 只记录目标，不记录边界

“优化项目”只是目标，没有说明哪些东西不能动。Agent 很容易把重构、升级依赖和删除兼容代码都理解成优化。

### 把工具存在误认为用户授权

系统装有邮件发送工具，不代表每次任务都允许发邮件。能力和授权必须分开。

### 完成标准写成“尽力处理”

没有可检查的标准，Agent Loop 就不知道何时停止，评估模块也只能相信一段自我总结。

### 每次都追问所有细节

过度询问会让 Agent 失去价值。契约层应该识别安全默认值，只把真正会改变结果或风险的问题交给用户。

### 执行中静默扩大任务

用户授权修一个 Bug，Agent 顺便重构整个模块。即使结果看起来更好，也破坏了可预测性。

## 从原型开始怎么做

不需要一开始就建立复杂的任务 DSL。可以先做四件事：

1. 每个任务都生成 `objective`、`scope`、`allowed_actions` 和 `done_when`；
2. 把外部写入和破坏性操作单独分类；
3. 要求 Agent 在执行前记录关键假设；
4. 最终回复逐条对应完成标准，并附上证据。

当任务类型逐渐稳定，再把常见契约做成模板，例如“代码修复”“内容发布”“数据分析”和“客户沟通”。

## 任务入口检查清单

- 目标是否描述了结果，而不只是动作？
- 操作对象和范围是否明确？
- 哪些动作被允许，哪些动作被禁止？
- 是否区分只读、本地修改、外部写入和破坏性操作？
- 高风险歧义是否会触发询问或审批？
- 是否记录了 Agent 自行采用的假设？
- 完成标准能否被程序或人工检查？
- 最终需要返回哪些证据？
- 任务范围变化时，是否生成新的契约版本？

## 最后理解任务契约

任务契约不是为了束缚 Agent，而是为了让自主执行变得可信。

没有契约时，系统只能在“每一步都问用户”和“什么都让模型自己决定”之间摇摆。有了契约，Harness 才能把安全的小决定交给 Agent，把真正重要的选择留给用户，并让后续的上下文、工具、安全和评估围绕同一个目标协作。

一句话总结：**先定义什么叫完成，再让 Agent 开始行动。**
