news 2026/8/26 10:38:24

Qwen3.5实战:微调、RAG与Agent的完整落地链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qwen3.5实战:微调、RAG与Agent的完整落地链路

最近不少读者在准备大模型应用落地时,都会遇到同一类问题:模型微调怎么跑通?Prompt 怎么写才稳定?RAG 知识库为什么总答非所问?Agent 一接工具就报错?网上资料很多,但大多是零散片段,串不起一条完整链路。这篇文章把“大模型入门到项目落地”最关心的六块内容——Prompt 工程、ReAct 模式、RAG 检索增强、Agent 开发、QAT 量化、Harness 评估——整合成一份微调实战过程笔记。无论你是刚接触大模型的新手,还是已经在做应用层开发的工程师,都能按章节找到可直接复用的代码和排查思路。

为了便于理解,这里以 Qwen3.5 开源模型为主线,结合 LoRA/QLoRA 微调、Ollama 推理、向量检索、Agent 工具调用几大模块,演示一条从模型微调到应用部署的完整闭环。需要说明的是,Qwen3.5 在不同版本的官方仓库、第三方 GGUF 仓库中可能存在差异,文中示例以常见开源环境为主,具体路径和参数要按你实际拉到的模型版本做调整。

1. 背景与核心概念

1.1 为什么突然都在聊“微调 + RAG + Agent”

过去一年里,大模型的能力边界不断被扩展,但企业项目落地时很快会发现两个问题。

第一个问题是通用模型不够“懂业务”。基座模型虽然在预训练时学习了海量语料,但你问它“我们公司内部审批流程是什么”“某个私有协议怎么解析”,它大概率只能给出泛泛而谈的答案。要让模型贴合特定领域术语、输出格式、交互风格,就需要在开源基座模型上做微调。

第二个问题是模型“记忆”不够新、不够准。基座模型的训练数据有截止时间,面对实时数据、私有文档、最新规范,模型无法给出可靠答案。于是 RAG(检索增强生成)成为主流方案:先从知识库中检索出相关片段,再把这些片段作为上下文交给模型回答。微调负责改变模型的“行为习惯”,RAG 负责补足“最新事实”。

而 Agent 解决的是“大模型不能主动做事”的问题。语言模型本身只能生成文本,但通过 ReAct 模式,模型可以输出“思考过程 + 工具调用”,由代码解析这些输出并真正执行函数调用,再把结果回传给模型继续推理。这样大模型就从“聊天机器人”变成了“能操作的助手”。

1.2 本文涉及的技术栈关系

用一条链路来概括:

原始数据 -> 文本清洗 -> Prompt 构造 -> Qwen3.5 基座模型 -> LoRA/QLoRA 微调 -> 导出/合并权重 -> Ollama 或 vLLM 部署 -> 接入 RAG 知识库(向量检索) -> 构建 Agent(ReAct 模式 + 工具调用) -> Harness 评估 -> QAT 量化压缩 -> 上线

每个环节都有独立的知识体系,但生产项目里它们是环环相扣的。所谓“三天速通”,不是三天把所有细节都挖透,而是先建立起这条主线的完整认知,每个环节先跑通最小可运行版本,再逐步深入。

1.3 常见概念区分

  • Prompt 工程:通过设计输入文本,引导模型输出符合预期的结果。它不改变模型权重。
  • 微调(Fine-tuning):在基座模型基础上,用标注数据继续训练,改变模型权重,让模型学会特定风格或能力。
  • RAG:在推理阶段引入外部检索结果,让模型基于检索到的内容回答。不改变模型权重。
  • Agent:让模型能够调用外部工具,获取新信息或执行操作,核心是“模型决策 + 工具执行”的循环。
  • QAT(量化感知训练):在训练阶段模拟量化误差,让模型权重适应低比特表示,从而减少推理时精度损失。
  • Harness:这里指大模型评估框架(如 lm-evaluation-harness),用于在标准数据集上评估模型的准确率、困惑度等指标。

明白这些区别之后,后面每章的实操就不会混淆了。

