声明式业务表单:从 Skill 到多步交互
在 skill 中声明字段、步骤和提交方式,让宿主在聊天中渲染业务表单。本教程以三步差旅费用登记为例,说明配置范式、模型调用与提交后的数据流转。
完成后:创建并导入一个三步业务表单,核对草稿、导航和冻结的提交数据。
前置条件:准备一个自己的 skill 目录,按下文创建文件并导入应用。聊天提交示例无需插件 Demo、SDK 或业务服务器。
本页内容
01声明式表单的分工
开发者在 skill 中定义业务入口,在 YAML 中确定字段、校验、步骤和提交方式。Agent 负责发现并展示合适的模板;宿主负责渲染、保存草稿、校验及处理用户点击。用户确认后,数据按配置发送到聊天或交给业务 Operation。模型不自行决定这份业务表单需要哪些字段。
- 01开发者
Skill + YAML 定义规则
- 02Agent
发现并展示合适的模板
- 03宿主
渲染、校验、冻结提交
- 04你的服务
通过扩展实现业务处理
021. 创建你自己的 skill
下面从一个可独立导入的 skill 开始,示例不依赖插件 Demo 或业务服务器。创建这两个文件后,在应用的技能管理中导入 travel-expense 目录并启用。若随插件交付,在 extension.json 的 skills 数组中登记相对目录,例如 "skills": ["skills/travel-expense"]。
travel-expense/
SKILL.md
forms/
travel.yaml032. 在 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
```043. 定义完整的三步表单
将下面 YAML 保存为 forms/travel.yaml。本例依次收集行程、费用和确认信息。中间步骤省略 next,表示校验后直接前进;只有最后点击“发送申请信息”才向聊天发送。核对步骤使用说明和确认勾选框,不会自动生成前面字段的汇总视图。
亲手走一遍三步表单
浏览器教学演示:对应下方 YAML,使用内存中的示例数据。不会调用宿主或业务服务器,刷新即重置。
- 1行程
- 2费用
- 3核对
- id: itinerary
title: 行程
fields:
- name: destination
type: text
label: 目的地
required: true前两步仅更新草稿;最后确认后,才展示冻结数据示意。
展开完整 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: onSubmit05字段和步骤的配置规则
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.lookupSubmission11写入结果和恢复责任
写操作必须配置同插件的只读 recovery Operation。宿主在 InvocationContext.form 注入 submissionId 等表单身份;业务服务用它结合真实用户、租户和操作范围去重。requestId 不能代替 submissionId。未知结果先核实,不自动重发写入;恢复接口返回 succeeded 加 result、notExecuted 或 unknown。只有服务能证明没有执行且旧请求不会再产生副作用,才应返回 notExecuted。
实现业务 Operation128. 验证你的 skill
导入并启用 skill 后,确认 forms_list 中出现模板;若缺失,检查根级代码块、引用路径和 YAML 校验错误。触发聊天,检查预填、必填校验和三步前后导航;确认前两步不会投递消息。提交后核对冻结 values、金额字符串和 submissionId;重启应用检查已保存记录。更新或停用 skill 后,旧实例和旧提交可能失效,应重新展示。只有本例的聊天路径通过,并不能证明业务服务器写入或任意模型行为已验证。
13编辑器和集合是另一种模板类型
本文的业务表单使用 amble-form 和 forms_* 工具。需要展示可选择的数据集合或编辑器时,使用对应的 UI 模板与 ui_* 工具;其 flow 回执和提交数据不同,不能互换。通用“补充信息”则使用独立的 input_* 工具,不参与本文的固定业务表单流程。
继续学习编辑器与集合检查结果与排错
创建并导入一个三步业务表单,核对草稿、导航和冻结的提交数据。
按本页的验证步骤核对实际结果。涉及业务服务时,分别检查界面提交、工具回执与服务端记录。
打开错误代码与排错 →