File size: 20,443 Bytes
46b244e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# LLaMA-Factory Function Call训练完整指南

## 1. 同步上游和本地更新代码

### 1.1 同步上游代码
```bash
# 进入LLaMA-Factory目录
cd LLaMA-Factory

# 添加上游仓库(如果还没有添加)
git remote add upstream https://github.com/hiyouga/LLaMA-Factory.git

# 获取上游最新代码
git fetch upstream

# 合并上游代码到本地分支
git merge upstream/main
```

### 1.2 处理冲突
如果出现冲突,需要手动解决冲突后提交:
```bash
# 解决冲突后
git add .
git commit -m "Merge upstream changes"
```

## 2. Dataset使用说明

### 2.1 数据组织结构
自定义数据全部放在 `LLaMA-Factory/data/dataset` 目录下,按照训练日期分割:
```
LLaMA-Factory/data/dataset/
├── 8_29/          # 8月29日的数据
├── 8_30/          # 8月30日的数据
├── 9_10/          # 9月10日的数据
│   └── function_call_data/  # function call数据目录
├── 9_14/          # 9月14日的数据
└── preprocess_dara/  # 数据预处理脚本目录
```

### 2.2 Function Call数据拼接
分散的function_call数据拼接成为多轮对话格式:

**数据位置**:`LLaMA-Factory/data/dataset/9_10/function_call_data/` 中的json数据

**拼接脚本**`LLaMA-Factory/data/dataset/preprocess_dara/convert_to_function_call_format.py`

**重要提示**- 拼接的对话格式中,**偶数轮的信息才能被学习到,奇数轮的信息不能被学习到**
- 在构造hardmatch数据时需要特别注意这个规则
 
**使用示例**```bash
cd /home/ziqiang/LLaMA-Factory/data/dataset/preprocess_dara
python convert_to_function_call_format.py \
    --input_dir ../9_10/raw_data \
    --output_dir ../9_10/function_call_data \
    --output_file function_call_train.json
```

### 2.3 数据合并和格式转换

#### 2.3.1 混合训练数据合并
由于MCP function call使用多轮对话训练集结构,而价格服务部分使用单轮instruction input output格式,混训时需要统一格式。

**脚本**`LLaMA-Factory/data/dataset/preprocess_dara/merge_and_convert_data.py`

**功能**- 将不同格式的数据转换为统一的sharegpt格式
- 自动在dataset_info.json中创建相应条目
- 支持多种数据格式的混合训练

**使用示例**
```bash
python merge_and_convert_data.py \
    --function_call_data ../9_10/function_call_data/function_call_train.json \
    --price_service_data ../9_10/price_service_data.json \
    --output_file ../9_14/mixed_training_data.json \
    --dataset_name mixed_training_data
```

#### 2.3.2 简单JSON文件合并
如果只需要合并不同的JSON文件:

**脚本**`LLaMA-Factory/data/dataset/preprocess_dara/merge_json_files.py`

**使用示例**```bash
python merge_json_files.py \
    --input_files file1.json file2.json file3.json \
    --output_file merged_data.json
```

### 2.4 创建dataset_info.json条目
每次新建dataset进行训练时,需要在 `LLaMA-Factory/data/dataset_info.json` 中创建相应条目。

**自动创建**`merge_and_convert_data.py` 脚本目前支持自动添加条目

**手动创建示例**```json
{
  "mixed_training_data": {
    "file_name": "/home/ziqiang/LLaMA-Factory/data/dataset/9_14/mixed_training_data.json",
    "formatting": "sharegpt",
    "columns": {
      "messages": "conversations",
      "system": "system",
      "tools": "tools"
    }
  }
}
```

## 3. 训练和评估命令

### 3.1 训练命令