2. 环境准备与版本说明

2.1 硬件与运行环境

大模型微调和推理对硬件要求较高,尤其显存是关键瓶颈。以 Qwen3.5 系列的 7B~9B 量级模型为例:

  • 纯 CPU 推理可以跑,但速度较慢,适合验证流程。
  • 4bit 量化推理建议 8GB 以上显存。
  • QLoRA 微调 7B~9B 模型,建议 16GB 以上显存;如果使用 LoRA 并且开启梯度检查点,有条件可以压到更低。
  • 全参数微调 7B 以上模型,建议多卡 A100 或 H100,普通开发者不推荐轻易尝试。

整体环境版本如下,具体以你的实际项目为准:

组件版本建议说明
操作系统Ubuntu 20.04 / 22.04,Windows WSL2 也可Linux 下 CUDA 生态最顺
Python3.10 / 3.11兼容最新 PyTorch 与 Transformers
CUDA11.8 / 12.1根据显卡驱动选择
PyTorch2.1 及以上量化、训练算子更稳
Transformers4.40 及以上具体版本看模型官方要求
PEFT0.10 及以上LoRA/QLoRA 训练
TRL0.8 及以上SFT 训练器
Datasets2.16 及以上数据集加载处理
vLLM / Ollama最新稳定版推理服务部署
LanceDB / Chroma / FAISS按需选择向量检索

这里特别提醒:不要盲目追最新版本。很多报错的根源是 transformers、peft、trl 三者版本不匹配。建议先固定一套组合,跑通后再升级。

2.2 推荐项目结构

为了后期维护方便,建议按下面结构组织项目目录。

qwen3-finetune-project/ ├── data/ # 原始数据与处理脚本 │ ├── raw/ # 原始 JSON/JSONL 数据 │ └── processed/ # 处理后的训练集、验证集 ├── scripts/ │ ├── prepare_data.py # 数据清洗与格式化 │ ├── train_lora.py # LoRA/QLoRA 微调 │ ├── merge_weights.py # 合并 LoRA 权重 │ ├── build_rag.py # 构建 RAG 向量库 │ ├── run_agent.py # Agent 主程序 │ └── evaluate_harness.py # 模型评估 ├── models/ # 模型权重 ├── logs/ # 训练日志与评估结果 └── configs/ # 配置文件

2.3 拉取模型与国内访问优化

使用 Ollama 拉取 Qwen3.5 模型时,常见的命令是:

ollama pull qwen3.5:9b

如果遇到网络下载慢或超时,可以先检查网络连接,再考虑配置环境变量或切换为国内可访问的镜像源。需要提醒的是,这里只讨论网络源配置,不涉及任何代理工具。部分第三方用户上传的 GGUF 模型(例如社区命名的 uncensored 版本)来源不明,可能存在数据投毒或安全后门,不建议在生产环境使用。请优先从模型官方仓库或可信渠道下载。

下载完成后,通过 Ollama 快速验证模型是否可用:

ollama run qwen3.5:9b "你好,请介绍一下你自己"

能看到正常回复,说明模型基础推理没问题。

3. Prompt 工程与 ReAct 模式

3.1 Prompt 的基本结构

Prompt 是与模型交互的输入文本,它的质量直接决定输出质量。一个工程化的 Prompt 通常包含四部分:

  1. 系统角色:告诉模型你是谁、你的职责、输出风格。
  2. 任务描述:明确要完成的任务。
  3. 上下文信息:背景资料、文档片段、历史对话。
  4. 输出约束:格式要求、长度限制、禁止事项。

下面是一个典型的系统 Prompt 示例:

system_prompt = """你是一名专业的技术文档助手,擅长把复杂技术概念讲清楚。 你的任务要求: 1. 根据用户提供的资料回答问题。 2. 如果资料中没有相关信息,直接回答“资料库中没有找到相关内容”,不要编造。 3. 你的回答要分点列出,每个要点不超过 50 字。 4. 使用中文回答,不要使用英文缩写(除专业名词外)。 用户资料: {context} 用户问题: {question} """

