从文本到语义:让智能体高效处理 Markdown 的结构化语义中间层
从文本到语义:让智能体高效处理 Markdown 的结构化语义中间层
一、引言:智能体编辑 Markdown 的困境
Markdown 已成为技术文章的事实标准格式。它轻量、易读、可渲染为多种形式(如 HTML、PDF、知识库页面),因而广泛用于技术文档、博客和学术笔记。然而,当我们希望智能体(Agent)自动审阅、改写或生成 Markdown 文档时,却会发现它在这一环节表现往往不够理想:
• 结构混乱:Agent 在插入或修改章节时容易破坏文档层级; • 格式丢失:修改后代码块闭合符、列表缩进常被破坏; • 语义模糊:难以区分正文、注释和示例代码; • 上下文不连贯:对章节间逻辑关系缺乏理解。
根本原因在于——Markdown 是一种纯文本标记语言,结构靠符号隐式表达,语义依赖渲染器解析。对于智能体而言,它看到的只是文本行,并不真正“理解”哪些是章节、哪些是代码或表格。
要让智能体能像编辑器或 IDE 一样高效、安全地操作 Markdown,我们需要在它与文本之间引入一个结构化层,使文档语义可感知、可操控。这正是“结构化解析与语义编辑方案”的核心思想。
项目地址:https://github.com/ForceInjection/markdown-mcp
原文地址:https://github.com/ForceInjection/markdown-mcp/blob/main/docs/markdown-agent.md
相关文章:从零构建 MCP 服务:为 TRAE IDE 添加智能 Markdown TOC 处理能力
二、Markdown 的结构与语义挑战
Markdown 的简洁性带来了灵活性,也带来了歧义。其结构单元包括:
• 层级化元素:标题、列表、引用; • 块级内容:段落、代码块、表格; • 内联元素:强调、链接、行内代码; • 语义表达相对隐晦的格式:缩进、空行、标点变体。
同一语义结构可以有多种写法:
1. 列表项
- 子项或
- 列表项
- 子项两者渲染效果相同,但文本结构不同。这种不确定性使得智能体难以通过简单字符串匹配完成语义修改。
此外,Markdown 的上下文依赖性(如标题级别决定章节归属、列表嵌套依赖缩进)进一步增加了智能体理解与编辑的难度。
三、核心思路:结构化中间表示(SIR)与方案选择
3.1 实现方案对比
| 实现方案 | 思路 | 优点 | 局限 |
|---|---|---|---|
| AST(抽象语法树) | |||
| JSON IR | |||
| HTML/DOM | |||
| 双向模型(AST + Source Map) |
方案说明:
• AST(抽象语法树):通过标准 Markdown 解析器构建精确的语法结构,适合需要精确控制文档结构的场景 • JSON IR:将 AST 序列化为 JSON 格式,便于与 API 和 LLM 交互,适合需要跨平台数据交换的场景 • HTML/DOM:利用浏览器生态进行可视化编辑,适合需要富文本编辑功能的场景 • 双向模型(AST + Source Map):同时保留结构化表示和原文映射,提供完整的可逆性保证
从技术实现角度来看,AST 和 JSON IR 都是可行的技术路径,它们能够提供结构化的文档表示。但在实际智能体应用场景中,我们选择了更完善的双向模型(AST + Source Map) 方案,因为它提供了完整的可逆性保证和原文映射能力。
3.2 SIR 的核心概念与原理
3.2.1 SIR 的定义与目标
SIR(Structured Intermediate Representation)是一个语义化的中间表示层,它充当了智能体与原始 Markdown 文本之间的桥梁。为了解决智能体在纯文本上操作的脆弱性,需要在 Markdown 与自然语言之间引入这个结构化中间层。
其核心思想是:
• 语义抽象:将 Markdown 的文本符号转换为具有明确语义的节点对象 • 结构层次化:构建树状结构来反映文档的层级关系 • 操作安全化:提供语义级别的编辑接口,避免直接文本操作
3.2.2 SIR 的作用机制
SIR 的作用类似于:
• HTML 中的 DOM:提供结构化的文档对象模型,支持精确的节点操作 • 程序语言中的抽象语法树(AST):将源代码转换为可分析的树结构 • 数据库中的模式定义(Schema):定义文档结构的规范和约束
它将 Markdown 文档转换为一棵语义树,使智能体可以像操作数据结构一样编辑文档节点,而不直接修改文本。
3.2.3 SIR 的结构化表示
在语义层,文档可被视为一棵结构化的树:
Document (根节点)
├── Heading(level=1, text="引言") ← 一级标题节点
│ └── Paragraph("Markdown 的流行与挑战...") ← 段落子节点
├── Heading(level=2, text="结构化中间表示") ← 二级标题节点
│ ├── Paragraph("SIR 的定义与目标...") ← 段落子节点
│ └── CodeBlock(language="python", content="...") ← 代码块子节点
└── Heading(level=2, text="实现方案") ← 另一个二级标题节点
├── List(type="unordered") ← 无序列表节点
│ ├── ListItem("方案一:AST 解析") ← 列表项
│ └── ListItem("方案二:JSON IR") ← 列表项
└── Table() ← 表格节点
├── TableRow(["方案", "优点"]) ← 表头行
└── TableRow(["AST", "结构精确"]) ← 数据行3.2.4 SIR 的工作原理
SIR 的工作流程遵循以下核心原则:
1. 解析阶段:将原始 Markdown 文本解析为抽象语法树(AST) 2. 转换阶段:将 AST 转换为语义化的 SIR 节点树 3. 操作阶段:智能体通过语义接口操作 SIR 节点 4. 渲染阶段:将修改后的 SIR 节点树重新渲染为 Markdown 文本
这种分层架构确保了:
• 操作安全性:所有编辑都在结构化层面进行,避免文本级错误 • 语义明确性:每个节点都有明确的类型和语义含义 • 可逆性保证:通过源代码映射实现精确的文本位置跟踪
3.3 为什么选择 SIR 方案?
基于对上述方案的深入分析和实际项目需求,我们最终选择了双向模型(AST + Source Map) 作为 SIR 的实现方案,主要原因如下:
3.3.1 技术优势
1. 完整的可逆性保证:通过源代码映射,能够精确追踪每个 SIR 节点对应的原始文本位置,支持精确的撤销/重做操作 2. 语义完整性:既保留了 AST 的结构精确性,又通过 SIR 提供了更高层次的语义抽象 3. 操作安全性:所有编辑操作都在结构化层面进行,避免了直接文本操作的风险
3.3.2 智能体友好性
1. 接口语义化:提供 update_heading、insert_section等语义明确的编辑接口,而非低级的文本操作2. 上下文感知:SIR 节点包含完整的层级关系信息,智能体可以理解章节之间的逻辑关系 3. 错误预防:结构化操作自动处理格式细节(如缩进、闭合符),避免人为错误
3.3.3 工程实践考量
1. 扩展性:模块化设计支持轻松添加新的节点类型和编辑操作 2. 可维护性:清晰的架构分层使得各组件职责明确,易于维护和调试 3. 性能优化:支持增量更新和选择性渲染,提高大规模文档处理效率
3.3.4 与替代方案的对比优势
• 相比纯 AST:提供了更高层次的语义抽象,更适合智能体理解 • 相比 JSON IR:保持了源代码映射能力,支持精确的位置追踪 • 相比 HTML/DOM:保留了 Markdown 特有的语义信息,不会丢失原始格式
3.4 本章小结
SIR 方案的核心价值在于实现了从文本编辑到语义编辑的范式转变:
1. 智能体不再需要理解 Markdown 语法细节,只需关注文档的语义结构 2. 编辑操作变得意图明确且安全可靠,避免了格式破坏的风险 3. 支持复杂的结构化操作,如章节移动、内容重组、格式批量更新 4. 提供了完整的编辑历史追踪,支持精确的撤销和版本控制
这种方案特别适合需要自动化处理技术文档的场景,如:
• 智能文档审校和格式化 • 自动化章节重组和编号 • 多语言文档同步更新 • 技术文档知识图谱构建
通过 SIR 方案,我们为智能体提供了既安全又强大的 Markdown 编辑能力,真正实现了"让智能体像人类编辑一样理解和操作文档"的目标。
四、具体实现:Python SIR 框架
基于上述理论,我们实现了一个完整的 Python SIR 框架,位于 src/markdown_editor/ 目录下。该框架采用双向模型(AST + Source Map) 实现,提供了完整的结构化编辑能力。
4.1 架构概览
+-----------------------+
| Semantic Editor | ← 智能体调用语义接口
+-----------------------+
↓ ↑
+-----------------------+
| Structured IR | ← 内存中的语义树表示
+-----------------------+
↓ ↑
+-------------+ +-----------------------+ +-------------+
| Markdown | → | Parser & Converter | → | Markdown |
| (Text Input)| +-----------------------+ | (Text Output)|
+-------------+ | - AST Parser | +-------------+
| - SIR Converter |
| - Source Mapper |
+-----------------------+文件结构:
markdown_editor/
├── sir_schema.py # SIR 节点类型定义(数据模型层)
├── ast_parser.py # Markdown → AST 解析器(解析层)
├── sir_converter.py # AST → SIR 转换器(转换层)
├── semantic_editor.py # 语义编辑接口(业务逻辑层)
├── sir_renderer.py # SIR → Markdown 渲染器(渲染层)
├── source_map.py # 源代码映射管理(基础设施层)
└── __init__.py # 模块导出(API 层)4.2 SIR Schema 设计
在 sir_schema.py 中定义了完整的 SIR 节点类型,采用 TypedDict 和枚举实现:
class NodeType(str, Enum):
"""SIR 节点类型枚举"""
DOCUMENT = "document"
SECTION = "section"
HEADING = "heading"
PARAGRAPH = "paragraph"
CODE_BLOCK = "code_block"
LIST = "list"
LIST_ITEM = "list_item"
TABLE = "table"
TABLE_ROW = "table_row"
TABLE_CELL = "table_cell"
BLOCKQUOTE = "blockquote"
HR = "hr"
HTML_BLOCK = "html_block"
INLINE = "inline"
class HeadingLevel(int, Enum):
"""标题级别枚举"""
H1 = 1
H2 = 2
H3 = 3
H4 = 4
H5 = 5
H6 = 6
class SIRNode(TypedDict):
"""SIR 节点基础接口"""
id: str
type: NodeType
content: Optional[str]
children: List['SIRNode']
attributes: Dict[str, Any]
source_location: Optional[SourceLocation]
parent_id: Optional[str]
class HeadingNode(SIRNode):
"""标题节点"""
type: Literal[NodeType.HEADING]
level: HeadingLevel
title: str
anchor: Optional[str]
auto_number: Optional[str]
class SIRDocument(TypedDict):
"""完整的 SIR 文档表示"""
metadata: SIRMetadata
ast: SIRNode
source_map: Dict[str, SourceLocation]
errors: List[Dict[str, Any]]
warnings: List[Dict[str, Any]]4.3 解析与转换流程
框架采用两阶段处理:
1. AST 解析 ( ast_parser.py): 使用markdown-it-py构建标准 AST2. SIR 转换 ( sir_converter.py): 将 AST 转换为语义化的 SIR
# 完整处理流程
def process_markdown(content: str) -> SIRDocument:
# 1. 解析为 AST
ast_parser = MarkdownASTParser()
ast_root = ast_parser.parse(content)
# 2. 转换为 SIR
sir_converter = SIRConverter()
sir_document = sir_converter.convert(ast_root)
# 3. 生成源代码映射
source_mapper = SourceMapper(content)
source_mapper.build_mapping(sir_document)
return sir_document4.4 语义编辑接口
在 semantic_editor.py 中定义了丰富的语义操作:
class EditOperation(str, Enum):
"""编辑操作类型枚举"""
UPDATE_HEADING = "update_heading"
INSERT_SECTION = "insert_section"
DELETE_SECTION = "delete_section"
MOVE_SECTION = "move_section"
UPDATE_CONTENT = "update_content"
ADD_PARAGRAPH = "add_paragraph"
ADD_CODE_BLOCK = "add_code_block"
ADD_LIST = "add_list"
ADD_TABLE = "add_table"
RENUMBER_HEADINGS = "renumber_headings"
FIX_NUMBERING = "fix_numbering"
CHECK_CONSISTENCY = "check_consistency"
AUTO_REPAIR = "auto_repair"
class EditPosition(str, Enum):
"""编辑位置枚举"""
BEFORE = "before"
AFTER = "after"
CHILD = "child"
REPLACE = "replace"
@dataclass
class EditResult:
"""编辑操作结果"""
success: bool
message: str
changes: List[Dict[str, Any]]
warnings: List[str]
errors: List[str]
class SemanticEditor:
"""语义化编辑器"""
def __init__(self, sir_document: SIRDocument, config: Optional[SIRConfig] = None):
self.document = sir_document
self.config = config or SIRConfig()
self.edit_history: List[Dict[str, Any]] = []
self.source_map: Optional[SourceMap] = None
def update_heading(self, node_id: str, new_title: str,
new_level: Optional[int] = None) -> EditResult:
"""更新标题内容和/或级别"""
# 实现细节...
def insert_section(self, parent_id: str, position: EditPosition,
title: str, level: int = 2, content: Optional[str] = None) -> EditResult:
"""插入新的章节"""
# 实现细节...
def delete_section(self, node_id: str) -> EditResult:
"""删除指定章节"""
# 实现细节...4.5 源代码映射与可逆性
source_map.py 实现了精确的源代码位置跟踪:
class SourceMapper:
def build_mapping(self, sir_document: SIRDocument):
"""构建 SIR 节点到原始文本的映射"""
for node in traverse_sir(sir_document):
if node.source_location:
self._mapping[node.id] = node.source_location
def get_original_text(self, node_id: str) -> str:
"""获取节点对应的原始文本"""
location = self._mapping[node_id]
return self.original_content[location.start_line:location.end_line]4.6 高级特性
框架还提供了以下高级功能:
• 自动编号重排: 修改标题级别时自动重新编号 • 锚点生成: 为标题生成唯一的 URL 锚点 • 编辑历史: 支持撤销/重做操作 • 批量操作: 支持原子性的多步编辑 • 一致性验证: 编辑后验证 Markdown 语法正确性
4.7 完整使用示例
以下示例展示了从解析到编辑的完整流程,使用当前实际的 API 接口:
from markdown_editor import (
create_editor_from_markdown,
EditPosition,
EditOperation
)
# 原始 Markdown 内容
original_markdown = """
# 项目介绍
这是一个技术文档项目,旨在解决智能体编辑 Markdown 的挑战。
## 当前功能
- 基础解析
- 简单编辑
## 技术架构
项目采用模块化设计。
"""
print("=== 初始文档 ===")
print(original_markdown)
# 创建语义编辑器
editor = create_editor_from_markdown(original_markdown)
# 1. 更新现有标题
print("\n=== 更新标题 ===")
result1 = editor.update_heading(
node_id="heading_2", # "当前功能"标题的ID
new_title="已实现功能",
new_level=2
)
print(f"更新结果: {result1.success}")
# 2. 插入新的章节
print("\n=== 插入新章节 ===")
result2 = editor.insert_section(
parent_id="section_1", # "项目介绍"章节
position=EditPosition.CHILD,
title="设计目标",
level=3,
content="""
本项目旨在提供:
1. 安全的结构化编辑
2. 精确的源代码映射
3. 丰富的语义操作接口
"""
)
print(f"插入结果: {result2.success}")
# 3. 获取编辑历史
print("\n=== 编辑历史 ===")
for i, edit in enumerate(editor.edit_history):
print(f"{i+1}. {edit['operation']}")
# 渲染最终结果
final_markdown = editor.render()
print("\n=== 最终文档 ===")
print(final_markdown)输出结果:
# 项目介绍
这是一个技术文档项目,旨在解决智能体编辑 Markdown 的挑战。
### 设计目标
本项目旨在提供:
1. 安全的结构化编辑
2. 精确的源代码映射
3. 丰富的语义操作接口
## 已实现功能
- 基础解析
- 简单编辑
- 高级语义操作
- 源代码映射
- 一致性验证
## 技术架构
项目采用模块化设计。4.8 测试与验证
项目包含完整的测试套件,确保功能正确性和稳定性:
# 运行所有测试
pytest tests/ -v
# 运行编辑器相关测试
pytest tests/editor/ -v
pytest tests/test_semantic_editor.py -v
# 运行目录提取相关测试
pytest tests/toc/ -v
pytest tests/test_toc_mcp_server.py -v
# 运行 MCP 服务器测试
pytest tests/test_editor_mcp_server.py -v
pytest tests/test_toc_mcp_server.py -v
# 生成测试覆盖率报告
pytest --cov=src/markdown_editor tests/ --cov-report=html测试覆盖以下关键场景:
• 各种 Markdown 语法的正确解析 • 语义编辑操作的正确执行(插入、更新、删除等) • 目录提取和生成功能 • MCP 服务器接口的正确性 • 边界情况和错误处理 • 中文内容和特殊字符的处理
4.9 本章小结
本章详细介绍了基于 Python 的 SIR 框架实现,该框架具有以下核心优势:
1. 完整的结构化表示:通过双向模型(AST + Source Map)实现了精确的文档结构表示和源代码映射 2. 丰富的语义接口:提供了覆盖常见编辑场景的语义操作,包括标题更新、章节插入删除、内容替换等 3. 强大的可逆性保证:基于源代码映射实现了精确的撤销/重做和位置追踪能力 4. 模块化架构设计:采用清晰的层次结构,各组件职责明确,易于维护和扩展 5. 类型安全保障:使用 Python dataclass 和 Enum 确保类型正确性和代码健壮性 6. 测试验证完善:包含完整的测试套件,覆盖编辑器功能和目录提取功能 7. MCP 集成支持:与 MCP 服务器架构完美集成,支持智能体调用
该实现完全遵循了前文所述的结构化编辑理念,为智能体提供了既安全又强大的 Markdown 文档操作能力,真正实现了从文本编辑到语义编辑的范式转变。
五、功能示例:智能体重写技术章节
5.1 智能体编辑场景
以下是一些典型的智能体编辑场景,通过自然语言与智能体交互:
场景 1:文档重构
请帮我重新组织文档结构,将第5个标题的层级改为2级,并在"项目介绍"章节下插入一个三级标题"重组后的结构",内容为"重新组织后的文档内容..."。场景 2:内容扩展
请扩展技术文档,在"架构设计"章节下插入一个三级标题"性能优化",内容包含:
通过以下技术实现性能优化:
1. 缓存机制
2. 懒加载策略
3. 并行处理
同时将"实现"标题更新为"详细实现"并保持二级标题。场景 3:错误修复
请修复文档中的错误:
1. 将"错误标题"的层级修正为3级
2. 将"格式错误的标题"更新为"正确的标题"并保持2级标题5.2 智能体重写示例
假设原文如下:
## 实验结果
以下展示模型在不同参数下的性能。智能体交互指令:
请在'实验结果'章节后追加一段分析结论,内容为"综合来看,模型在中等参数下表现最稳定。"智能体执行后的结果:
## 实验结果
以下展示模型在不同参数下的性能。
综合来看,模型在中等参数下表现最稳定。整个过程通过自然语言指令完成,智能体自动处理 Markdown 解析、节点定位、内容插入和格式保持,避免了手动字符串操作可能造成的格式错误。
六、总结与展望
Markdown 的开放性让人类写作变得轻松,却给机器编辑带来了巨大挑战。要让智能体真正具备技术文档的"理解与编辑"能力,关键在于从纯文本处理过渡到结构化表示层。通过构建结构化中间表示(SIR)并提供语义化操作接口,智能体可以安全、精确地修改文档内容,实现从传统的"文本编辑"到现代的"语义编辑"的根本性转变。
展望未来,这一技术思路具有广阔的扩展空间:
• 自动化文档审校与一致性检查:基于 SIR 实现智能化的文档质量评估 • 技术文档知识图谱生成:从结构化文档中提取知识关系网络 • 多模态协作编辑:支持文本、图表、代码块等多种元素的协同处理
实施说明:当前实现仍处于 MVP(最小可行产品)阶段,后续需要与 IDE 文本编辑器深度整合,并解决手工编辑文档时如何高效更新 SIR 等关键技术问题。