# AI Chat API 简要说明:提供基于外部大模型(OpenAI 兼容协议)的简单对话接口。默认路由前缀 `/ai`,统一使用 JSON 请求/响应,并沿用 `service/internal/common/response.Response` 包装。前端通过从存储表 `ai_config` 中选择一条配置(使用其 `id`,即 `config_id`)来指定要调用的 provider 与 model;API Key 存放在 `ai_config`(字段含 id/name/provider/model/base_url/api_key),不再依赖环境变量或在请求中传递密钥。TOML 仅配置是否启用 AI,所有连接信息由 `ai_config` 管理。 ## 前置条件 - 配置:`config.toml` ```toml [mcp] enable = true # 仅启用 MCP 时会自动注册 ai_chat 工具;HTTP 接口与 MCP 各自独立 [ai] enable = true ``` - 无需环境变量:API Key 直接存放在 `ai_config.api_key`,通过接口更新。 - 构建/运行:`go build ./...` 或 `go run ./` ## 通用响应格式 ```json { "code": 0, // 0=成功,非0=失败 "msg": "ok", // 简短提示 "data": {}, // 成功时返回的业务数据 "error": "" // 失败时的底层错误信息 } ``` ## 接口一览 | 方法 | 路径 | 功能 | | ---- | ---- | ---- | | POST | /ai/chat | 单一入口,mode 控制同步/流式/异步(支持 request_id 幂等与取消) | | POST | /ai/chat/cancel | 取消指定的聊天请求(按 request_id 或 session_id) | | POST | /ai/history | 按 session_id 查询对话历史 | | POST | /ai/history/delete | 删除指定 session 的历史 | | POST | /ai/config/get | 获取当前(默认)AI 配置 | | POST | /ai/config/list | 获取全部 AI 配置列表 | | POST | /ai/config/create | 新建 AI 配置(单行表,等价覆盖 default) | | POST | /ai/config/update | 更新 AI 配置,覆盖存储中的 ai_config | | POST | /ai/config/delete | 删除 AI 配置(默认 id=default,删除后需重新插入/更新) | ## POST /ai/chat - 功能:单一入口,`mode` 控制同步/流式/异步;支持 request_id 幂等、显式取消;成功后写入历史(user/assistant)。 - Content-Type: `application/json` ### 请求体 | 字段 | 类型 | 必填 | 说明 | | ---- | ---- | :--: | ---- | | session_id | string | 是 | 会话 ID,用于归档历史(同一会话请复用) | | prompt | string | 是 | 用户输入内容 | | system | string | 否 | 系统指令/角色设定 | | model | string | 否 | 覆盖配置中的 `model`(优先使用请求中的 `model`) | | config_id | string | 否 | 指定使用的 `ai_config.id`(优先于默认配置);推荐前端先调用 `/ai/config/list` 获取可用配置并传入该字段 | | request_id | string | 否 | 幂等与取消用:同一 request_id 重复调用直接命中缓存;取消也可用该 ID | | mode | string | 否 | `sync`(默认)、`stream`、`async` | | timeoutMs | int | 否 | 单次调用超时,毫秒;<=0 时默认 45s | ### 响应 - `mode=sync`(默认):`data = {"mode": "sync", "text": "...", "request_id": "..."}` - `mode=stream`:SSE 事件 `start` -> `message`/`error` -> `done`,header `Content-Type: text/event-stream` - `mode=async`:`data = {"mode": "async", "task_id": "...", "request_id": "..."}` ### 说明与约束 - 配置选择:若请求不带 `config_id`,服务会使用默认配置(可通过 `/ai/config/get` 查看);若带 `config_id`,服务会在 `ai_config` 中查找对应 `id` 并使用其 `base_url`/`api_key`/`provider`/`model` 发起调用;若找不到会返回错误。 - Model 覆盖:请求中的 `model` 可临时覆盖配置中的模型字段(仅影响本次请求)。 - 超时:默认 45 秒,可通过 `timeoutMs` 指定;取消或客户端断开会终止下游请求。 - 历史:仅在模型调用成功后写入 user/assistant 消息到 `ai_chat_history`(字段含 session_id/role/content/model/provider/created_at)。 - 幂等:携带 `request_id` 时,若之前已成功完成同一 ID 的请求,直接返回缓存结果,不重复计费。 - 取消:通过 `/ai/chat/cancel` 或客户端断开 SSE/HTTP 连接可取消当前生成。 - 安全:API Key 存储在 `ai_config.api_key`,前端通过配置接口写入;不要在 `/ai/chat` 请求体中携带密钥。 ### cURL 示例(同步) ```bash curl -X POST http://127.0.0.1:8080/ai/chat \ -H "Content-Type: application/json" \ -d '{ "session_id": "demo-session-1", "prompt": "解释 SQL 索引的作用", "system": "你是数据库助手", "config_id": "default", "request_id": "req-123" }' ``` ### SSE 示例(流式) 与同步示例相同请求体,增加 `"mode": "stream"`,前端用 EventSource/Fetch-SSE 读取事件。 ### 异步示例 与同步示例相同请求体,增加 `"mode": "async"`;返回 task_id/request_id,结果由任务订阅或轮询获取。 ## POST /ai/chat/cancel - 功能:取消指定的聊天请求。 - Content-Type: `application/json` ### 请求体 | 字段 | 类型 | 必填 | 说明 | | ---- | ---- | :--: | ---- | | request_id | string | 否 | 优先匹配该 ID 对应的请求 | | session_id | string | 否 | 备用匹配;两者至少填一个 | ### 成功响应 ```json { "code": 0, "msg": "ok" } ``` ### 说明 - 若找不到对应的进行中请求会返回错误;取消成功后下游 HTTP 调用会被终止。 ## POST /ai/history ### 请求体 | 字段 | 类型 | 必填 | 说明 | | ---- | ---- | :--: | ---- | | session_id | string | 是 | 会话 ID | | limit | int | 否 | 返回条数,默认 100 | | offset | int | 否 | 偏移量,默认 0 | ### 成功响应 `data` 字段为: ```json { "messages": [ {"id": "u1", "session_id": "demo-session-1", "role": "user", "content": "hi", "model": "gpt-4o-mini", "provider": "openai", "created_at": "2024-01-01T00:00:00Z"}, {"id": "a1", "session_id": "demo-session-1", "role": "assistant", "content": "hello", "model": "gpt-4o-mini", "provider": "openai", "created_at": "2024-01-01T00:00:01Z"} ] } ``` ## POST /ai/history/delete - 功能:删除指定 session 的全部历史记录。 - Content-Type: `application/json` ### 请求体 | 字段 | 类型 | 必填 | 说明 | | ---- | ---- | :--: | ---- | | session_id | string | 是 | 要删除的会话 ID | ### 成功响应 ```json { "code": 0, "msg": "ok" } ``` ## MCP ai_chat(补充说明) 当 `[mcp].enable=true` 时,MCP 服务会注册工具 `ai_chat`(与 HTTP 路由独立)。参数含义与 HTTP 相同,客户端通过 MCP 协议的 `tools/call` 请求调用。 示例(MCP tools/call) ```json { "method": "tools/call", "params": { "name": "ai_chat", "arguments": { "prompt": "写一个创建表的 SQL", "config_id": "default", "model": "deepseek-chat" } } } ``` ## POST /ai/config/get - 功能:获取当前(默认)AI 配置,返回单条记录。 - Content-Type: `application/json` - 请求体:无 ### 成功响应 `data` 字段为当前配置: ```json { "ai_settings": { "id": "default", "name": "default", "provider": "openai", "model": "gpt-4o-mini", "base_url": "https://api.openai.com/v1/chat/completions", "api_key": "sk-xxx", "updated_at": "2024-01-01T00:00:00Z" } } ``` ## POST /ai/config/list - 功能:获取全部 AI 配置列表(按 updated_at 降序)。 - Content-Type: `application/json` - 请求体:无 ### 成功响应 `data` 字段为: ```json { "items": [ {"id": "default", "name": "default", "provider": "openai", "model": "gpt-4o-mini", "base_url": "https://api.openai.com/v1/chat/completions", "api_key": "sk-xxx", "updated_at": "2024-01-01T00:00:00Z"} ] } ``` ## POST /ai/config/update - 功能:部分更新 AI 配置;仅覆盖请求体中非空字段,其余沿用当前存储值。 - Content-Type: `application/json` ### 请求体(示例,仅更新 model) ```json { "ai_settings": { "model": "gpt-4o-mini" } } ``` ### 成功响应 `data` 同 /ai/config/get。 说明与约束: - 非空字段才会更新;name/provider/model/base_url/api_key 为空时保持原值。 - 若存储中值为空,仍会回落默认 name=default、provider=openai、model=gpt-4o-mini、base_url=官方地址。 - `model`、`api_key` 最终需要有值(若为空则依赖已有或默认值)。 - 更新后即写入 `ai_config`,后续 /ai/chat 和 MCP ai_chat 调用均使用新配置。 ## POST /ai/config/create - 功能:新建 AI 配置;若未传 id 后端自动生成,若指定 id 已存在则报错(不覆盖)。 - Content-Type: `application/json` ### 请求体 ```json { "ai_settings": { "name": "default", "provider": "openai", "model": "gpt-4o-mini", "base_url": "https://api.openai.com/v1/chat/completions", "api_key": "sk-xxx" } } ``` ### 成功响应 同 `/ai/config/update`。 说明:允许多条配置记录,但客户端通常使用 id/name=default。 ## POST /ai/config/delete - 功能:删除指定 AI 配置记录(默认删除 id=default)。删除后需要用 /ai/config/create 或 /ai/config/update 重新写入。 - Content-Type: `application/json` ### 请求体 ```json { "id": "default" } ``` ### 成功响应 ```json { "code": 0, "msg": "ok" } ```