这里的关键在于“如果资料中没有相关信息,直接回答没有”——这能显著减少模型的幻觉。

3.2 ReAct:让模型具备推理与行动能力

ReAct 的核心思路是让模型在推理时交替输出 Thought(思考)、Action(动作)、Observation(观察)三个字段。

一个典型的 ReAct Prompt 长这样:

你可以使用以下工具: - search_web(query: str): 搜索互联网信息 - get_weather(city: str): 查询城市天气 请按照以下格式回答: Thought: 分析用户问题,决定下一步动作。 Action: 工具名称(参数) Observation: 工具返回结果 最后根据 Observation 给出最终回答。

模型输出如下:

Thought: 用户想知道北京今天的天气,我需要调用天气查询工具。 Action: get_weather("北京") Observation: 晴,25℃,空气质量良。 Thought: 已获取天气信息,可以直接回答。 Answer: 北京今天晴天,气温 25℃,空气质量良。

注意:当前很多开源模型在输出 Action 时会出现格式漂移,比如漏掉括号、把工具名写错。解决办法是在指令数据集中加入大量 ReAct 格式的样本并进行微调,或者在后端解析时做格式化修正。

3.3 Prompt 常见报错与处理

使用 Prompt 时会遇到几种典型的报错,其中与内容安全策略相关的报错尤其常见。

问题现象常见原因解决思路
invalid prompt: your prompt was flagged as potentially violating our usage policy提示词触发了服务端安全策略检查提示词是否包含暴力、违法、违规内容,尝试改写为更中性的表达
prompt is too long ... automatic compaction failed: api error: 400输入 token 数超过了模型上下文窗口,或上下文压缩失败截断历史消息、缩短 Prompt、使用更大上下文窗口模型
Prompt 闪退某些客户端对超长 Prompt 处理崩溃分批输入或限制 Prompt 最大长度
Agent 执行时报错工具参数格式错误、工具返回异常工具注册时做参数校验,异常捕获后返回可读信息

尤其是“invalid prompt”这类报错,很多开发者会误以为是网络问题,实际是提示词触发了安全过滤。你需要先自查提示词内容,而不是反复重试。官方建议参考平台文档中关于 prompt 引导的最佳实践。

4. 基于 Qwen3.5 的 LoRA 微调实战

4.1 为什么要用 LoRA / QLoRA

全参数微调对整个模型所有参数做梯度更新,显存开销巨大。LoRA(Low-Rank Adaptation)的思路是冻结原模型参数,只在 attention 层的权重旁边插入低秩矩阵进行训练。训练完成后,把低秩矩阵与原模型合并,或者单独保存 LoRA 权重。

QLoRA 则进一步引入 4bit 量化基座模型,显著降低显存占用,让普通显卡也能微调大模型。我们的实战选用 QLoRA 方案,数据量控制在几千条,单卡 16GB 显存即可运行。

4.2 准备微调数据

微调数据一般使用对话格式。以 JSONL 为例,每行是一个完整的对话样本:

{"messages": [{"role": "user", "content": "什么是 RAG?"}, {"role": "assistant", "content": "RAG 是检索增强生成,先检索知识库再生成答案。"}]}

训练前要处理数据:去除重复样本、过滤过短样本、检查特殊字符。这里给出一个简单的数据处理脚本:

# 文件路径:scripts/prepare_data.py import json def load_and_filter(input_path, output_path, min_len=10): samples = [] with open(input_path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue obj = json.loads(line) messages = obj.get("messages", []) if len(messages) < 2: continue # 过滤过短样本 content_all = "".join(m["content"] for m in messages) if len(content_all) < min_len: continue samples.append(obj) with open(output_path, "w", encoding="utf-8") as f: for s in samples: f.write(json.dumps(s, ensure_ascii=False) + "\n") print(f"过滤完成, 原始数据 -> 有效数据: {len(samples)} 条")

4.3 编写 QLoRA 训练脚本

