mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-01 23:15:27 +08:00
Replace hardcoded DSML typo variant lists in Go/Node tool call parsers with generalized prefix consumption that tolerates repeated leading <, repeated DSML prefix noise, and trailing pipe terminators. Split tiktoken-dependent token counting into a build-tagged file for non-cgo platform compatibility. Add /data directory to Dockerfile for bind-mount permissions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
601 lines
19 KiB
Markdown
601 lines
19 KiB
Markdown
# DS2API 部署指南
|
||
|
||
语言 / Language: [中文](DEPLOY.md) | [English](DEPLOY.en.md)
|
||
|
||
本指南基于当前 Go 代码库,详细说明各种部署方式。
|
||
|
||
本页导航:[文档总索引](./README.md)|[架构说明](./ARCHITECTURE.md)|[接口文档](../API.md)|[测试指南](./TESTING.md)
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
- [部署方式优先级建议](#部署方式优先级建议)
|
||
- [前置要求](#0-前置要求)
|
||
- [一、下载 Release 构建包](#一下载-release-构建包)
|
||
- [二、Docker / GHCR 部署](#二docker--ghcr-部署)
|
||
- [三、Vercel 部署](#三vercel-部署)
|
||
- [四、本地源码运行](#四本地源码运行)
|
||
- [五、反向代理(Nginx)](#五反向代理nginx)
|
||
- [六、Linux systemd 服务化](#六linux-systemd-服务化)
|
||
- [七、部署后检查](#七部署后检查)
|
||
- [八、发布前进行本地回归](#八发布前进行本地回归)
|
||
|
||
---
|
||
|
||
## 部署方式优先级建议
|
||
|
||
推荐按以下顺序选择部署方式:
|
||
|
||
1. **下载 Release 构建包运行**:最省事,产物已编译完成,最适合大多数用户。
|
||
2. **Docker / GHCR 镜像部署**:适合需要容器化、编排或云环境部署。
|
||
3. **Vercel 部署**:适合已有 Vercel 环境且接受其平台约束的场景。
|
||
4. **本地源码运行 / 自行编译**:适合开发、调试或需要自行修改代码的场景。
|
||
|
||
---
|
||
|
||
## 0. 前置要求
|
||
|
||
| 依赖 | 最低版本 | 说明 |
|
||
| --- | --- | --- |
|
||
| Go | 1.26+ | 编译后端 |
|
||
| Node.js | `20.19+` 或 `22.12+` | 仅在需要本地构建 WebUI 时 |
|
||
| npm | 随 Node.js 提供 | 安装 WebUI 依赖 |
|
||
|
||
配置来源(任选其一):
|
||
|
||
- **文件方式**:`config.json`(推荐本地/Docker 使用)
|
||
- **环境变量方式**:`DS2API_CONFIG_JSON`(推荐 Vercel 使用,支持 JSON 字符串或 Base64 编码,也可以直接写原始 JSON)
|
||
|
||
统一建议(最优实践):
|
||
|
||
```bash
|
||
cp config.example.json config.json
|
||
# 编辑 config.json
|
||
```
|
||
|
||
建议把 `config.json` 作为唯一配置源:
|
||
- 本地运行:直接读 `config.json`
|
||
- Docker / Vercel:从 `config.json` 生成 `DS2API_CONFIG_JSON`(Base64)注入环境变量
|
||
|
||
---
|
||
|
||
## 一、下载 Release 构建包
|
||
|
||
仓库内置 GitHub Actions 工作流:`.github/workflows/release-artifacts.yml`
|
||
|
||
- **触发条件**:仅在 Release `published` 时触发(普通 push 不会构建)
|
||
- **构建产物**:多平台二进制压缩包 + `sha256sums.txt`
|
||
- **容器镜像发布**:仅发布到 GHCR(`ghcr.io/cjackhwang/ds2api`)
|
||
|
||
| 平台 | 架构 | 文件格式 |
|
||
| --- | --- | --- |
|
||
| Linux | amd64, arm64, armv7 | `.tar.gz` |
|
||
| macOS | amd64, arm64 | `.tar.gz` |
|
||
| Windows | amd64, arm64 | `.zip` |
|
||
|
||
每个压缩包包含:
|
||
|
||
- `ds2api` 可执行文件(Windows 为 `ds2api.exe`)
|
||
- `static/admin/`(WebUI 构建产物)
|
||
- `config.example.json`、`.env.example`
|
||
- `README.MD`、`README.en.md`、`LICENSE`
|
||
|
||
### 使用步骤
|
||
|
||
```bash
|
||
# 1. 下载对应平台的压缩包
|
||
# 2. 解压
|
||
tar -xzf ds2api_<tag>_linux_amd64.tar.gz
|
||
cd ds2api_<tag>_linux_amd64
|
||
|
||
# 3. 配置
|
||
cp config.example.json config.json
|
||
# 编辑 config.json
|
||
|
||
# 4. 启动
|
||
./ds2api
|
||
```
|
||
|
||
### 维护者发布步骤
|
||
|
||
1. 在 GitHub 创建并发布 Release(带 tag,如 `vX.Y.Z`)
|
||
2. 等待 Actions 工作流 `Release Artifacts` 完成
|
||
3. 在 Release 的 Assets 下载对应平台压缩包
|
||
|
||
---
|
||
|
||
## 二、Docker / GHCR 部署
|
||
|
||
### 2.1 基本步骤
|
||
|
||
```bash
|
||
# 拉取预编译镜像
|
||
docker pull ghcr.io/cjackhwang/ds2api:latest
|
||
|
||
# 复制环境变量模板和配置文件
|
||
cp .env.example .env
|
||
cp config.example.json config.json
|
||
|
||
# 编辑 .env(请改成你的强密码),至少设置:
|
||
# DS2API_ADMIN_KEY=your-admin-key
|
||
# 如需修改宿主机端口,可额外设置:
|
||
# DS2API_HOST_PORT=6011
|
||
|
||
# 启动
|
||
docker-compose up -d
|
||
|
||
# 查看日志
|
||
docker-compose logs -f
|
||
```
|
||
|
||
默认 `docker-compose.yml` 直接使用 `ghcr.io/cjackhwang/ds2api:latest`,并把宿主机 `6011` 映射到容器内的 `5001`。如果你希望直接对外暴露 `5001`,请设置 `DS2API_HOST_PORT=5001`(或者手动调整 `ports` 配置)。
|
||
Compose 模板还会默认设置 `DS2API_CONFIG_PATH=/data/config.json` 并挂载 `./config.json:/data/config.json`,优先避免 `/app` 只读带来的配置持久化问题。
|
||
镜像内会预创建 `/data` 并授权给非 root 的 `ds2api` 用户;如果你使用 bind mount 单文件,请确保宿主机 `config.json` 至少可被容器用户读取/写入,例如 `chmod 644 config.json`,否则 Linux UID/GID 不一致时仍可能出现 `open /data/config.json: permission denied`。
|
||
兼容说明:若未设置 `DS2API_CONFIG_PATH` 且运行目录是 `/app`,新版本会优先使用 `/data/config.json`;当该文件不存在但检测到历史 `/app/config.json` 时,会自动回退读取旧路径,避免升级后“配置丢失”。
|
||
|
||
如需固定版本,也可以直接拉取指定 tag:
|
||
|
||
```bash
|
||
docker pull ghcr.io/cjackhwang/ds2api:v3.0.0
|
||
```
|
||
|
||
### 2.2 更新
|
||
|
||
```bash
|
||
docker-compose up -d --build
|
||
```
|
||
|
||
### 2.3 Docker 架构说明
|
||
|
||
`Dockerfile` 提供两条构建路径:
|
||
|
||
1. **本地/开发默认路径(`runtime-from-source`)**:三阶段构建(WebUI 构建 + Go 构建 + 运行阶段)。
|
||
2. **Release 路径(`runtime-from-dist`)**:发布工作流先生成 tag 命名的 Release 压缩包,再把 Linux 产物复制成 `dist/docker-input/linux_amd64.tar.gz` / `linux_arm64.tar.gz`;Docker 构建阶段直接消费这些输入,不再重复执行 `npm build`/`go build`。
|
||
|
||
Release 路径可确保 Docker 镜像与 release 压缩包使用同一套产物,减少重复构建带来的差异。
|
||
|
||
容器内启动命令:`/usr/local/bin/ds2api`,默认暴露端口 `5001`。
|
||
|
||
### 2.4 开发环境
|
||
|
||
```bash
|
||
docker-compose -f docker-compose.dev.yml up
|
||
```
|
||
|
||
开发模式特性:
|
||
- 源代码挂载(修改即生效)
|
||
- `LOG_LEVEL=DEBUG`
|
||
- 不自动重启
|
||
|
||
### 2.5 健康检查
|
||
|
||
Docker Compose 已配置内置健康检查:
|
||
|
||
```yaml
|
||
healthcheck:
|
||
test: ["CMD", "/usr/local/bin/busybox", "wget", "-qO-", "http://localhost:${PORT:-5001}/healthz"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
start_period: 10s
|
||
```
|
||
|
||
### 2.6 Docker 常见排查
|
||
|
||
如果容器日志正常但面板打不开,优先检查:
|
||
|
||
1. **端口是否一致**:`PORT` 改成非 `5001` 时,访问地址也要改成对应端口(如 `http://localhost:8080/admin`)。
|
||
2. **开发 compose 的 WebUI 静态文件**:`docker-compose.dev.yml` 使用 `go run` 开发镜像,不会在容器内自动安装 Node.js;若仓库里没有 `static/admin`,`/admin` 会返回 404。可先在宿主机构建一次:`./scripts/build-webui.sh`。
|
||
|
||
### 2.7 Zeabur 一键部署(Dockerfile)
|
||
|
||
仓库提供 `zeabur.yaml` 模板,可在 Zeabur 上一键部署:
|
||
|
||
[](https://zeabur.com/templates/L4CFHP)
|
||
|
||
部署要点:
|
||
|
||
- **端口**:服务默认监听 `5001`,模板会固定设置 `PORT=5001`。
|
||
- **配置持久化**:模板挂载卷 `/data`,并设置 `DS2API_CONFIG_PATH=/data/config.json`;在管理台导入配置后,会写入并持久化到该路径。
|
||
- **`open /app/config.json: permission denied`**:说明当前实例在尝试把运行时 token 持久化到只读路径(常见于镜像内 `/app`)。
|
||
处理建议:
|
||
1. 显式设置可写路径:`DS2API_CONFIG_PATH=/data/config.json`(并挂载持久卷到 `/data`);
|
||
2. 若你使用 `DS2API_CONFIG_JSON` 启动且不需要运行时落盘,可保持环境变量模式(`DS2API_ENV_WRITEBACK` 关闭);
|
||
3. 最新版本中,即使持久化失败,登录/会话测试仍会继续,仅提示“token 未持久化(重启后丢失)”。
|
||
- **构建版本号**:Zeabur / 普通 `docker build` 默认不需要传 `BUILD_VERSION`;镜像会优先使用该构建参数,未提供时自动回退到仓库根目录的 `VERSION` 文件。
|
||
- **首次登录**:部署完成后访问 `/admin`,使用 Zeabur 环境变量/模板指引中的 `DS2API_ADMIN_KEY` 登录(建议首次登录后自行更换为强密码)。
|
||
|
||
---
|
||
|
||
## 三、Vercel 部署
|
||
|
||
### 3.1 部署步骤
|
||
|
||
1. **Fork 仓库**到你的 GitHub 账号
|
||
2. **在 Vercel 上导入项目**
|
||
3. **配置环境变量**(最少只需设置以下一项):
|
||
|
||
| 变量 | 说明 |
|
||
| --- | --- |
|
||
| `DS2API_ADMIN_KEY` | 管理密钥(必填) |
|
||
| `DS2API_CONFIG_JSON` | 配置内容,JSON 字符串或 Base64 编码(可选,建议) |
|
||
|
||
4. **部署**
|
||
|
||
### 3.1.1 推荐填写方式(避免 `DS2API_CONFIG_JSON` 填错)
|
||
|
||
如果你想先完成一键部署,也可以先不填 `DS2API_CONFIG_JSON`,部署后进入 `/admin` 导入配置,再在「Vercel 同步」里写回环境变量。
|
||
|
||
建议先在仓库目录复制示例配置,再按实际账号填写:
|
||
|
||
```bash
|
||
cp config.example.json config.json
|
||
# 编辑 config.json
|
||
```
|
||
|
||
不要在 Vercel 面板里手写复杂 JSON,建议本地生成 Base64 后粘贴:
|
||
|
||
```bash
|
||
# 在仓库根目录执行
|
||
DS2API_CONFIG_JSON="$(base64 < config.json | tr -d '\n')"
|
||
echo "$DS2API_CONFIG_JSON"
|
||
```
|
||
|
||
如果你选择在部署前就预置配置,请在 Vercel Project Settings -> Environment Variables 配置:
|
||
|
||
```text
|
||
DS2API_ADMIN_KEY=请替换为强密码
|
||
DS2API_CONFIG_JSON=上一步生成的一整行 Base64
|
||
```
|
||
|
||
可选但推荐(用于 WebUI 一键同步 Vercel 配置):
|
||
|
||
```text
|
||
VERCEL_TOKEN=你的 Vercel Token
|
||
VERCEL_PROJECT_ID=prj_xxxxxxxxxxxx
|
||
VERCEL_TEAM_ID=team_xxxxxxxxxxxx # 个人账号可留空
|
||
```
|
||
|
||
### 3.2 可选环境变量
|
||
|
||
| 变量 | 说明 | 默认值 |
|
||
| --- | --- | --- |
|
||
| `DS2API_ACCOUNT_MAX_INFLIGHT` | 每账号并发上限 | `2` |
|
||
| `DS2API_ACCOUNT_MAX_QUEUE` | 等待队列上限 | `recommended_concurrency` |
|
||
| `DS2API_GLOBAL_MAX_INFLIGHT` | 全局并发上限 | `recommended_concurrency` |
|
||
| `DS2API_ENV_WRITEBACK` | 检测到 `DS2API_CONFIG_JSON` 时自动写入 `DS2API_CONFIG_PATH`,并在成功后转为文件模式(`1/true/yes/on`) | 关闭 |
|
||
| `DS2API_VERCEL_INTERNAL_SECRET` | 混合流式内部鉴权 | 回退用 `DS2API_ADMIN_KEY` |
|
||
| `DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS` | 流式 lease TTL | `900` |
|
||
| `DS2API_RAW_STREAM_SAMPLE_ROOT` | raw stream 样本保存/读取根目录 | `tests/raw_stream_samples` |
|
||
| `VERCEL_TOKEN` | Vercel 同步 token | — |
|
||
| `VERCEL_PROJECT_ID` | Vercel 项目 ID | — |
|
||
| `VERCEL_TEAM_ID` | Vercel 团队 ID | — |
|
||
| `DS2API_VERCEL_PROTECTION_BYPASS` | 部署保护绕过密钥(内部 Node→Go 调用) | — |
|
||
|
||
### 3.3 运行时行为配置(通过 Admin API 设置)
|
||
|
||
部分运行时行为无法通过环境变量直接配置,需要在部署后通过 Admin API 设置,例如:
|
||
|
||
- **自动删除会话模式** (`auto_delete.mode`):支持 `none` / `single` / `all`,默认为 `none`。可通过 `PUT /admin/settings` 更新。
|
||
- **每账号并发上限** (`account_max_inflight`):环境变量已支持,但也可通过 Admin API 热更新。
|
||
- **全局并发上限** (`global_max_inflight`):同上。
|
||
|
||
详细说明参见 [API.md](../API.md#admin-接口) 中 `/admin/settings` 部分。
|
||
|
||
### 3.4 Vercel 架构说明
|
||
|
||
```text
|
||
请求 ─────┐
|
||
│
|
||
▼
|
||
vercel.json 路由规则
|
||
│
|
||
┌─────┴─────┐
|
||
│ │
|
||
▼ ▼
|
||
api/index.go api/chat-stream.js
|
||
(Go Runtime) (Node Runtime)
|
||
```
|
||
|
||
- **入口文件**:`api/index.go`(Serverless Go)
|
||
- **流式入口**:`api/chat-stream.js`(Node Runtime,保证实时 SSE)
|
||
- **路由重写**:`vercel.json`
|
||
- **构建命令**:`npm ci --prefix webui && npm run build --prefix webui`(自动执行)
|
||
|
||
#### 流式处理链路
|
||
|
||
由于 Vercel Go Runtime 存在平台层响应缓冲,本项目在 Vercel 上采用"**Go prepare + Node stream**"的混合链路:
|
||
|
||
1. `api/chat-stream.js` 收到 `/v1/chat/completions` 请求
|
||
2. Node 调用 Go 内部 prepare 接口(`?__stream_prepare=1`),获取会话 ID、PoW、token 等
|
||
3. Go prepare 创建 stream lease,锁定账号
|
||
4. Node 直连 DeepSeek 上游,实时流式转发 SSE 给客户端(含 OpenAI chunk 封装与 tools 防泄漏筛分)
|
||
5. 流结束后 Node 调用 Go release 接口(`?__stream_release=1`),释放账号
|
||
|
||
> 该适配**仅在 Vercel 环境生效**;本地与 Docker 仍走纯 Go 链路。
|
||
|
||
#### 非流式回退与 Tool Call 处理
|
||
|
||
- `api/chat-stream.js` 仅对非流式请求回退到 Go 入口(`?__go=1`)
|
||
- 流式请求(包括带 `tools`)走 Node 路径,并执行与 Go 对齐的 tool-call 防泄漏处理
|
||
- Node 流式路径同时对齐 Go 的终结态语义:空可见输出会返回同形状错误 SSE,空 `content_filter` 会返回 `content_filter` 错误
|
||
- WebUI 的"非流式测试"直接请求 `?__go=1`,避免 Node 中转造成长请求超时
|
||
|
||
#### 函数时长
|
||
|
||
`vercel.json` 已将 `api/chat-stream.js` 与 `api/index.go` 的 `maxDuration` 设为 `300`(受 Vercel 套餐上限约束)。
|
||
|
||
### 3.5 Vercel 常见报错排查
|
||
|
||
#### Go 构建失败
|
||
|
||
```text
|
||
Error: Command failed: go build -ldflags -s -w -o .../bootstrap ...
|
||
```
|
||
|
||
**原因**:Vercel 项目的 Go 构建参数配置不正确(`-ldflags` 没有作为一个整体字符串传递)。
|
||
|
||
**解决**:
|
||
|
||
1. 进入 Vercel Project Settings → Build and Development Settings
|
||
2. **清空**自定义 Go Build Flags / Build Command(推荐)
|
||
3. 若必须设置 ldflags,使用 `-ldflags="-s -w"`(保证它是一个参数)
|
||
4. 确认仓库 `go.mod` 为受支持版本(当前为 `go 1.26.0`)
|
||
5. 重新部署(建议清缓存后 Redeploy)
|
||
|
||
#### Internal 包导入错误
|
||
|
||
```text
|
||
use of internal package ds2api/internal/server not allowed
|
||
```
|
||
|
||
**原因**:Vercel Go 入口文件直接 `import internal/...`。
|
||
|
||
**解决**:当前仓库已通过公开桥接包 `app` 解决:`api/index.go` → `ds2api/app` → `internal/server`。
|
||
|
||
#### 输出目录错误
|
||
|
||
```text
|
||
No Output Directory named "public" found after the Build completed.
|
||
```
|
||
|
||
**解决**:当前仓库使用 `static` 作为输出目录(`vercel.json` 中 `"outputDirectory": "static"`)。若你在项目设置里手动改过 Output Directory,请设为 `static` 或清空让仓库配置生效。
|
||
|
||
#### 部署保护拦截
|
||
|
||
如果接口返回 Vercel HTML 页面 `Authentication Required`:
|
||
|
||
- **方案 A**:关闭该部署/环境的 Deployment Protection(推荐用于公开 API)
|
||
- **方案 B**:请求中添加 `x-vercel-protection-bypass` 头
|
||
- **方案 C**:设置 `VERCEL_AUTOMATION_BYPASS_SECRET`(或 `DS2API_VERCEL_PROTECTION_BYPASS`),仅影响内部 Node→Go 调用
|
||
|
||
### 3.6 仓库不提交构建产物
|
||
|
||
- `static/admin` 目录不在 Git 中
|
||
- Vercel / Docker 构建阶段自动生成 WebUI 静态文件
|
||
|
||
---
|
||
|
||
## 四、本地源码运行
|
||
|
||
### 4.1 基本步骤
|
||
|
||
```bash
|
||
# 克隆仓库
|
||
git clone https://github.com/CJackHwang/ds2api.git
|
||
cd ds2api
|
||
|
||
# 复制并编辑配置
|
||
cp config.example.json config.json
|
||
# 使用你喜欢的编辑器打开 config.json,填入:
|
||
# - keys: 你的 API 访问密钥
|
||
# - accounts: DeepSeek 账号(email 或 mobile + password)
|
||
|
||
# 启动服务
|
||
go run ./cmd/ds2api
|
||
```
|
||
|
||
默认本地访问地址是 `http://127.0.0.1:5001`;服务实际绑定 `0.0.0.0:5001`,可通过 `PORT` 环境变量覆盖。
|
||
|
||
### 4.2 WebUI 构建
|
||
|
||
本地首次启动时,若 `static/admin/` 不存在,服务会自动尝试构建 WebUI(需要 Node.js/npm;缺依赖时会先执行 `npm ci`,再执行 `npm run build -- --outDir static/admin --emptyOutDir`)。
|
||
|
||
你也可以手动构建:
|
||
|
||
```bash
|
||
./scripts/build-webui.sh
|
||
```
|
||
|
||
或手动执行:
|
||
|
||
```bash
|
||
cd webui
|
||
npm install
|
||
npm run build
|
||
# 产物输出到 static/admin/
|
||
```
|
||
|
||
通过环境变量控制自动构建行为:
|
||
|
||
```bash
|
||
# 强制关闭自动构建
|
||
DS2API_AUTO_BUILD_WEBUI=false go run ./cmd/ds2api
|
||
|
||
# 强制开启自动构建
|
||
DS2API_AUTO_BUILD_WEBUI=true go run ./cmd/ds2api
|
||
```
|
||
|
||
### 4.3 编译为二进制文件
|
||
|
||
```bash
|
||
go build -o ds2api ./cmd/ds2api
|
||
./ds2api
|
||
```
|
||
|
||
---
|
||
|
||
## 五、反向代理(Nginx)
|
||
|
||
如果在 Nginx 后部署,**必须关闭缓冲**以保证 SSE 流式响应正常工作:
|
||
|
||
```nginx
|
||
location / {
|
||
proxy_pass http://127.0.0.1:5001;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_buffering off;
|
||
proxy_cache off;
|
||
chunked_transfer_encoding on;
|
||
tcp_nodelay on;
|
||
}
|
||
```
|
||
|
||
如果需要 HTTPS,可以在 Nginx 层配置 SSL 证书:
|
||
|
||
```nginx
|
||
server {
|
||
listen 443 ssl;
|
||
server_name api.example.com;
|
||
|
||
ssl_certificate /path/to/cert.pem;
|
||
ssl_certificate_key /path/to/key.pem;
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:5001;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection "";
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_buffering off;
|
||
proxy_cache off;
|
||
chunked_transfer_encoding on;
|
||
tcp_nodelay on;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 六、Linux systemd 服务化
|
||
|
||
### 6.1 安装
|
||
|
||
```bash
|
||
# 将编译好的二进制文件和相关文件复制到目标目录
|
||
sudo mkdir -p /opt/ds2api
|
||
sudo cp ds2api config.json /opt/ds2api/
|
||
sudo cp -r static/admin /opt/ds2api/static/admin
|
||
```
|
||
|
||
### 6.2 创建 systemd 服务文件
|
||
|
||
```ini
|
||
# /etc/systemd/system/ds2api.service
|
||
|
||
[Unit]
|
||
Description=DS2API (Go)
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
WorkingDirectory=/opt/ds2api
|
||
Environment=PORT=5001
|
||
Environment=DS2API_CONFIG_PATH=/opt/ds2api/config.json
|
||
Environment=DS2API_ADMIN_KEY=your-admin-key-here
|
||
ExecStart=/opt/ds2api/ds2api
|
||
Restart=always
|
||
RestartSec=5
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
### 6.3 常用命令
|
||
|
||
```bash
|
||
# 加载服务配置
|
||
sudo systemctl daemon-reload
|
||
|
||
# 设置开机自启
|
||
sudo systemctl enable ds2api
|
||
|
||
# 启动服务
|
||
sudo systemctl start ds2api
|
||
|
||
# 查看状态
|
||
sudo systemctl status ds2api
|
||
|
||
# 查看日志
|
||
sudo journalctl -u ds2api -f
|
||
|
||
# 重启服务
|
||
sudo systemctl restart ds2api
|
||
|
||
# 停止服务
|
||
sudo systemctl stop ds2api
|
||
```
|
||
|
||
---
|
||
|
||
## 七、部署后检查
|
||
|
||
无论使用哪种部署方式,启动后建议依次检查:
|
||
|
||
```bash
|
||
# 1. 存活探针
|
||
curl -s http://127.0.0.1:5001/healthz
|
||
# 预期: {"status":"ok"}
|
||
|
||
# 2. 就绪探针
|
||
curl -s http://127.0.0.1:5001/readyz
|
||
# 预期: {"status":"ready"}
|
||
|
||
# 3. 模型列表
|
||
curl -s http://127.0.0.1:5001/v1/models
|
||
# 预期: {"object":"list","data":[...]}(包含 `*-nothinking` 变体)
|
||
|
||
# 4. 管理台页面(如果已构建 WebUI)
|
||
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:5001/admin
|
||
# 预期: 200
|
||
|
||
# 5. 测试 API 调用
|
||
curl http://127.0.0.1:5001/v1/chat/completions \
|
||
-H "Authorization: Bearer your-api-key" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"hello"}]}'
|
||
```
|
||
|
||
---
|
||
|
||
## 八、发布前进行本地回归
|
||
|
||
建议在发布前执行完整的端到端测试集(使用真实账号):
|
||
|
||
```bash
|
||
./tests/scripts/run-live.sh
|
||
```
|
||
|
||
可自定义参数:
|
||
|
||
```bash
|
||
go run ./cmd/ds2api-tests \
|
||
--config config.json \
|
||
--admin-key admin \
|
||
--out artifacts/testsuite \
|
||
--timeout 120 \
|
||
--retries 2
|
||
```
|
||
|
||
测试集自动执行内容:
|
||
|
||
- ✅ 语法/构建/单测 preflight
|
||
- ✅ 隔离副本配置启动服务(不污染原始 `config.json`)
|
||
- ✅ 真实调用场景验证(OpenAI/Claude/Admin/并发/toolcall/流式)
|
||
- ✅ 全量请求与响应日志落盘(用于故障复盘)
|
||
|
||
详细测试集说明参阅 [TESTING.md](TESTING.md)。PR 前的固定本地门禁以 [TESTING.md](TESTING.md#pr-门禁--pr-gates) 为准。
|