首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >#WorkBuddy#如何用 AI 整理 2000+ 政策文件——从混乱到有序的全流程实战教程

#WorkBuddy#如何用 AI 整理 2000+ 政策文件——从混乱到有序的全流程实战教程

原创
作者头像
用户12613957
修改2026-07-10 16:39:50
修改2026-07-10 16:39:50
1180
举报
文章被收录于专栏:AI办公实战AI办公实战

本文记录了借助 AI 编程助手整理 2000+ 份政策制度文件的真实全过程。涵盖文件摸底、分类体系设计、自动归类、OCR 批处理、双库架构搭建等完整环节,并详细标注了 5 个容易返工的坑3 个技术踩坑点,供有类似需求的同行直接参考。


一、项目背景

机关事业单位通常会积累大量政策制度文件——上级发文、内部规章、历史档案……年复一年堆在硬盘里,文件夹嵌套五六层,命名混乱,格式混杂(PDF / DOC / DOCX / HTM / XLS),其中还有大量扫描件。

笔者的实际情况:

维度

数据

文件总数

2068 个

总大小

2.18 GB

目录数

256 个

PDF

1159 个(含大量扫描件)

DOC

529 个

DOCX

120 个

HTM

114 个

XLS

76 个

原有文件夹结构是多年手工累积的,存在以下典型问题:

  • 分类太粗:最大的一个"法规库"子文件夹塞了 1009 个文件,等于没分类
  • 命名残留:216 个 DOC 文件带着 WPS"只读模式"尾巴(文件名后缀多余字符)
  • 扫描件未处理:296 个大于 2MB 的 PDF 疑似扫描件,无法直接检索文本
  • 嵌套层级深:部分文件在五六层子目录下,找一份制度要翻半天

目标:把 2000+ 文件整理成按事项分类、可检索、可导入 LLM 的结构化知识库。


二、工具选择

工具

用途

选择理由

AI 编程助手

全程规划+脚本编写

能操作本地文件、写 Python 脚本、后台长任务

RapidOCR

OCR 文字识别

PaddleOCR 模型 + ONNX 引擎,纯 CPU 可跑,Windows 兼容

Python

批量脚本

分类、重命名、索引表生成、OCR 调度

Ollama + AnythingLLM

本地 LLM(备选)

敏感文件不联网,本地部署 DeepSeek R1 7B

⚠️ 硬件提示:OCR 和本地 LLM 都吃算力。笔者的电脑没有 NVIDIA 显卡(AMD 显卡不支持 CUDA),OCR 只能跑 CPU 模式,速度约 2 分钟/页。如果有 NVIDIA 显卡(6GB+ 显存),OCR 速度可提升 5-10 倍,还能跑本地 13B 大模型。


三、分类体系设计(最容易返工的环节!)

3.1 第一版分类——直接返工

最初的想法是"在原有 13 个文件夹基础上微调"。结果发现:

  • 原有分类太粗,一个"法规库"就 1009 个文件
  • 有些分类是按来源分的("上级文件""内部文件"),有些是按事项分的,体系不统一
  • 存在大量"其他""综合"之类的泛泛分类,等于垃圾桶

教训:不要在旧体系上修补,直接推倒重来。 旧分类的惯性会干扰你的判断。

3.2 第二版分类——30 个大类

最终确定了 30 个大类,核心原则有三条:

  1. 按事项分类,不按来源分类——"财务管理"下既有上级财务规定,也有本单位财务制度,按事项归类更便于查找
  2. 消灭所有泛泛分类——不允许"其他""综合"" Miscellaneous"这类垃圾桶存在,每个文件必须归入一个具体事项
  3. 每个大类对应一个实际工作场景——如果某个分类你平时工作中根本不会去查,就说明这个分类有问题

分类示例(脱敏后):

代码语言:bash
复制
01_人事管理        02_工程建设与采购    03_财务管理
04_党建            05_安全管理         06_纪检与处分
07_机构编制        08_公文与档案       09_议事规则
10_审计            11_合同管理         12_巡视巡察
13_固定资产        14_公务用车         15_会议管理
16_政治建设        17_培训管理         18_出国境管理
19_休假考勤        20_宣传管理         21_保密与信息安全
22_工会群团        23_督查督办         24_信息化管理
25_信访与政务公开  26_外事合作         27_规划与科技
28_印章与机关事务  29_行业业务管理     30_法律事务