下面给出一个基于 Transformers、PEFT、TRL 的 QLoRA 训练核心示例。

# 文件路径:scripts/train_lora.py import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, ) from trl import SFTTrainer from peft import LoraConfig # 模型路径按实际环境修改 model_name = "Qwen/Qwen3.5-9B" # 以官方实际名称/路径为准 # 4bit 量化配置 bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True, ) model = AutoModelForCausalLM.from_pretrained( model_name, quantization_config=bnb_config, device_map="auto", torch_dtype=torch.bfloat16, ) tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token # LoRA 配置 lora_config = LoraConfig( r=8, lora_alpha=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", ) # 训练参数 training_args = TrainingArguments( output_dir="./logs/qwen3_lora", per_device_train_batch_size=1, per_device_eval_batch_size=1, gradient_accumulation_steps=16, learning_rate=2e-4, num_train_epochs=3, logging_steps=50, save_steps=500, eval_strategy="epoch", save_strategy="epoch", bf16=True, gradient_checkpointing=True, ) trainer = SFTTrainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, tokenizer=tokenizer, peft_config=lora_config, dataset_text_field="text", max_seq_length=2048, ) trainer.train() trainer.save_model("./logs/qwen3_lora/final")

几个关键参数说明:

  • gradient_accumulation_steps=16:相当于累积 16 个 batch 后再更新一次参数,可以弥补小 batch 导致的训练不稳定。
  • gradient_checkpointing=True:用计算换显存,训练时能省下不少显存。
  • target_modules需要和模型结构匹配,不同版本的 Qwen 模块名可能不同,如果报错请检查模型 config 中实际存在的层名称。

4.4 合并权重并部署推理

训练完成后,LoRA 权重单独保存在输出目录。为了方便 vLLM、Ollama 这类推理框架直接加载,需要把 LoRA 权重合并回原模型。

# 文件路径:scripts/merge_weights.py from peft import PeftModel from transformers import AutoModelForCausalLM, AutoTokenizer base_model_name = "Qwen/Qwen3.5-9B" # 按实际路径调整 lora_path = "./logs/qwen3_lora/final" output_path = "./models/qwen3.5-9b-lora-merged" model = AutoModelForCausalLM.from_pretrained( base_model_name, torch_dtype="auto", device_map="auto", ) model = PeftModel.from_pretrained(model, lora_path) model = model.merge_and_unload() model.save_pretrained(output_path) tokenizer = AutoTokenizer.from_pretrained(base_model_name) tokenizer.save_pretrained(output_path)

合并完成后,可以先用 Transformers 快速验证微调效果:

from transformers import AutoModelForCausalLM, AutoTokenizer model_path = "./models/qwen3.5-9b-lora-merged" tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, device_map="auto", torch_dtype="auto") prompt = "用户:什么是检索增强生成?\n助手:" inputs = tokenizer(prompt, return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0], skip_special_tokens=True))

如果回复风格、术语明显符合预期,说明微调成功。接下来可以接入 Ollama:

ollama create qwen3.5-finetuned -f ./configs/Modelfile

Modelfile 内容大致如下:

FROM ./models/qwen3.5-9b-lora-merged SYSTEM "你是一个专注于企业内部知识问答的助手,回答要简洁、准确。"

然后启动推理:

ollama run qwen3.5-finetuned "请介绍一下公司的差旅报销流程"

5. RAG 知识库构建与切块策略

5.1 RAG 原理与流程

RAG 并不是一个复杂的模型,而是一条数据流水线:

  1. 把文档切分为多个文本块(chunk)。
  2. 为每个文本块生成向量表示(embedding)并存入向量数据库。
  3. 用户提问时,把问题编码为向量,在向量库中做相似度检索。
  4. 取 Top-K 个相关文本块,连同问题一起组成新的 Prompt。
  5. 模型基于上下文生成最终回答。

一个常见误区是“切块越大越好”。切块太大会引入大量无关信息,降低检索准确率;切块太小会导致语义不完整。切块策略需要根据文档类型和下游任务调优。

