fix: 修复 AI 回复无法送达发送者 + 重复消息 + action角色泄露 + OS环境支持
广播逻辑重构: - AI 回复 (stream_start/response/stream_segments/multi_message/stream_end) 改用 broadcastToUser 发送给所有客户端 - 用户消息回显保持 broadcastToUserExcept 排除发送者 消息去重与角色修复: - CacheMessage(user) 移至回复生成后,避免本轮 LLM 调用出现重复用户消息 - action 角色消息在 DB 存储时映射为 assistant,DeepSeek 等模型不支持自定义角色 - stream_end defer 机制确保错误路径也会终止客户端思考指示器 OS 完整环境支持: - host 包重构为 HostBackend 接口 + Direct/WSL/Docker 三种后端 - 新增 os_exec/os_file/os_system 工具供 AI 在完整 Linux 环境中自由操作 其他: - 视觉模型注入 + 图片预处理后清空 Images 避免传给 Chat 模型 - 图片 URL 相对路径→绝对 URL 转换 - DevTools 链路追踪页面 + 重启修复 - 记忆搜索模糊匹配增强 - 后台思考定时调度支持 - 管理后台页面 (模型配置/用户管理等) - docs/api 更新广播机制说明 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# AI-Core Service API
|
||||
|
||||
**Base URL:** `http://<host>:8091` | **Auth:** 无(/internal 路由除外)
|
||||
**Base URL:** `http://<host>:8081` | **Auth:** 无(/internal 路由除外)
|
||||
|
||||
AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调度、结果合成。所有对话和记忆端点通过 **Server-Sent Events (SSE)** 或 **JSON** 返回。
|
||||
|
||||
@@ -14,8 +14,11 @@ AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调
|
||||
4. [POST /api/v1/memory — 添加记忆](#4-post-apiv1memory)
|
||||
5. [DELETE /api/v1/memory — 删除记忆](#5-delete-apiv1memory)
|
||||
6. [POST /api/v1/internal/presence — 在线状态](#6-post-apiv1internalpresence)
|
||||
7. [GET /api/v1/health — 健康检查](#7-get-apiv1health)
|
||||
8. [Model Selector 路由说明](#8-model-selector-路由说明)
|
||||
7. [GET /api/v1/system/info — OS 环境信息](#7-get-apiv1systeminfo)
|
||||
8. [GET /api/v1/tools/calls — 工具调用日志](#8-get-apiv1toolscalls)
|
||||
9. [GET /api/v1/llm-calls — LLM 调用日志](#9-get-apiv1llm-calls)
|
||||
10. [GET /api/v1/health — 健康检查](#10-get-apiv1health)
|
||||
11. [Model Selector 路由说明](#11-model-selector-路由说明)
|
||||
|
||||
---
|
||||
|
||||
@@ -29,11 +32,16 @@ AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调
|
||||
|-----------|---------|------|------|
|
||||
| `user_id` | string | 是 | 用户 ID |
|
||||
| `session_id` | string | 是 | 会话 ID |
|
||||
| `message` | string | 是 | 用户消息文本 |
|
||||
| `images` | []string | 否 | base64 Data URL 数组 |
|
||||
| `message` | string | 是 | 用户消息文本(纯图片时可留空 `""`) |
|
||||
| `images` | []string | 否 | 图片 URL 数组(data URL 或 https URL) |
|
||||
| `mode` | string | 否 | 默认 `"text"` |
|
||||
| `nickname` | string | 否 | 用户昵称 |
|
||||
|
||||
> **图片预处理:** 当 `images` 非空时,AI-Core 使用视觉模型 (`routing.vision`) 自动分析图片:
|
||||
> - 纯图片 (`message=""`) → 生成场景描述作为用户消息
|
||||
> - 文字+图片 → 视觉分析追加到消息末尾
|
||||
> - 原始图片仍传递给下游 LLM(如模型支持多模态)
|
||||
|
||||
### SSE 事件
|
||||
|
||||
**delta** — 逐 token 发送
|
||||
@@ -64,6 +72,18 @@ AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调
|
||||
}
|
||||
```
|
||||
|
||||
**tool_progress** — 工具执行进度
|
||||
```json
|
||||
{
|
||||
"type": "tool_progress",
|
||||
"tool_name": "host_exec",
|
||||
"status": "started|running|completed|failed",
|
||||
"progress": 0.5,
|
||||
"message": "正在执行 host_exec",
|
||||
"message_id": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**done** — 流结束
|
||||
```json
|
||||
{ "message_id": "string", "mode": "string", "done": true }
|
||||
@@ -207,7 +227,65 @@ AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调
|
||||
|
||||
---
|
||||
|
||||
## 7. GET /api/v1/health
|
||||
## 7. GET /api/v1/system/info
|
||||
|
||||
返回 OS 环境状态信息(WSL/Docker 后端状态、系统信息、磁盘使用)。
|
||||
|
||||
```json
|
||||
{
|
||||
"os_enabled": true,
|
||||
"backend": "wsl",
|
||||
"system": { "hostname": "...", "os": "linux", "arch": "amd64", "cpu_cores": 12, "total_memory": "16.0 GB" },
|
||||
"disk": { "path": "/", "total": "250.0 GB", "used": "120.0 GB", "free": "130.0 GB", "used_percent": 48.0 }
|
||||
}
|
||||
```
|
||||
|
||||
`os_enabled=false` 表示未配置 OS 后端。
|
||||
|
||||
---
|
||||
|
||||
## 8. GET /api/v1/tools/calls
|
||||
|
||||
工具调用日志(分页)。
|
||||
|
||||
| Query 参数 | 说明 |
|
||||
|-----------|------|
|
||||
| `tool_name` | 按工具名过滤 |
|
||||
| `limit` | 每页条数 (默认 50, 最大 500) |
|
||||
| `page` | 页码 (从 1 开始) |
|
||||
|
||||
```json
|
||||
{
|
||||
"calls": [ CallLogRecord ],
|
||||
"total": 100,
|
||||
"total_pages": 2,
|
||||
"page": 1,
|
||||
"limit": 50
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/v1/tools/calls/stats — 工具调用统计
|
||||
|
||||
返回各工具的调用次数、成功率等统计信息。
|
||||
|
||||
---
|
||||
|
||||
## 9. GET /api/v1/llm-calls
|
||||
|
||||
LLM 调用日志(调试用)。
|
||||
|
||||
`?limit=50` (默认 50, 最大 500)
|
||||
|
||||
```json
|
||||
{
|
||||
"calls": [ LLMCallRecord ],
|
||||
"total": 50
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. GET /api/v1/health
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -219,7 +297,7 @@ AI-Core 是 LLM 编排引擎,负责对话处理、意图分析、子会话调
|
||||
|
||||
---
|
||||
|
||||
## 8. Model Selector 路由说明
|
||||
## 11. Model Selector 路由说明
|
||||
|
||||
AI-Core 使用基于用途的模型路由。模型配置从 `models.json` 加载,回退到 `.env` 环境变量。
|
||||
|
||||
@@ -232,6 +310,8 @@ AI-Core 使用基于用途的模型路由。模型配置从 `models.json` 加载
|
||||
| `intent_analysis` | `PurposeIntentAnalysis` | 意图分析 |
|
||||
| `tool_calling` | `PurposeToolCalling` | 工具调用 |
|
||||
| `memory_extraction` | `PurposeMemoryExtraction` | 记忆提取 |
|
||||
| `vision` | `PurposeVision` | 图片理解/视觉分析 (图片预处理、vision_analyze 工具) |
|
||||
| `ocr` | `PurposeOCR` | 专用 OCR 文字提取 |
|
||||
|
||||
### 路由策略
|
||||
|
||||
|
||||
+12
-1
@@ -170,7 +170,7 @@ ws://<gateway>/ws/chat?token=<jwt>&session_id=<optional>&client_id=<optional>&de
|
||||
"type": "message|voice_input|ping|history",
|
||||
"session_id": "string (可选)",
|
||||
"mode": "text|voice_msg|voice_assistant",
|
||||
"content": "string (message 类型必填)",
|
||||
"content": "string (纯图片消息可留空,文字+图片时填写提问内容)",
|
||||
"audio_data": "string (voice_input 类型必填, base64)",
|
||||
"attachments": [
|
||||
{
|
||||
@@ -250,6 +250,10 @@ ws://<gateway>/ws/chat?token=<jwt>&session_id=<optional>&client_id=<optional>&de
|
||||
| `device_update` | IoT 设备状态更新 |
|
||||
| `background_thinking` | 后台思考状态变更 |
|
||||
|
||||
> **广播机制**:服务端推送分为两类:
|
||||
> - **用户消息回显**(`type: "response"`, `role: "user"`):通过 `SendToUserExcept` 广播,排除发送者自身(发送者本地已渲染),仅同步到同用户的其他设备。
|
||||
> - **AI 回复消息**(`stream_start`、`stream_end`、`response`/`review`、`multi_message`、`stream_segments` 等 `role: "assistant"` 的消息):通过 `SendToUser` 广播给所有设备,包括发送者。
|
||||
|
||||
> **消息类型分类 (`msg_type`)**:所有 `response`、`multi_message`、`history_response`、`stream_chunk`、`thinking`、`tool_progress`、`system_info` 类型的服务端消息中,`msg_type` 字段均由后端自动分类填充,前端只需直接读取 `msg_type` 并据此渲染,无需解析消息内容来猜测类型。
|
||||
>
|
||||
> `msg_type` 可选值:
|
||||
@@ -482,6 +486,13 @@ Content-Type: `multipart/form-data`。字段 `file`。最大 20MB。
|
||||
|
||||
错误: 400 `{"error":"文件大小超过限制 (最大 20MB)","errorType":"file_too_large"}`, 400 `{"error":"不支持的文件类型: ...","errorType":"unsupported_type"}`
|
||||
|
||||
> **文件在 AI 对话中的传递链路**:客户端上传文件后获得的 `url` 为相对路径(如 `/api/v1/files/{id}/download`)。当用户消息携带 `attachments` 时:
|
||||
> 1. **Gateway** 在转发前将相对路径补全为绝对 URL(`http://127.0.0.1:{port}/api/v1/files/{id}/download`)
|
||||
> 2. **AI-Core** 的 LLM 适配器在调用外部模型 API 前,将非 `data:` 的图片 URL 下载并转为 base64 data URL
|
||||
> 3. 最终以多模态格式(`[{type: "text", text: "..."}, {type: "image_url", image_url: {url: "data:..."}}]`)传递给 LLM
|
||||
>
|
||||
> 即文件存储层对外部 LLM API 透明,无需暴露内网文件服务。
|
||||
|
||||
### GET /files — 列表
|
||||
|
||||
`?page=1&limit=20`
|
||||
|
||||
Reference in New Issue
Block a user