关于 book-sft-pipeline
Book SFT Pipeline 是将书籍文本转为监督微调数据集并训练风格迁移模型的技能,适用于研究者和模型训练者。它覆盖分段、指令生成、数据构建、LoRA 训练与验证。
主要功能
- 01从 ePub 提取文本
- 02按语义边界分段
- 03生成多样化训练指令
- 04构建消息格式数据集
- 05使用 Tinker 进行 LoRA 训练
- 06通过新场景与原创性验证
适用场景
- 01从文学作品构建微调数据集
- 02训练模仿作者文风的模型
- 03为长文本设计分段流程
- 04评估模型是否学到文风而非情节
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ muratcankoylan/ agent-skills-for-context-engineering --skill book-sft-pipeline安装后在 Claude Code 中输入/book-sft-pipeline确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdexamples/gertrude-stein/dataset_sample.jsonlREADME.mdsample_outputs.mdtraining_config.jsonreferences/segmentation-strategies.mdtinker-format.mdtinker.txtscripts/pipeline_example.py详细介绍
书籍 SFT 流水线
一套完整的系统,用于将书籍转换为 SFT 数据集并训练风格迁移模型。本技能介绍从原始 ePub 到能够以任意作者的口吻写作的模型的完整流程。
何时启用
在以下情形启用此技能:
- 从文学作品构建微调数据集
- 创建作者口吻或风格迁移模型
- 为 Tinker 或类似的 SFT 平台准备训练数据
- 为长篇内容设计文本分段流水线
- 使用有限数据训练小型模型(8B 或更小)
核心概念
书籍 SFT 的三大支柱
1. 智能分段 文本片段必须在语义上连贯。在句子中间切分会让模型学会生成零散的内容。目标:每个片段 150-400 个单词,并始终在自然边界处切分。
2. 多样化的指令生成 使用多个提示词模板和系统提示词,避免过拟合。单一提示词风格会导致记忆化。使用 15 个以上的提示词模板和 5 个以上的系统提示词。
3. 风格优先于内容 目标是学习作者的节奏和词汇模式,而不是记住情节。合成指令应描述发生的事情,而不引用原文。
流水线架构
┌─────────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR AGENT │
│ Coordinates pipeline phases, manages state, handles failures │
└──────────────────────┬──────────────────────────────────────────┘
│
┌───────────────┼───────────────┬───────────────┐
▼ ▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ EXTRACTION │ │ SEGMENTATION │ │ INSTRUCTION │ │ DATASET │
│ AGENT │ │ AGENT │ │ AGENT │ │ BUILDER │
│ ePub → Text │ │ Text → Chunks│ │ Chunks → │ │ Pairs → │
│ │ │ 150-400 words│ │ Prompts │ │ JSONL │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ TRAINING │ │ VALIDATION │
│ AGENT │ │ AGENT │
│ LoRA on │ │ AI detector │
│ Tinker │ │ Originality │
└──────────────┘ └──────────────┘
阶段 1:文本提取
关键规则
- 始终优先使用 ePub,而非 PDF——OCR 错误会成为模型学到的模式
- 按段落提取——从
<p>标签提取,以保留段落分隔 - 移除正文前后的内容——版权信息和目录会污染数据集
# Extract text from ePub paragraphs
from epub2 import EPub
from bs4 import BeautifulSoup
def extract_epub(path):
book = EPub(path)
chapters = []
for item in book.flow:
html = book.get_chapter(item.id)
soup = BeautifulSoup(html, 'html.parser')
paragraphs = [p.get_text().strip() for p in soup.find_all('p')]
chapters.append('\n\n'.join(p for p in paragraphs if p))
return '\n\n'.join(chapters)
阶段 2:智能分段
更小的片段 + 重叠
与较大的片段(250-650 个单词)相比,较小的片段(150-400 个单词)能生成更多训练示例,并带来更好的风格迁移效果。
def segment(text, min_words=150, max_words=400):
paragraphs = text.split('\n\n')
chunks, buffer, buffer_words = [], [], 0
for para in paragraphs:
words = len(para.split())
if buffer_words + words > max_words and buffer_words >= min_words:
chunks.append('\n\n'.join(buffer))
# Keep last paragraph for overlap
buffer = [buffer[-1], para] if buffer else [para]
buffer_words = sum(len(p.split()) for p in buffer)
else:
buffer.append(para)
buffer_words += words
if buffer:
chunks.append('\n\n'.join(buffer))
return chunks
预期结果
对于一本 86,000 个单词的书:
- 旧方法(250-650 个单词):约 150 个片段
- 新方法(150-400 个单词 + 重叠):约 300 个片段
- 每个片段使用 2 个变体:600 个以上的训练示例
阶段 3:多样化的指令生成
关键见解
使用单一提示词模板会导致记忆化。多样化的模板能教会模型底层风格。
SYSTEM_PROMPTS = [
"You are an expert creative writer capable of emulating specific literary styles.",
"You are a literary writer with deep knowledge of classic prose styles.",
"You are a creative writer skilled at emulating distinctive authorial voices.",
"You write prose that captures the essence of modernist literature.",
"You are a talented writer who can channel classic American authors.",
]
PROMPT_TEMPLATES = [
"Write a passage in the style of {author}: {desc}",
"Channel {author}'s voice to write about: {desc}",
"In {author}'s distinctive prose style, describe: {desc}",
"Write this scene as {author} would have: {desc}",
"Using {author}'s repetitive technique, describe: {desc}",
"Capture the rhythm of {author} in this passage: {desc}",
"Write like {author}: {desc}",
"In the voice of {author}, write: {desc}",
"This is a literary exercise. Write like {author}: {desc}",
"Can you write in {author}'s style? {desc}",
]
指令生成
INSTRUCTION_PROMPT = """Describe what is happening in this excerpt in 2-3 sentences.
Focus on: characters present, actions, emotions, setting.
Do NOT quote the text directly.
Excerpt:
{text}
"""
# Use a fast, cheap LLM (e.g., Gemini Flash)
instruction = llm_call(INSTRUCTION_PROMPT.format(text=chunk))
阶段 4:数据集构建
消息格式
{
"messages": [
{"role": "system", "content": "You are an expert creative writer..."},
{"role": "user", "content": "Write in the style of Author: Scene description..."},
{"role": "assistant", "content": "The actual book text from chunk..."}
]
}
每个片段的多个变体
def build_examples(chunk, instruction, author, variants=2):
examples = []
for i in range(variants):
system = SYSTEM_PROMPTS[i % len(SYSTEM_PROMPTS)]
template = PROMPT_TEMPLATES[(chunk.id + i) % len(PROMPT_TEMPLATES)]
user = template.format(author=author, desc=instruction)
examples.append({"messages": [
{"role": "system", "content": system},
{"role": "user", "content": user},
{"role": "assistant", "content": chunk.text}
]})
return examples
阶段 5:在 Tinker 上进行 LoRA 训练
配置
CONFIG = {
"model_name": "Qwen/Qwen3-8B-Base", # Base, not instruct
"lora_rank": 32, # 352MB adapter
"learning_rate": 5e-4, # Higher for LoRA
"batch_size": 4,
"epochs": 3,
}
为什么使用基础模型?
使用基础(预训练)模型,而不是经过指令微调的版本:
- 基础模型更容易适应新风格
- 指令微调模型具有不易覆盖的模式
- 风格是一种底层模式,基础模型更擅长捕捉
训练循环
import tinker
from tinker import types
training_client = await service_client.create_lora_training_client_async(
base_model="Qwen/Qwen3-8B-Base",
rank=32
)
for epoch in range(3):
for batch in batches:
await training_client.forward_backward_async(batch, loss_fn="cross_entropy")
await training_client.optim_step_async(types.AdamParams(learning_rate=5e-4))
result = await training_client.save_weights_for_sampler_async(name="final")
阶段 6:验证
现代场景测试
使用原书中不可能出现的场景进行测试:
TEST_PROMPTS = [
"Write about a barista making lattes",
"Describe lovers communicating through text messages",
"Write about someone anxious about climate change",
]
如果模型能将风格标记应用于现代场景,说明它学到的是风格,而不是内容。
原创性验证
# Search training data for output phrases
grep "specific phrase from output" dataset.jsonl
# Should return: No matches
AI 检测器测试
使用 GPTZero、Pangram 或 ZeroGPT 测试输出。
已知问题及解决方案
角色名称泄漏
症状:模型在新场景中使用原有角色名称。 原因:仅使用一本书,名称多样性有限。 解决方案:使用多本书训练,或添加合成示例。
模型照搬原句
症状:输出中包含训练数据中的原句。 原因:提示词变体太少,或训练轮数太多。 解决方案:使用 15 个以上的模板,并将训练轮数限制为 3 轮。
输出零散
症状:句子读起来不完整。 原因:分段不当,在意思尚未表达完整时就进行了切分。 解决方案:始终在段落边界处切分。
指南
- 始终优先选择 ePub,而非 PDF——OCR 错误会变成模型学会的模式
- 不要在句子中间截断——边界必须符合语法且完整
- 使用多样化的提示词——15 种以上的模板、5 种以上的系统提示词
- 使用基础模型——不要使用指令微调版本
- 使用更小的文本块——每块 150-400 个单词,以获得更多示例
- 预留测试集——至少 50 个示例
- 使用现代场景进行测试——证明风格迁移能力,而非记忆能力
- 验证原创性——使用 grep 在训练数据中搜索输出短语
预期结果
| 指标 | 值 |
|---|---|
| 训练示例 | 每本书 500-1000 个 |
| 模型 | Qwen/Qwen3-8B-Base |
| LoRA 秩 | 32 |
| 适配器大小 | ~350 MB |
| 训练时间 | ~15 分钟 |
| 损失下降 | 90%+ |
| 风格迁移成功率 | ~50% 完美 |
成本估算
| 组成部分 | 成本 |
|---|---|
| LLM(指令生成) | ~$0.50 |
| Tinker 训练(15 分钟) | ~$1.50 |
| 总计 | ~$2.00 |
与上下文工程技能集成
此示例应用了 Agent Skills for Context Engineering 集合中的多项技能:
project-development
该流水线遵循分阶段、幂等的架构模式:
- 获取:从 ePub 中提取文本
- 准备:将文本切分为训练文本块
- 处理:生成合成指令
- 解析:构建消息格式
- 渲染:输出兼容 Tinker 的 JSONL
- 训练:LoRA 微调
- 验证:测试现代场景
每个阶段都可恢复,并会生成中间产物以供调试。
context-compression
分段是训练中的一种上下文压缩形式。上下文压缩的核心观点也适用于此:信息密度比信息数量更重要。较小且连贯的文本块(150-400 个单词)比更大且内容稀释的文本块能带来更好的风格迁移效果。
双层策略与上下文压缩评估相呼应:
- 第 1 层:快速、确定性的压缩
- 第 2 层:借助 LLM 处理边缘情况
multi-agent-patterns
该流水线采用监督者/编排者模式:
- 编排者协调各阶段并管理状态
- 专用 Agent(提取、分段、指令、构建)各自拥有隔离的上下文
- 每个 Agent 只接收完成任务所需的信息
这符合以下原则:子 Agent 的主要作用是隔离上下文,而不是模拟角色。
evaluation
验证遵循最终状态评估模式:
- 功能测试:输出是否符合预期的风格标记?
- 原创性验证:内容是否确实由模型生成?
- 外部验证:AI 检测器评分
“现代场景”测试是一种分布外评估,可用于证明泛化能力。
context-fundamentals
提示词多样性可避免模型在单一模式上出现注意力坍缩。使用相同的提示词结构训练时,模型会记住指令与响应之间的映射。多样化的模板会迫使注意力聚焦于风格模式本身。
参考资料
内部参考资料:
- 分段策略 - 文本切块模式
- Tinker 格式规范 - Datum 结构
- Tinker API 文档 - 完整的 API 参考
Agent Skills for Context Engineering 中的相关技能:
- project-development - 流水线架构模式
- context-compression - 压缩策略
- multi-agent-patterns - Agent 协调
- evaluation - 评估框架
- context-fundamentals - 注意力与信息密度
外部资源:
- 研究论文 - Chakrabarty 等人,2025 年
- Hugging Face 上的数据集
- Gertrude Stein 案例研究 - 完整的可运行示例
技能元数据
创建时间:2025-12-26 最后更新:2025-12-28 作者:Muratcan Koylan 版本:2.0.0 独立运行:是(与主上下文工程合集分开)