5.2 文档切块策略

切块方式适用场景优点缺点
固定长度切块通用文本实现简单、速度最快可能切断完整句子或段落
按段落切块结构清晰的 Markdown/Word 文档语义相对完整长段落仍会超长
滑动窗口切块长文本、需要上下文衔接能保留相邻句子的上下文会产生较多重复块
语义切块新闻、论文、合同语义边界相对合理计算成本较高

实际项目中我常用的策略是:固定长度为主(例如 512 token),重叠 64 token。这样既能控制向量库大小,又能避免句子被硬生生切断。

# 文件路径:scripts/chunk_text.py def chunk_text(text, chunk_size=512, overlap=64): """按 token 近似长度切块,保留重叠区域。""" if len(text) <= chunk_size: return [text] chunks = [] start = 0 while start < len(text): end = start + chunk_size chunk = text[start:end] chunks.append(chunk) if end >= len(text): break start = end - overlap return chunks

5.3 构建向量库并在问答中接入

这里选用轻量级向量数据库,方便本地验证。完整示例使用 LangChain 风格组装。

# 文件路径:scripts/build_rag.py from sentence_transformers import SentenceTransformer import lancedb # 1. 加载 embedding 模型 embed_model = SentenceTransformer("BAAI/bge-small-zh-v1.5") # 2. 准备文本块 texts = [ "公司差旅报销需要提前在系统提交申请。", "报销发票需为合规增值税发票。", "差旅标准:高铁二等座,住宿标准每晚 400 元。", ] embeddings = embed_model.encode(texts).tolist() # 3. 写入向量库 db = lancedb.connect("./data/vector_db") table = db.create_table("company_kb", data=[ {"id": i, "text": t, "vector": embeddings[i]} for i, t in enumerate(texts) ]) print(f"向量库写入完成,共 {table.count()} 条记录")

查询时,把用户问题也变成向量,然后查相似度最高的片段。

query = "高铁能坐几等座?" query_vec = embed_model.encode([query])[0] results = table.search(query_vec).limit(3).to_list() for r in results: print(f"相似度: {r['_distance']:.4f} 文本: {r['text']}")

检索出相关片段后,再把它拼进 Prompt。这与第 3 章的 Prompt 结构衔接起来:

retrieved_text = "\n".join(r["text"] for r in results) final_prompt = f"""基于以下资料回答问题。如果资料中没有答案,请直接说明“资料中未找到”。 资料: {retrieved_text} 问题: {query} """

5.4 RAG 常见的“答非所问”问题

RAG 效果好坏的瓶颈通常不在模型,而在检索环节。遇到“答非所问”时,优先按下面顺序排查:

  1. Embedding 模型是否匹配领域:通用 embedding 对专业术语效果差,可换领域微调的 embedding 模型。
  2. 切块是否切断语义:检查 Top-K 结果,看检索到的片段是不是真正回答了问题。
  3. 向量检索是否需要混合检索:单纯向量检索可能漏掉关键词精确匹配,可以结合 BM25 做混合召回。
  4. Prompt 中上下文是否过多:5 条不相关片段比 1 条相关片段干扰更大,适当降低 Top-K 数值。

6. Agent 开发与工具调用实战

6.1 Agent 的核心循环

Agent 的本质是一个循环过程:

  1. 接收用户任务。
  2. 模型根据 Prompt 和现有信息决定调用哪个工具。
  3. 代码执行工具函数并返回结果。
  4. 模型根据结果决定下一步动作或生成最终答案。

这个循环会在模型输出“最终答案”或达到最大迭代次数时停止。ReAct 模式是其中最常见的实现方式。

6.2 一个最小可用的 ReAct Agent

下面给出一个简化版 Python 实现,它把工具函数注册到字典中,解析模型输出的 Action 字段并执行。

