wechat_ai/docs/api-design.md

56 KiB
Raw Permalink Blame History

微信 AI 助手 API 接口设计

依据当前 src/ 页面字段、数据结构和交互设计。本文定义目标契约,不表示这些接口已经实现。

适用范围:单机 Windows、单个本地操作者、Tauri 桌面端、本机 SQLite 业务状态、本机 sidecar。默认不引入账号、租户、Workspace 或远程同步。

1. 设计结论

1.1 协议选择

场景 协议 原因
列表、详情、筛选、创建、更新、启停、删除、配置保存 HTTP JSON 一次请求对应一个确定结果,便于重试、校验、审计和错误处理
文件上传 HTTP multipart/form-data;大文件使用分片 HTTP WebSocket 不适合传二进制大文件HTTP 更容易限制大小、校验哈希和断点续传
智能体测试流式回复 WebSocket 同一会话需要发送消息、接收 token 增量、完成或失败事件
蒸馏任务进度 WebSocket 后台任务跨页面持续运行,需要实时阶段和进度事件
引擎状态、启动检查、结构化日志 WebSocket 状态和日志持续产生,轮询会增加延迟和重复流量
知识文件解析状态 WebSocket PDF、DOCX、PPT/PPTX 的文本提取可能耗时;图片和视频只做上传、校验及预览,不做自动识别
标注截图、窗口选择、区域保存、桌面窗口控制 Tauri IPC 全程由本地 React/Tauri/Rust 处理,不进入 HTTP、WebSocket 或 Go 后端服务
主题、当前 Tab、临时弹窗状态 前端本地状态 纯 UI 状态,不进入业务 API

1.2 服务地址

  • HTTPhttp://127.0.0.1:8766/api/v1
  • WebSocketws://127.0.0.1:8766/api/v1/ws?ticket={singleUseTicket}
  • 现有视觉预览服务使用 127.0.0.1:8765,业务 API 使用 8766,避免端口冲突。
  • 服务必须只监听 loopback不监听局域网地址。

1.3 安全边界

  1. Tauri 启动 sidecar 时生成随机 sessionTokenHTTP 使用 Authorization: Bearer {sessionToken}
  2. WebSocket 不在 URL 中携带长期 token。前端先申请 30 秒有效、单次使用的 ticket
  3. 模型 API Key 进入系统密钥库;任何 GET 响应只返回 keyConfigured,不得返回明文或掩码后的原始值。
  4. 日志禁止记录 API Key、完整系统提示词、无关聊天原文、剪贴板内容和本机绝对文件路径。
  5. 所有资源更新使用 revision 做乐观并发控制;版本不匹配返回 409 REVISION_CONFLICT
  6. 删除知识库、智能体、员工等不可逆操作必须由前端二次确认,并在请求中传 confirmation

2. 通用规范

2.1 数据格式

  • JSON 字段统一使用 camelCase,与 React/Tauri 当前数据结构一致。
  • 时间统一为 UTC RFC 3339例如 2026-07-21T08:30:15.238Z
  • 文件大小统一为整数 sizeBytesKB/MB 仅由前端格式化。
  • 比率统一为 0~1 小数,例如 successRate: 0.984;分数使用 0~100
  • ID 不使用名称,建议前缀:kb_kv_file_agent_employee_distill_test_log_
  • 列表使用 cursor 分页;页面当前数据量虽小,接口仍保持可扩展。

2.2 成功响应

{
  "data": {},
  "meta": {
    "requestId": "req_01J3...",
    "nextCursor": null,
    "total": 6
  }
}
  • 单资源接口可省略 nextCursortotal
  • 204 No Content 用于成功删除且无响应体的场景。

2.3 错误响应

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求字段校验失败",
    "retryable": false,
    "fieldErrors": {
      "title": "知识标题不能为空"
    },
    "details": null
  },
  "requestId": "req_01J3..."
}

常用状态码和错误码:

HTTP code 含义
400 VALIDATION_ERROR 字段格式、枚举或业务前置条件错误
401 UNAUTHORIZED 本机 session token 无效或过期
404 NOT_FOUND 资源不存在或已删除
409 REVISION_CONFLICT 乐观锁版本冲突
409 STATE_CONFLICT 当前状态不允许该操作
413 FILE_TOO_LARGE 文件超过用途限制
415 UNSUPPORTED_FILE_TYPE 文件扩展名、MIME 或内容签名不受支持
422 FILE_PARSE_FAILED 文件上传成功但无法解析
429 RATE_LIMITED 模型或任务并发达到限制
500 INTERNAL_ERROR 未分类内部错误
502 MODEL_UPSTREAM_ERROR 模型供应商错误
504 MODEL_TIMEOUT 模型调用超时

2.4 列表参数

?query=退款&status=enabled&type=file&limit=20&cursor=eyJpZCI6...
参数 类型 默认 说明
query string "" 名称、标签或正文关键字,最大 100 字
status string all 各资源定义的状态枚举
limit integer 20 1~100
cursor string 服务端返回的游标,不允许客户端解析
sort string updatedAt:desc 白名单排序字段与方向

2.5 幂等性

以下 POST 请求必须携带 Idempotency-Key

  • 创建知识库草稿、发布知识版本;
  • 创建智能体、发送测试消息;
  • 创建蒸馏任务、发布员工;
  • 启动或停止引擎。

服务端在 24 小时内对相同 key 和相同请求体返回首次结果;同 key 不同请求体返回 409 IDEMPOTENCY_CONFLICT


3. 核心数据对象

3.1 FileAsset

{
  "id": "file_01J3...",
  "purpose": "knowledge_source",
  "fileName": "refund-policy.pdf",
  "contentType": "application/pdf",
  "extension": "pdf",
  "sizeBytes": 2516582,
  "sha256": "6fe1...",
  "kind": "text",
  "status": "ready",
  "parseStatus": "completed",
  "extractedTextLength": 12680,
  "convertedTextFileId": "filetxt_01J3...",
  "warnings": [
    { "code": "EMBEDDED_IMAGES_SKIPPED", "message": "文档中的 3 张图片已省略" }
  ],
  "error": null,
  "previewStatus": "ready",
  "description": null,
  "descriptionSource": null,
  "createdAt": "2026-07-21T08:30:15.238Z"
}

枚举:

  • purpose: knowledge_source | agent_test_attachment | distill_source | report_export
  • kind: text | image | video | binary
  • status: uploading | uploaded | processing | ready | failed | deleted
  • parseStatus: not_required | queued | processing | completed | failed
  • previewStatus: none | processing | ready | failed
  • descriptionSource: 当前只允许 manual | null,禁止返回 ai | ocr | vision

图片或视频知识文件示例:

{
  "id": "file_01J4...",
  "purpose": "knowledge_source",
  "fileName": "refund-process.png",
  "contentType": "image/png",
  "extension": "png",
  "sizeBytes": 356240,
  "sha256": "7a2d...",
  "kind": "image",
  "status": "ready",
  "parseStatus": "not_required",
  "extractedTextLength": 0,
  "convertedTextFileId": null,
  "warnings": [],
  "error": null,
  "previewStatus": "ready",
  "description": "退款申请、审核和到账三个步骤的流程图。",
  "descriptionSource": "manual",
  "createdAt": "2026-07-21T08:31:15.238Z"
}

3.2 KnowledgeSummary

{
  "id": "kb_refund",
  "title": "售后常见问题与退款边界",
  "type": "file",
  "tags": ["售后", "退款"],
  "status": "enabled",
  "currentVersion": "v1.7",
  "referenceCount": 82,
  "fileCount": 4,
  "updatedAt": "2026-06-05T01:42:00Z",
  "revision": 7
}
  • type: file | image | video | mixed
  • status: draft | processing | enabled | disabled | failed

3.3 AgentSummary

{
  "id": "agent_intent",
  "name": "客户意图识别",
  "type": "builtin",
  "enabled": true,
  "version": "v2.1",
  "tags": ["线索分级", "异议判断", "下一步建议"],
  "knowledgeCount": 3,
  "recentCallCount": 16,
  "lastTestStatus": "passed",
  "updatedAt": "2026-06-16T10:20:00Z",
  "revision": 4
}
  • type: builtin | custom
  • lastTestStatus: not_run | running | passed | failed

3.4 DistillJobSummary

{
  "id": "distill_01J3...",
  "name": "销售冠军 Aileen 话术蒸馏",
  "state": "extracting",
  "stage": "strategy_extraction",
  "progress": 0.72,
  "estimatedRemainingSeconds": 180,
  "sourceCount": 1,
  "successCount": 248,
  "failedCount": 7,
  "createdAt": "2026-07-21T08:30:15.238Z",
  "updatedAt": "2026-07-21T08:34:10.000Z",
  "revision": 9
}
  • state: draft | queued | extracting | evaluating | ready_to_publish | completed | cancelled | failed
  • stage: source_validation | data_cleaning | scene_clustering | strategy_extraction | boundary_induction | counterexample_generation | evaluation | completed

3.5 EmployeeSummary

{
  "id": "employee_1",
  "name": "销售冠军 Aileen",
  "version": "v3.2",
  "enabled": true,
  "traits": ["高意向逼单", "异议拆解", "温和推进"],
  "domain": "private_sales",
  "score": 96,
  "weeklyCallCount": 28,
  "updatedAt": "2026-06-18T09:00:00Z",
  "revision": 3
}

4. 应用初始化与实时连接

4.1 获取启动数据

GET /bootstrap

请求:无 body。

响应:

{
  "data": {
    "apiVersion": "1.0",
    "serverVersion": "0.1.0",
    "platform": "windows",
    "capabilities": {
      "knowledge": true,
      "agents": true,
      "distillation": true,
      "engine": true,
      "nativeAnnotation": true
    },
    "engineState": {
      "lifecycle": "idle",
      "autoSendPaused": false,
      "annotationComplete": true,
      "updatedAt": "2026-07-21T08:30:15.238Z"
    },
    "badges": {
      "clone": 3,
      "knowledge": 0,
      "agents": 1,
      "distill": 0
    }
  }
}

用途:主窗口一次请求获得能力开关、引擎初始状态和底部 Tab badge。主题仍存本地不进入接口。

4.2 申请 WebSocket ticket

POST /realtime-tickets

请求:

{
  "clientId": "desktop-main-7cb8",
  "lastEventId": "evt_01J3...",
  "subscriptions": ["engine", "logs", "distill:distill_01J3", "files:file_01J3"]
}

字段:

字段 类型 必填 说明
clientId string 每个窗口唯一,最大 64 字
lastEventId string/null 断线续传起点
subscriptions string[] 初始订阅频道,最多 50 个

响应:

{
  "data": {
    "ticket": "wst_01J3...",
    "webSocketUrl": "ws://127.0.0.1:8766/api/v1/ws?ticket=wst_01J3...",
    "expiresAt": "2026-07-21T08:30:45.238Z",
    "heartbeatSeconds": 20
  }
}

5. 微信分身、引擎与日志

5.1 引擎状态

GET /engine/state

响应 EngineState

{
  "data": {
    "lifecycle": "running",
    "agent": "running",
    "visionStream": "running",
    "wechatWindow": "connected",
    "annotationComplete": true,
    "autoSendPaused": false,
    "activeConversationId": null,
    "consecutiveErrors": 0,
    "lastError": null,
    "startedAt": "2026-07-21T08:30:15.238Z",
    "updatedAt": "2026-07-21T08:30:18.000Z",
    "revision": 12
  }
}

枚举:

  • lifecycle: idle | checking | starting | running | stopping | error
  • agent / visionStream: stopped | starting | running | error
  • wechatWindow: unknown | connected | missing | changed

5.2 执行启动检查

POST /engine/startup-checks

请求:

{ "forceRefresh": true }

响应 202 Accepted

{
  "data": {
    "runId": "check_01J3...",
    "state": "running",
    "checks": [
      { "id": "config", "label": "基础配置", "status": "waiting", "passed": null, "detail": null },
      { "id": "annotation", "label": "界面标注", "status": "waiting", "passed": null, "detail": null },
      { "id": "window", "label": "微信窗口连接情况", "status": "waiting", "passed": null, "detail": null }
    ]
  }
}

后续通过 engine.startup_check.updated WS 事件返回逐项状态;最终结果也可通过 GET /engine/startup-checks/{runId} 查询。

5.3 启动引擎

POST /engine/start

请求:

{
  "startupCheckRunId": "check_01J3...",
  "expectedRevision": 12
}

响应 202 Accepted:返回最新 EngineState。若检查未通过,返回 409 STARTUP_CHECK_FAILEDdetails.failedCheckIds 指明失败项。

5.4 停止引擎

POST /engine/stop

请求:

{ "expectedRevision": 13, "reason": "operator_request" }

响应 202 Accepted:返回 lifecycle: "stopping"EngineState,最终状态通过 WS 推送。

5.5 暂停或恢复自动发送

PATCH /engine/auto-send

请求:

{ "paused": true, "expectedRevision": 14 }

响应:返回最新 EngineState。当前界面的“暂停自动发送/恢复自动发送”直接绑定此接口。

5.6 日志列表

GET /logs?level=warning&module=model&query=req_91fa&limit=100&cursor=...

响应:

{
  "data": {
    "items": [
      {
        "id": "log_01J3...",
        "time": "2026-07-21T08:30:15.238Z",
        "level": "warning",
        "module": "model",
        "message": "model gateway latency is higher than expected",
        "requestId": "req_91fa",
        "context": {
          "fromSnapshotId": "snapshot_9821",
          "toSnapshotId": "snapshot_9822"
        }
      }
    ]
  },
  "meta": { "requestId": "req_...", "nextCursor": null, "total": 1 }
}
  • level: info | warning | error
  • module: agent | vision | capture | retriever | model | policy | sender

暂停接收仅停止当前窗口的 WS 消费,不调用后端、不暂停引擎。清空视图只清前端缓存,不删除审计日志。

5.7 导出日志

POST /logs/exports

请求:

{
  "filter": { "level": "all", "module": "all", "query": "" },
  "format": "jsonl",
  "from": "2026-07-20T00:00:00Z",
  "to": "2026-07-21T23:59:59Z"
}

响应 202 Accepted

{
  "data": {
    "exportId": "export_01J3...",
    "status": "processing",
    "fileId": null
  }
}

完成后发送 export.completedpayload 中提供 fileId;前端调用 GET /files/{fileId}/content 下载。


6. 文件上传、解析与预览

6.1 用途限制

purpose 支持格式 单文件限制 数量限制
agent_test_attachment PDF、DOCX、PPT、PPTX、TXT、MD、CSV、JSON 20 MB 每条消息最多 5 个
knowledge_source TXT、PDF、DOCX、PPT、PPTX、PNG、JPG/JPEG、GIF、WEBP、MP4、WEBM、MOV 文档/图片 100 MB视频 2 GB 每个草稿最多 100 个
distill_source TXT、MD、CSV、JSON、PDF、DOCX、PPT、PPTX 500 MB 每个任务最多 50 个

服务端必须同时校验扩展名、MIME 和文件头;不能只信任浏览器提交的 contentType

知识文件首期处理边界:

  1. TXT 按 UTF-8 规范化保存PDF 只提取已有文本层DOCX 提取段落和表格文字PPT/PPTX 提取文本框、表格和备注文字。
  2. 文档中的嵌入图片直接省略,不调用 OCR、视觉模型或图片理解。
  3. 图片和视频可以作为独立知识来源上传、保存和预览,但不执行 OCR、图片理解、视频理解、ASR、关键帧提取或自动摘要。
  4. 图片和视频的 description 只能由操作者人工填写,descriptionSource 固定为 manual;后端不得自动生成或补全描述。
  5. 媒体文件有人工描述时,知识检索只索引标题、标签和人工描述;没有描述时只索引标题和标签,原始媒体内容不进入文本检索。
  6. 扫描版 PDF 或只有图片、没有可提取文字的 Office 文档返回 422 NO_EXTRACTABLE_TEXT,不能标记为文档转换成功。
  7. 文档转换结果生成独立 UTF-8 .txt 文件,并通过 convertedTextFileId 关联原文件;知识版本正文由转换后的 TXT 和媒体人工描述组成。

6.2 小文件直接上传

POST /files

Content-Typemultipart/form-data

表单字段:

字段 类型 必填 说明
file binary 文件内容
purpose enum 上述用途
clientFileId string 前端本次选择生成的 UUID用于去重
sha256 string 客户端可计算时传入

响应 201 Created:返回 FileAsset。文本类文件通常返回 parseStatus: "queued",不能把上传成功展示成解析成功。

6.3 大文件分片初始化

POST /file-uploads

请求:

{
  "purpose": "knowledge_source",
  "fileName": "product-training.mp4",
  "contentType": "video/mp4",
  "sizeBytes": 734003200,
  "sha256": "可选整体哈希",
  "clientFileId": "8fb2a9e5-..."
}

响应:

{
  "data": {
    "uploadId": "upload_01J3...",
    "chunkSizeBytes": 8388608,
    "uploadedParts": [],
    "expiresAt": "2026-07-22T08:30:15.238Z"
  }
}

6.4 上传分片

PUT /file-uploads/{uploadId}/parts/{partNumber}

Headers

Content-Type: application/octet-stream
Content-Length: 8388608
Content-Range: bytes 0-8388607/734003200
X-Chunk-SHA256: 1c9e...

响应:

{
  "data": {
    "partNumber": 1,
    "sizeBytes": 8388608,
    "sha256": "1c9e...",
    "accepted": true
  }
}

重复上传同一分片且哈希相同必须幂等;哈希不同返回 409 CHUNK_CONFLICT

6.5 完成分片上传

POST /file-uploads/{uploadId}/complete

请求:

{
  "parts": [
    { "partNumber": 1, "sha256": "1c9e..." },
    { "partNumber": 2, "sha256": "41af..." }
  ]
}

响应 201 Created:返回 FileAsset

6.6 查询和取消上传

  • GET /file-uploads/{uploadId}:返回已上传分片,用于断点续传。
  • DELETE /file-uploads/{uploadId}:删除临时分片,返回 204

6.7 查询文件

GET /files/{fileId}:返回 FileAsset

文件解析过程通过 WS 推送 file.processing.updated

{
  "fileId": "file_01J3...",
  "status": "processing",
  "parseStatus": "processing",
  "progress": 0.64,
  "stage": "extracting_text",
  "extractedTextLength": 0,
  "error": null
}

6.8 文档转换与媒体预览

  • GET /files/{fileId}/text?offset=0&limit=20000:分页预览文档转换后的纯文本。
  • GET /files/{fileId}/text-file:下载 UTF-8 .txt 转换结果,响应为 text/plain; charset=utf-8
  • GET /files/{fileId}/content:下载原文件或预览图片、视频;支持 Range
  • PATCH /files/{fileId}:只用于操作者保存图片或视频的人工描述。

文档转换规则:

  • PDF 只读取文本层,不对页面截图或扫描内容执行 OCR。
  • DOCX 中的段落、表格文本按文档顺序输出;图片、形状内不可直接读取的图像文字省略。
  • PPT/PPTX 中的文本框、表格和备注按页输出;每页使用稳定页码分隔,图片内容省略。
  • 成功提取到正文但省略了图片时,parseStatuscompleted,同时返回 EMBEDDED_IMAGES_SKIPPED warning。
  • 没有任何可提取正文时,parseStatusfailederror.codeNO_EXTRACTABLE_TEXT

媒体处理规则:

  • 图片、视频上传完成并通过文件安全校验后,parseStatus 固定为 not_required
  • 服务端只生成安全预览能力,不识别画面、不抽取文字、不识别语音、不生成描述。
  • description 完全来自人工输入,服务端原样保存;空描述允许保存,但媒体内容本身不会进入 FTS5 正文索引。

PATCH /files/{fileId} 请求:

{
  "description": "退款申请、审核和到账三个步骤的流程图。",
  "descriptionSource": "manual",
  "expectedRevision": 1
}

服务端必须拒绝 descriptionSource 不是 manual 的请求;响应返回最新 FileAsset

文本响应:

{
  "data": {
    "fileId": "file_01J3...",
    "text": "第一章 退款申请范围……",
    "offset": 0,
    "returnedLength": 12680,
    "totalLength": 12680,
    "truncated": false
  }
}

6.9 删除文件

DELETE /files/{fileId}?expectedRevision=1

  • 未绑定草稿或消息时返回 204
  • 已被已发布版本引用时返回 409 FILE_IN_USE,不能物理删除。

7. 知识库接口

7.1 知识库列表与全文搜索

GET /knowledge-bases?query=退款&status=all&limit=20&cursor=...

响应:data.items: KnowledgeSummary[]

搜索范围由设置中的 knowledgeSearchFields 决定;页面输入“标题、标签或完整正文”时,服务端返回匹配后的知识库摘要,不把完整正文放进列表响应。

7.2 创建草稿

POST /knowledge-drafts

请求:

{
  "mode": "create",
  "knowledgeId": null,
  "baseVersion": null,
  "title": "售后退款政策",
  "description": "用于回答售后退款范围、异常订单与客户安抚相关问题。",
  "tags": ["私域成交", "售后"]
}

更新知识库时:

{
  "mode": "update",
  "knowledgeId": "kb_refund",
  "baseVersion": "v1.7"
}

响应:

{
  "data": {
    "id": "kbdraft_01J3...",
    "mode": "create",
    "knowledgeId": null,
    "baseVersion": null,
    "title": "售后退款政策",
    "description": "用于回答……",
    "tags": ["私域成交", "售后"],
    "fileIds": [],
    "state": "draft",
    "revision": 1,
    "updatedAt": "2026-07-21T08:30:15.238Z"
  }
}

7.3 保存草稿基本信息

PATCH /knowledge-drafts/{draftId}

请求:

{
  "title": "售后退款政策",
  "description": "用于回答售后问题。",
  "tags": ["私域成交", "售后"],
  "expectedRevision": 1
}

校验:title 1100 字;description 最大 2000 字;标签最多 20 个,每个 130 字,去重后保存。

响应:返回完整草稿和递增后的 revision

7.4 绑定或移除来源文件

POST /knowledge-drafts/{draftId}/files

{
  "fileIds": ["file_01J3...", "file_01J4..."],
  "expectedRevision": 2
}

响应:

{
  "data": {
    "draftId": "kbdraft_01J3...",
    "files": [{ "id": "file_01J3...", "fileName": "refund-policy.pdf", "sizeBytes": 2516582, "kind": "text", "status": "ready", "parseStatus": "completed" }],
    "readyCount": 1,
    "processingCount": 1,
    "failedCount": 0,
    "revision": 3
  }
}

DELETE /knowledge-drafts/{draftId}/files/{fileId}?expectedRevision=3:从草稿移除,返回更新后的文件汇总。

7.5 草稿预览汇总

GET /knowledge-drafts/{draftId}/preview

响应:

{
  "data": {
    "draftId": "kbdraft_01J3...",
    "sourceCount": 3,
    "ready": true,
    "files": [{ "id": "file_01J3...", "fileName": "refund-policy.pdf", "sizeBytes": 2516582, "kind": "text", "status": "ready", "parseStatus": "completed" }],
    "totalTextLength": 26000,
    "blockingErrors": []
  }
}

ready 只有在至少一个来源且所有必需解析完成时为 true

7.6 发布知识库或保存新版本

POST /knowledge-drafts/{draftId}/publish

请求:

{
  "versionNote": "补充异常订单处理边界",
  "enableAfterPublish": true,
  "expectedRevision": 4
}

响应 201 Created

{
  "data": {
    "knowledge": { "id": "kb_refund", "title": "售后常见问题与退款边界", "type": "file", "tags": ["售后", "退款"], "status": "enabled", "currentVersion": "v1.8", "referenceCount": 0, "fileCount": 1, "updatedAt": "2026-07-21T08:40:00Z", "revision": 1 },
    "version": {
      "id": "kv_01J3...",
      "knowledgeId": "kb_refund",
      "version": "v1.8",
      "versionNote": "补充异常订单处理边界",
      "fileIds": ["file_01J3..."],
      "textLength": 26000,
      "contentHash": "5c82...",
      "createdAt": "2026-07-21T08:40:00Z"
    }
  }
}

版本号由服务端生成,客户端不得自行加一。若 baseVersion 已落后,返回 409 REVISION_CONFLICT

7.7 知识库详情

GET /knowledge-bases/{knowledgeId}

响应:

{
  "data": {
    "id": "kb_refund",
    "title": "售后常见问题与退款边界",
    "description": "涵盖退款期限、数字商品限制、异常订单处理和安抚话术边界。",
    "tags": ["售后", "退款"],
    "type": "file",
    "status": "enabled",
    "currentVersion": "v1.7",
    "creator": { "id": "local_operator", "displayName": "本机管理员" },
    "effectiveAt": "2026-06-05T01:42:00Z",
    "lastRetrievedAt": "2026-07-21T08:18:00Z",
    "metrics": {
      "weeklyHitCount": 32,
      "agentReferenceCount": 3,
      "employeeBindingCount": 2,
      "textLength": 26000
    },
    "revision": 7,
    "updatedAt": "2026-06-05T01:42:00Z"
  }
}

7.8 详情子资源

  • GET /knowledge-bases/{id}/files:当前版本的 FileAsset[]
  • GET /knowledge-bases/{id}/references?type=all:引用关系。
  • GET /knowledge-bases/{id}/versions?limit=20&cursor=...:版本历史。

引用关系项:

{
  "resourceType": "agent",
  "resourceId": "agent_quote",
  "name": "报价策略生成",
  "enabled": true,
  "boundVersion": "v1.7"
}

版本项:

{
  "id": "kv_01J3...",
  "version": "v1.7",
  "versionNote": "修正数字商品退款边界",
  "isCurrent": true,
  "createdAt": "2026-06-05T01:42:00Z"
}

7.9 启停和删除

PATCH /knowledge-bases/{id}/status

{ "enabled": false, "expectedRevision": 7 }

响应:返回最新 KnowledgeSummary。停用后已绑定关系保留,但检索时不能命中。

DELETE /knowledge-bases/{id}

{
  "confirmation": "售后常见问题与退款边界",
  "expectedRevision": 8
}

有引用关系时默认返回 409 RESOURCE_IN_USE 和引用摘要;不提供静默级联删除。


8. 智能体接口

8.1 列表

GET /agents?query=报价&type=all&enabled=all&limit=20&cursor=...

响应:data.items: AgentSummary[]

筛选枚举:type=all|builtin|customenabled=all|true|false

8.2 创建智能体草稿

POST /agent-drafts

请求:

{
  "mode": "create",
  "agentId": null,
  "name": "报价策略生成",
  "description": "根据客户意向、商品成本和优惠边界生成报价建议。",
  "tags": ["利润保护", "阶梯报价", "优惠边界"]
}

更新模式传 mode: "update"agentId。响应:

{
  "data": {
    "id": "agentdraft_01J3...",
    "mode": "create",
    "agentId": null,
    "name": "报价策略生成",
    "description": "根据客户意向……",
    "tags": ["利润保护", "阶梯报价", "优惠边界"],
    "systemPrompt": "",
    "knowledgeIds": [],
    "lastTestSessionId": null,
    "lastTestStatus": "not_run",
    "revision": 1
  }
}

8.3 保存基本信息、提示词和授权

PATCH /agent-drafts/{draftId}

请求可部分更新:

{
  "name": "报价策略生成",
  "description": "根据客户意向、商品成本和优惠边界生成报价建议。",
  "tags": ["利润保护", "阶梯报价", "优惠边界"],
  "systemPrompt": "你是报价策略助手……",
  "knowledgeIds": ["kb_price", "kb_discount"],
  "expectedRevision": 1
}

校验:名称 1~80 字;描述最大 2000 字;标签最多 20 个;系统提示词最大 20000 字;只能授权已生效知识库。

响应:返回完整草稿和新 revision

8.4 发布或更新智能体

POST /agent-drafts/{draftId}/publish

请求:

{
  "releaseNote": "首次发布报价策略生成智能体。",
  "enableAfterPublish": true,
  "expectedRevision": 3
}

前置条件:lastTestStatus 必须为 passed,且测试使用的 draftRevision 必须等于当前草稿 revision提示词或授权变更后旧测试失效。

响应:

{
  "data": {
    "agent": { "id": "agent_quote", "name": "报价策略生成", "type": "custom", "enabled": true, "version": "v1.0", "tags": ["利润保护", "阶梯报价", "优惠边界"], "knowledgeCount": 2, "recentCallCount": 0, "lastTestStatus": "passed", "updatedAt": "2026-07-21T08:50:00Z", "revision": 1 },
    "release": {
      "version": "v1.0",
      "releaseNote": "首次发布报价策略生成智能体。",
      "createdAt": "2026-07-21T08:50:00Z"
    }
  }
}

8.5 详情

GET /agents/{agentId}

响应:

{
  "data": {
    "id": "agent_intent",
    "name": "客户意图识别",
    "type": "builtin",
    "enabled": true,
    "version": "v2.1",
    "description": "识别客户所处阶段、购买意向、核心异议,并输出下一步跟进建议。",
    "tags": ["线索分级", "异议判断", "下一步建议"],
    "systemPrompt": "你是报价策略助手……",
    "permissions": [
      { "code": "knowledge.query", "label": "查询知识库", "granted": true },
      { "code": "conversation.read_current", "label": "读取当前会话", "granted": true },
      { "code": "message.send", "label": "直接发送消息", "granted": false }
    ],
    "knowledge": [
      { "id": "kb_refund", "title": "售后退款政策", "version": "v1.7", "enabled": true }
    ],
    "metrics": {
      "recentCallCount": 16,
      "successRate": 0.984,
      "averageLatencyMs": 1200,
      "knowledgeCount": 3
    },
    "updatedAt": "2026-06-16T10:20:00Z",
    "revision": 4
  }
}

8.6 权限和测试记录

  • GET /agents/{id}/permissions:返回上述 permissionsknowledge
  • GET /agents/{id}/test-records?limit=20&cursor=...

测试记录项:

{
  "id": "test_01J3...",
  "scenario": "高意向询价",
  "status": "passed",
  "latencyMs": 1200,
  "draftRevision": 3,
  "createdAt": "2026-06-18T09:30:00Z",
  "error": null
}

8.7 启停和删除

PATCH /agents/{id}/status

{ "enabled": false, "expectedRevision": 4 }

DELETE /agents/{id}

{
  "confirmation": "客户意图识别",
  "expectedRevision": 5
}

内置智能体可按产品规则返回 403 BUILTIN_AGENT_READ_ONLY;若允许删除,必须明确为隐藏/禁用而非物理删除。


9. 智能体测试会话与 WebSocket 流式回复

9.1 创建测试会话

POST /agent-test-sessions

请求:

{
  "agentId": "agent_intent",
  "draftId": null,
  "draftRevision": null,
  "mode": "published"
}

编辑器沙箱传:

{
  "agentId": null,
  "draftId": "agentdraft_01J3...",
  "draftRevision": 3,
  "mode": "draft"
}

响应:

{
  "data": {
    "sessionId": "testsession_01J3...",
    "state": "ready",
    "channel": "agent-test:testsession_01J3...",
    "maxFilesPerMessage": 5,
    "maxFileSizeBytes": 20971520,
    "acceptedExtensions": ["pdf", "docx", "ppt", "pptx", "txt", "md", "csv", "json"],
    "expiresAt": "2026-07-21T10:00:00Z"
  }
}

9.2 发送测试消息

使用 WebSocket command不把文件二进制放进 WS。附件必须先通过 POST /files 上传。

{
  "type": "agent.test.message.send",
  "requestId": "client_req_8",
  "payload": {
    "sessionId": "testsession_01J3...",
    "clientMessageId": "bce8e547-...",
    "content": "客户预算为 10000 元,可以如何报价?",
    "fileIds": ["file_01J3..."]
  }
}

校验:contentfileIds 至少一个非空;内容最大 20000 字;附件最多 5 个;附件 purpose 必须为 agent_test_attachment 且解析完成。

服务端事件顺序:

  1. agent.test.message.accepted
  2. 零到多个 agent.test.message.delta
  3. agent.test.message.completedagent.test.message.failed

accepted

{
  "sessionId": "testsession_01J3...",
  "messageId": "msg_01J3...",
  "clientMessageId": "bce8e547-...",
  "assistantMessageId": "msg_01J4...",
  "acceptedAt": "2026-07-21T08:55:00Z"
}

delta

{
  "sessionId": "testsession_01J3...",
  "assistantMessageId": "msg_01J4...",
  "sequence": 7,
  "delta": "建议先核对",
  "accumulatedLength": 28
}

completed

{
  "sessionId": "testsession_01J3...",
  "assistantMessageId": "msg_01J4...",
  "content": "建议先核对客户需求……",
  "finishReason": "stop",
  "usage": { "inputTokens": 412, "outputTokens": 96 },
  "latencyMs": 1320,
  "testResult": {
    "status": "passed",
    "draftRevision": 3,
    "warnings": []
  },
  "completedAt": "2026-07-21T08:55:01.320Z"
}

failed

{
  "sessionId": "testsession_01J3...",
  "assistantMessageId": "msg_01J4...",
  "code": "MODEL_TIMEOUT",
  "message": "模型在 8000ms 内未返回",
  "retryable": true
}

9.3 历史与取消

  • GET /agent-test-sessions/{sessionId}/messages?limit=100&cursor=...:恢复弹窗后的对话。
  • WS command agent.test.generation.cancel{ sessionId, assistantMessageId }
  • DELETE /agent-test-sessions/{sessionId}:结束会话并清理未引用测试附件。

消息对象:

{
  "id": "msg_01J3...",
  "role": "user",
  "content": "客户预算为 10000 元",
  "files": [
    { "id": "file_01J3...", "fileName": "budget.txt", "sizeBytes": 126 }
  ],
  "state": "completed",
  "createdAt": "2026-07-21T08:55:00Z"
}

10. 蒸馏任务接口

10.1 当前任务和员工列表

  • GET /distill-jobs?state=active&limit=10:返回 DistillJobSummary[],用于“当前任务”。
  • GET /employees?query=Aileen&enabled=all&limit=20&cursor=...:返回 EmployeeSummary[]

10.2 创建蒸馏草稿

POST /distill-drafts

请求:

{
  "name": "销售冠军 Aileen 话术蒸馏",
  "minimumValidConversations": 50
}

响应:

{
  "data": {
    "id": "distilldraft_01J3...",
    "name": "销售冠军 Aileen 话术蒸馏",
    "fileIds": [],
    "minimumValidConversations": 50,
    "state": "draft",
    "revision": 1
  }
}

10.3 绑定上传文件

POST /distill-drafts/{draftId}/files

{
  "fileIds": ["file_01J3..."],
  "expectedRevision": 1
}

响应:返回草稿、文件列表和有效内容统计:

{
  "data": {
    "draftId": "distilldraft_01J3...",
    "files": [{ "id": "file_01J3...", "fileName": "champion-scripts.docx", "sizeBytes": 245760, "kind": "text", "status": "ready", "parseStatus": "completed" }],
    "statistics": {
      "validConversationCount": 1286,
      "scriptCount": 38,
      "invalidRecordCount": 7
    },
    "revision": 2
  }
}

当前来源页只保留文件上传;不设计导入微信聊天、选择已有案例或日期范围字段。

10.4 保存草稿

PATCH /distill-drafts/{draftId}

{
  "name": "销售冠军 Aileen 话术蒸馏",
  "minimumValidConversations": 50,
  "expectedRevision": 2
}

响应:返回完整草稿。

10.5 开始能力提取

POST /distill-drafts/{draftId}/start

{ "expectedRevision": 3 }

响应 202 Accepted:返回 DistillJobSummary。文件未解析完成、有效记录不足或草稿为空时返回 400 VALIDATION_ERROR

任务进度通过 distill.progress.updated 推送:

{
  "jobId": "distill_01J3...",
  "state": "extracting",
  "stage": "strategy_extraction",
  "stageLabel": "策略提取",
  "progress": 0.72,
  "processedCount": 1286,
  "totalCount": 1286,
  "stageCurrent": 13,
  "stageTotal": 18,
  "estimatedRemainingSeconds": 180,
  "recognizedCapabilities": ["高意向识别", "异议拆解", "温和推进", "优惠边界", "长期跟进"],
  "updatedAt": "2026-07-21T09:05:00Z",
  "revision": 9
}

10.6 查询任务详情

GET /distill-jobs/{jobId}

响应:

