ambleloft

声明式业务表单:从 Skill 到多步交互

在 skill 中声明字段、步骤和提交方式,让宿主在聊天中渲染业务表单。本教程以三步差旅费用登记为例,说明配置范式、模型调用与提交后的数据流转。

实践指南

完成后:创建并导入一个三步业务表单,核对草稿、导航和冻结的提交数据。

前置条件:准备一个自己的 skill 目录,按下文创建文件并导入应用。聊天提交示例无需插件 Demo、SDK 或业务服务器。

本页内容

01声明式表单的分工

开发者在 skill 中定义业务入口,在 YAML 中确定字段、校验、步骤和提交方式。Agent 负责发现并展示合适的模板;宿主负责渲染、保存草稿、校验及处理用户点击。用户确认后,数据按配置发送到聊天或交给业务 Operation。模型不自行决定这份业务表单需要哪些字段。

  1. 01开发者

    Skill + YAML 定义规则

  2. 02Agent

    发现并展示合适的模板

  3. 03宿主

    渲染、校验、冻结提交

  4. 04你的服务

    通过扩展实现业务处理

021. 创建你自己的 skill

下面从一个可独立导入的 skill 开始,示例不依赖插件 Demo 或业务服务器。创建这两个文件后,在应用的技能管理中导入 travel-expense 目录并启用。若随插件交付,在 extension.json 的 skills 数组中登记相对目录,例如 "skills": ["skills/travel-expense"]。

代码示例
travel-expense/
  SKILL.md
  forms/
    travel.yaml

032. 在 SKILL.md 中登记模板

将下面内容保存为 SKILL.md。amble-form-ref 必须是正文根级代码块;path 相对 skill 目录,不能越界或使用符号链接。也可以用根级 amble-form 代码块直接写 YAML。仅在普通文字中提到文件名不会注册模板。

代码示例
---
name: travel-expense
description: 使用三步表单收集差旅费用,并整理申请草稿。
---
当用户需要登记差旅费用时:
1. 调用 forms_capabilities,确认 singleClickChat=1、readSubmission=1。
2. 调用 forms_list,找到本 skill 的 travel-expense 模板,使用返回的真实 key。
3. 调用 forms_present,可预填对话中已知的信息。不要用 Markdown 重画表单,也不要替用户提交。
4. 等待用户提交事件;使用事件中的 submissionId 调用 forms_read_submission。
5. 根据冻结的 values 整理申请草稿。发送到聊天不表示已经提交财务系统。

```amble-form-ref
path: forms/travel.yaml
```
查看完整 SKILL.md

043. 定义完整的三步表单

将下面 YAML 保存为 forms/travel.yaml。本例依次收集行程、费用和确认信息。中间步骤省略 next,表示校验后直接前进;只有最后点击“发送申请信息”才向聊天发送。核对步骤使用说明和确认勾选框,不会自动生成前面字段的汇总视图。

配置 ↔ 界面 ↔ 数据

亲手走一遍三步表单

浏览器教学演示:对应下方 YAML,使用内存中的示例数据。不会调用宿主或业务服务器,刷新即重置。

  1. 1行程
  2. 2费用
  3. 3核对
forms/travel.yaml · 行程
  - id: itinerary
    title: 行程
    fields:
      - name: destination
        type: text
        label: 目的地
        required: true

差旅费用登记

第 1 / 3 步 · 行程

前两步仅更新草稿;最后确认后,才展示冻结数据示意。

展开完整 YAML · 可直接保存使用
forms/travel.yaml
version: 1
id: travel-expense
title: 差旅费用登记
description: 填写并核对后发送到聊天,由 Agent 整理申请草稿。
steps:
  - id: itinerary
    title: 行程
    fields:
      - name: destination
        type: text
        label: 目的地
        required: true
  - id: expenses
    title: 费用
    fields:
      - name: amount
        type: money
        label: 金额
        currency: CNY
        scale: 2
        minimum: "0.01"
        required: true
      - name: note
        type: textarea
        label: 费用说明
        required: true
        maxLength: 500
  - id: review
    title: 核对
    description: 请返回前两步核对填写内容,再确认发送。
    fields:
      - name: confirmed
        type: checkbox
        label: 我已核对填写内容
        required: true
submit:
  kind: chat
  label: 发送申请信息
  confirmation: onSubmit
查看完整 YAML

05字段和步骤的配置规则

version 固定为 1;id 是模板的稳定标识。单步表单使用根 fields,宿主将其归一为 main 步骤;多步使用 steps,不能同时写根 fields。step.id 与 field.name 用于数据寻址,title 与 label 用于显示。当前支持 text、textarea、number、money、date、select、checkbox、switch、group-toggle;扩展属性以 forms_capabilities 为准。money 传十进制字符串,date 使用有效 YYYY-MM-DD,select 提交 option.value。最多 20 步、累计 100 字段、YAML 128 KiB。

查阅完整字段与动作参考

064. 让 Agent 展示业务表单

