# Chat SDK 第三方系统集成指南 > 本文档说明第三方系统如何接入 AI 智能客服的 Chat SDK,完成从创建 API Key 到嵌入对话组件的全流程。 --- ## 目录 1. [集成架构总览](#1-集成架构总览) 2. [第一步:创建 API Key](#2-第一步创建-api-key) 3. [第二步:绑定客服角色(可选)](#3-第二步绑定客服角色可选) 4. [第三步:后端换取 SDK Token](#4-第三步后端换取-sdk-token) 5. [第四步:前端嵌入 Chat SDK](#5-第四步前端嵌入-chat-sdk) - [5.5 角色切换](#55-角色切换) 6. [API 接口参考](#6-api-接口参考) 7. [SDK 配置参数参考](#7-sdk-配置参数参考) 8. [错误码与排查](#8-错误码与排查) 9. [安全建议](#9-安全建议) --- ## 1. 集成架构总览 ``` ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ 第三方前端 │ │ 第三方后端 │ │ AI 客服后端 │ │ (嵌入 SDK) │ │ (你的服务) │ │ (本系统) │ │ │ │ │ │ │ │ Chat SDK ──────┼─────┼──────────────────┼─────┼─► /ai/** 对话 │ │ ↑ token │ │ │ │ │ │ │ │ ① 携带 API Key │ │ ② 返回 JWT Token│ │ │ │ POST /open-api/ │─────┼─► /auth/token │ │ │ │ auth/token │ │ │ └─────────────────┘ └──────────────────┘ └──────────────────┘ ``` **两段式鉴权流程:** 1. **管理后台**:管理员创建 API Key,可选绑定客服角色 2. **第三方后端**:用 API Key 换取短期 JWT Token + 可用角色列表 3. **第三方前端**:Chat SDK 携带 JWT Token 请求 `/ai/**` 接口进行对话 --- ## 2. 第一步:创建 API Key 在管理后台「系统设置 → API Key 管理」页面创建。 ### 管理后台操作 1. 登录管理后台 `http://localhost:9090/index.html` 2. 进入「系统设置 → API Key 管理」 3. 点击「+ 新建 API Key」 4. 填写名称、描述、频率限制等参数 5. **(可选)** 在创建弹窗中勾选需要绑定的客服角色 6. 创建后**立即复制保存 Key**,关闭后无法再次查看 ### API Key 格式 ``` sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(sk_ 前缀 + 32 位 UUID) ``` --- ## 3. 第二步:绑定客服角色(可选) 客服角色决定 AI 的人设、知识库范围和 MCP 工具权限。 ### 角色绑定规则 | role_ids 状态 | Token 换取行为 | |---|---| | 空数组 `[]`(默认) | 返回**所有**启用的客服角色(向后兼容) | | 非空 `[1, 2, 3]` | 仅返回绑定的角色 | ### 通过管理后台绑定 在 API Key 列表中点击「绑定角色」按钮,勾选需要的角色后保存。 ### 通过 API 绑定 ```bash PUT /api-key/{keyId}/roles Content-Type: application/json Authorization: Bearer {管理后台 JWT Token} { "roleIds": [1, 2, 3] } ``` 响应: ```json { "success": true, "message": "角色绑定更新成功" } ``` --- ## 4. 第三步:后端换取 SDK Token **⚠️ 重要:Token 换取必须在第三方后端完成,不可在前端暴露 API Key。** ### 请求 ```bash POST /open-api/auth/token Content-Type: application/json X-API-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx { "ttl": 7200 } ``` | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `X-API-Key` | Header | 是 | 创建的 API Key | | `ttl` | Body | 否 | Token 有效期(秒),默认 7200(2 小时),范围 [300, 86400] | ### 成功响应 ```json { "success": true, "token": "eyJhbGciOiJIUzI1NiJ9...", "expiresIn": 7200, "roles": [ { "id": "1", "key": "general", "name": "通用客服" }, { "id": "2", "key": "finance", "name": "财务顾问" } ] } ``` | 字段 | 说明 | |---|---| | `token` | SDK JWT Token,传给前端使用 | | `expiresIn` | 过期时间(秒) | | `roles` | 可用客服角色列表,前端用于展示角色选择器 | ### 错误响应 | HTTP 状态码 | 说明 | |---|---| | 401 | API Key 无效或已禁用 | | 403 | 无可用客服角色 | --- ## 5. 第四步:前端嵌入 Chat SDK ### 使用测试面板快速验证 访问 `http://localhost:9090/sdk/test.html` 打开测试面板: 1. 在「🔐 SDK Token 鉴权」区域输入 API Key 2. 点击「获取 Token」按钮自动换取(或手动粘贴已有的 Token) 3. Token 获取成功后,integrateId 会自动填充为第一个可用角色 4. 点击「🚀 初始化 SDK」即可测试对话功能 测试面板支持所有 P0/P1/P2 测试用例的自动化运行,包括 API 连通性验证。 ### 5.1 引入 SDK ```html ``` ### 5.2 初始化 ```javascript const chatbot = ChatbotSDK.init({ // ========== 必填参数 ========== integrateId: '1', // 客服角色 ID(从 Token 换取接口的 roles 中选择) requestDomain: 'https://your-domain.com', // AI 客服后端域名 // ========== 鉴权参数(推荐) ========== token: 'eyJhbGciOiJIUzI1NiJ9...', // 后端换取的 SDK Token roles: [ // 可用角色列表(传多个时 SDK header 显示角色切换下拉框) { id: '1', key: 'general', name: '通用客服' }, { id: '2', key: 'finance', name: '财务顾问' } ], // ========== 可选参数 ========== userId: 'user_12345', // 用户标识(用于会话隔离) title: 'AI 智能助手', // 对话窗口标题 theme: 'light', // 主题:light / dark primaryColor: '#4F46E5', // 主题色(十六进制) streaming: true, // 启用流式回复(默认 true) enableRag: true, // 启用 RAG 知识库检索(默认 true) quickReplies: ['如何退款?', '联系人工客服'], // 快捷问题 position: 'right-bottom', // 悬浮按钮位置:right-bottom / left-bottom width: 380, // 窗口宽度(px) height: 520, // 窗口高度(px) debug: true, // 控制台调试日志 // ========== 回调函数 ========== onReady: function() { console.log('SDK 就绪'); }, onMessage: function(msg) { console.log('收到消息', msg); }, onError: function(err) { console.error('SDK 错误', err); } }); ``` ### 5.3 SDK 方法 ```javascript // 销毁实例(移除 DOM 和事件监听) chatbot.destroy(); ``` ### 5.4 不使用 Token 的兼容模式 如果暂时不接入后端 Token 换取,可直接使用兼容模式(**不推荐用于生产环境**): ```javascript ChatbotSDK.init({ integrateId: '1', // 直接指定角色 ID requestDomain: 'https://your-domain.com' // 不传 token 和 roles }); ``` 兼容模式下,`integrateId` 直接作为 `roleId` 传递给后端,无需 Token 换取步骤。由于不传 `roles`,SDK 不会显示角色选择器,用户只能使用初始指定的单一角色。 ### 5.5 角色切换 当 `roles` 数组长度 > 1 时,SDK 会在聊天窗口头部自动显示角色选择下拉框,用户可随时切换当前使用的客服角色。 **触发条件:** - `ChatbotSDK.init()` 时传入的 `roles` 数组包含 2 个及以上角色 **切换行为:** 1. 自动保存当前对话到 localStorage(与旧角色关联) 2. 清空当前消息列表 3. 生成新的 `chatId`(与新角色关联) 4. 尝试从 localStorage 恢复新角色的缓存消息 5. 异步从后端加载新角色的历史会话 **示例:** ```javascript // 1. 后端换取 Token,获取可用角色列表 const data = await fetch('/api/chatbot/token').then(r => r.json()); // 2. 初始化 SDK,传入角色列表 ChatbotSDK.init({ integrateId: data.roles[0].id, // 默认使用第一个角色 requestDomain: 'https://your-domain.com', token: data.token, roles: data.roles, // 传入多个角色 → header 显示角色选择器 userId: 'current_user_id' }); ``` **安全说明:** - 角色切换由 SDK 前端发起,后端 `SdkAuthFilter` 会校验 JWT Token 中的 `rids` claim,确保用户只能切换到被授权的角色 - 切换角色不需要重新换取 Token,JWT 中已包含允许的角色 ID 列表 --- ## 6. API 接口参考 ### 6.1 Token 换取 ``` POST /open-api/auth/token ``` 详见 [第三步:后端换取 SDK Token](#4-第三步后端换取-sdk-token)。 ### 6.2 对话接口(SDK 内部调用,无需手动对接) | 接口 | 方法 | 说明 | |---|---|---| | `/ai/assistant_app/chat/sync` | GET | 同步对话(返回完整文本) | | `/ai/assistant_app/chat/sse` | GET | SSE 流式对话 | | `/ai/assistant_app/chat/rag/sse` | GET | RAG 增强流式对话 | | `/ai/assistant_app/rag/sources` | GET | 获取 RAG 引用来源 | | `/ai/sdk/conversation/list` | GET | 会话列表 | | `/ai/sdk/conversation/{id}/messages` | GET | 会话消息 | | `/ai/sdk/conversation/{id}` | DELETE | 删除会话 | | `/ai/sdk/conversation/{id}/export` | GET | 导出会话 | | `/category/tree` | GET | 知识库分类树 | | `/feedback` | POST | 消息反馈 | **通用请求参数(对话接口):** | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `message` | Query | 是 | 用户消息 | | `chatId` | Query | 是 | 会话 ID(SDK 自动管理) | | `roleId` | Query | 否 | 客服角色 ID | | `accountId` | Query | 否 | 用户标识 | | `categoryId` | Query | 否 | 知识库分类 ID | | `rewriteStrategy` | Query | 否 | RAG 查询重写策略:REWRITE / TRANSLATION / COMPRESSION / MULTI_QUERY | **认证方式:** 所有 `/ai/**` 请求自动在 Header 中携带 `Authorization: Bearer {token}`。 ### 6.3 管理接口(需要管理后台 JWT) | 接口 | 方法 | 说明 | |---|---|---| | `/api-key/list` | GET | API Key 列表(admin) | | `/api-key` | POST | 创建 API Key(admin) | | `/api-key/{id}/revoke` | PUT | 吊销 API Key(admin) | | `/api-key/{id}/enable` | PUT | 启用 API Key(admin) | | `/api-key/{id}` | DELETE | 删除 API Key(admin) | | `/api-key/{id}/roles` | PUT | 更新角色绑定(admin) | | `/role/list` | GET | 客服角色列表(admin) | | `/role/all` | GET | 全部角色含停用(admin) | --- ## 7. SDK 配置参数参考 | 参数 | 类型 | 默认值 | 说明 | |---|---|---|---| | `integrateId` | String/Number | **必填** | 客服角色 ID | | `requestDomain` | String | **必填** | 后端域名 | | `token` | String | - | SDK JWT Token(推荐) | | `roles` | Array | - | 角色列表 `[{id, key, name}]`,长度 > 1 时 header 显示切换下拉框 | | `userId` | String | - | 用户标识(会话隔离) | | `categoryId` | String | - | 默认知识库分类 ID | | `showCategorySwitch` | Boolean | false | 显示分类切换器 | | `title` | String | 'AI 智能助手' | 窗口标题 | | `width` | Number | 380 | 窗口宽度(px) | | `height` | Number | 520 | 窗口高度(px,最小 300) | | `position` | String | 'right-bottom' | 悬浮按钮位置 | | `primaryColor` | String | '#4F46E5' | 主题色 | | `launcherTheme` | String | - | 按钮主题:dream-purple / mint-tech / coral-peach / sky-blue | | `launcherIcon` | String | (内置) | 自定义悬浮按钮 SVG | | `theme` | String | 'light' | 界面主题:light / dark | | `streaming` | Boolean | true | 流式回复 | | `enableRag` | Boolean | true | RAG 知识库检索 | | `rewriteStrategy` | String | 'REWRITE' | 查询重写策略 | | `quickReplies` | String[] | [] | 快捷问题列表 | | `showClear` | Boolean | true | 显示清空按钮 | | `showAdminPanel` | Boolean | false | 显示管理入口 | | `showTeaser` | Boolean | true | 显示提示气泡 | | `teaserText` | String | '' | 提示气泡文本 | | `sound` | Boolean | false | 消息提示音 | | `notification` | Boolean | false | 浏览器通知 | | `locale` | String | 'zh-CN' | 语言:zh-CN / en | | `debug` | Boolean | true | 调试日志 | | `onReady` | Function | - | SDK 就绪回调 | | `onMessage` | Function | - | 消息回调 | | `onError` | Function | - | 错误回调 | --- ## 8. 错误码与排查 ### Token 换取阶段 | 错误 | 原因 | 解决方案 | |---|---|---| | 401 `API Key 鉴权失败` | X-API-Key 无效或缺失 | 检查 Header 是否正确携带 | | 401 `API Key 已被禁用` | Key 被吊销 | 在管理后台重新启用或创建新 Key | | 401 `API Key 已过期` | Key 超过有效期 | 创建新的 API Key | | 403 `无可用客服角色` | 未绑定角色且系统无启用角色 | 在管理后台创建并启用客服角色 | ### SDK 对话阶段 | HTTP 状态码 | SDK 提示 | 原因 | |---|---|---| | 401 | 鉴权失败 | Token 过期或无效,需重新换取 | | 403 | 无访问权限 | roleId 不在 Token 允许范围内 | | 429 | 请求过于频繁 | 超过 API Key 频率限制 | | 500 | 服务器异常 | 后端错误,查看服务端日志 | | 502/503 | 服务暂不可用 | 后端未启动或正在部署 | ### 常见问题 **Q: Token 过期后怎么办?** A: Token 默认 2 小时过期。建议在第三方后端实现 Token 缓存和自动刷新逻辑:检测到 401 时重新调用 `/open-api/auth/token` 换取新 Token。 **Q: 如何让用户只能使用特定角色?** A: 在 API Key 上绑定角色(`PUT /api-key/{id}/roles`),SDK 初始化时只传入绑定的角色 ID。 **Q: 多个第三方系统可以用同一个 API Key 吗?** A: 可以,但建议每个系统使用独立的 API Key,便于独立管控频率限制和角色权限。 --- ## 9. 安全建议 1. **API Key 仅在后端使用**:永远不要将 API Key 暴露到前端代码中 2. **Token 短有效期**:生产环境建议 TTL 设为 1-2 小时,配合自动刷新 3. **角色最小权限**:只绑定必要的客服角色,避免授予过多权限 4. **频率限制**:根据业务量设置合理的 rateLimit(默认 60 次/分钟) 5. **HTTPS**:生产环境必须使用 HTTPS,防止 Token 被中间人截获 6. **定期轮换 Key**:定期吊销旧 Key 并创建新 Key --- ## 附录:完整对接示例(Node.js) ```javascript // ==================== 第三方后端示例 ==================== const express = require('express'); const app = express(); const AI_DOMAIN = 'https://your-ai-domain.com'; const API_KEY = 'sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Token 缓存 let cachedToken = null; let tokenExpireAt = 0; // 换取 Token(带缓存) async function getSdkToken() { if (cachedToken && Date.now() < tokenExpireAt) { return cachedToken; } const res = await fetch(`${AI_DOMAIN}/open-api/auth/token`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY }, body: JSON.stringify({ ttl: 7200 }) }); const data = await res.json(); if (!data.success) throw new Error(data.message); cachedToken = data.token; tokenExpireAt = Date.now() + (data.expiresIn - 300) * 1000; // 提前 5 分钟刷新 return { token: data.token, roles: data.roles }; } // 给前端提供 Token app.get('/api/chatbot/token', async (req, res) => { try { const data = await getSdkToken(); res.json({ success: true, ...data }); } catch (e) { res.status(500).json({ success: false, message: e.message }); } }); app.listen(3000); ``` ```html ```