

▐ Cases
-
品牌一致性,在述说A商品相关的信息时,需要使用该商品对应的品牌主打的特性词汇,比如运动、舒适,而不要使用B商品品牌主打的品牌特性,比如优雅、大方等; -
准确性,比如在输出一份账单的时候,账单的编码以及账单金额只输出在特定位置,不在正文中重复出现,避免多次输出可能带来的不一致性; -
合规性,在引用A公司的案例进行陈述的时候,不要同时引用其竞争对手B公司的案例,以免造成商业敏感和合规等问题; -
风格指南,可能对于输出文档的语法、标点、格式或术语有特定的要求。
▐ Antipattern

Logits Masking模式的反例描述
▐ Solution
-
用户可以针对输出内容的约束,生成一些Rules,这些Rule是可以通过程序来自己实现的(比如对于一些关键字、词的屏蔽); -
在生成过程的每一个中间步骤,获取当前可能的后续词元(continuations)集合,对于不符合预设规则的候选续写项,将其对应的logits(模型输出的原始分数)置零,从而在概率分布中彻底排除这些非法选项; -
只要还存在至少一个符合规则的合法续写路径,生成过程就可以继续向前推进; -
如果当前状态没有符合条件的续写选项,或该状态此前已被标记为“死胡同”(dead end),则需要回退一步(backtrack),尝试其他可能的前序选择; -
当达到预设的最大重试次数后,若仍无法生成满足所有规则的内容,则向用户返回拒绝响应,说明“无法生成符合要求的内容”。

