Skip to content

Commit 97e06e0

Browse files
committed
feat(automation): 添加 RAG 数据自动更新工作流和状态管理
- 创建 GitHub Actions 工作流实现博客内容变更后自动更新向量数据库 - 引入 .ingest_state.json 文件记录处理状态实现增量更新 - 更新相关文档说明自动化流程和配置要求 - 优化聊天框 API 请求错误处理逻辑
1 parent 2aaf09b commit 97e06e0

6 files changed

Lines changed: 62 additions & 76 deletions

File tree

docs/PRD/PRD-基于RAG的博客数字分身助手-v1.1.md

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,9 @@ sequenceDiagram
4545
文件位置:/scripts/ingest.py
4646

4747
* **环境依赖**:requests, python-frontmatter (需生成 requirements.txt)
48-
* **鉴权配置**:脚本需读取环境变量 CLOUDFLARE\_ACCOUNT\_ID 和 CLOUDFLARE\_API\_TOKEN(注意:CF\_ 前缀已弃用,需使用 CLOUDFLARE\_ 前缀)。
49-
* **处理逻辑**
50-
1. **解析 Frontmatter**:遍历 content/posts/\*.md,提取 title, date, url (slug)。
51-
2. **文本切片 (Chunking)**
52-
* 清洗 Markdown 符号 (去除图片、粗体标记等)。
53-
* 长度控制:约 500 字符/chunk,重叠 50 字符。
54-
3. **生成确定性 ID (关键)**
55-
* **ID 生成规则**:md5(full\_url \+ chunk\_index)。
56-
* **目的**:实现幂等性。如果文章内容未变,重新运行脚本时,生成的向量 ID 不变,Cloudflare 会执行 Upsert (覆盖) 而不是 Insert (新增),防止数据库产生重复脏数据。
57-
4. **向量化与存储**
58-
* 调用 Cloudflare Workers AI REST API 生成向量。
59-
* 调用 Vectorize REST API 批量上传 (ndjson 格式)。
60-
* **Metadata 设计**
61-
{
62-
"url": "/posts/my-k8s-article/",
63-
"title": "K8s 学习笔记",
64-
"text": "Kubernetes 是一个容器编排平台..."
65-
}
48+
* **鉴权配置**:脚本需读取环境变量 CLOUDFLARE\_ACCOUNT\_ID 和 CLOUDFLARE\_API\_TOKEN。
49+
* **状态管理**:使用 `.ingest_state.json` 记录文件哈希,实现增量更新。
50+
* **自动化**:通过 GitHub Actions (`.github/workflows/rag-ingest.yml`) 自动触发,并自动提交状态文件。
6651

6752
### **模块 B: 后端 API (Pages Function)**
6853

@@ -98,16 +83,10 @@ sequenceDiagram
9883

9984
描述:嵌入博客的悬浮聊天窗。
10085
文件位置:layouts/partials/chatbox.html
86+
样式文件:assets/css/extended/chat.css (移动到 extended 目录以被 Hugo 自动处理)
10187

10288
* **技术栈**:Vanilla JS (无框架依赖,确保轻量)。
103-
* **UI 构成**
104-
* **Launcher**:右下角悬浮圆钮 (SVG Icon)。
105-
* **Chat Window**:包含 Header (博主头像), Message List (滚动区), Input Area。
106-
* **交互逻辑**
107-
* **状态管理**:维护一个简单的 chatHistory 数组在内存中。
108-
* **Markdown 渲染**:引入轻量级库 marked.js (通过 CDN 引入),将 AI 返回的 markdown 文本转为 HTML 显示。
109-
* **Loading 态**:发送请求时,显示 "思考中..." 动画,且禁用输入框。
110-
* **引用展示**:解析后端返回的 metadata,在气泡下方用小字显示 "Ref: \[文章标题\]" 链接,增加可信度。
89+
* **依赖**:marked.js (用于渲染 Markdown 回复)。
11190

11291
## **5\. 提示词工程规范 (System Prompt Spec)**
11392

@@ -150,4 +129,5 @@ Cursor 提示 (Cursor Prompts):
150129
2. requirements.txt: Python 依赖列表。
151130
3. functions/api/chat.js: 含历史记录处理的后端。
152131
4. layouts/partials/chatbox.html: 含 marked.js 集成的前端。
153-
5. assets/css/chat.css: 适配移动端的样式。
132+
5. assets/css/extended/chat.css: 适配移动端的样式。
133+
6. .github/workflows/rag-ingest.yml: 自动化数据更新工作流。

