Skip to content

目录递归处理

概述

目录递归处理功能(ingest-directory.ts)是 RAG Worker 工具集中的一个核心组件,专门用于批量处理指定目录下的 Hugo 内容文件。该功能支持递归遍历目录结构,自动识别和处理 index.md_index.md 文件,并智能过滤 draft 状态的文件。

核心特性

🎯 文件类型支持

  • index.md: 页面内容文件
  • 博客文章内容
  • 书籍章节内容
  • 文档页面内容
  • 自定义页面内容

  • _index.md: 章节/分类索引文件

  • 书籍目录和章节介绍
  • 博客分类页面
  • 文档分区概述
  • 导航结构文件

🛡️ 智能 Draft 过滤

系统会按照 Hugo 的 draft 规则自动过滤不应该被索引的内容:

  1. 直接 Draft 检查
---
title: "示例文章"
draft: true  # 此文件将被过滤
---
  1. Section 级别 Draft
# content/zh/book/example/_index.md
---
title: "示例书籍"
draft: true  # 整个 example 目录下的文件都将被过滤
---
  1. Cascade Draft 继承
# content/zh/book/example/_index.md
---
title: "示例书籍"
cascade:
  draft: true  # 所有子页面都继承 draft 状态
  layout: book-content
---

📊 详细进度跟踪

处理过程中会显示:

  • 发现的文件总数
  • Draft 过滤结果
  • 逐文件处理进度
  • 向量化块数统计
  • 上传成功/失败状态
  • 总体处理时间和平均速度

使用方法

基础用法

# 进入 rag-worker 目录
cd tools/rag-worker

# 处理单个目录
npm run ingest-directory -- ../../content/zh/book

# 处理多个目录
npm run ingest-directory -- ../../content/zh/book ../../content/en/book

高级用法

# 使用绝对路径
npm run ingest-directory -- /path/to/hugo/content/zh/docs

# 混合处理不同类型的目录
npm run ingest-directory -- \
  ../../content/zh/book \
  ../../content/zh/docs \
  ../../content/en/blog

# 处理特定的子目录
npm run ingest-directory -- ../../content/zh/book/kubernetes-handbook

输出示例

📁 RAG Directory Ingestion Tool
📄 Processes all index.md and _index.md files recursively
🎯 Target directories: ../../content/zh/book/example

🚀 Starting directory ingestion...
🔍 Searching for index.md and _index.md files in: /path/to/content/zh/book/example
📁 Found 15 index/section files in ../../content/zh/book/example

📊 Total files found: 15
🔍 Checking draft status for files...
⏭️  Skipping draft file: ../../content/zh/book/example/draft-chapter/_index.md
⏭️  Skipping draft file: ../../content/zh/book/example/draft-chapter/intro/index.md
📝 Filtered out 2 draft files

📊 Files to process after draft filtering: 13

📋 Files to be processed:
  1. ../../content/zh/book/example/_index.md
  2. ../../content/zh/book/example/chapter1/_index.md
  3. ../../content/zh/book/example/chapter1/intro/index.md
  ...

📄 Processing (1/13): ../../content/zh/book/example/_index.md
✅ Processed: 3 chunks
⬆️  Uploaded: 3 chunks

📄 Processing (2/13): ../../content/zh/book/example/chapter1/_index.md
✅ Processed: 2 chunks
⬆️  Uploaded: 2 chunks

...

🎉 Directory ingestion completed!
📈 Stats:
  - Found: 15 total files
  - Processed: 13/13 non-draft files
  - Skipped: 2 draft files
  - Failed: 0 files
  - Total chunks: 45
⏱️  Time: 12.3s
🚀 Average speed: 3.7 chunks/sec

技术实现

Draft 检查算法