# 文件路径:scripts/run_agent.py import re import json def get_weather(city: str) -> str: """模拟天气查询工具。""" weather_map = {"北京": "晴, 25℃", "上海": "多云, 28℃", "广州": "小雨, 26℃"} return weather_map.get(city, "暂无数据,请检查城市名称。") def search_web(query: str) -> str: """模拟搜索工具。""" return f"关于「{query}」的搜索结果为:示例数据一、示例数据二。" TOOLS = { "get_weather": get_weather, "search_web": search_web, } TOOL_DESCRIPTION = """ 可用工具: - get_weather(city: str): 查询城市天气 - search_web(query: str): 搜索互联网信息 输出格式: Thought: 你的思考 Action: 工具名(参数) Observation: 你观察到的结果 ...(可多轮) Thought: 我已经得到最终答案 Answer: 最终回答 """ def parse_action(text: str): """从模型输出中解析 Action 字段。""" match = re.search(r"Action:\s*(\w+)\((.+)\)", text) if not match: return None, None name, raw_args = match.group(1), match.group(2) try: args = json.loads(f"[{raw_args}]") except json.JSONDecodeError: args = [raw_args.strip().strip("'\"")] return name, args def run_agent(prompt): messages = [ {"role": "system", "content": TOOL_DESCRIPTION}, {"role": "user", "content": prompt}, ] for step in range(5): # 防止死循环,最多迭代 5 轮 response = chat_with_model(messages) # 调用本地模型生成回复 print("模型输出:", response) if "Answer:" in response: return response.split("Answer:")[-1].strip() action_name, args = parse_action(response) if action_name and action_name in TOOLS: result = TOOLS[action_name](*args) messages.append({"role": "assistant", "content": response}) messages.append({"role": "user", "content": f"Observation: {result}"}) else: messages.append({"role": "assistant", "content": response}) messages.append({"role": "user", "content": "请重新输出 Action 或直接给出 Answer。"}) return "达到最大迭代次数,任务结束。"

这里的chat_with_model是你自己对接模型推理的函数,可以调用前面的 Ollama 接口或 vLLM 接口。最关键的是设计“Action 解析失败后如何重试”——这是 Agent 工程中最容易疏漏的地方。

6.3 Agent 常见报错与调试

问题现象常见原因解决思路
agent terminated due to error工具执行抛异常,Agent 循环没有捕获在工具调用外加 try-except,把错误信息作为 Observation 返回
Action 格式一直解析失败模型没有严格遵循 ReAct 格式微调数据中加入大量 ReAct 示例,或后端对输出做正则校正
工具参数总传错模型不知道工具参数类型在工具描述中明确参数类型和示例
进入死循环模型不断重复相同 Action设置最大迭代次数,并检测重复 Action

7. QAT 量化与 Harness 评估

7.1 量化感知训练(QAT)

微调后的模型权重通常占用较大显存,部署到生产环境前需要压缩。量化是常用手段。按量化发生的时间点,可以分成两类:

  • 训练后量化(PTQ):直接对训练好的模型做 INT8/INT4 量化,速度快但精度损失可能较大。
  • 量化感知训练(QAT):在训练或继续训练阶段就模拟量化误差,让模型逐步适应低比特表示,量化后精度损失更小。

QAT 的流程可以概括为:

原模型 -> 插入伪量化节点 -> 使用带量化的前向/反向训练 -> 导出低比特模型

现实中 Qwen 系的 QAT 工作通常依赖专门的量化工具链,不同框架的 API 差异较大,这里不贴死代码。建议在项目中使用前先对照官方量化文档,在验证集上对比量化前后效果。不要盲目追求 4bit,如果任务本身对数字推理、代码生成敏感,精度损失可能不可接受。

7.2 用 Harness 评估模型效果

评估是容易被忽略却至关重要的环节。没有评估,你就无法判断微调到底是变好还是变坏。开源社区常用的评估框架是lm-evaluation-harness

安装方式:

pip install lm-eval

评估命令示例:

lm_eval \ --model hf \ --model_args pretrained=./models/qwen3.5-9b-lora-merged \ --tasks mmlu,ceval-valid \ --batch_size auto \ --output_path ./logs/eval_results

