Skip to main content
最佳实践

Outcome 最佳实践

使用 Outcome 的推荐方式:编写任务与验收标准、选择评估轮次、判断完成并取回产物。

本文介绍使用 Outcome 的推荐方式,并给出一个完整示例。字段与机制说明见 Outcome 验收判定。

流程概览

一次通过评估的 Outcome 按以下顺序执行:
  1. 客户端发送 user.define_outcome,任务写在 description,验收标准写在 rubric。
  2. Agent 按 description 工作,Session 进入 running。
  3. 评估线程评估产出,事件流发送 span.outcome_evaluation_start、span.outcome_evaluation_ongoing 和 span.outcome_evaluation_end。
  4. span.outcome_evaluation_end.result 为 satisfied,Session 对象的 outcome_evaluations[].completed_at 写入。
  5. Agent 输出最终回复,Session 回到 idle。

任务与验收标准

description 是 Agent turn 的输入,rubric 仅供评估线程使用,两者互不可见:
内容位置可见方
任务内容、产物路径、输出格式、源数据descriptionAgent
验收标准、期望值、失败条件rubric评估线程
  • 任务内容只写在 rubric 中时,Agent 无法读取任务。
  • 评估线程无法读取 description。标准依赖的期望值或源数据需要写进 rubric,不要使用「按任务描述核对」这类标准。
验收标准的写法:
类型示例
产物位置存在 /data/report.html
具体内容包含吞吐与延迟两组数据,各至少 1 个图表
证据每个瓶颈附代码位置或 profiling 数据
失败条件沙箱中没有该文件,且 Agent 声明无法完成时判定为 failed
每条标准只描述一件事。把「完整」「可运行」「有证据」拆成三条,而不是合并为一条。

评估轮次

max_iterations 是评估次数的上限,每次评估都会消耗 credits。
取值适用场景
1只需要通过或不通过的结论。评估未通过时,Outcome 进入 max_iterations_reached
2–3(默认 3)需要 Agent 根据评估结论修订。needs_revision 后自动开始修订 turn
大于 3任务需要多轮修订才能收敛
建议先用 max_iterations: 1 调整 rubric,确认一轮评估即可得出正确结论后,再按需增加轮次。

发送时机

user.define_outcome 需要单独发送,并且只能在 Session 为 idle 且没有活跃 Outcome 时发送:
curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  | jq '{status, active_outcomes: [.outcome_evaluations[] | select(.completed_at == null)] | length}'
status 为 idle 且 active_outcomes 为 0 时可以发送。约束说明见请求约束。

判断完成

Outcome 运行期间 Session 持续处于 running。按目的选择判断条件:
目的判断条件
读取评估结论outcome_evaluations[].completed_at 不为 null
读取 Agent 的最终回复,或发送下一个事件Session status 回到 idle
读取 result 的同时读取 explanation。explanation 包含逐条标准的评估说明,可以展示给用户或写入日志。 使用事件流时,session.status_idle 的 stop_reason.type 为 requires_action 表示工具调用等待确认,不表示 Outcome 结束,见工具确认。

取回产物

rubric 要求文件产物时,在 description 中要求 Agent 将文件写入 /data/ 并通过 DeliverArtifacts 交付。交付成功时事件流发送 agent.artifact_delivered。
  • 修订 turn 重新交付时会生成新的 File。使用最后一条 agent.artifact_delivered 的 file_id 获取最终版本。
  • 文件可能在交付数秒后才出现在文件列表中。
  • Agent 也可能直接在回复中给出结果,客户端应同时处理这两种情况。
接口说明见 Session 产出物的交付与取回。

示例:订单汇总

本示例让 Agent 根据一份订单 CSV 计算订单数、总金额和消费金额最高的客户,写入 /data/summary.json 并交付,再由 Outcome 评估结果是否正确。

1. 创建 Agent

评估线程继承 Agent 的工具权限。将评估所需的工具配置为 always_allow,Outcome 运行期间不需要人工确认。
AGENT_ID=$(curl -s -X POST "https://api.qoder.com.cn/api/v1/cloud/agents" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "order-summary-agent",
    "model": "auto",
    "system": "You are a data assistant. Produce exactly the files the user asks for.",
    "tools": [{
      "type": "agent_toolset_20260401",
      "enabled_tools": ["Bash", "Read", "Write", "Glob", "Grep", "DeliverArtifacts"],
      "configs": [
        {"name": "Bash",  "permission_policy": {"type": "always_allow"}},
        {"name": "Read",  "permission_policy": {"type": "always_allow"}},
        {"name": "Write", "permission_policy": {"type": "always_allow"}},
        {"name": "Glob",  "permission_policy": {"type": "always_allow"}},
        {"name": "Grep",  "permission_policy": {"type": "always_allow"}},
        {"name": "DeliverArtifacts", "permission_policy": {"type": "always_allow"}}
      ]
    }]
  }' | jq -r '.id')

2. 创建 Session