async function isDraftFile(filePath: string): Promise<boolean> {
  // 1. 检查文件本身的 draft 状态
  const content = await fs.readFile(filePath, 'utf-8');
  const fm = matter(content);

  if (fm.data.draft === true) {
    return true;
  }

  // 2. 检查父级目录的 cascade draft 设置
  let currentDir = path.dirname(filePath);

  while (currentDir && currentDir !== '.' && currentDir !== '/') {
    const indexPath = path.join(currentDir, '_index.md');

    try {
      const indexContent = await fs.readFile(indexPath, 'utf-8');
      const indexFm = matter(indexContent);

      // 检查直接的 draft 设置
      if (indexFm.data.draft === true) {
        return true;
      }

      // 检查 cascade 中的 draft 设置
      if (indexFm.data.cascade && indexFm.data.cascade.draft === true) {
        return true;
      }
    } catch (error) {
      // _index.md 文件不存在,继续检查上级目录
    }

    currentDir = path.dirname(currentDir);
  }

  return false;
}

文件发现机制

使用 globby 库进行高效的文件匹配:

const patterns = [
  '**/index.md',    // 所有子目录下的 index.md
  '**/_index.md'    // 所有子目录下的 _index.md
];

const files = await globby(patterns, {
  cwd: targetDirectory,
  absolute: true,
  onlyFiles: true
});

最佳实践

1. 目录组织建议

content/
├── zh/
│   ├── book/
│   │   ├── handbook1/
│   │   │   ├── _index.md      # 书籍介绍
│   │   │   ├── chapter1/
│   │   │   │   ├── _index.md  # 章节介绍
│   │   │   │   └── intro/
│   │   │   │       └── index.md # 具体内容
│   │   │   └── draft-content/
│   │   │       └── _index.md  # draft: true
│   │   └── handbook2/
│   └── docs/
└── en/
    └── book/

2. Draft 管理策略

  • 开发阶段: 使用 draft: true 标记未完成的内容
  • 章节级别: 在 _index.md 中使用 cascade: {draft: true} 标记整个章节
  • 发布准备: 移除 draft 标记前先本地测试

3. 批量处理建议

# 开发环境:只处理非 draft 内容
npm run ingest-directory -- ../../content/zh/book/ready-book

# 测试环境:可以临时移除 draft 标记进行测试
# (记得测试后恢复 draft 状态)

# 生产环境:确保所有内容都已移除 draft 标记
npm run ingest-directory -- ../../content/zh ../../content/en

错误处理和故障排除

常见问题

  1. 权限错误 - 文件访问被拒绝:

    Error: EACCES: permission denied, open '/path/to/file'
    

    解决方案: 检查文件权限,确保有读取权限

  2. 路径不存在 - 目录未找到:

    ❌ Failed to access directory /path: ENOENT: no such file or directory
    

    解决方案: 验证路径是否正确,使用绝对路径或正确的相对路径

  3. 内存溢出(处理大量文件时) 解决方案: 分批处理目录,或增加 Node.js 内存限制:

NODE_OPTIONS="--max-old-space-size=4096" npm run ingest-directory -- /path

调试模式

设置环境变量以获得更详细的输出:

DEBUG=true npm run ingest-directory -- ../../content/zh/book

性能优化

处理大型目录的建议

  1. 分批处理: 将大型目录分解为较小的子目录
  2. 并发控制: 脚本内置了合理的并发限制
  3. 网络优化: 确保稳定的网络连接以避免上传失败

监控指标

  • 处理速度: 正常情况下应该在 2-5 chunks/sec
  • 失败率: 应该保持在 5% 以下
  • 内存使用: 监控 Node.js 进程的内存占用

集成工作流

与 CI/CD 集成

# .github/workflows/content-update.yml
name: Update RAG Index
on:
  push:
    paths:
      - 'content/**/*.md'

jobs:
  update-index:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20'
      - name: Update specific changed directories
        run: |
          cd tools/rag-worker
          npm install
          npm run ingest-directory -- ../../content/zh/book
        env:
          ADMIN_TOKEN: ${{ secrets.ADMIN_TOKEN }}
          WORKER_URL: ${{ secrets.WORKER_URL }}
          QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}

与 Hugo 部署集成

#!/bin/bash
# deploy.sh - 部署脚本示例

# 1. 构建 Hugo 站点
hugo --minify

# 2. 更新 RAG 索引
cd tools/rag-worker
npm run ingest-directory -- ../../content/zh ../../content/en

# 3. 部署到服务器
# rsync -av public/ user@server:/var/www/

相关文档