我用AI辅助开发了一系列小工具,第一个落地的是文件提取工具。这个工具解决一个特别常见的痛点:电脑里堆了几个G的下载文件、邮件附件、压缩包,东西一多,想找某类文件只能靠肉眼翻,翻到崩溃。于是我用AI辅助写了一个能按扩展名、文件名关键词、文件大小等规则,把目标文件批量提取到指定文件夹的小工具。算是一个最小可用的起点,后面再往上叠功能做成了系列。
这篇文章就把整个过程拆开来讲:从需求拆解、框架设计,到AI提示词怎么写、代码怎么改,再到真实使用中踩过的坑。适合看了AI编程很心动但不知道从哪里下手的人,也适合手里明明有文件整理需求、却一直懒得动手的人。看完你基本可以复刻一个自己的版本。
1. 项目背景:为什么我决定用AI开发这个小工具
1.1 需求从哪来
说个真实场景。我不是那种把桌面整理得干干净净的人,下载文件夹更是重灾区:PDF文档、Word、Excel、安装包、图片、压缩包,混杂在一起,时间久了连自己都找不到东西。有一次为了找一个合同扫描件,翻了整整二十分钟,还在微信里翻出好几份同名文件对比版本号,那一刻就很想写一个小工具来解决。
常规思路是写脚本,但问题在于:写一个能用的Python脚本并不难,难的是用脚本去处理一堆真实、不规则的文件名,并且让人敢放心去用它批量操作文件。我自己有基础但写代码不算特别熟,传统做法是查文档、搜帖子、反复试错,搞一个下午也就差不多了。但这次我换了个思路,用AI辅助来写,结果效率比想象中高很多。
由此也定下了一个小系列的基调:我不准备做多么复杂的工程,就做那种单个功能明确、能立刻解决具体问题、不用装一堆依赖的小工具合集。文件提取是第一个,后面还会有按规则重命名的、批量转格式的、清空重复文件的,等等。
1.2 为什么选AI辅助而不是纯手写
你可能会问:这种小工具本来就不复杂,手写不就行了?我的答案是:可以,但AI辅助有几个明显优势。
第一,AI能把模糊需求快速变成骨架代码。我刚接触一个需求时,脑子里往往只有一个大概轮廓,比如“把文件按扩展名归类”,但具体涉及哪些边界条件、用正则还是用Pathlib、要不要处理重名文件,这些细节一开始并不清晰。AI能快速给出一版结构完整的实现,这相当于有了一个草稿,再在这个基础上做修改和打磨,比自己从零敲要快很多。
第二,AI很适合当“语法和API速查字典”。比如用Python的pathlib遍历文件时,rglob和glob的区别、shutil.copy2的参数,这些我经常记不准。与其翻文档,不如直接问AI要一段实现,再自己审一遍逻辑,效率高很多。
第三,也是最实际的,AI能帮我写测试用的样例和边界用例。比如生成一堆不同扩展名的假文件,测试我的提取规则是否生效。这种活儿本身没什么技术含量,但很耗时间,AI做起来很快,我能把精力留在真正需要判断的事情上。
1.3 这个工具适合谁来用
文件提取工具不是万人通用的,它的定位非常明确:适合那些每天和大量文件打交道、又不想花太多时间学习编程的人。
如果你是办公族,经常收到一堆邮件附件,要把里面的PDF单独提取出来存档,这个工具能帮你省下不少手工操作时间。如果你是开发或者运维,需要从日志目录里把相关日志文件按日期、按类型抽取出来做分析,它也能当个快速辅助。如果只是普通用户,电脑下载文件夹爆炸了,也可以靠这个工具把安装包、图片、文档分别塞进对应文件夹,还桌面一份清净。
当然,工具本身需要有Python环境才能跑,这对零基础的人来说算是一个门槛。不过我会把代码和用法写清楚,照着复制粘贴就能跑,基本不涉及复杂的工程知识。这正是“小工具”的意义所在,不需要你会多少编程,只要会用命令行就够了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体设计思路:一个能快速复用的文件提取框架
2.1 先定义清楚“文件提取”到底提取什么
写工具最容易犯的错,是没想清楚需求就直接动手。我刚开始想把“文件提取”做成一个万能工具:既能按扩展名过滤,又能按文件名关键词过滤,还要处理嵌套目录,还要自动去重,甚至还想加一个图形界面。想得越多,复杂度越高,差点把自己劝退。
后来我给自己划定了一条边界:第一版只做三件事,按扩展名提取、按文件名关键词提取、按文件大小过滤。这三件事覆盖了日常80%以上的提取需求。至于去重、归档成压缩包、监听文件夹自动整理,那些都留到后面的迭代里。
这个取舍很关键。小工具的本意就是“小而精”,一个工具解决一类问题。你把所有想法都塞进去,最后只会得到一个永远写不完的半成品。
2.2 三段式结构:输入、规则、输出
我把整个工具的架构定义成一个非常简单的三段式:
输入是源目录,也就是你要从哪个文件夹里扫描文件。规则是提取条件,比如扩展名是.pdf,或者文件名带了“合同”两个字,或者文件大于10MB。输出是目标目录,把命中的文件复制(注意是复制,不是移动)到一个新的文件夹里。
为什么是复制而不是移动?这算是我设计时的一个安全考虑。移动文件一旦误判,原文件就换了位置,找回来很折腾。先复制到目标目录,人工扫一眼确认没问题,再手动删掉源文件,这个操作路径安全得多。工具设计的原则之一,是要让误操作的代价足够低。
基于这个三段式,我设计了一个通用的命令行参数接口,后续再加别的工具时也沿用同一套参数风格,减少了学习和记忆成本:
bash复制python extract_tool.py --source ./downloads --output ./extracted --ext .pdf,.docx
python extract_tool.py --source ./downloads --output ./logs --keyword "合同"
python extract_tool.py --source ./downloads --output ./large --min-size 100MB
这样的好处是规则之间还能组合使用,比如既要扩展名是.pdf,又要文件名包含“合同”,两个条件叠加,能定位到更精确的目标。我把这种组合式设计当成整个小工具系列的通用风格,后面开发的工具也都用了类似的方式。
3. AI辅助开发实录:从第一版代码到顺手工具
3.1 第一轮提示:把模糊需求变成AI能理解的任务
我实际使用AI的过程不是大家想象的那种“一句话生成整个程序”,而是分了几轮对话,每轮聚焦一个子问题。第一轮,我的提示词大概是这样的:
我准备用Python写一个命令行工具,功能是从一个目录(包含所有子目录)中根据扩展名提取文件到目标目录。需求:
- 支持参数传入源目录、目标目录、扩展名列表
- 遍历所有子目录
- 只复制,不移动,保持原文件名
- 如果目标已有同名文件,自动加序号
- 中文路径也能正常处理
AI很快就给出一版代码,用的是pathlib.rglob遍历,shutil.copy2复制,然后通过判断目标文件是否存在来追加序号。整体结构清楚,直接可用。这一版速度很快,但有一个隐藏问题,AI默认给的是Windows路径,因为我没说明我的运行环境,它猜了最常见的情况。后来我在实际使用中发现自己在macOS上跑,于是让它改了路径风格,这也就是为什么提示词里最好把环境信息写清楚。
3.2 第一版代码的核心逻辑
AI生成的代码修修改改之后,核心部分长这样:
python复制import argparse
from pathlib import Path
import shutil
def unique_dest_path(dest_dir: Path, filename: str) -> Path:
candidate = dest_dir / filename
if not candidate.exists():
return candidate
stem = candidate.stem
suffix = candidate.suffix
counter = 1
while True:
new_name = f"{stem}_{counter}{suffix}"
new_candidate = dest_dir / new_name
if not new_candidate.exists():
return new_candidate
counter += 1
def extract_files(source: str, output: str, extensions: list[str]) -> int:
src_dir = Path(source)
out_dir = Path(output)
if not src_dir.is_dir():
raise NotADirectoryError(f"源目录不存在: {src_dir}")
out_dir.mkdir(parents=True, exist_ok=True)
exts = {ext.lower() if ext.startswith(".") else f".{ext.lower()}" for ext in extensions}
copied = 0
for file_path in src_dir.rglob("*"):
if not file_path.is_file():
continue
if file_path.suffix.lower() in exts:
dest = unique_dest_path(out_dir, file_path.name)
shutil.copy2(file_path, dest)
print(f"[提取] {file_path} -> {dest}")
copied += 1
return copied
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="按扩展名提取文件")
parser.add_argument("--source", required=True, help="源目录")
parser.add_argument("--output", required=True, help="目标目录")
parser.add_argument("--ext", required=True, help="扩展名列表,逗号分隔,如 .pdf,.docx")
args = parser.parse_args()
ext_list = [e.strip() for e in args.ext.split(",") if e.strip()]
total = extract_files(args.source, args.output, ext_list)
print(f"完成,共提取 {total} 个文件")
这里有两个关键设计是AI一开始就做对了的:一个是扩展名自动补点,方便用户传pdf还是.pdf都能理解;另一个是重名文件自动加序号,避免目标目录被覆盖。这两个细节看着不起眼,但实际用起来少了它们会很头疼。
当然,AI给的第一版也不是没毛病。它最初用os.walk而不是pathlib,我改成rglob纯粹是个人偏好,代码读起来更简洁。另外它最初没有处理“目标文件已存在”的情况,我追问了第二轮才加上去。AI辅助开发的节奏就是这样:不是一次性收货,而是不断提出问题、补充边界条件、让它迭代。
3.3 扩展关键词过滤与大文件识别
扩展名过滤能解决一部分问题,但远远不够。比如我想从一堆文件里找出所有“简历”相关的PDF,扩展名过滤做不到,必须按文件名关键词匹配。我还想找出所有大于100MB的大文件,方便清理磁盘。这两类需求,我分别让AI加上了。
python复制def match_by_keyword(filename: str, keywords: list[str]) -> bool:
lowered = filename.lower()
return any(kw.lower() in lowered for kw in keywords)
def filter_by_size(file_path: Path, min_size: int = 0, max_size: int = 0) -> bool:
if min_size and file_path.stat().st_size < min_size:
return False
if max_size and file_path.stat().st_size > max_size:
return False
return True
参数上我用一个字符串统一解析,支持用户传以下格式:min-size 100MB、max-size 2GB。解析函数是让AI帮我写的,处理了KB、MB、GB三个单位的换算,我只需要在调用时把字符串转成字节数。
python复制def parse_size(size_str: str) -> int:
size_str = size_str.strip().upper()
units = {"KB": 1024, "MB": 1024 ** 2, "GB": 1024 ** 3}
for unit, multiplier in units.items():
if size_str.endswith(unit):
number = float(size_str[: -len(unit)].strip())
return int(number * multiplier)
return int(float(size_str))
这个解析函数第一版还有个小bug,就是没处理纯数字的情况,比如直接输入“2048”当作字节数。AI一开始默认了必须带单位,我补充用例测试后才发现,于是改成了最后一行兜底处理。这种小问题不自己测一遍根本发现不了。
3.4 如何让AI生成的代码更可靠
AI生成代码的速度确实快,但可靠性得靠自己把关。我总结了一套自己的审查流程:
第一步,拿着代码逐行过一遍逻辑,重点看有没有边界遗漏。比如源目录不存在会怎样,目标目录创建失败会怎样,扩展名大小写会不会影响匹配。第二步,用假数据实测。我让AI生成几十个模拟文件,包括中文文件名、带空格的文件名、同名但不同内容、子目录嵌套,然后跑一次完整的提取流程。第三步,用真实数据小规模试跑。先挑选一个小一点的文件夹,比如几百个文件,确认没有异常,再处理大规模目录。
这套流程看起来麻烦,但对文件类工具特别重要。文件操作不可逆,出错了影响很大。哪怕你是复制操作,白白复制出一堆用不上的文件,整理起来也很痛苦。
3.5 从“能用”到“好用”的小优化
第一版跑通之后,我陆续加了几个小功能,有些是AI建议的,有些是自己实际用出来的。
加了自动创建日期文件夹的功能。就是把提取结果按日期归档,比如输出目录下自动生成2025-01-15这样的子文件夹,适合每天导出文件的场景。这个功能我用一个time参数控制:按“按年/按月/按天”归档,不想归档就关掉。
加了目录结构保留选项。默认平铺到目标目录,重名加序号。有些场景下需要保留原来的子目录结构,比如按合同类别提取文件,不希望全部堆成一个文件列表。这时加一个--keep-dir参数,文件提取后保留相对于源目录的路径。这是实际用了一阵子之后自己想到的需求,AI不会主动替你考虑。
加了日志输出。默认打印到控制台,也支持写日志文件,方便批量处理时回溯。对日常手动工具来说,日志不是必需品,但用了就会觉得安心。
4. 将单点工具扩展成“小工具系列”的经验
4.1 系列工具的统一约定:每个工具都遵守同一套规则
做完文件提取工具后,我就开始思考这个系列应该怎么生长。一个系列如果没有统一约定,每加一个工具就是一种新风格,代码复用和记忆成本都会失控。
我给所有工具定了以下统一规则:命令行参数风格一致,源路径都叫--input或--source,输出路径都叫--output,不让用户每次重新记。处理所有文件操作优先使用pathlib而不是os.path,因为pathlib的Path对象操作更安全也更现代。默认行为尽量保守,默认复制不删除、默认不覆盖、默认平铺输出,任何有风险的操作都要显式加参数。对中文文件名和空格文件名的支持优先级最高,因为实际办公环境中这类文件非常普遍。
这样做的直接受益点是:我开发第二个工具(批量重命名工具)时,直接复制了文件提取工具的框架,只改了核心的“处理逻辑”部分,大概不到半小时就完成了一版能跑的。系列化不只是为了“好看”,是为了让下一个工具的开发成本越来越低。
4.2 沉淀一套适合自己的AI辅助开发流程
AI辅助开发这件事,如果只是“有问题就问AI”,那和搜索引擎没什么区别。真正有价值的,是形成一套适合自己的流程。
我现在每次开发一个新工具,都会先写一个简短的需求文档。不用很长,几百字到一个巴掌那么长,说明输入是什么、输出是什么、有哪些边界条件。然后把需求文档丢给AI,让它生成第一版。拿到代码后先别急着跑,先人工审查数据流方向:数据从哪里来,经过什么处理,到哪里去,中间有没有可能出错。接着创建测试目录,放上各种边界情况的样本文件,自动跑一轮测试。最后在真实数据上做小规模试用,确认没问题再正式用。
这套流程跑下来,AI辅助开发的产出质量基本稳定。和直接用现成GUI工具比,这种方式前期成本高一点,但可控性和扩展性强很多,对我来说是值得的。
4.3 关于“AI编程最厉害三个软件”的个人看法
经常看到有人在问现在最强的AI编程工具是什么、哪个AI写代码最厉害。我的个人观点是:工具的具体选择不重要,重要的是你的使用方式和审阅能力。
我自己是几款主流AI编程工具混着用的,同一个需求会让不同工具各生成一版,然后对比它们的设计思路。这个对比过程本身就是学习,因为每个模型擅长的风格不太一样,有的更敢写,会主动建议你做错误处理;有的则偏保守,输出基础但相对稳妥。多对比几轮,你对什么代码是好代码的判断会明显提升。
如果非要给个方向性的建议:想快速体验AI编程,可以先从在线聊天式AI开始,把需求描述清楚,让它生成脚本代码,放到本地跑;想获得更连贯的编程体验,可以试试自带编辑器插件的那种,代码上下文更长,改起来更顺手。关键不在于工具本身,而在于你愿意花多少时间去“审查”AI给出的结果。
5. 常见问题与排查技巧实录
5.1 问题速查表
我实际用这个工具跑了不少目录,也踩了些坑。整理一个速查表,方便你以后排查:
| 现象 | 常见原因 | 解决方法 |
|---|---|---|
| 一个文件都没提取出来 | 扩展名带了点号或者全大写 | 代码里统一处理,传入pdf和.pdf都行 |
| 中文文件名乱码 | 终端编码不是UTF-8 | Windows控制台执行chcp 65001后重试 |
| 提取出来的文件重复名被覆盖 | 没有检查dest.exists() | 用unique_dest_path逻辑,同名自动加序号 |
| 中途报权限错误 | 目标目录没有写入权限 | 检查目录权限,或换一个输出目录 |
| 文件很多、提取很慢 | 大量小文件逐个复制 | 加上测试后无问题,仍慢则用shutil.copyfile绕开元数据复制 |
| 提示源目录不存在 | 参数写成了相对路径但当前目录不对 | 先用绝对路径测试,跑通后再考虑相对路径 |
| 符号链接导致的重复提取 | rglob会把软链接文件也遍历到 | 按需在遍历时排除符号链接 |
5.2 我踩过的三个和AI代码相关的坑
第一个坑,是AI生成的代码里出现了一个循环引用的问题。当时我为了让代码支持正则表达式,让AI加了一个“高级模式”,结果它在判断扩展名时把正则匹配的module import也卷进来了,逻辑绕来绕去,最后还是我手动拆成了两个函数。所以说,AI代码的架构未必优秀,评审环节不能跳。
第二个坑,是文件编码问题。我在命令行打印中文文件名时,在Windows终端里全是乱码。AI生成的代码没有考虑终端编码,我打印日志时才暴露。后来我在脚本开头统一设置了标准输出编码,用自己的工作环境测试通过后才觉得可靠。
第三个坑,是AI给的“去重”方案默认是MD5哈希,但它在计算大文件哈希时没有按块读取,直接整个文件读进内存。一个2GB的文件差点把内存撑爆。我这次没有直接用AI的代码,而是改成先按文件大小和修改时间做初步筛选,再用分块哈希确认。这个经历也印证了:AI生成的代码只是起点,性能和资源消耗还是得自己把关。
5.3 使用文件提取工具的几个安全建议
最后分享几个使用原则,都是实操中总结出来的。
第一,重要文件先测试再批量操作。第一次跑工具时,先选一个只有少量文件的目录试运行,确认输出结果符合预期,再处理大型目录。第二,默认复制而不是移动,万一提取规则设置得不理想,至少原文件还在原地,不会造成不可逆的损失。第三,不要轻易开启auto-clean功能。有人会在提取后自动删除源目录中的文件,除非你对匹配结果有百分之百的信心,否则我建议保留源文件。清理可以是后续步骤,但不建议做成无人工干预的自动化流程。
6. 我认为AI辅助小工具开发值得坚持的原因
写到这里,这篇文章也接近尾声了。最后想分享一点我个人的真实体会。
我没有把AI当成一个“可以替代程序员”的黑盒,而是当成一个随叫随到的搭子:它能快速把想法变成代码,也能在我不熟悉的语法上给我提示,还会在我提出边界条件后帮我迭代。真正的判断力和责任心始终在我这边,尤其是处理文件、处理数据、处理可能影响他人工作的脚本时,人工审核永远是最后一道防线。
文件提取工具只是这个系列的第一个成员。我手里还有几张小纸条,上面写着下一个要做的工具:给文件名批量加前缀的、把jpg批量压缩成webp的、扫描重复照片的、给导出的聊天记录整理成Markdown的。有了这套流程和统一框架,下一个工具的开发时间应该能控制在一顿饭的工夫里。
如果你也有一大堆文件需要整理,或者单纯想体验一下AI辅助开发的感觉,建议你就拿“文件提取”这个需求开刀。需求简单,见效快,还能积累一套能复用的开发流程,一举多得,值得一试。
