docs(api): api-client → v0.53(阶段 5 全部契约)+ api-reference 同步 + .env.example 补 9 键
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 新端点 GET /admin/llm/catalog 全契约(200/gzip/503 catalog_unavailable/快照副作用/不进热路径/审计 llm.catalog)
- models.json 组级三键:reasoning.kind(形状)+ personaModels/personaProviders(角色级模型/协议路由),
  含「缺省=保留、给出=整块/整表替换」语义、Group.Validate 的 400 口径、回落与 WARN 规则
- GET /admin/llm 新增恒下发的 reasoning 与两个取值域(reasoningKinds/personaProviderOptions)
- 语义修正(此前文档写反):multimodal = 主模型能否收图;LLM_VISION_MODEL/LLM_OCR_MODEL 只配视觉/OCR 工具
- 新工具 image-crop(x/y/width/height、50MiB/16MP/8MiB 上限、越界报错不 clamp、策略默认 owner-only)
- 推理开关按形状下发:替换 v0.41「Qwen 只 WARN 不发」;effort 非法值改为丢弃+WARN(不降档)、effort:none 显式关思考
- .env.example 新增 9 键(LLM_REASONING_KIND / LLM_OCR_MODEL / LLM_LOCAL_* / CAPACITY_L3_*),默认均为保守值
- 权限矩阵计数按 routes.go 校正 56→59(owner/admin 只读档 9→10,含 /admin/llm/catalog)
This commit is contained in:
AskaEth committed 2026-10-04 13:07:09 +08:00
1 parent 1ac02bd77e
commit 58cba0b8d2
3 files changed
+106 -17

No files matched your search

