1. 这个Skill到底在解决什么麻烦
1.1 图片命名混乱的痛点
聊起Obsidian,先自报家门:我是重度用户,笔记库累积了四五年,Markdown文件一千多篇,附件文件夹里躺着四千多张图片。早年写笔记时为了图省事,截图直接拖进库,Obsidian默认生成Pasted image 20231021.png这种带时间戳的名字,手动截图存档的则是一堆DSC0001.JPG、微信图片_2023。文章一长,纯文字能看懂,真要回找某张插图,只能一张张点开预览,或者靠文件名里的日期碰运气。
一开始我觉得忍忍也就过去了,毕竟图片能显示、文章能读,追求文件名的美感没太大必要。直到有一天我需要把整批笔记迁移成公众号排版,发现每个插图引用都得手工改成带语义的文件名,四千多张图改到第三天心态直接崩了。那一刻我确定了必须做个一次性方案,把历史图片的“归位加重命名”全部交给AI处理。
1.2 我为啥不直接用现成的插件
Obsidian生态里不是没有改名工具,Templater可以按模板批量重命名,也有插件能批量移动附件,比如Text Format、Linter之类都带文件整理功能。但它们的共同问题是:改名规则由你预设,比如“按日期重命名”或“按父笔记标题重命名”,而历史插图最缺的恰恰就是上下文语义。同一篇文章里,一张是架构图、一张是截图、一张是流程图,光靠父笔记标题根本区分不开,只能得到一堆文章A-1.png、文章A-2.png这种看似整齐、实际还是大海捞针的文件名。
我也试过直接开个AI对话框,把图片和文章丢进去,说“帮我起名字”,它确实能返回很漂亮的建议。但问题在于,每处理一批文章都要重新解释一遍背景、重新粘贴附件路径、重新说命名规则,处理两三个小时之后你会发现,时间全浪费在和AI“对齐需求”上面了。后来看到社区里在讨论“Skill”这个概念——说白了就是给AI写一份结构化、可复用的操作说明书,让它不用每一次都从零理解需求。于是我就把整套重命名流程固化成了Skill,喂给AI执行,效果比插件野蛮多了。
1.3 适合谁来抄作业
如果你符合下面任意一种情况,这份经验可以直接拿过去改改就用:
- 笔记库里有大量
Pasted image xxx.png、image(1).png这类无意义文件名; - 文章里配图很多,你经常在正文里写“见下图”,但根本想不起图片叫什么名字;
- 你要批量把库里的图片和文章迁移到博客、公众号或PDF,必须让文件名有可读性;
- 你用AI辅助写作、整理笔记,但每次让它改文件都得重复交代背景规则。
反过来,如果你全库统一按“文章标题+序号”命名、每张图片路径清晰,那这套Skill解决不了什么大问题。不过你倒是可以拿它做一致性检查,查一下有没有漏网之鱼。
我的原则一直是:能花一个下午写工具解决的事,绝不花三个晚上手工硬扛。这个Skill也不只是写给我自己用,后面帮朋友整理知识库时改几个参数就能复制过去,这就是它最大的价值。
2. Skill的核心工作流程是怎么拆出来的
2.1 先理解“Skill”到底是什么
写之前我认真琢磨过普通提示词和Skill的差别。普通提示词最大的问题是“一次性”:规则写在聊天框里,改完这批图,下次还得重新输入;如果规则复杂点,比如要结合正文判断图片语义,那更依赖临场发挥。Skill的本质,是把提示词升级成一份有固定格式、固定执行步骤、固定输出结构的工作手册。
这份手册至少要包含几部分:角色定位(AI现在是谁)、任务目标(要干什么)、输入输出规范(给什么、返回什么)、执行步骤(先做什么后做什么)、边界条件(什么不要做、遇到歧义怎么处理)。这样AI就不是靠运气在猜,而是像同事一样按既定流程来处理。我把这个思路固化成了自己的Skill文件,平时放在Obsidian库外的skills目录里,每次要用的时候直接把Skill内容注入AI对话上下文,不用再从零描述需求。
2.2 拆出来的三步工作流
整套处理逻辑其实可以压成三步,Skill描述里我也只写三步,越简洁越好执行。
第一步,扫描附件目录,把待处理图片的清单生成一张“旧名清单”,包括图片路径、大小、创建时间、当前引用它的文章路径。注意这里必须先做“引用扫描”而不是单纯列文件,否则图片列出来一堆,根本不知道哪些还活着、哪些早已是孤儿文件。我见过不少批量整理脚本,上来就把整个附件目录改名,结果文章里的链接全部挂掉,哭都来不及。
第二步,让AI逐个读取引用图片的文章片段,理解图片在当前上下文里承担什么角色。流程图、截图、示意图、封面图,语义判断越准确,新文件名越靠谱。我会让它输出一个候选新名,同时附上一句“判断依据”,方便我复核时不用重新看原图。
第三步,把候选新名与旧名组装成映射表,经过确认后执行重命名,并同步回写正文里的图片引用链接。很多工具只做改名不处理引用,文章里头全部挂掉,这一步不能省。
2.3 给AI的“岗位说明书”怎么写
我踩过最大的坑是让AI自由发挥命名。你直接说“给这些图起个合适的名字”,它能给你整出花来:有加日期的、有带编号的、有把整段正文塞进文件名的,命名风格完全不统一。后面我学乖了,在Skill里明确规定了新文件的命名模板,格式是:
原图所属文章名(或主题关键词)- 图片作用 - 序号.png
比如文章标题是《Obsidian插件精选》,配图是截图某插件的设置页,新文件名就是Obsidian插件精选-插件设置截图-01.png。同一篇文章如果有多个同类截图,再按流水号区分。规范定死之后,AI输出的结果我基本一眼能扫完,不用一张张去猜它为什么起这个名字。
我还在Skill里加了一条硬规则:禁止改动仍被引用的图片文件不动,孤儿文件统一归入orphan文件夹。这条在实测中救了我很多次,因为历史库里经常有重复图、废弃图,AI要是手痒把它删了,后续想找回就麻烦了。
2.4 Skill文件里实际长什么样
我的Skill文件是纯Markdown,头部有YAML配置区,正文是给AI看的指令。结构大致如下,你可以直接参考:
--- skill_name: obsidian_image_renamer input_dir: 附件 backup_dir: _backup_rename 命名模板: "{文章名}-{图片作用}-{序号}.{ext}" 允许格式: [png, jpg, jpeg, webp, gif] --- 你是Obsidian笔记库的图片管理员。你的任务是分析文章上下文,为所有附件图片生成语义化文件名。 执行步骤: 1. 扫描附件目录,生成待处理清单,包含图片路径和引用文章路径。 2. 对每张图片,读取其所在文章段落,提取上下文信息,判断图片作用。 3. 按命名模板输出旧文件名、新文件名、判断依据三列。 4. 等待用户确认映射表后,再执行重命名和链接回写。 约束: - 新文件名只能包含中文、英文、数字、短横线。 - 同一文章内按出现顺序编号,从01开始。 - 被多篇文章引用的图片,以首次出现文章作为命名依据。 - 不要删除任何图片,孤儿图片移动到orphan目录。这里要注意的是,配置区和正文分离很有用。我日常复用的时候,只需要改头部几个参数,比如把附件换成images、把命名模板调一下,就能适配另一套库。AI看到头部配置就知道该用哪套规则,不用在正文里反复兜圈子。
3. 实操:把这个Skill接进Obsidian工作流
3.1 准备环境:软件与文件结构
说干就干。我本机用Obsidian,编辑器是VS Code,AI执行环境用自己日常调用的API客户端。除了Obsidian本体,你需要准备:
- Python环境,我用了Python 3.11,用来做映射表应用和链接回写;
- 一个能读取Markdown文件并生成结构化输出的AI客户端,任意支持长上下文的模型均可;
- 文本编辑器,用来修改Skill文件和映射表,VS Code或者Obsidian自带的编辑器都够用。
Skill本身是文本文件,不依赖特定插件,所以这套方案在Typora、Logseq甚至任何文件夹体系的笔记库里都能复刻,不一定非要Obsidian才能用。我选择Obsidian只是因为我的主库在这里,附件引用机制相对标准。
3.2 附件目录与命名规范
我库里的附件存放策略是“所有图片平铺在一个附件文件夹”,没有按文章分子目录。这个做法的优点是引用路径简单,缺点是文件名重复概率高。所以我在Skill里先内置了两条硬规则:
- 扫描范围限定在
附件/下所有png、jpg、jpeg、webp、gif文件,不处理其他类型; - 新文件名不能包含特殊字符、空格、中英文括号,统一用中文、英文、数字和短横线。
写进Skill的“命名规范”区块里,AI输出时就会严格遵守。万一它非要来一个括号或空格,我会让它重新生成。从实践看,把规则写得像“法律条文”而不是“建议”,AI的服从度会高很多。
3.3 生成“改名映射表”的正确姿势
执行时,我让AI先输出一张完整映射表,格式如下:
| 旧文件名 | 引用文章 | 语义判断 | 新文件名 |
|---|---|---|---|
| image(1).png | 2023/Obsidian插件精选.md | 插件设置页截图 | Obsidian插件精选-插件设置截图-01.png |
| Pasted image 20231021.png | 2023/Obsidian插件精选.md | 官方插件市场界面 | Obsidian插件精选-插件市场界面-01.png |
| 微信图片_20230101.png | 2023/双链实战.md | 双向链接关系示意图 | 双链实战-双向链接关系示意图-01.png |
这一步人工介入非常必要。AI对上下文的理解有时会偏差,比如把“示例图片”识别成“产品封面图”,实际改完名再去读文章就会觉得别扭。所以我的建议是,无论如何让AI先生成一张纯文本表,人工快速过一遍。文章多的时候,不用逐张看,只看“语义判断”那一列,有明显不对的打回去重跑就行。
3.4 批量重命名和链接回写怎么落地
映射表确认后,接下来就是工程活了。我写了一个极简单的Python脚本,读入CSV格式的映射表,先复制旧文件到备份目录,然后执行os.rename,再遍历库里的Markdown文件,把旧引用路径替换为新文件名。
这里有一个容易踩坑的细节:Obsidian内部链接有两种写法,一种是纯Markdown.png),一种是Wiki链接![[image(1).png]],两种都得处理。我的脚本用正则分别匹配两类语法,分别替换路径部分。同时它还做了个保护判断:如果新文件名在附件目录里已经存在,就自动在末尾追加-02,避免覆盖。
脚本核心逻辑不长,大概一百行左右,但防呆逻辑占大头。网上有很多“批量重命名并替换链接”的现成插件,但它们的改名规则都是基于模板,而我们这个映射表是AI判断出来的,所以建议还是自己写脚本,别指望通用插件能读CSV。下面这段是我脚本里的核心替换函数,逻辑很简单但够用:
import os, re, csv, shutil def load_mapping(csv_path): mapping = [] with open(csv_path, encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: mapping.append(row) return mapping def apply_rename(vault_dir, mapping): backup_dir = os.path.join(vault_dir, "_backup_rename") os.makedirs(backup_dir, exist_ok=True) for row in mapping: old_path = os.path.join(vault_dir, row["old_path"].lstrip("/")) new_path = os.path.join(vault_dir, row["new_path"].lstrip("/")) if os.path.exists(new_path): stem, ext = os.path.splitext(new_path) new_path = f"{stem}-02{ext}" shutil.copy2(old_path, os.path.join(backup_dir, os.path.basename(old_path))) os.rename(old_path, new_path) row["new_path"] = new_path def update_links(vault_dir, mapping): link_map = {row["old_path"]: row["new_path"] for row in mapping} md_pattern = re.compile(r"(!\[[^\]]*\]\()([^)]+)(\))") wiki_pattern = re.compile(r"(!\[\[)[^\]|]+(\]?|\|[^\]]+\]\])") for root, _, files in os.walk(vault_dir): for name in files: if not name.endswith(".md"): continue path = os.path.join(root, name) content = open(path, encoding="utf-8").read() changed = False for old, new in link_map.items(): new_content = md_pattern.sub( lambda m: m.group(1) + new + m.group(3) if m.group(2) == old else m.group(0), content) if new_content != content: content = new_content changed = True if changed: with open(path, "w", encoding="utf-8") as f: f.write(content)正则部分不用特别严谨,因为映射表里的路径是精确匹配,只要Obsidian链接语法没变就不会误伤。真正要小心的反而是Windows下的路径分隔符问题,统一用正斜杠,不然正则匹配会跑偏。
4. 实测记录:一次处理四千张图的真实过程
4.1 库规模与总体耗时
拿我自己这个库做了两次全量测试。第一次全量扫描出4126张图片,其中被Markdown文章引用的有3210张,另外916张是历史遗留的孤儿图片。Skill跑完扫描、AI逐篇判断语义、人工复核映射表,大概花了两小时。真正的文件重命名和链接替换只花了不到四分钟。
注意,时间大头不是AI执行,而是人工复核。四千张图如果完全不看,AI自己改完我当时不敢信,所以我每五十张卡一个检查点,扫一眼“语义判断”列有没有离谱的。后面发现了,其实不用从头看到尾,只看“语义判断”和文章路径是否匹配就够了,大概花了几百行,实际出错的就三处,比预期好很多。
4.2 三种典型错误与应对
第一次实测遇到的错误,整理下来也就三类。
第一类是AI把“示意图”全部命名为“封面图”。典型原因是文章开头有“如下图展示整体架构”,它就以为这是一张架构封面。解决办法是在Skill里增加明细规则:正文位置在开头50%之前的不准叫封面,开头50%之后的才可以叫封面。改完之后准确率高了一大截。
第二类是不同文章引用了同一张图片。这在历史笔记里很常见,一个截图既放在A文章里解释某功能,又被B文章引用作为补充对比。AI会为同一张旧图生成一个名字,挂到两篇文章下面,但两篇文章语境不同,命名就会打架。我最终的规则是:当一张图被多篇文章引用时,保留第一次出现的语境作为命名依据,另一篇文章里的引用不参与命名判断,只更新链接。这个规则写进Skill后,再也没有出现过一张图两个名字的分裂情况。
第三类是超大尺寸图片被当作“无聊截图”。我的库里有很多长截图,宽度超过2000像素,AI有时候想给它起名“微信截图”或“聊天记录”。我给Skill加了一条:尺寸大于2000像素宽的一般是长图,命名时加“长截图”后缀,效果立竿见影。这个尺寸阈值你可以根据自己的截图比例调,但确实比让AI自己猜稳定。
4.3 操作中值得注意的几个小细节
实测下来有几个小事很影响体验,这里顺便强调一下。
备份必须要做。虽然我的脚本强制先复制原始文件到_backup_rename目录,但Obsidian会有同步机制,改名过程中最好暂停同步,否则云端会同步一堆带着旧链接的碎片状态。我用的同步方案是Obsidian官方同步,实测中暂停同步后文件替换非常干净,没出现过链接半更新的情况。
AI上下文窗口别塞太满。如果文章本身很长,让它一次扫描几十篇,AI的注意力会被稀释,命名依据容易混乱。我改进后的做法是分批处理,每批限二十篇文章,映射表分批生成,最后再合并。测试下来准确率提升非常明显,AI在短上下文里对图片语义的判断明显更可靠。
还有一点,改了文件名之后,Obsidian的图谱视图可能要重建索引才刷新。重启一下Obsidian或者点一下“重新索引笔记库”就行,不会丢链接,但要让缓存更新。
5. 常见问题与避坑实录
5.1 映射表确认后还能反悔吗
能。这也是为什么我坚持“先备份、再改名、最后回写链接”这个顺序。如果你改名后觉得不满意,直接从备份目录恢复旧文件,再跑一次映射表回滚脚本就能回到原始状态。我给自己留了个简单的回滚脚本,逻辑和应用脚本完全相反,把备份目录里的文件复制回附件目录,再用旧映射表替换链接。
实际操作中,我真正反悔过两次,一次是AI给某张图片起的名字和文章文风完全不搭,一张是命名规范里忘了处理“文章名带书名号”的情况。好在那两次都发生在人工复核阶段,没有真正执行文件操作,所以回滚成本为零。如果你是在全量应用之后才发现问题,也别慌,备份目录里原始文件都在,慢慢恢复就行。
5.2 图片在文章里有多处引用,怎么处理最稳
这是很多人会忽略的地方。同一张图片在文章里出现三次,比如正文一次、附录一次、封面一次,AI如果只看第一次出现的段落,判断依据可能不够全面。我的做法是在Skill里给“被引用次数”单独设一列,超过两次的图片先单独列出来,人工重点审核。
对应规则是:如果第一次出现处的上下文语义不清晰,AI可以用第二次出现处的段落作为补充判断依据,但新文件名始终只保留一个。实践下来,这招比让AI合并所有语境更可靠,因为合并逻辑很容易让AI“精神分裂”,最后命名变成四不像。
5.3 长文章里的图片数量太多,会不会漏
有一定概率。一万字的长文可能有二三十张配图,AI在读取文章段落时,有时会把“见下图”后面的图片和前面的图片搞混。我应对的办法是让AI在输出映射表时,额外附上“原文引用序号”,比如文章第8段引用的是旧文件名。这样人工复核时可以交叉确认,漏图的情况会明显减少。
如果确实发现漏了,没必要重新全量跑,你可以单独写一个小Skill实例,只处理漏掉的那几张图。我的整个方案本来就是模块化的,扫描、语义判断、链接应用三步彼此独立,单独处理零星图片非常方便。
5.4 遇到AI死活不按命名格式走怎么办
这种问题多半不是AI笨,而是你的Skill描述不够强制。我试过把“必须使用模板”写在描述里,但AI偶尔还是会返回带空格和括号的名字。后来我直接在约束区加了一行:“输出结果若不符合命名规范,将直接判定失败,需要重新生成。”同时我在Skill末尾放了一个“自检清单”,让AI在输出前自己检查一遍。
别小看这个自检清单,它本质上是把规则重复了一遍,相当于让AI在交卷前做完形填空。实测里加了这个之后,命名格式违规率降到了接近零。
6. 把Skill沉淀成可复用资产的一些心得
6.1 踩过之后才总结出的Skill设计原则
写完这个Skill并用了三周后,我有几个明显体会。第一,技能描述里每一个规则都要能被执行,不要写“尽量”“适当”这种AI无法量化的词。比如“遇到模糊图片应询问用户”就比“看情况处理”强得多。这个原则听着简单,真正写的时候,你会发现自己随手就会写出很多含糊其辞的句子。
第二,Skill要设计成“一次输入、多次复用”的格式,所以尽量把运行参数(附件路径、命名模板、是否生成备份)放在文件顶部的配置区。用的时候改参数,不要改动规则正文,规则正文是逻辑主体,参数一变就很容易产生前后矛盾。
第三,给AI的指令要按“先原则后例外”的顺序组织。先告诉它大目标是“为图片生成有语义的文件名”,然后才是各种例外和约束。如果你一上来就列一堆“不准做什么”,AI容易变得畏手畏脚,输出一堆保守但没用的名字。
6.2 为什么不满足于写完就完事
这个Skill后来被我扩展了一次,把“给正文补插图说明文字”和“为文章生成图片清单”两件事也并了进来。处理完重命名后,AI顺便给每篇文章生成一张图片索引表,放在文章末尾YAML区。这样以后想找“某篇文章的某张截图”时,直接在Obsidian搜索框里搜文件名关键词就行,再也不用手动翻文件夹。
说实话,重命名只是第一步,真正让我觉得值回票价的是图片索引。以前写总结文章时,要一屏一屏找配图位置,现在打开文章就能看到“本文共引用6张图片,分别对应文件名”,直接对着文件名找图,节省了非常多的时间。
6.3 一个更适合日常的小建议
如果你嫌脚本太重,只想马上用,最低成本的做法是:复制Skill文本,打开AI客户端让它生成映射表,三五篇的小库可以手动改文件名加编辑引用,虽然累两步,但同样能把历史欠账清掉。这个Skill真正的价值,不在于一次性执行这个动作,而在于把“图片归位”这件事从靠感觉、靠运气变成了有流程、有依据的工程行为。
我实际体验下来,AI批量改动文件这件事,别追求一步到位。先在小库试跑一遍,确认AI的命名风格、人工复核的节奏、脚本替换逻辑都顺手,再放到全量库上执行。后来我帮朋友整理他的知识库时,把这套流程改了改参数,比如把附件目录名改掉、把命名模板里的文章名长度限制调整一下,直接复制过去就能用,效果非常稳定。希望这份经验能帮你少走点弯路,早日摆脱手动重命名的体力劳动。