Logits Masking流程图
from transformers import pipelineMODEL_ID = "/Users/mario/.cache/modelscope/hub/models/LLM-Research/Phi-3-mini-4k-instruct"pipe = pipeline( task="text-generation", model=MODEL_ID, kwargs={ "return_full_text": False, }, model_kwargs={})results = pipe(input_message, max_new_tokens=512, do_sample=True, temperature=0.8, num_beams=10, # 束宽为10 use_cache=True, logits_processor=[<Your_Customized_Processor extends LogitsProcessor>]) # 设置你实现的Processor实例

grammar_str = """timestamp_literal ::= { t 'yyyy-mm-dd hh:mi:ss' } |'date_literal time_literal'date_literal ::= { d'yyyy-mm-dd'} |mm-dd-yyyy| mm/dd/yyyy| mm-dd-yy| mm/dd/yy| yyyy-mm-dd | yyyy/mm/dd| dd-mon-yyyy| dd/mon/yyyy| dd-mon-yy| dd/mon/yytime_literal ::= { t 'hh:mi:ss'}|hh:mi:ss[:mls]"""

Grammar执行流程
from transformers import pipelinefrom transformers_cfg.grammar_utils import IncrementalGrammarConstraintfrom transformers_cfg.generation.logits_process import GrammarConstrainedLogitsProcessorMODEL_ID = "/Users/mario/.cache/modelscope/hub/models/LLM-Research/Phi-3-mini-4k-instruct"pipe = pipeline( task="text-generation", model=MODEL_ID, kwargs={ "return_full_text": False, }, model_kwargs={})def get_expression_that_solves(math_problem: str) -> str: system_prompt = """ You are a math instructor. I will ask you a math question. Respond with the mathematical expression that can be used to solve the problem. """ # load the grammar grammar_str = """ root ::= (expr "=" ws term "n")+ expr ::= term ([-+*/] term)* term ::= ident | num | "(" ws expr ")" ws ident ::= [a-z] [a-z0-9_]* ws num ::= [0-9]+ ws ws ::= [ tn]* """ grammar = IncrementalGrammarConstraint(grammar_str, "root", pipe.tokenizer) grammar_processor = GrammarConstrainedLogitsProcessor(grammar) input_message = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": math_problem} ] results = pipe(input_message, max_new_tokens=256, do_sample=False, logits_processor=[grammar_processor] ) return results[0]['generated_text'][-1]['content'].strip()
import osfrom openai import OpenAIclient = OpenAI( # 若没有配置环境变量,请用ideaLAB的API Key将下行替换为:api_key="xxx", api_key=os.getenv("OPENAI_API_KEY"), base_url="https://idealab.alibaba-inc.com/api/openai/v1",)system_prompt = """ You will be given a short paragraph about a book. Extract the author, title, and publication year of the book. Return the result as JSON with the keys author, title, and year. If any piece of information is not found, fill the spot with NULL """completion = client.chat.completions.create( model="DeepSeek-R1-671B", # 此处以DeepSeek-R1-671B为例,可按需更换模型名称。 messages=[ {'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': 'Love in the Time of Cholera'}], response_format={"type": "json_object"}, # 指定返回的结果类型 )print(completion.choices[0].message.content)

▐ Cases
-
内容已经ready,但是最终的输出我们有额外的偏好、格式等要求; -
这些要求,有些比较具体,这部分可能可以通过上述的基于动态规则以及一些数据格式来约束,但是有些要求比较细节,不太容易沉淀出rule,也不太容易去做格式化的约束; -
虽然给不出具体的判定规则,但是可以给出一些范本的例子。
-
Few-shot:通过Few-shot的方式,让模型按照示例所给出的输入和输出案例的一些特征(输出的格式、语调、风格等),来约束回答的样式,这是一种比较常用的方式; -
Fine-Tuning:收集示例数据,使用这部分数据对模型进行微调,改变相关的权重参数,重新部署微调后的模型;
-
微调可以让模型更充分地学习到输出样式的细节,比如需要按照标准术语及口语类型进行输出,会涉及比较庞大的术语映射表和映射关系,这个通过few-shot的方式不太能很好的达到最终效果; -
可以提升整体推理速度,因为相较于前者,在整体context的token数上有比较明显的优势;
-
Bigger models lead to better results:模型参数越大,在同等example下,表现会更优,不过效果不好时,可以先看下纰漏点在哪里,可以适当进行例子的补充,来进行第一步的调优; -
Limits of the Context:例子的数量多,会让模型可以有更好的转换效果,但是同时,这些例子会增加推理上下文的长度,长度过大,模型整体的处理效果,极端的话会超出模型可处理的context长度的上限,这里可以对用户的问题进行分类,同时去额外召回和该query相关的例子来补充context,可以达到一定程度的平衡; -
推理速度:few-shot会增加模型处理的context大小,这部分会直接影响推理响应的速度,优化这部分损失可以是换比较小的模型,亦或者是对few-shot的例子进行一些缩减或者按需添加,如果对rt非常敏感,可能建议做fine-tuning。

-
历史内容中没有沉淀所谓你个人风格下的内容产物对应的普通风格内容; -
这类内容所能覆盖的内容主题会比较有限;

逆向中和模式的流程图
-
收集你的历史的邮件,让一个通用LLM以你的历史邮件为输入,生成中性的版本(可以是一个商务邮件对话风格); -
将上一步产生的结果和你的历史邮件一一对应,但是输入输出做调换,即产生的中性邮件版本为输入,你个人的邮件作为输出,构建一个训练样本集; Neutralize the tone and style from the following email to make it professional and suitable for communication between executives who may not know each other very well.

逆向中和模式推理流程
-
中性风格的选择上,可以做一些调试,还是以邮件为例,比如按照初中一年级水平输出,亦或是按照英国商务标准输出,都可以是一种中性内容输出的提示,但是这里可以针对两种风格定义看下输出的内容和原始个人邮件内容的差异性,选一种差异性小、在表达的内容完整程度上更接近的一种风格; -
微调数据的选择上,在主题方面也需要尽量涵盖丰富一些,至少能覆盖到后续可能使用到的场景,同时针对模型生成的训练数据,进行人为的判断和筛选,可以提升整体的效果。

▐ Cases
▐ Solution

-
在Step1中,有涉及到对于原始Prompt的改写,这里的改写主要做的是在保持prompt原意的前提下,进行同等的替换、或者是进一步的解释说明,或者是提供一些例子,使得让两次生成的结果有一些差异性; -
Step2中使用的是LLM来评估两个结果的好坏,标注为LLM-as-judge,一般是参数量更大的模型,当然也可以是人为标注,这里可以结合场景来看,各有利弊; -
Step4中的Preference tuning,比较常见的是做DPO强化,增对一个prompt,有倾向的选择“chosen”,和不太倾向的结果选择“rejected”。
▐ Considerations
-
使用更权威的模型做判定,模型参数越大,一般来说效果越好,整体在处理大量数据的标注上,有比较大的优势,但是对于什么是更好的评定标准是个黑盒,不一定能够非常好的match使用场景; -
专家标注,该方式成本偏高,在处理少数据量的时候,有可行性,同时在一些客观和高难度问题上,标注准确性有比较大的保障,但是,对于一些主观类的问题,在标注的时候会潜在带入个人的价值观、喜好等因素; -
基于反馈的判定,比如在产品链路上做的反馈设计(好or不好),亦或者是基于结果指标的一些判定(比如基于某个回答下,用户后续的互动率更高等等),该方式需要结合后置的体验交互链路设计以及相关指标的定义和数据的回收来达成,优点是会更契合使用场景。

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

