摘要
良好的上下文格式直接影响LLM对信息的理解和提取能力。本文系统讲解Markdown格式在LLM上下文中的应用,包括标题层级、列表结构、表格设计、代码块使用,以及与XML标签、JSON格式的对比,并提供信息密度控制和噪声过滤的实战策略。
关键词速览
| 术语 | 英文 | 说明 |
|---|---|---|
| Markdown | Markdown | 轻量级标记语言 |
| Frontmatter | Frontmatter | 文件开头的元数据 |
| 信息密度 | Information Density | 单位长度内的信息量 |
| 噪声过滤 | Noise Filtering | 去除无关信息 |
| 分层结构 | Hierarchical Structure | 多级嵌套的内容组织 |
| 代码块 | Code Block | 格式化代码区域 |
| 表格 | Table | 行列数据组织 |
| Callout | Callout | 强调块/提示框 |
| Wikilink | Wikilink | 内部链接语法 |
| 嵌入 | Embed | 内容嵌入语法 |
一、Markdown格式基础
1.1 为什么Markdown适合LLM
Markdown作为一种结构化的纯文本格式,对LLM具有独特优势:
- 结构明确:标题、列表、代码块都有明确的语法标记
- 层级清晰:通过缩进和标题级别表示从属关系
- 解析简单:LLM可以准确理解标记含义
- 灵活扩展:支持代码块、表格等复杂结构
- 与Wiki兼容:Obsidian等工具原生支持
1.2 基本格式对比
| 格式类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Markdown | 结构清晰、易读 | 表达能力有限 | 大多数场景 |
| XML标签 | 可自定义、语义明确 | 冗长、可读性差 | 需要精确语义标注 |
| JSON | 结构化、程序友好 | 嵌套深时不直观 | 结构化数据 |
| 纯文本 | 最简洁 | 无结构、解析难 | 简单信息 |
二、标题层级设计
2.1 标准标题层级
# 一级标题 - 文档主题
## 二级标题 - 主要章节
### 三级标题 - 子章节
#### 四级标题 - 详细内容
##### 五级标题 - 细节
###### 六级标题 - 最小单元2.2 LLM上下文的标题使用原则
TITLE_GUIDELINES = """
标题使用规范:
1. H1只用于文档主标题,每个文档限一个
2. H2用于主要功能模块或章节,不超过7个(符合认知限制)
3. H3用于子功能或具体步骤
4. 避免超过4级标题,过深的嵌套不利于LLM理解
5. 标题应简洁明了,包含关键词
6. 相关内容应有相邻的标题
"""2.3 实战:文档结构模板
# [主标题] - 简洁描述核心内容
> [!abstract]+ 摘要
>
> 一句话概括文档目的和核心内容
## 关键词速览
| 术语 | 说明 |
|------|------|
| 关键概念1 | 定义 |
| 关键概念2 | 定义 |
## 一、[第一章主题]
### 1.1 [子主题]
#### 1.1.1 [具体点]
## 二、[第二章主题]
## 三、[第三章主题]
## 总结三、列表结构
3.1 有序列表 vs 无序列表
适用场景对比:
| 列表类型 | 适用场景 | 示例 |
|---|---|---|
| 有序列表 | 步骤流程、排名、需要强调顺序 | 操作步骤、排名榜单 |
| 无序列表 | 并列项、分类列举 | 功能列表、特点说明 |
3.2 嵌套列表
# 正确示例 - 清晰的层级关系
1. 第一步操作
- 子步骤1.1
- 子步骤1.2
- 细项1.2.1
- 细项1.2.2
2. 第二步操作
- 相关说明
# 错误示例 - 混乱的嵌套
1. 第一步
- 错误:缩进不一致
* 混用标记3.3 任务列表(Checkbox)
- [x] 已完成的任务 ✓
- [ ] 待完成的任务
- [ ] 另一个待办
- [x] 子任务已完成
- [ ] 子任务待完成LLM应用:
def generate_task_list_prompt(tasks: List[Dict]) -> str:
"""生成任务列表提示"""
lines = ["## 待处理任务\n"]
for i, task in enumerate(tasks, 1):
priority = "🔴高" if task.get('priority') == 'high' else "🟡中" if task.get('priority') == 'medium' else "🟢低"
lines.append(f"- [ ] **任务{i}** {priority}")
lines.append(f" - 描述: {task['description']}")
if task.get('deadline'):
lines.append(f" - 截止: {task['deadline']}")
lines.append(f" - 状态: {task.get('status', '未开始')}")
return "\n".join(lines)四、表格设计
4.1 基础表格语法
| 列1 | 列2 | 列3 |
|-----|-----|-----|
| A1 | B1 | C1 |
| A2 | B2 | C2 |4.2 复杂表格设计
| 功能 | 支持情况 | 说明 | 优先级 |
|:-----|:-------:|:----:|:------:|
| 左对齐 | ✓ | 常用 | P1 |
| 居中 | ✓ | 标题 | P2 |
| 右对齐 | ✗ | 不支持 | P3 |
# 对齐语法
# :--- 左对齐
# :--: 居中
# ---: 右对齐4.3 表格与LLM的交互
def format_table_for_llm(
headers: List[str],
rows: List[List[str]],
caption: str = None
) -> str:
"""格式化为LLM友好的表格"""
lines = []
if caption:
lines.append(f"**{caption}**\n")
# 表头
header_line = "| " + " | ".join(headers) + " |"
separator = "| " + " | ".join(["---"] * len(headers)) + " |"
lines.append(header_line)
lines.append(separator)
# 数据行
for row in rows:
row_line = "| " + " | ".join(str(cell) for cell in row) + " |"
lines.append(row_line)
return "\n".join(lines)
# 示例
table = format_table_for_llm(
headers=["模型", "上下文", "特点"],
rows=[
["GPT-4o", "128K", "多模态强"],
["Claude 3.5", "200K", "长文本优"],
["Gemini 1.5", "1M", "超长上下文"]
],
caption="主流模型对比"
)五、代码块使用
5.1 基础代码块
```python
def hello():
print("Hello, World!")
```5.2 带行号的代码块
| 行号 | 代码 | 说明 |
|:----:|------|------|
| 1 | ```python | 开始代码块 |
| 2 | def example(): | 函数定义 |
| 3 | return True | 返回值 |
| 4 | ``` | 结束代码块 |5.3 代码块与注释结合
```python
def process_data(data: List[Dict]) -> Dict:
"""
处理数据的主函数
Args:
data: 原始数据列表
Returns:
处理后的结果字典
处理流程:
1. 数据清洗
2. 格式转换
3. 统计分析
"""
# 步骤1: 数据清洗
cleaned = [item for item in data if item.get('valid')]
# 步骤2: 格式转换
transformed = [{'id': i, 'value': item['value']}
for i, item in enumerate(cleaned)]
# 步骤3: 统计分析
result = {
'count': len(transformed),
'total': sum(item['value'] for item in transformed)
}
return result
## 六、Callout(提示块)
### 6.1 Callout类型
```markdown
> [!note] 笔记提示
>
> 一般性信息说明
> [!tip] 技巧提示
>
> 有用的建议或快捷方式
> [!warning] 警告
>
> 需要注意的重要信息
> [!danger] 危险
>
> 可能会导致问题的警告
> [!example] 示例
>
> 具体的使用示例
> [!quote] 引用
>
> 引用他人的话或外部来源
> [!abstract] 摘要
>
> 文档或章节的摘要
> [!info] 信息
>
> 补充信息
6.2 Callout嵌套
> [!note]+ 可折叠的笔记
>
> 这是默认展开的笔记内容
>
> > [!warning]- 嵌套的警告
> > 这是一个嵌套的可折叠警告
> > 展开时显示,折叠时隐藏6.3 Callout在LLM提示中的应用
SYSTEM_PROMPT_TEMPLATE = """
你是专业的技术文档助手。
> [!important]+ 核心职责
>
> 1. 准确理解用户问题
> 2. 提供结构清晰的回答
> 3. 在回答中引用相关文档
> [!warning]- 回答限制
>
> - 只基于提供的上下文回答
> - 不编造未提供的信息
> - 不确定时明确说明
> [!example]:: 良好回答示例
>
> **问题**: 如何使用Python的列表推导式?
>
> **回答**:
> 列表推导式是Python的简洁语法...
"""
def build_structured_prompt(context: str, query: str) -> str:
return f"""
{ SYSTEM_PROMPT_TEMPLATE }
## 提供的上下文
> [!info]- 背景信息
>
{context}
## 用户问题
{query}
## 回答要求
1. 先确认是否可以从上下文中找到答案
2. 如果能找到,给出具体引用
3. 如果不能,明确说明
"""七、分层缩进设计
7.1 缩进层级规范
INDENTATION_RULES = """
缩进层级与含义:
- 0级:无缩进,顶级内容
- 2空格:一级子内容
- 4空格:二级子内容
- 6空格:三级子内容
示例结构:
顶级内容(0缩进)
一级子内容(2空格)
二级子内容(4空格)
三级子内容(6空格)
"""7.2 缩进在列表中的应用
## 功能模块
模块A
- 功能A1
- 具体操作步骤:
1. 打开配置
2. 修改参数
3. 保存设置
- 功能A2
模块B
- 功能B17.3 缩进在表格中的替代
# 用分层列表替代复杂表格
## 电商系统功能
### 商品管理
- 商品列表
- 添加商品
- 编辑商品
- 删除商品
- 库存管理
- 入库操作
- 出库操作
### 订单管理
- 订单列表
- 查看详情
- 取消订单
- 支付处理
- 在线支付
- 货到付款八、信息密度控制
8.1 密度评估方法
def calculate_information_density(text: str) -> float:
"""
计算信息密度
返回:信息密度分数 (0-1)
"""
# 过滤停用词和常见词
content_words = extract_meaningful_words(text)
# 计算有效信息比例
total_words = len(text.split())
content_word_ratio = len(content_words) / total_words if total_words > 0 else 0
# 考虑结构化程度
structure_markers = count_structure_markers(text)
structure_score = min(structure_markers / 10, 1.0)
# 综合评分
density = 0.6 * content_word_ratio + 0.4 * structure_score
return density
def extract_meaningful_words(text: str) -> List[str]:
"""提取有意义的词汇"""
stopwords = {'的', '了', '是', '在', '和', '与', '等', '以及', '这', '那'}
words = text.split()
return [w for w in words if w not in stopwords and len(w) > 1]8.2 密度优化策略
| 策略 | 适用场景 | 实现方法 |
|---|---|---|
| 删除冗余 | 重复描述 | 去重压缩 |
| 提取核心 | 长段落 | 摘要提取 |
| 结构化 | 散乱信息 | 列表/表格化 |
| 编码 | 重复模式 | 使用占位符 |
| 分层 | 复杂内容 | 展开/折叠 |
8.3 自动密度优化
class ContextDensityOptimizer:
"""上下文密度优化器"""
def __init__(self, llm_client):
self.llm = llm_client
def optimize(
self,
text: str,
target_density: float = 0.7,
mode: str = "balance"
) -> str:
"""
优化上下文密度
mode: 'compress' (压缩), 'expand' (扩展), 'balance' (平衡)
"""
current_density = calculate_information_density(text)
if mode == "compress" or current_density < target_density:
return self._compress_to_density(text, target_density)
elif mode == "expand" or current_density > target_density * 1.2:
return self._expand_with_context(text)
else:
return text
def _compress_to_density(self, text: str, target: float) -> str:
"""压缩到目标密度"""
prompt = f"""请压缩以下文本,在保持关键信息的同时提高信息密度。
要求:
1. 删除重复和无意义的表述
2. 使用更简洁的表达
3. 保留所有关键数据和事实
4. 保持原有的结构层次
原文:
{text}
压缩后的版本(保持Markdown格式):"""
return self.llm.generate(prompt)
def _expand_with_context(self, text: str) -> str:
"""在保持密度的同时补充必要上下文"""
prompt = f"""以下文本信息密度过高,请适当补充必要上下文使其更易理解。
原文:
{text}
补充后的版本:"""
return self.llm.generate(prompt)九、噪声过滤
9.1 常见噪声类型
| 噪声类型 | 示例 | 过滤方法 |
|---|---|---|
| 格式噪声 | 多余空行、重复标记 | 清理脚本 |
| 内容噪声 | 模板文本、无关广告 | 内容识别 |
| 语义噪声 | 重复观点、过时信息 | 语义去重 |
| 标记噪声 | 失效链接、损坏引用 | 链接检查 |
9.2 噪声过滤实现
import re
class NoiseFilter:
"""上下文噪声过滤器"""
def __init__(self):
self.patterns = {
'extra_whitespace': re.compile(r'\n{3,}'),
'trailing_spaces': re.compile(r' +$', re.MULTILINE),
'empty_brackets': re.compile(r'\[\s*\]'),
'placeholder': re.compile(r'\[TODO\]|\[TBD\]|\[PLACEHOLDER\]'),
}
def filter_format_noise(self, text: str) -> str:
"""过滤格式噪声"""
result = text
for name, pattern in self.patterns.items():
result = pattern.sub('\n\n' if name == 'extra_whitespace' else '', result)
return result.strip()
def filter_content_noise(self, text: str) -> str:
"""过滤内容噪声(需要LLM辅助)"""
prompt = f"""请从以下文本中删除与核心信息无关的噪声内容。
噪声包括:
- 重复的表述
- 与主题无关的插入内容
- 过时的信息
- 模板化的客套话
原文:
{text}
清理后的版本(保持Markdown格式):"""
return self.llm.generate(prompt)
def filter_noise(self, text: str, level: str = "basic") -> str:
"""
综合噪声过滤
level: 'basic' (仅格式), 'medium' (格式+内容), 'aggressive' (激进过滤)
"""
result = self.filter_format_noise(text)
if level in ['medium', 'aggressive']:
result = self.filter_content_noise(result)
return result9.3 增量式过滤
class IncrementalNoiseFilter:
"""增量式噪声过滤器"""
def __init__(self, noise_threshold: float = 0.3):
self.noise_threshold = noise_threshold
self.noise_patterns = []
self.learned_patterns = []
def add_noise_pattern(self, pattern: str, description: str):
"""添加已知噪声模式"""
self.noise_patterns.append({
'pattern': re.compile(pattern),
'description': description
})
def learn_pattern(self, example: str, is_noise: bool):
"""从示例中学习噪声模式"""
if is_noise:
self.learned_patterns.append(example)
def filter_incremental(self, text: str) -> tuple:
"""增量过滤,返回过滤后的文本和被过滤的内容"""
filtered_parts = []
removed_parts = []
current = text
for noise in self.noise_patterns:
current, removed = noise['pattern'].subn(
'', current
)
if removed > 0:
removed_parts.append({
'type': noise['description'],
'count': removed
})
return current, removed_parts十、综合实战模板
10.1 完整文档模板
---
title: [文档标题]
date: [日期]
tags:
- [标签1]
- [标签2]
categories:
- [分类1]
- [分类2]
---
> [!abstract]+ 摘要
>
> [一句话概括文档核心内容]
## 关键词速览
| 术语 | 说明 |
|------|------|
| [关键概念1] | [定义] |
| [关键概念2] | [定义] |
---
## 一、[第一章主题]
### 1.1 [子主题]
[内容...]
> [!tip] 实践技巧
>
> [相关提示内容]
> [!warning] 注意事项
>
> [警告内容]
### 1.2 [子主题]
```python
# 代码示例
def example():
return "Hello"二、[第二章主题]
| 参数 | 类型 | 说明 | 必填 |
|---|---|---|---|
| param1 | str | 参数1 | ✓ |
| param2 | int | 参数2 | ✗ |
三、[第三章主题]
完整示例
# 完整使用示例 result = process(param1="value") print(result)
总结
要点回顾
- [要点1]
- [要点2]
- [要点3]
相关主题
## 十一、相关主题
- [[分隔符与标记系统]]
- [[上下文结构化]]
- [[RAG上下文优化指南]]
- [[上下文压缩技术]]
- [[Obsidian格式最佳实践]]
## 十二、参考文献
1. Gruber, J. (2004). Markdown.
2. Obsidian (2024). Obsidian Flavored Markdown.
3. CommonMark (2024). A strongly defined, highly compatible specification of Markdown.