docs/ingest-strategy.md

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,15 @@ make ingest-data
7171
make ingest-data FILE=content/posts/new-article.md
7272
```
7373

74-
### 方式 3: Git Hook(自动化)
74+
### 方式 3: GitHub Actions(CI/CD) - **推荐**
7575

76-
可以添加到 Git pre-commit hook,自动处理修改的文件:
76+
已配置 `.github/workflows/rag-ingest.yml`
77+
每次推送到 `main` 分支且包含 `content/` 目录变更时,会自动运行摄取脚本。
78+
脚本会自动提交更新后的 `.ingest_state.json` 文件,保持状态同步。
7779

78-
```bash
79-
# 安装 Git hooks(如果还没有)
80-
bash scripts/setup_git_hooks.sh
81-
82-
# 然后每次提交包含 .md 文件时,会自动运行摄取脚本
83-
```
84-
85-
### 方式 4: GitHub Actions(CI/CD)
86-
87-
可以添加到 GitHub Actions workflow,在推送时自动运行。
80+
需配置 Secrets:
81+
- `CLOUDFLARE_ACCOUNT_ID`
82+
- `CLOUDFLARE_API_TOKEN`
8883

8984
## 📝 自动化方案
9085

@@ -123,28 +118,29 @@ make ingest-data FILE=content/posts/new-article.md # 处理单个文件
123118
- 需要配置 Git hooks
124119
- 可能增加提交时间
125120

126-
### 方案 C: GitHub Actions(CI/CD 集成)
121+
### 方案 C: GitHub Actions(CI/CD 集成) - **已采用**
127122

128-
GitHub Actions workflow 中添加步骤
123+
`.github/workflows/rag-ingest.yml` 中实现
129124

130125
```yaml
131-
- name: Ingest blog content to Vectorize
132-
env:
133-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
134-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
126+
- name: Run Ingestion Script
135127
run: |
136-
pip install -r requirements.txt
137128
python scripts/ingest.py
129+
- name: Commit State File
130+
run: |
131+
git add .ingest_state.json
132+
git commit -m "🤖 Update RAG ingestion state"
133+
git push
138134
```
139135
140136
**优点**:
141-
- 完全自动化
142-
- 在云端运行,不占用本地资源
143-
- 可以设置定时任务
137+
- 完全自动化,无需本地操作
138+
- 自动处理新文章(包括自动生成的 Daily AI)
139+
- 状态文件自动同步,避免重复计算
144140
145-
**缺点**:
146-
- 需要配置 GitHub Secrets
147-
- 每次推送都会运行(可能不必要)
141+
**注意**:
142+
- 确保 GitHub Secrets 配置正确
143+
- 赋予 Workflow `contents: write` 权限以提交状态文件
148144

149145
### 方案 D: 增量更新脚本(推荐用于频繁更新)
150146

docs/rag-chatbot-setup.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,21 @@ uv pip install -r requirements.txt
8484
- **Metric**: `cosine` (推荐) 或 `euclidean`
8585
6. 点击 "Create"
8686

87-
### 步骤 2: 运行数据摄取脚本
87+
### 步骤 2: 数据摄取(自动化)
88+
89+
推荐使用 GitHub Actions 自动处理。每次推送到 main 分支时,如果内容有更新,系统会自动更新向量数据库。
90+
91+
您也可以手动运行脚本:
8892

8993
```bash
90-
# 处理所有 Markdown 文件
94+
# 处理所有 Markdown 文件(增量更新)
9195
python scripts/ingest.py
9296