在聊天中说“帮我登记差旅费用”。Agent 阅读 skill 后调用 forms_capabilities、forms_list,再以列表中的 key 调用 forms_present。下面是 forms_present 的参数示例,必须替换 key;prefill 按步骤 ID 分组,只应填入已有业务信息。展示立即返回 {id,status},不等待填写,也不代表提交完成。

代码示例
{
  "key": "REPLACE_WITH_FORMS_LIST_KEY",
  "prefill": {
    "itinerary": {
      "destination": "上海"
    },
    "expenses": {
      "amount": "120.00"
    }
  }
}

075. 理解填写和提交的数据流

用户编辑产生宿主保存的草稿。下一步校验当前可见字段,通过后记录该步 values;保存或前后导航不会发送聊天消息。最终提交时,宿主冻结 values、initialValues、touched、模板和来源身份,并把附有 submissionId 的消息投递到当前聊天。Agent 使用 forms_read_submission 读取这份冻结数据,再完成后续任务。

代码示例
SKILL.md + YAML
  → forms_list:发现已登记模板
  → forms_present:创建表单实例并预填
  → 用户填写:草稿 → 逐步校验
  → 用户最终提交:冻结数据 + submissionId
  → 当前聊天:forms_read_submission
  → Agent:基于确认数据生成申请草稿

08读取结构化答案

以下仅展示 forms_read_submission 结果中的部分字段,不是完整回执。values 按步骤保存校验后的值;initialValues 是创建时实际提供的预填。touched 的键是“步骤ID.字段名”,true 表示用户曾编辑,即使最后改回原值也成立。缺少 touched 键不能解释为用户明确关闭了该字段。deliveryStatus 描述投递状态,不代表业务系统已受理。

代码示例
{
  "values": {
    "itinerary": {
      "destination": "上海"
    },
    "expenses": {
      "amount": "120.00",
      "note": "市内交通"
    },
    "review": {
      "confirmed": true
    }
  },
  "initialValues": {
    "itinerary": {
      "destination": "上海"
    },
    "expenses": {
      "amount": "120.00"
    }
  },
  "touched": {
    "expenses.note": true,
    "review.confirmed": true
  }
}

096. 返回修改、依赖与确认

返回上一步保留已保存的草稿。修改前置内容会使受影响的步骤结果和必要确认失效;已发生的业务操作不会撤销。dependsOn 与 visibleWhen 引用之前声明的“步骤ID.字段名”;上游变化后,关联输入保留但需要用户检查确认。隐藏字段保留草稿,不进入最终答案。当前不支持任意表达式或远程动态选项。本例的 confirmation: onSubmit 表示最后点击即确认发送;省略时使用额外确认,Operation 的权限确认不受此设置影响。

107. 接入业务服务时再使用 Operation

纯 skill 的 chat 表单可以独立运行。若某一步需要保存业务草稿,或最终要提交财务系统,需由插件在 manifest.operations 中声明并实现同插件的 Operation,exposeTo 包含 page。中间步骤用 next.kind: operation;最终用 submit.kind: operation。input.from 可读取 steps.<步骤>.<字段>、前置 results.<步骤>.<顶层结果字段> 和 context.projectId。以下是替换 submit 的配置片段,不是可单独运行的后端。

代码示例
submit:
  kind: operation
  label: 提交报销
  operation: example.expense.submit
  input:
    destination: {from: steps.itinerary.destination}
    amount: {from: steps.expenses.amount}
    note: {from: steps.expenses.note}
  recovery:
    operation: example.expense.lookupSubmission

11写入结果和恢复责任

写操作必须配置同插件的只读 recovery Operation。宿主在 InvocationContext.form 注入 submissionId 等表单身份;业务服务用它结合真实用户、租户和操作范围去重。requestId 不能代替 submissionId。未知结果先核实,不自动重发写入;恢复接口返回 succeeded 加 result、notExecuted 或 unknown。只有服务能证明没有执行且旧请求不会再产生副作用,才应返回 notExecuted。

实现业务 Operation

128. 验证你的 skill

导入并启用 skill 后,确认 forms_list 中出现模板;若缺失,检查根级代码块、引用路径和 YAML 校验错误。触发聊天,检查预填、必填校验和三步前后导航;确认前两步不会投递消息。提交后核对冻结 values、金额字符串和 submissionId;重启应用检查已保存记录。更新或停用 skill 后,旧实例和旧提交可能失效,应重新展示。只有本例的聊天路径通过,并不能证明业务服务器写入或任意模型行为已验证。

13编辑器和集合是另一种模板类型

本文的业务表单使用 amble-form 和 forms_* 工具。需要展示可选择的数据集合或编辑器时,使用对应的 UI 模板与 ui_* 工具;其 flow 回执和提交数据不同,不能互换。通用“补充信息”则使用独立的 input_* 工具,不参与本文的固定业务表单流程。

继续学习编辑器与集合

检查结果与排错

创建并导入一个三步业务表单,核对草稿、导航和冻结的提交数据。

按本页的验证步骤核对实际结果。涉及业务服务时,分别检查界面提交、工具回执与服务端记录。

打开错误代码与排错 →
SDK / CLI 0.1.0-alpha.9 · 接口基线 兼容性与预览说明 · 案例源码