参考 microsoft/aici
,以简洁易使用的方式实现大语言模型可控生成,能够通过额外的控制信息精确控制模型的生成格式。目前支持 vllm
, transformers
库 。
假设我们要让大语言模型生成一个表单,遵循特定的格式,并且只包含五个元素,例如:
请列举五个摸鱼的方法
通常,需要使用额外的提示词来限制生成的格式:
请列举五个摸鱼方法,仅返回一个列表,不要有多余的解释
然而,大语言模型通常难以稳定地按照提示词的要求生成特定格式的文本,并且提示词可能也会因使用的模型而异,因为每个模型都倾向于以不同的格式输出以及有不同的解释说明。虽然使用 few-shot 通常能解决这个问题,但是 few-shot 会在一定程度上影响模型的输出结果,并且也大幅增加了提示词的长度。
本项目通过在模型生成的过程中动态地插入关键的格式信息,有效地控制模型的输出格式,具体有以下功能:
- 防止模型在开头添加解释
- 控制表单的格式(如:1. 2. 3. 或 i. ii. iii. 或 a. b. c. )
- 控制模型返回的表单的条数
- 防止模型在结尾添加解释
使用 qwen-1.5-14B-Chat-gptq-Int4
进行演示,继续使用上面的问题,并让模型用 a. b. c. d. e.
分点输出结果,输入数据为:
datas = [
{
"messages": [
{"role": "user", "content": "请列举五个摸鱼方法"}
],
"add_stop_char": ['<|llmci_bos|>', '\n', '\n', '\n', '\n', '\n'],
"fixed_content": ['a. ', 'b. ', 'c. ', 'd. ', 'e. ', '<|llmci_eos|>']
}
]
其中,messages
对标 OpenAI 的对话模板,填写由 system
, user
, assistant
组成的对话记录。
add_stop_char
为停止符列表。在模型生成过程中,当 add_stop_char
不为空时,若模型新生成的 token 经过解码后包含 add_stop_char[0]
,则将 fixed_content[0]
中的内容填充到当前生成结果中,然后删除 add_stop_char[0]
与 fixed_content[0]
。<|llmci_bos|>
和 <|llmci_eos|>
都是本项目的特殊标记符,<|llmci_bos|>
用作开头便要添加内容的情况。<|llmci_eos|>
则用于强制终止模型的生成。
在本案例中,由于 add_stop_char[0]
为 <|llmci_bos|>
,因此模型的生成以 a.
开头,然后模型继续生成,直到生成了包含 \n
的 token,便会在生成结果中追加 b.
,然后继续生成。当遇到最后一个 \n
时,<|llmci_eos|>
会被自动替换为模型的 eos_token
并追加到生成结果中,以强迫模型结束生成。
完整示例代码如下:
from vllm_llmci import VllmLLMci
# qwen-1.5 config
model_path = r'Qwen/Qwen1.5-14B-Chat-GPTQ-Int4'
lora_path = None
generation_config = {
"stop_token_ids": [151645, 151643],
"max_tokens": 1024,
"top_p": 0.8,
"top_k": 20,
"temperature": 0.95, # 0.95
"repetition_penalty": 1.05,
"use_beam_search": False,
}
model = VllmLLMci(model_path, model_path, generation_config, lora_path, gpu_memory_utilization=0.80)
datas = [
{
"messages": [
{"role": "user", "content": "请列举五个摸鱼方法"}
],
"add_stop_char": ['<|llmci_bos|>', '\n', '\n', '\n', '\n', '\n'],
"fixed_content": ['a. ', 'b. ', 'c. ', 'd. ', 'e. ', '<|llmci_eos|>']
}
]
outputs = model.generate(datas)
for output in zip(*outputs):
print(output[0])
print(f'output tokens: {output[1]}\n')
模型输出:
a. 伪装工作:假装在进行线上会议或者处理工作邮件,但实际上是在后台浏览无关紧要的网页或社交媒体。
b. 创造虚拟任务:将一些非紧急或不重要的事情标记为优先级高的任务,以制造忙碌的假象。
c. 长时间短暂休息:频繁使用休息、喝水或上厕所等借口离开座位,降低实际工作时间。
d. 分散注意力:参与看似与工作相关的讨论或活动,实则消耗时间,例如闲聊、玩桌游或组织小型团建活动。
e. 模拟高效:使用番茄工作法或其他时间管理技巧,看似在集中工作,实际上利用间隙偷偷休息或处理私事。
output tokens: 148
结果生成了5条方法建议,符合要求
-
参考
vllm-project/vllm
的文档Installation
安装vllm -
使用
vllm_llmci.py
中的VllmLLMci
类即可加载 vllm 支持的任意模型,模型参数设置以及数据输入格式请参考 示例 。更多示例详见vllm_llmci_demo.py
-
vllm 的开发是基于
vllm==0.4.1
版本,我仅替换了llm.llm_engine.output_processor
的_process_sequence_group_outputs
函数 -
目前不支持
beam_search
-
目前支持
transformers>=4.38.0
的版本 (2024/04/30) -
使用
transformers_llmci.py
中的TransformersLLMci
类即可加载 transformers 支持的任意模型,模型参数设置以及数据输入格式详见transformers_llmci_demo.py
-
transformers 的开发是基于
transformers
的4.38.0
以及4.40.1
版本 -
目前仅支持
sample
方法
- 支持 vllm 的 Beam search case 的格式控制
- 支持 transformers 的 LLMCI(仅 sample 方法)
- 支持 transformers 除 sample 外其他方法的 LLMCI(有生之年系列)
- 跟进 transformers 以及 vllm 库的更新(如果有人需要的话 0.0)
- 同步一个英文版 README