💡 第 29 类"行业业务管理"是预留的行业专属分类,不同单位根据自身业务替换即可。

3.3 分类合并的返工

第二版定稿后,又发现 11 组重复分类需要合并(比如"人员培训管理"和"培训管理"重复、"干部选拔任用"应该归入"人事管理"而不是独立成类)。

合并后又引发子文件夹序号重复的问题(详见第五节踩坑清单)。

总结:分类设计至少要经过 3 轮迭代,不要指望一次到位。


四、自动分类实现

4.1 分类脚本设计

分类脚本的核心逻辑是 三轮关键词匹配

第一轮:精确匹配

  • 文件名中包含分类关键词的,直接归入对应大类
  • 例如:文件名含"采购"→ 归入"工程建设与采购"

第二轮:模糊匹配

  • 第一轮没匹配上的,用更宽泛的关键词再扫一遍
  • 例如:文件名含"招标""投标""询价"→ 也归入"工程建设与采购"

第三轮:兜底分配

  • 前两轮都没匹配上的,逐个人工审核文件名,补充关键词规则
  • 这一步最耗时,但必须做——否则又会产生"未分类"垃圾桶

4.2 文件名清洗

分类前必须先清洗文件名,否则关键词匹配会漏掉大量文件:

代码语言:python
复制
import re

def clean_filename(name):
    # 去除 WPS 只读尾巴(如"(只读)" "[只读]"等)
    name = re.sub(r'[\((]\s*只读\s*[\))]', '', name)
    name = re.sub(r'[\[\【]\s*只读\s*[\]\】]', '', name)
    # 去除日期前缀(如"20230101_" "2023-01-01 ")
    name = re.sub(r'^\d{4}[-_]?\d{2}[-_]?\d{2}[\s_\-]*', '', name)
    # 去除序号前缀(如"01_" "001-" "(1)")
    name = re.sub(r'^\d{1,3}[\s_\-).\)]+', '', name)
    # 去除多余空格
    name = name.strip()
    return name

⚠️ 踩坑预警:笔者有 216 个 DOC 文件带着 WPS 只读尾巴,如果不清洗,关键词匹配会漏掉 10% 以上的文件。

4.3 分类结果

经过三轮匹配 + 人工审核:

  • 2068 个文件全部分配到 30 个大类
  • 0 个未分类文件(这是硬性指标,不允许有漏网之鱼)
  • 0 个泛泛分类(没有"其他""综合"这类垃圾桶)
  • 0 个空分类(每个大类至少有 5 个文件)

五、踩坑清单:子文件夹序号重复

问题描述

在第二轮分类合并后,发现 27 个大类存在子文件夹序号重复。例如:

代码语言:bash
复制
01_人事管理/
    01_人员培训管理/      ← 旧的序号
    01_干部选拔任用/      ← 合并后新增,序号重复!
    02_薪酬福利/

根因

每次调整分类后,新增子文件夹时没有重新排列序号,导致同一层级出现多个"01_"。

修复

写了批量重命名脚本,扫描所有大类的子文件夹,按名称排序后重新编号:

代码语言:python
复制
import os

def fix_subfolder_numbering(base_dir):
    for category in os.listdir(base_dir):
        cat_path = os.path.join(base_dir, category)
        if not os.path.isdir(cat_path):
            continue
        subfolders = [f for f in os.listdir(cat_path) 
                      if os.path.isdir(os.path.join(cat_path, f))]
        # 提取子文件夹名(去掉序号前缀)
        subfolders_clean = []
        for sf in subfolders:
            clean = re.sub(r'^\d{2}_', '', sf)
            subfolders_clean.append(clean)
        # 按名称排序后重新编号
        subfolders_clean.sort()
        for i, name in enumerate(subfolders_clean, 1):
            new_name = f"{i:02d}_{name}"
            old_path = os.path.join(cat_path, subfolders[i-1])
            new_path = os.path.join(cat_path, new_name)
            if old_path != new_path:
                os.rename(old_path, new_path)

共执行了 52 次重命名/合并操作。

💡 教训:每次调整分类结构后,都要跑一遍序号检查脚本。 不要指望手动维护。