评估时需要注意:

  • 先测基座模型再做对比:不要只评估微调后的模型,要和基座模型在同一批数据集上对比,才能看出提升或退化。
  • 任务要贴合业务:通用榜单(如 MMLU)只反映通用能力,你的场景如果是法律问答,需要额外构造业务评测集。
  • 评估不代表一切:客观指标提升,不代表用户体验变好,建议结合人工抽检。

7.3 线上部署建议

压缩后的模型可以用 vLLM 或者 Ollama 提供服务。Ollama 适合中小规模内部使用,vLLM 适合高并发生产环境。下面是 vLLM 启动示例:

vllm serve ./models/qwen3.5-9b-lora-merged \ --served-model-name qwen3.5-ft \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9

启动后可以通过 OpenAI 兼容接口调用,方便接入 Agent 框架。

8. 常见问题排查清单

最后整理一份高频问题排查表,建议收藏备查。

问题现象常见原因优先排查步骤
训练时报显存不足batch 太大、未开梯度检查点调小 batch、开启 gradient_checkpointing、用 QLoRA
训练损失不下降学习率过大或数据噪声过强先用小批次拟合少量样本,再调整学习率
微调后模型变“笨”了数据分布偏斜或过拟合增加通用数据比例,控制训练轮数
合并权重后推理出错基座模型与 LoRA 版本不匹配确认 LoRA 基座路径完全一致
RAG 检索结果不相关Embedding 模型与领域不匹配换领域 Embedding 模型,或混合检索
Agent 工具调用失败工具解析逻辑太脆弱增加格式校正、异常捕获、重试机制
invalid prompt 报错触发了安全策略改写提示词为中立表达
prompt too long上下文超限减少历史轮数、缩短系统 Prompt
推理速度慢未量化、并发配置低使用 vLLM 并发、考虑量化压缩
评估指标比基座差评测集与微调方向不一致重新审视微调目标,增加通用能力数据

9. 最佳实践与工程建议

9.1 数据质量比模型参数更重要

微调的效果上限往往由数据质量决定。一个几千条高质量样本的 QLoRA,效果可能好过几万条低质量样本的全参数微调。在准备数据时,重点关注:

  • 去重、清洗、格式统一。
  • 多轮对话中要控制 assistant 回答长度,避免过长的样板回答。
  • 覆盖边界场景,例如“我不知道”“资料不足”等拒绝回答的样本。

9.2 安全与合规边界

生产环境里,大模型应用无法回避安全问题。

  • 涉及用户个人数据时,要注意数据合规与脱敏,不要随意把内部文档送入公有云 API。
  • 微调数据中不得包含敏感信息,模型可能通过记忆泄露训练数据。
  • 在 Agent 工具设计中,涉及删除、更新、转账等高风险操作,必须加人工审批或二次确认。
  • 外部工具调用要限制白名单,防止 Prompt 注入导致恶意工具执行。

这里特别想强调:Agent 面临的安全风险比单纯对话更大。如果模型的输入中存在恶意注入指令,它可能调用不在预期范围内的工具。解决办法是在工具注册时做严格的参数校验,并且不要给模型提供“万能执行”类工具。

9.3 版本管理和可复现性

大模型项目迭代很快,但工程上必须讲究可复现:

  • 固定依赖版本,使用requirements.txtconda env export保存环境。
  • 每次训练记录模型路径、数据版本、训练参数、评估结果。
  • 建议使用 WanDB 或本地日志记录训练曲线。
  • LoRA 权重和基座模型分开存储,方便回溯和增量训练。

9.4 推荐的上手路线

如果你是从零开始,不建议一上来就追全参数微调或复杂分布式训练。推荐按下面节奏推进:

  1. 先用 Ollama 跑通 Qwen3.5 的对话。
  2. 在本地写好 Prompt,熟悉输出格式。
  3. 用 QLoRA 做一次小规模微调,掌握训练流程。
  4. 接入 RAG,跑通知识库问答。
  5. 实现一个工具调用 Agent,体验 ReAct 模式。
  6. 最后再考虑 QAT 量化和 Harness 评估。

