资料整理最值得自动化的,不一定是“帮我全部归类”,而是先回答一个具体问题:每个项目应该交的文件,究竟缺了哪一份?

项目材料常常是这样交来的:需求、方案、备注分散在不同目录,文件名又各有习惯。临近交付时,人要逐个点开文件夹核对;下次收到新一批,又从头检查。直接让 AI “整理干净”,反而容易把复制、重命名、删除和内容判断混成一个不可检查的动作。

本文把范围缩小为一个本地检查器:只检查副本,不移动原件;交付缺件清单,不替人宣布内容合格。 我们用三组明确构造的模拟资料实际运行,检查器找到两个缺件,七项边界测试通过。样本不含客户资料,不代表真实业务收益。

先分清两件事:用 Codex 协助写出检查器,与检查器运行时调用模型,是两步独立工作。下文脚本只用 Python 标准库,在本地运行,不请求模型。

一、把“资料齐了吗”写成具体规则

假设每个项目必须提交三份文件:

  • 01_brief.md:需求说明;
  • 02_plan.md:执行方案;
  • 03_notes.txt:交付备注。

本例采用固定名称,一级子目录各代表一个项目。只要求普通文件存在且非空,不读取正文、不判断内容真实性,也不递归猜测其他目录里的同名文件是不是替代件。

多出来的文件列入 extras,输入根目录的散落文件列入 ignored_root_files,两者都不删除。必交文件如果是目录、空文件或符号链接,均不算齐备;项目入口本身是符号链接时直接停止,避免把其他位置当作当前交付目录。

这不是唯一正确的业务规则。允许多个文件名、附件可选、不同项目要求不同,都可以设计,但必须先讲清楚。最容易复用的工具,通常从一套小而明确的规则开始,而不是第一次就支持所有资料格式。

二、给 Codex 的要求,要能落到文件和结果上

可以把下面这段要求连同模拟目录交给它:

请编写资料缺件检查器,使用 Python 标准库。只处理我指定的工作副本,按一级项目目录检查三份必交文件,缺件、空文件和非普通文件分别列出。不要移动、改名、删除输入,不读取业务正文,不安装依赖。报告写到输入目录之外的全新 JSON 文件,已有报告不能覆盖。先运行模拟样本,再测试异常边界,告诉我结果路径、实际数量和没有检查的内容。不要只给一段代码就说完成。

这里的“不联网”约束的是示例脚本和不必要的工具操作,不表示 Codex 自身完全离线,也不保证提供给 AI 的资料不会经过模型服务。第一次应使用模拟或获准的脱敏材料。

如果需求变成“判断方案内容是否漏项”,就超出了本例的范围。先把业务人员的检查标准写成清单,再准备一份已知合格、一份已知漏项的脱敏样本;不要直接把真实材料交给工具,并把自动判断当成人工验收结论。

三、完整检查器:原件不动,报告不覆盖

将下面内容保存为 check_delivery.py。它只使用目录项、文件类型与文件大小,不分析文件内容。

import argparse
import json
from pathlib import Path


REQUIRED = ('01_brief.md', '02_plan.md', '03_notes.txt')


def check_delivery(source):
    source = Path(source)
    if source.is_symlink() or not source.is_dir():
        raise ValueError('输入必须是实际目录,不接受符号链接')
    projects = []
    ignored = []
    for project in sorted(source.iterdir()):
        if project.is_symlink():
            raise ValueError('项目入口不能是符号链接')
        if not project.is_dir():
            ignored.append(project.name)
            continue
        issues = []
        for filename in REQUIRED:
            candidate = project / filename
            if candidate.is_symlink():
                reason = '符号链接不计入'
            elif not candidate.exists():
                reason = '缺件'
            elif not candidate.is_file():
                reason = '不是普通文件'
            elif candidate.stat().st_size == 0:
                reason = '空文件'
            else:
                continue
            issues.append({'file': filename, 'reason': reason})
        projects.append({
            'project': project.name,
            'ready': not issues,
            'issues': issues,
            'extras': sorted(entry.name for entry in project.iterdir()
                             if entry.name not in REQUIRED),
        })
    if not projects:
        raise ValueError('没有项目目录,不能生成齐备报告')
    return {
        'summary': {'projects': len(projects),
                    'ready': sum(project['ready'] for project in projects),
                    'issues': sum(len(project['issues']) for project in projects)},
        'projects': projects,
        'ignored_root_files': ignored,
    }


def write_report(source, destination):
    source = Path(source)
    report = check_delivery(source)
    destination = Path(destination).absolute()
    if destination.is_symlink() or source.resolve() in destination.resolve().parents:
        raise ValueError('报告不能写进输入目录或符号链接')
    with destination.open('x', encoding='utf-8') as handle:
        json.dump(report, handle, ensure_ascii=False, indent=2)
        handle.write('\n')
    return report


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='只读检查资料齐备性,不判断内容质量')
    parser.add_argument('source')
    parser.add_argument('report')
    arguments = parser.parse_args()
    result = write_report(arguments.source, arguments.report)
    print(json.dumps(result['summary'], ensure_ascii=False))

