novel-agent微调教程

novel-agent微调教程

1. 微调的场景与目标

1.1 场景

现有长篇中文小说 Agent 虽然通过提示词约束去除 AI 腔,但生成章节中仍会出现模板化句式、空泛心理描写、机械转折和过度解释等问题。

  • 仅仅通过提示词工程的约束无法完全消除AI味的句子的生成。

1.2 目标

因此计划使用 Qwen3-8B,在 A10 22GB GPU 上通过 LoRA 微调一个“局部文学编辑器”。它接收目标段落及前后文,只对句子或段落做最小幅度改写:

  • 去除明显 AI 腔;
  • 保持人物、剧情、时间、数字、境界、道具和因果关系不变;
  • 不新增剧情、不续写、不解释;
  • 原文自然时保持原样。
    最终目标是把它接入现有小说生成流程,在章节生成后对高风险段落进行局部润色,使成稿更自然、更像人工写作,同时不破坏长篇小说的一致性。

1.3 现在已有的可以解决该问题的技术

A. 使用skill去AI味:

humanizer

Humanizer 是一款面向 Claude Code / OpenCode 环境的开源 Skill 插件,核心作用是识别并消除 AI 生成文本中的典型写作痕迹,将文本改写得更自然、更贴近人类真实写作风格。

局限性

  • 本质是规则化指令工程,存在效果天花板:属于Skill 级别的指令工程
  • 场景偏向通用非虚构文本,文学创作适配性极差:完全没有覆盖小说、散文等文学体裁的典型 AI 问题
  • 原生仅适配英文,中文场景效果大幅打折

B. 现有微调模型去AI味

魔搭社区官方发布过《我们给大模型去掉了 “AI 味”》实战教程:

我们给大模型去掉了“AI味”-大模型微调全链路实战

  • 基于 LoRA 技术微调大模型,让输出文本减少标准化 AI 腔,更贴近人类口语 / 写作风格
  • 教程实测微调后模型的 AI 感明显降低

局限性

  • 训练目标是通用评论风格,不是小说场景的局部改写,也不做 “事实不变” 约束
  • 训练的数据集不贴合网文写作的内容

Qwen 系列网文写作 LoRA:基于 Qwen2/Qwen3 基座微调,覆盖男频、女频、玄幻、现实等题材,训练数据为优质人类网文正文,能让生成文本更符合网文叙事节奏,减少通用 AI 的书面化腔调和空泛描写。

1.4 微调模型 vs 中文大模型

只针对段落为整体的内容进行改写

微调模型不一定要比先进大模型“写得更好”,它的价值可以是更便宜、更稳定、更快、更可控。

2. 选择微调框架

这里使用的是LlamaFactory大模型微调框架

LlamaFactory

3. 选择微调的基础模型

最终选择:

  1. 使用Qwen/Qwen3-8B

资源限制

  1. 受制于硬件GPU显存等的限制,这里最多选择一个7b参数量左右的小模型
  2. 因为写的小说是中文网文,所以最好选择中文模型

选型优点

  1. 中文能力和中文网文表达较稳定;
  2. 是Instruct模型,指令遵循能力比 Base 模型好,适合“只改写目标段落、不能改变事实”;
  3. 文本理解能力比qwen2.5-7b-instruct更强
  4. 你的任务不是从零创作,而是“理解上下文后做局部编辑”,8B 足够
  5. ModelScope、Transformers、ms-swift 生态成熟;支持 LoRA/QLoRA;

4. 数据集的构造

4.1 Alpaca 格式

在指令监督微调时,instruction 列对应的内容会与 input 列对应的内容拼接后作为提示词,即提示词为 instruction\ninput。而 output 列对应的内容为模型回答。

如果指定,system 列对应的内容将被作为系统提示词。

1
2
3
4
5
6
7
8
[
{
"instruction": "用户指令(必填)",
"input": "用户输入(选填)",
"output": "模型回答(必填)",
"system": "系统提示词(选填)",
}
]

对于上述格式的数据,dataset_info.json 中的数据集描述应为:

1
2
3
4
5
6
7
8
9
10
"数据集名称": {
"file_name": "data.json",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output",
"system": "system",
"history": "history"
}
}