按这个顺序,每一步都在上一步的基础上扩展,排查问题时也能快速定位到具体环节。

10. 总结

这次实战过程其实可以用一句话概括:聊模型,不只看生成,更要看“训练 — 检索 — 工具 — 评估”整条链路。基于 Qwen3.5 的微调、Prompt 调优、RAG 知识库、Agent 开发、QAT 量化和 Harness 评估,六个环节互相独立又有紧密关联。微调负责优化模型的行为习惯,RAG 补充最新事实,Agent 让模型从“会说话”变成“会办事”,量化降低部署成本,评估保证每次迭代方向正确。建议你先从最小闭环开始:一条数据、一次 QLoRA 微调、一个 RAG 查询、一次工具调用,跑通之后再逐步扩大数据规模和业务复杂度。做任何生产变更前,记得先在测试环境验证,做好备份,守住安全边界。希望这份实战笔记能帮你省去一些摸索时间,少踩几个坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 10:37:08

安卓后台录音权限丢失:前台服务解决方案与实战指南

1. 项目概述&#xff1a;安卓后台麦克风权限丢失的“幽灵”问题最近在做一个需要后台录音的安卓应用时&#xff0c;踩了一个大坑&#xff1a;应用在前台时&#xff0c;麦克风权限工作得稳稳当当&#xff0c;录音清晰流畅&#xff1b;可一旦把应用切到后台&#xff0c;或者锁屏&…

作者头像 李华
网站建设 2026/8/26 10:30:56

I2C协议从硬件连接到软件调试的实战指南

1. 项目概述&#xff1a;为什么I2C如此重要且“难缠”&#xff1f;如果你玩过单片机或者嵌入式开发&#xff0c;肯定对I2C这个名字不陌生。它和SPI、UART一起&#xff0c;被称为嵌入式世界的“三巨头”通信协议。但和UART的简单直接、SPI的高速霸道不同&#xff0c;I2C以其独特…

作者头像 李华
网站建设 2026/8/26 10:29:34

基于Codex Skill的科研论文写作自动化:从空目录到可投稿初稿

最近用 Codex 跑科研论文流程的人明显变多了。原因不复杂&#xff1a;Codex 这类智能体工具能一口气完成文献整理、论文框架、初稿撰写、润色、参考文献格式化和投稿信起草&#xff0c;而这些工作过去至少占掉论文投稿前一周的时间。这篇文章不讨论概念&#xff0c;直接给你一套…

作者头像 李华
网站建设 2026/8/26 10:28:07

Grok API高频定时任务用量控制与限流重试实践

如果你准备把 Grok API 接到定时任务里&#xff0c;比如每 5 分钟跑一次文本分类、摘要生成、标签补全&#xff0c;那我建议先停下来想一个问题&#xff1a;用量控制。Grok 这类大模型接口通常按调用和 token 计算使用量&#xff0c;一个看起来很简单的高频任务&#xff0c;跑上…

作者头像 李华
网站建设 2026/8/26 10:28:03

AI Agent规模化落地:Token成本与延迟挑战下的基础设施优化方案

1. 项目概述&#xff1a;当AI的“燃料”与“引擎”面临物流瓶颈最近在折腾几个AI Agent项目时&#xff0c;我被一个看似不起眼、实则要命的问题卡住了脖子&#xff1a;Token消耗速度远超预期&#xff0c;成本像坐上了火箭。这让我想起一个经典的比喻&#xff1a;你造了一台性能…

作者头像 李华
网站建设 2026/8/26 10:27:17

腾讯云视频内容安全方案评测:3步接入与15天免费试用实战

1. 项目概述&#xff1a;为什么我们需要一个“快上手”的视频内容安全方案&#xff1f; 最近在对接几个内容平台项目时&#xff0c;我被一个老生常谈但又极其关键的问题绊住了脚&#xff1a;视频内容安全审核。无论是UGC社区、在线教育还是电商直播&#xff0c;只要涉及用户上传…

作者头像 李华