尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

无需微调:用CAA引导Qwen3跨期偏好,让模型更懂长期价值

无需微调:用CAA引导Qwen3跨期偏好,让模型更懂长期价值 如果你正在用 Qwen3 做 Agent、金融问答或中长期规划类应用大概率会遇到一种不太好描述的“失控感”模型明明什么都懂却在关键决策上表现得特别短视。它可能因为用户一句“立刻要结果”就放弃完整方案也可能在多步任务里只优化当前这一步导致后续步骤全部失效。你可能会试 prompt、试 few-shot甚至考虑 LoRA但 prompt 不稳定微调成本又高。其实还有另一条路不动任何一个权重通过修改模型内部的激活向量直接把它的“跨期偏好”掰过来。这条技术路线就是 Contrastive Activation Addition也就是 CAA。本文将把 CAA 的原理讲清楚并给出它在 Qwen3 上进行跨期偏好引导的完整思路与可运行示例。先说结论CAA 不是微调方法也不是普通的 prompt 工程而是“在推理时给模型加一个可插拔的性格旋钮”。这个旋钮专门控制模型在时间维度上的取舍是更看重眼前利益还是更倾向长期回报。对于 Qwen3 这类开源模型我们既不需要重新训练也不需要维护多份权重只要算出一个 steering vector在 generate 时把它加回某个隐藏层就能观察到稳定的行为变化。但 CAA 也有明显边界它只能放大模型中原本已经存在的行为倾向不能凭空注入模型没有的能力。本文会用可运行的代码演示整个流程并专门讨论常见坑和生产环境的取舍。1. 这篇文章真正要解决的问题1.1 为什么“跨期偏好”在 LLM 应用里如此重要跨期偏好Intertemporal Preference原本是行为经济学里的概念用来描述人在面对不同时间点的收益时如何评估“现在拿到”和“未来拿到”之间的价值差异。很多人会为了眼前立刻能获得的小回报放弃以后本来更大的收益心理学上称为“延迟满足”失败。研究大脑和行为的学者发现这种偏好并不是单纯“不懂事”而是大脑对时间折扣的默认参数设置。放到大模型场景里这个问题变得更加微妙。LLM 本身没有生理欲望它的所有行为都是训练目标塑造出来的。但在多步 Agent 任务里模型必须在“先完成当前子目标”和“保证最终目标成功”之间做取舍在投资问答里模型要在“迎合用户快速赚钱心理”和“提示长期风险”之间找平衡在健康咨询里模型要在“让用户马上舒服”和“给出真正有效的长期方案”之间做选择。这些决定都涉及时间维度上的偏好。而目前很多开源模型的默认偏好往往偏向“短视”。原因也很直观模型在训练和 RLHF 阶段大量人类反馈来自即时对话体验。用户更倾向于对“立刻给出现成答案”的模型给出好评而不是对“建议您等一个月再决策”的模型给出好评。这导致模型学到的用户满意度信号天然带上了“求快”的偏差。如果直接把这种模型接入 Agent 或严肃问答系统它很容易在关键节点上给出一时爽、长期坑的回复。1.2 微调太重prompt 太飘面对这种偏好偏差传统思路有三种一是写更详细 system prompt强调“请考虑长期价值”二是收集大量跨期决策数据做 LoRA 微调三是在后处理阶段加规则拦截短视答案。但这三种方式都不完美。Prompt 方法的问题在于稳定性差。模型可能在某几个模板上表现良好换一种问法或者用户稍微引导一下它又回到短视倾向。尤其当模型已经被训练成“服从用户即时要求”时一句“但用户现在就要答案”就可能覆盖掉 system prompt 里的长期主义要求。这种级联失效在 Agent 场景中经常出现。LoRA 微调的问题在于成本高、周期长。你必须构造高质量数据集、做训练、做评测、维护多份适配器还要考虑不同版本模型权重之间的兼容性。如果只是想让模型“更有耐心一点”为这种单维属性启动一次训练流程在工程上并不划算。更麻烦的是微调很容易在改变目标行为的同时影响到模型其他能力比如数学推理、代码生成、指令遵循等而这类回归有时候很难定位。1.3 CAA 的适用范围与本文读者CAA 的定位刚好落在这两种传统方案中间它不需要训练只需要几十条对比文本它比 prompt 更稳定因为它直接作用在模型的内部表示上它又能随时关闭不会污染模型原始权重。因此它特别适合用来调教模型的“行为倾向”比如礼貌程度、风险偏好、创造力和保守程度以及本文要讲的跨期偏好。这篇文章适合这几类读者第一正在用 Qwen3 做 Agent 或决策类应用希望模型在多步任务里更稳健的开发者第二对大模型对齐、可解释性和激活工程感兴趣的算法工程师第三尝试过 prompt 和微调但对效果和成本都不满意的技术负责人。读完你至少能理解 CAA 的原理跑通一个最小示例并知道如何判断 steering vector 是否真的有效。2. 跨期偏好模型决策中的时间维度2.1 从经济学到 LLM Agent跨期选择的核心是“时间折扣率”。如果一个人认为“一年后的 150 元”和“今天的 100 元”没有区别他的年折扣率大概是 50%。如果他认为“一年后的 1000 元”才和“今天的 100 元”没有区别那么他的折扣率会低很多更看重长期回报。在 LLM Agent 里这个折扣率并不是显式参数而是隐含在无数量权重中。模型对每一步动作的评估既会看当前状态也会看未来回报。不过由于训练数据里的很多决策示范都是短视的模型学到的“折扣率”往往偏高。结果就是模型一旦发现当前步骤有一个明显收益就会忽略后续的更优路径。跨期偏好影响的不只是“选择题”。在代码生成任务中如果模型只顾眼前编译通过可能会写出可读性极差、后续无法维护的代码在推荐系统中如果模型只顾用户当前点击率可能会推荐低质量、高短期吸引力的内容。可以说跨期偏好是模型行为中一条很容易被忽视但影响面很广的“暗线”。2.2 模型为什么容易短视大模型的训练过程决定了它很难天然具备“长期主义”。预训练目标是下一个 token 预测这个目标本身就是极度短视的模型只需要预测好下一个词并不需要对整篇文档的长期收益负责。虽然更深的注意力机制可以让模型看到长上下文但训练信号并没有真正鼓励它“为了长期目标牺牲短期表现”。到了 RLHF 阶段人类偏好标注员通常也是即时评价一句回答的好坏很少会为“这个回答可能在三个月后给用户带来什么影响”去打分。于是模型进一步被推向即时满意度。这种隐藏偏差在常规 benchmark 里很难暴露因为大多数基准测试只看单轮答案是否正确并不会设计一个需要连续多轮决策的任务来考察跨期一致性。理解了这一点你就会明白跨期偏好不是“知识”而更像是一种“决策倾向”。这也是为什么 CAA 这类激活编辑方法很适合处理它。知识需要通过训练注入但倾向往往只对应高维空间里的一个方向我们完全可以直接修改这个方向。2.3 跨期偏好不等于知识这里要特别强调一个容易误解的点CAA 不能提升模型对长期决策的推理能力。如果 Qwen3 本身不知道“长期投资需要分散风险”那么你再怎么加 steering vector它也不可能突然变成理财专家。CAA 能做的是让模型把已知的知识和偏好以更一致的方式表达出来。换句话说CAA 调整的是“路由权重”而不是“知识容量”。这就像同一个象棋选手在心态激进和心态保守时会走出完全不同的棋路但棋盘知识并没有变化。理解这个边界能帮你在实际项目中避免对 CAA 提出过高要求。3. CAA 核心原理对比激活添加3.1 激活空间中的方向神经网络中每一层的隐藏状态可以看作一个高维空间中的点。大量研究表明这个空间并不是完全杂乱无章的很多语义概念会沿着某个方向分布。比如“正面情绪”和“负面情绪”可能分别集中在空间中的两个相反区间模型内部的某个线性方向可能对应着“性别偏见”另一个方向可能对应着“事实性”。当模型处理“我宁愿等待更大回报”和“我只要眼前的奖励”这两种文本时虽然文字不同但在解码层它们会激活一组与“耐心-短视”相关的神经通路。如果我们在这些层上做一个平均差就能得到一条从“短视”指向“耐心”的向量。这条向量就是 steering vector。CAA 的核心假设就是我们可以把这条向量理解为模型内部“决策倾向”的位移。推理时把输入向量往这个方向推模型就更容易产生对应倾向的输出。这种干预不需要对权重做任何梯度更新也不需要额外的标注数据只需要对比文本。3.2 CAA 三步法CAA 的整体流程可以分为三步准备两组文本一组代表你希望模型拥有的行为比如耐心另一组代表对立行为比如短视在某个隐藏层上分别提取这两组文本对应的激活计算均值差并在必要时做归一化在生成阶段把这条方向向量乘以一个缩放系数 alpha加到模型的隐藏状态上引导模型向目标行为偏移。这个流程看起来简单但每一步都有细节问题。比如提取哪个层的激活、用哪个 token 位置的向量、alpha 取多大、方向向量是否需要归一化这些都会显著影响最终效果。后面的代码部分会分别说明。3.3 与其他方案对比为了让 CAA 的定位更清楚可以把它和几种常见方法放在一起比较方法是否训练模型是否需要数据干预成本可解释性可逆性Prompt 工程否否极低弱直接改提示词即可Few-shot 示例否是低弱可切换示例LoRA/微调是需要大量数据高弱需保留多份权重RLHF/DPO是需要偏好数据很高弱重新训练CAA否几十条即可低中去掉 hook 即可CAA 最突出的优势是“轻量”和“可插拔”。你可以在不改动原权重的情况下为一个模型准备多个 steering vector。不同 Agent 实例可以用不同的偏好向量这在服务端只需要维护不同的 hook 配置不需要加载多个模型副本。3.4 关键误区很多初看 CAA 的人会把它理解为“在输出概率上做手脚”其实不是。CAA 作用在隐藏层而不是输出层的 logits它影响的是模型后续每一层对语义的处理方式比强行干预概率分布自然得多。另一个误区是“既然 CAA 有方向向量那它应该能把模型变成完全不同的人”。实际效果要保守得多。CAA 只能在原有模型分布附近做微调如果目标行为和模型自身能力相差太大steering vector 可能会把生成文本推向语法崩坏或无意义重复。后面我们会看到alpha 的控制非常关键。4. Qwen3 为什么适合做激活干预实验4.1 开源与中文能力Qwen3 是目前中文开源模型生态里非常有关注度的一条产品线。相比只擅长英文的模型Qwen3 的中文指令理解能力更贴近国内开发者的真实场景。跨期偏好的语料很大部分来自中文表达我们需要一个对中文 token 处理足够好的底座这样提取出来的方向向量才有实际迁移价值。从工程角度看Qwen3 采用标准的 decoder-only Transformer 架构兼容 transformers 生态。这意味着我们可以用很常见的方式加载模型、注册 forward hook、读取隐藏层状态不需要为了干预激活去修改官方源码。这也让 CAA 的复现门槛比较低。4.2 模型结构对 CAA 的影响CAA 对模型结构有要求吗从原理上说任何带隐藏层的神经网络都能做类似操作但效果和稳定性会因为模型结构不同而有差异。对于 Qwen3 这种使用相对较深 decoder-only 结构的模型干预点一般选在靠后的层。靠前的层更多负责语法和局部语义靠后的层则更接近决策输出因此更适合干预高层偏好。同时Qwen3 的参数量跨度比较大。不同规模的模型其隐藏层宽度、层数、激活分布都不一样。这意味着在一个模型上计算出的 steering vector不能直接迁移到另一个尺寸的模型上。实际使用时必须针对每一个模型单独计算方向向量。4.3 多模态方向的潜在相关性最近的公开讨论里Qwen3 也经常和 ASR、VQA 等话题一起出现属于典型的多模态扩展方向。不过本文只处理文本侧的跨期偏好CAA 示例也完全基于文本生成接口。如果你后续需要把语音或视觉任务接入同一个偏好控制逻辑思路是类似的只是需要根据多模态编码器的结构重新定位干预层。本文不展开但你要知道“干预层在哪”这个问题在不同模态下需要重新回答。5. 环境准备与模型加载5.1 运行环境做 CAA 实验不需要特别大的算力但至少要能加载一个可以生成流畅中文的 Qwen3 模型。这里涉及两个选择本地 GPU 推理还是使用云服务。CAA 需要注册内部 hook大多数云端 API 不会开放隐藏状态因此我们必须使用可本地加载的开源权重。如果你公司已经有内部推理服务也可以通过自定义后端接口暴露 hidden state但那样做复杂度会高很多。操作系统方面Linux 或 macOS 都可以Windows 上只要能跑 PyTorch 也没问题。显存方面建议至少 16GB 以上的 GPU因为我们要同时保留模型和中间激活。如果显存不够可以考虑使用 4bit 量化加载降低单卡占用。5.2 安装依赖下面用 conda 创建一个独立的虚拟环境。Python 版本建议 3.10 或更高。依赖只需要 transformers 和 PyTorch以及一个用于保存中间变量的 torch 自带功能。代码中不涉及额外复杂的库。conda create -n qwen3-caa python3.10 -y conda activate qwen3-caa # 请根据你的 CUDA 版本选择合适的 PyTorch 安装命令 pip install --upgrade pip pip install torch transformers accelerate这里没有写死 PyTorch 版本因为不同机器的 CUDA 环境差异很大。建议你以 PyTorch 官网给出的安装命令为准避免装错 CUDA 版本。如果计划使用量化加载可以再补一个 bitsandbytespip install bitsandbytes5.3 加载 Qwen3 权重加载模型时最重要的是确定权重路径。由于 Qwen3 不同版本权重名在不同平台的命名可能有差异下面统一用MODEL_PATH指代你实际获得的模型权重目录。如果你已经通过 Hugging Face 或 ModelScope 下载到本地就把路径填进去。# 文件路径load_model.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer # 替换为你的 Qwen3 权重目录 MODEL_PATH /path/to/your/qwen3 model AutoModelForCausalLM.from_pretrained( MODEL_PATH, torch_dtypetorch.bfloat16, device_mapauto, ) tokenizer AutoTokenizer.from_pretrained(MODEL_PATH)这里使用torch.bfloat16是为了降低显存占用。如果你的显卡不支持 bfloat16可以换成torch.float16。如果显存仍然不足可以再加load_in_4bitTrue但要注意量化后的激活分布可能和原始模型略有差异steering vector 也需要在量化模型上重新提取。5.4 验证加载加载完成后可以快速做一次最小生成验证prompt 请用一句话解释什么是跨期偏好。 inputs tokenizer(prompt, return_tensorspt).to(model.device) outs model.generate(**inputs, max_new_tokens32, do_sampleFalse) print(tokenizer.decode(outs[0], skip_special_tokensTrue))这一步的目的是确认权重、tokenizer 和模型结构都能正常工作避免后面花很多时间提取特征后才发现模型加载阶段就有问题。6. 构造跨期偏好对比语料6.1 语料设计原则CAA 的方向向量质量很大程度上取决于对比语料的质量。设计对比语料时要遵循三个原则语义对仗、表达稳定、目标单一。语义对仗是指“正向组”和“负向组”除了行为倾向不同尽量不在长度、复杂度、主题上出现明显差异。比如正向组写“我愿意等待一年换取更高回报”负向组就应该写“我要立刻得到回报不想等待一年”而不是写一段完全无关的内容。表达稳定是指每一组内部的句子不能目标分散。如果正向组里既包含“耐心”又包含“诚信”那提取出来的方向向量可能同时编码了多个概念后续干预时容易出现意外效果。目标单一更关键。我们只想要“跨期偏好”这个维度所以正向文本应该都围绕“延迟满足、长期价值、等待收益”负向文本围绕“即时满足、眼前收益、风险规避”不要轻易加入其他主题。6.2 示例语料下面是一组可以直接用的中文对比语料。每条句子都保持简短方便提取最后一个 token 的 hidden state。你可以根据实际场景扩充到 20 条甚至 50 条数量越多方向向量越稳定。# 文件路径pairs.py positive_texts [ 为了未来更大的回报我愿意耐心等待并承担这段等待中的不确定性。, 长期主义者更看重最终价值不会因为眼前的波动而改变计划。, 如果等待一年能获得明显更高的收益我会选择等待。, 延迟收益虽然来得慢但往往更持久也更值得追求。, 真正优秀的决策会优先考虑未来的长期价值。, ] negative_texts [ 我只想立刻得到结果未来的收益看得见但摸不着风险太大。, 抓住当下才最真实长期规划往往因为变化而落空。, 如果现在就能拿到一笔奖励我不会把它推迟到一年之后。, 眼前的小确幸比遥远的大目标更重要因为我控制不了未来。, 应该抓住眼前的利益不要指望遥远的将来。, ]6.3 语料数量、长度和语言语料数量太少算出的向量会受单句句式干扰数量太多则可能带来额外计算成本。从实践经验看每组 20 到 50 条已经足够。文本长度建议控制在 20 到 40 个 token 之间太短缺乏语义载体太长则最后一个 token 可能丢失前文关键信息。语言方面如果你要控制的是中文模型的偏好就用中文语料如果后续要在一个混合中英文的场景下使用可以中英混合构造但最好先在小规模实验里确认方向向量不会偏向某一种语言。7. 提取激活并计算 steering vector7.1 hook 的选择在 PyTorch 中提取隐藏层激活最方便的方法是注册 forward hook。我们关心的是模型在解码器最后一层输出的 hidden state。为什么选最后一层而不是第一层因为越靠近输出的层越直接反映模型在“准备生成什么内容”时的语义决策而较早的层更多在编码局部语法。如果要围绕 Qwen3 做更精细的干预你也可以对比多个层。后面会解释如何选择。这里先用model.model.layers[-1]作为默认层。7.2 提取激活的代码实现我们需要一个函数输入一组文本输出这组文本在指定层的最后一个 token 位置向量。为了让 hook 能捕获每一层输出需要先定位到对应模块。# 文件路径extract_steer.py import torch def collect_last_token_states(model, tokenizer, texts, layer_index-1): 提取一组文本在指定层最后一个 token 位置上的 hidden state。 model.eval() collected [] # 用于在 hook 中暂存 hidden state cache [] def hook_fn(module, input_, output): hidden output[0] if isinstance(output, tuple) else output cache.append(hidden.detach()) target_layer model.model.layers[layer_index] handle target_layer.register_forward_hook(hook_fn) with torch.no_grad(): for text in texts: # 清空 cache避免多个 batch 之间混叠 cache.clear() inputs tokenizer(text, return_tensorspt).to(model.device) model(**inputs) if not cache: continue hidden cache[0] # 由于这里每次只输入一条文本直接取最后一个 token last_vec hidden[0, -1, :].float().cpu() collected.append(last_vec) handle.remove() return torch.stack(collected)这个函数的核心逻辑是在目标层注册 hook对每一条文本跑一次前向传播从 hook 捕获的 hidden state 中取出最后一个 token 的向量所有向量堆叠成一个矩阵返回。注意这里逐条输入是为了避免 padding 带来的“最后一个 token 其实是 padding token”的问题。如果为了速度想 batch 化输入就必须用 attention mask 定位真实最后一个有效 token。7.3 计算方向向量并保存拿到正向矩阵和负向矩阵后计算中心差向量并做 L2 归一化。归一化可以让 alpha 的选择在不同模型之间更有可比性。# 继续在 extract_steer.py 中执行 pos_states collect_last_token_states(model, tokenizer, positive_texts) neg_states collect_last_token_states(model, tokenizer, negative_texts) pos_vec pos_states.mean(dim0) neg_vec neg_states.mean(dim0) steer_vec pos_vec - neg_vec steer_vec steer_vec / (steer_vec.norm() 1e-8) torch.save(steer_vec, steer_vec.pt) print(steering vector shape:, steer_vec.shape)运行后如果一切正常会打印一个类似steering vector shape: torch.Size([4096])的维度信息。不同模型隐藏维度不同具体数字以你加载的模型为准。这一步最容易出现的问题是 hook 没有捕获到输出。可以先打印一下hidden.shape确认形状是否符合预期。如果 hook 返回的 output 是 tuple代码里已经做了兼容如果模块结构不同需要先打印模型结构再修改model.model.layers的定位方式。8. 在推理时应用 steering vector8.1 alpha 调节alpha 是干预强度系数。alpha 越大模型行为越偏向目标方向但 alpha 过大模型可能开始输出重复内容、语义漂移甚至直接崩溃。所以实际使用中应该从一个小值开始比如 0.5然后逐步增加找到既不破坏生成质量、又能明显改变偏好的临界值。8.2 生成函数封装为了对比干预前后效果最好封装一个带开关的生成函数。当steer_vec为空或alpha0时走原始生成逻辑当提供向量时则注册 hook 后再生成。# 文件路径guided_generation.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer def make_steering_hook(steer_vec, alpha, layer_index-1): 构造一个向 hidden state 添加方向向量的 hook。 def steer_hook(module, input_, output): hidden output[0] if isinstance(output, tuple) else output hidden hidden steer_vec.to(hidden.device) * alpha if isinstance(output, tuple): return (hidden,) output[1:] return hidden return steer_hook def generate_with_steering( model, tokenizer, prompt, steer_vecNone, alpha0.0, max_new_tokens128, layer_index-1, ): if steer_vec is not None and alpha ! 0: handle model.model.layers[layer_index].register_forward_hook( make_steering_hook(steer_vec, alpha, layer_index) ) else: handle None try: inputs tokenizer(prompt, return_tensorspt).to(model.device) outputs model.generate( **inputs, max_new_tokensmax_new_tokens, do_sampleFalse, ) response outputs[0][inputs[input_ids].shape[1]:] return tokenizer.decode(response, skip_special_tokensTrue) finally: if handle is not None: handle.remove()注意make_steering_hook里传入的layer_index没有实际使用只是保持签名一致也可以删掉。真正使用的model.model.layers[layer_index]在外部注册时被定位。8.3 干预效果对比示例现在用一条跨期选择题来观察干预前后的差异prompt ( 选项A今天拿到100元选项B一年后拿到150元。\n 请只回答你会选A还是B并给出理由。 ) print( alpha0原始 ) print(generate_with_steering(model, tokenizer, prompt)) print(\n alpha1.5偏向长期 ) print(generate_with_steering(model, tokenizer, prompt, steer_vec, alpha1.5)) print(\n alpha-1.0偏向短视 ) print(generate_with_steering(model, tokenizer, prompt, steer_vec, alpha-1.0))这里用负 alpha 是为了反向验证方向向量确实编码了“耐心-短视”这个维度。如果 alpha 为负能让模型更偏好即时收益说明方向向量的方向是正确的如果正负都没有区别那就要回头检查语料或层选择。需要特别说明的是由于不同 Qwen3 基座和采样设置不同运行结果不会完全一样。预期现象是原始模型可能摇摆不定正向 alpha 下模型更多选择“一年后拿 150 元”并强调长期价值负向 alpha 下模型更多强调“现在拿到 100 元更稳妥”。如果实际现象不明显优先尝试调大 alpha或者换一个层。8.4 为什么只加一层很多人会好奇为什么不把 steering vector 加到每一层。虽然每一层都加更“彻底”但也会带来更大的语义扰动。只加一层相当于在信息流动过程中做了一次小偏转后续层还会对偏转结果做一定缓冲因此生成结果更容易保持自然。选哪一层需要做一个小实验在倒数第 1 层、倒数第 3 层、倒数第 5 层分别生成结果观察哪个层能在“改变偏好”和“保持生成质量”之间取得最佳平衡。这个实验不复杂但值得认真做。9. 验证效果设计一个跨期选择测试集9.1 任务设计CAA 最怕的不是“看起来有效”而是“换个问题就失效”。为了系统评估 steering 的有效性可以设计一组跨期选择题。测试题应该覆盖三类金钱回报、时间分配、任务优先级。比如金钱回报今天拿 50 元或者明年拿 100 元你选哪个时间分配现在多玩一小时游戏或者先完成任务再放松你更倾向哪一种任务优先级先做一个能快速交付但不太重要的需求还是先做对项目更关键但需要两周的长期任务每道题都要求模型明确回答“选 A 还是选 B”这样我们就可以统计选择长期选项的比例。9.2 自动化评估脚本可以把测试集写成列表再循环调用generate_with_steering最后按关键词简单归类。为了减少随机性使用do_sampleFalse做确定性生成。# 文件路径eval_preference.py test_prompts [ 明天拿到100元还是一个月后拿到180元请直接回答你选哪个。, 现在轻松工作一天还是连续努力十天换取更大机会用一句话回答。, 马上满足一个小愿望还是等一年实现一个更大的愿望请只回答选择结果。, ] long_keywords [一个月后, 更大机会, 更大的愿望] def classify_output(text): for kw in long_keywords: if kw in text: return long return short for prompt in test_prompts: out_orig generate_with_steering(model, tokenizer, prompt) out_steer generate_with_steering(model, tokenizer, prompt, steer_vec, alpha1.5) print(问题, prompt) print( 原始倾向, out_orig.strip()[:60]) print( steering, out_steer.strip()[:60]) print( 结果, classify_output(out_orig), -, classify_output(out_steer))这个脚本很简单关键词匹配也粗糙但足以提供初步反馈。更严谨的做法是让另一个大模型作为裁判或者人工对 50 条测试结果打分。重点不是精度而是看方向向量是否在多个不同问题上都有一致的引导效果。9.3 并行对比与判断维度评估时不要只看“是否选了长期选项”还要关注生成质量。一个只在选择题里有效但一到开放生成就语无伦次的 steering vector是不能上生产的。因此建议从三个维度判断偏好改变
返回列表