六、OCR 批量处理

6.1 为什么需要 OCR

整理完成后,发现 836 个大于 500KB 的 PDF 文件。检查后发现:

类别

数量

处理方式

有文本层的 PDF

338 个

直接提取文本,无需 OCR

需要 OCR 的扫描件

471 个

用 RapidOCR 识别

已有 OCR 结果

27 个

跳过

6.2 第一版 OCR 脚本——惨痛踩坑

踩坑:Errno 22 Invalid argument

第一版脚本用 pdf2image 将 PDF 页面转为临时 PNG 文件,再传给 RapidOCR 识别:

代码语言:python
复制
# ❌ 错误做法
images = pdf2image.convert_from_path(pdf_path)
for i, img in enumerate(images):
    temp_path = f"_temp_page_{i}.png"
    img.save(temp_path)  # ← 这里报错!
    result = ocr(temp_path)

273 个文件全部失败,报错 OSError: [Errno 22] Invalid argument

根因分析

临时文件路径中包含中文(文件名本身是中文政策标题),Windows + Python 在某些路径长度/编码组合下,创建临时文件会触发 Errno 22。

修复方案

第二版脚本改用 cv2.imdecode 将 PDF 页面解码为 numpy 数组,直接传给 RapidOCR,完全不创建临时文件

代码语言:python
复制
import fitz  # PyMuPDF
import cv2
import numpy as np
from rapidocr_onnxruntime import RapidOCR

ocr = RapidOCR()

def ocr_pdf(pdf_path):
    doc = fitz.open(pdf_path)
    full_text = []
    for page in doc:
        # 将 PDF 页面渲染为图片,存入内存
        pix = page.get_pixmap(dpi=200)
        img_bytes = pix.tobytes("png")
        # 解码为 numpy 数组(不写磁盘!)
        img_array = np.frombuffer(img_bytes, dtype=np.uint8)
        img_np = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
        # 直接传 numpy 数组给 OCR
        result, elapse = ocr(img_np)
        if result:
            text = "\n".join([line[1] for line in result])
            full_text.append(text)
    doc.close()
    return "\n\n".join(full_text)

3/3 测试通过,471 个文件批量处理正式启动。

⚠️ 这是整个项目中最大的技术坑。 如果你也在中文 Windows 环境下做 OCR,务必避免临时文件,用内存中的 numpy 数组直接传递。

6.3 OCR 输出格式选择

OCR 结果保存为 Markdown 格式,而非纯文本或 JSON:

代码语言:markdown
复制
# 文件标题

## 第一章 总则

**第一条** 为了规范……,制定本办法。

**第二条** 本办法适用于……

## 第二章 适用范围

**第三条** ……

选择 Markdown 的理由:

  1. 保留章节条款结构——便于人工快速定位
  2. 适合 LLM 嵌入——Markdown 格式是主流 LLM/RAG 系统的最佳输入格式
  3. 可读性好——比 JSON 更直观,比纯文本结构更清晰

6.4 断点续传设计

471 个文件跑 OCR,中途可能断电、崩溃、被手动终止。脚本支持断点续传:

代码语言:python
复制
def batch_ocr(file_list, output_dir):
    for pdf_path in file_list:
        # 检查是否已有输出文件(断点续传)
        md_name = Path(pdf_path).stem + "_OCR.md"
        md_path = os.path.join(output_dir, md_name)
        if os.path.exists(md_path):
            print(f"跳过已完成: {pdf_path}")
            continue
        # 执行 OCR
        text = ocr_pdf(pdf_path)
        with open(md_path, "w", encoding="utf-8") as f:
            f.write(text)

同时还写了一个 进度查看脚本,可以双击运行,显示:

  • 已完成数 / 总数
  • 百分比 + 进度条
  • 预计剩余时间
  • Python 进程是否存活

💡 建议:长任务一定要有进度查看机制,否则你永远不知道它是在跑还是挂了。


七、双库架构设计

整理完成后,需要两个输出目标:

7.1 正式库(人工查阅)

代码语言:bash
复制
政策文件_整理后/
├── 01_人事管理/
│   ├── 01_人员培训管理/
│   │   ├── 培训管理办法.pdf
│   │   ├── 培训考核制度.doc
│   │   └── ...
│   ├── 02_干部选拔任用/
│   └── ...
├── 02_工程建设与采购/
└── ...

