# 案例模板（templates/case.md）

本模板适用于全部**企业案例**（`case-001`–`case-080`）。每个案例回答一个具体业务问题：“在 X 场景下，如何用 AgentTeam Workflow 解决 Y 痛点”。案例统一结构，便于读者按需检索、便于 Review 与统稿。

复制本文件到 `manuscript/part-05-enterprise-cases/<类别子目录>/` 并改名为 `case-<三位序号>-<slug>.md`（序号即案例编号，全书 `case-001`–`case-080`），替换 `{{…}}` 字段。类别子目录以任务树为准：`22-engineering` / `23-product-project` / `24-sales-presales-marketing` / `25-support-customer-success` / `26-human-resources` / `27-finance` / `28-legal-compliance-security` / `29-procurement-supply-chain` / `30-admin-enterprise-it` / `31-management-cross-functional`。案例识别 glob：`manuscript/part-05-enterprise-cases/**/case-*.md`。

**关于 10 个槽位**：下方“槽位骨架”给出全书唯一的 10 个 canonical 槽位标记与填写指南；“完整范例”是填好的样例，不再含槽位标记。检查器只扫描 `manuscript/**/*.md`，不计本模板与 `STYLE.md` / `TERMINOLOGY.md`（见 `STYLE.md` §15）。作者生成案例文件时，10 个槽位标记各出现一次；不涉及的槽位保留标记并写“本案例不涉及 X（原因）”，不得删除标记。

## 元数据表（置于案例首部）

| 字段 | 必填 | 说明 |
| --- | --- | --- |
| `{{case-no}}` | 是 | 三位案例编号，与文件名序号一致（`001`–`080`） |
| `{{industry}}` | 是 | 行业（互联网 / SaaS / 金融 / 制造 …） |
| `{{department}}` | 是 | 部门（研发 / 产品 / 销售 / 客服 / 人力 / 财务 / 法务 / 采购 …） |
| `{{role}}` | 是 | 主要使用者角色 |
| `{{difficulty}}` | 是 | `入门` / `进阶` / `复杂` |
| `{{source}}` | 是 | 调用来源 `manual` / `schedule`（见 `TERMINOLOGY.md` §4） |
| `{{nodes}}` | 是 | 用到的节点类型（以 `TERMINOLOGY.md` §3 的 10 种为准） |
| `{{external}}` | 否 | 对接的外部系统（由 Agent 承担，非工作流直接调用） |
| `{{media-list}}` | 否 | 媒体清单 |

## 槽位骨架

> 复制本节正文到你的文件。全书 10 个 canonical 槽位标记各出现一次；填写时保留每个标记、替换其下占位为正文，不涉及的也保留标记并写“本案例不涉及 X（原因）”。

<!-- slot: 目标 -->
**业务目标**：为谁解决什么痛点 + 可量化指标（响应时间、准确率、人力节省）。一个案例只解一个主问题。

<!-- slot: 边界 -->
**边界与假设**：“覆盖 / 不覆盖 / 假设”三栏，钉死适用面。

<!-- slot: 提示词 -->
**提示词**：完整可复制的提示词（用 `text` 代码块），与配置中交给 Agent 的文本对应。

<!-- slot: 流程 -->
**解决方案概览**：端到端流程（`mermaid` 或图，图存 `media/`）。

<!-- slot: 配置 -->
**配置**：可运行的 `yaml` 节选，字段与 `loop.plan/v1` schema 一致，每个关键节点配一句说明。

<!-- slot: 异常 -->
**异常与降级**：≥2 种典型失败：现象 → 原因 → 处置；报错用 `text` 代码块。失败语义须与 runtime 一致（见 `TERMINOLOGY.md` §6/§8）。

<!-- slot: 审批 -->
**审批与人工环节**：审批人 / 内容 / 驳回行为。`request_approval` 无创作期 timeout，不写“超时升级”。不涉及也显式声明。

<!-- slot: 外部系统 -->
**外部系统对接**：由 Agent 承担集成（`send_message` callback），工作流不直接调用 HTTP。不涉及也显式声明。

<!-- slot: 验收 -->
**运行与验收**：可复现判定（回放数据集、阈值、抽检比例），与目标指标对应。