具体构造数据集示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

[
{
"system": "你是中文网文局部编辑器。只改写表达,不得改变剧情事实、人物关系、时间、数字、专名、叙事视角和对白归属。原文自然时保持原样。只输出处理后的文本,不解释。",
"instruction": "去除空泛心理描写,改为更自然、克制的表达。",
"input": "这一刻,他的心中不由得涌现出了一股复杂的情绪。",
"output": "复杂的情绪在他心头翻涌。"
},
{
"system": "你是中文网文局部编辑器。只改写表达,不得改变剧情事实、人物关系、时间、数字、专名、叙事视角和对白归属。原文自然时保持原样。只输出处理后的文本,不解释。",
"instruction": "删除冗余表达,保持原意不变。",
"input": "他缓缓地抬起了自己的右手,然后轻轻地擦拭了一下嘴角的鲜血。",
"output": "他抬起右手,擦掉嘴角的血。"
},
{
"system": "你是中文网文局部编辑器。只改写表达,不得改变剧情事实、人物关系、时间、数字、专名、叙事视角和对白归属。原文自然时保持原样。只输出处理后的文本,不解释。",
"instruction": "如果原文已经自然,不做任何修改。",
"input": "陈默把伞搁在门后,鞋底在门槛上蹭了两下。",
"output": "陈默把伞搁在门后,鞋底在门槛上蹭了两下。"
}
]

4.2 数据集格式的建议

  1. system固定,instruction尽量短一些
  2. input的文本长度(这个尽量对应后续真实改写时的上下文长度)
    • 70%:单句、短句改写
    • 30%:几百字段落改写样本,平衡长短,防止模型只会输出短句
  3. 加入原样保留样本,必须占比30%左右: input和output一样
  4. 训练和实际推理的输入形式必须一致
  5. system固定写入硬约束:不得改变事实、不得改变剧情、不得改变专名和数字等
  6. instruction 最好使用有限、稳定的几类要求
    • 去除空泛心理描写
    • 删除重复动作
    • 减少机械转折
    • 压缩解释性句子
    • 让对白更自然
    • 调整句子节奏
    • 保留原文,不做修改
  7. input中的文本必须完整
    • 完整的一句话
    • 完整的几句话
    • 完整的一个段落

4.3 第一版数据集构造格式示例

  • system和instruction都固定
  • input是输入的原文内容
  • output是润色改写后的文章内容
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "这一刻,他的心中不由得涌现出了一股复杂的情绪。",
"output": "此刻复杂的情绪在他的心头翻涌。"
}

{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "雨水顺着屋檐滴下来,砸在青石板上。",
"output": "雨水顺着屋檐滴下来,砸在青石板上。"
}

4.4 数据集常见问题的解决方案

A. 数据量:先做小规模高质量数据

1000->3000->5000

分阶段:

1
2
3
第一轮验证:1000 条左右
正式训练:3000~5000 条
多题材、多风格:8000~10000 条以上

B. 样本比例

第一轮 1000 条可以这样分:

  1. 需要改写:700 条
  2. 原样保留:300 条

改写样本内部再覆盖这些问题,并且这些问题需要是平均的:

1
2
3
4
5
6
7
空泛心理描写
重复动作
机械转折
解释性复述
模板化收尾
不自然对白
句子节奏问题

C. 样本偏差:长度和内容要接近真实使用场景

最重要的是,训练集要接近未来真实输入
网文小说的特点就是以段落为一个整体内容

长度比例:

  • 80%:完整段落
  • 20%:单独句子或几个短句

D. 多样性:针对多种题材的网文内容

不仅要支持历史小说、还支持玄幻、都市、言情等题材的小说

增加多来源、多题材数据。 至少覆盖现代都市、玄幻、科幻、悬疑、言情、轻松对白、第一人称和不同叙述密度,避免把任务等同于“古风化”。

4.5 最终生成的数据集

