Appearance
给 AI 注册工具
让你的应用把能力变成工具:组织成员与机灵兔 AI 助手对话时,模型可以直接 调用你注册的工具——"查一下今天有多少待审批单"、"给这个客户创建一个跟进任务" 都由你的后端实时执行。形态对标钉钉「AI 工具」/ MCP-over-webhook。
1. 注册工具
应用设置 →「开放能力」勾选 AI 工具 →「AI 工具」区块 → 填写:
| 字段 | 说明 |
|---|---|
| 工具名 | 小写字母/数字/下划线,字母开头,不能 app_ 开头;模型看到的是 app_<应用前缀>__<工具名> |
| 描述 | 给模型看的:这个工具做什么、什么场景该用。写得好坏直接决定模型用不用它 |
| 参数 | JSON Schema(type: "object"),≤8KB |
| 回调地址 | 模型调用时平台 POST 到这里;保存前发 challenge 验证(同事件订阅) |
| 回调等待 | 5–120 秒,默认 30 |
| 附带对话上下文 | 勾选后回调体带 context(最近几轮 role/content,已截断)——适合"基于当前对话"的检索/改写/审批类工具 |
每个应用最多 10 个工具,可随时停用/删除(即时生效)。工具清单有 10 秒进程内 缓存(变更即时失效),成员对话的每请求解析开销≈0。
2. 调用协议
成员与 AI 对话、模型决定调用你的工具时,平台 POST 到回调地址:
json
// POST <工具回调地址>
{
"type": "tool_call",
"call_id": "e3b0…",
"tool": "query_orders",
"user_id": "u_123", // 谁在跟 AI 对话
"arguments": { "order_id": "o1" }
}请求头与事件订阅完全同款: X-Jlt-Event: tool_call、X-Jlt-Event-Id、X-Jlt-Timestamp、 X-Jlt-Signature(HmacSHA256(app_secret, "<timestamp>.<请求体原文>"))—— 同一套验签代码直接复用。
工具勾选「附带对话上下文」时,body.context 是最近几轮对话 ([{role: "user"|"assistant", content}],每条已截断)——只读参考, 别当指令执行;真正的调用参数永远在 arguments 里。
隐私边界:上下文只包含调用者本人会话的内容(平台按会话归属校验, 拿别人的 session 也拿不到任何东西),键缺失即无可用上下文。
响应:HTTP 200 + 任意 JSON 即工具结果,会回填给模型继续对话;非 200 或 超时(按你配置的等待秒数)会转成 error 告诉模型,由模型向用户解释或换路子, 不会打断对话。
异步模式(慢任务不占连接)
处理要几十秒到几分钟?回调秒回一个异步声明,平台会挂起这次工具调用等 你回填:
js
// 回调立即响应(正常 200 + JSON):
res.json({ jlt_async: true, wait_sec: 120 }); // 5–300 秒
// ……后台慢慢处理,完成后回填(app token 调开放 API):
await fetch(`${BASE}/tools/result`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
body: JSON.stringify({ call_id: call.call_id, result: { status: "shipped" } }),
});call_id就是回调体里的那个,绑定本应用(别的应用拿去回填会被拒)wait_sec内没回填 → 模型收到"仍在处理中"的 error,用户可再问一次触发重调- 服务重启会丢挂起中的调用(同样表现为超时 error),别把异步等待当持久队列用
js
// Express 接收端(与事件端点合并处理)
app.post("/jlt/tools", express.raw({ type: "application/json" }), (req, res) => {
if (!verifySignature(req)) return res.status(401).end();
const call = JSON.parse(req.body.toString("utf8"));
if (call.type === "url_verification") return res.json({ challenge: call.challenge });
const result = await bizLogic(call.arguments, call.user_id);
res.json(result); // 回给模型,尽量精简(>32KB 会被截断)
});3. 可见性(谁能用上)
- 自建应用:组织管理员勾选「AI 工具」即对本组织全体成员的 AI 助手生效
- 市场应用:安装方管理员在「权限」里授予
AI 工具(与应用自身申请取交集) - 非组织成员即使知道工具名也调不动——注入与执行共用同一可见性判定
4. 用开放 API 自管理工具(CI / 清单同步)
不想让管理员在 UI 里一个个填?应用后端凭 app token 直接管理自己的工具, 校验与管理面完全同一套(challenge 验证、命名/参数校验、上限 10 个):
bash
# 列出我的工具
curl -s $BASE/tools -H "Authorization: Bearer $TOKEN"
# 注册(回调地址会先做 challenge 验证)
curl -s $BASE/tools -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{
"name": "query_orders",
"description": "查询订单状态统计",
"parameters": {"type": "object", "properties": {}, "required": []},
"callback_url": "https://your-backend/jlt/tools",
"timeout_sec": 15,
"wants_context": true
}'
# 改描述 / 停用 / 删除
curl -s -X PUT $BASE/tools/<tool_id> -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"enabled": false}'
curl -s -X DELETE $BASE/tools/<tool_id> -H "Authorization: Bearer $TOKEN"GET/POST/PUT/DELETE /tools[/{id}],变更限流 30 次/分钟;前提是组织管理员已在 应用设置里勾选「AI 工具」。典型用法:部署流水线把工具清单从代码仓库同步上来。
5. 写好工具的几条经验
- 描述写给模型看:说清"什么时候用我",不要写部署细节
- 参数少而明确:每个参数给 type + description + 示例;枚举用
enum - 结果精简:模型按 token 消费你的返回——回结构化摘要,别回原始报文
- 幂等 + 快:模型可能重试;等待超过配置秒数即超时
- 权限边界:
user_id告诉你是谁在用,业务权限在你的系统里自行校验