#### 3.1.1 基础训练命令
```bash
CUDA_VISIBLE_DEVICES=6 llamafactory-cli train \
    --stage sft \
    --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --preprocessing_num_workers 16 \
    --finetuning_type lora \
    --template qwen3 \
    --flash_attn auto \
    --dataset_dir data \
    --dataset mixed_training_data_09_17 \
    --cutoff_len 8192 \
    --learning_rate 5e-05 \
    --num_train_epochs 5 \
    --max_samples 100000 \
    --per_device_train_batch_size 2 \
    --gradient_accumulation_steps 8 \
    --lr_scheduler_type cosine \
    --max_grad_norm 1.0 \
    --logging_steps 5 \
    --save_steps 100 \
    --warmup_steps 0 \
    --packing False \
    --enable_thinking False \
    --output_dir /home/ziqiang/LLaMA-Factory/saves/Qwen3-8B/lora/train_$(date +%Y-%m-%d-%H-%M) \
    --bf16 True \
    --plot_loss True \
    --trust_remote_code True \
    --ddp_timeout 180000000 \
    --include_num_input_tokens_seen True \
    --optim adamw_torch \
    --lora_rank 8 \
    --lora_alpha 16 \
    --lora_dropout 0 \
    --lora_target all
```

#### 3.1.2 带调试日志的训练命令

```bash
# 将训练日志同时输出到控制台和文件
CUDA_VISIBLE_DEVICES=6,7 llamafactory-cli train \
    --stage sft \
    --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --preprocessing_num_workers 16 \
    --finetuning_type lora \
    --template qwen3 \
    --flash_attn auto \
    --dataset_dir data \
    --dataset mixed_training_data_09_17 \
    --cutoff_len 8192 \
    --learning_rate 5e-05 \
    --num_train_epochs 5 \
    --max_samples 100000 \
    --per_device_train_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --lr_scheduler_type cosine \
    --max_grad_norm 1.0 \
    --logging_steps 5 \
    --save_steps 100 \
    --warmup_steps 0 \
    --packing False \
    --enable_thinking False \
    --output_dir /home/ziqiang/LLaMA-Factory/saves/Qwen3-8B/lora/train_$(date +%Y-%m-%d-%H-%M) \
    --bf16 True \
    --plot_loss True \
    --trust_remote_code True \
    --ddp_timeout 180000000 \
    --include_num_input_tokens_seen True \
    --optim adamw_torch \
    --lora_rank 8 \
    --lora_alpha 16 \
    --lora_dropout 0.1 \
    --lora_target all \
    --gradient_checkpointing True \
    2>&1 | tee token_debug_current.log

CUDA_VISIBLE_DEVICES=6 llamafactory-cli train \
    --stage sft \
    --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --preprocessing_num_workers 16 \
    --finetuning_type lora \
    --template qwen3 \
    --flash_attn auto \
    --dataset_dir data \
    --dataset mixed_training_data_09_17 \
    --cutoff_len 8192 \
    --learning_rate 5e-05 \
    --num_train_epochs 1 \
    --max_samples 100000 \
    --per_device_train_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --lr_scheduler_type cosine \
    --max_grad_norm 1.0 \
    --logging_steps 5 \
    --save_steps 100 \
    --warmup_steps 0 \
    --packing False \
    --enable_thinking False \
    --output_dir /home/ziqiang/LLaMA-Factory/saves/Qwen3-8B/lora/train_$(date +%Y-%m-%d-%H-%M) \
    --bf16 True \
    --plot_loss True \
    --trust_remote_code True \
    --ddp_timeout 180000000 \
    --include_num_input_tokens_seen True \
    --optim adamw_torch \
    --lora_rank 4 \
    --lora_alpha 8 \
    --lora_dropout 0.1 \
    --lora_target all \
    --gradient_checkpointing True \
    2>&1 | tee token_debug_current.log

```