<!-- slot: 媒体槽位 -->
**媒体槽位**：用媒体标记登记图位（命名 `fig-case-<编号>-<序号>-<slug>.png`），成稿补图与图题。

## 完整范例（worked example：`case-001` 研发 Bug 分诊）

> 术语与字段以 `TERMINOLOGY.md` 与当前 `loop.plan/v1` schema 为准。本范例“配置”块原样提取后经 `workflow plan validate` 为 `diagnostics=[]`；switch 片段使用合法的 `||`。范例按最短链收缩为“分诊 → 人工确认 → 通知已确认的指派结果”，不含 Issue 写回（见“外部系统对接”）。

| 字段 | 值 |
| --- | --- |
| 案例编号 | `001` |
| 行业 / 部门 | 互联网 / 研发 |
| 角色 | 工程经理 |
| 难度 | `进阶` |
| 调用来源 | `manual`（每日由外部定时发起一次手动调用） |
| 节点 | `send_message`（callback 调用分诊 Agent）、`request_approval`、`send_message`（sent 通知）、`end` |
| 外部系统 | 无（本范例不含写回；见“外部系统对接”） |

### 业务目标

新提交的 Bug 每天堆积，人工分诊耗时。目标：每条新 Bug 由分诊 Agent 给出指派建议，经人工确认后把结果通知到团队频道。指标：分诊响应中位数 < 10 分钟；每条结果都经人工确认。

### 边界与假设

- **覆盖**：对新 Bug 自动分诊、人工确认、把确认后的指派结果通知到频道。
- **不覆盖**：Bug 修复本身、自动写回代码托管 Issue（需额外 `send_message(callback)` 的 Agent 节点，见“复用与变体”）、按严重度分流。
- **假设**：Bug 以结构化摘要进入；分诊 Agent 能在频道中被调用。

### 解决方案概览

<!-- media: fig-case-001-flow.png -->
图 case-001-1 流程：发起调用 → `send_message(callback)` 让分诊 Agent 返回 `assignee_team` → `request_approval` 人工确认 → `send_message(sent)` 把确认后的指派结果通知到频道 → 成功 / 驳回。

### 提示词

```text
你是资深 Bug 分诊工程师。输入为一个 Bug 工单（标题、描述、堆栈、初判严重度）。
请返回 JSON：assignee_team（应指派的团队），并给出一句理由。
```

### 配置

```yaml
# apiVersion/kind/graph 结构与字段以 loop.plan/v1 为准（见 TERMINOLOGY.md §9）
apiVersion: loop.plan/v1
kind: PlanVersion
input:
  destination: {type: scope, required: true}      # 团队频道
  triager: {type: agent, required: true}           # 分诊 Agent
  bug_summary: {type: string, required: true}
graph:
  entry:
    nodeId: triage
    port: in
    input:
      destination: {ref: plan.input.destination}
      triager: {ref: plan.input.triager}
      bug_summary: {ref: plan.input.bug_summary}
  nodes:
    - id: triage                # 调用分诊 Agent：发消息并等回调
      type: send_message
      input:
        destination: {type: scope, required: true}
        triager: {type: agent, required: true}
        bug_summary: {type: string, required: true}
      sendMessage:
        scope: {ref: input.destination}
        responder: {ref: input.triager}
        text: "请分诊以下 Bug，返回 assignee_team：{{ input.bug_summary }}"
        completion: callback
        callbackOutput:
          assignee_team: {type: string, required: true}
    - id: approve               # 人工确认指派建议
      type: request_approval
      input:
        destination: {type: scope, required: true}
        assignee_team: {type: string, required: true}
      requestApproval:
        assignee: owner
        summary: "确认 Bug 指派"
    - id: notify                # 把确认后的指派结果通知到频道（仅投递消息）
      type: send_message
      input:
        destination: {type: scope, required: true}
        assignee_team: {type: string, required: true}
      sendMessage:
        scope: {ref: input.destination}
        text: "已确认，Bug 指派给 {{ input.assignee_team }}。"
        completion: sent
    - id: done
      type: end
      end: {outcome: succeeded}
    - id: stopped
      type: end
      end: {outcome: failed, code: approval_rejected}
  edges:
    - id: classified            # triage 的回调输出 assignee_team 经 binding 传入 approve
      source: {nodeId: triage, port: completed}
      target: {nodeId: approve, port: in}
      bindings:
        destination: {ref: input.destination}
        assignee_team: {ref: output.assignee_team}
    - id: approved              # approve 把所需输入透传给 notify
      source: {nodeId: approve, port: approved}
      target: {nodeId: notify, port: in}
      bindings:
        destination: {ref: input.destination}
        assignee_team: {ref: input.assignee_team}
    - id: rejected
      source: {nodeId: approve, port: rejected}
      target: {nodeId: stopped, port: in}
    - id: sent
      source: {nodeId: notify, port: completed}
      target: {nodeId: done, port: in}
```

