raft
通过 RAG+微调双阶段训练,让 AI 学会模拟特定真实人物的思维方式与对话风格
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
通过 RAG+微调双阶段训练,让 AI 学会模拟特定真实人物的思维方式与对话风格
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
你有没有想过,如果让 AI 去模仿 Elon Musk、乔布斯或你的老板说话,会是什么效果?不是简单模仿语气,而是真正理解他们思考问题的方式——知道他们在某个话题上会怎么举例、会怎么反驳、会引用什么观点来支撑立场。
这正是 RAFT(Retrieval-Augmented Fine-Tuning) 试图解决的问题。这是一个由独立开发者 @lumpenspace 发起的开源实验项目,提出了一种将 RAG(检索增强生成)与微调相结合的独特方法,目标是构建能够高度逼真地模拟特定真实人类对话风格的 AI 智能体。
重要说明: 此 RAFT 与 Meta/微软团队发表的同名 RAFT 论文(RAFT: Adapting Language Model to Domain Specific RAG)是两个不同的研究。后者由 Berkeley 团队发表,使用 Llama2-7B 做领域特定 RAG 优化;本项目则聚焦于人类角色模拟,技术路线和目标场景均有显著差异。
在 AI 领域,构建能够模拟特定人类风格的对话智能体并非新鲜需求。它的应用场景包括:训练 AI 客服学习行业专家的沟通风格;为历史人物创建交互式数字分身;在心理治疗或教育培训中模拟特定角色的对话方式;以及更极端的场景——通过大量真实对话数据,训练出能够以假乱真的 AI 版本。
传统方案通常有两种:规则驱动(手工编写对话模板和逻辑规则)和纯微调(直接用目标人物的对话数据训练模型)。但两者都有明显缺陷——规则方案过于僵硬,一旦超出预设场景就会穿帮;纯微调方案则容易陷入过度拟合,模型只是机械地复述训练数据中的具体句子,而非真正学会背后的思维方式。
RAFT 的核心洞察是:一个人如何回答问题,取决于他过去写过什么、思考过什么。 换句话说,要模仿一个人说话,不能只看他的对话记录,还需要理解他过去写作中积累的记忆——这些记忆塑造了他的观点框架和表达习惯。
RAFT 采用了两阶段设计,这是一个在设计上颇为巧妙的方案。
这个阶段的目标是生成高质量的微调数据。输入需要两类数据:目标人物的访谈记录(包含问答应对的文本)和目标人物过去发表的内容(如博客文章、推文、论文等)。
处理流程如下:先将目标人物过去的内容进行分块(chunk),每个块约 4096 token;然后用 OpenAI 的 text-embedding-ada-002 模型为每个块生成向量嵌入;接着将这些向量和元数据一起存入 ChromaDB 向量数据库——这是一个轻量级的本地向量数据库,支持持久化存储。
在生成微调数据时,系统会逐一读取访谈记录中的每个问答对。对于每个问题,先通过向量检索从 ChromaDB 中找出语义最相关的记忆片段(即目标人物过去的写作内容)。然后,系统会调用 OpenAI 模型对这些记忆进行改写——让记忆的语言风格适配当前问题的语境,同时评估这些记忆对回答当前问题是否有帮助(无帮助的会被丢弃)。
最终,每个微调样本的结构为:历史问答加记忆链加上当前问题,映射到当前答案。这样训练出的模型,不仅学会了目标人物的具体表达方式,更重要的是学会了如何结合过去的知识来组织当前的回答——这才是思维方式模拟的关键。
微调完成后,推理阶段采用简化流程:将用户问题与改写后的相关记忆一起作为上下文,喂给微调后的模型,生成符合目标人物风格的回答。推理阶段不再需要 ChromaDB 检索(因为微调过程已经内化了这种能力),也不需要复杂的评估流程。
项目采用标准 Python 包结构,核心模块在 raft/ 目录下:
cli.py:命令行入口,基于 argparse 构建,支持 7 种子命令(fetch/chunk/embed/ft:gen/ft:run/bench:setup/ask),通过 poetry run raft <action> <name> 调用。memories.py:RAG 记忆管理的核心逻辑,MemoryManager 类封装了 ChromaDB 连接、向量检索和记忆摘要生成。使用 tiktoken 做 token 计数,ThreadPoolExecutor 并发处理检索任务。generate_finetune.py:微调数据生成流水线,核心函数 process_transcripts() 读取访谈 JSON,调用 MemoryManager 获取相关记忆,组装成微调样本写入 JSONL 文件。oai_finetune.py:OpenAI 微调任务提交与监控封装,支持上传微调文件、创建微调任务、查询任务状态。chunker.py 和 substack_embeddings.py:内容分块和 Substack 博客的自动化抓取嵌入,支持从 Substack URL 直接拉取文章并处理。prompt_manager.py:提示词模板管理,为记忆改写、评估等环节提供系统提示词。依赖生态非常清晰:ChromaDB 做向量存储、OpenAI SDK 做嵌入和微调、BeautifulSoup 做网页解析、pandas 做数据处理、tiktoken 做 token 计量、pynput 做可能的交互输入。整体依赖较轻,Poetry 一键安装即可运行。
记忆驱动的风格迁移。与大多数直接用对话数据微调的项目不同,RAFT 刻意引入了记忆这一中间层。项目的实验对象是 Gary Marcus(知名 AI 认知科学家),设计者认为要模拟 Marcus 的回答方式,不能只看他接受过的访谈,还需要理解他过去文章中的论点框架——这些才是塑造他思维方式的核心素材。
双阶段 RAG 加微调范式。传统 RAG 在推理时动态检索,RAFT 则将检索能力内化到模型权重中。这类似于将开卷考试的技巧内化为知识——模型不仅知道答案在哪里,还学会了在回答特定类型问题时主动调用相关背景知识的思维模式。
无外部依赖的本地向量数据库。ChromaDB 的使用让整个系统可以完全离线运行,不依赖任何云端 API(嵌入和微调阶段除外)。这为数据隐私敏感的场景提供了便利。
微调数据规模较小。OpenAI 的微调 API 对数据量有最低要求,且单个微调任务成本不低。项目作者也承认这是一个实验性项目,代码质量和文档完备度都存在不足。
评估体系(RATF)缺乏客观标准。RATF(Replica Agent Testing Framework)通过对比原始人类回答和 AI 生成回答来评估模拟质量,但这种评估高度主观,难以自动化。项目中 benchmark:setup 功能的存在说明作者意识到了这一问题,但具体实现细节较为简陋。
仅支持对话风格而非真实知识。模型学会的是像 Gary Marcus 一样说话,而不是和 Gary Marcus 拥有一样的知识。在涉及实时信息或超出训练数据范围的问题时,模型可能给出风格正确但内容错误的回答。
代理机制可解释性不足。记忆检索、改写、评估的流程缺乏可解释的中间输出,用户难以理解为什么某个记忆被保留或丢弃,调试成本较高。
RAFT 代表了 AI 智能体研究的一个细分方向:个性化角色模拟。这个方向与斯坦福的 Smallville 虚拟小镇、Replika 等个人 AI 助理、以及 Character.AI 等平台在底层技术上有共通之处。
值得注意的是,同名概念在学术界也有更广泛的应用——Meta 的 RAFT 论文证明了 RAG 加微调混合训练在医学、法律等垂直领域的 RAG 任务中显著优于纯 RAG 基线。这种将检索能力内化的思路,正在成为 LLM 领域的重要研究方向。
对于开发者而言,RAFT 项目提供了两个层面的参考:狭义上,它是一个完整的人类角色模拟 Pipeline,展示了如何将 RAG 与微调结合用于风格迁移;广义上,它的检索、改写、评估、训练四步框架,可以迁移到任何需要让 LLM 学会特定领域知识组织方式的任务中。
# 安装依赖
poetry install
# 查看帮助
poetry run raft -h
# 完整 Pipeline 示例(以 Substack 博客为例)
poetry run raft fetch <blog-name> # 抓取博客内容
poetry run raft chunk <blog-name> # 分块处理
poetry run raft embed <blog-name> # 生成嵌入并存入 ChromaDB
poetry run raft ft:gen <blog-name> # 生成微调数据
poetry run raft ft:run <blog-name> # 提交 OpenAI 微调任务
需要准备的外部资源:OpenAI API Key(用于嵌入生成和微调)、目标人物的访谈数据和/或 Substack 博客链接。数据格式为 JSON,具体格式见项目 README。