前10条展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
[
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "第一声闷响从地底下炸开,然后是第二声,紧接着是两声几乎叠在一起。泥块和碎木飞起来,火药爆炸的气浪带着呛人的硫磺味灌进隘口,两道排栅从根部整个被掀起来,木桩断裂的咔嚓声尖锐刺耳,塌下来的栅栏砸在篝火堆上,火星溅得满天都是。",
"output": "第一声闷响从地底下炸开,然后是第二声,紧接着是几乎叠在了一起的两声。泥块和碎木都飞了起来,火药爆炸的气浪带着呛人的硫磺味灌进隘口,两道排栅从根部整个被掀起来,木桩断裂的咔嚓声尖锐刺耳,塌下来的栅栏砸在篝火堆上,火星溅得四处都是。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "戍卒们围拢过来,七嘴八舌,又惊又喜。田埂一夜活下来的,疫病七日捡回命的,昨夜火光里拼杀的——这些日子,一点一点,全攒在这一刻里。从那个连戈都握不稳的李二,到执掌一屯的屯长,不过月余。",
"output": "戍卒们围拢了过来,七嘴八舌,又惊又喜。田埂那一夜活下来的,疫病七日中捡回命的,昨夜火光里拼杀的——这些日子,一点一点,全攒在这一刻里。从那个连戈都握不稳的李二,到如今执掌一屯的屯长,不过月余。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "“军功。”李恒吐出两个字,“《军爵律》怎么写的,什长比我清楚——斩首一级,赐爵一级。立功可抵罪,斩首三级者,抵一死罪而有余。”",
"output": "“军功。”李恒吐出两个字,“《军爵律》怎么写的,什长们应该比我清楚,斩首一级,则赐爵一级。立功可抵罪,斩首三级者,抵一死罪而有余。”"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "赵佗在等中原的乱。他也在等。史册里那几页模糊的字——始皇崩,二世立,陈胜吴广揭竿,楚汉相争,血流成河——那是别人的劫数,是他抢窗口、攒力气的天时。",
"output": "赵佗在等中原之乱,他也在等。史册里记录下来的史实——始皇崩,二世立,陈胜吴广揭竿,楚汉相争,血流成河。正是他崛起的好时刻。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "而眼前这个会打仗、会种地、会聚人心的屯长,是他这盘棋里,一颗刚刚被他看见的、有点意思的子。",
"output": "而眼前这个会打仗、会种地、会笼络人心的屯长,是他的这盘棋里一颗刚刚被他看到的有点意思的子。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "严某脸上的笑意淡了些。他确实有那册子,记得分毫不差,正是周吏誊送来的。李恒这一说,等于把他预备拿来发难的“私”字,先卸了一半——账目公开,记录在册,哪里“私”了?",
"output": "严某脸上的笑意淡了些。他确实有那册子,正是周吏誊送来的。李恒这一说,等于把他预备拿来发难的“私”字先卸了一半——账目公开并且记录在册,哪里“私”了?"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "天光大亮时,他撑着戈,挨个清点。",
"output": "天光大亮时,他撑着戈,挨个清点。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "而此刻他趴在这里,另一个秦烈的记忆也叠了进来——松山参将麾下总旗官,年二十五,陕西延安卫人,崇祯十二年从军,随洪承畴出关,打过锦州,最后困在松山。昨夜突围时被清军截杀,身边的弟兄全打光了,他自己背部中箭,摔下马背,被尸体压住。",
"output": "而此刻他趴在这里,另一个秦烈的记忆也叠了进来——松山参将麾下总旗官,年二十五,陕西延安卫人,崇祯十二年从军,随洪承畴出关,打过锦州,最后困在松山。昨夜突围时被清军截杀,身边的弟兄全打光了,他自己背部中箭,摔下马背,被尸体压住。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "北边、西边,凡车上了水的田,打蔫的禾苗,正一寸一寸缓过来。叶子返青,茎秆挺直,蔫黄褪尽。一片本要枯死的苗,被那昼夜不停的水车,从死里拽了回来。",
"output": "北边、西边,但凡水车浇灌过的田地,打蔫的禾苗正一寸寸缓过劲来。叶片渐渐返青,茎秆挺直如初,枯黄的色泽尽数褪去。这片原本即将枯死的禾苗,全靠昼夜不停运转的水车,从绝境里硬生生捞了回来。"
},
{
"system": "你是中文网络小说局部编辑器。仅修改语言表达,不得新增、遗漏或改变任何事实信息,包括剧情、人物关系、专名、数字、时间、地点、境界、道具、因果关系和对白归属。不得续写、扩写或解释。只输出可以直接替换原文的最终文本。",
"instruction": "请对以下文本进行最小必要的去AI腔改写;仅在确有必要时修改,原文自然则保持原样。",
"input": "黑石口的隘口窄,清军扎的营栅不是砖石墙,是粗木桩打进地里、横闩藤条捆扎的排栅。这种栅栏防人攀爬没问题,但有个毛病——底下的桩根吃土不深。",
"output": "黑石口隘口地势狭窄,清军修筑的营栅并非砖石墙体,而是将粗木桩打入地底,再以藤条横捆加固的排栅。这类营栅足以防备人攀爬,却有一处短板——地底的桩根扎得并不深。"
}
]

