本地调试与启动

在开发机上把数据服务、节点控制服务、Tunnel Runtime 和 Web 前端逐个拉起来,并用日志与接口探针定位问题。生产部署走 Docker Compose,见 部署文档。

0. 四个进程与端口

本地调试是手工拉起多个进程,不是一个命令。先记住谁监听哪个端口、谁是可选的:

进程启动命令默认端口必需性
数据服务python main.py8001必需。API、管理端、用户门户、Agent 运行时、MCP 都在这里。
节点控制服务python -m node_server8003用节点/编辑器/任务/终端时必需。不是网页,只接节点连接和数据服务的内部调用。
Tunnel Runtimepython -m tunnel_server8004用内网穿透(frp / cloudflared / nps)时必需。
Web 前端 Vitepnpm dev:offline11180调前端页面时用;只调 API 可以不启,直接打 8001。
三个 Python 进程共享同一份 .env 和同一个 PostgreSQL/Redis。它们各自独立解析配置(数据服务读 server/bootstrap_config.py,控制服务读 node_server/config.py),字段含义见 环境变量清单。Compose 里这三个进程是三个容器跑同一个镜像、换 command。

1. 环境准备

还没有代码?先完成部署文档的「拉取代码与子模块」一步——五个子模块必须显式拉取,否则前端和节点二进制都不在。
  • Python 3.11(推荐 venv)+ requirements.txt 依赖。这一份依赖同时覆盖三个 Python 进程,不需要分别装。
  • PostgreSQL 与 Redis(本机、Docker 或远程均可)。Redis 必须 ≥ 6.0:客户端强制 HELLO 3 握手,早期版本没有这个命令。
  • 前端:Node.js 18+ 与 pnpm(仓库锁文件是 pnpm-lock.yaml)。
  • (可选)Go 工具链用于重新构建节点二进制;调试后端通常不需要。
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows Git Bash
# source .venv/Scripts/activate
pip install -r requirements.txt

cp .env.example .env

2. 启动 PostgreSQL 与 Redis

最简单的方式是只启动 Compose 中的依赖,不启动应用:

docker compose up -d postgres redis
docker compose ps

这会把 PostgreSQL 映射到宿主 127.0.0.1:15432、Redis 映射到 127.0.0.1:6479(不是容器内的 5432/6379)。此时把 .env 指到这两个宿主端口:

POSTGRES_HOST=127.0.0.1
POSTGRES_PORT=15432
POSTGRES_USER=ai_lubricant
POSTGRES_PASSWORD=ai_lubricant
POSTGRES_DATABASE=ai-lubricant

REDIS_HOST=127.0.0.1
REDIS_PORT=6479
REDIS_DB=0
REDIS_PREFIX_KEY=marsview
.env 是扁平的 KEY=VALUE,没有 [section] 节头。.env.example 里的 # [postgres] 只是分组注释。当前代码不解析任何 INI/JSON 配置文件——启动配置只有「环境变量 → .env → 内置默认值」三层,写成 host = 127.0.0.1 这种 INI 风格不会生效。
也可以直接用系统安装的服务在 macOS/Windows 上手动安装 PostgreSQL/Redis,然后把 .env 的 host/port 指过去(通常是默认的 5432/6379)。Docker Compose 只负责依赖,不负责前端和节点控制服务。

3. 初始化数据库

python server/init_db.py

脚本连接到默认 postgres 库,若不存在则创建 ai-lubricant 数据库,然后执行 sql/init.sql 建表。重复运行是安全的(存在则跳过)。注意路径带 server/,脚本不在仓库根。

主配置与引导建表和写业务配置是两回事。若数据服务启动时提示缺少 app_config['main'] 主配置,需要从既有环境导入配置,或在管理端完成初始化引导(取决于部署流程)。不要用“反复重启”解决配置缺失。

4. 启动数据服务

# 常规
python main.py

# 调试开发模式:自动重载
uvicorn main:app --host 0.0.0.0 --port 8001 --reload

# 只监听本机
uvicorn main:app --host 127.0.0.1 --port 8001

python main.py 固定监听 8001(端口写在 main.py 末尾,.env 里的 SERVER_HOST/SERVER_PORT 不生效)。要换地址或端口就用 uvicorn main:app --host ... --port ...。python main.py 没有热重载;日常改代码调试用 uvicorn ... --reload。

