用Obsidian管理小说人物:双链+脚本自动生成关系白板

用Obsidian管理小说人物:双链+脚本自动生成关系白板 写小说最怕的不是没灵感而是写到第 30 章时你突然忘了林晚晴到底是慕容昭的师姐还是他的长姐也忘了那个只出场过两章的白发老者究竟属于天机阁还是青云宗。人物一旦超过十个关系一旦跨过两代再强的记忆力也会在高强度写作里失真。这个问题其实不是个例。长篇作者、剧本写手、同人文创作者、甚至跑团玩家都会遇到同一个困境设定越写越多人物越写越乱。更麻烦的是混乱是动态的——角色在第 5 章还是盟友第 18 章就反目了你以为的配角写到后来成了关键人物。用 Word 管理人物卡检索困难用 xmind 这类脑图软件画关系画完一次就再也不想维护。这篇文章要解决的核心问题只有一个如何用 Obsidian 管理小说人物并自动生成一张可视化的人物关系白板。我的判断很明确真正值得学的不是某一个“一键生成”的黑科技插件而是一套组合拳——Markdown 结构化记录 双链表达关系 脚本自动解析 Canvas 白板展示。理解这套组合拳你不仅能管理小说人物还能把它迁移到剧本排演、产品文档、团队架构、项目关系梳理等场景。文章会从 Obsidian 的核心概念讲起然后给出可直接复制的人物卡模板、三种不同层级的关系白板方案最后重点拆解一个用 Python 脚本解析 Markdown、自动生成 Obsidian Canvas 白板的完整实现。不需要你额外付费不需要你把笔记上传到任何云服务所有操作都发生在本地。1. 为什么写小说的人需要 Obsidian很多新接触 Obsidian 的人第一反应是“这不就是一个支持 Markdown 的文件夹管理器吗”这个理解不算错但会严重低估它在长文本创作中的价值。小说创作和写技术文档有一个共同点信息之间不是孤立的而是靠引用关系编织起来的。一个人物卡会关联到某个门派、某段历史、某个事件一个事件又会涉及多个角色。传统文档的树状文件夹结构强依赖“分类”但小说设定经常跨越多个分类——林晚晴既属于“天机阁”这个阵营又在“主角团”里还和“慕容世家”有血缘关系。你把她放在哪个文件夹里都不完整。Obsidian 解决这个问题的方式是双链。你可以把林晚晴独立成一篇笔记然后在她的笔记里用[[天机阁]]、[[慕容昭]]、[[主角团]]这样的双链语法把相关实体全部串起来。文件夹不再负责切割主题而只是物理归类真正的关系网由双链来承载。如果你只是把 Obsidian 当 Markdown 编辑器用那它和 Typora、VS Code 差别不大。但如果你开始用双链组织人物关系再配合关系图谱、白板等插件Obsidian 会变成一个“会自动画出你思维结构”的创作库。这篇文章适合这几类读者写长篇网文或实体书人物超过 10 个需要管理人物卡。写剧本、同人文、世界观设定需要随时查证角色关系。跑 TRPG 团需要记录 NPC 关系和阵营变化。对 Obsidian 插件生态感兴趣想找一个真实可落地的练习项目。如果你本来就了解 Obsidian可以直接跳到第 4 章看人物卡建模再跳到第 6 章看自动化脚本。2. 核心概念Markdown、双链、关系图谱与白板在进入实操之前先把几个关键概念讲清楚。这些概念决定了你后面能不能真正“自动生成”白板。2.1 Markdown 与 frontmatterMarkdown 是一种轻量级标记语言用#表示标题、-表示列表、**表示加粗。Obsidian 的所有笔记默认使用 Markdown 格式。但 Markdown 笔记里还有一种容易被忽略的结构frontmatter也叫 YAML 元数据区。它以---开头和结尾放在笔记最顶部用来记录结构化信息。--- name: 林晚晴 alias: 晚晴 faction: 天机阁 tags: [人物] ---frontmatter 的好处是它把“该笔记的元数据”和“笔记正文”分离开。Obsidian 可以通过 Dataview 插件对这些元数据做筛选、排序、表格渲染后面的 Python 脚本也是靠解析 frontmatter 来提取人物信息的。没有 frontmatter很多自动化都无从谈起。2.2 双链语法双链是 Obsidian 的灵魂。在笔记中输入[[林晚晴]]就等于创建了一个指向“林晚晴”这篇笔记的链接。慕容昭的师姐是[[林晚晴]]但两人其实没有血缘关系。这时林晚晴的笔记会自动出现一个“反向链接”区域展示哪些笔记提到了她。双链不仅在阅读时能跳转还会被关系图谱、Juggl、Canvas 等工具读取为“关系边”。你在写笔记时随手加的双链就是未来关系白板的原材料。2.3 关系图谱 Graph View关系图谱是 Obsidian 的核心插件之一默认开启。它会把全库所有笔记的双链关系渲染成一张可放大缩小的网络图。Graph View 几乎是零成本的关系可视化方案只要坚持写双链它就会自动生成全库关系图。不过它也有明显局限——全库的图太乱过滤条件有限布局不可保存也不太适合直接拿去给别人展示。2.4 Canvas 白板Canvas 是 Obsidian 官方推出的“白板”能力。它以一种可视化画布的方式承载笔记卡片你可以在画布上拖拽、连线、分类、写注释。Canvas 比较适合做“需要手动整理和沉淀”的展示型内容比如最终的人物关系图、剧情线索图、世界观地图。它的文件后缀是.canvas本质是一个 JSON 文件。这个特性很关键——JSON 是程序可以生成的所以我们可以写脚本自动生成白板让 Obsidian 直接打开。2.5 插件生态Obsidian 的社区插件非常丰富。和本主题相关的核心插件有Dataview用类 SQL 语法查询笔记元数据。Templater通过模板快速新建结构统一的笔记。Juggl把双链关系渲染成交互式网络视图比 Graph View 更适合筛选。Canvas官方白板能力。这里要做一个判断不要一上来就装几十个插件。插件的价值必须建立在“笔记结构规范”之上。如果笔记之间没有双链没有 frontmatter装再多可视化插件也渲染不出关系。这也是本文为什么先用第 4 章讲数据建模再在第 5 章讲可视化。3. 环境准备3 分钟搭好 Obsidian 创作库3.1 安装 Obsidian从 Obsidian 官网下载对应你操作系统的安装包即可。安装完成后新建一个 Vault库库的本质就是一个本地文件夹。注意一点尽量从官网下载不要用来路不明的第三方安装包。Obsidian 会把笔记以纯文本形式存在本地安全性和可控性都比较高但如果你用了被篡改的安装包这个优势就不存在了。3.2 开启核心插件打开 Obsidian 后进入“设置 - 核心插件”确认以下功能已开启关系图谱画板Canvas新版 Obsidian 可能默认叫“画布”模板如果你找不到“画板”说明你当前 Obsidian 版本较老建议先升级到较新版本。不同版本的中文译名会有差异认准英文名 Canvas 即可。3.3 安装社区插件进入“设置 - 第三方插件 - 社区插件”关闭“安全模式”然后浏览并安装DataviewTemplaterJuggl可选如果安装后出现兼容问题可以先跳过安装后在“已安装插件”里启用它们。注意社区插件会随 Obsidian 版本迭代更新安装时如果提示依赖不兼容以你当前实际版本的提示为准。3.4 规划库目录我建议在一个新建的库中做练习避免干扰你现有的笔记。目录结构可以参考你的库/ ├── 00 收件箱/ ├── 10 小说设定/ │ ├── 人物/ │ ├── 势力/ │ └── 事件/ ├── 20 正文/ └── 99 模板/这只是参考不是强制。关键是后面脚本里的路径要和你的实际目录一致。3.5 准备 Python 环境如果你打算用第 6 章的脚本自动生成 Canvas 白板需要准备一个 Python 3.8 以上的环境并安装pyyaml依赖pip install pyyaml如果不确定 Python 是否可用可以先运行python --version如果显示类似Python 3.10.x的输出就说明环境没问题。4. 人物数据的建模先有结构后有自动很多人上来就想找一个“自动识别人物”的插件实际上目前最稳定可靠的方式是你在记录人物时先给出结构化字段。插件和脚本只是把这些字段“翻译”成可视化结果。结构不统一自动化就是空中楼阁。4.1 统一人物卡模板在 Obsidian 的模板文件夹里新建一个人物卡模板.md内容可以这样写--- name: 未命名 alias: faction: age: relations: - target: type: tags: [人物] --- ## 角色定位 ## 外貌与性格 ## 生平经历 ## 当前目标 ## 重要事件我解释一下这几个字段的用途name人物正式名脚本匹配关系的依据。alias别名或外号方便你在正文里用多种称呼。faction阵营、门派或势力。relations结构化关系列表每一项包含target和type。tags统一打上“人物”标签方便 Dataview 索引。用 Templater 可以把这个过程进一步自动化。新建一个 Templater 模板文件加入系统提示--- name: % tp.system.prompt(请输入角色名) % alias: faction: % tp.system.suggester([天机阁, 青云宗, 散修], [天机阁, 青云宗, 散修]) % relations: tags: [人物] --- ## 角色定位 ## 外貌与性格 ## 生平经历之后在人物文件夹里调用这个模板Obsidian 会弹出输入框引导你录入角色名和阵营。这样能有效避免人物卡字段写得不统一。4.2 在正文中用双链建立关系人物卡之间不要只靠 frontmatter 的 relations 字段建立关系。在正文里同样要用双链因为双链会被 Graph View 和 Juggl 直接读取。比如林晚晴的笔记正文慕容昭的师姐是[[林晚晴]]但两人之间没有任何血缘关系。慕容昭的笔记正文[[林晚晴]]教了他十年剑法却在他出师那天不告而别。这些双链会在关系图谱里自动形成两条连接线。你不需要额外维护一张“关系表”只需要专注写内容即可。4.3 用 frontmatter 记录结构化关系双链能表达“有关系”但表达不了“是什么关系”。这时候需要用relations字段补足语义。--- name: 林晚晴 alias: 晚晴 faction: 天机阁 relations: - target: 慕容昭 type: 师姐弟 - target: 天机阁 type: 所属 tags: [人物] ---这样设计有两个目的第一脚本可以根据relations快速生成白板上的连接线第二将来如果你想统计“谁和谁是敌对关系”可以直接查询这个字段。需要提醒的是在同一部作品里两个人的关系可能会变。比如前期的“师徒”到后期变成“仇敌”。我建议在relations里记录“当前状态”而把关系的变化过程写进正文的“重要事件”部分。这样白板展示的永远是当前的关系结构不会因为剧情发展而失控。4.4 用 Dataview 生成人物索引页人物一多你需要一个总览页。在任意笔记里插入以下 Dataview 查询TABLE alias AS 别名, faction AS 阵营, join(relations.target, 、) AS 相关人物 FROM #人物 SORT file.name ASC打开阅读视图后它会自动渲染成一张表格把所有人物卡汇总展示。Dataview 这一步虽然不是必须的但它能让你在写正文之前快速检索“我已经创建了哪些人物”。5. 三种自动生成人物关系白板的方案现在进入主题自动生成人物关系白板。这里给出三种方案从简单到进阶你可以根据自己的需求选择。5.1 方案一Graph View 快速预览最零成本的方式是用 Obsidian 自带的关系图谱。操作步骤确保每篇人物笔记都打了人物标签。打开左侧“关系图谱”。在过滤器里输入#人物把视图收敛到人物节点。不出意外你会看到所有人物通过双链连成一张网络图。这个方案的好处是零配置坏处是节点位置无法保存线条没有语义很难区分“师姐弟”和“仇敌”。所以 Graph View 适合做日常写作时的“快速预览”不适合作为最终白板作品。5.2 方案二Juggl 做可筛选的交互式关系图Juggl 是社区里比较知名的关系可视化插件。它把双链渲染成交互式网络视图支持按标签筛选、展开收起节点视觉上比 Graph View 更接近“白板”的效果。使用步骤安装并启用 Juggl。在命令面板搜索“Juggl”打开 Juggl 视图。选择#人物标签作为筛选条件。点击某个节点右键展开相邻节点。Juggl 的优点是交互性强适合探索式阅读缺点是布局同样不好固定保存而且它和 Obsidian 版本的兼容性有时会有问题。如果你在安装后发现视图无法正常打开我建议先放弃 Juggl直接使用方案一或方案三。5.3 方案三脚本解析 Markdown生成 Canvas 白板这是我个人最推荐的做法。Obsidian 的 Canvas 文件本质是 JSON我们可以写一个脚本读取人物笔记里的 frontmatter 和双链再自动生成一个.canvas文件。在 Obsidian 里打开这个文件就能得到一张可拖拽、可整理、可分享的人物关系白板。这个方案相比前两个有四个优势布局可保存Canvas 文件里的节点坐标是写死的打开什么位置就是什么位置。文件可交付可以直接把.canvas文件发给别人或放进团队协作库。可二次编辑自动生成的节点生成后你可以在白板上继续手动拖拽和注释。可定制脚本逻辑完全掌握在自己手里想抽取什么字段、生成什么边都能自己改。下面第 6 章给出完整的脚本实现。6. 完整代码一键解析 Markdown 生成 Canvas 白板6.1 脚本思路这个脚本的逻辑分四步遍历指定文件夹下的所有.md文件。解析每篇笔记的 frontmatter得到人物名称、阵营、relations 等信息。用正则提取笔记正文里的双链得到笔记间的引用关系。把所有笔记生成为 Canvas 节点把 relations 和双链生成为连接线输出.canvas文件。6.2 完整脚本代码把以下代码保存为generate_canvas.py放在你的库根目录之外或库根目录均可。注意修改开头的四个路径变量。import json import re import os import sys import yaml # 配置区根据你的库结构修改 VAULT_ROOT /Users/你的用户名/你的Obsidian库 # Obsidian 库根目录的绝对路径 NOTES_DIR 10 小说设定/人物 # 人物笔记目录相对库根目录 OUTPUT_FILE 10 小说设定/人物关系白板.canvas # 输出 Canvas 文件相对库根目录 # def load_frontmatter(file_path): 读取 Markdown 文件的 frontmatter 和正文部分 with open(file_path, r, encodingutf-8) as f: text f.read() if not text.startswith(---): return {}, text parts text.split(---, 2) if len(parts) 3: return {}, text try: data yaml.safe_load(parts[1]) or {} except Exception: data {} return data, parts[2] def extract_wikilinks(body): 提取正文中的 [[链接]] 双链返回目标页面名列表 pattern re.compile(r\[\[([^\]|#])(?:#[^\]|]*)?(?:\|([^\]]))?\]\]) links pattern.findall(body) return [link[0].strip() for link in links] def find_note_file(note_dir, name, name_to_path): 根据人物名或文件名找到对应的笔记相对路径 # 先按 frontmatter 的 name 字段精确匹配 if name in name_to_path: return name_to_path[name] # 再按去掉扩展名的文件名匹配 for file_path in os.listdir(note_dir): if file_path.endswith(.md): base_name os.path.splitext(file_path)[0] if base_name name: return os.path.join(NOTES_DIR, file_path).replace(\\, /) return None def main(): notes_abs_dir os.path.join(VAULT_ROOT, NOTES_DIR) if not os.path.isdir(notes_abs_dir): print(f[错误] 找不到笔记目录{notes_abs_dir}) sys.exit(1) # 第一轮扫描所有人物笔记收集元数据 note_records [] name_to_path {} for file_name in os.listdir(notes_abs_dir): if not file_name.endswith(.md): continue file_path os.path.join(notes_abs_dir, file_name) meta, body load_frontmatter(file_path) if not meta: continue note_name meta.get(name) or os.path.splitext(file_name)[0] rel_path os.path.join(NOTES_DIR, file_name).replace(\\, /) note_records.append({ id: fnode_{len(note_records)}, title: note_name, file: rel_path, meta: meta, body: body, links: extract_wikilinks(body), }) name_to_path[note_name] rel_path if not note_records: print([提示] 没有解析到任何人物笔记请确认目录和 frontmatter 是否正确。) sys.exit(0) # 第二轮生成 Canvas 节点和边 nodes [] edges [] edge_id_counter 0 cols 4 for idx, record in enumerate(note_records): x 100 (idx % cols) * 360 y 100 (idx // cols) * 320 node { id: record[id], type: file, file: record[file], x: x, y: y, width: 260, height: 220, } nodes.append(node) # 根据正文双链生成边 for record in note_records: for target_name in record[links]: target_path find_note_file(notes_abs_dir, target_name, name_to_path) if not target_path: continue target_id None for rec in note_records: if rec[file] target_path: target_id rec[id] break if target_id and target_id ! record[id]: edges.append({ id: fedge_{edge_id_counter}, fromNode: record[id], fromSide: right, toNode: target_id, toSide: left, }) edge_id_counter 1 # 根据 frontmatter 的 relations 字段生成边 for record in note_records: relations record[meta].get(relations) or [] if isinstance(relations, list): for rel in relations: if isinstance(rel, dict): target_name rel.get(target) if not target_name: continue target_path find_note_file(notes_abs_dir, target_name, name_to_path) if not target_path: continue target_id None for rec in note_records: if rec[file] target_path: target_id rec[id] break if target_id and target_id ! record[id]: edges.append({ id: fedge_{edge_id_counter}, fromNode: record[id], fromSide: bottom, toNode: target_id, toSide: top, }) edge_id_counter 1 # 写出 Canvas JSON canvas_data { nodes: nodes, edges: edges, } output_abs os.path.join(VAULT_ROOT, OUTPUT_FILE) os.makedirs(os.path.dirname(output_abs), exist_okTrue) with open(output_abs, w, encodingutf-8) as f: json.dump(canvas_data, f, ensure_asciiFalse, indent2) print(f[成功] 已生成白板文件{output_abs}) print(f节点数量{len(nodes)}) print(f边数量{len(edges)}) if __name__ __main__: main()6.3 如何使用脚本使用前确认你的目录结构大体这样你的Obsidian库/ └── 10 小说设定/ └── 人物/ ├── 林晚晴.md ├── 慕容昭.md └── 天机阁.md然后运行python generate_canvas.py如果配置正确脚本会输出类似[成功] 已生成白板文件/Users/你的用户名/你的Obsidian库/10 小说设定/人物关系白板.canvas 节点数量3 边数量4回到 Obsidian在文件列表里点开人物关系白板.canvas就能看到自动生成的白板了。6.4 脚本关键点解释为什么用 Canvas 而不是直接输出 MermaidMermaid 可以渲染流程图但它本质是文本图表很难在 Obsidian 里拖拽调整布局。Canvas 则是真正的可视化画布节点和连接线可以手动移动。自动生成只是第一步人工整理布局是第二步。双链和 relations 会不会生成重复边有可能。如果正文里写了[[慕容昭]]frontmatter 的 relations 里也写了慕容昭那么这两个节点之间会出现两条线。脚本没有做自动去重这是为了保留不同维度的信息。你可以后续在 Canvas 里手动删掉不需要的线或者在脚本里加入去重逻辑。这就引出一个更重要的理念自动化脚本的目的不是取代人的整理而是把重复劳动降到最低。脚本负责把“人物节点”和“基本关系线”摆放出来你负责在画布上调整位置、加注释、美化展示。7. 运行结果与效果验证运行脚本后你需要判断生成结果是否符合预期。7.1 检查 Canvas 文件是否有效在 Obsidian 中打开生成的.canvas文件你应该看到每个.md人物笔记对应一个卡片节点。卡片上显示笔记文件名。存在双链或 relations 关系的人物笔记之间有连接线相连。如果某篇笔记没有name字段脚本会用文件名作为节点标题。如果 Canvas 文件打开后显示“无法解析”或空白第一步先检查生成的文件内容。用文本编辑器打开.canvas文件确认里面是一个合法的 JSON 结构包含nodes和edges字段。{ nodes: [ { id: node_0, type: file, file: 10 小说设定/人物/林晚晴.md, x: 100, y: 100, width: 260, height: 220 } ], edges: [] }如果连 JSON 结构都没有说明脚本没有成功写入回到第 6.3 节重新检查路径配置。7.2 验证关系线是否完整一个常见的困惑是为什么脚本生成了边但 Canvas 里看不到连线可能原因有两个fromNode或toNode的 id 和 nodes 里的 id 对不上。两个节点重合连线被节点挡住了。针对第一种情况检查脚本生成的边是否都指向存在的节点 id针对第二种情况进入 Canvas 后尝试拖动节点看看是否有线从节点边缘延伸出来。7.3 验证 frontmatter 是否被正确解析如果你发现某个角色没有出现在白板里大概率是该笔记的 frontmatter 没有写name字段或者---分隔符格式不对。在 Obsidian 里编辑模式下frontmatter 必须位于文件最顶部且以---开头和结尾。如果你在 YAML 里写了relations但脚本没有生成对应边可以先查看 frontmatter 的缩进relations: - target: 慕容昭 type: 师姐弟注意-和target之间的空格以及type的缩进。YAML 对缩进敏感缩进错误会导致解析结果不是列表或者直接跳过。8. 常见问题与排查思路问题现象可能原因排查方式解决方案脚本提示找不到目录VAULT_ROOT或NOTES_DIR路径不对打印notes_abs_dir确认绝对路径修正路径变量Windows 用户注意反斜杠转义生成的文件在 Obsidian 中打不开Canvas JSON 格式不正确用文本编辑器查看.canvas文件内容对照第 7.1 节的 JSON 结构检查字段有些人物没有出现在白板里笔记缺少 frontmatter或name字段为空打开笔记检查文件顶部补充 frontmatter或修改脚本改用文件名关系线只有一部分双链目标名和笔记名不一致检查正文里的[[人物名]]是否和实际笔记名一致统一命名或给笔记设置 alias中文乱码控制台编码问题检查终端编码Windows 上可尝试chcp 65001后重新运行relations关系没生成边YAML 缩进或类型错误检查relations是否被解析为列表在脚本中打印record[meta]确认结构手机端看不到白板效果手机端 Obsidian 版本过旧更新到较新版本更新后重新打开 Canvas插件装太多导致启动卡顿启用了过多不必要的社区插件在设置中逐步禁用测试只保留写作必需的插件定期清理这里单独说一下手机端的问题。Obsidian 的手机端是支持 Canvas 的但如果你用了较多社区插件手机端首次启动会比较慢更新插件时也容易遇到版本冲突。如果你是重度手机写作用户建议手机端只保留最核心的 Dataview 和 Templater其他插件在桌面端管理。9. 实践中总结的 7 条工程建议这部分是我实际使用 Obsidian 组织小说设定后的经验沉淀。很多新手在开始阶段过度关注“用什么插件”忽略了更基础的工程规范导致后面越来越乱。9.1 人物命名要全局唯一脚本匹配关系时最核心的根据是name字段和笔记文件名。如果你在不同章节里一会儿叫“林晚晴”一会儿叫“晚晴”白板里的连线就会断掉。我的建议是人物笔记的文件名就用正式全名别名放进 frontmatter 的 alias 字段。正文里可以用别名写但双链里尽量用标准名。Obsidian 也支持在双链中通过|指定显示文本例如[[林晚晴|晚晴]]这在链接指向层面不会造成混乱。9.2 一张人物卡只讲一个人人物卡的颗粒度要足够小。不要在一张笔记里写“林晚晴和慕容昭的共同经历”这种做法短期内省事时间一长会让关系图变得混乱。正确做法是以单个人物为最小单位人物间的纠葛用双链和 relations 表达涉及大事件时单独建一篇事件笔记。9.3 保持双链语义的纯度双链不只是“引用”它在 Graph View 和脚本里会被识别为“关系边”。如果你在人物笔记里写了一句“参考[[写作技巧]]”那么白板上也会多出一条指向“写作技巧”的线。如果这条线不想出现在人物关系白板上请把这类参考链接统一放进“灵感”或“资料”文件夹并用标签隔离而不是直接用双链混在正文里。9.4 定期生成及时提交脚本生成白板只是异步操作你的笔记每天都在变化。建议养成固定节奏每次大规模修改设定后重新运行一次脚本顺便在 Canvas 里手动调整连线布局。如果你使用 Git 管理 Obsidian 库生成的.canvas文件同样纳入版本控制。这样即使某次手动整理把画布改坏了也能回滚到上一个版本。9.5 备份优先不要依赖云同步Obsidian 的本地文件是纯文本这是一个巨大优势。你可以用 iCloud、OneDrive、坚果云等同步也可以用 Git 做增量备份。我建议至少配置一种“本地 远端”双备份方案尤其是小说创作这种花了大量心血的资料丢失成本太高。9.6 自动化脚本要保留不要只留在临时文件里脚本本身也是资产。当你的小说设定从 10 个人物扩张到 50 个人物脚本的路径配置、字段逻辑大概率需要调整。建议把generate_canvas.py放到独立目录并配上必要的注释方便半年后回来还能看懂。9.7 可以扩展但不要一开始就上 AIObsidian 生态里有很多 AI 插件比如可以用大模型自动抽取人物关系并生成结构化数据。这个方向确实有潜力但它有两个前提第一你已经有了规范的人物笔记第二你愿意接受 AI 抽取结果存在错误需要人工校对。对于新手我建议先把“双链 frontmatter 脚本”这套确定性流程跑通再考虑引入 AI。先确定性后智能。否则你连错误出在哪里都分辨不出来。10. 总结与下一步这篇教程讲的不是某一个插件而是一条完整的人物关系管理链路用 Markdown 和 frontmatter 让人物卡变成机器可读的结构化数据。用双链在写作过程中自然建立人物之间的关联。用 Graph View 做日常快速预览。用 Python 脚本读取笔记自动生成 Canvas 白板。在 Canvas 里手动调整布局得到一张可以交付、可以分享的人物关系白板。这套流程的迁移性很强。你只要把NOTES_DIR指向其他文件夹把 frontmatter 字段改成“事件”“地点”“势力”同样能生成事件关系白板、地点关系白板。我甚至见过有人用它管理开源项目的模块依赖关系原理完全一样结构化的 Markdown 笔记 双链关系 脚本生成可视化文件。下一步你可以尝试的方向有三个给脚本增加“去重边”功能根据type给连接线做颜色区分。用 Dataview 做一个人物阵营总览 Dashboard。为每个人物生成一条时间线然后在 Canvas 里把时间线和人物关系组合成一张更复杂的“设定地图”。如果你正在用 Obsidian 写小说或者准备搭建一个长期维护的知识库我建议先按第 4 章的人物卡模板建 3 个角色跑通第 6 章的脚本感受一下“从 Markdown 到白板”的完整流程。再用 10 个角色压测看脚本是否需要优化。大部分情况下这套方案能支撑的作品体量远远超过你现在的写作规模。