SESSION_ID=$(curl -s -X POST "https://api.qoder.com.cn/api/v1/cloud/sessions" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"agent\": \"$AGENT_ID\", \"environment_id\": \"$ENVIRONMENT_ID\", \"title\": \"order summary\"}" \
  | jq -r '.id')

3. 定义 Outcome

任务和源数据写在 description 中,期望值写在 rubric 中。max_iterations 设为 2,允许 Agent 根据评估结论修订一次。
cat > define.json <<'EOF'
{
  "events": [{
    "type": "user.define_outcome",
    "description": "下面是一份订单 CSV。请计算订单数、总金额、消费金额最高的客户,写到 /data/summary.json,格式为 {\"order_count\": <int>, \"total_amount\": <number>, \"top_customer\": <string>},然后用 DeliverArtifacts 交付该文件。最后用一句话回复结论。\n\norder_id,customer,amount\n1001,alice,120.50\n1002,bob,80.00\n1003,alice,35.25\n1004,carol,210.00\n1005,bob,60.00",
    "rubric": {
      "type": "text",
      "content": "# 订单汇总 rubric\n\n以下期望值已根据源数据预先计算。\n\n## 产出物\n- 沙箱中存在 /data/summary.json(读取文件核验,不以 Agent 的回复为依据)\n- 内容是合法 JSON,且只包含 order_count、total_amount、top_customer 三个字段\n\n## 数值\n- order_count == 5\n- total_amount == 505.75(允许 0.01 误差)\n- top_customer == \"carol\"\n\n## 判定\n- 任一条不满足:needs_revision,逐条写出差距与修正方法\n- 沙箱中没有该文件且 Agent 声明无法完成:failed"
    },
    "max_iterations": 2
  }]
}
EOF

curl -s -X POST "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID/events" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d @define.json

4. 读取评估结论

until [ "$(curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  | jq -r '.outcome_evaluations[-1].completed_at // empty')" != "" ]; do sleep 3; done

curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  | jq '.outcome_evaluations[-1] | {result, iteration, explanation, completed_at}'
响应示例:
{
  "result": "satisfied",
  "iteration": 0,
  "explanation": "Read /data/summary.json directly. It is valid JSON with exactly three keys: order_count=5, total_amount=505.75, top_customer=\"carol\" — matching every rubric criterion. Agent reply values are consistent with the file but were not relied upon; the file itself is the evidence.",
  "completed_at": "2026-09-24T03:15:54.986863Z"
}

5. 读取最终回复

completed_at 写入时收尾 turn 可能尚未结束。等待 Session 回到 idle 后读取最后一条 agent.message:
until [ "$(curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" | jq -r '.status')" = "idle" ]; do sleep 2; done

curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID/events?limit=100" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  | jq -r '[.data[] | select(.type == "agent.message")][-1].content[0].text'

6. 取回产物

FILE_ID=$(curl -s "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID/events?limit=100" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
  | jq -r '[.data[] | select(.type == "agent.artifact_delivered")][-1].file_id')

curl -s "https://api.qoder.com.cn/api/v1/cloud/files/$FILE_ID/content" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN" | jq -r '.url' | xargs curl -s
输出:
{"order_count": 5, "total_amount": 505.75, "top_customer": "carol"}

7. 归档 Session

curl -s -X POST "https://api.qoder.com.cn/api/v1/cloud/sessions/$SESSION_ID/archive" \
  -H "Authorization: Bearer $QODER_ACCESS_TOKEN"

事件流

本示例一轮评估通过时的事件顺序(省略 span.model_request_* 和 agent.thinking):
session.status_running
user.define_outcome
agent.tool_use                     Write
agent.tool_use                     DeliverArtifacts
agent.artifact_delivered           summary.json
agent.message                      Agent turn 的回复
span.outcome_evaluation_start      iteration=0
span.outcome_evaluation_ongoing
span.outcome_evaluation_end        result=satisfied
agent.message                      最终回复
session.status_idle                stop_reason.type=end_turn
Agent 的首次产出未通过评估时,span.outcome_evaluation_end 的 result 为 needs_revision,随后依次出现修订 turn 的 agent.tool_use、新的 agent.artifact_delivered 和 iteration=1 的评估事件。此时 Session 下有两个 summary.json,最后一条 agent.artifact_delivered 对应最终版本。

检查清单

  • 任务内容、产物路径和输出格式写在 description 中,验收标准写在 rubric 中。
  • rubric 不依赖 description 的内容,期望值或源数据已写入 rubric。
  • 每条标准可以独立核验,并写明失败条件。
  • 首次上线使用 max_iterations: 1,确认一轮评估即可得出正确结论。
  • 评估所需的只读工具配置为 always_allow,或客户端已处理 requires_action。
  • 只在 Session 为 idle 且没有活跃 Outcome 时发送 user.define_outcome,并单独发送。
  • 重试同一请求时携带 Idempotency-Key。
  • 通过 completed_at 判断 Outcome 是否结束;读取最终回复或发送下一个事件前,等待 Session 回到 idle。
  • 读取并记录 explanation。
  • 使用最后一条 agent.artifact_delivered 的 file_id 取回产物。
Outcome 最佳实践 - Qoder CN