Task 不是 Request:从用户目标到可验收任务

用户目标不是 Request:Agent 为什么需要任务契约

前两篇已经把一次 LLM call 的边界讲清:应用发出 Request,模型基于 Context 完成一次 Inference,服务返回 Response。现在看一个看似普通的用户要求:

调研三个主流 Agent Runtime,并给出选型建议。

应用当然可以立刻把它作为 Request 发给模型。模型很可能返回一篇结构完整的比较和推荐,调用状态也会是 completed。但这并不意味着用户的工作已经完成:三个“主流”产品由谁决定?资料截至何时?没有来源的结论能否用于决策?报告面向谁?

这不是模型回答得不够好,而是让一次 Request 承担了它不具备的责任。

本文继续使用本系列的统一案例——“技术调研与报告交付 Agent”。其中第三个实践版本编号为 C03:它不执行调研,而是先把这句模糊需求整理成可确认、可计划、可验收的工作定义。下文的 C03 均指这个案例版本。

Request 成功,为什么任务仍可能失败

先把 C03 的两种处理方式放在一起:

直接发起 Request 先建立任务契约
模型自行猜测研究对象和比较范围 范围、约束与默认值被明确记录
Response 返回文本后,没有统一的完成依据 验收条件决定能否完成
某次调用失败时,只能靠聊天记录恢复上下文 任务、进度和失败点可独立保存
模型可以写“调研已完成” 只有验收器或授权人可以改变任务状态

一次 Request 只回答:“这一次让模型计算什么?”它没有天然的业务授权,也没有跨调用的生命周期,更没有独立的验收机制。要把用户的目标变成可靠工作,系统还需要一份跨 Request 保持有效的承诺;本文将它称为 Task Contract(任务契约)

用户目标
   ↓ 澄清或记录可接受默认值
Task Contract:承诺交付什么、受什么约束、怎样算完成
   ↓
Plan:当前准备怎样完成
   ↓
Executable Tasks:现在可调度和检查的工作
   ↓
Request / Tool Call:推进某项工作的具体动作

不同框架的名字不一样。本文用 Spec 表示任务契约,用 Executable Task 表示可调度的工作单元;重要的不是术语,而是不要把这几层职责混成“任务”。

任务契约先固定不该由模型猜的事

任务契约回答的是 What:系统承诺交付什么,在什么边界内交付,又按什么证据验收。对 C03 而言,最小契约至少应明确:

  • goal:要支持哪项决策;
  • scope:研究对象、比较维度与资料截止日期;
  • constraints:预算、时限、禁止事项;
  • source_requirements:什么可以作为证据;
  • deliverable:交给谁、以什么形式交付;
  • acceptance_criteria:哪些条件通过后才能宣布完成。

例如,经确认后的 ResearchTaskSpec 可以是:

goal: 为需要长任务恢复和人工审批的内部研究系统选择 Agent Runtime
scope:
  targets: [OpenAI Agents SDK, LangGraph, Google ADK]
  dimensions: [状态管理, 持久化, 人工审批, 可观测性]
  as_of: <确认日期>
constraints:
  - 不执行付费测试,不使用未公开资料
source_requirements:
  - 功能事实优先采用官方文档
  - 关键结论保存来源链接和访问日期
deliverable:
  format: markdown
  audience: 技术负责人和平台工程师
acceptance_criteria:
  - 三个对象均覆盖四个比较维度
  - 比较矩阵中的功能事实均可追溯到来源
  - 推荐结论说明适用前提、取舍和不确定项

这份契约没有告诉系统“先搜什么、后写什么”。这是有意的:路径可以改变,交付基线不能在模型遇到困难时悄悄降低。

并非每个空白都必须打断用户。低风险、可逆的默认值可以由系统采用,但必须显式写入契约;会改变研究范围、成本、外部写入或验收标准的假设,则应请求用户确认。否则系统只是把自己的偏好伪装成用户要求。

结构合法,不等于可以交付

JSON Schema 能检查字段、日期和数量,例如保证研究对象恰好有三个;它无法判断“报告要专业”能否真正验收。前者是结构校验,后者需要业务规则。可检查的条件应更接近“每个对象覆盖四个维度,关键事实带来源”,而不是把主观评价留给模型自行解释。

Task Contract 也不是某次 Prompt。Prompt 可以随步骤变化;契约要跨多次调用保持稳定。模型可以建议修订它,却不应在找不到资料时自行删除“关键结论必须有来源”。

Plan 是路径,不是新的承诺

契约明确后,系统才生成 Plan。Plan 回答 How:当前准备以什么顺序满足承诺。C03 的第一版计划可以很简单:

P1 收集三个对象的官方资料
P2 提取四个维度的事实并保存证据
P3 生成比较矩阵和推荐草稿
P4 检查覆盖度、引用与推荐前提

Plan 的说服力不在于步骤听起来全面,而在于它能覆盖契约。每条验收条件都应能找到负责它的步骤:

契约要求 负责步骤
三个对象、四个维度均有覆盖 P1、P2
关键事实可追溯 P2、P4
交付比较矩阵 P3
推荐写明前提和取舍 P3、P4

若“人工审批”这个维度在 P1~P4 中没有任何产出位置,计划再流畅也是不完整的。反过来,一步若不服务任何契约要求,也不为后续步骤提供输出,就应该质疑它是否只是模型习惯性增加的待办。

