diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 00000000..dc09d416 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "tabby": { + "type": "http", + "url": "http://localhost:3001/mcp" + } + } +} diff --git a/AGENTS.md b/AGENTS.md index cd1756d5..ca6b887b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -130,3 +130,264 @@ For request structs that are parsed from client JSON and then re-marshaled to up - field absent in client JSON => `nil` => omitted on marshal; - field explicitly set to zero/false => non-`nil` pointer => must still be sent upstream. - Avoid using non-pointer scalars with `omitempty` for optional request parameters, because zero values (`0`, `0.0`, `false`) will be silently dropped during marshal. + + +# new-api 项目排障记录 + +## 本次对话确认的关键信息 + +### 1. 部署与配置位置 +- 远程服务器:`个人-minione-ubuntu-infra-4c16g120g` +- `new-api` 以 Docker 容器运行,容器名:`new-api` +- 渠道配置不在 `docker-compose.yml` 里维护,核心数据在 PostgreSQL 数据库表中: + - `channels` + - `abilities` + - `options` + +### 2. 新渠道 `xianyu-claude-opus4.6-40` +- 数据库中已存在该渠道,不是“未创建”问题。 +- 关键字段: + - `name = xianyu-claude-opus4.6-40` + - `type = 14` + - `base_url = http://cccai.cfd` + - `models = claude-opus-4-6` +- `abilities` 已同步出三组能力: + - `default` + - `vip` + - `svip` +- 已补齐: + - `test_model = claude-opus-4-6` + +### 3. 上游协议与验证方式 +- 该渠道支持 `v1/messages`。 +- 直接请求上游验证通过: + - `POST http://cccai.cfd/v1/messages` + - Header 需要: + - `content-type: application/json` + - `x-api-key: ` + - `anthropic-version: 2023-06-01` +- 实测返回 `200`,模型 `claude-opus-4-6` 可正常响应。 + +### 4. `/api/channel/test` 报错的真实原因 +- 报错: + - `模型 claude-opus-4-6 倍率或价格未配置` +- 这不是渠道连通性问题,而是计费配置问题。 +- 代码位置: + - `relay/helper/price.go` +- 测试渠道时,服务端会先查: + - `options.ModelPrice` + - 查不到再查 `options.ModelRatio` +- 两者都 miss 时,就会抛出上面的错误。 + +### 5. 本次实际修复 +- 远程数据库中的 `options.ModelRatio` 被自定义值覆盖,缺少: + - `claude-opus-4-6` +- 已补上: + - `ModelRatio["claude-opus-4-6"] = 2.5` +- 补完后验证通过: + - `GET /api/channel/test/9?model=claude-opus-4-6&endpoint_type=anthropic` + - 返回:`{"message":"","success":true,"time":8.601}` + +### 6. 默认值与线上值的关系 +- 代码默认倍率里本来就有: + - `claude-opus-4-6: 2.5` +- 代码位置: + - `setting/ratio_setting/model_ratio.go` +- 但线上运行时会被数据库中的 `options.ModelRatio` 覆盖。 +- 结论: + - 代码里有默认值,不代表线上一定可用。 + - 查问题时必须先看数据库 `options` 实际内容。 + +### 7. 线上热同步行为 +- `new-api` 会定时从数据库同步 `options` 和 `channels`,不需要每次都重启容器。 +- 日志关键字: + - `syncing options from database` + - `syncing channels from database` +- 这次补 `ModelRatio` 后,服务在热同步后即生效。 + +### 8. 当前遗留问题 +- 日志里仍有报错: + - `failed to update option map: json: cannot unmarshal object into Go value of type float64` +- 说明某些 `options` JSON 结构与当前解析逻辑不匹配。 +- 这次 `claude-opus-4-6` 问题已修复,但后续应专项清理 `ModelPrice` / 其他 option 的 JSON 格式问题。 + +## 后续排障原则 +- 不要先改 Docker 配置,先查数据库表: + - `channels` + - `abilities` + - `options` +- 不要因为代码默认值存在,就假定线上有效。 +- 遇到“倍率或价格未配置”时,优先检查: + - `options.ModelRatio` + - `options.ModelPrice` +- 遇到渠道测试失败时,先分清: + - 是上游不通 + - 还是服务端计费配置缺失 + +## 9. 当前线上部署形态(2026-04-04 更新) +- 远程服务器仍是:`个人-minione-ubuntu-infra-4c16g120g` +- `new-api` **不再**以 Docker 应用容器运行;当前由宿主机 `systemd` 服务启动: + - 服务名:`new-api` + - `systemctl is-active new-api` 应返回 `active` + - `systemctl is-enabled new-api` 应返回 `enabled` +- 当前线上运行版本固定为最新稳定 tag: + - `v0.11.9` +- 实际部署目录不是 `/root/new-api`,而是单独的源码 worktree: + - `/root/new-api-v0.11.9` +- 关键文件: + - 二进制:`/root/new-api-v0.11.9/new-api` + - 运行环境:`/root/new-api-v0.11.9/.env.runtime` + - 启动脚本:`/root/new-api-v0.11.9/run-new-api.sh` + - systemd 单元文件:`/etc/systemd/system/new-api.service` + +## 10. 依赖服务与连接方式(2026-04-04 更新) +- PostgreSQL 和 Redis 仍然跑在 Docker 中,但**只作为依赖容器**存在,不再承载应用本体。 +- 当前容器: + - PostgreSQL:`postgres` + - Redis:`redis` +- 当前宿主机固定入口: + - PostgreSQL:`127.0.0.1:5433` + - Redis:`127.0.0.1:6379` +- `new-api` 宿主机进程必须连接宿主机固定入口,不要再依赖容器名或容器 IP: + - `SQL_DSN=postgresql://root:123456@127.0.0.1:5433/new-api` + - `REDIS_CONN_STRING=redis://127.0.0.1:6379` +- 原因: + - 容器 IP 会变,写死就是垃圾设计。 + - 用宿主机固定入口,重建 PG/Redis 容器时不需要改应用配置。 + +## 11. 数据保护与备份(2026-04-04 更新) +- PostgreSQL 数据仍保存在 Docker volume: + - `new-api_pg_data` +- **不要**删除、重建、覆盖这个 volume,除非明确知道自己在做什么。 +- 本次切换前已做 PG 备份: + - `/root/backups/new-api/new-api-cutover-20260404-094849.dump` +- 这次切换后已核对关键表仍在: + - `channels=10` + - `abilities=153` + - `options=9` + +## 12. 运维入口与排障顺序(2026-04-04 更新) +- 现在排障先看 `systemd`,不是先看 Docker 应用容器: + - `systemctl status new-api` + - `journalctl -u new-api -n 200 --no-pager` + - `journalctl -u new-api -f` +- 服务健康检查: + - `curl http://127.0.0.1:3000/api/status` +- 当前线上版本应看到: + - `v0.11.9` +- Docker 现在只需要关心依赖容器是否活着: + - `docker ps | grep -E 'postgres|redis'` +- 不要再默认使用 `/root/new-api/docker-compose.yml` 管理应用本体。 + - 这个仓库目录现在主要是源码主仓库,不是实际运行目录。 + - 实际运行目录是 `/root/new-api-v0.11.9` + +## 13. 后续升级原则(2026-04-04 更新) +- 升级时优先选择新的**稳定 tag**,不要直接拿 `main` 或 `latest` 当生产版本。 +- 合理流程应该是: + 1. 为目标稳定 tag 建单独部署目录或 worktree + 2. 编译产出新二进制 + 3. 保留 PG volume,不迁移数据库文件路径 + 4. 让 systemd 指向新版本 + 5. 验证 `api/status`、日志、数据库连接再收尾 +- 如果有人再次看到 `docker-compose.yml` 里定义了 `new-api` 服务,不要想当然地认定线上还在用容器跑应用;先查: + - `systemctl status new-api` + - `ss -lntp | grep :3000` + +## 14. infra 虚拟机上的 Gitea 部署(2026-04-04 更新) +- 远程服务器:`个人-minione-ubuntu-infra-4c16g120g` +- Gitea 当前以 Docker 方式部署,不与 `new-api` 共用应用容器。 +- 当前镜像固定为稳定版本: + - `docker.gitea.com/gitea:1.25.5` +- 容器名: + - `gitea` +- 访问端口: + - Web:`3001` + - SSH:`2222` +- 当前 Web 根地址配置为: + - `http://100.64.0.11:3001/` +- 如果后续公网域名或访问地址变了,优先修改: + - `/opt/gitea/data/gitea/conf/app.ini` + - 重点字段:`DOMAIN`、`SSH_DOMAIN`、`ROOT_URL` + +## 15. Gitea 数据与配置位置(2026-04-04 更新) +- Gitea 部署目录: + - `/opt/gitea` +- compose 文件: + - `/opt/gitea/docker-compose.yml` +- Gitea 数据目录(bind mount,不是 named volume): + - `/opt/gitea/data` +- 主配置文件: + - `/opt/gitea/data/gitea/conf/app.ini` +- 敏感环境变量文件(root only): + - `/opt/gitea/.env` +- 这份 `.env` 里包含: + - PostgreSQL 密码 + - Gitea 管理员初始密码 + - Gitea 各类 secret/jwt token +- 不要把 `/opt/gitea/.env` 提交到仓库、复制到公开位置或随手改权限。 + +## 16. Gitea 与 PostgreSQL 的关系(2026-04-04 更新) +- Gitea **复用了现有 PostgreSQL 实例**,但没有复用 `new-api` 的数据库。 +- Gitea 专用 PostgreSQL 角色与数据库: + - role:`gitea` + - database:`gitea` +- 连接方式不是宿主机 `127.0.0.1:5433`,而是容器内直接走共享 Docker 网络: + - host:`postgres:5432` +- 共享网络: + - `new-api_new-api-network` +- 原则: + - 复用的是 PG 实例,不是 `new-api` 数据库。 + - 不要把 Gitea 表写进 `new-api` 库,那是纯粹找死。 + +## 17. Gitea 运维与排障(2026-04-04 更新) +- 查看状态: + - `cd /opt/gitea && docker compose ps` + - `docker ps | grep gitea` +- 查看日志: + - `docker logs -f gitea` +- 重启: + - `cd /opt/gitea && docker compose restart` +- 健康检查: + - `curl --noproxy '*' http://127.0.0.1:3001/` +- 由于远程机器设置了代理环境变量,使用本机 `curl` 打本机端口时优先加: + - `--noproxy '*'` +- 否则很容易出现假的 `502`,把问题看错。 +- Gitea SSH 应走**内置 SSH 服务**,当前正确的宿主机端口映射是: + - `2222:2222` +- 不要把宿主机 `2222` 映射到容器 `22`。 + - 那样连到的是容器里的 OpenSSH,不是 Gitea SSH,用户公钥会“看起来加了但就是登不上”。 + +## 18. Gitea 初始化状态(2026-04-04 更新) +- 当前已完成初始化,不是安装向导状态。 +- 首页应能看到: + - `Explore` + - `Sign In` +- 当前已创建管理员账号: + - 用户名:`admin` +- 初始密码不写进文档正文,去看: + - `/opt/gitea/.env` +- 第一次登录后应尽快修改管理员密码。 +- 当前推荐通过 Tailscale 地址访问: + - Web:`http://100.64.0.11:3001/` + - SSH:`ssh -p 2222 git@100.64.0.11` +- 当前设备的 SSH 公钥已加入 `admin` 账号,key title 为: + - `qingse-macbook-id_ed25519` +- 如果后续再次修改了 `2222` 的目标服务,客户端可能需要刷新: + - `~/.ssh/known_hosts` + +## 19. Gitea 上的 new-api 镜像仓库(2026-04-04 更新) +- 已在 Gitea 中创建仓库: + - `admin/new-api` +- 当前不是普通仓库,而是 **GitHub pull mirror**: + - 上游:`https://github.com/QuantumNous/new-api.git` + - Gitea 地址:`http://100.64.0.11:3001/admin/new-api` + - SSH clone:`ssh://git@100.64.0.11:2222/admin/new-api.git` +- 当前镜像同步间隔: + - `24h0m0s` +- 这类 mirror 的核心用途是同步 Git 数据: + - branches + - tags + - commits +- 不要把它误解成 GitHub 全量镜像站。 + - 现在配置的不是 GitHub issue / PR / release 的持续双向同步。 + - 它的重点是把仓库代码历史持续拉到 Gitea。 diff --git a/CLAUDE.md b/CLAUDE.md index f0385a57..220ea3b6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -130,3 +130,165 @@ For request structs that are parsed from client JSON and then re-marshaled to up - field absent in client JSON => `nil` => omitted on marshal; - field explicitly set to zero/false => non-`nil` pointer => must still be sent upstream. - Avoid using non-pointer scalars with `omitempty` for optional request parameters, because zero values (`0`, `0.0`, `false`) will be silently dropped during marshal. + + +# new-api 项目排障记录 + +## 本次对话确认的关键信息 + +### 1. 部署与配置位置 +- 远程服务器:`个人-minione-ubuntu-infra-4c16g120g` +- `new-api` 以 Docker 容器运行,容器名:`new-api` +- 渠道配置不在 `docker-compose.yml` 里维护,核心数据在 PostgreSQL 数据库表中: + - `channels` + - `abilities` + - `options` + +### 2. 新渠道 `xianyu-claude-opus4.6-40` +- 数据库中已存在该渠道,不是“未创建”问题。 +- 关键字段: + - `name = xianyu-claude-opus4.6-40` + - `type = 14` + - `base_url = http://cccai.cfd` + - `models = claude-opus-4-6` +- `abilities` 已同步出三组能力: + - `default` + - `vip` + - `svip` +- 已补齐: + - `test_model = claude-opus-4-6` + +### 3. 上游协议与验证方式 +- 该渠道支持 `v1/messages`。 +- 直接请求上游验证通过: + - `POST http://cccai.cfd/v1/messages` + - Header 需要: + - `content-type: application/json` + - `x-api-key: ` + - `anthropic-version: 2023-06-01` +- 实测返回 `200`,模型 `claude-opus-4-6` 可正常响应。 + +### 4. `/api/channel/test` 报错的真实原因 +- 报错: + - `模型 claude-opus-4-6 倍率或价格未配置` +- 这不是渠道连通性问题,而是计费配置问题。 +- 代码位置: + - `relay/helper/price.go` +- 测试渠道时,服务端会先查: + - `options.ModelPrice` + - 查不到再查 `options.ModelRatio` +- 两者都 miss 时,就会抛出上面的错误。 + +### 5. 本次实际修复 +- 远程数据库中的 `options.ModelRatio` 被自定义值覆盖,缺少: + - `claude-opus-4-6` +- 已补上: + - `ModelRatio["claude-opus-4-6"] = 2.5` +- 补完后验证通过: + - `GET /api/channel/test/9?model=claude-opus-4-6&endpoint_type=anthropic` + - 返回:`{"message":"","success":true,"time":8.601}` + +### 6. 默认值与线上值的关系 +- 代码默认倍率里本来就有: + - `claude-opus-4-6: 2.5` +- 代码位置: + - `setting/ratio_setting/model_ratio.go` +- 但线上运行时会被数据库中的 `options.ModelRatio` 覆盖。 +- 结论: + - 代码里有默认值,不代表线上一定可用。 + - 查问题时必须先看数据库 `options` 实际内容。 + +### 7. 线上热同步行为 +- `new-api` 会定时从数据库同步 `options` 和 `channels`,不需要每次都重启容器。 +- 日志关键字: + - `syncing options from database` + - `syncing channels from database` +- 这次补 `ModelRatio` 后,服务在热同步后即生效。 + +### 8. 当前遗留问题 +- 日志里仍有报错: + - `failed to update option map: json: cannot unmarshal object into Go value of type float64` +- 说明某些 `options` JSON 结构与当前解析逻辑不匹配。 +- 这次 `claude-opus-4-6` 问题已修复,但后续应专项清理 `ModelPrice` / 其他 option 的 JSON 格式问题。 + +## 后续排障原则 +- 不要先改 Docker 配置,先查数据库表: + - `channels` + - `abilities` + - `options` +- 不要因为代码默认值存在,就假定线上有效。 +- 遇到“倍率或价格未配置”时,优先检查: + - `options.ModelRatio` + - `options.ModelPrice` +- 遇到渠道测试失败时,先分清: + - 是上游不通 + - 还是服务端计费配置缺失 + +## 9. 当前线上部署形态(2026-04-04 更新) +- 远程服务器仍是:`个人-minione-ubuntu-infra-4c16g120g` +- `new-api` **不再**以 Docker 应用容器运行;当前由宿主机 `systemd` 服务启动: + - 服务名:`new-api` + - `systemctl is-active new-api` 应返回 `active` + - `systemctl is-enabled new-api` 应返回 `enabled` +- 当前线上运行版本固定为最新稳定 tag: + - `v0.11.9` +- 实际部署目录不是 `/root/new-api`,而是单独的源码 worktree: + - `/root/new-api-v0.11.9` +- 关键文件: + - 二进制:`/root/new-api-v0.11.9/new-api` + - 运行环境:`/root/new-api-v0.11.9/.env.runtime` + - 启动脚本:`/root/new-api-v0.11.9/run-new-api.sh` + - systemd 单元文件:`/etc/systemd/system/new-api.service` + +## 10. 依赖服务与连接方式(2026-04-04 更新) +- PostgreSQL 和 Redis 仍然跑在 Docker 中,但**只作为依赖容器**存在,不再承载应用本体。 +- 当前容器: + - PostgreSQL:`postgres` + - Redis:`redis` +- 当前宿主机固定入口: + - PostgreSQL:`127.0.0.1:5433` + - Redis:`127.0.0.1:6379` +- `new-api` 宿主机进程必须连接宿主机固定入口,不要再依赖容器名或容器 IP: + - `SQL_DSN=postgresql://root:123456@127.0.0.1:5433/new-api` + - `REDIS_CONN_STRING=redis://127.0.0.1:6379` +- 原因: + - 容器 IP 会变,写死就是垃圾设计。 + - 用宿主机固定入口,重建 PG/Redis 容器时不需要改应用配置。 + +## 11. 数据保护与备份(2026-04-04 更新) +- PostgreSQL 数据仍保存在 Docker volume: + - `new-api_pg_data` +- **不要**删除、重建、覆盖这个 volume,除非明确知道自己在做什么。 +- 本次切换前已做 PG 备份: + - `/root/backups/new-api/new-api-cutover-20260404-094849.dump` +- 这次切换后已核对关键表仍在: + - `channels=10` + - `abilities=153` + - `options=9` + +## 12. 运维入口与排障顺序(2026-04-04 更新) +- 现在排障先看 `systemd`,不是先看 Docker 应用容器: + - `systemctl status new-api` + - `journalctl -u new-api -n 200 --no-pager` + - `journalctl -u new-api -f` +- 服务健康检查: + - `curl http://127.0.0.1:3000/api/status` +- 当前线上版本应看到: + - `v0.11.9` +- Docker 现在只需要关心依赖容器是否活着: + - `docker ps | grep -E 'postgres|redis'` +- 不要再默认使用 `/root/new-api/docker-compose.yml` 管理应用本体。 + - 这个仓库目录现在主要是源码主仓库,不是实际运行目录。 + - 实际运行目录是 `/root/new-api-v0.11.9` + +## 13. 后续升级原则(2026-04-04 更新) +- 升级时优先选择新的**稳定 tag**,不要直接拿 `main` 或 `latest` 当生产版本。 +- 合理流程应该是: + 1. 为目标稳定 tag 建单独部署目录或 worktree + 2. 编译产出新二进制 + 3. 保留 PG volume,不迁移数据库文件路径 + 4. 让 systemd 指向新版本 + 5. 验证 `api/status`、日志、数据库连接再收尾 +- 如果有人再次看到 `docker-compose.yml` 里定义了 `new-api` 服务,不要想当然地认定线上还在用容器跑应用;先查: + - `systemctl status new-api` + - `ss -lntp | grep :3000`