思源笔记迁移 Obsidian Markdown 实战:避免表格压平与链接丢失

思源笔记迁移 Obsidian Markdown 实战:避免表格压平与链接丢失

前言

思源笔记(SiYuan Note)是国内开发者常用的知识管理工具,其 .sy 格式文档提供了块引用、子文档层级、表格合并单元格等丰富功能。

我从本科时期开始使用思源笔记,用了四五年,一直用到工作第三年。期间积累了大量学习笔记、项目资料和刷题记录,但没有形成了比较完整的知识体系。今年开始尝试结合 AI Agent 梳理知识库维护流程,经过一番选型对比后,最终决定迁移到 Obsidian。

原因主要有三点:

  • Obsidian 是 Markdown 优先的工具,文件格式开放,不依赖私有数据库
  • Obsidian 支持 AI Agent 直接操作 Markdown 文件,便于自动化知识梳理
  • Obsidian 的双链和图谱功能更适合长期知识库维护

但迁移过程中遇到了很多坑。本文将分享我从思源笔记迁移到 Obsidian Markdown 的实战经验,重点解决三个高频痛点:

  • 表格被压平成一整段文本
  • 思源块链接失效或变成无法解析的占位符
  • 子文档层级关系丢失

一、迁移前的认知准备

1.1 Markdown 可读性优先

迁移的第一原则:Markdown 可读性优先,结构保留其次,思源私有语义最后。

这意味着:

  • 如果思源表格可以转为标准 Markdown 表格,必须转为表格
  • 如果思源块引用无法保留,至少要留下被引用的文本和追溯备注
  • 如果思源子文档层级无法保留,通过目录或链接表达父子关系

1.2 迁移不是"搬运"

迁移不是把思源文件搬到 Obsidian 目录,而是:

  • 识别源文档的语义
  • 选择合适的目标目录
  • 转换为 Markdown 可读格式
  • 保留可追溯信息

1.3 迁移前必须做的事

1. 确认目录映射

迁移前先确认"源目录语义 → 目标目录结构"的映射关系,避免内容落到不合适的目录后又要整体挪动。

示例:

源目录:
- 刷题
- 数据结构

目标映射提案:
- 刷题 → 10-subjects/algorithms/刷题
- 数据结构 → 10-subjects/algorithms/数据结构

2. 建立源文档清单

递归枚举源目录中的全部 .sy 文档,建立清单并分类:

  • 必迁:有正文内容、知识记录、题目记录、索引作用明确的文档
  • 可忽略:仅承载挂件、空日记节点、纯层级容器、无正文导航壳的文档
  • 待确认:是否有迁移价值无法仅凭标题判断的文档

迁移完成后,必须按清单回查,不允许凭感觉认定"已经迁完"。

二、表格迁移:避免被压平

2.1 现象:表格变成一整段文本

思源笔记中的表格,迁移后在 Obsidian 中显示成一长段文本,不再是表格。

错误示例:

方法描述[clear()](...)删除 hashMap 中的所有键值对[clone()](...)复制一份 hashMap[isEmpty()](...)判断 hashMap 是否为空

2.2 正确做法:转为 Markdown 表格

正确示例:

| 方法 | 描述 |
| --- | --- |
| [clear()](https://www.runoob.com/java/java-hashmap-clear.html) | 删除 hashMap 中的所有键值对 |
| [clone()](https://www.runoob.com/java/java-hashmap-clone.html) | 复制一份 hashMap |
| [isEmpty()](https://www.runoob.com/java/java-hashmap-isempty.html) | 判断 hashMap 是否为空 |

2.3 Markdown 表格迁移规则

如果源内容是表格,迁移结果必须满足:

  • 保留表头行
  • 保留列顺序
  • 每一条逻辑记录仍然占一行
  • 单元格内的链接仍保留在原单元格里
  • 单元格文本里如果有 |,必须做转义
  • 单元格内如果有换行,无法拆列时用 <br> 保留

2.4 合并单元格的处理

标准 Markdown 表格不支持合并单元格,如果思源原表格包含合并单元格:

  • 拆平成普通行
  • 优先保证 Obsidian 中可读
  • 在表格附近补一条迁移备注

示例:

| 分类 | 方法 | 描述 |
| --- | --- | --- |
| 基础操作 | clear() | 删除 hashMap 中的所有键值对 |
| 基础操作 | clone() | 复制一份 hashMap |
| 基础操作 | isEmpty() | 判断 hashMap 是否为空 |

> 迁移备注:原表格包含合并单元格,已按 Obsidian Markdown 表格能力拆平展示。

三、块引用与链接迁移

3.1 思源链接类型

思源笔记中存在多种专有链接:

  • siyuan://blocks/...:块链接
  • 嵌入块:动态引用其他块的内容
  • 块引用:在正文中引用其他块的文本

这些链接在 Obsidian 中无法直接解析。

3.2 转换优先级

转换思源链接时遵循以下优先级:

  1. 能稳定映射到目标笔记:转换为普通 Markdown 链接或 [[双链]]
  2. 不能稳定映射,但引用文本有阅读价值:保留文本并补原块 ID 备注
  3. 既不能映射,也没有阅读价值:删除思源专有链接壳,仅保留必要说明

3.3 禁止行为

  • siyuan://blocks/... 原样保留到 Markdown
  • LeetCode1题1 这类仅在源文脉中有意义的占位链接直接写入目标仓库
  • 宣称"已转换为双链",但仓库里仍残留不可解析链接

3.4 块引用的处理

如果思源块引用无法原生保留:

  • 保留被引用文本
  • 能链接到目标笔记时保留链接
  • 有必要时补充原块 ID

示例:

> 引用自 [[Java集合框架]]:ArrayList 是基于动态数组实现的 List 接口。
> 
> 迁移备注:原块 ID `20220115143330-50zu2x3`

四、子文档层级迁移

4.1 思源子文档结构

思源笔记支持父子文档关系,父文档下可以有多个子文档,形成层级结构。

4.2 Markdown 中的处理方式

Markdown 本身不支持子文档概念,但可以通过以下方式保留层级关系:

方式 1:目录层级

10-subjects/algorithms/
├── algorithms.md          ← 父文档摘要
├── 数据结构/
│   ├── 链表.md
│   ├── 数组.md
│   └── 哈希表.md
└── 刷题/
    ├── DFS.md
    └── 滑动窗口.md

方式 2:链接索引

在父文档中创建子文档链接列表:

## 子文档索引

- [[数据结构/链表]]
- [[数据结构/数组]]
- [[数据结构/哈希表]]
- [[刷题/DFS]]
- [[刷题/滑动窗口]]

4.3 思源 ID 的处理

思源 ID 只作为追溯元数据保留,不作为主文件名。

示例 frontmatter:

---
siyuan_id: 20220115143330-50zu2x3
siyuan_title: 链表
siyuan_parent: 20220115143320-abc123
---

五、资源文件迁移

5.1 思源资源存储方式

思源笔记的图片和附件存储在 data/assets/ 目录,笔记中通过相对路径或思源专有路径引用。

5.2 Markdown 中的处理

  • 图片和附件迁到 Obsidian 仓库资源目录(如 assets/
  • 笔记中的引用改成相对路径
  • 不把二进制内容直接塞进正文

示例:

![](../assets/screenshot-20220115.png)

六、迁移检查清单

6.1 迁移前检查

  • 是否先完成了"源目录 → 目标目录"的映射确认?
  • 是否已递归枚举全部源 .sy,并完成 必迁 / 可忽略 / 待确认 分类?
  • 是否确定了每个必迁文档的目标路径?

6.2 迁移后验收

  • 必迁 清单中的每个 siyuan_id 是否都有对应 Markdown?
  • 仓库中是否仍存在 siyuan://blocks/ 残留?
  • 是否仍存在无法解析的占位链接,如 [[LeetCode1]][[题1]]
  • 是否存在文件名与其 siyuan_id 对应源标题不一致、且未说明原因的文档?

6.3 表格专项检查

  • 源表格是否仍然是表格?
  • 输出里是否存在分隔行 | --- |
  • 每一行源记录是否仍可识别为一行输出?
  • 单元格链接是否还在原来的单元格中?
  • 遇到合并单元格时,是否补了迁移备注?

七、常见错误与修正

错误 1:表格压平成段落

现象:Obsidian 中显示成一长段文本,不是表格。

修正:重新按源表格恢复行列,输出标准 Markdown 表格语法。

错误 2:内容还在,但展示语义丢了

现象:文字都保住了,但行列关系消失。

修正:把"在 Obsidian 中显示为表格"视为硬验收项,而不是样式优化。

错误 3:过度保留思源内部信息

现象:正文里充满 ID、元数据、编辑态信息,但还是不可读。

修正:可读 Markdown 优先,ID 只保留在 frontmatter 或迁移备注里。

错误 4:没确认目录映射就直接迁移

现象:内容先被落到了不合适的目录,后续又要整体挪动。

修正:迁移前先生成目录映射提案,先复用现有合适目录,经确认后再写入。

错误 5:漏迁非空源文档

现象:顶层索引、刷题正文已经生成,但某些有实际内容的子文档没有迁入。

修正:迁移前先递归建立源 .sy 清单,明确标注 必迁 / 可忽略 / 待确认,迁移后按 siyuan_id 逐项对账。

错误 6:文件名与源文档映射错位

现象:目标文件名看似合理,但 frontmatter 中的 siyuan_id 实际对应另一篇源文档。

修正:写入前核对"源标题 → 文件名 → siyuan_id",遇到重名时使用"标题 + 原 ID 备注"的保守命名。

八、实战案例:Java HashMap 表格迁移

原思源表格

思源笔记中有一篇"Java的HashMap"笔记,包含一个方法表格,每个方法有链接和描述。

迁移后的 Markdown

# Java的HashMap

## 常用方法

| 方法 | 描述 |
| --- | --- |
| [clear()](https://www.runoob.com/java/java-hashmap-clear.html) | 删除 hashMap 中的所有键值对 |
| [clone()](https://www.runoob.com/java/java-hashmap-clone.html) | 复制一份 hashMap |
| [isEmpty()](https://www.runoob.com/java/java-hashmap-isempty.html) | 判断 hashMap 是否为空 |
| [size()](https://www.runoob.com/java/java-hashmap-size.html) | 计算 hashMap 中键值对的数量 |
| [put()](https://www.runoob.com/java/java-hashmap-put.html) | 将键值对添加到 hashMap 中 |
| [get()](https://www.runoob.com/java/java-hashmap-get.html) | 获取指定键对应的值 |

---
siyuan_id: 20220115143330-50zu2x3

Obsidian 中显示效果

在 Obsidian 中,表格正常渲染,链接可点击,整体可读性良好。

九、AI Agent 协作迁移实践

这次迁移没有完全依赖单个 Agent 一口气完成,而是拆成了"读需求生成 spec → 按 spec 实施代码 → 回收经验沉淀 Skill"三个阶段。这样做的好处是:需求、执行和复盘相互隔离,后续发现问题时可以定位到底是 spec 不完整,还是执行偏离,还是验收规则缺失。

9.1 Codex GPT-5:先读需求,生成迁移 spec

第一阶段先让 Codex GPT-5 读取迁移需求、现有 Obsidian 目录结构、思源源文件目录和已有草稿,不直接写迁移代码,而是生成一份可执行 spec。

这份 spec 重点说明:

  • 迁移目标:从思源 .sy 转为 Obsidian 可读 Markdown
  • 目录映射:源目录应该落到哪个 Obsidian 目录
  • 文档分类:哪些是 必迁 / 可忽略 / 待确认
  • 内容转换规则:表格、块链接、子文档、资源文件分别怎么处理
  • 元数据保留规则:siyuan_id、源标题、父子关系放在哪里
  • 验收标准:如何检查漏迁、链接残留、表格压平和目录错位

我会要求 spec 尽量写成"执行者可以照着做"的格式,而不是泛泛描述原则。尤其是表格和块链接这类容易出错的部分,spec 必须给出明确的禁止行为和合格示例。

示例要求可以写成:

请先不要迁移文件。先读取当前 Obsidian 仓库结构和思源源文件结构,生成一份迁移 spec。
spec 需要包含目录映射、必迁清单、转换规则、验收清单和风险点。
对表格、块链接、子文档层级、资源文件分别给出处理规则。

9.2 GLM-5 / DeepSeek 4 Flash:读取 spec,实施迁移代码

第二阶段再把 spec 交给 GLM-5 或 DeepSeek 4 Flash 这类执行型模型,让它们读取 spec 后实施代码。这里的重点不是让模型重新理解业务,而是让它严格按 spec 写脚本、跑转换、生成结果。

实际执行时,我会把任务约束得更窄:

  • 先按 spec 枚举源 .sy 文档并生成清单
  • 再实现转换脚本或局部转换逻辑
  • 每次只处理一类问题,例如先修表格,再处理链接,再处理子文档
  • 输出变更文件、跳过原因和待确认项
  • 不允许擅自修改已经确认的 Obsidian 目录结构

这样可以降低执行模型自由发挥的空间。GLM-5 / DeepSeek 4 Flash 更适合承担批量读取、规则执行、代码实现和重复修正;但目录语义、验收标准和取舍原则最好提前由 spec 固定下来。

示例要求可以写成:

请严格读取 migration-spec.md,不要重新设计迁移方案。
只实现 spec 中定义的转换脚本和校验逻辑。
完成后列出:新增文件、修改文件、跳过文件、待确认文件、仍然存在的风险。

9.3 Codex GPT-5:回看结果,总结为 Skill

第三阶段再用 Codex GPT-5 回看整个迁移过程,把已经验证过的经验总结成 siyuan-markdown-migration Skill。这个阶段关注的不是继续迁移更多文件,而是把可复用规则沉淀下来,方便以后遇到类似迁移任务时复用。

Skill 中保留的是稳定规则,而不是一次性的临时上下文:

  • 什么时候触发这个 Skill
  • 迁移前必须收集哪些上下文
  • .sy 到 Markdown 的转换优先级
  • 表格、块链接、资源、子文档的处理规则
  • 常见错误和禁止行为
  • 验收清单和回查方式

我会特别要求 Codex GPT-5 区分"本次仓库特有信息"和"可复用迁移原则"。例如 10-subjects/algorithms/ 是本次仓库的目录约定,不应该写成所有迁移都必须使用的固定路径;但"迁移前必须确认源目录到目标目录的映射"就是可以复用的原则。

9.4 这套分工的关键点

这套流程最重要的是不要把 Agent 当成一次性文本生成器,而是把它们放到不同阶段:

阶段 使用模型 主要产物 关键要求
需求整理 Codex GPT-5 迁移 spec 先定规则,不急着写代码
代码实施 GLM-5 / DeepSeek 4 Flash 转换脚本、迁移结果、校验输出 严格按 spec 执行,减少自由发挥
经验沉淀 Codex GPT-5 siyuan-markdown-migration Skill 提炼稳定规则,剥离一次性上下文

最终沉淀下来的不是某一次迁移结果,而是一套可复用的 Agent 协作流程:先让强推理模型把需求压成明确 spec,再让执行模型按规则批量实施,最后再由强推理模型做复盘和 Skill 总结。

十、总结

思源笔记迁移到 Obsidian Markdown 的核心原则:

  1. 可读性优先:Markdown 在 Obsidian 中必须能正常阅读,表格必须显示为表格。
  2. 结构其次:父子文档关系通过目录或链接表达,不强行保留思源私有结构。
  3. 追溯最后:思源 ID、块引用等私有语义通过 frontmatter 或迁移备注保留,不影响正文阅读。
  4. 清单验收:迁移前后都要有清单,按 siyuan_id 逐项对账,不凭感觉认定完成。

迁移不是简单的文件搬运,而是从思源私有格式到 Markdown 标准格式的语义转换。把握好可读性、结构、追溯的优先级,才能避免表格压平、链接丢失、层级混乱等常见问题。

十一、迁移成果展示

经过约一周的迁移工作,最终形成的 Obsidian 仓库结构如下:

.
├── .obsidian/                   ← Obsidian 配置目录
├── 00-inbox/                    ← 收件箱(待处理内容)
│   ├── ai-drafts/              ← AI 生成草稿
│   ├── quick-notes/            ← 快速笔记
│   ├── todo-review/            ← 待复盘内容
│   └── web-clips/              ← 网页剪藏
├── 01-ideas/                    ← 想法收集
├── 02-journal/                  ← 日记与复盘
│   ├── daily/                  ← 日记
│   └── weekly/                 ← 周记
├── 03-tasks/                    ← 任务管理
│   ├── inbox/                  ← 任务收集
│   └── done/                   ← 已完成任务
├── 10-subjects/                 ← 主题知识库
│   ├── ai/                     ← AI 相关
│   ├── algorithms/             ← 算法与刷题
│   ├── backend/                ← 后端开发
│   ├── frontend/               ← 前端开发
│   ├── engineering/            ← 工程实践
│   ├── electron/               ← Electron 开发
│   ├── nodejs/                 ← Node.js
│   └── career/                 ← 职业发展
├── 20-summaries/                ← 总结与复盘
├── 30-projects/                 ← 项目资料
│   └── active/                 ← 活跃项目
├── 40-templates/                ← 模板文件
├── 90-archive/                  ← 归档区(原始资料)
│   ├── 2022-algorithms-study/ ← 2022 年算法学习原始记录
│   └── 2022-backend-study/    ← 2022 年后端学习原始记录
├── 90-assets/                   ← 资源文件(图片、附件)
└── 首页导航.md                  ← 仓库入口导航

迁移成果统计

  • 迁移时间:约 7 天
  • 源文档数量:约 50+ 篇 .sy 文档(含子文档)
  • 迁移后文件数:约 80+ 篇 Markdown 文件
  • 归档原始资料:约 30+ 篇(保留在 90-archive
  • 沉淀迁移规范:形成 siyuan-markdown-migration Skill

核心变化

思源目录结构 Obsidian 目录结构 说明
刷题 10-subjects/algorithms/ 合并到算法主题
数据结构 10-subjects/algorithms/数据结构/ 作为算法子目录
Java后端 10-subjects/backend/ + 90-archive/2022-backend-study/ 活跃内容归 subjects,原始记录归 archive
SpringBoot项目 90-archive/2022-backend-study/springboot-practice/ 历史项目归档
项目笔记 30-projects/active/ 按项目分类

后续维护策略

  • 10-subjects/ 只保留可继续维护的摘要和索引
  • 90-archive/ 保留原始资料,不做二次编辑
  • 新笔记直接写入 00-inbox/,定期整理到 subjects
  • 经验沉淀为 Skill 文件,便于 Agent 复用

参考资料


本文基于实际迁移经验整理,如有问题欢迎留言交流。

posted @ 2026-06-04 20:42  bleemyoung  阅读(217)  评论(0)    收藏  举报