两个设计需要特别说明。

第一,成功运行不等于全部齐备。 脚本正常退出,只表示报告已生成;还要看 summary.readysummary.issues。如果有三个项目、只有一个齐备,就不能把“程序没报错”翻译成“交付检查全过”。

第二,报告使用排他创建。 open('x') 会拒绝覆盖同名旧报告。再次检查请换一个报告名,保留前后结果便于对照;不要先删除旧报告,只为让命令变绿。报告的父目录需要预先存在,权限或磁盘问题会直接报错。

本例面向可信、静态的资料副本,不是抵御恶意路径或并发篡改的安全沙箱。检查期间有人增删文件,结果可能不再对应同一份快照。重要交付应先固定副本,再核对;写报告中途失败也可能留下不完整文件,必须按失败处理,而不是拿残缺 JSON 做验收。

四、构造可以手工核对的三组样本

这组教学样例由 FishAI(作者运营的网站:yufish.cc)整理,复现过程只使用下方给出的本地脚本,不依赖该网站,也不调用模型服务。先用已知缺件的小样验证检查规则,再处理获准使用的工作副本。

在一个新的演示目录中,把以下代码保存为 make_sample.py,与检查器放在一起。它会新建 sample_input:alpha 三份齐全,beta 缺方案,gamma 缺备注。所有文件内容都明确标为模拟资料。

from pathlib import Path


source = Path('sample_input')
source.mkdir(exist_ok=False)
files = {
    'alpha': ('01_brief.md', '02_plan.md', '03_notes.txt'),
    'beta': ('01_brief.md', '03_notes.txt'),
    'gamma': ('01_brief.md', '02_plan.md'),
}
for project, filenames in files.items():
    directory = source / project
    directory.mkdir()
    for filename in filenames:
        (directory / filename).write_text('仅用于演示的模拟资料\n', encoding='utf-8')
print('已新建3个模拟项目,共7个文件;未读取真实业务资料。')

在这个目录里执行:

python3 make_sample.py
python3 check_delivery.py sample_input sample_report.json

如果电脑上的 Python 命令名不是 python3,先确认实际安装情况;不要直接运行来源不明的“自动修复环境”程序。示例不会安装任何依赖。若已经存在 sample_input,创建样本会报错;请换一个新的演示目录,不要覆盖自己的同名目录。

这两条命令在本地实际运行后,输出为:

已新建3个模拟项目,共7个文件;未读取真实业务资料。
{"projects": 3, "ready": 1, "issues": 2}

打开 sample_report.json,应该能核对出:

  • alpha:ready=true,没有缺件;
  • beta:02_plan.md,原因“缺件”;
  • gamma:03_notes.txt,原因“缺件”。

这组结果无需相信模型判断,用文件管理器也能逐项验证。三项目、一齐备、两缺件是教学样例的结果,不是准确率评测,更不能据此承诺任何目录都不会漏检。

五、不要只检查正常样本

本地还用临时目录实际运行了七项回归测试:齐备报告及输入文件哈希不变;缺件和空文件不算齐备;符号链接文件不计入;符号链接项目停止;已有报告不覆盖;报告不能写进输入目录;空输入不生成齐备报告。七项均通过,测试数据也是专门构造的,不是线上客户材料。

这些边界比再增加一个彩色界面更重要。拿到工具后,至少尝试“缺一份、空一份、重复输出同一个报告名”三种情况,检查失败信息是否清楚、原件是否仍在。非空不等于有用:一个文件只有“待补充”三个字,也会通过本例的齐备检查,内容质量仍须业务人员审核。

如果后续加入内容检查,应另列检查范围、失败项和人工复核结果。例如一份方案只有标题,虽然不是空文件,却可能完全没有回答需求。当前检查器只能回答文件是否齐备,不能回答方案是否合格;这两类检查需要不同的小样和验收标准。

六、怎样从一次演示变成下周还能用的工具

第一次先保留三个东西:规则表、检查器版本、已知预期的小样。下周只要文件命名规则不变,就用相同检查器处理新的工作副本,输出带日期的新报告。规则改变时,先更新小样预期,再改代码,不能拿旧测试通过替新版背书。

例如增加“合同是可选项”,应先决定缺合同是否影响齐备;增加“方案必须包含预算章节”,已经从文件元信息走向内容分析,需要新验收标准。不要把两种能力都叫“智能整理”,否则使用者根本不知道绿色结果保证了什么。

OpenAI 的权限与安全说明区分技术上的沙箱限制和执行前的审批策略。提示词是工作要求,不是权限隔离;仍需限制工具可操作范围、保留副本,并验证交付结果。

本文采用 AI 辅助写作与代码实现;展示的样例、输出和边界测试均在本地实际执行,未使用真实客户资料。核验日期:2026-09-03。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