+8 -5
View File
@@ -1,6 +1,6 @@
# Cyrene v2 后端 API 参考(api-reference.md)
> **权威归属(先读这条)**:**契约以 `Docs/api-client.md` 为准**——那是版本化的跨平台客户端契约,每个端点的形状 / 语义 / 版本变更都记在那里(当前 `v0.52`)。**本文件是内部与运维参考**:端点全集索引 + 示例 + 部署细节。**凡是与 api-client 重复的契约性描述,一律以 api-client 为准(本文件不再维护第二份契约);发现两者不一致时,改本文件而不是改 api-client。**
> **权威归属(先读这条)**:**契约以 `Docs/api-client.md` 为准**——那是版本化的跨平台客户端契约,每个端点的形状 / 语义 / 版本变更都记在那里(当前 `v0.53`)。**本文件是内部与运维参考**:端点全集索引 + 示例 + 部署细节。**凡是与 api-client 重复的契约性描述,一律以 api-client 为准(本文件不再维护第二份契约);发现两者不一致时,改本文件而不是改 api-client。**
> **本文件的正确用法**:查「有哪些端点、大致形状、错误码、部署注意事项」可以;**写客户端代码时请以 `Docs/api-client.md` 为准**,本文件的字段表 / 示例可能滞后。
> **历史包袱(如实)**:本文件长期自称「全部后端 API 的唯一详细参考 / 超详细主文档 / 每变更必同步」,但实际**系统性滞后于实现与 api-client**(2026-10-03 的 16 路 design-vs-code 审计结论)。本次已修正与实现**直接矛盾**的陈述、并把若干复述型段落改为引用 api-client;**仍未登记的端点 / WS 事件清单见 `DevDocs/audit/00-总览.md` §4④**,属后续「文档补全」批次,本文件暂不补全。
> **其余仍成立**:所有字段名、取值、鉴权规则、状态码最终**以代码为准**(`internal/services/gateway/*.go`);契约变更版本化(REST 走 `/api/v1`,破坏性变更升 v2),不得破坏既有客户端(版本化承诺本身记在 api-client §5)。
@@ -42,7 +42,7 @@
### 0.3 上传 / 媒体(重要确认)
- **`POST /api/v1/upload`**(B1)上传图片 → 返回**同源 URL**(`/api/v1/files/<name>`),可直接作 `chat.image`;也可继续用 **base64 data: URI** 或 http(s) URL 走 `POST /api/v1/chat` / WS `chat` 的 `image` 字段(入视觉真推理,见 §6 流式与直连)。
- **`POST /api/v1/upload`**(B1)上传图片 → 返回**同源 URL**(`/api/v1/files/<name>`),可直接作 `chat.image`;也可继续用 **base64 data: URI** 或 http(s) URL 走 `POST /api/v1/chat` / WS `chat` 的 `image` 字段(入视觉路由,见 §6 流式与直连)。**语义(v0.53 修正,见 api-client §1 行 3)**:**主模型能否收图 = 生效 `models.json` 组的 `multimodal`**(不是「有没有配独立视觉模型」);`LLM_VISION_MODEL` / `LLM_OCR_MODEL` **只配视觉/OCR 工具用的模型**;主模型不收图时由 vision/OCR 工具返回**文本描述**(另有 `image-crop` 工具可裁区域后重读,便于大图分区精读)。
- **REST 语音端点已存在**:`POST /api/v1/audio/transcribe`(STT)、`POST /api/v1/audio/speech`(TTS)、`POST /api/v1/audio/voice-clone`(声音复刻),均 owner-only + 审计,绕开 WS 4KB 帧限。语音也可走 WS `voice_input`(上行)/`voice_output`(下行)。
- 管理端导入知识文档(RAG)走 JSON body 文本(`POST /api/v1/admin/rag`),非文件上传。
@@ -208,7 +208,7 @@ curl -s -X POST http://<host>:8080/api/v1/auth/login \
|------|------|:---:|------|
| `sessionId` | string | 否 | 目标会话 id;缺省 `"web"`(主会话)。子会话用 `web:<uuid>` |
| `text` | string | 是* | 用户文本。`text` 与 `image` 至少一项非空 |
| `image` | string | 否 | 视觉输入:base64 **data: URI** 或 http(s) URL;入 vision/OCR 或主模型多模态(design/06)。图文并存则为带图 + 文本的 turn |
| `image` | string | 否 | 视觉输入:base64 **data: URI** 或 http(s) URL;入 vision/OCR 工具或主模型多模态(design/06)。图文并存则为带图 + 文本的 turn。**语义(v0.53)**:主模型能否收图看生效组的 `multimodal`;`LLM_VISION_MODEL`/`LLM_OCR_MODEL` 只配视觉/OCR **工具**的模型(见 api-client §1 行 3) |
| `deviceId` | string | 否 | 客户端生成的端标识(design/16 §4.5,如 `web:chrome:a1b2c3`),落库到消息,可选 |
| `mode` | string | 否 | 行为模式(design/01 §3、design/16 §5.1,如 `chat`/`code`/…);随该轮落库供气泡渲染;**IM 恒 `chat`、缺省回落 `chat`**(`chatRequest.Mode`) |
| `stream` | bool | 否 | `true` = 经 WS 触发流式(`publishChatStream` 发 `ws.chat`),**立即返回**;缺省 / `false` = 同步返回完整回复(Go bool 零值即 false,仍**无「必填」约束**) |
@@ -493,10 +493,13 @@ curl -s http://<host>:8080/api/v1/admin/iot -H "Authorization: Bearer $TOKEN" -H
### 4.9 GET /api/v1/admin/llm
- **响应**:`200 {"data":{"providers":[<AdminLlmProvider>...]}}`(`AdminLlmConfig`)。
- `AdminLlmProvider`:`{id, name, provider, baseUrl, model, multimodal, enabled, fallback?, maxTokens?}`。
- `AdminLlmProvider`:`{id, name, provider, baseUrl, model, multimodal, enabled, fallback?, maxTokens?, reasoning, personaModels?, personaProviders?}`(**v0.53 新增三键**,见 api-client 的「模型配置契约(v0.53)」);顶层 response 另含 `reasoningKinds` / `personaProviderOptions` 两个取值域数组(面板表单选项的唯一来源)。**`multimodal` = 主模型自己能否收图**(裁决 14.4.1)——它**不**表示「本部署有视觉能力」;视觉/OCR **工具**的模型由 `.env` 的 `LLM_VISION_MODEL` / `LLM_OCR_MODEL` 单独配置,与 `multimodal` 无关。`reasoning` 恒下发(`{kind}`,`kind:""` = 未声明形状)。
- `provider` 协议 ∈ `openai|anthropic`;`name` 为友好标签(OpenAI/Anthropic 或组 id)。
- `enabled`:index 0 的组为生效组 = `true`。
- `maxTokens`:该组的 token 预算(`omitempty`,缺省/0 = 未设);缺省时链末端回退步回落 `LLM_FALLBACK_MAX_TOKENS`(`.env`,默认 8192),再回落适配器默认(anthropic 8192)。
- `reasoning`(v0.53,恒下发):`{kind}` —— `kind` ∈ `auto|deepseek|openai|vllm|dashscope`,决定该组用哪种**提供商开关形状**下发推理指令(`""`/`auto` = 按模型名/baseURL 推断,形状有歧义就不下发);详见 api-client「模型配置契约(v0.53)」。
- `personaModels` / `personaProviders`(v0.53,`omitempty`):**角色级模型 / 协议路由表**(`{personaId: modelId}` / `{personaId: "openai"|"anthropic"}`);未配置 = 该键不出现。
- `multimodal`:**主模型自己能否收图**(= 面板的「多模态」勾选);视觉/OCR **工具**的模型是 `.env` 的 `LLM_VISION_MODEL`/`LLM_OCR_MODEL`,与本字段无关(裁决 14.4.1 修语义)。
- **API key 永不返回**(wire 无 key 字段)。
- 数据源:`models.json` 各组(index 0 = 生效组);无 `models.json` 时按 `.env` 合成单组。curl:
@@ -726,7 +729,7 @@ curl -s -X DELETE http://<host>:8080/api/v1/admin/automations/<id> -H "Authoriza
```
### 5.13 POST /api/v1/admin/llm
- **Body**(`llmProviderRequest`):`{"id?","name?","provider?","baseUrl","apiKey?","model","multimodal?","fallback?","maxTokens?"}`。`baseUrl`+`model` 必填;`provider` 空默认 `openai`(仅允许 `openai|anthropic`);`maxTokens` 缺省/`0` = 未设,负数回 `400`。
- **Body**(`llmProviderRequest`):`{"id?","name?","provider?","baseUrl","apiKey?","model","multimodal?","fallback?","maxTokens?","reasoning?","personaModels?","personaProviders?"}`。`baseUrl`+`model` 必填;`provider` 空默认 `openai`(仅允许 `openai|anthropic`);`maxTokens` 缺省/`0` = 未设,负数回 `400`。**v0.53 三键**缺省 = 保留已存值(`reasoning` 整块给出即整块替换;两张 persona 表给出即整表替换);非法 `reasoning.kind`、非法协议名、anthropic 组声明 openai 系形状 → `400 bad_request`(`Group.Validate` 报错,不落盘)。契约见 api-client「模型配置契约(v0.53)」。
- **响应**:`201 {"data":{"provider":<AdminLlmProvider>,"persisted":true,"path":"<models.json 绝对路径>"}}`。**真实持久化**:读-改-写 `models.json`,保存组**提升为生效组**(index 0),并**热重载**运行中的 LLM stack(无需重启)。
- **错误**:`400`(缺 baseUrl/model / invalid provider);`500`(LLM 服务未注入 / 写盘失败 / 热重载失败)。**API key 写入文件但永不回显、不落日志**。
- **审计**:`llm.addProvider`。curl: