先确认这 4 件事
- 一个可用的 softwareId / tenantId / userId 约定
- 一条真实业务页面 route,例如 /orders/list
- 一个最小 Token,至少能区分角色和租户
- 一个试点模块,不要一开始就覆盖全系统
Checklist
question、softwareId、tenantId、userId、route。少这几项,智引只能退化成普通问答。
pageTitle、selectedMenu、platform、module。这样回答会明显更贴当前页面。
pageId、recordId、workflowNode、errors、formState。
availableActions 和 executor context,让宿主前端按白名单执行跳转、追问、聚焦、打开弹窗。
10 Minutes
curl -X POST https://ziin.shenliu.cc/api/ziin/query \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer editor|softwareId:erp-suite|tenantId:tenant-east-cn|userId:u-1001' \
-d '{
"question": "订单管理在哪里?",
"mode": "ui-assistant",
"module": "orders",
"context": {
"route": "/workbench/overview",
"pageTitle": "经营总览",
"selectedMenu": "工作台 / 经营总览",
"platform": "web"
}
}'/embed 不是另一个介绍页,而是当前最短的“结构化 Agent 验收页”。如果这里的intent、taskState、nextAction、cards 和宿主执行日志都能成立, 客户就更容易理解后续为什么要补 availableActions 和 executor context。
Web ESM
import {
createHostRuntimeAdapter,
createActionPlanExecutor,
createZiinWidget,
} from "https://ziin.shenliu.cc/sdk/js/index.js";
const runtimeAdapter = createHostRuntimeAdapter({
adapterConfig: {
clientConfig: {
baseUrl: "https://ziin.shenliu.cc",
token: "editor|softwareId:erp-suite|tenantId:tenant-east-cn|userId:u-1001",
},
defaults: {
mode: "ui-assistant",
module: "orders",
softwareId: "erp-suite",
tenantId: "tenant-east-cn",
userId: "u-1001",
},
},
getContext: () => ({
route: window.location.pathname,
pageTitle: document.title,
selectedMenu: readSelectedMenu(),
platform: "web",
pageId: readStablePageId(),
availableActions: ["navigate", "focus_field", "scroll_to", "open_dialog"],
}),
});
const widget = createZiinWidget({
runtimeAdapter,
actionExecutor: createActionPlanExecutor({
allowActions: ["navigate", "focus_field", "scroll_to", "open_dialog"],
handlers: {
navigate: (plan) => router.push(plan.payload?.route || plan.route || "/"),
focusField: (plan) =>
focusHostField(plan.payload && "target" in plan.payload ? plan.payload.target || "" : plan.target || ""),
scrollTo: (plan) =>
document
.querySelector(plan.payload && "target" in plan.payload ? plan.payload.target || "" : plan.target || "")
?.scrollIntoView({ behavior: "smooth", block: "center" }),
openDialog: (plan) =>
openDialog(plan.payload && "dialogId" in plan.payload ? plan.payload.dialogId : plan.target),
},
}),
title: "智引操作内核",
subtitle: "权限感知式操作指引",
buttonLabel: "打开使用助手",
contextLabel: "当前页面",
defaultOpen: true,
});
await widget.refreshContext();动作协议现在优先消费 payload: - assistant nextAction 是任务推进动作,例如 ask_followup、goto_module、create_order_draft - SDK actionPlans 是宿主页面动作计划,例如 navigate、scroll_to、focus_field、open_dialog - 两层动作都必须由宿主白名单 executor 执行 - 不要从 answer 文本里反推动作 - navigate.payload.route - scroll_to.payload.target - focus_field.payload.target / fieldKey - open_dialog.payload.dialogId 老字段 route / target / fieldKey 仍兼容,但不建议新宿主继续只按旧字段接。
{
"intent": "ship_create",
"taskState": "ship_drafting",
"riskLevel": "draft",
"nextAction": {
"type": "create_order_draft",
"payload": {
"destinationCity": "成都",
"cargoName": "日用品",
"weight": "300公斤"
}
},
"followups": ["直接帮我生成草稿", "我只是先咨询"],
"cards": [
{
"type": "draft",
"title": "订单草稿建议",
"data": {
"destinationCity": "成都",
"cargoName": "日用品",
"weight": "300公斤"
}
}
]
}executeFloatingAssistantNextAction({
action: result.nextAction,
response: { answer: result.answer },
context: {
routerPush: (route) => router.push(route),
setQuestion,
setTextMode,
setStatus,
focusInput: () => inputRef.current?.focus(),
submitQuestion: (question) => query(question),
},
});Validation
用你们系统真实页面、真实菜单、真实角色去问,不要只在空白 demo 页里测。
用你们系统真实页面、真实菜单、真实角色去问,不要只在空白 demo 页里测。
用你们系统真实页面、真实菜单、真实角色去问,不要只在空白 demo 页里测。
用你们系统真实页面、真实菜单、真实角色去问,不要只在空白 demo 页里测。
Boundary