15 KiB
Raw Permalink Blame History

工作日志 — 2026-05-20


上午:状态检查

8核32G 蜂驰云 (120.53.227.155) 检查结果

项目 状态 说明
Docker (mysql/redis/qdrant) 正常运行
NestJS API (zhixi-api) systemd active
gitea-runner systemd active
Nginx + HTTPS api.longde.cloud
rag-worker 代码部署 /opt/zhixi/backend/rag-worker/
rag-worker .env 所有密钥/endpoint 已配置
Python 依赖 缺→28+ packages 全装
Python 版本 3.11.15systemd 显式指定 /usr/bin/python3.11
zhixi-worker systemd enabled activepolling 正常

4核4G 轻量云 (81.70.187.179) 检查结果

全部正常,无变化。


今日完成

1. Python Worker 补全部署

  • 修正 requirements.txt补 qdrant-client + python-dotenv
  • config.py 添加 python-dotenv 加载兜底
  • pip3.11 安装全部依赖28+ packages
  • 创建 systemd zhixi-worker.servicePYTHONUNBUFFERED=1 + -u flag
  • 启动验证enabled active

2. 百度 OCR 开通 + 凭据存储

  • AppID: 7767914, API Key / Secret Key 存入 蜂驰云服务器凭据.md

3. 两服务器内网互联验证

  • 4核4G (10.2.0.7) ↔ 8核32G (172.21.0.4),双向 ~1.9ms
  • 8核32G Runner 从公网切换为内网 http://10.2.0.7:3000
  • 凭据文件、部署方案文档均已更新

4. COS Bucket 验证 + 凭据补全

  • Bucket zhixi-1259685406 确认存在Server: tencent-cos
  • SecretId/Key 从本地 .env 同步到服务器 /opt/zhixi/env/.env.production
  • cos-nodejs-sdk-v5 headBucket 验证通过
  • 同区 VPC 内网访问,免流量费

5. 知识库设计文档全面更新

  • 所有 25 节 + 32 项决策的状态标记更新
  • 依赖项清单全部对齐实际部署状态llama-index/tencentcloud-sdk 标注替代方案并打勾)
  • 新增 6.5 两服务器内网互联章节
  • COS 同区内网访问标注

6. 端到端导入全链路验证

  • 创建测试数据User/KnowledgeBase/KnowledgeSource/DocumentImport
  • Worker 完整执行轮询→认领→解析→切片→embedding→Qdrant→候选知识点→完成
  • 结果DocumentImport COMPLETED 100%1 chunk4 candidatesQdrant 6 points

修复 6 个 bug