{
  "data": {
    "summary": { "id": "distill_01J3...", "name": "销售冠军 Aileen 话术蒸馏", "state": "extracting", "stage": "strategy_extraction", "progress": 0.72, "estimatedRemainingSeconds": 180, "sourceCount": 1, "successCount": 248, "failedCount": 7, "createdAt": "2026-07-21T08:30:15.238Z", "updatedAt": "2026-07-21T08:34:10Z", "revision": 9 },
    "stages": [
      { "code": "data_cleaning", "label": "数据清洗", "state": "completed", "current": 1286, "total": 1286 },
      { "code": "scene_clustering", "label": "场景聚类", "state": "completed", "current": 18, "total": 18 },
      { "code": "strategy_extraction", "label": "策略提取", "state": "running", "current": 13, "total": 18 },
      { "code": "boundary_induction", "label": "边界归纳", "state": "waiting", "current": 0, "total": null },
      { "code": "counterexample_generation", "label": "反例生成", "state": "waiting", "current": 0, "total": null }
    ],
    "recognizedCapabilities": ["高意向识别", "异议拆解", "温和推进", "优惠边界", "长期跟进"],
    "error": null
  }
}

页面已移除失败样本入口,因此不提供面向 UI 的失败样本明细接口;failedCount 只作为任务健康摘要和日志字段。

10.7 效果评估

GET /distill-jobs/{jobId}/evaluation

响应:

{
  "data": {
    "jobId": "distill_01J3...",
    "state": "completed",
    "overallScore": 92,
    "publishThreshold": 85,
    "publishable": true,
    "metrics": {
      "sceneHitRate": 0.94,
      "refusalAccuracy": 0.91,
      "overreachRate": 0.003,
      "consistency": 0.89
    },
    "cases": [
      { "id": "case_1", "name": "高意向询价", "result": "建议合理", "passed": true },
      { "id": "case_2", "name": "超边界优惠", "result": "已拒绝越权", "passed": true },
      { "id": "case_3", "name": "售后退款混合场景", "result": "回答包含不确定信息", "passed": false }
    ],
    "completedAt": "2026-07-21T09:10:00Z"
  }
}

POST /distill-jobs/{jobId}/evaluation-runs:重新评估,响应 202,进度通过 WS 推送。

POST /distill-jobs/{jobId}/evaluation-exports:生成报告,响应结构同日志导出。

10.8 发布员工

POST /distill-jobs/{jobId}/publish

请求:

{
  "name": "销售冠军 Aileen",
  "domain": "private_sales",
  "agentIds": ["agent_intent", "agent_quote"],
  "knowledgeIds": ["kb_price", "kb_discount", "kb_refund"],
  "enableAfterPublish": true,
  "expectedRevision": 11
}
  • domain: private_sales | b2b_consulting | after_sales
  • 至少一个授权能力;知识授权可为空;只允许授权已启用资源。

响应 201 Created

{
  "data": {
    "employee": { "id": "employee_1", "name": "销售冠军 Aileen", "version": "v1.0", "enabled": true, "traits": ["高意向识别", "异议拆解"], "domain": "private_sales", "score": 92, "weeklyCallCount": 0, "updatedAt": "2026-07-21T09:15:00Z", "revision": 1 },
    "sourceJobId": "distill_01J3...",
    "publishedAt": "2026-07-21T09:15:00Z"
  }
}

10.9 取消任务

POST /distill-jobs/{jobId}/cancel

{ "expectedRevision": 9, "reason": "operator_request" }

queued | extracting | evaluating 可取消。响应返回 state: "cancelled" 的任务摘要。


11. 员工详情接口

11.1 详情

GET /employees/{employeeId}

响应:

{
  "data": {
    "id": "employee_1",
    "name": "销售冠军 Aileen",
    "version": "v3.2",
    "enabled": true,
    "domain": "private_sales",
    "traits": ["高意向逼单", "异议拆解", "温和推进"],
    "profile": {
      "applicableScenario": "已有明确需求、处于报价或决策阶段的私域客户",
      "prohibitedBehavior": "承诺未授权折扣、绕过人工确认直接发送敏感信息"
    },
    "metrics": {
      "overallScore": 96,
      "weeklyCallCount": 28,
      "adoptionRate": 0.82,
      "exceptionCount": 1
    },
    "agentBindings": [
      { "id": "agent_intent", "name": "客户意图识别", "granted": true }
    ],
    "knowledgeBindings": [
      { "id": "kb_price", "title": "产品价格表", "bound": true }
    ],
    "updatedAt": "2026-06-18T09:00:00Z",
    "revision": 3
  }
}

11.2 启停、画像和授权

PATCH /employees/{id}/status

{ "enabled": false, "expectedRevision": 3 }

PATCH /employees/{id}/profile

{
  "name": "销售冠军 Aileen",
  "domain": "private_sales",
  "traits": ["高意向逼单", "异议拆解", "温和推进"],
  "applicableScenario": "已有明确需求、处于报价或决策阶段的私域客户",
  "prohibitedBehavior": "承诺未授权折扣",
  "expectedRevision": 4
}

PUT /employees/{id}/bindings

{
  "agentIds": ["agent_intent", "agent_quote"],
  "knowledgeIds": ["kb_price", "kb_discount", "kb_sales_champion"],
  "expectedRevision": 5
}

均返回最新员工详情。

11.3 详情页各 Tab

  • GET /employees/{id}/evaluation:结构同蒸馏评估摘要。
  • GET /employees/{id}/versions?limit=20&cursor=...
  • GET /employees/{id}/calls?limit=50&cursor=...

调用记录项:

{
  "id": "call_01J3...",
  "time": "2026-07-21T04:26:00Z",
  "scenario": "高意向询价",
  "result": "suggestion_adopted",
  "resultLabel": "建议已采纳",
  "requestId": "req_01J3..."
}

11.4 重新蒸馏和复制

POST /employees/{id}/redistill

{ "baseVersion": "v3.2" }

响应 201:返回预填的 distillDraftId

POST /employees/{id}/clone

{ "name": "销售冠军 Aileen 副本", "copyBindings": true }

响应 201:返回新员工详情,默认 enabled: false


12. 设置接口

12.1 获取全部配置

GET /settings

响应:

{
  "data": {
    "revision": 12,
    "model": {
      "provider": "volcengine",
      "endpoint": "https://ark.cn-beijing.volces.com/api/v3",
      "modelName": "doubao-pro-32k",
      "requestTimeoutMs": 8000,
      "keyConfigured": true,
      "keyUpdatedAt": "2026-07-20T09:00:00Z"
    },
    "prompt": {
      "fixedPrompt": "你是本地微信分身助手,需要遵守托管策略、回复边界与用户授权。",
      "customPrompt": "保持友好、简洁、可信赖。优先调用知识库和已授权员工能力。",
      "customPromptMaxLength": 4000
    },
    "replyRules": {
      "quietHoursEnabled": false,
      "quietHours": { "start": "22:00", "end": "08:00", "timezone": "Asia/Shanghai" },
      "autoAddFriend": false,
      "proactiveContact": false,
      "distillationEnabled": true
    },
    "featureGates": {
      "agentsEnabled": true,
      "employeesEnabled": true,
      "knowledgeEnabled": true
    },
    "knowledgeSearch": {
      "algorithm": "sqlite_fts5_bm25",
      "maxResults": 5,
      "fields": ["title", "tags", "fullText"],
      "activeKnowledgeIds": ["kb_sales_champion", "kb_refund"]
    },
    "hosting": {
      "enabled": false,
      "localMessageServiceEnabled": true,
      "confirmBeforeSend": true,
      "abnormalPauseEnabled": true,
      "consecutiveErrorLimit": 3,
      "messageWaitSeconds": 30
    },
    "updatedAt": "2026-07-21T08:00:00Z"
  }
}

