dieya_risk_prediction_backend/docs/外部系统风险评估报告接口.md

235 lines
10 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.

# 第三方风险评估与报告追问接口
当前第三方系统只需调用两个 POST 接口,均一次性返回 JSON:
| 用途 | 路径 | 响应类型 |
| --- | --- | --- |
| 生成报告或重取原报告 | `/api/v1/integrations/risk-assessments/report` | `application/json` |
| 针对原报告继续追问 | `/api/v1/integrations/risk-assessments/follow-up` | `application/json` |
没有单独的创建会话、历史查询、状态查询或流式接口。PLM 不需要管理 `conversationId`,只需保存报告 `requestId`。后端第一次追问时自动建立会话,后续同一调用系统、同一报告、同一报告操作人的多次追问沿用该会话。
## 1. 鉴权与操作人
两个接口均使用系统 HMAC-SHA256 鉴权,不依赖平台用户 JWT。系统密钥只保存在双方后端;PLM 后端必须从真实登录态获取操作人身份,不允许浏览器自行冒用账号。
| 请求头 | 说明 |
| --- | --- |
| `Content-Type` | `application/json` |
| `X-Client-Id` | 已开通的调用系统编号,例如 `dieya-plm` |
| `X-Timestamp` | 当前 Unix 秒级时间戳,误差不超过 5 分钟 |
| `X-Nonce` | 每次请求使用新的 8~64 位随机串,允许字母、数字、下划线和短横线 |
| `X-Signature` | HMAC-SHA256 结果,标准 Base64 编码 |
| `Idempotency-Key` | 生成报告时等于 `requestId`;追问时等于 `messageRequestId` |
| `X-Signature-Version` | 仅追问接口必须提供,固定为 `2` |
生成报告沿用原签名,避免变更已有签名代码:
```text
时间戳 + 换行 + Nonce + 换行 + 原始请求正文
```
追问的 v2 签名绑定方法、路径和正文,使用真实换行字节(0x0A):
```text
POST + 换行 + /api/v1/integrations/risk-assessments/follow-up + 换行 + 空查询串 + 换行 + 时间戳 + 换行 + Nonce + 换行 + 原始请求正文
```
追问签名 Python 示例;`body` 必须与实际发送的 UTF-8 字节完全一致:
```python
import base64
import hashlib
import hmac
import secrets
import time
def sign_follow_up_request(method, path_and_query, body, client_id, client_secret):
timestamp = str(int(time.time()))
nonce = secrets.token_urlsafe(18)
path, _, query = path_and_query.partition("?")
canonical = b"\n".join((
method.upper().encode("ascii"), path.encode("ascii"), query.encode("ascii"),
timestamp.encode("ascii"), nonce.encode("ascii"), body,
))
signature = base64.b64encode(
hmac.new(client_secret.encode("utf-8"), canonical, hashlib.sha256).digest()
).decode("ascii")
return {
"X-Signature-Version": "2", "X-Client-Id": client_id,
"X-Timestamp": timestamp, "X-Nonce": nonce, "X-Signature": signature,
}
```
`operator` 使用以下两种身份之一,不能混用:
- 钉钉用户:`{"dingtalkUnionId":"真实UnionId","dingtalkUserId":"真实UserId"}`,其中 UserId 可省略。
- 外部用户:`{"externalUserId":"superadmin"}`,需要提前配置该调用系统到平台本地账号的映射。
`name`、`employeeNo` 不能单独作为身份依据。账号需启用并拥有 `risk.assess` 操作权限;每次追问都会重新校验报告归属,不能跨系统、跨用户访问,也不按名字猜测用户。
## 2. 生成报告
```http
POST /api/v1/integrations/risk-assessments/report
Content-Type: application/json
Idempotency-Key: PLM-REPORT-001
```
另需提供系统签名请求头。请求正文:
```json
{
"requestId": "PLM-REPORT-001",
"sourceSystem": "dieya-plm",
"operator": {"externalUserId": "superadmin"},
"assessment": {
"subjectId": "PRODUCT-001",
"productName": "保湿面霜",
"productCategory": "面霜/护肤类",
"specification": "50g",
"materialType": "塑料罐",
"stageNew": "产品开发",
"supplier": null,
"factory": null,
"description": "新品包装风险评估",
"asOfDate": "2026-10-28"
}
}
```
必填字段:`requestId`、`sourceSystem`、`operator`,以及 `assessment.subjectId`、`productCategory`、`materialType`。`sourceSystem` 必须与 `X-Client-Id` 一致。其他评估字段可省略:产品名、规格、供应商、加工厂、开发阶段、缺陷等级、描述和截止日期。
- `requestId` 为 1~128 位字母、数字、下划线、点、冒号或短横线。
- `stageNew` 可为需求发现、产品立项、产品开发、量产上市、产品生命管理。
- `defectLevel` 可为 A、B、C;代表已知信息,不预测新品缺陷等级。
- `asOfDate` 为 YYYY-MM-DD,不允许未来日期;省略时采用平台当天日期。
- 评分仍采用现有七维规则和风险平台本地数据。无法归类或缺少数据时会在报告里说明,不能把默认分理解为通过验证。
成功返回 `HTTP 200`:
```json
{
"code": 200,
"message": "success",
"data": {
"requestId": "PLM-REPORT-001",
"status": "completed",
"assessmentId": 123,
"score": 62.5,
"level": "moderately_low",
"modelVersion": "database-seven-dimension-v1",
"asOfDate": "2026-10-28",
"reportMarkdown": "# 新品风险评估报告\n\n完整报告正文……"
}
}
```
示例分数和 ID 仅说明格式。报告正文仍是 Markdown,但放在 JSON 的 `data.reportMarkdown` 中,HTTP 响应不再是 `text/markdown`。已集成旧响应的调用方需要改为解析 JSON 后读取该字段。保留 `X-Request-Id`、`X-Assessment-Id`、`X-Risk-Score`、`X-Risk-Level`、`X-Model-Version` 响应头,便于现有日志衔接。
同一 `sourceSystem + requestId` 重复提交同一内容,返回已保存的同一份报告;相同编号换内容返回 `409`。获取原报告直接重复 POST 原参数,不再提供 GET 查询接口。尚在生成时返回 `202` 和 `Retry-After`,等待后重发相同参数,每次使用新的 Nonce 和签名。
## 3. 对报告追问
```http
POST /api/v1/integrations/risk-assessments/follow-up
Content-Type: application/json
X-Signature-Version: 2
Idempotency-Key: PLM-QUESTION-001
```
另需提供对应的 HMAC v2 签名请求头。请求正文:
```json
{
"requestId": "PLM-REPORT-001",
"messageRequestId": "PLM-QUESTION-001",
"operator": {"externalUserId": "superadmin"},
"content": "为什么供应商这一项得分较低?"
}
```
- `requestId` 是前一步已成功生成的原报告编号。
- `messageRequestId` 是本次问题的唯一编号,每个新问题换一个编号;重试同一个问题保持编号及内容不变。
- `operator` 必须具有原报告的访问权限。
- `content` 为 1~2000 字符,不能为空或纯空格。
- 无需传报告正文、完整聊天历史或会话 ID,后端自行加载。
完成后一次性返回 `HTTP 200` JSON,不发送 SSE 或增量文字:
```json
{
"code": 200,
"message": "success",
"data": {
"requestId": "PLM-REPORT-001",
"messageRequestId": "PLM-QUESTION-001",
"status": "completed",
"reply": "根据原报告,供应商维度的得分依据是……"
}
}
```
继续问“应该怎么改善”,仍使用相同 `requestId`,换用 `messageRequestId=PLM-QUESTION-002` 即可。两次问题自动进入同一会话,模型同时获得原报告和近期聊天。
追问会复用现有 Prompt 语义路由,每轮固定提供原始产品资料、报告截止日期和结构化评分;Markdown 正文最多带入 32000 字符,截断时会标记。近期聊天超过窗口后,原报告仍会保留。追问不修改原报告,也不触发重新评分;正式重算应使用新报告编号提交更新后的评估参数。
## 4. 重试与错误
- 同一个问题重复 POST:返回原答案,不重复插入用户消息,不重复生成已完成的回答。
- 同问题编号更改内容:`409`。
- 同一问题正在处理中:`202` JSON,`data.status=processing`、`reply=null`,携带 `Retry-After: 3`;之后仍重复调用本接口,不需要状态查询接口。
- 同一会话有另一条未完成问题:`409`,先用原问题编号完成重试,避免上下文乱序。
- 生成失败或超时:`503` JSON,可用原编号和原内容重试。
- 网络断开或服务重启后:重复调用同一接口及原参数;如果旧处理租约仍有效,会先返回 `202`,过期后重试恢复。
- 签名无效或重放 Nonce:`401`;账号未开通、停用或无权限:`403`;报告不存在或无权访问:`404`;参数不合法:`422`;超出频率:`429`。
处理中的追问示例:
```json
{
"code": 202,
"message": "原问题正在生成,请用相同编号重试",
"data": {
"requestId": "PLM-REPORT-001",
"messageRequestId": "PLM-QUESTION-001",
"status": "processing",
"reply": null
}
}
```
普通错误统一为 `{"code":503,"message":"可阅读的错误说明","data":null}`。追问总生成时限默认 240 秒,处理租约 5 分钟。回答正文和完成状态在同一事务中提交;过期旧处理令牌不能覆盖新的回答。
## 5. 服务端启用与调用脚本
发布前执行迁移并重启后端:
```powershell
.\.venv\Scripts\python.exe -m alembic upgrade head
```
新增 `integration_conversations` 和 `integration_conversation_requests` 仅用于后端关联会话和幂等,不需要第三方额外调用接口。已有内部用户会话的流式功能不受此处接口精简影响。
```dotenv
RISK_INTEGRATION_CLIENTS={"dieya-plm":"replace-with-at-least-32-random-characters"}
RISK_INTEGRATION_OPERATOR_MAPPINGS={"dieya-plm":{"superadmin":"plm_superadmin"}}
RISK_INTEGRATION_REQUESTS_PER_MINUTE=60
RISK_INTEGRATION_REPORT_TIMEOUT_SECONDS=110
RISK_INTEGRATION_CHAT_TIMEOUT_SECONDS=240
```
示例密钥必须替换为双方后端保管的独立密钥,至少 32 字符,不能提交真实 `.env`。默认空 JSON 不允许外部调用。可用 `scripts/setup_external_risk.py` 开通系统与批准操作人映射。
调用方终端设置 `RISK_INTEGRATION_CLIENT_SECRET` 后:
```powershell
# report-request.json 使用第 2 节正文
.\.venv\Scripts\python.exe scripts/call_external_risk_report.py --url http://127.0.0.1:18474/api/v1/integrations/risk-assessments/report --body-file report-request.json --output report.md
# follow-up.json 使用第 3 节正文
.\.venv\Scripts\python.exe scripts/call_external_follow_up.py --url http://127.0.0.1:18474/api/v1/integrations/risk-assessments/follow-up --body-file follow-up.json
```
生成报告脚本读取 JSON 中的 `reportMarkdown` 保存为 Markdown 文件;追问脚本直接打印完整 JSON。PLM 后端按同一协议接入即可,HMAC 密钥不下发浏览器。