baodan/docs/保险智能客服系统_API接口文档.md
wsb1224 cf77d40569 本轮新增:
PPT 对象选择和绿色选中框。
双击编辑文本框、表格单元格。
文字字体、字号、加粗、颜色、对齐属性。
Ctrl/Cmd+Z、Ctrl/Cmd+Shift+Z 撤销重做。
PPT 缩略图/网格总览切换。
历史版本只读查看。
历史版本“恢复为新版本”,不覆盖旧文件。
海报区块显示/隐藏。
长图区块上移、下移排序。
新背景候选确认,可选择使用新背景或保留原背景。
合规问题“一键采用建议”。
新增 warn 合规级别。
解析失败人工填写入口。
展示解析方法和低质量页诊断。
同步更新了[API 接口文档](/D:/work/code/python/coding/baodanagent/docs/保险智能客服系统_API接口文档.md)。
验证结果:
相关后端测试:28 passed, 1 skipped
Python 编译检查:通过
前端生产构建:通过
git diff --check:通过
2026-07-31 15:41:58 +08:00

1364 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 保险智能客服系统 — API 接口文档
> **版本**V1.1(与需求文档 V1.0 对齐)
> **基础路径**`/api`
> **认证方式**JWT Bearer TokenHeader: `Authorization: Bearer <token>`
> **内容类型**`application/json`(除文件上传接口外)
> **接口总数**45 个(含企微/健康检查)
---
## 一、全局约定
### 1.1 统一响应格式
```json
{
"code": 0,
"message": "success",
"data": { ... }
}
```
- `code = 0`:成功
- `code != 0`:失败,`message` 为错误描述,`data` 为 null 或错误详情
### 1.2 错误码表
| 错误码 | 说明 | 处理建议 |
|:---:|------|---------|
| 0 | 成功 | - |
| 1001 | 参数错误 | 检查请求参数 |
| 1002 | 未授权 | 重新登录 |
| 1003 | Token 已过期 | 调用 refresh-token |
| 1004 | 权限不足 | 联系管理员 |
| 1005 | 资源不存在 | 检查资源 ID |
| 2001 | BaoDan API 调用失败 | 检查 BaoDan 服务 |
| 2002 | BaoDan API 超时 | 重试 |
| 2003 | BaoDan Workflow 失败 | 检查 Workflow 配置 |
| 3001 | 企微 API 调用失败 | 检查企微配置 |
| 4001 | 文件上传失败 | 检查文件格式/大小 |
| 9999 | 服务器内部错误 | 检查日志 |
### 1.3 分页参数
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| page | int | 1 | 页码 |
| page_size | int | 20 | 每页条数,最大 100 |
### 1.4 认证方式
所有标注"需要认证"的接口,请求 Header 必须包含:
```
Authorization: Bearer <JWT_TOKEN>
```
JWT Token 有效期 2 小时7200 秒),过期后调用 `/api/auth/refresh-token` 刷新。
### 1.5 实现方式标注
| 标注 | 含义 |
|------|------|
| 自研(调 BaoDan | 自研后端接口,内部调 BaoDan API |
| 自研 | 完全自研 |
| BaoDan 原生 | 直接使用 BaoDan不需要自研后端 |
| BaoDan + 增强 | BaoDan 有基础,需要少量增强代码 |
---
## 二、系统接口
### 2.1 健康检查
| 项 | 值 |
|----|---|
| URL | `GET /api/health` |
| 认证 | 不需要 |
| 实现 | 自研 |
**响应**
```json
{ "status": "ok" }
```
### 2.2 企微机器人回调URL 验证)
| 项 | 值 |
|----|---|
| URL | `GET /api/wecom/callback` |
| 认证 | 不需要(企微签名校验) |
| 实现 | 自研 + 企微 API |
**参数**`msg_signature`、`timestamp`、`nonce`、`echostr`
**响应**:解密后的 echostr纯文本非 JSON
**处理逻辑**
1. 将 Token、timestamp、nonce、echostr 按字典序排列拼接
2. SHA1 哈希,与 msg_signature 比对
3. 验证通过则返回解密后的 echostr
### 2.3 企微机器人消息接收
| 项 | 值 |
|----|---|
| URL | `POST /api/wecom/callback` |
| 认证 | 不需要(企微签名校验) |
| 实现 | 自研 + 企微 API |
**请求体**:企微加密的 XML 消息体
**响应**`success`(纯文本,必须在 5 秒内返回)
**处理逻辑**
1. 验证签名 + 解密 XML
2. 判断 MsgType文本消息继续处理非文本回复"暂不支持"
3. 群聊消息去掉"@机器人"前缀
4. **立即返回 `success`**
5. 异步处理:调 BaoDan Chat API → 通过企微 API 回复用户
### 2.4 企微 OAuth 登录入口
| 项 | 值 |
|----|---|
| URL | `GET /api/wecom/oauth` |
| 认证 | 不需要 |
| 实现 | 自研 |
**响应**302 重定向到企微授权页面
### 2.5 企微 OAuth 回调
| 项 | 值 |
|----|---|
| URL | `GET /api/wecom/oauth/callback` |
| 认证 | 不需要 |
| 实现 | 自研 |
**参数**`code`(企微授权码)、`state`
**处理逻辑**
1. 用 code 换取企微 access_token
2. 获取用户信息userid、name、department
3. 查找/创建 wecom_user_mapping 记录
4. 生成 JWT Token
5. 302 重定向到前端首页
---
## 三、认证鉴权A1
### A1.1.1 企微登录
| 项 | 值 |
|----|---|
| URL | `POST /api/auth/wework-login` |
| 认证 | 不需要 |
| 实现 | 自研(调 BaoDan |
**请求**
```json
{
"code": "企微授权回调code",
"state": "随机状态值"
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| code | string | 是 | 1-512 字符 | "授权码无效" |
| state | string | 否 | 0-256 字符 | - |
**响应**
```json
{
"code": 0,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 7200,
"user": {
"id": "user-001",
"username": "张三",
"wecom_userid": "zhangsan",
"role": "sales",
"department": "上海团队"
}
}
}
```
### A1.1.2 账密登录
| 项 | 值 |
|----|---|
| URL | `POST /api/auth/password-login` |
| 认证 | 不需要 |
| 实现 | 自研(调 BaoDan |
**请求**
```json
{
"username": "admin",
"password": "hashed_password"
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| username | string | 是 | 1-64 字符,非空 | "请输入用户名" |
| password | string | 是 | 1-128 字符,非空 | "请输入密码" |
**响应**
```json
{
"code": 0,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 7200
}
}
```
**失败响应**
```json
{ "code": 1002, "message": "用户名或密码错误" }
```
### A1.1.3 刷新 Token
| 项 | 值 |
|----|---|
| URL | `POST /api/auth/refresh-token` |
| 认证 | 需要(旧 Token |
| 实现 | 自研(调 BaoDan |
**响应**
```json
{
"code": 0,
"data": { "token": "eyJhbGci...", "expires_in": 7200 }
}
```
### A1.1.4 退出登录
| 项 | 值 |
|----|---|
| URL | `POST /api/auth/logout` |
| 认证 | 需要 |
| 实现 | 自研 |
**处理**:将当前 Token 加入黑名单Redis后续请求使用该 Token 时返回 1002。
**响应**
```json
{ "code": 0, "message": "success" }
```
---
## 四、智能问答A2
### A2.1.1 发送消息SSE 流式)
| 项 | 值 |
|----|---|
| URL | `POST /api/chat/message` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**请求**
```json
{
"session_id": "sess-001",
"message": "重疾险的等待期是多少天?",
"filters": { "险种": "重疾险", "保司": null }
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 枚举 | 错误提示 |
|------|------|:---:|------|------|---------|
| message | string | 是 | 1-10000 字符 | - | "请输入问题内容" |
| session_id | string | 否 | UUID 格式,空串=新对话 | - | "会话ID格式无效" |
| filters | object | 否 | - | - | - |
| filters.险种 | string | 否 | 0-32 字符 | 重疾险/寿险/医疗险/意外险/车险/年金险/储蓄险 | "不支持的险种" |
| filters.保司 | string | 否 | 0-64 字符 | - | - |
**响应**SSE 流式,`Content-Type: text/event-stream`
```
data: {"type":"source","data":{"doc_name":"XX重疾险条款.md","chunk":"等待期为合同生效之日起90天..."}}
data: {"type":"delta","data":"根据"}
data: {"type":"delta","data":"XX重疾险条款规定等待期为90天。"}
data: {"type":"done","data":{"message_id":"msg-001","conversation_id":"conv-001"}}
```
**SSE 事件类型**
| type | 说明 | data 结构 |
|------|------|----------|
| source | 来源引用 | `{doc_name, chunk, score}` |
| delta | 文本增量 | `{data: "文本片段"}` |
| done | 回答完成 | `{message_id, conversation_id}` |
| error | 错误 | `{message}` |
### A2.1.2 获取会话列表
| 项 | 值 |
|----|---|
| URL | `GET /api/chat/sessions` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**查询参数**`page`、`page_size`
**响应**
```json
{
"code": 0,
"data": {
"total": 35,
"items": [
{
"id": "sess-001",
"title": "重疾险等待期问题",
"created_at": "2026-05-31T10:00:00Z",
"updated_at": "2026-05-31T10:05:00Z",
"message_count": 6
}
]
}
}
```
### A2.1.3 创建会话
| 项 | 值 |
|----|---|
| URL | `POST /api/chat/sessions` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**响应**
```json
{ "code": 0, "data": { "session_id": "sess-002" } }
```
### A2.1.4 删除会话
| 项 | 值 |
|----|---|
| URL | `DELETE /api/chat/sessions/{id}` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**路径参数**`id`UUID 格式,错误提示:"会话ID格式无效"
**响应**
```json
{ "code": 0, "message": "success" }
```
### A2.1.5 获取消息记录
| 项 | 值 |
|----|---|
| URL | `GET /api/chat/sessions/{id}/messages` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**响应**
```json
{
"code": 0,
"data": {
"messages": [
{
"id": "msg-001",
"role": "user",
"content": "重疾险的等待期是多少天?",
"created_at": "2026-05-31T10:00:00Z"
},
{
"id": "msg-002",
"role": "assistant",
"content": "根据 XX 重疾险条款规定等待期为合同生效之日起90天。",
"sources": [
{"doc_name": "XX重疾险条款.md", "chunk": "等待期为..."}
],
"created_at": "2026-05-31T10:00:05Z"
}
]
}
}
```
### A2.1.6 提交反馈
| 项 | 值 |
|----|---|
| URL | `POST /api/chat/messages/{id}/feedback` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**请求(有用)**
```json
{ "rating": "helpful", "comment": null }
```
**请求(纠错)**
```json
{ "rating": "not_helpful", "comment": "等待期应该是180天而不是90天" }
```
**字段约束**
| 字段 | 类型 | 必填 | 枚举 | 错误提示 |
|------|------|:---:|------|---------|
| rating | string | 是 | helpful / not_helpful | "评分值无效" |
| comment | string | 否 | 0-2000 字符 | - |
### A2.2.1 向量检索
| 项 | 值 |
|----|---|
| URL | `POST /api/retrieval/search` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**请求**
```json
{
"query": "重疾险等待期",
"filters": { "险种": "重疾险", "保司": null },
"top_k": 5
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 默认值 | 错误提示 |
|------|------|:---:|------|--------|---------|
| query | string | 是 | 1-1000 字符 | - | "请输入搜索内容" |
| filters.险种 | string | 否 | 枚举值 | null | "不支持的险种" |
| top_k | int | 否 | 1-20 | 5 | "top_k 应在 1-20 之间" |
**响应**
```json
{
"code": 0,
"data": {
"results": [
{
"doc_name": "XX重疾险条款.md",
"chunk": "等待期为合同生效之日起90天...",
"score": 0.92,
"metadata": { "险种": "重疾险", "保司": "XX人寿" }
}
]
}
}
```
### A2.2.2 推荐追问
| 项 | 值 |
|----|---|
| URL | `POST /api/chat/suggest` |
| 认证 | 需要 |
| 实现 | 自研 |
**请求**
```json
{ "message": "根据 XX 重疾险条款规定等待期为90天。" }
```
**响应**
```json
{
"code": 0,
"data": {
"suggestions": [
"重疾险的免赔额是多少?",
"哪些情况不在理赔范围内?",
"等待期内出险怎么处理?"
]
}
}
```
---
## 五、方案生成A3
### A3.1.1 生成推荐方案
| 项 | 值 |
|----|---|
| URL | `POST /api/recommend/generate` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan Workflow |
**请求**
```json
{
"customer": {
"name": "李四",
"age": 35,
"gender": "male",
"health_status": "健康",
"occupation": "软件工程师",
"annual_income": 300000,
"monthly_budget": 2000
},
"insurance_types": ["重疾险", "医疗险", "意外险"],
"coverage_amount": 500000,
"coverage_period": "终身",
"existing_policies": []
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 枚举 | 错误提示 |
|------|------|:---:|------|------|---------|
| customer.age | int | 是 | 0-150 | - | "年龄应在 0-150 之间" |
| customer.gender | string | 是 | - | male/female | "性别值无效" |
| customer.health_status | string | 是 | 1-32 字符 | 健康/有既往病史/慢性病/重大疾病史 | "健康状况值无效" |
| customer.occupation | string | 是 | 1-50 字符 | - | "请输入职业" |
| customer.annual_income | int | 是 | >=0 | - | "年收入不能为负数" |
| customer.monthly_budget | int | 是 | >=1 | - | "月预算必须大于 0" |
| insurance_types | string[] | 是 | 1-10 项 | 寿险/重疾险/医疗险/意外险/年金险/储蓄险 | "请至少选择一个险种" |
| coverage_amount | int | 是 | >=1 | - | "保额必须大于 0" |
| coverage_period | string | 是 | - | 定期10年/20年/30年/保至60岁/70岁/80岁/终身 | "请选择保障期限" |
| existing_policies | object[] | 否 | 0-20 项 | - | - |
**响应**
```json
{ "code": 0, "data": { "task_id": "task-001", "status": "processing" } }
```
### A3.1.2 轮询任务状态
| 项 | 值 |
|----|---|
| URL | `GET /api/recommend/generate/{task_id}` |
| 认证 | 需要 |
| 实现 | 自研 |
**字段约束**`task_id`UUID 格式,错误提示:"任务ID格式无效"
**响应(生成中)**
```json
{ "code": 0, "data": { "task_id": "task-001", "status": "processing" } }
```
**响应(完成)**
```json
{
"code": 0,
"data": {
"task_id": "task-001",
"status": "done",
"proposal": {
"id": "prop-001",
"plans": [
{
"name": "基础方案",
"total_premium": 4800,
"items": [
{
"product_name": "XX重疾险",
"coverage": 300000,
"premium": 2400,
"reason": "35岁男性投保性价比高覆盖120种重疾"
}
],
"summary": "基础保障方案,覆盖重疾、医疗、意外三大类..."
}
]
}
}
}
```
**响应(失败)**
```json
{ "code": 0, "data": { "task_id": "task-001", "status": "failed", "error_message": "生成超时" } }
```
### A3.1.3 方案导出
| 项 | 值 |
|----|---|
| URL | `POST /api/recommend/{id}/export` |
| 认证 | 需要 |
| 实现 | 自研 |
**请求**`{ "format": "pdf" }`
**字段约束**
| 字段 | 类型 | 必填 | 枚举 | 错误提示 |
|------|------|:---:|------|---------|
| format | string | 是 | pdf/pptx/docx | "不支持的导出格式" |
**响应**
```json
{
"code": 0,
"data": {
"download_url": "https://your-domain.com/api/recommend/{id}/download?token=xxx",
"expire_at": "2026-06-03T10:00:00Z"
}
}
```
### A3.1.4 生成分享链接
| 项 | 值 |
|----|---|
| URL | `POST /api/recommend/{id}/share` |
| 认证 | 需要 |
| 实现 | 自研 |
**请求**`{ "expire_hours": 72 }`
**字段约束**`expire_hours`int1-720错误提示"有效期应在 1-720 小时之间"
**响应**
```json
{
"code": 0,
"data": {
"share_url": "https://your-domain.com/shared/prop-001?token=xxx",
"expire_at": "2026-06-03T10:00:00Z"
}
}
```
---
## 六、知识库A4
### A4.1.1 上传文档
| 项 | 值 |
|----|---|
| URL | `POST /api/kb/documents/upload` |
| Content-Type | multipart/form-data |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**表单字段**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| files | file[] | 是 | 1-50 个文件,每个 <50MB格式 md/word/txt | "仅支持 MD/Word/TXT 格式" |
| 险种 | string | | 1-32 字符 | "请选择险种" |
| 保司 | string | | 1-64 字符 | "请填写保司名称" |
**响应**
```json
{
"code": 0,
"data": {
"upload_id": "upload-001",
"documents": [
{ "doc_id": "doc-001", "filename": "file1.md", "status": "processing" }
]
}
}
```
### A4.1.2 文档列表
| | |
|----|---|
| URL | `GET /api/kb/documents` |
| 认证 | 需要 |
| 实现 | 自研 BaoDan |
**查询参数**
| 参数 | 类型 | 必填 | 约束 | 枚举值 |
|------|------|:---:|------|--------|
| page | int | | >=1默认 1 | - |
| page_size | int | 否 | 1-100默认 20 | - |
| 险种 | string | 否 | 0-32 | - |
| 保司 | string | 否 | 0-64 | - |
| status | string | 否 | - | pending/processing/completed/failed |
| keyword | string | 否 | 0-100 | - |
**响应**
```json
{
"code": 0,
"data": {
"total": 150,
"items": [
{
"doc_id": "doc-001",
"filename": "XX重疾险条款.md",
"编号": "CJ-XX-001",
"险种": "重疾险",
"保司": "XX人寿",
"tags": ["产品条款", "等待期"],
"status": "completed",
"uploaded_at": "2026-05-15T10:00:00Z",
"processed_at": "2026-05-15T10:05:00Z"
}
]
}
}
```
### A4.1.3 文档处理状态
| 项 | 值 |
|----|---|
| URL | `GET /api/kb/documents/{id}/status` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**响应**
```json
{
"code": 0,
"data": {
"doc_id": "doc-001",
"filename": "XX重疾险条款.md",
"pipeline": [
{ "stage": "upload", "status": "completed", "time": "2026-05-15T10:00:01Z" },
{ "stage": "format_convert", "status": "completed", "time": "2026-05-15T10:00:02Z" },
{ "stage": "chunking", "status": "completed", "time": "2026-05-15T10:00:03Z", "chunk_count": 45 },
{ "stage": "embedding", "status": "completed", "time": "2026-05-15T10:05:00Z" }
]
}
}
```
### A4.1.4 重试失败文档
| 项 | 值 |
|----|---|
| URL | `POST /api/kb/documents/{id}/retry` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
### A4.1.5 更新文档元数据
| 项 | 值 |
|----|---|
| URL | `PATCH /api/kb/documents/{id}` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
**请求**`{ "编号": "CJ-XX-002", "tags": ["产品条款", "核保"] }`
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| 编号 | string | 否 | 0-32 字符 | "编号格式无效" |
| tags | string[] | 否 | 0-20 项,每项 1-32 字符 | - |
### A4.1.6 删除文档
| 项 | 值 |
|----|---|
| URL | `DELETE /api/kb/documents/{id}` |
| 认证 | 需要 |
| 实现 | 自研(调 BaoDan |
### A4.2.1 数据源列表
| 项 | 值 |
|----|---|
| URL | `GET /api/kb/datasources` |
| 认证 | 需要 |
| 实现 | 自研 |
**响应**
```json
{
"code": 0,
"data": [
{
"id": "ds-001",
"name": "XX人寿产品接口",
"api_url": "https://api.xxlife.com/products",
"sync_frequency": "0 2 * * *",
"last_sync": "2026-05-31T02:00:00Z",
"last_sync_status": "success",
"last_sync_count": 156
}
]
}
```
### A4.2.2 新建数据源
| 项 | 值 |
|----|---|
| URL | `POST /api/kb/datasources` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
**请求**
```json
{
"name": "XX人寿产品接口",
"api_url": "https://api.xxlife.com/products",
"api_key": "encrypted_key_here",
"sync_frequency": "0 2 * * *"
}
```
### A4.2.3 手动同步
| 项 | 值 |
|----|---|
| URL | `POST /api/kb/datasources/{id}/sync` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
### A4.2.4 同步日志
| 项 | 值 |
|----|---|
| URL | `GET /api/kb/datasources/{id}/logs` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
---
## 七、用户权限A5
### A5.1.1 用户管理
| 项 | 值 |
|----|---|
| URL | `GET/POST/PUT/DELETE /api/admin/users` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**GET 列表请求**`GET /api/admin/users?page=1&page_size=20&role=sales&department=上海团队`
**GET 列表响应**
```json
{
"code": 0,
"data": {
"total": 50,
"items": [
{
"id": "user-001",
"username": "张三",
"wecom_userid": "zhangsan",
"role": "sales",
"department": "上海团队",
"status": "active",
"created_at": "2026-05-01T10:00:00Z",
"last_active_at": "2026-05-31T09:30:00Z"
}
]
}
}
```
**POST 新增请求**
```json
{
"username": "李四",
"wecom_userid": "lisi",
"role": "sales",
"department": "上海团队"
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 枚举 | 错误提示 |
|------|------|:---:|------|------|---------|
| username | string | 是 | 1-64不可重复 | - | "用户名已存在" |
| role | string | 是 | - | super_admin/admin/manager/sales | "角色值无效" |
**PUT 编辑**`PUT /api/admin/users/{id}`
**DELETE 停用**`DELETE /api/admin/users/{id}`(停用时吊销所有 Token
### A5.1.2 批量导入用户
| 项 | 值 |
|----|---|
| URL | `POST /api/admin/users/batch-import` |
| Content-Type | multipart/form-data |
| 认证 | 需要(超级管理员) |
| 实现 | 自研 |
### A5.1.3 角色管理
| 项 | 值 |
|----|---|
| URL | `GET/POST/PUT/DELETE /api/admin/roles` |
| 认证 | 需要(超级管理员) |
| 实现 | 自研 |
**GET 响应**
```json
{
"code": 0,
"data": [
{ "id": "role-001", "name": "超级管理员", "permissions": ["*"], "builtin": true },
{ "id": "role-002", "name": "管理员", "permissions": ["kb_manage","log_view","user_manage","config_manage"], "builtin": true },
{ "id": "role-003", "name": "销售主管", "permissions": ["chat","proposal","kb_view","team_stats"], "builtin": true },
{ "id": "role-004", "name": "销售人员", "permissions": ["chat","proposal"], "builtin": true },
{ "id": "role-005", "name": "客户", "permissions": ["chat"], "builtin": true }
]
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| name | string | 是 | 1-32不可重复 | "角色名已存在" |
| permissions | string[] | 是 | 1-50 项 | "权限标识无效" |
---
## 八、系统配置A6
### A6.1.1 LLM 配置
| 项 | 值 |
|----|---|
| URL | `GET/POST/PUT /api/admin/llm-configs` |
| 认证 | 需要(超级管理员) |
| 实现 | 自研(调 BaoDan |
**POST 请求**
```json
{
"provider": "deepseek",
"model": "deepseek-chat",
"api_key": "sk-xxxxxxxxxxxx",
"base_url": "https://api.deepseek.com/v1",
"is_default": true,
"params": { "temperature": 0.7, "max_tokens": 4096, "top_p": 0.9 }
}
```
**字段约束**
| 字段 | 类型 | 必填 | 枚举 | 错误提示 |
|------|------|:---:|------|---------|
| provider | string | 是 | deepseek/openai/zhipu/qwen | "不支持的供应商" |
| model | string | 是 | 1-64 字符 | "请输入模型名称" |
| api_key | string | 是 | 1-512 字符 | "请输入 API Key" |
**POST 响应**
```json
{
"code": 0,
"data": {
"id": "llm-001",
"provider": "deepseek",
"model": "deepseek-chat",
"api_key_masked": "sk-xxxx****xxxx",
"is_default": true,
"status": "active"
}
}
```
### A6.1.2 连通性测试
| 项 | 值 |
|----|---|
| URL | `POST /api/admin/llm-configs/{id}/ping` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**响应**
```json
{ "code": 0, "data": { "reachable": true, "latency_ms": 320, "model": "deepseek-chat" } }
```
### A6.1.3 Prompt 管理
| 项 | 值 |
|----|---|
| URL | `GET/POST/PUT /api/admin/prompts` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**POST 请求**
```json
{
"name": "保险顾问系统提示词",
"type": "system",
"content": "你是一名专业的保险顾问助手...",
"variables": ["险种", "保司"]
}
```
**字段约束**
| 字段 | 类型 | 必填 | 约束 | 错误提示 |
|------|------|:---:|------|---------|
| content | string | 是 | 1-100000 字符 | "Prompt 内容不能为空" |
**POST 响应**(自动生成版本快照):
```json
{
"code": 0,
"data": {
"id": "prompt-001",
"name": "保险顾问系统提示词",
"version": 3,
"versions": [
{"version": 1, "created_at": "2026-05-01T10:00:00Z"},
{"version": 2, "created_at": "2026-05-15T10:00:00Z"},
{"version": 3, "created_at": "2026-05-31T10:00:00Z"}
]
}
}
```
### A6.1.4 Prompt 测试
| 项 | 值 |
|----|---|
| URL | `POST /api/admin/prompts/test` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**请求**`{ "prompt_id": "prompt-001", "test_query": "重疾险等待期多少天?" }`
**响应**
```json
{
"code": 0,
"data": {
"response": "根据条款规定重疾险等待期为90天...",
"latency_ms": 1200,
"token_usage": { "prompt_tokens": 520, "completion_tokens": 180 }
}
}
```
---
## 九、留痕日志A7
### A7.1.1 问答记录查询
| 项 | 值 |
|----|---|
| URL | `GET /api/admin/logs/chat` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**查询参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|:---:|------|
| page | int | 否 | 页码,默认 1 |
| page_size | int | 否 | 每页条数,默认 50 |
| user_id | string | 否 | 按用户筛选 |
| start_date | string | 否 | 开始日期 YYYY-MM-DD |
| end_date | string | 否 | 结束日期 YYYY-MM-DD |
| keyword | string | 否 | 关键词搜索 |
| rating | string | 否 | 评分筛选,枚举 helpful/not_helpful |
| export | string | 否 | 设为 "csv" 时返回 CSV 文件流 |
**响应JSON 模式)**
```json
{
"code": 0,
"data": {
"total": 1200,
"items": [
{
"id": "msg-001",
"user_id": "user-001",
"username": "张三",
"question": "重疾险等待期多少天?",
"answer": "等待期为合同生效之日起90天。",
"sources": ["XX重疾险条款.md"],
"rating": "helpful",
"created_at": "2026-05-31T10:00:00Z"
}
]
}
}
```
**响应CSV 导出)**:当 `export=csv` 时返回文件流
```
Content-Type: text/csv
Content-Disposition: attachment; filename="chat_logs_202605.csv"
```
### A7.1.2 导出对话记录
| 项 | 值 |
|----|---|
| URL | `GET /api/admin/logs/chat/export` |
| 认证 | 需要(管理员) |
| 实现 | 自研(调 BaoDan |
**查询参数**:同 A7.1.1 的筛选参数
**响应**:返回 CSV 文件流
```
Content-Type: text/csv
Content-Disposition: attachment; filename="chat_logs_202606.csv"
```
### A7.1.3 系统操作日志
| 项 | 值 |
|----|---|
| URL | `GET /api/admin/logs/system` |
| 认证 | 需要(超级管理员) |
| 实现 | 自研 |
**查询参数**`page`、`page_size`、`action`、`user_id`
**响应**
```json
{
"code": 0,
"data": {
"total": 200,
"items": [
{
"id": "log-001",
"action": "login",
"user_id": "user-001",
"username": "张三",
"ip": "192.168.1.100",
"device": "Chrome/120 Windows",
"detail": "企微 OAuth 登录",
"created_at": "2026-05-31T09:00:00Z"
}
]
}
}
```
---
## 十、统计报表A8
### A8.1.1 使用概览
| 项 | 值 |
|----|---|
| URL | `GET /api/stats/overview` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
**响应**
```json
{
"code": 0,
"data": {
"today_chats": 45,
"active_users": 12,
"kb_hit_rate": 0.87,
"total_documents": 1500
}
}
```
### A8.1.2 趋势数据
| 项 | 值 |
|----|---|
| URL | `GET /api/stats/trend` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
**查询参数**`metric`(如 chat_count、`start_date`、`end_date`、`granularity`day/week/month
**响应**
```json
{
"code": 0,
"data": {
"metric": "chat_count",
"granularity": "day",
"data": [
{ "date": "2026-05-01", "value": 45 },
{ "date": "2026-05-02", "value": 62 }
]
}
}
```
### A8.1.3 知识库健康度
| 项 | 值 |
|----|---|
| URL | `GET /api/stats/kb-health` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
**查询参数**`days`
**响应**
```json
{
"code": 0,
"data": {
"hot_questions": [{"question": "重疾险等待期多少天", "count": 230}],
"missed_questions": [{"question": "XX新产品费率", "count": 45, "handled": false}],
"coverage": {
"寿险": {"doc_count": 320, "status": "completed"},
"重疾险": {"doc_count": 280, "status": "completed"}
}
}
}
```
### A8.1.4 Token 消耗统计
| 项 | 值 |
|----|---|
| URL | `GET /api/stats/token-cost` |
| 认证 | 需要(管理员) |
| 实现 | 自研 |
**查询参数**`start_date`、`end_date`、`group_by`model
**响应**
```json
{
"code": 0,
"data": {
"total_tokens": 2500000,
"total_cost_usd": 12.5,
"by_model": [
{"model": "deepseek-chat", "input_tokens": 1500000, "output_tokens": 500000, "cost_usd": 10.0}
],
"daily_trend": [
{"date": "2026-05-01", "tokens": 80000, "cost_usd": 0.4}
]
}
}
```
---
## 十一、接口清单汇总
| # | 方法 | URL | 认证 | 实现 | 对应功能 |
|---|------|-----|:---:|------|---------|
| 1 | GET | /api/health | 否 | 自研 | 健康检查 |
| 2 | GET | /api/wecom/callback | 否 | 自研+企微 | 企微回调验证 |
| 3 | POST | /api/wecom/callback | 否 | 自研+企微 | 企微消息接收 |
| 4 | GET | /api/wecom/oauth | 否 | 自研 | OAuth 入口 |
| 5 | GET | /api/wecom/oauth/callback | 否 | 自研 | OAuth 回调 |
| 6 | POST | /api/auth/wework-login | 否 | 自研(调BaoDan) | 企微登录 |
| 7 | POST | /api/auth/password-login | 否 | 自研(调BaoDan) | 账密登录 |
| 8 | POST | /api/auth/refresh-token | 是 | 自研(调BaoDan) | 刷新Token |
| 9 | POST | /api/auth/logout | 是 | 自研 | 退出登录 |
| 10 | POST | /api/chat/message | 是 | 自研(调BaoDan) | 发送消息(SSE) |
| 11 | GET | /api/chat/sessions | 是 | 自研(调BaoDan) | 会话列表 |
| 12 | POST | /api/chat/sessions | 是 | 自研(调BaoDan) | 创建会话 |
| 13 | DELETE | /api/chat/sessions/{id} | 是 | 自研(调BaoDan) | 删除会话 |
| 14 | GET | /api/chat/sessions/{id}/messages | 是 | 自研(调BaoDan) | 消息记录 |
| 15 | POST | /api/chat/messages/{id}/feedback | 是 | 自研(调BaoDan) | 提交反馈 |
| 16 | POST | /api/chat/suggest | 是 | 自研 | 推荐追问 |
| 17 | POST | /api/retrieval/search | 是 | 自研(调BaoDan) | 向量检索 |
| 18 | POST | /api/recommend/generate | 是 | 自研(调BaoDan) | 生成推荐方案 |
| 19 | GET | /api/recommend/generate/{id} | 是 | 自研 | 查询方案状态 |
| 20 | POST | /api/recommend/{id}/export | 是 | 自研 | 方案导出 |
| 21 | POST | /api/recommend/{id}/share | 是 | 自研 | 生成分享链接 |
| 22 | POST | /api/kb/documents/upload | 是 | 自研(调BaoDan) | 上传文档 |
| 23 | GET | /api/kb/documents | 是 | 自研(调BaoDan) | 文档列表 |
| 24 | GET | /api/kb/documents/{id}/status | 是 | 自研(调BaoDan) | 文档处理状态 |
| 25 | POST | /api/kb/documents/{id}/retry | 是 | 自研(调BaoDan) | 重试文档 |
| 26 | PATCH | /api/kb/documents/{id} | 是 | 自研(调BaoDan) | 更新元数据 |
| 27 | DELETE | /api/kb/documents/{id} | 是 | 自研(调BaoDan) | 删除文档 |
| 28 | GET | /api/kb/datasources | 是 | 自研 | 数据源列表 |
| 29 | POST | /api/kb/datasources | 是 | 自研 | 新建数据源 |
| 30 | POST | /api/kb/datasources/{id}/sync | 是 | 自研 | 手动同步 |
| 31 | GET | /api/kb/datasources/{id}/logs | 是 | 自研 | 同步日志 |
| 32 | GET/POST/PUT/DELETE | /api/admin/users | 管理员 | 自研(调BaoDan) | 用户管理 |
| 33 | POST | /api/admin/users/batch-import | 超管 | 自研 | 批量导入 |
| 34 | GET/POST/PUT/DELETE | /api/admin/roles | 超管 | 自研 | 角色管理 |
| 35 | GET/POST/PUT | /api/admin/llm-configs | 超管 | 自研(调BaoDan) | LLM配置 |
| 36 | POST | /api/admin/llm-configs/{id}/ping | 管理员 | 自研(调BaoDan) | 连通性测试 |
| 37 | GET/POST/PUT | /api/admin/prompts | 管理员 | 自研(调BaoDan) | Prompt管理 |
| 38 | POST | /api/admin/prompts/test | 管理员 | 自研(调BaoDan) | Prompt测试 |
| 39 | GET | /api/admin/logs/chat | 管理员 | 自研(调BaoDan) | 问答日志 |
| 40 | GET | /api/admin/logs/chat/export | 管理员 | 自研(调BaoDan) | 导出对话记录 |
| 41 | GET | /api/admin/logs/system | 超管 | 自研 | 系统日志 |
| 42 | GET | /api/stats/overview | 管理员 | 自研 | 使用概览 |
| 43 | GET | /api/stats/trend | 管理员 | 自研 | 趋势数据 |
| 44 | GET | /api/stats/kb-health | 管理员 | 自研 | 知识库健康度 |
| 45 | GET | /api/stats/token-cost | 管理员 | 自研 | Token消耗 |
| 46 | POST | /api/wecom/callback企微内部 | - | - | 同 #3 |
| 47 | POST | /api/recommend/generateBaoDan内部 | - | - | 同 #18 |
> 注:#46 和 #47 是企微/BaoDan 侧视角的接口,实际为同一端点。有效独立接口为 **45 个**。
### 11.1 海报用户产品小册子补充接口
以下接口统一要求登录认证,资料详情、预览、修改、删除和生成时都会校验当前用户所有权。
| 方法 | URL | 用途 |
|------|-----|------|
| GET | `/insurance/poster/product-sources` | 查询系统产品、“我的资料”和功能开关状态 |
| GET | `/insurance/poster/product-materials` | 查询当前用户上传的产品小册子 |
| POST | `/insurance/poster/product-materials` | 上传 PDF 并异步解析;支持可选 `password`、`companyId`、`planType` |
| GET | `/insurance/poster/product-materials/{id}` | 查询解析状态和核对数据 |
| PUT | `/insurance/poster/product-materials/{id}/confirm` | 校验并确认产品规则,确认后可用于生成 |
| POST | `/insurance/poster/product-materials/{id}/retry` | 解析失败后重新投递任务 |
| GET | `/insurance/poster/product-materials/{id}/file` | 鉴权预览原 PDF |
| DELETE | `/insurance/poster/product-materials/{id}` | 软删除本人资料 |
| POST | `/insurance/poster/product-materials/{id}/submit-review` | 可选:提交公共库审核 |
文案、计划书上传和海报生成接口优先接受:
```json
{
"productSource": {
"type": "user_material",
"id": "123"
}
}
```
旧请求只传 `productId` 时仍按系统产品处理。关闭 `POSTER_USER_MANUAL_UPLOAD_ENABLED` 后,前端隐藏上传入口,后端拒绝私有资料生成请求。
### 11.2 PPT/海报优化接口2026-07-31
生成接口不再接受用户侧脱敏决策;即使旧客户端继续提交 `useMaskedData`,服务端也会忽略该值,并使用保司/产品配置快照。
| 方法 | URL | 用途 |
|------|-----|------|
| GET/POST | `/insurance/admin/ppt/scenarios` | 查询、新增 PPT 生成场景 |
| PUT/DELETE | `/insurance/admin/ppt/scenarios/{code}` | 修改、软删除自定义场景;内置场景只能停用 |
| DELETE | `/insurance/admin/ppt/companies/{id}` | 软删除保司;存在启用产品时拒绝 |
| DELETE | `/insurance/admin/ppt/products/{id}` | 软删除产品并保留历史快照 |
| DELETE | `/insurance/admin/ppt/templates/{id}` | 软删除 PPT 模板;内置模板只能停用 |
| DELETE | `/insurance/admin/ppt/copy-templates/{id}` | 软删除文案模板 |
| POST | `/insurance/poster/compliance-check` | 返回文案合规状态、哈希、规则编号和字符区间 |
| GET/PUT | `/insurance/poster/records/{id}/document` | 读取或保存可编辑海报文档 |
| GET | `/insurance/poster/records/{id}/background` | 读取 AI 背景资产 |
| POST | `/insurance/poster/records/{id}/rendered` | 上传浏览器合成的最终 PNG 和文档快照 |
| GET | `/insurance/ppt/preview/{sessionId}?revision={revision}` | 查看当前或指定历史版本预览 |
| POST | `/insurance/ppt/preview/{sessionId}/versions/{revision}/restore` | 将历史版本复制恢复为新版本 |
保司写接口新增 `maskingEnabled`、`logoEnabled`;产品写接口新增 `maskingEnabled`。开启名称脱敏时 `maskedDisplayName` 必填。
`GET /insurance/ppt/validate/{sessionId}` 新增:
```json
{
"canProceed": true,
"blockerCount": 0,
"warningCount": 2,
"infoCount": 0
}
```
兼容期内继续返回 `validated`、`errorCount`、`warnCount`。利益演示和退保提取问题只进入警告,不影响 `canProceed`