12.2 保存配置

PUT /settings

请求传完整可编辑配置,但不传 fixedPromptkeyConfiguredkeyUpdatedAt

{
  "expectedRevision": 12,
  "model": {
    "provider": "volcengine",
    "endpoint": "https://ark.cn-beijing.volces.com/api/v3",
    "modelName": "doubao-pro-32k",
    "requestTimeoutMs": 8000
  },
  "prompt": {
    "customPrompt": "保持友好、简洁、可信赖。"
  },
  "replyRules": {
    "quietHoursEnabled": false,
    "quietHours": { "start": "22:00", "end": "08:00", "timezone": "Asia/Shanghai" },
    "autoAddFriend": false,
    "proactiveContact": false,
    "distillationEnabled": true
  },
  "featureGates": {
    "agentsEnabled": true,
    "employeesEnabled": true,
    "knowledgeEnabled": true
  },
  "knowledgeSearch": {
    "maxResults": 5,
    "fields": ["title", "tags", "fullText"],
    "activeKnowledgeIds": ["kb_sales_champion", "kb_refund"]
  },
  "hosting": {
    "enabled": false,
    "localMessageServiceEnabled": true,
    "confirmBeforeSend": true,
    "abnormalPauseEnabled": true,
    "consecutiveErrorLimit": 3,
    "messageWaitSeconds": 30
  }
}

响应:完整最新配置。前端“恢复”必须恢复最近一次 GET/PUT 成功的数据,不能只清除 dirty 状态。

12.3 API Key

PUT /settings/model-api-key

{ "apiKey": "真实密钥" }

响应:

{
  "data": {
    "keyConfigured": true,
    "keyUpdatedAt": "2026-07-21T09:30:00Z"
  }
}

DELETE /settings/model-api-key:返回 204。密钥只在此 PUT 请求中出现一次。

12.4 测试模型连接

POST /settings/model-connection-tests

使用当前未保存表单值:

{
  "provider": "volcengine",
  "endpoint": "https://ark.cn-beijing.volces.com/api/v3",
  "modelName": "doubao-pro-32k",
  "requestTimeoutMs": 8000,
  "useStoredApiKey": true
}

响应:

{
  "data": {
    "success": true,
    "latencyMs": 324,
    "provider": "volcengine",
    "modelName": "doubao-pro-32k",
    "checkedAt": "2026-07-21T09:31:00Z"
  }
}

失败时仍返回对应 HTTP 错误和明确 codeMODEL_AUTH_FAILED | MODEL_NOT_FOUND | MODEL_TIMEOUT | MODEL_NETWORK_UNREACHABLE

12.5 组合提示词预览

POST /settings/prompt-previews

{ "customPrompt": "保持友好、简洁、可信赖。" }

响应:

{
  "data": {
    "fixedPrompt": "你是本地微信分身助手……",
    "customPrompt": "保持友好、简洁、可信赖。",
    "combinedPrompt": "你是本地微信分身助手……\n\n保持友好、简洁、可信赖。",
    "characterCount": 52
  }
}

12.6 黑白名单

GET /contact-lists?type=allow|block&query=张三

响应项:

{
  "id": "contact_rule_01J3...",
  "type": "allow",
  "displayName": "张三",
  "headerFingerprint": "sha256:...",
  "source": "manual",
  "createdAt": "2026-07-21T09:32:00Z"
}

POST /contact-lists

{
  "type": "allow",
  "displayName": "张三",
  "headerFingerprint": "sha256:...",
  "source": "manual"
}

DELETE /contact-lists/{ruleId}:返回 204

仅名称不足以稳定识别微信会话;生产数据必须包含当前会话头生成的 headerFingerprint

12.7 管理页逐项开关

以下接口复用资源状态,不额外创建第二套启停数据:

  • 智能体:PATCH /agents/{id}/status
  • 员工:PATCH /employees/{id}/status
  • 知识库:PATCH /knowledge-bases/{id}/status
  • 三个总开关:PUT /settings 中的 featureGates

13. WebSocket 通用协议

13.1 连接和订阅

连接成功事件:

{
  "eventId": "evt_01J3...",
  "type": "connection.ready",
  "occurredAt": "2026-07-21T09:35:00Z",
  "payload": {
    "clientId": "desktop-main-7cb8",
    "heartbeatSeconds": 20,
    "resumeAccepted": true
  }
}

客户端订阅:

{
  "type": "subscribe",
  "requestId": "client_req_1",
  "payload": {
    "channels": ["engine", "logs", "distill:distill_01J3", "files:file_01J3"]
  }
}

服务端确认:

{
  "eventId": "evt_01J4...",
  "type": "ack",
  "occurredAt": "2026-07-21T09:35:00.010Z",
  "requestId": "client_req_1",
  "payload": { "acceptedChannels": ["engine", "logs", "distill:distill_01J3", "files:file_01J3"] }
}

13.2 服务端事件包络

{
  "eventId": "evt_01J5...",
  "type": "engine.state.changed",
  "occurredAt": "2026-07-21T09:35:01Z",
  "requestId": "req_01J3...",
  "resource": { "type": "engine", "id": "local" },
  "payload": {}
}

13.3 事件清单

type channel payload
engine.state.changed engine 完整 EngineState,不是局部 patch
engine.startup_check.updated engine runIdstate、完整 checks[]
engine.annotation.changed engine annotationCompleterevisionupdatedAt
log.appended logs 单条完整 LogEvent
file.processing.updated files:{fileId} 文件处理进度对象
knowledge.changed knowledge:{id} KnowledgeSummary
agent.changed agent:{id} AgentSummary
agent.test.message.accepted agent-test:{sessionId} 消息受理对象
agent.test.message.delta agent-test:{sessionId} token 增量对象
agent.test.message.completed agent-test:{sessionId} 完成对象
agent.test.message.failed agent-test:{sessionId} 错误对象
distill.progress.updated distill:{jobId} 完整进度对象
distill.evaluation.updated distill:{jobId} 评估状态和结果摘要
employee.changed employee:{id} EmployeeSummary
settings.changed settings revisionchangedSections[];前端收到后重新 GET
export.completed exports:{exportId} exportIdstatusfileIderror

13.4 心跳、重连和顺序

  • 服务端每 20 秒发送 ping,客户端 10 秒内返回 pong
  • 事件在单连接内按 eventId 顺序发送;业务顺序以资源 revision 为准。
  • 前端忽略 revision 小于当前状态的迟到事件。
  • 断线后指数退避1s、2s、4s、8s最大 15s。
  • 重连时用最后一个已处理 eventId 申请新 ticket事件缓存建议保留 10 分钟。
  • 无法续传时 connection.ready.payload.resumeAccepted=false,前端必须重新 GET 当前页面资源。
  • WS 只负责通知和流式增量;创建、更新、删除仍由 HTTP 完成。

14. Tauri 原生 IPC不得改成 HTTP/WS 的能力

这些接口仍是 API 契约,但调用形式只允许 invoke(command, payload)。标注调试全程在本机 React/Tauri/Rust 内完成,直接操作本机窗口、截图和应用生命周期。