5. 微调训练

下载llamafactory环境

1
2
3
4
5
6
7
8
cd /mnt/workspace/LlamaFactory



python -m pip install -e .
python -m pip install -r requirements/metrics.txt

hash -r

对话命令(非思考型):

1
2
3
4
5
llamafactory-cli chat \
--model_name_or_path /mnt/workspace/models/Qwen3-8B \
--template qwen3 \
--enable_thinking false \
--infer_backend huggingface

训练参数(qwen3_8b_ai_style_qlora_full.yaml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
### model
model_name_or_path: /mnt/workspace/models/Qwen3-8B
trust_remote_code: true
quantization_bit: 4
quantization_method: bitsandbytes
upcast_layernorm: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset
dataset: ai_style_editing
dataset_dir: /mnt/workspace/LlamaFactory/data
template: qwen3
enable_thinking: false
cutoff_len: 1024
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 4
dataloader_num_workers: 2

### output
output_dir: /mnt/workspace/LlamaFactory/saves/qwen3-8b/lora/ai_style_full
logging_steps: 10
save_steps: 100
save_total_limit: 3
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_steps: 38
bf16: true
gradient_checkpointing: true
ddp_timeout: 180000000
resume_from_checkpoint: null

正式训练命令:

1
2
3
4
5
cd /mnt/workspace/LlamaFactory

CUDA_VISIBLE_DEVICES=0 \
llamafactory-cli train \
/mnt/workspace/LlamaFactory/qwen3_8b_ai_style_qlora_full.yaml

训练完成之后对话命令:

1
2
3
4
5
6
llamafactory-cli chat \
--model_name_or_path /mnt/workspace/models/Qwen3-8B \
--adapter_name_or_path /mnt/workspace/LlamaFactory/saves/qwen3-8b/lora/ai_style_full \
--template qwen3 \
--no_enable_thinking \
--infer_backend huggingface

6. 测试模型

在 data/dataset_info.json 注册:

1
2
3
4
5
6
7
8
9
10
"ai_style_editing_test": {
"file_name": "ai_style_editing/test.json",
"formatting": "alpaca",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output",
"system": "system"
}
}

测试模型命令的yaml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
### model
model_name_or_path: /mnt/workspace/models/Qwen3-8B
adapter_name_or_path: /mnt/workspace/LlamaFactory/saves/qwen3-8b/lora/ai_style_full
trust_remote_code: true
quantization_bit: 4
quantization_method: bnb

### method
stage: sft
do_train: false
do_eval: false
do_predict: true
finetuning_type: lora

### dataset
eval_dataset: ai_style_editing_test
dataset_dir: /mnt/workspace/LlamaFactory/data
template: qwen3
enable_thinking: false
cutoff_len: 1024
max_samples: 100
overwrite_cache: true
preprocessing_num_workers: 4

### output
output_dir: /mnt/workspace/LlamaFactory/saves/qwen3-8b/lora/ai_style_test_predictions
overwrite_output_dir: true
report_to: none

### predict
per_device_eval_batch_size: 1
predict_with_generate: true
do_sample: false
max_new_tokens: 1024

执行测试命令:

1
2
3
CUDA_VISIBLE_DEVICES=0 \
llamafactory-cli train \
/mnt/workspace/LlamaFactory/qwen3_8b_ai_style_predict.yaml