特点:

  • 两级目录(大类/子类),层级清晰
  • 保留所有原件(PDF/DOC/DOCX 原始文件)
  • 包含扫描件原件
  • 供人工查阅、打印、归档使用

7.2 LLM 导入库(机器读取)

代码语言:bash
复制
政策文件_LLM导入/
├── 01_人事管理_培训管理办法.txt
├── 01_人事管理_培训考核制度.txt
├── 02_工程建设与采购_招标管理办法.txt
└── ...

特点:

  • 一级目录(拍平,无子文件夹)——这点很重要,详见下方踩坑
  • 仅文本文件(.txt / .md),无原件
  • 排除扫描件原件(只有 OCR 成功的才放入)
  • 文件名格式:大类编号_大类名称_文件名.txt
  • 用完可删,正式库是唯一数据源

7.3 踩坑:LLM 导入库的层级问题

最初 LLM 导入库也按照正式库的两级目录结构来组织。后来发现:

  • 大多数 LLM 导入工具(AnythingLLM、Dify 等)在处理嵌套目录时容易出错
  • 嵌套目录导致导入后文档路径过长,检索不方便
  • 子文件夹的分类信息其实可以编码到文件名中

修复:将 LLM 导入库从两级目录拍平为一级目录,分类信息编码到文件名前缀中。

💡 教训:人工查阅库和机器读取库的结构需求不同。人工需要层级导航,机器需要扁平结构。不要用同一套目录结构。


八、索引表生成

整理完成后,生成一份 Excel 索引表,记录每个文件的元信息:

序号

文件名

大类

子类

格式

大小

是否扫描件

OCR状态

发文日期

发文单位

1

培训管理办法

01_人事管理

01_人员培训管理

PDF

256KB

有文本层

2023-05-12

XX部门

2

财务报销规定

03_财务管理

-

DOC

128KB

-

2022-03-08

XX单位

索引表的用途:

  • 快速检索:不用翻文件夹,在 Excel 里搜关键词就能定位
  • 后续维护:新增文件时先更新索引表,再物理归档
  • 制度盘点:可以按发文日期排序,找出过时制度;按发文单位筛选,找缺失制度

后续计划:从 OCR 文本中自动提取发文日期,回填到索引表中(很多旧文件的发文日期只在正文里,文件名中没有)。


九、新增文件处理流程

整理完成后,日常还会有新文件需要入库。为此写了一个 add_new_file.py 脚本,一键完成:

代码语言:bash
复制
新文件 → [1]文件名清洗 → [2]关键词分类 → [3]OCR(如需)→ [4]放入正式库 → [5]同步到LLM导入库 → [6]更新索引表

这个脚本可以在本地独立运行,不需要每次都依赖 AI 助手。


十、五大返工点总结

返工点

问题描述

代价

预防建议

1. 分类体系推倒重来

第一版在旧分类上修补,后发现体系不统一,全部推倒

重新分类 2000+ 文件

开工前先定好分类原则,不要在旧体系上修补

2. 分类合并引发连锁反应

合并 11 组重复分类后,子文件夹序号全部乱掉

52 次重命名

每次合并后立即跑序号检查脚本

3. 未分类文件堆积

105 个文件因关键词没覆盖到,留在根目录

三轮额外匹配

第一轮分类时就把兜底规则写全

4. OCR 全量返工

v1 因临时文件问题 273 个全失败

重写整个 OCR 脚本

中文路径环境下避免临时文件

5. LLM 导入库重构

两级目录导致导入工具出错

重新拍平 30 个大类

机器读取库用一级目录,信息编码到文件名


十一、技术踩坑清单

坑 1:Errno 22 — 中文路径下的临时文件

  • 现象:OCR 脚本创建临时 PNG 文件时报 OSError: [Errno 22] Invalid argument
  • 根因:Windows + 中文路径 + Python 临时文件创建的兼容性问题
  • 修复:用 cv2.imdecode 解码为 numpy 数组,直接传给 OCR,不创建临时文件
  • 适用场景:所有在中文 Windows 环境下做图像处理的同学

