接入 AI 大模型对话
更新日期:2026-10-25。当前生产版本:65ddec15。
本文面向调用知影平台大模型能力的 iOS、Web、UniApp 和外部应用。API 根地址为 https://work.zingyang.com/api。平台封装模型选择、会话、鉴权与权益计量;客户端不持有模型厂商密钥。
这不是 OpenAI API 的直接兼容地址。 请使用下文的平台请求、标准 Result 响应及命名 SSE 事件,不要将 OpenAI SDK 的 baseURL 直接改到这里并假定协议一致。
1. 调用前提
每次发起 AI 调用都必须同时满足:
- 平台登录 token 有效,用户存在且未停用、未删除。
- 当前租户存在、启用且在有效期内,租户 ID 为正数。
- 当前用户在该租户内具有有效成员关系。
- 租户具有有效的
AI_CHAT_TOKENS权益,且剩余额度足以覆盖本次调用预算。
管理员也不豁免。服务端覆盖请求中的 userId/tenantId,不能通过 JSON 冒用用户、切换租户或指定免扣费。有效订阅、附加包、赠送及无限额度沿用平台现有权益计算;不能只判断“购买过套餐”就认定可以调用。
X-Access-Token: <平台登录token>
X-Tenant-Id: <当前已确认租户ID>
Content-Type: application/json
不要传 Apple identity token,不要把模型厂商 API Key 放在这里,也不要假设 Bearer 头可以替代平台认证头。登录流程见 Apple 登录与平台会话。
如果是 AI 工具代理用户发起调用,按平台 AI 调用规则先取得授权,并携带 X-Zing-Ai-Context: 1;涉及写入的调用还需 X-Open-Confirm: confirmed。对话会保存会话/消息并产生用量,不能把它当作无副作用的 GET 查询。普通客户端页面操作无需伪装成 AI 工具请求。
2. 模型选择
| 接口 | 用途 |
|---|---|
GET /ai/model/config/options |
获取已启用模型选项;客户端选择平台已有配置 |
GET /ai/model/config/default |
获取当前可用默认模型配置;无可用默认项时返回业务失败 |
两者使用相同认证与租户头。读取模型选项不等于已经通过推理额度检查。
首次接入建议省略模型字段,使用服务端默认配置。需要固定模型时,使用选项接口返回的配置 id 作为 modelConfigId,并沿用所选项的 providerCode、modelCode 对应填入 provider、model;不要猜测配置 ID 或拼装不匹配的组合。
模型配置和厂商密钥由平台管理。新增或编辑平台模型是另一个管理功能,有 ai:model:* 权限要求;不应由普通客户端通过新增配置来绕过现有模型选择或套餐限制。
3. 普通对话
POST /ai/chat/completions
最小请求:
{"prompt":"请用三句话介绍会议纪要应该包含什么。"}
| 字段 | 类型 | 用法 |
|---|---|---|
| prompt | string | 本轮用户问题;简单接入优先使用 |
| conversationId | string | 首轮省略,后续填服务端返回的会话 ID |
| modelConfigId | string | 可选,平台模型配置 ID |
| provider | string | 可选,所选配置的 providerCode |
| model | string | 可选,所选配置的 modelCode |
| messages | array | 高级调用的消息数组,成员包含 role、content;普通客户端无需重复发送整个已保存历史 |
| knowledgeBaseIds | string[] | 可选,仅传用户有权使用的知识库 ID |
| toolCallEnabled | boolean | 默认 false;接入工具调用前须完成权限及写操作确认交互 |
首次只发送 prompt;不要同时拼装重复的 prompt 和全量 messages。已有 conversationId 必须属于当前用户与租户,不能复用其他账号的会话 ID。平台会话入口会启用个人记忆处理,具体行为受服务端实现和用户配置影响。
不要把 userId、tenantId、quotaExempt 当成客户端可控制的授权参数。quotaExempt 不从 JSON 接收;stream 也不代替选择流式接口。本文不把内部 hitsPayload、answerMeta、availableTools 等字段作为普通客户端协议。
curl --request POST 'https://work.zingyang.com/api/ai/chat/completions' \
--header 'X-Access-Token: <平台token>' \
--header 'X-Tenant-Id: <当前租户ID>' \
--header 'Content-Type: application/json' \
--data '{"prompt":"请用三句话介绍会议纪要应该包含什么。"}'
成功响应示意(值仅为示例):
{
"success": true,
"code": 200,
"message": "",
"result": {
"conversationId": "<会话ID>",
"provider": "<实际提供方>",
"model": "<实际模型>",
"content": "会议纪要应包含议题、结论和行动项。",
"finishReason": "stop",
"promptTokens": 100,
"completionTokens": 30,
"totalTokens": 130,
"ragContext": null,
"citations": [],
"toolCalls": []
},
"timestamp": 1792886400000
}
检查 HTTP 状态后,还必须检查 success 和 code。答案在 result.content,不是 choices[0].message.content。用量字段可能包含平台估算或厂商返回值,不保证等于套餐账本的预算占用或厂商最终账单;有剩余额度也可能因不足以覆盖本轮预算被拒绝。
4. 流式对话(SSE)
POST /ai/chat/completions/stream
Accept: text/event-stream
请求体及认证头与普通对话一致。浏览器应使用支持 POST、JSON body 和认证头的 fetch 流式读取方式;原生 EventSource 不能直接满足这组请求条件。iOS 可使用 URLSession 的流式接收能力,UniApp 应选支持分块读取的平台适配。
curl --no-buffer --request POST 'https://work.zingyang.com/api/ai/chat/completions/stream' \
--header 'X-Access-Token: <平台token>' \
--header 'X-Tenant-Id: <当前租户ID>' \
--header 'Accept: text/event-stream' \
--header 'Content-Type: application/json' \
--data '{"prompt":"帮我列出会议纪要的三个要点。"}'
协议示意(省略未使用的可选字段):
event: start
data: {"conversationId":"<会话ID>","provider":"<提供方>","model":"<模型>"}
event: delta
data: {"conversationId":"<会话ID>","content":"第一个要点"}
event: delta
data: {"conversationId":"<会话ID>","content":"是会议结论。"}
event: done
data: {"conversationId":"<会话ID>","messageId":"<消息ID>","finishReason":"stop","totalTokens":130}
| 事件 | 客户端处理 |
|---|---|
| start | 保存 conversationId,可包含模型及业务附加信息 |
| delta | 追加 content,不要覆盖之前收到的文本 |
| heartbeat | 保持连接,不追加到答案 |
| tool_start / tool_result / tool_error | 可选工具执行进度;按工具数据展示,不能当作文本增量 |
| done | 本轮完成,保存 messageId、用量、引用等信息;不保证携带完整答案 |
| error | 本轮失败,读取 message,停止成功状态展示 |
SSE data 是事件 JSON 本身,没有外层 Result,也没有 OpenAI 的 choices[].delta 或 [DONE] 约定。
解析时使用流式 UTF-8 解码;网络 chunk 可能截断汉字、JSON 或事件。按 SSE 空行分隔缓冲完整事件,支持 LF/CRLF、多行 data 和注释,不能每收到一个网络 chunk 就直接 JSON.parse。只有收到 done 才标记正常完成;连接结束不自动等于成功。
5. 错误与升级提示
普通 JSON 接口沿用标准结构:
| 业务码 | 含义与建议处理 |
|---|---|
| 401 | 登录或用户无效,重新登录 |
| 403 | 租户无效、未生效、停用、缺少成员关系,或调用确认条件不满足;按实际 message 提示 |
| 402 | 对应权益未开通、失效或额度不足;提示查看/续费/升级套餐,不自动无限重试 |
| 510 | 其他能力(例如知识库、工具、管理接口)的角色权限不足;不能通过换接口绕过 |
| 500 等 | 模型配置、参数、厂商或其他业务异常;保留实际错误信息,不全部提示为套餐不足 |
不能只看 HTTP 200:同步业务失败可能仍是 HTTP200 + success=false。
流式错误需要单独处理:认证过滤器等前置拒绝可能返回非 SSE 的 JSON/HTTP 错误;检查状态和 Content-Type 后再选择解析器。进入 SSE 后,当前控制器会把同步准备阶段错误转成 error 事件,数据只有 message 等事件字段,不保证附带 401/402/403 业务码:
event: error
data: {"message":"<服务端实际错误信息>"}
因此不要对 SSE error 执行 data.code === 402 并假定一定能识别套餐状态,也不要靠匹配某一句中文消息作为稳定协议。需要准确区分升级场景时,应结合客户端现有套餐状态界面;流式错误本身按实际 message 展示。本文不虚构新的升级接口、错误结构或套餐购买地址。
6. 会话恢复、重命名和删除
| 接口 | 请求 |
|---|---|
GET /ai/chat/conversations |
本人当前租户会话列表 |
GET /ai/chat/conversations/{id} |
会话详情及已保存消息 |
PUT /ai/chat/conversations/{id}/rename |
JSON:{"title":"新标题"} |
DELETE /ai/chat/conversations/{id} |
删除本人会话 |
以上接口仍要求有效身份及租户归属,但读取历史、重命名和删除不作为新的模型推理扣费。不要绕过归属校验。AI 工具执行 DELETE 还须采用 X-Open-Confirm: text:<至少4字符的确认文本>。
网络断开后,服务端可能继续生成并保存回答。客户端中止 HTTP 接收不等于厂商任务已取消,也不等于自动退还额度;先用会话详情核实结果,避免立即重试造成重复生成和用量。通用对话接口没有在本文承诺幂等请求键或独立停止接口;不要套用 Talk 的专用取消协议。
7. 知识库、工具与其他 AI 能力
- 知识库问答通过
knowledgeBaseIds关联已授权资料,答案可带 citations;不要把普通模型回答伪装成有资料出处。 - 工具调用默认关闭。开启后仍受当前用户权限及数据写操作确认限制;模型决定调用工具不等于用户已经授权写入。
- 应用固定的人设、指令和输出模板应复用平台提示词管理;不要在客户端复制一套长期维护的系统提示词。用户当轮问题作为输入提交。
- 图片附件、录音问答、ASR/OCR、图片生成有各自业务协议与计量口径;不能仅修改本接口字段就假定调用了这些能力。文件上传见 COS 上传文档。
- TTS 当前未核实到可发布的业务调用入口,本文不提供虚构路径。
8. 验证边界
源码依据:AiChatController、AiChatRequest/Response/StreamEvent、AiChatServiceImpl、AiInvocationAccess、AiModelConfigController;实际调用方为 Admin 的 ai.api.ts 和共享 SSE 解析链路。基础准入随65ddec15部署;本次文档编写没有发起新的生产模型推理或消耗客户额度,不将协议示例当作真实厂商联调结果。