7. 部署模型

7.1 合并模型

合并原始模型Qwen3-8B和lora训练好的adapter

合并模型的参数配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
### model
model_name_or_path: /mnt/workspace/models/Qwen3-8B
adapter_name_or_path: /mnt/workspace/LlamaFactory/saves/qwen3-8b/lora/ai_style_full
trust_remote_code: true

### method
finetuning_type: lora

### dataset
template: qwen3

### export
export_dir: /mnt/workspace/models/Qwen3-8B-ai-style-merged
export_size: 4
export_device: cpu
export_legacy_format: false

合并的命令:

1
2
llamafactory-cli export \
/mnt/workspace/LlamaFactory/qwen3_8b_ai_style_export.yaml

合并后模型的产物:

1
2
3
4
5
6
7
8
9
10
11
12
Qwen3-8B-ai-style-merged/
├── chat_template.jinja
├── config.json
├── generation_config.json
├── model-00001-of-00005.safetensors
├── model-00002-of-00005.safetensors
├── model-00003-of-00005.safetensors
├── model-00004-of-00005.safetensors
├── model-00005-of-00005.safetensors
├── model.safetensors.index.json
├── tokenizer_config.json
└── tokenizer.json

7.2 将 Hugging Face 模型转换为 F16 GGUF

Tokenizer 修复并验证通过后,重新执行转换:

1
2
3
4
5
6
cd /mnt/workspace/llama.cpp

python convert_hf_to_gguf.py \
/mnt/workspace/models/Qwen3-8B-ai-style-merged \
--outfile /mnt/workspace/Qwen3-8B-ai-style-F16.gguf \
--outtype f16

完成后检查:

1
ls -lh /mnt/workspace/Qwen3-8B-ai-style-F16.gguf

本次生成的 F16 GGUF 约 16 GB。F16 文件主要作为量化输入,不适合直接在 16 GB 内存的 M1 Mac 上运行。

7.3 编译 llama.cpp 并执行 Q4_K_M 量化

执行 Q4_K_M 量化:

1
2
3
4
./build/bin/llama-quantize \
/mnt/workspace/Qwen3-8B-ai-style-F16.gguf \
/mnt/workspace/Qwen3-8B-ai-style-Q4_K_M.gguf \
Q4_K_M

本次量化统计:

1
2
3
4
张量进度:399 / 399
原始模型大小:15623.18 MiB,16.00 BPW
量化模型大小:4789.19 MiB,4.90 BPW
量化耗时:963056.87 ms,约 16 分钟

最终文件:

1
2
/mnt/workspace/Qwen3-8B-ai-style-F16.gguf       约 16 GB
/mnt/workspace/Qwen3-8B-ai-style-Q4_K_M.gguf 约 4.7 GB

7.4 在本地电脑使用微调模型

  1. 从 Notebook 直接下载模型: 最终只需迁移 Q4_K_M 文件;
  2. 在 Apple M1 Mac 上部署 llama.cpp

在本地电脑使用llama.cpp用微调模型进行推理对话

显示思考过程:

1
2
3
4
llama-cli \
-m "/Users/bilibili/Desktop/llm/Qwen3-8B-ai-style-Q4_K_M.gguf" \
-ngl 99 \
-c 4096

隐藏 Qwen3 思考过程:

1
2
3
4
5
llama-cli \
-m "/Users/bilibili/Desktop/llm/Qwen3-8B-ai-style-Q4_K_M.gguf" \
-ngl 99 \
-c 4096 \
--reasoning off

启动本地网页与 API 服务

启动 llama-server:

1
2
3
4
5
6
7
8
9
llama-server \
-m "/Users/bilibili/Desktop/llm/Qwen3-8B-ai-style-Q4_K_M.gguf" \
-ngl 99 \
-c 4096 \
-np 2 \
--host 127.0.0.1 \
--port 8080 \
--alias qwen3-ai-style \
--reasoning off

浏览器访问:

1
http://127.0.0.1:8080

OpenAI 兼容接口:

1
http://127.0.0.1:8080/v1/chat/completions