ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

企业级AI应用实战:从RAG到SFT的完整工程化路径

企业级AI应用实战:从RAG到SFT的完整工程化路径 在实际企业级大模型应用开发中RAG检索增强生成和SFT监督式微调是两种核心的工程化路径。很多开发者会陷入一个误区认为它们是互斥的选择。实际上RAG擅长快速、低成本地引入外部知识而SFT则能从根本上调整模型的行为和知识结构。一个成熟的AI应用往往需要先通过RAG验证知识注入的有效性再针对高频、核心、固定的知识领域进行SFT以实现更低的延迟、更高的准确性和更可控的成本。本文将以一个“企业内部技术文档问答系统”为场景带你完整走通从RAG到SFT的实战链路。你将学会如何部署一个开源的Embedding模型使用LangChain构建一个可运行的RAG系统并最终将积累的高质量问答对用于私有化微调一个轻量级大语言模型。整个过程强调工程落地包含具体的环境配置、代码实现、参数解释和排错指南。1. 理解RAG与SFT的核心差异与协同关系在动手之前必须厘清RAG和SFT分别解决了什么问题以及它们如何协作。这决定了后续技术栈选型和工程投入的方向。1.1 RAG基于检索的“外挂知识库”RAG的核心思想是“按需查询动态拼接”。它不改变大语言模型LLM本身的参数而是通过以下流程工作知识预处理将私有文档如PDF、Word、Markdown切分成片段Chunk通过Embedding模型转换为向量存入向量数据库。用户查询用户提问时将问题同样转换为向量。向量检索在向量数据库中搜索与问题向量最相似的文本片段。提示词构建将检索到的相关片段作为“上下文”与用户原始问题一起拼接成最终的提示词Prompt发送给LLM。生成答案LLM基于提供的上下文生成答案。优点实施快速无需训练接入文档即可用。知识可追溯答案来源于检索到的片段可提供引用来源增强可信度。知识更新方便更新文档后重新生成向量并入库即可模型本身不变。成本较低主要消耗在推理时的Token和向量检索上。缺点依赖检索质量如果切分策略不当或检索不到相关内容模型会“胡编乱造”。上下文长度限制检索到的片段总长度受LLM上下文窗口限制。存在延迟需要经过文档处理、向量化、检索等多步操作。答案风格不一致模型可能无法完全模仿特定领域或公司的行文风格。1.2 SFT基于微调的“内化知识库”SFT的核心思想是“调整参数改变行为”。它通过使用高质量的指令-回答对Instruction-Response Pairs数据集对预训练好的基座模型进行有监督训练从而让模型学习到新的知识或特定的回答模式。优点回答质量高且风格一致模型内化了知识回答更流畅、专业风格可控。推理速度快微调后的模型在推理时无需额外的检索步骤单次前向传播即可生成答案。突破上下文限制模型本身掌握了知识不受提示词长度限制。私有化部署模型完全私有数据不出域安全性高。缺点需要高质量数据数据质量直接决定模型效果数据清洗和标注成本高。训练有门槛需要机器学习基础和GPU资源。更新不灵活要注入新知识需要重新收集数据并训练周期较长。可能遗忘原有能力不当的微调可能导致模型在其他通用任务上能力下降。1.3 如何选择与协同RAG先行SFT深化对于企业知识库场景一个高效的策略是第一阶段快速验证使用RAG快速接入所有文档构建原型系统。通过实际用户问答收集高频问题、优质答案以及RAG失败检索错误或生成不佳的案例。第二阶段数据积累将RAG系统中产生的优质问答对特别是人工修正过的沉淀下来形成高质量的SFT训练数据集。第三阶段效果深化针对最核心、最稳定、问答频率最高的知识领域使用积累的数据集对一个小参数量的模型如Qwen1.5-1.8B进行SFT。微调后的模型可以独立或与RAG系统结合使用例如用微调模型做重排序或最终答案润色。下表总结了关键决策点考量维度RAG (检索增强生成)SFT (监督式微调)协同建议启动速度快天级别慢需数据准备、训练周级别先用RAG上线收集数据。知识更新频率高随时更新文档低重训练成本高动态知识用RAG静态核心知识用SFT。单次查询成本中检索长上下文生成低仅生成高频查询服务用SFT降成本。答案风格一致性低依赖基座模型高可被训练对品牌语音、报告格式有要求时用SFT。硬件要求低需CPU/内存跑Embedding和向量库高需要GPU进行训练RAG验证需求再投资SFT硬件。数据需求原始文档高质量的(问题, 答案)对用RAG生产的数据反哺SFT。2. 环境准备与核心组件部署我们将构建一个本地开发环境所有组件均可在Linux或MacOS上运行Windows建议使用WSL2。2.1 基础环境与Python依赖首先确保系统已安装Python 3.8-3.11和pip。创建一个独立的虚拟环境是好的实践。# 创建项目目录并进入 mkdir rag-to-sft-project cd rag-to-sft-project # 创建虚拟环境 python -m venv venv # 激活虚拟环境 (Linux/Mac) source venv/bin/activate # 激活虚拟环境 (Windows) # venv\Scripts\activate安装核心的Python库。这里我们固定一些关键版本以保证兼容性。pip install -U pip pip install langchain0.1.0 pip install langchain-community0.0.10 # 社区集成的组件 pip install chromadb0.4.22 # 轻量级向量数据库 pip install sentence-transformers2.2.2 # 用于运行Embedding模型 pip install pypdf3.17.4 # 用于解析PDF pip install tiktoken0.5.1 # 用于Token计数和文本分割 pip install accelerate # 用于模型加载和推理加速 pip install transformers4.37.0 # Hugging Face 模型库2.2 部署本地Embedding模型在RAG中Embedding模型的质量直接决定检索精度。虽然可以使用OpenAI等云端API但出于数据隐私和成本考虑部署本地模型是更常见的生产选择。我们选用BAAI/bge-small-zh-v1.5这是一个效果优秀且体积较小的中英文双语模型。在项目根目录下创建embedding_server.py文件使用Flask快速搭建一个本地Embedding服务。# embedding_server.py from flask import Flask, request, jsonify from sentence_transformers import SentenceTransformer import numpy as np import logging app Flask(__name__) logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) # 加载模型 (首次运行会自动从Hugging Face下载) MODEL_NAME BAAI/bge-small-zh-v1.5 logger.info(f正在加载Embedding模型: {MODEL_NAME}...) model SentenceTransformer(MODEL_NAME) logger.info(模型加载完毕。) app.route(/embed, methods[POST]) def embed_text(): 接收文本列表返回向量列表 data request.json if not data or texts not in data: return jsonify({error: 请求体中必须包含 texts 字段文本列表}), 400 texts data[texts] if not isinstance(texts, list): return jsonify({error: texts 必须是一个列表}), 400 try: # 生成向量 embeddings model.encode(texts, normalize_embeddingsTrue) # 归一化便于余弦相似度计算 # 转换为Python列表numpy数组不可JSON序列化 embeddings_list embeddings.tolist() return jsonify({embeddings: embeddings_list}) except Exception as e: logger.error(f生成向量时出错: {e}) return jsonify({error: str(e)}), 500 app.route(/health, methods[GET]) def health_check(): return jsonify({status: healthy}) if __name__ __main__: # 启动服务监听本地5001端口 app.run(host0.0.0.0, port5001, debugFalse)运行这个服务python embedding_server.py服务启动后你可以用curl测试curl -X POST http://localhost:5001/embed \ -H Content-Type: application/json \ -d {texts: [什么是RAG, 监督式微调是什么]}你会收到一个包含两个向量每个向量384维的JSON响应。注意首次运行会从Hugging Face下载模型约100MB请确保网络通畅。生产环境建议提前下载好模型文件并通过环境变量TRANSFORMERS_CACHE指定缓存路径。2.3 准备大语言模型LLM为了流程完整我们同样需要一个LLM。在开发测试阶段你可以选择本地模型如Qwen1.5-1.8B-Chat需要约4GB显存。使用transformers库加载。云端API如OpenAI GPT、DeepSeek等需要网络和API Key。本文为简化流程先使用一个本地模拟的LLMFakeListLLM来验证RAG链路后续在SFT部分再使用真实的本地模型。这能帮你把关注点先放在RAG流程本身。在项目根目录创建llm_mock.py# llm_mock.py from langchain.llms.base import LLM from typing import Any, List, Optional, Dict from langchain.callbacks.manager import CallbackManagerForLLMRun class MockLLM(LLM): 一个模拟的LLM总是返回固定的答案用于测试RAG流程是否通畅。 property def _llm_type(self) - str: return mock def _call( self, prompt: str, stop: Optional[List[str]] None, run_manager: Optional[CallbackManagerForLLMRun] None, **kwargs: Any, ) - str: # 简单检查prompt中是否包含检索到的上下文 if 根据以下上下文 in prompt: return 这是一个基于模拟LLM和RAG流程生成的测试答案。上下文已成功传入。 else: return 这是一个模拟LLM的直接回复。 property def _identifying_params(self) - Dict[str, Any]: return {model_type: mock}3. 构建完整的RAG系统从文档到答案现在我们将利用部署好的Embedding服务和LangChain构建一个完整的RAG问答管道。3.1 项目结构与文档加载创建以下目录结构rag-to-sft-project/ ├── data/ # 存放原始文档PDF、TXT等 ├── vector_db/ # Chroma向量数据库持久化目录 ├── embedding_server.py ├── llm_mock.py └── rag_pipeline.py # RAG主流程在data/目录下放入你的测试文档例如一份名为company_handbook.pdf的公司手册。我们创建一个示例文本文件sample.txt作为演示公司技术栈规范 后端主要使用Java (Spring Boot) 和 Python (FastAPI)。 数据库使用MySQL和Redis。 代码仓库使用GitLabCI/CD采用Jenkins。 项目上线必须经过单元测试、集成测试和代码评审。3.2 实现RAG管道创建rag_pipeline.py实现从文档加载、切分、向量化、存储到检索问答的全流程。# rag_pipeline.py import os from typing import List from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import TextLoader from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from llm_mock import MockLLM # 导入我们模拟的LLM class RAGPipeline: def __init__(self, data_dir: str ./data, persist_dir: str ./vector_db/chroma_db): self.data_dir data_dir self.persist_dir persist_dir self.vectorstore None self.qa_chain None # 1. 初始化Embedding模型连接本地服务 # 注意这里我们直接使用sentence-transformers避免HTTP调用更稳定。 # 如果你需要分布式部署可以将上一节的HTTP服务封装成CustomEmbeddings。 self.embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-small-zh-v1.5, model_kwargs{device: cpu}, # 如果没有GPU使用cpu encode_kwargs{normalize_embeddings: True} ) # 2. 初始化文本分割器 self.text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符数保持上下文连贯 separators[\n\n, \n, 。, , , , , , ] # 中文友好的分隔符 ) def load_and_split_documents(self) - List: 加载并分割文档 documents [] for filename in os.listdir(self.data_dir): file_path os.path.join(self.data_dir, filename) if filename.endswith(.txt): loader TextLoader(file_path, encodingutf-8) docs loader.load() documents.extend(docs) # 可以扩展支持PDF、Word等格式 # elif filename.endswith(.pdf): # from langchain_community.document_loaders import PyPDFLoader # loader PyPDFLoader(file_path) # docs loader.load() # documents.extend(docs) if not documents: raise ValueError(f在 {self.data_dir} 目录下未找到支持的文档。) print(f已加载 {len(documents)} 个原始文档。) # 分割文档 split_docs self.text_splitter.split_documents(documents) print(f分割后得到 {len(split_docs)} 个文本块。) return split_docs def create_vectorstore(self, split_docs: List): 创建并持久化向量存储 print(正在创建向量存储...) self.vectorstore Chroma.from_documents( documentssplit_docs, embeddingself.embeddings, persist_directoryself.persist_dir ) self.vectorstore.persist() print(f向量存储已创建并保存至 {self.persist_dir}) def load_existing_vectorstore(self): 加载已存在的向量存储 if os.path.exists(self.persist_dir) and os.listdir(self.persist_dir): print(加载已存在的向量存储...) self.vectorstore Chroma( persist_directoryself.persist_dir, embedding_functionself.embeddings ) return True return False def init_qa_chain(self): 初始化QA链 if self.vectorstore is None: raise ValueError(请先创建或加载向量存储。) # 定义自定义提示词模板明确要求模型基于上下文回答 prompt_template 请根据以下上下文信息回答问题。如果上下文信息不足以回答问题请直接说“根据提供的信息无法回答此问题”不要编造信息。 上下文 {context} 问题{question} 答案 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 初始化检索器设置相似度检索的top_k retriever self.vectorstore.as_retriever(search_kwargs{k: 3}) # 初始化LLM (这里使用模拟LLM后续可替换) llm MockLLM() # 创建RetrievalQA链 self.qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将检索到的所有文档“堆叠”进上下文 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回源文档便于追溯 ) print(QA链初始化完成。) def ask(self, question: str) - dict: 提问并获取答案 if self.qa_chain is None: self.init_qa_chain() result self.qa_chain({query: question}) return { question: question, answer: result[result], source_documents: result.get(source_documents, []) } def main(): pipeline RAGPipeline() # 检查是否已有向量存储没有则创建 if not pipeline.load_existing_vectorstore(): print(未找到现有向量存储开始处理文档...) split_docs pipeline.load_and_split_documents() pipeline.create_vectorstore(split_docs) else: print(成功加载现有向量存储。) # 初始化QA链 pipeline.init_qa_chain() # 测试问答 test_questions [ 公司后端主要使用什么技术, 上线流程需要哪些步骤, 什么是Python # 这个问题在上下文中没有直接答案 ] for q in test_questions: print(f\n问题{q}) result pipeline.ask(q) print(f答案{result[answer]}) if result[source_documents]: print(参考来源) for i, doc in enumerate(result[source_documents][:2]): # 显示前两个来源 print(f [{i1}] {doc.page_content[:150]}...) # 截取片段 if __name__ __main__: main()运行这个脚本python rag_pipeline.py预期输出未找到现有向量存储开始处理文档... 已加载 1 个原始文档。 分割后得到 X 个文本块。 正在创建向量存储... 向量存储已创建并保存至 ./vector_db/chroma_db QA链初始化完成。 问题公司后端主要使用什么技术 答案这是一个基于模拟LLM和RAG流程生成的测试答案。上下文已成功传入。 参考来源 [1] 公司技术栈规范后端主要使用Java (Spring Boot) 和 Python (FastAPI)。数据库使用MySQL和Redis。代码仓库使用GitLabCI/CD采用Jenkins... ...至此一个本地的、可运行的RAG系统就搭建完成了。它完成了文档加载、智能切分、向量化存储和检索问答的完整闭环。4. 从RAG到SFT数据准备与模型微调实战RAG系统运行后我们会积累大量用户查询以及系统生成的答案或人工修正后的答案。这些数据是进行SFT的宝贵原料。接下来我们演示如何利用这些数据对一个轻量级开源模型进行微调。4.1 准备SFT训练数据格式SFT通常需要指令-回答对格式的数据。假设我们从RAG日志中整理出如下数据保存为data/sft_train_data.jsonl每行一个JSON对象。{instruction: 公司后端主要使用什么技术, output: 公司后端主要使用JavaSpring Boot框架和PythonFastAPI框架。} {instruction: 项目上线必须经过哪些流程, output: 项目上线必须经过单元测试、集成测试和代码评审这三个关键步骤。} {instruction: 我们使用什么工具进行代码版本管理, output: 代码版本管理使用GitLab。} {instruction: 缓存数据库用的是哪个, output: 缓存数据库使用的是Redis。}关键点SFT数据的质量至关重要。指令应清晰、多样输出应准确、完整、符合期望的风格如正式、简洁。可以从RAG的成功问答、人工客服日志、产品文档QA章节中提炼。4.2 选择微调方法与模型对于资源有限的场景LoRALow-Rank Adaptation是首选的微调方法。它只训练模型的一小部分参数低秩矩阵却能取得接近全参数微调的效果极大节省了显存和训练时间。我们选择Qwen1.5-1.8B-Chat作为基座模型。它是一个1.8B参数的中英文对话模型在消费级GPU如RTX 3090/4090上即可进行LoRA微调。安装额外的训练依赖pip install peft0.9.0 # LoRA实现 pip install datasets2.16.1 # 数据处理 pip install trl0.7.10 # Transformer Reinforcement Learning库简化SFT pip install scipy # 可能被依赖4.3 编写微调脚本创建train_sft_lora.py脚本。这是一个简化的训练示例展示了核心流程。# train_sft_lora.py import json from datasets import Dataset from transformers import ( AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForSeq2Seq ) from peft import LoraConfig, get_peft_model, TaskType import torch import os # 1. 加载模型和分词器 MODEL_NAME Qwen/Qwen1.5-1.8B-Chat # Hugging Face模型ID tokenizer AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_codeTrue) # 设置padding token如果模型没有 if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token model AutoModelForCausalLM.from_pretrained( MODEL_NAME, torch_dtypetorch.bfloat16, # 使用BF16节省显存A100/V100等支持 device_mapauto, # 自动分配模型层到GPU/CPU trust_remote_codeTrue ) print(f模型 {MODEL_NAME} 加载完成。) # 2. 加载和预处理数据 def load_data(file_path: str): instructions [] outputs [] with open(file_path, r, encodingutf-8) as f: for line in f: data json.loads(line.strip()) instructions.append(data[instruction]) outputs.append(data[output]) return instructions, outputs train_file ./data/sft_train_data.jsonl instructions, outputs load_data(train_file) # 构建模型需要的对话格式 (Qwen1.5-Chat 格式) def format_chat_prompt(instruction, output): messages [ {role: system, content: 你是一个专业的企业知识问答助手。}, {role: user, content: instruction}, {role: assistant, content: output} ] # 使用tokenizer的apply_chat_template方法格式化 text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptFalse # 训练时不需要生成提示 ) return text texts [format_chat_prompt(i, o) for i, o in zip(instructions, outputs)] # 创建Dataset dataset Dataset.from_dict({text: texts}) print(f训练数据量{len(dataset)}) # 3. Tokenization def tokenize_function(examples): return tokenizer( examples[text], truncationTrue, paddingmax_length, max_length512 # 根据你的数据调整不要超过模型最大长度 ) tokenized_dataset dataset.map(tokenize_function, batchedTrue) # 4. 配置LoRA lora_config LoraConfig( task_typeTaskType.CAUSAL_LM, # 因果语言模型任务 r8, # LoRA秩影响参数量通常8-32 lora_alpha32, # 缩放参数 lora_dropout0.1, # Dropout概率 target_modules[q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj] # 针对Qwen的注意力层和前馈层 ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 打印可训练参数量应该只占原模型很小一部分 # 5. 配置训练参数 training_args TrainingArguments( output_dir./output/qwen1.5-1.8b-sft-lora, # 输出目录 num_train_epochs3, # 训练轮数 per_device_train_batch_size2, # 根据GPU显存调整 (RTX 3090 24G 可设为4-8) gradient_accumulation_steps4, # 梯度累积模拟更大batch size warmup_steps50, # 预热步数 logging_steps10, save_steps100, evaluation_strategyno, # 本例无验证集 save_total_limit2, learning_rate2e-4, # LoRA常用学习率 fp16False, # 如果使用BF16这里关闭FP16 bf16torch.cuda.is_bf16_supported(), # 如果硬件支持BF16则开启 gradient_checkpointingTrue, # 使用梯度检查点节省显存 remove_unused_columnsFalse, push_to_hubFalse, # 不上传到Hugging Face Hub report_tonone, # 不报告到wandb等 ) # 6. 初始化Trainer并开始训练 trainer Trainer( modelmodel, argstraining_args, train_datasettokenized_dataset, data_collatorDataCollatorForSeq2Seq( tokenizertokenizer, paddingTrue, return_tensorspt ), ) print(开始训练...) trainer.train() print(训练完成) # 7. 保存LoRA权重和适配器配置 model.save_pretrained(./output/qwen1.5-1.8b-sft-lora-adapter) tokenizer.save_pretrained(./output/qwen1.5-1.8b-sft-lora-adapter) print(LoRA适配器已保存。)运行训练脚本确保有足够的GPU显存CUDA_VISIBLE_DEVICES0 python train_sft_lora.py4.4 加载并使用微调后的模型训练完成后你会得到LoRA适配器权重。加载并使用微调后模型的代码如下# load_finetuned_model.py from transformers import AutoTokenizer, AutoModelForCausalLM from peft import PeftModel import torch base_model_name Qwen/Qwen1.5-1.8B-Chat lora_adapter_path ./output/qwen1.5-1.8b-sft-lora-adapter # 加载基座模型和分词器 tokenizer AutoTokenizer.from_pretrained(base_model_name, trust_remote_codeTrue) base_model AutoModelForCausalLM.from_pretrained( base_model_name, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue ) # 加载LoRA适配器并合并到基座模型 model PeftModel.from_pretrained(base_model, lora_adapter_path) model model.merge_and_unload() # 合并适配器到原模型便于后续推理 model.eval() # 使用微调后的模型进行推理 def ask_finetuned_model(question): messages [ {role: system, content: 你是一个专业的企业知识问答助手。}, {role: user, content: question} ] text tokenizer.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue) inputs tokenizer(text, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate( **inputs, max_new_tokens256, do_sampleTrue, temperature0.7, top_p0.9 ) response tokenizer.decode(outputs[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue) return response # 测试 test_questions [公司后端主要使用什么技术, 我们使用什么工具进行代码版本管理] for q in test_questions: answer ask_finetuned_model(q) print(f问题{q}\n答案{answer}\n{-*40})现在你得到了一个内化了特定企业知识的轻量级模型。它可以独立、快速地回答训练数据覆盖范围内的问题无需检索外部文档。5. 关键配置解析、常见问题与生产建议5.1 RAG 关键配置与调优文本切分策略chunk_size通常设置在200-1000字符之间。太小会丢失上下文太大会超出LLM窗口限制且检索不精准。chunk_overlap设置50-150字符的重叠可以避免在句子中间被切断。separators针对中文需要调整分隔符列表优先按段落、句子切分。Embedding 模型选择中文场景BAAI/bge-*系列是当前主流选择如bge-large-zh-v1.5效果更好但更慢。多语言场景可考虑intfloat/multilingual-e5-large。生产部署可将Embedding模型封装为gRPC/HTTP服务并添加缓存、批处理、负载均衡。向量数据库选型开发/轻量生产ChromaDB足够简单。大规模生产考虑Milvus、Qdrant、Weaviate或PGVector如果已用PostgreSQL。它们支持分布式、持久化、高级过滤和更好的性能。检索策略相似度搜索最常用基于余弦相似度或点积。混合搜索结合关键词搜索如BM25和向量搜索提升召回率。重排序先用向量检索出大量候选如top 50再用一个更精细的模型或规则重新排序选出top 3给LLM。5.2 SFT (LoRA) 关键参数解析参数含义典型值/建议影响r(秩)LoRA矩阵的秩决定可训练参数量。8, 16, 32值越大能力越强但可能过拟合训练更慢。通常从8开始尝试。lora_alphaLoRA缩放参数。16, 32与学习率相关。通常设为r的2-4倍。lora_dropoutLoRA层的Dropout率。0.05, 0.1防止过拟合。数据少时可适当调高。target_modules将LoRA应用到哪些原模型层。[q_proj,v_proj]等最常用的是注意力层的Q、V矩阵。不同模型结构名称不同需查阅文档。learning_rate学习率。1e-4 到 5e-4LoRA学习率通常比全参微调大如2e-4。per_device_train_batch_size每个GPU的批次大小。根据显存调整RTX 3090 (24G) 对Qwen1.5-1.8B可设4-8。gradient_accumulation_steps梯度累积步数。2, 4, 8有效批次大小 batch_size * accumulation_steps。用于在显存不足时模拟大batch。max_length输入序列最大长度。512, 1024, 2048根据数据中最长样本设置不宜过长以免浪费计算和显存。5.3 常见问题排查RAG 相关问题问题现象可能原因检查与解决答案与文档无关胡编乱造1. 检索到的上下文不相关。2. LLM忽略了上下文。1. 检查Embedding模型是否匹配语种检查切分是否合理尝试调整检索的k值或使用重排序。2. 强化提示词使用更明确的指令如“必须依据上下文回答”。答案不完整截断了1. LLM的max_tokens设置过小。2. 上下文太长挤占了答案空间。1. 调大生成时的max_new_tokens参数。2. 减少检索的k值或chunk_size或使用map_reduce等链式类型处理长上下文。检索速度慢1. 向量数据库未索引或数据量大。2. Embedding模型推理慢。1. 确认向量库创建了索引如HNSW。对Chroma确保使用persist_directory持久化后后续加载会快很多。2. 考虑使用更小的Embedding模型或对Embedding服务进行批处理。新增文档后检索不到向量数据库未更新。确保调用了add_documents或from_documents并persist()。对于增量更新使用vectorstore.add_documents(new_docs)。SFT 相关问题问题现象可能原因检查与解决训练损失不下降1. 学习率太高或太低。2. 数据格式错误。3. 模型冻结了不该冻结的层。1. 尝试经典值如2e-4, 1e-4。2. 检查apply_chat_template后的文本格式确保与模型预训练格式一致。3. 检查target_modules是否正确用model.print_trainable_parameters()确认有参数可训练。训练后模型输出乱码或重复1. 过拟合。2. 数据量太少、质量差。3. 生成参数不当。1. 增加数据量使用Dropout减少训练轮数或r值。2. 严格清洗数据确保问答对高质量。3. 调整生成时的temperature降低和repetition_penalty增加。显存不足OOM1.batch_size太大。2.max_length太长。3. 未使用梯度检查点或量化。1. 减小per_device_train_batch_size增加gradient_accumulation_steps。2. 减小max_length或对长文本进行截断。3. 开启gradient_checkpointingTrue。考虑使用bitsandbytes进行4/8比特量化加载模型。5.4 生产环境最佳实践RAG 生产化服务化将RAG管道封装为API服务如FastAPI并添加认证、限流、监控。缓存对频繁的相同或相似查询缓存最终答案或检索到的上下文向量。可观测性记录用户问题、检索到的文档、生成的答案、耗时用于效果分析和迭代。评估定期使用测试集评估检索精度Recallk和答案质量通过LLM-as-a-Judge或人工评估。SFT 生产化数据闭环将RAG服务中的用户反馈点赞/点踩和人工修正持续回流到SFT训练数据集。渐进式训练不要一次性用所有数据训练。采用课程学习或增量学习逐步加入新数据。模型评估训练后必须在独立的验证集上评估不仅看损失更要看生成答案的准确性、相关性和流畅性。可以使用Rouge、BLEU或GPT-4作为评判员。安全与合规对微调后的模型进行内容安全过滤测试防止产生有害输出。混合部署策略路由机制构建一个路由层根据问题类型决定走RAG路径还是SFT路径。例如事实性、实时性问题走RAG流程性、风格化问题走SFT。SFT作为RAG的增强用SFT微调一个“重排序模型”或“答案润色模型”对RAG检索出的粗答案进行优化。从RAG到SFT是一个从快速验证到深度优化的自然演进过程。RAG帮你低成本地验证知识注入的需求和可行性并在此过程中积累宝贵的训练数据。SFT则利用这些数据打造一个更专、更快、更可控的私有化模型。在实际项目中两者并非替代关系而是互补的利器。建议团队先从RAG入手快速构建MVP并收集数据待数据质量和业务价值明确后再针对核心场景开展SFT最终形成混合智能的稳定服务。
返回列表