#### 3.1.3 调试Token限制问题的训练命令
```bash
# 使用较小的cutoff_len来观察截断情况
CUDA_VISIBLE_DEVICES=6 llamafactory-cli train \
    --stage sft \
    --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --preprocessing_num_workers 16 \
    --finetuning_type lora \
    --template qwen3 \
    --flash_attn auto \
    --dataset_dir data \
    --dataset mixed_training_data_09_17 \
    --cutoff_len 8192 \
    --learning_rate 5e-05 \
    --num_train_epochs 5 \
    --max_samples 1000 \
    --per_device_train_batch_size 1 \
    --gradient_accumulation_steps 1 \
    --lr_scheduler_type cosine \
    --max_grad_norm 1.0 \
    --logging_steps 1 \
    --save_steps 100 \
    --warmup_steps 0 \
    --packing False \
    --enable_thinking False \
    --output_dir /home/ziqiang/LLaMA-Factory/saves/Qwen3-8B/lora/debug_$(date +%Y-%m-%d-%H-%M) \
    --bf16 True \
    --plot_loss True \
    --trust_remote_code True \
    --ddp_timeout 180000000 \
    --include_num_input_tokens_seen True \
    --optim adamw_torch \
    --lora_rank 8 \
    --lora_alpha 16 \
    --lora_dropout 0 \
    --lora_target all 
```

**重要参数说明**- `--dataset`:指定在dataset_info.json中注册的条目名称
- `--output_dir`:LoRA模型保存位置
- `--enable_thinking`:是否训练模型的think模型
- `--cutoff_len`:Token长度限制,调试时建议使用2048观察截断情况
- `--max_samples`:调试时建议使用较小值(如1000)快速验证
- `2>&1 | tee`:将标准输出和错误输出同时显示在控制台和保存到文件

### 3.2 评估命令
```bash
CUDA_VISIBLE_DEVICES=6 llamafactory-cli train \
    --stage sft \
    --do_predict True \
    --model_name_or_path /data/models/Qwen3-8B \
    --adapter_name_or_path /home/ziqiang/LLaMA-Factory/saves/Qwen3-8B/lora/train_2025-09-14-10-48-context/checkpoint-430 \
    --preprocessing_num_workers 8 \
    --finetuning_type lora \
    --template qwen3 \
    --flash_attn auto \
    --dataset_dir data \
    --eval_dataset test_data \
    --cutoff_len 2048 \
    --per_device_eval_batch_size 8 \
    --predict_with_generate True \
    --max_new_tokens 1024 \
    --do_sample False \
    --temperature 0.0 \
    --top_p 1.0 \
    --bf16 True \
    --trust_remote_code True \
    --output_dir Qwen3-8B/eval_results/9_14
```

**重要参数说明**- `--eval_dataset`:指定在dataset_info.json中注册的测试数据集名称
- `--output_dir`:评估结果保存位置

### 3.3 评估结果分析
评估后会生成 `generated_predictions.jsonl` 文件,包含每条数据的label和predict。

**价格服务评估脚本**`LLaMA-Factory/data/dataset/preprocess_dara/eval_by_field.py`

**使用示例**```bash
python eval_by_field.py \
    --predictions_file Qwen3-8B/eval_results/9_14/generated_predictions.jsonl \
    --output_file eval_results_by_field.json
```

## 4. Function Call训练数据的Loss Mask机制详解

### 4.1 数据转换过程

#### 原始对话数据:
```json
{
  "conversations": [
    {"from": "system", "value": "你是一个智能助手..."},
    {"from": "human", "value": "报表编号H20250611的收入类型分布情况能分析一下吗?"},
    {"from": "function_call", "value": "{\"name\": \"analyze_revenue_by_type\", \"arguments\": {...}}"},
    {"from": "observation", "value": "工具返回的结果..."},
    {"from": "gpt", "value": "<answer>根据分析结果...</answer>"}
  ]
}
```

#### 转换为Token序列:
```
<|im_start|>system
你是一个智能助手...
<|im_end|>
<|im_start|>user
报表编号H20250611的收入类型分布情况能分析一下吗?
<|im_end|>
<|im_start|>assistant
<tool_call>
{"name": "analyze_revenue_by_type", "arguments": {...}}
</tool_call>
<|im_end|>
<|im_start|>user
<tool_response>
工具返回的结果...
</tool_response>
<|im_end|>
<|im_start|>assistant
<answer>根据分析结果...</answer>
<|im_end|>
```

