353 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 工作日志 — 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 补全部署 ✅
- [x] 修正 requirements.txt补 qdrant-client + python-dotenv
- [x] config.py 添加 python-dotenv 加载兜底
- [x] pip3.11 安装全部依赖28+ packages
- [x] 创建 systemd zhixi-worker.servicePYTHONUNBUFFERED=1 + -u flag
- [x] 启动验证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 模块 ✅
- [x] 新建 `reranker.py` — 调用硅基流动 `BAAI/bge-reranker-v2-m3`
- [x] `config.py` 新增 `RERANK_MODEL` 配置
- [x] 推送服务器验证 — 相关性评分 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 | `cp``systemctl` 权限不足 | `act_runner``ubuntu` 用户运行,不能写 `/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. **Checkout**`git pull` 拉取最新代码(内网 `http://10.2.0.7:3000`
2. **Ensure infrastructure**`docker start mysql redis qdrant`
3. **Deploy RAG Worker**`rsync``cp service``daemon-reload``restart``is-active`
4. **Health check**`curl 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_task``action_run_job``action_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 为成功:
```sql
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 模板语法错误:
```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(原地容器升级,数据无损):
```bash
# 备份数据库
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/config``Port 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`
- **Embedding**SiliconFlow bge-m3
- **检索**Qdrant REST API按 knowledgeBaseId 过滤)
- **Rerank**SiliconFlow 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` 参数:
```json
{
"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 个模块代码已全部就绪,但串联涉及产品交互决策(学习步骤、回忆形式、诊断粒度、复习触发时机),待用户确定后单独建文档设计。
---