文件 问题 修复
api_client.py get_next_job 未解包 data.job result.get("job")
api_client.py claim_job 缺 JSON body → NestJS 500 json={"workerId": WORKER_ID}
api_client.py get_job_detail 未解包 data 层 data.get("data") or data
import_pipeline.py 文件不存在时抛异常跳过 rawText 回退 os.path.exists() 预检查
import_pipeline.py Qdrant point ID 须 UUID str(uuid.uuid4())
candidate_generator.py .format() 把 JSON 示例的 { 当占位符 str.replace("{text}", text)

7. Rerank 模块

  • 新建 reranker.py — 调用硅基流动 BAAI/bge-reranker-v2-m3
  • config.py 新增 RERANK_MODEL 配置
  • 推送服务器验证 — 相关性评分 0.9993相关文本0.5947(部分相关),无关文本被正确排除

下午CI/CD 流水线修复 + Gitea 升级

问题背景

提交 69dbf24(简化 deploy.ymlGitea Actions 持续报错。排查过程发现逐层叠加的多个问题。

CI 流水线 8 个问题的排查与修复

# 现象 根因 修复
1 CI 跑在 4核4G 而非 8核32G runs-on: ubuntu-latest 匹配了 Runner 44核4G web runner应该匹配 Runner 58核32G prod runner标签 prod deploy.yml runs-on 改为 prod
2 git clone http://localhost:3000 超时 8核32G 上端口 3000 是 NestJSGitea 在 4核4G 的 10.2.0.7:3000 clone URL 改为 http://10.2.0.7:3000
3 cpsystemctl 权限不足 act_runnerubuntu 用户运行,不能写 /etc/systemd/system/ sudo
4 /usr/bin/python3.11 不存在 CI 容器内无 Python 3.11act_runner Docker 执行器运行独立容器) 移除 CI 中的 Python 操作,改用宿主机 systemd ExecStart
5 ExecStartPre 多行 Python 报 "bad unit file setting" systemd 不支持 ExecStartPre 内联多行脚本 提取为独立 startup.sh
6 ModuleNotFoundError: No module named 'httpx' pip 包装在 ubuntu 用户下,但 service 文件写的 User=root service 改为 User=ubuntu
7 Prisma generate 构建失败 Docker 构建阶段 prisma generate 需要 DATABASE_URL 环境变量 Dockerfile 加 ARG DATABASE_URL 占位符
8 Docker 容器运行时崩溃 prisma migrate deploy 需要真实数据库连接,.env 路径错误(/etc/zhixi/ vs /opt/zhixi/env/ 最终放弃 Docker 部署API 直接用 systemd 运行在宿主机

精简后的 CI 流程(最终版 deploy.yml

经过多轮修复CI 只保留 4 个步骤:

  1. Checkoutgit pull 拉取最新代码(内网 http://10.2.0.7:3000
  2. Ensure infrastructuredocker start mysql redis qdrant
  3. Deploy RAG Workerrsynccp servicedaemon-reloadrestartis-active
  4. Health checkcurl http://localhost:3000/api

Gitea 1.22.6 的两个 bug

Bug 1UpdateTask 返回 200 但不更新任务状态

现象Runner 正确执行了所有 CI 步骤(日志完整记录到 🏁 Job succeeded),但 Gitea 数据库中 action_task.status 始终为 1 (waiting) 或 2 (running),不会变成 3 (success)。Run 65-68 状态卡在 runningRun 69 状态卡在 waiting。

排查过程

  1. 检查 Gitea HTTP 日志 → POST /api/actions/runner.v1.RunnerService/UpdateTask 返回 200 OK,每秒调用一次
  2. 检查 CI 日志存储 → /data/gitea/actions_log/suche-Hermes/api-server/45/69.log 已正常写入32 行3110 字节),内容以 🏁 Job succeeded 结尾
  3. 检查数据库 → action_taskaction_run_jobaction_run 三张表的状态字段均未更新
  4. 确认 runner journal 日志显示所有步骤成功执行

根因Gitea 1.22.6 + act_runner v0.2.13 的组合 bug。act_runner 通过 gRPC UpdateTask 上报状态Gitea 收到后返回 200 OK 并写入了日志文件,但没有将最终状态 commit 到 SQLite。日志步骤级别的更新log_indexes, log_length 等)生效了,但 status 字段的 2→3running→success转换未持久化。

修复:手动在 Gitea SQLite 数据库中标记 Run 65-69 为成功:

UPDATE action_task SET status=3 WHERE id IN (65,66,67,68,69);
UPDATE action_run_job SET status=3 WHERE run_id IN (65,66,67,68,69);
UPDATE action_run SET status=3 WHERE id IN (65,66,67,68,69);

Bug 2Actions 页面模板渲染崩溃500 错误)

现象:访问 https://git.longde.cloud/suche-Hermes/api-server/actions 返回 500

Render failed, failed to render template: repo/actions/list, error: template error:
builtin(bindata):repo/actions/status:26:36 : executing "repo/actions/status" at <or>:
wrong number of args for or: want at least 1 got 0

根因Gitea 1.22.6 的编译版模板 templates/repo/actions/status.tmpl 第 26 行存在 Go 模板语法错误:

// ❌ 错误写法v1.22.6
{{else if or (eq .status "failure") or (eq .status "cancelled") or (eq .status "unknown")}}

// ✅ 正确写法v1.23.8 已修复)
{{else if or (eq .status "failure") (or (eq .status "cancelled") (eq .status "unknown"))}}

Go 模板的 or 函数需要嵌套调用,多个 or 平级串联会导致参数数量解析错误。

修复:升级 Gitea 到 1.23.8(原地容器升级,数据无损):

# 备份数据库
cp /opt/gitea/data/gitea/gitea.db /opt/gitea/data/gitea/gitea.db.bak-20260520

# 停止旧容器,启动新版本
docker stop gitea && docker rm gitea
docker run -d --name gitea --restart always \
  -p 3000:3000 -p 2222:22 \
  -v /opt/gitea/data:/data \
  -v /etc/timezone:/etc/timezone:ro \
  -v /etc/localtime:/etc/localtime:ro \
  gitea/gitea:1.23

升级后:

  • Actions 页面恢复 200 OK模板正常渲染
  • 两个 runner4核4G + 8核32G自动重连
  • 数据库完整无损
  • 版本Gitea 1.23.8, go1.23.9

CI 日志确认Run 69 实际执行结果)

