--- license: apache-2.0 language: - zh base_model: Qwen/Qwen3.5-9B pipeline_tag: text-generation library_name: transformers tags: - lora - role-play - chinese - qwen3.5 --- # sbsam 用烧饼社区([linux.sb](https://linux.sb))用户 `Sam.Altman` 的发言微调 Qwen3.5-9B,得到的「赛博 Sam」。 > 这里的 `Sam.Altman` 只是论坛网名,与 OpenAI 及其 CEO 无关。 ## 内容 | 路径 | 内容 | |---|---| | `/` | 合并好的完整权重(bf16,`Qwen3_5ForCausalLM`,纯文本,约 18 GB) | | `adapter/` | LoRA adapter(约 230 MB),对应基座 `Qwen/Qwen3.5-9B` | ## 输入格式(必须一致) 训练时每条样本由 system prompt 加上帖子上下文组成: ``` system: 你是烧饼社区(linux.sb)的用户 Sam.Altman。这只是网名,跟 OpenAI 没关系。说话短、随意。你的身份就是 Sam.Altman 本人,别说自己是别的用户。 user: 话题:GPT好慢啊! 版块:错误地方 [楼主 路人甲] 今天用GPT问个问题等了两分钟 [#1 小王] 我这也是 [#2 老李] 换Claude吧 ``` - 楼主正文截到 300 字,每层楼截到 150 字。只放最近 6 层楼,如果回复的是更早的某层,再把那层补进来。 - 想让他回复第 N 层,就把 `@作者 #N` 作为 assistant 回复的开头预先填好,让模型接着写,这和训练数据的格式一致。 - 让他发新帖:user 写 `在「错误地方」版块发一个新帖`,输出格式是 `标题:xxx\n\n正文`。 ## 用法 **两个必须注意的地方:** 1. **关闭 thinking**(`enable_thinking=False`)。训练时回复前都是空的 `\n\n\n\n`。 2. **eos 用 `<|im_end|>`**。仓库里的 `generation_config.json` 已经设好了。 ### vLLM ```bash vllm serve CryKy/sbsam --served-model-name sbsam \ --default-chat-template-kwargs '{"enable_thinking": false}' ``` ### transformers ```python from transformers import AutoModelForCausalLM, AutoTokenizer import torch tok = AutoTokenizer.from_pretrained("CryKy/sbsam") model = AutoModelForCausalLM.from_pretrained("CryKy/sbsam", dtype=torch.bfloat16, device_map="auto") SYS = ("你是烧饼社区(linux.sb)的用户 Sam.Altman。这只是网名,跟 OpenAI 没关系。" "说话短、随意。你的身份就是 Sam.Altman 本人,别说自己是别的用户。") msgs = [ {"role": "system", "content": SYS}, {"role": "user", "content": "话题:GPT好慢啊!\n版块:错误地方\n\n[楼主 路人甲] 今天用GPT问个问题等了两分钟\n[#1 小王] 我这也是"}, ] text = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True, enable_thinking=False) enc = tok(text, return_tensors="pt", add_special_tokens=False).to(model.device) out = model.generate(**enc, max_new_tokens=120, do_sample=True, temperature=0.9, top_p=0.9, repetition_penalty=1.15, eos_token_id=tok.convert_tokens_to_ids("<|im_end|>")) print(tok.decode(out[0][enc["input_ids"].shape[1]:], skip_special_tokens=True)) ``` 只用 adapter 的话:先加载基座 `Qwen/Qwen3.5-9B`(用 `AutoModelForCausalLM`,只加载文本部分),再执行 `PeftModel.from_pretrained(model, "CryKy/sbsam", subfolder="adapter")`。 ## 训练 | | | |---|---| | 方法 | LoRA(r=32,alpha=64,dropout=0.05) | | 挂载 | q/k/v/o_proj、gate/up/down_proj | | 数据 | 996 条回帖(带楼层上下文)+ 200 条发帖,来自 2026-08 至 2026-10 的发言 | | 序列长度 | 1024,只对回复部分计算 loss | | 轮数 | 最多 3 轮,取验证集 loss 最低的第 2 轮(3.91 → 2.71) | | 硬件 | NVIDIA L40S 48GB,约 15 分钟 | 数据清洗: - 帖子里删过楼会导致 `@某人 #N` 的楼号错位,已按「该账号在 N 楼及以前最近的一层」重新定位并改写。 - 如果被 @ 的人不在上下文里,就去掉这个 @,免得模型学会凭空 @ 人。 训练数据不公开。 ## 已知问题 - **会一本正经地编造事实。** 风格是像的,内容基本是幻觉。 - **偶尔还是会 @ 一个上下文里不存在的人。** - **数据量小**(约 1.2k 条),知识和话题只停留在这两个月的论坛内容。 - 输出是统计模仿,**不代表被模仿者本人的观点。不要拿它冒充本人发帖。**