要点：节点只能引用自己 `input:` 契约里声明、并由 `entry.input` 或边 `bindings` 传入的字段；`assignee_team` 来自 `triage` 的回调输出（`{ref: output.assignee_team}`），`destination` 沿边透传。`notify` 是 `completion: sent`，只保证消息投递到频道，不委派 Agent 做外部动作。

### 审批与人工环节

- 每条指派建议都经 `request_approval` 由 owner 确认后才通知：`approved` 继续、`rejected` 终止。`request_approval` **没有创作期 timeout**，不安排“审批超时升级”。

### 外部系统对接

- 本范例**不含**对代码托管 Issue 的写回。分诊由 `send_message(completion: callback)` 的分诊 Agent 承担；`notify` 只是 `completion: sent` 的频道通知，不能委派 Agent 写回外部系统。
- 若需要真实写回 Issue，应追加一个 `send_message(completion: callback)` 节点，`responder` 指向写回 Agent 并声明其 `callbackOutput`（见“复用与变体”）。Agent 侧凭据用 `<token>` 占位，由 Agent 运行时从密钥引用，不进入工作流定义。

### 异常与降级

- Agent 回传不符合 `callbackOutput` schema → 这次完成请求被拒绝（`ErrCallbackOutputInvalid`），Effect 仍 `awaiting`，Agent 修正后重交；**不是**按节点 `retry` 自动重跑。`retry` 只管 Effect 投递失败的重试。
- 审批 `rejected` → 进入 `stopped`（`outcome: failed, code: approval_rejected`），可在审批收件箱追溯。
- 长时间无人响应 → Run 停在 `waiting`，由运维介入；不存在 `timed_out` 状态（仅 `wait` 节点有 `timeout` / 超时路由）。

### 运行与验收

- 用标注好的历史 Bug 回放：指派建议与人工一致率 ≥ 85% 视为通过。
- 每条结果 100% 经过 `request_approval`。

### 复用与变体

- 同构迁移：客户工单分诊、运维告警分级、客服升级判定。
- 真实写回：把 `notify` 替换/追加为 `send_message(completion: callback)` 节点，`responder` 指向写回 Agent，声明其 `callbackOutput`（如 `issue_url`）。
- 按 `severity` 分流（只对高危走审批）：把回调结果写入 `state`，再用 `switch` 路由。表达式运算符用 `||`，**不支持** `or`（见 `TERMINOLOGY.md` §7）：

```yaml
# 片段：仅展示 switch 结构，完整边与绑定见第三篇与 spec
- id: route
  type: switch
  input:
    severity: {type: string, required: true}
  switch:
    mode: first_match
    cases:
      - port: high
        when: "input.severity == 'P0' || input.severity == 'P1'"
      - port: normal
        isDefault: true
```

### 媒体槽位

<!-- media: fig-case-001-flow.png -->

## 自检（提交前）

- [ ] 10 个 canonical 槽位标记齐全（定义见“槽位骨架”；本案例已覆盖，不适用处已写明）。
- [ ] 元数据：三位编号 `case-001`–`case-080`、难度取 `入门`/`进阶`/`复杂`；`{{…}}` 全替换；无 `TBD`/`TODO`。
- [ ] “配置”块原样提取后 `workflow plan validate` 为 `diagnostics=[]`；switch 片段用 `||`。
- [ ] 提示词可复制；YAML 字段与 schema 一致、敏感值占位。
- [ ] 失败语义与 runtime 一致（无 approval timeout / 升级；callback 不符 = 拒绝重交；无 `timed_out`）；`completion: sent` 节点不得描述为委派 Agent 外部动作。
- [ ] 媒体引用真实存在或为媒体标记登记。