坑 2:AMD 显卡不支持 CUDA

  • 现象:OCR 只能跑 CPU 模式,速度约 2 分钟/页,471 个文件需要十几小时
  • 根因:AMD 显卡不支持 CUDA,ONNX Runtime 无法用 GPU 加速
  • 应对:用后台批处理 + 断点续传,让它慢慢跑
  • 建议:如果经常做 OCR 或本地 LLM,优先选 NVIDIA 显卡的电脑

坑 3:文件名匹配的隐藏陷阱

  • 现象:OCR 生成的 Markdown 文件名和原始 PDF 文件名不完全一致(扩展名不同、特殊字符被替换),导致同步到 LLM 导入库时匹配不上
  • 修复:写了一个 deep_clean 函数,对文件名做深度清洗后再匹配(去除扩展名、特殊字符、空格、日期前缀等),匹配不上的再走关键词 fallback
  • 教训:跨格式的文件名匹配一定要做深度清洗,不能直接字符串比较

十二、给后来者的建议

  1. 先摸底再动手。花半天时间把文件总数、格式分布、目录结构、命名问题摸清楚,写一份"现状报告"。磨刀不误砍柴工。
  2. 分类体系至少迭代三轮。第一版必然不满意,做好心理准备。核心原则:按事项分类、消灭泛泛分类、每个分类对应实际工作场景。
  3. OCR 在中文 Windows 下避免临时文件。这是最大的技术坑。用 numpy 数组直传,一行代码的问题,省掉 273 个文件的返工。
  4. 人工库和机器库分开设计。人工查阅需要层级导航,机器读取需要扁平结构。不要用同一套目录。
  5. 长任务必须有进度查看机制。写一个简单的进度查看脚本,双击就能看到完成数、剩余数、预计时间。否则你永远在问"跑完了吗"。
  6. 整理完成后写一个"新增文件入库脚本"。整理是一次性工程,但日常维护是长期的。一个一键入库脚本能省掉 90% 的重复劳动。
  7. 善用 AI 助手的后台任务能力。现在的 AI 编程助手大多支持后台长任务(脚本执行、OCR 批处理等),不阻塞对话。你可以一边让它跑 OCR,一边继续做其他整理工作。

附录:完整工具链

环节

工具

备注

AI 助手

任意支持代码执行的 AI 编程助手

全程规划+脚本编写

OCR 引擎

RapidOCR (ONNX Runtime)

PaddleOCR 模型,纯 CPU 可跑

PDF 处理

PyMuPDF (fitz)

PDF 转图片、提取文本

图像处理

OpenCV (cv2)

图片解码、numpy 数组操作

批量脚本

Python 3.13

分类/重命名/索引/OCR调度

本地 LLM(备选)

Ollama + AnythingLLM

敏感文件本地处理

文档检索

AnyTXT

全文检索已整理文件


本文基于真实项目经验整理,已脱敏处理。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、项目背景
  • 二、工具选择
  • 三、分类体系设计(最容易返工的环节!)
    • 3.1 第一版分类——直接返工
    • 3.2 第二版分类——30 个大类
    • 3.3 分类合并的返工
  • 四、自动分类实现
    • 4.1 分类脚本设计
    • 4.2 文件名清洗
    • 4.3 分类结果
  • 五、踩坑清单:子文件夹序号重复
    • 问题描述
    • 根因
    • 修复
  • 六、OCR 批量处理
    • 6.1 为什么需要 OCR
    • 6.2 第一版 OCR 脚本——惨痛踩坑
      • 踩坑:Errno 22 Invalid argument
      • 根因分析
      • 修复方案
    • 6.3 OCR 输出格式选择
    • 6.4 断点续传设计
  • 七、双库架构设计
    • 7.1 正式库(人工查阅)
    • 7.2 LLM 导入库(机器读取)
    • 7.3 踩坑:LLM 导入库的层级问题
  • 八、索引表生成
  • 九、新增文件处理流程
  • 十、五大返工点总结
  • 十一、技术踩坑清单
    • 坑 1:Errno 22 — 中文路径下的临时文件
    • 坑 2:AMD 显卡不支持 CUDA
    • 坑 3:文件名匹配的隐藏陷阱
  • 十二、给后来者的建议
  • 附录:完整工具链
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档