### 4.2 Loss Mask应用

#### Input IDs (完整序列):
```
[系统消息tokens] [用户查询tokens] [工具调用tokens] [工具结果tokens] [最终回答tokens]
```

#### Labels (用于计算loss):
```
[   IGNORE_INDEX   ] [  IGNORE_INDEX  ] [工具调用tokens] [  IGNORE_INDEX  ] [最终回答tokens]
     (不训练)           (不训练)            (训练)          (不训练)           (训练)
```

### 4.3 训练目标

模型学习的目标是:
1. **根据用户查询生成正确的工具调用** - 从用户输入预测function_call部分
2. **根据工具结果生成合适的回答** - 从工具返回结果预测最终答案

模型**不会**学习:
1. 生成工具返回结果(observation部分被mask)
2. 重复用户输入或系统提示

### 4.4 关键代码实现

#### Template中的格式定义:
```python
# Qwen3模板
format_observation=StringFormatter(
    slots=["<|im_start|>user\n<tool_response>\n{{content}}\n</tool_response><|im_end|>\n<|im_start|>assistant\n"]
)
```

#### Loss计算时的mask:
```python
# 在supervised.py中
if self.data_args.train_on_prompt:
    source_label = source_ids
else:
    source_label = [IGNORE_INDEX] * source_len  # 输入部分被mask

# observation部分会被自动识别并mask为IGNORE_INDEX
```

## 5. Token调试日志系统

### 5.1 概述

为了帮助开发者更好地理解和调试ShareGPT格式训练中的token限制问题,我们在关键代码位置添加了详细的调试日志系统。

### 5.2 调试日志类型

#### 5.2.1 [TEMPLATE_DEBUG] - 模板编码阶段
**位置**: `src/llamafactory/data/template.py` 的 `encode_multiturn` 函数

**记录内容**:
- 输入messages数量
- 编码后messages数量  
- 生成的pairs数量和每个pair的token长度

**示例输出**:
```
[TEMPLATE_DEBUG] encode_multiturn开始
[TEMPLATE_DEBUG] 输入messages数量: 6
[TEMPLATE_DEBUG] 编码后messages数量: 6
[TEMPLATE_DEBUG] 生成的pairs数量: 3
[TEMPLATE_DEBUG] Pair 1: source=120 tokens, target=80 tokens
[TEMPLATE_DEBUG] Pair 2: source=1300 tokens, target=50 tokens
[TEMPLATE_DEBUG] Pair 3: source=400 tokens, target=200 tokens
```

#### 5.2.2 [TOKEN_DEBUG] - 数据编码阶段
**位置**: `src/llamafactory/data/processor/supervised.py` 的 `_encode_data_example` 函数

**记录内容**:
- 原始conversations长度
- 编码后的pairs数量
- 每个pair的原始长度和截断后长度
- 剩余预算和累计长度
- 最终结果和使用率