本地边界:

  1. src/pages/AnnotationPage.jsxsrc/overlay.js 不调用业务 HTTP 或 WebSocket。
  2. 截图字节、截图路径、窗口句柄、窗口元数据、标注区域和未保存会话状态不得发送给 Go 后端服务。
  3. Go 后端不提供标注调试接口,也不读取标注调试状态;保存和加载只通过 Tauri/Rust 本地存储。
  4. Tauri event 只在本机 WebView 窗口之间传递,不桥接到业务 WebSocket。

14.1 标注区域对象

{
  "id": "region_01J3...",
  "name": "聊天内容",
  "type": "chat_content",
  "description": "微信当前会话消息区",
  "bbox_image": [120, 180, 860, 1240],
  "bbox_source": [80, 120, 573.333, 826.667],
  "bbox_screen": [420, 280, 1160, 1340],
  "scaleFactor": 1.5
}

坐标统一为 XYXY[x1, y1, x2, y2]。生产必需类型:

  • conversation_header
  • chat_content
  • input_box
  • send_button

custom 只能附加,不能代替必需类型。

14.2 IPC 命令

command 请求 返回
enter_window_select_mode {} { mode: "window_select" }
capture_screen {} CaptureResult
read_screenshot_bytes { path } number[] 或二进制 buffer
load_regions {} `AnnotationConfig
save_regions { annotation: AnnotationConfig } { path, revision, updatedAt }
start_vision_stream {} { state: "running" }
stop_vision_stream {} { state: "stopped" }
start_agent {} { state: "running" }
stop_agent {} { state: "stopped" }
open_popup_window { route } { label }
close_current_window {} null
exit_application {} null

CaptureResult

{
  "screenshotPath": "受限应用数据目录中的路径",
  "screenshotWidth": 1440,
  "screenshotHeight": 900,
  "scaleFactor": 1.5,
  "source": {
    "id": "win-window:12345",
    "kind": "window",
    "label": "WeChat",
    "appName": "WeChat.exe",
    "title": "微信",
    "pid": 4312,
    "x": 200,
    "y": 100,
    "width": 960,
    "height": 600,
    "scaleFactor": 1.5
  },
  "screenListMs": 12,
  "captureMs": 40,
  "saveMs": 8,
  "totalMs": 60
}

AnnotationConfig

{
  "app": "wechat",
  "screenshotPath": "受限应用数据目录中的路径",
  "screenshotWidth": 1440,
  "screenshotHeight": 900,
  "scaleFactor": 1.5,
  "source": {},
  "regions": [],
  "createdAt": "2026-07-21T09:40:00Z",
  "updatedAt": "2026-07-21T09:42:00Z",
  "revision": 3
}

原生保存成功后由 Tauri event 发送:

{
  "event": "annotation-completion-changed",
  "payload": true
}

引擎状态变化沿用:

{
  "event": "engine-state-changed",
  "payload": { "enabled": true }
}

标注调试状态只允许 Tauri/Rust 本地模块读取。HTTP 业务服务和 Go 后端不得读取、同步或转发截图、窗口信息及标注区域。


15. 页面到接口映射

页面/窗口 源文件 初始加载 用户操作 实时事件
微信分身 src/pages/ClonePage.jsx /bootstrap/engine/state 启动检查、启动/停止引擎、暂停自动发送;标注走 Tauri IPC engine.*log.appended
运行日志 src/windows/EngineLogsWindow.jsx GET /logs 导出日志;清空/暂停是前端视图操作 log.appendedexport.completed
知识库列表 src/pages/KnowledgePage.jsx GET /knowledge-bases 搜索、打开详情 knowledge.changed 可选
新增/更新知识库 src/windows/KnowledgeWindows.jsx 创建/读取 knowledge draft 上传文档、图片或视频;预览转换后的 TXT人工填写媒体描述移除、发布 file.processing.updatedknowledge.changed
知识库详情、预览、引用、版本 src/windows/KnowledgeWindows.jsx knowledge detail/files/references/versions 预览、下载、启停、更新、删除 knowledge.changed、文件处理事件
智能体市场 src/pages/SkillsPage.jsx GET /agents 搜索、筛选、启停、打开详情 agent.changed 可选
新增/更新智能体 src/windows/SkillWindow.jsx 创建/读取 agent draft 基本信息、提示词、知识授权、测试、发布 测试会话事件
智能体详情 src/windows/SkillWindow.jsx GET /agents/{id} 更新、测试、启停、删除 agent.changed
测试智能体 src/components/AgentChatPanel.jsx 创建 test session、加载 messages 上传附件、发送、取消生成 agent.test.*
员工蒸馏主页 src/pages/DistillPage.jsx active jobs、employees 搜索、取消任务、打开详情 distill.progress.updated
开始蒸馏 src/windows/DistillWindows.jsx 创建/读取 distill draft 上传文件、开始提取、重新评估、导出、发布 file.processing.updateddistill.*
员工详情 src/windows/DistillWindows.jsx GET /employees/{id} 启停、编辑画像、管理授权、重新蒸馏、复制 employee.changed
设置 src/windows/SettingsContent.jsx GET /settings 保存/恢复、Key 更换/删除、连接测试、名单 CRUD settings.changed
标注调试页 src/pages/AnnotationPage.jsx Tauri capture_screen/load_regions 画框、编辑、删除、保存 Tauri annotation event
原生透明标注层 src/overlay.js Tauri overlay state 选窗、画框、编辑、删除、保存或取消 Tauri annotation event

16. 前端交互约束

  1. 所有页面首次打开必须显示 loading失败显示真实错误和重试入口不得用 mock 数据补成功状态。
  2. 按钮发起 mutation 后立即禁用,直到响应完成;重复点击依赖 Idempotency-Key 兜底。
  3. 搜索输入建议 250ms debounce新的请求发出时取消旧请求避免旧结果覆盖新结果。
  4. 详情窗口更新后关闭原窗口没有问题,但重新打开详情必须 GET 最新资源,不能依赖 localStorageBroadcastChannel 作为业务事实源。
  5. WS 事件只更新同 revision 或更新 revision发生缺号或冲突时重新 GET。
  6. 文件选择后先展示本地文件名和上传进度;只有 FileAsset.status=ready 才显示“格式有效/可预览”。
  7. 智能体测试期间禁用下一步、附件移除和重复发送;completed 后才标记测试通过。
  8. 蒸馏后台运行时关闭窗口不取消任务;再次打开按 jobId 查询并续订频道。
  9. 删除响应成功后从列表移除;409 RESOURCE_IN_USE 必须显示引用资源,不得假装删除成功。
  10. 配置保存以服务端返回的完整对象替换本地表单基线;连接测试不自动保存配置。

17. 实施顺序

  1. 基础层HTTP client、错误模型、session token、SQLite repository、revision、WebSocket ticket/重连。
  2. 设置与知识库:消除 API Key、本地配置、知识列表和创建流程中的 mock/localStorage。
  3. 文件中心:上传、解析、预览、清理和处理进度事件。
  4. 智能体:草稿、授权、测试 WS 流式输出、发布和详情。
  5. 蒸馏与员工:后台任务、进度、评估、发布和详情子资源。
  6. 引擎与日志:将现有 Tauri/sidecar 状态映射成结构化 HTTP/WS 契约,同时保留标注为 Tauri IPC。

完成判定:页面展示字段均来自上述响应;所有可操作按钮有真实 mutation长任务和流式生成有可恢复事件上传、解析失败、并发冲突和断线重连都有明确结果。