诸葛无用 · 技术报告
基于 Qwen3-32B 全流程微调的个人 AI 助手
Kiro 自动整理
🏗️ 系统架构
┌─────────────────────────────────────────────────────────────────┐
│ 用户浏览器 │
│ shenyuyang.site (HTTPS) │
└──────────────────────────┬──────────────────────────────────────┘
│ Nginx reverse proxy
▼
┌──────────────────────────────────────────────────────────────────┐
│ 云服务器 · Nginx + SSL + frp │
└──────────────────────────┬───────────────────────────────────────┘
│ frp TCP tunnel
▼
┌──────────────────────────────────────────────────────────────────┐
│ 本地 GPU 服务器 │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ Flask App │──▶│ vLLM Server │──▶│ Qwen3-32B-AWQ │ │
│ │ + RAG 检索 │ │ OpenAI API │ │ W4A16 量化模型 │ │
│ └─────────────┘ └──────────────┘ └───────────────────────┘ │
│ ┌─────────────┐ │
│ │ BGE-small-zh│ FAISS 向量检索 │
│ │ Embedding │ 知识库 → system prompt │
│ └─────────────┘ │
└──────────────────────────────────────────────────────────────────┘
⚙️ 技术栈总览
| 层级 | 技术 | 说明 |
|---|---|---|
| 基座模型 | Qwen3-32B | 32.8B 参数,通义千问团队 |
| 微调方法 | QLoRA | NF4 + LoRA r=16, α=32 |
| 对齐训练 | DPO | Direct Preference Optimization, β=0.3 |
| 模型合并 | PEFT merge_and_unload | 多阶段 LoRA 逐层融合 |
| 量化 | AWQ W4A16 | llm-compressor, ~64GB → ~18GB |
| 推理引擎 | vLLM | OpenAI-compatible API, SSE streaming |
| 知识检索 | RAG | FAISS + BGE-small-zh-v1.5 |
| Web 框架 | Flask | SSE streaming + IP 限流 |
| 反向代理 | Nginx + Let's Encrypt | SSL 自动续签 + frp 内网穿透 |
| 硬件 | 2× NVIDIA RTX A6000 | 48GB VRAM × 2, 训练推理分卡 |
🔄 训练流程
整个 post-training 分为三个阶段,每个阶段产出一个 LoRA adapter,逐层融合进基座模型。训练使用纯 PyTorch 手动训练循环(绕开 HuggingFace Trainer 在双卡 NF4 场景下的 NaN 问题)。标签掩码:prompt 部分设为 -100,仅对 assistant 回复计算 cross-entropy loss。
1
Identity SFT — 身份认知
86 条手写身份问答 + 29 条个人信息,过采样至 ~1,720 条 · lr=2e-4 · 3 epochs
↓ merge LoRA into base
2
Style SFT — 微信聊天风格
真实微信聊天记录处理,按回复质量取 top 65%,混入身份数据防遗忘 · lr=1e-4
↓ merge LoRA into base
3
DPO — 偏好对齐
303 条偏好 pair(身份/反幻觉/安全/风格 + TruthfulQA)· β=0.3 · lr=2e-5 · 1 epoch
↓ merge LoRA into base
4
AWQ 量化 — W4A16
llm-compressor, 8 条中文校准样本,~64GB → ~18GB,单卡推理
↓ deploy
5
vLLM 部署 + Flask Web
OpenAI-compatible API · SSE streaming · RAG 知识检索 · frp 内网穿透
🎯 SFT 训练配置
| 参数 | Stage 1: Identity | Stage 2: Style |
|---|---|---|
| LoRA r / α | 16 / 32 | 16 / 32 |
| target_modules | q/k/v/o/gate/up/down_proj | |
| learning_rate | 2e-4 | 1e-4 |
| epochs | 3 | 3 |
| batch_size | 16, grad_accum=2 | |
| max_seq_length | 512 | |
| optimizer | PagedAdamW8bit | |
| scheduler | cosine with warmup | |
| 量化 | NF4 + double quant | |
| 精度 | bfloat16 | |
⚖️ DPO 偏好对齐
DPO (Direct Preference Optimization) 跳过传统 RLHF 中显式训练 reward model 和 PPO 优化的步骤,直接从偏好数据学习。训练开始时 policy 和 reference 完全相同,随着 LoRA 参数更新,policy 逐渐偏好 chosen、远离 rejected,但 KL 约束防止偏离太远。
// DPO Loss L_DPO = -log(σ(β · [(log π(chosen) - log π_ref(chosen)) - (log π(rejected) - log π_ref(rejected))]))
| 类别 | 数量 | 过采样 | 说明 |
|---|---|---|---|
| 身份认知 pair | 13 | ×3 | chosen=正确身份 vs rejected=错误身份 |
| 反幻觉 pair | 18 | ×3 | chosen=拒绝/说不知道 vs rejected=编造信息 |
| 安全/隐私 pair | 15 | ×2 | chosen=拒绝泄露 vs rejected=泄露隐私 |
| 风格偏好 pair | 15 | ×2 | chosen=自然口语 vs rejected=机械AI腔 |
| TruthfulQA | 150 | ×1 | 开源数据集,通用诚实性 |
| 总计 | 303 |
🔍 RAG 知识检索
使用 FAISS + BGE-small-zh-v1.5 构建向量索引。6 个 Markdown 知识文件各自作为一个 chunk(避免切碎丢失上下文)。查询时 top-5 检索,相似度阈值 ≥0.35 过滤后拼入 system prompt。涉及沈宇阳的事实性问题使用低温 (0.05) 减少幻觉,其他问题使用 0.5。
# 检索流程 用户提问 → BGE embedding → FAISS top-5 检索 → 相似度阈值过滤 (≥0.35) → 命中的 chunk 拼入 system prompt 的【参考资料】部分 → 如果涉及沈宇阳但无检索结果,追加"记忆不可靠"提醒
| 组件 | 技术 | 说明 |
|---|---|---|
| Embedding | BGE-small-zh-v1.5 | 512 维中文语义向量,BAAI 出品 |
| 向量索引 | FAISS IndexFlatIP | 内积相似度(embedding 已归一化) |
| 知识库 | 6 × Markdown | 简历、论文、实习、研究、技能、项目 |
📊 自动化评测
自建 5 维度评测系统,覆盖模型核心能力指标,支持 baseline 对比、阈值检查和 Slack 通知。
身份准确率
≥ 95%
关键词匹配
事实准确率
≥ 90%
学校/论文/实习
幻觉率
≤ 10%
逆指标,越低越好
安全拒绝率
≥ 95%
隐私/注入/越狱
风格评分
≥ 70%
长度分 - 机械表达惩罚
🛡️ System Prompt 工程
System prompt 是模型行为的核心控制层,包含身份定义、核心事实锚定(硬编码学位/论文/实习等防止篡改)、反幻觉规则(最高优先级,只基于参考资料回答)、隐私保护、安全规则(拒绝 prompt injection)和行为准则。配合 RAG 检索结果动态拼接。
🚀 部署架构
本地 GPU 服务器通过 frp 内网穿透连接云服务器,Nginx 反向代理提供 HTTPS 访问。vLLM 和 Flask 分别处理推理和 RAG 检索。训练和推理分卡运行,互不干扰。
# vLLM 启动示例
python3 -m vllm.entrypoints.openai.api_server \
--model <merged-awq-model-path> \
--quantization compressed-tensors \
--dtype half \
--max-model-len 4096 \
--served-model-name zhuge-wuyong
| 组件 | 说明 |
|---|---|
| 内网穿透 | frp (frpc → frps) |
| 反向代理 | Nginx, proxy_buffering off (SSE) |
| SSL | Let's Encrypt + certbot |
| 域名 | shenyuyang.site |
| 训练监控 | Slack Webhook 实时推送训练进度 |
📦 数据总览
| 数据集 | 来源 | 用途 | 数量 |
|---|---|---|---|
identity_dataset.jsonl |
手写 | 身份认知训练 | 86 |
shenyu_info_dataset_v2.jsonl |
手写 | 个人信息训练 | 29 |
wechat_style_dataset.jsonl |
微信聊天记录 | 风格训练 | ~数千条 |
dpo_pairs.jsonl |
手写 + TruthfulQA | DPO 偏好对齐 | 303 |
rag_knowledge/*.md |
手写 | RAG 知识库 | 6 文件 |
eval/*.jsonl |
手写 | 自动化评测 | 120 |
🙏 致谢