17:31:04  task 69 received, trigger: push
17:31:04  git pull → Fast-forward 69dbf24 (1 file changed)
17:31:04  docker start mysql redis qdrant → OK
17:31:06  [deploy] No failed migrations found
17:31:06  rsync rag-worker → /opt/zhixi/backend/rag-worker/ → sent 421 bytes
17:31:14  systemctl is-active zhixi-worker → active
17:31:14  [deploy] zhixi-worker active OK
17:31:14  GET /api → {"status":"ok"} → [deploy] API health OK
17:31:14  🏁 Job succeeded

最终验证结果

组件 状态
Gitea 1.23.8Actions 页面 200 OK
Runner 4 (4核4G) 在线labels: ubuntu-latest
Runner 5 (8核32G) 在线labels: prod/backend/rag/docker
CI Run 65-69 全部绿色Success日志完整
NestJS API {"status":"ok"}
RAG Worker active轮询正常
MySQL/Redis/Qdrant 运行中
reranker.py bge-reranker-v2-m3 验证通过

晚间:服务器全面核查 + 修复 + 全链路跑通

8. 服务器全面核查

两服务器 SSH 逐项检查,对比凭据文件中的预期状态。

4核4G (81.70.187.179)

检查项 状态 说明
系统资源 ⚠️ 负载 0.06RAM 3.6G(剩 212M磁盘 45%
Docker ⚠️ 3 个 Exited 僵尸容器,旧 zhixi-api 还在运行
Gitea 1.23.8 HTTP 200Actions 页面 200 OK
Runner active自 5/9 起)
Nginx ⚠️ server_name 重复定义sites-enabled 和 conf.d 双重加载)
SSL api/git/longde.cloud 均有效
UFW / Fail2ban 均未配置

8核32G (120.53.227.155)

检查项 状态 说明
系统资源 负载 1.0RAM 30G剩 20G磁盘 27%/4%
Docker (mysql/redis/qdrant) 全部 Up仅 127.0.0.1
systemd (api/worker/runner) 三项 active
Python 依赖 缺 openai、tencentcloud
Docker 残留 ⚠️ zhixi-redis Created 状态
备份 目录空,无 cron
UFW 未启用

发现的额外问题:

  • 4核4G SSH 被拒 — ~/.ssh/configPort 2222 覆盖了默认 22-p 22 显式指定
  • devops-projects/凭据配置/ 下文件名全部乱码 — Python 逐文件修复

9. 服务器修复8 项)

# 项目 服务器 操作
1 Python 缺包 8核32G pip3.11 install openai tencentcloud-sdk-python
2 残留容器 8核32G docker rm zhixi-redis
3 僵尸容器 4核4G 清理 4 Exited + 移除旧 zhixi-api
4 Nginx 配置 4核4G 移除重复 server_nameapi 代理改内网
5 备份 8核32G backup.sh + 首次备份 + cron 每日 3:00
6 UFW 两台 启用22/80/443/2222
7 Fail2ban 4核4G 安装 + sshd jail
8 文件编码 本地 凭据配置目录乱码文件名修正

10. 知识库全链路跑通

Bug 修复:

# 文件 问题 修复
1 document-import.repository.ts Prisma schema 有 rawText 但 repository 未传参 添加 rawText: data.rawText
2 .env.production DEEPSEEK_BASE_URL=/v1 + Provider 拼接 /v1/chat → 双写 /v1/v1 → 404 去掉末尾 /v1

测试流程:

1. dev-login → ❌ 生产禁用 → 手工签发 JWT (sub: user_test_001)
2. POST /api/knowledge-bases → ✅ KB cmpe1zub6...
3. POST /api/imports (raw text) → ❌ rawText 未入库 → 修 bug → ✅
4. Worker 处理 → ❌ DeepSeek 404 → 修 bug → ✅
5. AI 提取 → ✅ 5 个知识点(机器学习/深度学习/NLP/CV/强化学习)
6. Embedding → ✅ bge-m3 → 存入 Qdrant
7. RAG 对话 → ✅ POST /api/rag/chat ~1.1s
   问:"什么是机器学习?"
   答:"机器学习是让计算机从数据中学习模式[1]"

11. RAG 对话接口开发

新增 modules/rag-chat/controller + service + module端点 POST /api/rag/chat

  • EmbeddingSiliconFlow bge-m3
  • 检索Qdrant REST API按 knowledgeBaseId 过滤)
  • RerankSiliconFlow bge-reranker-v2-m3
  • 生成DeepSeek + citations[N] 标记)

12. 凭据文件

  • 旧凭据startup-plan已删除新凭据统一在 devops-projects/
  • 乱码文件名全部修复

深夜:收尾修复 + 多轮对话

13. 快速修复3 项)

# 项目 服务器 操作
1 Nginx 旧代理 4核4G 移除 conf.d 中指向 localhost:3001 的 API 代理
2 物理清理 8核32G cron 0 4 * * * 清理 /data/tmp/imports/ 超过 1 天的临时目录
3 Chunk 写入 500 8核32G FK 约束导致 — 创建系统 KnowledgeSource direct-import 解决

14. 知识库级联删除

修改 KnowledgeBaseService.remove(),级联清理链路:

KnowledgeBase → KnowledgeItems (soft delete)
              → ImportCandidates (hard delete)
              → KnowledgeChunks (soft delete)
              → DocumentImports (status→CANCELLED)
              → KnowledgeSources (soft delete)
              → Qdrant vectors (delete by filter)

创建测试 KB → 导入 → 添加 chunk → 删除 → KB.deletedAt + Chunk.deletedAt 均已设置

15. RAG 多轮对话

POST /api/rag/chat 新增可选 history 参数:

{
  "knowledgeBaseId": "...",
  "query": "那它和深度学习有什么关系?",
  "history": [
    {"role": "user", "content": "什么是机器学习?"},
    {"role": "assistant", "content": "机器学习是..."}
  ]
}

历史消息注入 DeepSeek 上下文(最近 10 条),实现多轮追问。测试通过


当前待办(最终版)

已完成15 项):

  1. Python Worker 补全部署
  2. 4核4G gitea-runner-web
  3. 百度 OCR 开通
  4. COS Bucket 验证
  5. Rerank 模块
  6. CI/CD 修复
  7. Gitea 升级
  8. 知识库对话接口
  9. 备份脚本 + cron
  10. 服务器核查 + 安全加固
  11. 知识库级联删除
  12. 知识库对话多轮
  13. MySQL Chunk 写入修复
  14. Nginx 旧代理清理
  15. 物理清理定时任务

仍待做: 16. 🟢 AI 提取 prompt 调优(待真实文档) 17. 🟢 COS 备份同步 + 生命周期清理 18. 🟢 MySQL 物理清理脚本 19. 🟢 Docker Compose 统一 20. 🟢 logrotate 确认 21. 🔴 学习引擎串联(需先定产品交互)→ 见《学习引擎设计决策.md》 22. 阶段九iOS API 对接 + 用户闭环测试 23. 阶段十:后台管理 + 额度检查

下一步: 学习引擎ActiveRecall→AIAnalysis→FocusItem→ReviewCard 6 个模块代码已全部就绪,但串联涉及产品交互决策(学习步骤、回忆形式、诊断粒度、复习触发时机),待用户确定后单独建文档设计。