宿主 LLM 服务(指定智能体代答)
宿主后端原来若直接调大模型,可改为:由 Cadau 里 指定的工作智能体 代为回答。用户不必登录 Cadau,也不必打开页面挂件。
来源 sdk/host-embed/宿主LLM服务.md
宿主后端原来若直接调大模型,可改为:由 Cadau 里 指定的工作智能体 代为回答。用户不必登录 Cadau,也不必打开页面挂件。
本期:整套宿主共用 一个 Cadau 工作区(见
宿主增强-AgentRun与数据权限.md§0.3)。对照实现:
examples/hr-multi-tenant的POST …/me/agent-run(问答)与POST …/positions/suggest-for-org(编制建议)。
1. 和页面挂件有什么不同
| 页面助手(嵌入挂件) | 宿主 LLM 服务(本文) | |
|---|---|---|
| 谁发起 | 浏览器里的挂件 | 宿主服务端 |
| 用户看见什么 | 右下角对话浮层 | 由你决定(审批摘要、机器人接口、批处理……用户可以完全看不见 Cadau) |
| 用哪条智能体 | 按登录用户 分配 的那条 | 服务端指定:日常问答可用同一套分配;生成/分析用 任务型智能体(§5.1),不要占用页面助手 |
| 当前是谁 | host_actor 传给挂件 | 请求体带同一套 host_actor |
| 对话落在哪 | 嵌入会话 | 同一类嵌入会话(按登录用户隔离) |
两种路径 共用 智能体知识、数据连接策略与「当前是谁」。不要页面一套权限、服务端另一套。
不要把本文接口暴露给浏览器;页面对话继续走挂件。集成账号密码只放宿主服务端。
2. 调用链(用户视角)
sequenceDiagram participant App as 宿主业务(服务端) participant BFF as 宿主对接层 participant ML as Cadau participant Agent as 指定工作智能体 App->>BFF: 已登录用户要一句回答 BFF->>BFF: 查该用户分配的智能体 + 组装当前用户身份 BFF->>ML: 集成账号登录并进入工作区 BFF->>ML: 请这条智能体代答(消息 + 当前用户身份) ML->>Agent: 按知识、工具、数据策略作答 Agent-->>ML: 回复 ML-->>BFF: 回复 + 会话编号 BFF-->>App: 你的业务接口原样返回
智能体由 宿主管理员分配,终端用户不挑选「用哪条模型」。
3. Cadau 侧要准备什么
与 B 路径嵌入相同,不必另开一套账号:
- 工作区 + 模板智能体(知识已挂)
- 集成账号 已加入该工作区(不必拥有该智能体)
- (若要查业务库)工作区 数据连接 与访问策略已写入
详见 宿主增强-AgentRun与数据权限.md §1。
4. 对接:Cadau 接口
仅宿主服务端调用。鉴权用 集成账号 登录后的访问令牌(先 login,再按需 switch 工作区)。
POST /api/v1/host/agent-runs
Authorization: Bearer <集成账号访问令牌>
Content-Type: application/json
{
"user_agent_id": "<智能体 UUID>",
"app_id": "your-app-id",
"workspace_id": "<工作区 UUID,可省略则用令牌当前工作区>",
"message": "本月我的职级是什么?",
"session_id": "",
"stream": false,
"fresh": false,
"host_actor": {
"external_user_id": "宿主用户编号",
"actor_kind": "employee",
"display_name": "陈晨",
"tenant_external_id": "宿主租户编号",
"employee_id": "员工档案编号",
"roles": ["employee"]
}
}
4.1 请求字段
| 字段 | 必填 | 说明 |
|---|---|---|
user_agent_id | 是 | 代答的那条工作智能体,须在该工作区内 |
message | 是 | 用户问题或任务说明 |
host_actor | 是 | 当前宿主登录用户。actor_kind 为 employee 时 必须 有 employee_id |
app_id | 否 | 缺省 mindlink-embed;与嵌入登记一致便于会话归并 |
workspace_id | 否 | 缺省用集成账号当前工作区;本期与 MINDLINK_WORKSPACE_ID 相同 |
session_id | 否 | 续聊时传入上次返回的编号;空则默认接上该用户在此智能体下最近一条,没有则新建 |
fresh | 否 | 为 true 且未带 session_id 时 总是新建会话(适合「按部门生成岗位」这类一次性任务,避免部门 A 的上下文接到部门 B) |
stream | 否 | 见 §4.3 |
4.2 非流式响应(stream 为 false 或省略)
{
"session_id": "…",
"request_id": "…",
"reply": "助手全文",
"message_id": "…",
"user_agent_id": "…",
"workspace_id": "…",
"app_id": "…",
"host_actor": { }
}
| 字段 | 说明 |
|---|---|
reply | 给业务侧展示或落库的完整回答 |
session_id | 下次续聊带上,同一登录用户不会串到别人 |
request_id | 本轮追踪号 |
失败时常见:unauthorized(未登录)、forbidden_embed_token(误用嵌入令牌)、validation_error(缺消息 / 缺智能体 / 身份无效)、workspace_required、not_found(智能体不在该工作区)、host_agent_run_failed(作答失败)。
4.3 关于 stream: true
接口接受该字段,但 不是 页面挂件那种边生成边吐字:服务端仍一次跑完,再按 SSE 依次发出 session、delta(整段回复)、done。
HR 范例对接层 固定按非流式 取整段 reply。需要真流式时,用页面挂件的对话通道。
5. 宿主侧建议怎么包一层
不要让每个业务模块自己拿集成账号调 Cadau。做成「当前登录用户的一句问答」:
- 校验宿主登录与权限
- 查该用户已分配的智能体(未分配则明确失败,勿默默换一条)
- 组装与嵌入会话相同的 当前用户身份
- 集成账号进入工作区后调用上一节接口
- 把
reply/session_id返回给业务
HR 范例:
- 日常问答:
POST /api/v1/tenants/{租户}/me/agent-run(用该用户已分配的对话助手) - 任务型生成:
POST /api/v1/tenants/{租户}/positions/suggest-for-org(调用 已指定的生成/分析智能体) - 指定方式:服务端
.env的MINDLINK_GENERATE_USER_AGENT_ID,或宿主「用户管理 → 嵌入助手登记」 - 客户端:
examples/hr-multi-tenant/server/internal/mindlinkclient/的代调 - 验收:
examples/hr-multi-tenant/web目录npm run smoke:host-agent(问答链路);岗位建议在「岗位与职级」页手工验收
5.1 对话助手 vs 生成/分析智能体
页面挂件用的是 对话助手(管理员 / 主管 / 员工自助):给人聊天、可开人工客服。 生成、分析、填表 由宿主服务端调用 另一条指定的智能体(可与对话助手不同,也可复用已有助手)。
先在 Cadau 创建并配置好(知识、数据连接等),再在宿主 指定 它。不要靠脚本偷偷建一条。指定位置只有这两处,分析调用都走这里:
- 服务端
.env:MINDLINK_GENERATE_USER_AGENT_ID=<Cadau 智能体 UUID>(部署默认) - 宿主设置:「用户管理 → 嵌入助手登记 → 生成与分析用智能体」(保存后覆盖环境变量)
不要和 HRMS_SEED_MINDLINK_USER_AGENT_ID 搞混:后者只是 HR 范例启动时给演示账号补登记/分配,不是生成/分析用的智能体。
| 对话助手 | 生成 / 分析 | |
|---|---|---|
| 谁用 | 登录用户在页面里问 | 宿主某个按钮 / 批处理 |
| 指定 | 按用户分配 | .env 或宿主设置 一条 |
| 应用标识 | 挂件 MINDLINK_APP_ID | 默认 mindlink-embed-hr-generate(会话不和聊天混在一起;HR 范例可用 MINDLINK_GENERATE_APP_ID 覆盖,不必写入 .env) |
| 会话 | 默认可续聊 | 每次任务传 fresh: true |
| 落库 | 助手只回答 | 宿主先 预览,由人确认后再写业务表 |
HR 范例:选定部门 → 建议该部门应有哪些岗位(「岗位与职级」页)。结果只展示,不自动写入岗位库。
6. 会话与隔离
- 会话记在 Cadau,归属 集成账号,并打上当前宿主用户编号。
- 同一智能体下,用户甲与用户乙的代答历史 互不续接。
- 续聊:把上次的
session_id传回;若会话已属于另一用户,接口拒绝。 - 不传
session_id时:默认使用该用户在「同一工作区 + 同一智能体 + 同一应用标识」下最近一条;没有则新建。 - 一次性生成任务:传
fresh: true(且不要带session_id),每次新建,避免上一部门的建议污染这一次。
页面挂件里的对话与代答会话都按同一套用户编号隔离,但 不是 强制合成一条时间线。要「页面里接着服务端刚问的」需自行约定是否共用 session_id(一般两套入口分开即可)。
7. 智能体实际会做什么
代答走该智能体的知识、技能与数据连接,与页面里问同一助手相同:
- 系统会带上「当前是哪位宿主用户」(姓名、角色、员工档案等),避免再向用户索要工号来「确认身份」
- 查业务库必须走数据连接;行/字段由访问策略强制,模型去不掉
- 员工自助只能协助查本人(策略 + 身份提示共同约束)
策略写法见 宿主增强-AgentRun与数据权限.md §3。
8. 联调清单
- [ ] 集成账号能登录并进入智能体所在工作区
- [ ] 指定的智能体 ID 确在该工作区
- [ ] 请求带完整当前用户身份;员工自助含员工档案编号
- [ ] 未分配助手的用户:宿主接口明确失败,而不是随便找一条智能体
- [ ] 两名登录用户先后代答,
session_id不同、内容不串 - [ ] 同一用户第二次带上
session_id(或不带、走自动接续)能续上 - [ ] 任务型调用使用独立智能体 + 独立
app_id+fresh: true;结果先预览再落库 - [ ] (可选)
npm run smoke:host-agent通过 - [ ] 集成密码未出现在前端或公开仓库
9. 常见问题
| 现象 | 排查 |
|---|---|
| 无权 / 智能体不存在 | 集成账号未进工作区;智能体 ID 与工作区不一致;未 switch |
| 请提供有效的宿主用户身份 | 缺 host_actor 或 external_user_id;员工未带 employee_id |
| 员工用户须绑定员工档案 | 自助账号尚未绑本租户人员档案 |
| 调用助手失败 / 大模型未配置 | Cadau 侧模型未就绪 |
| 答出了不该看的行或列 | 数据连接访问策略未写入或未按当前用户身份收窄 |
| 浏览器直接调本接口 | 不要;页面走挂件,代答只走宿主服务端 |
10. 维护信息
| 项 | 值 |
|---|---|
| 文档类型 | 宿主服务端 LLM 代答对接说明 |
| Cadau 接口 | POST /api/v1/host/agent-runs |
| 参考范例 | examples/hr-multi-tenant → POST …/me/agent-run;生成/分析见 POST …/positions/suggest-for-org(智能体由 .env / 宿主设置指定) |
| 相关 | 宿主增强-AgentRun与数据权限.md、参考范例-HR接入指南.md、SDK契约.md V1.5.12 |