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

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

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

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

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

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

本文是《把 Harness 讲清楚:Agent 背后的运行系统》八个核心部分的第一篇。

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

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

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

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

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

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

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

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

例如:

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

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

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

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

{
  "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
  }
}

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

契约是怎样形成的

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

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

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

自主程度应该随动作变化

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

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

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

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

最小契约生成器

下面是一段接近 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 可能发现实际问题比预期更大。例如用户让修改一个前端错误,调查后发现根因在数据库迁移。

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

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

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

常见的失败方式

只记录目标,不记录边界

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

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

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

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

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

每次都追问所有细节

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

执行中静默扩大任务

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

从原型开始怎么做

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

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

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

任务入口检查清单

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

最后理解任务契约

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

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

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