设备发现
fsp/discover 只返回设备级最小元数据,不返回完整技能 Schema。
请求
{
"jsonrpc": "2.0",
"id": "discover-1",
"method": "fsp/discover",
"params": {}
}
响应
{
"jsonrpc": "2.0",
"id": "discover-1",
"result": {
"result_type": "complete",
"value": {
"devices": [
{
"device_id": "lab.device-01",
"name": "示例设备",
"description": "提供容器处理和状态读取技能。",
"capability_revision": "rev-20260902-02",
"available": true
}
]
},
"diagnostics": []
}
}
| 字段 | 类型 | 是否必需 | 范围与含义 |
|---|---|---|---|
devices | array[object] | 是 | 当前 FSP 服务管理的设备;没有设备时返回 [] |
devices[].device_id | string | 是 | 长度 1..128;稳定设备标识 |
devices[].name | string | 是 | 长度 1..128;设备显示名称 |
devices[].description | string | 是 | 长度 0..1024;说明设备用途,供调用方判断是否继续读取技能摘要 |
devices[].capability_revision | string | 是 | 长度 1..128;当前技能定义修订号 |
devices[].available | boolean | 是 | 表示设备当前是否可接收后续请求,不替代完整系统条件检查 |
device_id,不得使用显示名称定位设备。
渐进式披露
FSP 把技能信息分为三个读取层级:| 层级 | 接口 | 返回内容 | 使用时机 |
|---|---|---|---|
| 设备元数据 | fsp/discover | 设备身份、简介、修订号和可用性 | 建立设备候选集合 |
| 技能摘要 | fsp/get_capabilities,detail_level=summary | 技能标识、名称、说明、请求分类、执行模式和对象摘要 | 检索与选择技能 |
| 技能详情 | fsp/get_capabilities,detail_level=full | 所选技能的对象、控制、系统三个完整维度 | 校验并构造实际请求 |
write 或 invoke 类技能前,调用方必须取得对应完整详情;调用 read 类技能时也必须按完整详情校验输入参数。
获取技能定义
请求
{
"jsonrpc": "2.0",
"id": "capability-1",
"method": "fsp/get_capabilities",
"params": {
"device_id": "lab.device-01",
"detail_level": "full",
"command_ids": ["dispense"],
"if_revision": "rev-20260902-01"
}
}
| 参数 | 类型 | 是否必需 | 范围与约束 | 作用 |
|---|---|---|---|---|
device_id | string | 是 | 长度 1..128;必须来自当前服务的发现结果 | 指定设备 |
detail_level | string | 否 | summary 或 full;默认 summary | 指定披露级别 |
command_ids | array[string] | 否 | 仅适用于 full;元素数量 1..100,元素唯一且每项长度 1..128 | 只读取指定技能详情;省略时返回全部技能详情 |
if_revision | string | 否 | 长度 1..128;必须是调用方已经完整缓存的同级结果修订号 | 条件读取 |
params 不得携带未声明字段。detail_level=summary 时不得携带 command_ids。未知 command_id 必须返回错误,不得静默忽略。
技能摘要响应
{
"jsonrpc": "2.0",
"id": "capability-summary-1",
"result": {
"result_type": "complete",
"value": {
"device": {
"device_id": "lab.device-01",
"name": "示例设备",
"description": "提供容器处理和状态读取技能。"
},
"revision": "rev-20260902-02",
"detail_level": "summary",
"ttl_ms": 300000,
"cache_scope": "service",
"skills": [
{
"command_id": "read_device_state",
"name": "读取设备状态",
"description": "读取设备当前状态和观测时间。",
"request_class": "read",
"execution_mode": "sync",
"object_summary": "设备整体状态"
},
{
"command_id": "dispense",
"name": "加液",
"description": "向满足条件的目标容器加入指定体积液体。",
"request_class": "invoke",
"execution_mode": "async",
"object_summary": "已声明兼容类型的目标容器"
}
]
},
"diagnostics": []
}
}
request_class。调用方据此判断后续需要采用的安全校验级别。
技能详情响应
对象、控制和系统是同一项技能的三个说明维度,不是三组独立能力或三套设备接口。{
"jsonrpc": "2.0",
"id": "capability-1",
"result": {
"result_type": "complete",
"value": {
"device": {
"device_id": "lab.device-01",
"name": "示例设备",
"description": "提供容器处理和状态读取技能。"
},
"revision": "rev-20260902-02",
"detail_level": "full",
"ttl_ms": 300000,
"cache_scope": "service",
"skills": [
{
"command_id": "dispense",
"name": "加液",
"description": "向满足条件的目标容器加入指定体积液体。",
"request_class": "invoke",
"execution_mode": "async",
"object": {
"role": "target_container",
"description": "承接液体并保存执行后样品状态的目标容器。",
"container_types": [
{
"container_type_id": "container.vial.example",
"name": "示例进样瓶",
"properties": {
"shape": "cylindrical",
"height_mm": 75,
"outer_diameter_mm": 22.4,
"material": "glass",
"nominal_volume_mL": 2.0,
"max_working_volume_mL": 1.8
},
"required_states": {
"container_status": ["无盖"],
"sample_status": ["空", "液体"]
}
}
]
},
"control": {
"preconditions": [
"目标容器存在且类型兼容",
"目标容器处于无盖状态"
],
"parameters": [
{
"name": "target_container_id",
"type": "string",
"required": true,
"description": "目标容器实例标识",
"constraints": ["length 1..128"]
},
{
"name": "source_container_id",
"type": "string",
"required": true,
"description": "来源容器实例标识",
"constraints": ["length 1..128"]
},
{
"name": "volume",
"type": "object",
"required": true,
"description": "加液体积",
"children": [
{"name": "value", "type": "number", "required": true, "exclusive_minimum": 0, "maximum": 1.0},
{"name": "unit", "type": "enum", "required": true, "allowed_values": ["mL"]}
]
}
],
"input_schema": {
"type": "object",
"properties": {
"target_container_id": {"type": "string", "minLength": 1, "maxLength": 128},
"source_container_id": {"type": "string", "minLength": 1, "maxLength": 128},
"volume": {
"type": "object",
"properties": {
"value": {"type": "number", "exclusiveMinimum": 0, "maximum": 1.0},
"unit": {"type": "string", "enum": ["mL"]}
},
"required": ["value", "unit"],
"additionalProperties": false
}
},
"required": ["target_container_id", "source_container_id", "volume"],
"additionalProperties": false
},
"constraints": [
"volume.value <= target.max_working_volume - target.sample_volume"
],
"effects": {
"sample_status": {"空": "液体", "液体": "液体"}
},
"returns": [
{"name": "task_id", "type": "string", "required": true},
{"name": "status", "type": "enum", "required": true, "allowed_values": ["queued", "running", "completed", "failed", "cancelled"]}
],
"output_schema": {
"type": "object",
"properties": {
"task_id": {"type": "string", "minLength": 1, "maxLength": 128},
"status": {"type": "string", "enum": ["queued", "running", "completed", "failed", "cancelled"]}
},
"required": ["task_id", "status"],
"additionalProperties": false
}
},
"system": {
"required_device_states": ["idle"],
"forbidden_device_states": ["fault", "maintenance", "offline"],
"safety_fences": [
"目标容器剩余容量必须大于或等于加液体积"
],
"result_verification": [
"任务必须进入 completed 状态",
"返回实际加液体积和目标容器执行后状态",
"提交对象状态时必须产生新的状态修订号"
]
}
}
]
},
"diagnostics": []
}
}
响应字段
| 字段 | 类型 | 是否必需 | 范围与含义 |
|---|---|---|---|
device | object | 是 | 设备标识、名称和总体说明 |
revision | string | 是 | 长度 1..128;本次技能定义修订号 |
detail_level | string | 是 | 与请求一致,为 summary 或 full |
ttl_ms | integer | 是 | 0..86400000;0 表示不可缓存 |
cache_scope | string | 是 | none 或 service |
skills | array[object] | 是 | 当前披露范围内的技能;无匹配项时返回 [] |
diagnostics | array[object] | 是 | 非阻断提示;没有内容时返回 [] |
摘要条目
| 字段 | 类型 | 是否必需 | 范围与约束 |
|---|---|---|---|
command_id | string | 是 | 长度 1..128;仅允许 ASCII 字母、数字、_、-、.;同一设备内唯一 |
name | string | 是 | 长度 1..128 |
description | string | 是 | 长度 1..1024;同时说明技能用途和适用时机 |
request_class | string | 是 | read、write 或 invoke |
execution_mode | string | 是 | sync 或 async |
object_summary | string | 是 | 长度 0..512;概括作用对象或读取范围 |
完整条目
完整技能在摘要字段基础上必须增加以下三个维度:| 维度 | 必需内容 |
|---|---|
object | 对象角色、容器类型、形状、尺寸、材质、容积和允许状态;未知物理值使用 null |
control | 前置条件、参数展开定义、input_schema、跨字段约束、状态变化、返回展开定义和 output_schema |
system | 必需设备状态、禁止状态、安全围栏和结果验证规则 |
control.parameters 必须与 control.input_schema 表达同一组参数;control.returns 必须与 control.output_schema 表达同一组输出。两个 Schema 必须符合 JSON Schema 2020-12。Schema 不能表达的跨字段、对象状态和物理约束必须写入 preconditions、constraints 或 safety_fences。
分类约束
| 请求分类 | 完整技能必须声明 | 执行要求 |
|---|---|---|
read | 读取范围、输入参数、输出 Schema、观测时间和新鲜度语义 | 不得改变设备或对象状态;设备在线且数据源可用时通常允许调用 |
write | 可写字段、目标值范围、预期修订号、写入后验证规则 | 写前校验字段与修订号;写后回读或取得等价确认;验证失败不得报告成功 |
invoke | 对象条件、设备状态、全部前置条件、安全围栏、状态变化和结果验证 | 请求进入设备前必须完成强制检查;完成后必须用实际状态或证据验证结果 |
条件读取
if_revision 只适用于调用方已经完整缓存的相同披露级别和相同 command_ids 集合。修订号相同时,服务端返回:
{
"jsonrpc": "2.0",
"id": "capability-1",
"result": {
"result_type": "not_modified",
"value": {
"revision": "rev-20260902-02",
"detail_level": "full",
"ttl_ms": 300000,
"cache_scope": "service"
},
"diagnostics": []
}
}
if_revision。if_revision 不匹配不是错误,服务端必须返回当前结果。
错误响应
{
"jsonrpc": "2.0",
"id": "capability-1",
"error": {
"code": -32004,
"message": "技能不存在",
"data": {
"diagnostics": [
{
"code": "command_not_found",
"path": "params.command_ids[0]",
"message": "目标设备未声明该技能"
}
]
}
}
}
| 诊断代码 | 触发条件 | 服务端行为 |
|---|---|---|
invalid_request | 缺少必需参数、类型错误、未知参数或参数组合无效 | 返回协议错误,不返回技能数据 |
device_not_found | 当前服务没有对应 device_id | 返回协议错误 |
command_not_found | command_ids 包含设备未声明的技能 | 返回协议错误,不忽略未知项 |
invalid_revision | if_revision 格式错误或缓存条件不完整 | 返回协议错误 |
capability_unavailable | 暂时无法生成一致的技能定义 | 返回协议错误,不返回部分详情 |
修订规则
以下变化必须产生新的能力修订号:- 新增、删除或修改技能;
- 修改技能的对象、控制或系统任一维度;
- 修改请求分类、参数、返回值、前置条件、安全围栏或验证规则;
- 修改会影响调用方行为的适配映射。