93-
# 处理单个文件(测试用)
94-
python scripts/ingest.py --file zh/posts/welcome.md
95-
96-
# 自定义内容目录和基础URL
97-
python scripts/ingest.py --content-dir content --base-url https://hobbytp.github.io
97+
# 强制重新处理所有文件
98+
python scripts/ingest.py --force
9899
```
99100

100-
脚本会:
101-
- 扫描 `content/` 目录下的所有 `.md` 文件(排除 `_index.md`
102-
- 解析 frontmatter,提取标题、日期等信息
103-
- 清洗 Markdown 符号,将文本切片(约500字符/chunk,重叠50字符)
104-
- 生成确定性ID(基于URL和chunk索引,实现幂等性)
105-
- 调用 Cloudflare Workers AI 生成向量
106-
- 批量上传到 Vectorize
101+
**注意**:脚本会在本地生成 `.ingest_state.json` 文件,用于记录已处理文件的状态。建议将此文件提交到 Git,以实现多人协作和 CI/CD 状态同步。
107102

108103
### 步骤 3: 配置 Cloudflare Pages
109104

layouts/partials/chatbox.html

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ <h3>数字分身</h3>
130130
scrollToBottom();
131131

132132
try {
133-
const response = await fetch('/api/chat', {
133+
const apiBase = "{{ with site.Params.chatApiBase }}{{ . }}{{ end }}";
134+
const endpoint = (apiBase && apiBase !== "") ? `${apiBase}/api/chat` : "/api/chat";
135+
const response = await fetch(endpoint, {
134136
method: 'POST',
135137
headers: {
136138
'Content-Type': 'application/json'
@@ -140,17 +142,22 @@ <h3>数字分身</h3>
140142
history: chatHistory.slice(0, -1) // 不包含刚才发送的最新消息
141143
})
142144
});
143-
144-
const data = await response.json();
145+
const contentType = response.headers.get('content-type') || '';
146+
let data = null;
147+
if (contentType.includes('application/json')) {
148+
data = await response.json();
149+
} else {
150+
const text = await response.text();
151+
console.error('API returned non-JSON:', text.slice(0, 200));
152+
}
145153

146154
// 移除Loading
147155
loadingDiv.remove();
148156

149-
if (response.ok) {
157+
if (response.ok && data && typeof data === 'object') {
150158
await appendMessage('assistant', data.response || "抱歉,我没有理解你的问题。");
151159
} else {
152-
console.error('API error:', data.error);
153-
await appendMessage('assistant', '抱歉,服务暂时无法响应。请稍后再试或联系管理员。');
160+
await appendMessage('assistant', '抱歉,服务暂不可用或未部署。');
154161
}
155162
} catch (error) {
156163
loadingDiv.remove();

openspec/changes/complete-digital-twin/proposal.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@
2323
- 明确指定“找不到内容”时的回复语为用户要求的:“没有找到相关内容”。
2424
- 确保 AI 默认使用中文回答。
2525

26+
### 4. 自动化 RAG 数据更新
27+
- **操作**: 创建 `.github/workflows/rag-ingest.yml`
28+
- **原因**: 确保每次博客内容更新(包括自动生成的 Daily AI)后,向量数据库能自动同步更新。
29+
- **配置**: 使用 GitHub Actions 监听 `content/` 目录变更,运行 `scripts/ingest.py`,并回写状态文件 `.ingest_state.json`
30+
2631
## 验证计划
2732
1. **样式验证**: 部署后检查右下角是否出现悬浮聊天按钮,点击是否能正常展开聊天窗口。
2833
2. **功能验证**: 发送测试消息(如“你好”),确认是否收到回复。
2934
3. **Markdown 验证**: 询问需要代码块或列表回复的问题,确认渲染是否正常。
3035
4. **RAG 验证**: 询问博客相关问题,确认回复基于上下文。
3136
5. **Fallback 验证**: 询问无关问题(如“番茄炒蛋怎么做”),确认回复“没有找到相关内容”。
37+
6. **自动化验证**: 提交一篇新文章,检查 GitHub Actions 是否自动触发并成功更新向量库。
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Tasks
22

3-
- [ ] Create OpenSpec proposal file <!-- id: 0 -->
4-
- [ ] Move `assets/css/chat.css` to `assets/css/extended/chat.css` <!-- id: 1 -->
5-
- [ ] Add marked.js CDN to `layouts/partials/chatbox.html` <!-- id: 2 -->
6-
- [ ] Update system prompt in `functions/api/chat.js` <!-- id: 3 -->
3+
- [x] Create OpenSpec proposal file <!-- id: 0 -->
4+
- [x] Move `assets/css/chat.css` to `assets/css/extended/chat.css` <!-- id: 1 -->
5+
- [x] Add marked.js CDN to `layouts/partials/chatbox.html` <!-- id: 2 -->
6+
- [x] Update system prompt in `functions/api/chat.js` <!-- id: 3 -->
7+
- [x] Create GitHub Workflow `.github/workflows/rag-ingest.yml` <!-- id: 5 -->
8+
- [x] Generate and commit `.ingest_state.json` <!-- id: 6 -->
79
- [ ] Commit and push changes <!-- id: 4 -->

0 commit comments

Comments
 (0)