Plan 可以调整:某份文档迁移了,可以换入口或增加补充步骤;但这不等于用户同意放宽来源要求。契约是基线,Plan 是当前路径。复杂的动态重规划留给后文,C03 只要求第一版 Plan 有可检查的覆盖关系。

Executable Task 让路径可以运行和恢复

“收集三个 Runtime 的资料”仍然太大。Runtime 无法从中判断哪一份已完成、哪一份失败、少了什么,以及应当重试什么。因此 Plan 还要展开为带输入、输出、依赖与完成条件的 Executable Tasks:

Task 产出 依赖 完成条件
T1 OpenAI Agents SDK 的证据包 契约已确认 四个维度均有候选官方来源
T2 LangGraph 的证据包 契约已确认 四个维度均有候选官方来源
T3 Google ADK 的证据包 契约已确认 四个维度均有候选官方来源
T4 带来源的比较矩阵 T1、T2、T3 所有格子均有事实或明确缺口
T5 推荐与验证记录 T4 所有验收条件均有检查结果

Task 的粒度不必越小越好;只要 Runtime 能安排它、记录状态、定位失败并判断完成,就足够。“完成技术调研”太大,“想一想选型”又没有可观察输出。

Task 仍不等于 Request。T4 可能先读取三份证据包,再发一次 Request 生成矩阵,再发一次 Request 检查缺项。即使两次调用都成功,发现两个格子没有来源时,T4 仍然不应标为 completed

一个失败,如何证明这些层确实有用

假设 T2 缺少“人工审批”的官方证据。

没有任务契约时,下一次调用只看到一段旧聊天记录。系统难以知道这是“缺一条来源”、还是“可以忽略的维度”;它很容易重新生成整篇报告,或悄悄删掉该维度。

有了契约、Plan 与 Task 后,Runtime 可以保留 T1、T3 的证据,把 T2 标记为 blocked,并沿着完成条件准确报告:LangGraph / 人工审批 / 缺少候选官方来源。随后它可以重试资料收集、请求用户允许补充来源,或在用户修改契约后再重新检查受影响的任务。

spec_revision=2
  ← plan_version=1
      ← task_id=T2
          ← request_id=req_17
          ← status=blocked
          ← unmet=human_approval.source

这条追溯链能区分四类问题:用户没有说清范围、Plan 漏掉了要求、某个 Task 的执行失败,或一次 Request 的结果不满足完成条件。它们的处理方式不同,不能都归结为“模型不稳定”。

谁可以改变什么

模型擅长从自然语言提取候选契约、草拟 Plan 与提出下一步;但模型的输出只是建议。Runtime 保存权威版本、执行校验、记录状态;用户确认会影响目标或授权的决定。

变化 应由谁决定或执行
提议研究对象、计划或任务拆分 模型可以提议
接受低风险默认值 Runtime 显式记录
修改范围、成本、写入权限或验收标准 用户确认
将 Task 标为完成 Runtime 根据验收结果更新

这一边界防止模型既定义“什么算完成”,又生成结果并宣布自己通过。一次 Response 成功,只能说明某次计算成功;Task 是否完成,取决于独立的完成条件。

C03:建立可执行承诺,而不假装完成调研

C03 从那句模糊输入开始。系统先生成候选契约,发现研究对象、截止日期和验收条件缺失,状态为 needs_clarification。获得确认后,它保存 ResearchTaskSpec,生成 ResearchPlan v1、展开 T1~T5,并运行三道检查:

validate_contract  → 范围与验收条件完整、可检查
validate_plan      → 每条契约要求都有步骤覆盖
validate_tasks     → 每个 Task 有输入、输出、依赖和完成条件

最小 Trace 应能还原这个过程:

case=C03 event=contract.validation_failed revision=1
status=needs_clarification
missing=scope.targets,scope.as_of,acceptance_criteria

case=C03 event=contract.confirmed revision=2
case=C03 event=plan.created plan_version=1 steps=4
case=C03 event=tasks.created count=5
case=C03 event=coverage.checked uncovered=0
status=ready

ready 只表示执行承诺已准备好;它不表示已经调研。工具调用、证据收集和执行循环会从下一篇开始进入系统。

小结

Request 管一次模型计算;任务契约管系统对用户的交付承诺。两者之间还需要 Plan 组织当前路径、Executable Task 记录可运行和可恢复的工作。

Task Contract / Spec:我们承诺交付什么,怎样算完成?
Plan:当前准备怎样满足承诺?
Executable Task:现在可以执行、记录和验收哪项工作?
Request:这一次让模型计算什么?

下一篇将继续向执行层走:模型生成的 Tool Call 到底是什么,真正执行工具的又是谁?


案例实践清单

  • 保存原始用户目标,并记录缺失的关键条件。
  • 生成并确认 ResearchTaskSpec,显式记录默认值与用户确认项。
  • 为每条验收条件建立 Plan 覆盖关系。
  • 生成 ResearchPlan v1 与带完成条件的 T1~T5。
  • 模拟一个 Task 缺失证据,记录其状态、缺口与恢复选项。
  • 保存 Contract、Plan、Tasks 的版本号和 C03 Trace。
  • 确认 C03 只达到 ready,没有宣称完成调研。

参考资料