data-edit
把用户的自然语言变成一次安全的 CRM 主对象记录更新。整条链路是一个串行的解析过程:
准备编辑表单 → 组装 object_data → 保存 → 返回结果
每一步都依赖上一步的真实返回值。这条 skill 的核心风险只有一个:在信息还没确定时就往下猜——猜错对象、改错记录、给只读字段回填值、编造关联记录 ID、把展示名当提交值写进枚举。编辑比新建更危险,因为它直接覆盖一条已经存在、用户正在用的真实数据,改错往往要事后才被发现。所以下面每一步的约束,本质都是在回答同一个问题:“我现在掌握的信息,足够让我安全地改下一步吗?” 信息不足时,宁可停下来问用户,也不要编造。
一个贯穿全程的原则:用户中途改了任何会影响结果的信息(对象、目标记录、字段值、关联记录),就从受影响的最早步骤重新走一遍,不要复用旧的表单上下文。 那些旧数据是针对旧输入算出来的,复用就等于拿过期的真相去覆盖一条真实记录。
不适用场景 / 路由排除
本 skill 只处理通用主对象字段编辑。进入流程前,核查当前业务对象是否存在与用户意图完全匹配的专属能力;有则直接走专属能力,不启用本能力。
专属操作路由表
以下操作有专属能力,不走本 skill:
| 操作 | 路由原则 |
|---|---|
| 客户/线索分配 | 走对应专属能力 |
| 客户/线索退回 | 走对应专属能力 |
| 客户/线索收回 | 走对应专属能力 |
| 客户/线索转移 | 走对应专属能力 |
| 客户/线索移除 | 走对应专属能力 |
| 客户/线索领取 | 走对应专属能力 |
| 线索无效 | 走线索专属能力 |
| 线索跟进 | 走线索专属能力 |
| 线索转换 | 走线索专属 skill |
从对象排除
本 skill 只改主对象字段。用户要求修改从对象、子对象、明细行或 details 时,停下来说明本能力只支持主对象字段编辑。
工作流总览
| 步骤 | 目的 | 走下一步的前提 |
|---|---|---|
| 0 路由核查 | 确认没有更合适的专属能力 | 当前请求属于主对象通用字段编辑 |
| 1 准备编辑表单 | 一步完成识别对象、定位唯一记录、获取编辑表单 | 已拿到唯一 object_api_name、唯一 data_id 和 form |
| 2 组装 object_data | 在原记录基础上构造修改后快照 | 命中对象有专属引用文件时已读;关联字段已解析到唯一 ID |
| 3 保存 | 写入系统 | object_data 已组装完成 |
| 4 返回结果 | 回传更新卡片 | — |
步骤 1:准备编辑表单
先拿到记录关键词和表单,再做任何其他事。 在拿到编辑表单前,不要去解析关联记录、不要查任何关联 ID、也不要凭空向用户罗列“能改哪些字段”。
这一步只需要两样输入:对象名 和 记录关键词。对象识别只接受对象类型名(如“客户 / 商机 / 联系人”);要定位的那条记录的名称、编号、标题或记录 ID 用来定位具体记录。不要把记录关键词或要改的字段值当成对象名。
| 用户输入 | 对象识别使用 | 记录定位使用 |
|---|---|---|
| 把客户大麦网的来源改成线上注册 | 客户 |
大麦网 |
| 修改联系人张三的电话 | 联系人 |
张三 |
- 缺记录关键词时,先问用户“要编辑哪一条记录”
- 一句话里识别不出明确对象类型词时,先问用户“要编辑哪一类对象”
- 用户要改的字段和新值留到步骤 2 再用
1.1 识别对象
对象 apiName 未明确时,调用对象识别工具:
{
"apiName": "IdentifyObjectWithDescribe",
"query": "<对象名称>",
"include_simple_describe": false
}
处理规则:
resolution_status = RESOLVED且仅 1 个候选:采用该object_api_nameresolution_status = AMBIGUOUS:把object_candidates交给用户确认resolution_status = NO_MATCH或无可用候选:请用户更换对象名称或确认该对象是否存在
对象 apiName 已明确时,直接跳过对象识别。
1.2 定位唯一记录
记录 ID 未明确时,调用按名称查询记录 ID 工具:
{
"apiName": "QueryRecordIdByName",
"query": "<记录关键词>",
"apiNames": ["<object_api_name>"]
}
处理规则:
- 命中 1 条:采用该记录
id - 命中多条:把候选交给用户确认;确认前不要继续
- 命中 0 条:请用户提供更准确的名称或编号
需要查看候选记录的更多字段来帮助用户判断时,再调用:
{
"apiName": "QueryRecordByName",
"name": "<记录关键词>",
"object_api_names": ["<object_api_name>"]
}
记录 ID 已明确时,直接跳过记录定位。
1.3 获取编辑表单
调用编辑表单工具:
{
"apiName": "getEditFormContext",
"object_api_name": "<object_api_name>",
"data_id": "<data_id>"
}
返回中的以下三部分是后续组装数据的唯一真相:
form_fieldsfield_metadataobject_data
同一对象 + 同一条记录、且尚未保存过,可复用上一份表单。 如果本轮对话里刚刚已经为某条记录拿到编辑表单,且还没对这条记录成功保存过,就直接复用上一次返回的 form。
关于业务类型:编辑沿用记录已有的 record_type,不主动选择。如 object_data 已含 record_type,原样保留;除非字段元数据和对象专属规则都明确允许、且用户明确要求,否则不新增、删除或改写它。
步骤 2:组装 object_data
以 form.object_data 为基础复制一份,再合并用户要求修改的字段。只认步骤 1 返回的这份表单,几条铁律:
- 保留未改动的一切。 保留
_id或数据主键,保留用户没要求改的原值。 - 只读字段是雷区。
form_fields中is_readonly=true的字段保留原值,绝不写入用户值、推断值或计算值。 - 必填以
is_required为准。 不删除已有必填字段值,除非用户明确要求清空且该字段允许为空。 - 选项字段只认提交值。
field_metadata里带options的字段,必须写合法 value 而非展示名;映射不唯一或找不到时先确认。 - 不碰从对象。 不构造、不修改、不提交
details,不修改从对象、子对象或明细行。 - 除接口或对象专属规则明确要求外,只写
form_fields中存在且非只读的字段。
2.1 对象专属逻辑(命中即先读)
有些对象有超出通用规则的特殊构造逻辑。组装前先按下表判断是否需要读引用文件:
目标对象 apiName |
必须先读的引用文件 |
|---|---|
ActiveRecordObj |
{Current agent directory}/skill/{skillApiName}/references/ActiveRecordObj.md |
命中时先读对应文件并应用其约束,再构造 object_data。引用文件里的特殊构造逻辑优先于通用规则;但可改字段、必填状态、枚举提交值仍以本次编辑表单返回为准。
2.2 关联对象字段(必须解析到唯一 ID)
关联记录的解析只在这一步做,前提是表单里确实存在这个关联字段。先在 form_fields / field_metadata 里确认该字段存在,并拿到真实 field_name 和关联对象 apiName。
当字段类型是 object_reference、master_detail、object_reference_many,或元数据表明该字段要关联已有记录时,必须先解析成唯一可提交的记录 ID 再写入。
解析路径:
- 用户直接给了符合字段要求的明确 ID:可直接用
- 用户给的是名称 / 编号 / 手机号 / 公司名 / 联系人名等文本:从该字段
field_metadata中读取关联对象 apiName,再调用按名称查询记录 ID 工具
{
"apiName": "QueryRecordIdByName",
"query": "<关键词>",
"apiNames": ["<关联对象apiName>"]
}
需要查看候选详情再让用户判断时,再调用:
{
"apiName": "QueryRecordByName",
"name": "<关键词>",
"object_api_names": ["<关联对象apiName>"]
}
处理规则:
- 查到 1 条:可用
- 查到多条:交给用户选择
- 查不到 / 无法判断:停下来,不要编造 ID 或默认选第一条
2.3 各字段类型的写法
| 字段类型 | 写法 | 示例 |
|---|---|---|
owner / employee / department / dimension |
按元数据要求用 ID 数组 | {"owner": ["1016"]} |
date |
日期字符串 yyyy-MM-dd |
"close_date": "2026-06-08" |
date_time |
日期时间字符串 yyyy-MM-dd HH:mm:ss |
"meeting_time": "2026-06-08 14:30:00" |
select_one |
元数据中的合法提交值 | "sales_stage": "1" |
select_many |
数组,元素为合法提交值 | "crm__c": ["Salesforce"] |
percentile |
提交值是百分号前的数值(可小数),不要换算成 0–1 比例 | "discount_rate": 90 |
rich_text |
使用纯文本内容,不要写入 HTML 标签或富文本源码 | "description": "客户希望下周二沟通方案" |
object_reference / master_detail |
唯一命中或用户确认后的记录 ID 字符串 | "account_id": "69e9a174..." |
object_reference_many |
唯一命中或用户确认后的记录 ID 数组 | "contact_ids": ["69e9a174..."] |
步骤 3:保存数据
object_data 组装完成后,直接调用更新工具。保存 payload 中不得包含 details。
{
"apiName": "UpdateRecordsByData",
"object_api_name": "<object_api_name>",
"object_data": {
"_id": "<data_id>",
"...": "..."
}
}
仅在确有需要时,才传入 missing_required_field_handling;默认沿用后端校验结果,不自行猜测补值。
步骤 4:返回结果
调用保存后,先判断接口返回,只有记录确实更新成功时才视为成功。
- 需要二次确认:把系统要求确认的内容如实转达给用户,等用户确认后再重新提交
- 用户明确拒绝本次更新:立即终止整个操作
- 权限 / 禁止执行 / 当前对象不支持:立即终止,不重试
- 保存失败 / 报错:把失败原因如实告诉用户;仅当错误明确指出某个可修正字段问题时,修正后至多重试一次