直跑 main.py 会建双栈监听Windows 上 localhost 先解析 ::1,只绑 0.0.0.0 会让客户端先等一次 IPv6 连接失败(本机约 2 秒)。main.py 显式创建 IPv4/IPv6 双栈 socket 规避;用 uvicorn --host 时没有这层处理,排障统一用 127.0.0.1 而不是 localhost。
DEBUG 环境变量缺省时 DEBUG 视为 true(server/config.py),所以本地直跑默认就是调试行为。Compose 的数据服务显式设了 DEBUG=false,生产部署保持这样。

5. 启动节点控制服务

python -m node_server

默认监听 0.0.0.0:8003(NODE_CONTROL_HOST / NODE_CONTROL_PORT 可调)。它用 Hypercorn 而非 uvicorn,因为节点的 NodeConnect 走 h2c(明文 HTTP/2),uvicorn 不支持。

仅调试模型网关 API、前端页面或 MCP 时可以先不启动它;数据服务要用到编辑器、任务、终端、文件、节点出口时才会去调 AGENT_COMPOSE_BASE_URL(本地填 http://127.0.0.1:8003)。

缺 token/密钥时会回写 .env控制服务启动时若发现没有 NODE_CONTROL_TOKEN 或 NODE_CREDENTIAL_ENCRYPTION_KEY,会生成并写回 .env,因此 .env 必须是可写文件。NODE_CONTROL_TOKEN 是数据服务→控制服务的内部 Bearer,两个进程必须读到同一个值;生成后重启数据服务让它读到新值。
控制面切换铁律先停旧控制进程再启新进程,绝不让两个 Registry 对同一批节点下发命令。本地调试多次重启无妨,但不要在两台机器上同时运行控制服务管理同一节点集。

6. 启动 Tunnel Runtime(可选)

python -m tunnel_server

默认监听 0.0.0.0:8004(TUNNEL_RUNTIME_HOST / TUNNEL_RUNTIME_PORT 可调)。它负责管理 frpc / cloudflared / npc 客户端子进程——隧道方案管理页和任务预览端口对外暴露都依赖它。不用内网穿透时可以完全不启动,其余功能不受影响。

它自己不直连节点:启停命令都经 AGENT_COMPOSE_BASE_URL 转给节点控制服务,所以要先有 8003 在跑。穿透客户端二进制不随代码分发,首次使用时联网下载并缓存到 MC_TUNNEL_BIN_DIR。

不要和数据服务并发首启数据服务与 Tunnel Runtime 会各自对同一批穿透表做增量列对账,同时启动有小概率撞车。本地按 main.py → node_server → tunnel_server 的顺序起,Compose 里靠 depends_on + 健康检查达到同样效果。多实例还有单写者租约(TUNNEL_RUNTIME_LEASE_TTL_SECONDS),同一库不要同时跑两个。

7. 启动 Web 前端

cd user-frontend
pnpm install

# 离线/私有化版(默认首页跳到登录),开发端口 11180
pnpm dev:offline

# 在线版
# pnpm dev:online

Vite 默认监听 0.0.0.0:11180。开发服务器把 /api、/admin、/v1、/agent、/mcp 转发到 TARGET(.env.offline 指向 http://localhost:8001;.env.online 使用 VITE_APP_EDITION=online 并默认不设 TARGET)。如果数据服务不在本机 8001,用环境变量或对应 env 文件覆盖 TARGET。

/admin 双用途Vite 对 /admin 做了按 Accept 头分流:浏览器 HTML 导航回到 SPA 的 index.html,XHR/fetch 才转发后端。调试管理页面登录时若只见 HTML 不见接口响应,先确认数据服务是否在 TARGET 上运行。

管理端在 http://localhost:11180/manager,用户门户在 http://localhost:11180/console。

8. 移动端本地调试

移动端位于 mobile/(独立仓库,以 git submodule 挂在主仓该路径;首次需 git submodule update --init mobile),使用 Expo Router + React Native。它通过 Cookie 会话或 Basic Auth 访问同一套数据服务接口;本地调试时通常先按上文启动数据服务(8001),再让 App 指向该后端。

cd mobile
npm install

# 启动 Metro / Expo 开发服务
npm start

# 真机或模拟器调试
npm run android
npm run ios

启动后在登录页填写后端地址(例如 http://127.0.0.1:8001 或局域网 IP)。Android 模拟器访问宿主机后端时,部分环境需要用 http://10.0.2.2:8001 代替 127.0.0.1。

本地校验

cd mobile

# TypeScript 类型检查(当前仓库必须通过)
npx tsc --noEmit

# ESLint(expo 配置)
npx eslint . --no-cache

# Jest(当前 mobile/ 下暂无 *.test.ts(x) 用例,命令可用但通常没有测试可跑)
npm test -- --runInBand --silent
当前校验基线移动端改动至少应通过 npx tsc --noEmit。仓库目前未在 mobile/ 内置 Jest 用例,因此“测试通过”主要依赖类型检查、ESLint 和真机/模拟器手测。

9. 接口探针

数据服务(8001)

# 存活
curl -s http://127.0.0.1:8001/ | head -20

# MCP 运行时健康
curl -s http://127.0.0.1:8001/mcp/health

# 模型列表(无需鉴权)
curl -s http://127.0.0.1:8001/v1/models | head -c 400; echo

节点控制服务(8003)

# 健康:包含已连接节点数
curl -s http://127.0.0.1:8003/health

Tunnel Runtime(8004)

# 就绪:包含 running / notifier 状态
curl -s http://127.0.0.1:8004/ready

前端开发代理(11180)

# 经 Vite 代理访问后端,验证 /api 与 /admin 转发
curl -s http://127.0.0.1:11180/v1/models | head -c 200; echo
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:11180/manager
期望结果GET / 返回 HTML 首页;GET /v1/models 返回包含 data 的 JSON;/mcp/health 返回 {"ok": true, ...};/manager 返回 200(SPA 页面)。

10. 日志

  • 数据服务文件日志:项目根 logs/ai-lubricant-YYYY-MM-DD.log,按天轮转、保留 30 天并压缩。首次启动时自动创建。
  • 标准输出:启动时 loguru 也会输出到控制台。
  • 日志级别:文件 sink 固定 DEBUG;system.debug 与 logging.level 影响业务日志细节。可在管理端主配置页面调整。
  • 敏感字段:文件 sink 使用 diagnose=False,异常堆栈不打印变量值,避免把请求密钥写进日志。
# 跟随日志
tail -f logs/ai-lubricant-$(date +%F).log

# 只看最近错误
grep -iE 'error|traceback|exception' logs/ai-lubricant-$(date +%F).log | tail -30

11. 常见故障排查

现象原因排查/解决
启动即失败,提示连接 PostgreSQL 失败host/port/凭据错误或服务未启动核对 .env 或环境变量;确认 Compose 依赖已 up;从应用容器或宿主机测试端口连通。
启动失败,提示 Redis ping 失败Redis 未启动/地址错误/前缀错误redis-cli ping 验证;检查 prefix_key、db 和 max_connections。
“缺少必填主配置 app_config['main']”空库只有表结构,没有业务主配置补齐/导入主配置,或完成初始化引导;不要反复重启。
前端页面能打开,但 API 请求 404/502Vite TARGET 指向不对或后端没起确认 curl http://127.0.0.1:8001/v1/models;检查 .env 的 TARGET;看 Vite 控制台代理日志。
/manager 打开空白或一直加载管理会话过期或后端 /admin 不可达先访问 /manager/login 应急登录;确认后端 curl http://127.0.0.1:8001/admin/...。
节点控制服务拒绝启动,提示无法回写 .env.env 只读或目录不可写授予进程写权限;检查属主;容器场景确保卷可写。
Tunnel Runtime 起不来 / 一直 not ready8003 没起,或 8004 被占,或穿透客户端二进制下载失败先确认 curl http://127.0.0.1:8003/health 通;看 MC_TUNNEL_BIN_DIR 是否可写、是否联网下载了 frpc/cloudflared/npc。
节点连不上 / 校验失败public_url、token 或主密钥不一致,TOTP 时钟偏差核对节点拨号 URL 与 AGENT_COMPOSE_NODE_SERVER_PUBLIC_URL;确认节点时间与服务器时间偏差在 TOTP 窗口内;核对共享 token 和 NODE_CONTROL_TOKEN / NODE_CREDENTIAL_ENCRYPTION_KEY。
ClickHouse 相关对话/统计不可用未启用 ClickHouse 或地址错误主模型代理链路仍可用;确认是否真的需要该特性,再按部署文档启用。
请求日志出现但响应体为空payload 双写未启用或保留策略若需要 payload,开启 ClickHouse capture 并完成隐私/保留评估;普通日志与主链路不依赖它。