**示例输出**:
```
[TOKEN_DEBUG] 开始处理数据样本
[TOKEN_DEBUG] 原始conversations长度: 6 条消息
[TOKEN_DEBUG] 编码后的pairs数量: 3
[TOKEN_DEBUG] 初始total_length: 0
[TOKEN_DEBUG] cutoff_len: 2048
[TOKEN_DEBUG] === Pair 1 ===
[TOKEN_DEBUG] 原始长度: source=120, target=80
[TOKEN_DEBUG] 剩余预算: 2048
[TOKEN_DEBUG] 截断后长度: source=120->120, target=80->80
[TOKEN_DEBUG] 当前累计长度: 200/2048
[TOKEN_DEBUG] === Pair 2 ===
[TOKEN_DEBUG] 原始长度: source=1300, target=50
[TOKEN_DEBUG] 剩余预算: 1848
[TOKEN_DEBUG] 截断后长度: source=1300->1300, target=50->50
[TOKEN_DEBUG] 当前累计长度: 1550/2048
[TOKEN_DEBUG] === Pair 3 ===
[TOKEN_DEBUG] 原始长度: source=400, target=200
[TOKEN_DEBUG] 剩余预算: 498
[TOKEN_DEBUG] 截断后长度: source=400->298, target=200->200
[TOKEN_DEBUG] ⚠️ source被截断: 102 tokens
[TOKEN_DEBUG] 当前累计长度: 2048/2048
[TOKEN_DEBUG] === 最终结果 ===
[TOKEN_DEBUG] 最终input_ids长度: 2048
[TOKEN_DEBUG] 最终labels长度: 2048
[TOKEN_DEBUG] 最终total_length: 2048
[TOKEN_DEBUG] 使用率: 2048/2048 (100.0%)
[TOKEN_DEBUG] 处理完成
```

#### 5.2.3 [INFER_SEQLEN] - 截断策略阶段
**位置**: `src/llamafactory/data/processor/processor_utils.py` 的 `infer_seqlen` 函数

**记录内容**:
- 截断策略的选择过程
- 输入输出参数
- 具体的截断逻辑

**示例输出**:
```
[INFER_SEQLEN] 输入: source_len=400, target_len=200, cutoff_len=498
[INFER_SEQLEN] 条件1: target_len*2 < cutoff_len (200*2=400 < 498)
[INFER_SEQLEN] 策略1: target完全保留,截断source
[INFER_SEQLEN] 输出: source_len=400->298, target_len=200->200
```

### 5.3 日志查看方法

#### 5.3.1 运行训练并记录日志
```bash
CUDA_VISIBLE_DEVICES=0,1 llamafactory-cli train \
    --stage sft \
    --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --dataset your_dataset \
    --cutoff_len 2048 \
    --output_dir ./debug_output \
    2>&1 | tee debug_train.log
```

#### 5.3.2 过滤特定日志
```bash
# 查看所有token调试日志
grep 'TOKEN_DEBUG' debug_train.log

# 查看截断策略日志
grep 'INFER_SEQLEN' debug_train.log

# 查看模板编码日志
grep 'TEMPLATE_DEBUG' debug_train.log

# 查看截断事件
grep '⚠️' debug_train.log

# 查看使用率统计
grep '使用率:' debug_train.log
```

#### 5.3.3 使用分析脚本
```bash
# 分析日志文件
python analyze_token_logs.py debug_train.log
```

### 5.4 关键指标解读

#### 5.4.1 使用率 (Usage Rate)
- **100%**: 完全使用cutoff_len,可能有截断
- **<100%**: 未完全使用,数据较短
- **>100%**: 不可能出现,检查日志

#### 5.4.2 截断事件
- **source被截断**: 通常是observation内容过长
- **target被截断**: 通常是assistant回复被截断
- **预算耗尽**: 后续pairs被完全丢弃

#### 5.4.3 截断策略
- **策略1**: target完全保留,截断source (target_len * 2 < cutoff_len)
- **策略2**: source完全保留,截断target (source_len * 2 < cutoff_len)  
- **策略3**: 按比例截断source和target

### 5.5 优化建议

基于日志分析结果:

1. **如果observation经常被截断**:
   - 增加cutoff_len到4096或8192
   - 压缩observation内容长度

2. **如果assistant回复被截断**:
   - 这是最严重的问题,必须解决
   - 优先增加cutoff_len

3. **如果使用率很低**:
   - 考虑减少cutoff_len以提高训练效率

4. **如果经常预算耗尽**:
   - 数据过长,需要预处理压缩

### 5.6 日志文件位置

训练过程中的日志会输出到以下位置:

1. **统一调试日志文件**: `token_debug_YYYYMMDD_HHMMSS.log`(自动生成时间戳)
   - 包含所有 `[TOKEN_DEBUG]``[TEMPLATE_DEBUG]``[INFER_SEQLEN]` 日志
   - 自动轮转:文件大小达到50MB时自动创建新文件
   - 自动清理:保留3天的历史日志
   - 异步写入:不影响训练性能

2. **控制台输出**: 直接显示在终端(彩色格式)
3. **重定向文件**: 如果使用 `tee` 命令,会保存到指定文件
4. **训练日志**: 在 `output_dir` 目录下的 `trainer_log.jsonl` 文件
5. **系统日志**: 根据系统配置,可能输出到 `/var/log/` 或其他位置

**推荐做法**:
```bash
# 将日志同时输出到控制台和文件
CUDA_VISIBLE_DEVICES=0,1 llamafactory-cli train [参数] 2>&1 | tee training_$(date +%Y%m%d_%H%M%S).log

# 或者只保存到文件
CUDA_VISIBLE_DEVICES=0,1 llamafactory-cli train [参数] > training.log 2>&1
```

**查看统一调试日志**:
```bash
# 实时查看调试日志
tail -f token_debug_*.log

# 过滤特定类型的调试信息
grep "TOKEN_DEBUG" token_debug_*.log
grep "TEMPLATE_DEBUG" token_debug_*.log  
grep "INFER_SEQLEN" token_debug_*.log

# 查看截断事件
grep "截断" token_debug_*.log

# 统计使用率
grep "使用率" token_debug_*.log | tail -10
```

### 5.7 注意事项

1. **性能影响**: 调试日志会增加训练时间,建议只在调试时使用
2. **日志量**: 日志量较大,建议重定向到文件
3. **生产环境**: 生产环境建议移除或注释掉调试日志
4. **存储空间**: 长时间训练会产生大量日志,注意磁盘空间

## 6. 快速参考

### 6.1 常用调试命令

```bash
# 快速调试token截断问题
CUDA_VISIBLE_DEVICES=6 llamafactory-cli train \
    --stage sft --do_train True \
    --model_name_or_path /data/models/Qwen3-8B \
    --dataset your_dataset --cutoff_len 2048 \
    --max_samples 100 --num_train_epochs 1 \
    --output_dir ./debug_output \
    2>&1 | tee debug.log

# 查看截断事件
grep '⚠️' debug.log

# 查看使用率统计
grep '使用率:' debug.log

# 分析日志
python analyze_token_logs.py debug.log
```

### 6.2 日志文件位置总结

| 日志类型 | 位置 | 说明 |
|---------|------|------|
| **统一调试日志** | `token_debug_*.log` | 包含所有`[TOKEN_DEBUG]`等标记的调试信息 |
| **控制台输出** | 终端 | 实时显示,训练时可见 |
| **重定向文件** | `training_*.log` | 使用`tee`命令保存的完整日志 |
| **训练日志** | `output_dir/trainer_log.jsonl` | LLaMA-Factory生成的训练日志 |

### 6.3 关键文件路径

```
LLaMA-Factory/
├── src/llamafactory/data/
│   ├── processor/supervised.py          # TOKEN_DEBUG日志
│   ├── processor/processor_utils.py     # INFER_SEQLEN日志
│   └── template.py                      # TEMPLATE_DEBUG日志
├── configure_token_logs.py              # 日志配置脚本
├── token_debug_*.log                    # 统一调试日志文件
├── test_token_debug.py                  # 测试脚本
├── analyze_token_logs.py                # 日志分析脚本
└── TOKEN_DEBUG_README.md                # 快速使用指南
```

### 6.4 故障排除

| 问题 | 可能原因 | 解决方案 |
|------|----------|----------|
| 日志不显示 | 日志级别设置 | 检查logging配置 |
| 截断频繁 | cutoff_len太小 | 增加cutoff_len到4096或8192 |
| 使用率低 | 数据过短 | 考虑减少cutoff_len |
| 训练效果差 | assistant被截断 | 优先解决截断问题 |