失败是成功之母:利用负样本增强少样本上下文学习

失败是成功之母:利用负样本增强少样本上下文学习

ArXiv ID: 2507.23211
作者: Yunhao Liang, Ruixuan Ying, Takuya Taniguchi, Zhe Cui
机构: Zhejiang University, HIT
发布日期: 2025-07-31


摘要

大型语言模型展现出强大的少样本上下文学习(ICL)能力,但性能对提供的示例高度敏感。最近的研究主要集中在为每个查询检索正样本示例,忽略了负样本(导致错误预测的示例)的额外信息。本文提出利用负样本更好地选择正样本示例,通过分析负样本的特征识别导致失败的模式,从而选择更具代表性和互补性的正样本。实验表明,结合负样本信息的方法比仅使用正样本提升**12-18%**的准确率。


问题背景

少样本上下文学习的挑战

1
2
3
4
5
6
7
8
9
10
11
12
13
传统 ICL 示例选择方法:

正样本方法:
查询:"这部电影太棒了,我给 5 星!"
检索相似正样本:
✓ "剧情精彩,演技出色,强烈推荐!" → 正面
✓ "非常棒的观影体验!" → 正面
✓ "超级好看,值得二刷!" → 正面

问题:
- 所有示例都是正面的
- 模型无法学习边界情况
- 遇到否定句仍可能出错

核心洞察

  • 正样本告诉模型”应该是什么”
  • 负样本告诉模型”不應該是什么”
  • 两者结合才能学习完整概念

负样本的价值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
负样本示例:

查询:"这部电影太棒了,我给 5 星!"

负样本分析:
✗ "太棒了不是吗?" → 疑问句(模型误判为正面)
✗ "棒得让人失望" → 反讽(模型误判为正面)
✗ "不算太棒" → 否定词(模型误判为正面)

失败模式识别:
1. 疑问句处理薄弱
2. 反讽检测能力不足
3. 否定词理解有误

针对性正样本选择:
✓ "这部电影太棒了!"(陈述句,清晰正面)
✓ "虽然...但是太棒了"(转折句,仍为正面)
✓ "不是不好看,是太棒了"(双重否定,正面)

方法

整体流程

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
┌─────────────────────────────────────────────────────────┐
│ Negative-Sample Enhanced ICL │
│ │
│ 步骤 1: 识别负样本 │
│ ┌─────────────────┐ │
│ │ 初始推理测试 │ │
│ │ 在验证集上运行 │ → 收集预测错误样本 │
│ └─────────────────┘ │
│ ↓ │
│ 步骤 2: 分析负样本特征 │
│ ┌─────────────────┐ │
│ │ 失败模式聚类 │ │
│ │ - 句型特征 │ → 识别薄弱点 │
│ │ - 语义特征 │ │
│ │ - 词汇特征 │ │
│ └─────────────────┘ │
│ ↓ │
│ 步骤 3: 基于负样本选择正样本 │
│ ┌─────────────────┐ │
│ │ 互补性选择 │ │
│ │ 覆盖失败模式 │ → 选择针对性正样本 │
│ │ 避免相似陷阱 │ │
│ └─────────────────┘ │
│ ↓ │
│ 步骤 4: 构建 ICL Prompt │
│ ┌─────────────────┐ │
│ │ 正样本 + 负样本 │ → 增强少样本学习 │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘

步骤 1:负样本识别

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
import torch
from typing import List, Dict, Tuple

class NegativeSampleMiner:
"""负样本挖掘器"""

def __init__(self, model, tokenizer):
self.model = model
self.tokenizer = tokenizer

def mine_negatives(self, validation_set: List[Dict]) -> List[Dict]:
"""
从验证集中挖掘负样本

负样本定义:模型预测错误的样本
"""
negatives = []

for sample in validation_set:
# 运行推理
prediction = self.predict(sample['input'])
ground_truth = sample['label']

# 检查是否正确
if prediction != ground_truth:
negatives.append({
'input': sample['input'],
'true_label': ground_truth,
'predicted_label': prediction,
'confidence': self._get_confidence(sample['input']),
'error_type': self._classify_error(prediction, ground_truth)
})

return negatives

def predict(self, input_text: str) -> str:
"""模型预测"""
prompt = f"Input: {input_text}\nLabel:"
inputs = self.tokenizer.encode(prompt, return_tensors="pt")
outputs = self.model.generate(inputs, max_new_tokens=10)
prediction = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
return prediction.split("Label:")[-1].strip()

def _classify_error(self, pred: str, true: str) -> str:
"""分类错误类型"""
# 示例:情感分析错误类型
if pred == "positive" and true == "negative":
return "false_positive"
elif pred == "negative" and true == "positive":
return "false_negative"
return "unknown"

步骤 2:失败模式分析

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
class FailurePatternAnalyzer:
"""失败模式分析器"""

def __init__(self, negatives: List[Dict]):
self.negatives = negatives

def analyze_patterns(self) -> Dict:
"""
分析失败模式

返回:
{
"pattern_type": {
"description": "...",
"count": N,
"examples": [...],
"severity": 0.0-1.0
}
}
"""
patterns = {}

# 1. 句型模式分析
patterns['sentence_structure'] = self._analyze_structure_patterns()

# 2. 词汇模式分析
patterns['lexical_patterns'] = self._analyze_lexical_patterns()

# 3. 语义模式分析
patterns['semantic_patterns'] = self._analyze_semantic_patterns()

return patterns

def _analyze_structure_patterns(self) -> Dict:
"""分析句型模式"""
structure_failures = {
'interrogative': [], # 疑问句
'negative': [], # 否定句
'ironic': [], # 反讽句
'complex': [], # 复杂句
'simple': [] # 简单句
}

for neg in self.negatives:
input_text = neg['input']

# 分类句型
if '?' in input_text or input_text.startswith('Did') or input_text.startswith('Is'):
structure_failures['interrogative'].append(neg)
elif 'not' in input_text.lower() or '不' in input_text:
structure_failures['negative'].append(neg)
elif self._detect_irony(input_text):
structure_failures['ironic'].append(neg)
elif len(input_text.split()) > 20:
structure_failures['complex'].append(neg)
else:
structure_failures['simple'].append(neg)

# 计算各句型失败率
failure_rates = {}
for structure, samples in structure_failures.items():
failure_rates[structure] = {
'count': len(samples),
'severity': len(samples) / max(1, len(self.negatives)),
'examples': samples[:3] # 保留 3 个示例
}

return failure_rates

def _detect_irony(self, text: str) -> bool:
"""检测反讽(简化版)"""
irony_markers = ['呵呵', '真是', '太好了', 'sure', 'right']
return any(marker in text for marker in irony_markers)

def _analyze_lexical_patterns(self) -> Dict:
"""分析词汇模式"""
# 提取高频错误词
word_freq = {}
for neg in self.negatives:
words = neg['input'].lower().split()
for word in words:
word_freq[word] = word_freq.get(word, 0) + 1

# 返回 top 错误词
top_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:10]
return {'error_prone_words': top_words}

步骤 3:基于负样本的正样本选择

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
class NegativeGuidedSelector:
"""负样本指导的正样本选择器"""

def __init__(self, positives: List[Dict], negatives: List[Dict]):
self.positives = positives
self.negatives = negatives
self.patterns = FailurePatternAnalyzer(negatives).analyze_patterns()

def select_positive_samples(self, query: str, k: int = 5) -> List[Dict]:
"""
为查询选择 k 个正样本

策略:
1. 覆盖失败模式
2. 最大化互补性
3. 避免相似陷阱
"""
selected = []

# 1. 分析查询特征
query_features = self._extract_features(query)

# 2. 识别相关失败模式
relevant_failures = self._find_relevant_failures(query_features)

# 3. 为每个失败模式选择覆盖的正样本
for failure_type in relevant_failures:
# 找到能覆盖此失败模式的正样本
covering_samples = self._find_covering_samples(failure_type)
selected.extend(covering_samples[:2]) # 每个模式选 2 个

# 4. 补充剩余位置(按相似度)
remaining = k - len(selected)
if remaining > 0:
similar = self._find_similar_samples(query, remaining)
selected.extend(similar)

return selected[:k]

def _find_covering_samples(self, failure_type: str) -> List[Dict]:
"""找到能覆盖特定失败模式的正样本"""
covering = []

for pos in self.positives:
# 检查正样本是否能覆盖此失败模式
if self._covers_failure(pos, failure_type):
covering.append(pos)

return covering

def _covers_failure(self, positive: Dict, failure_type: str) -> bool:
"""检查正样本是否覆盖失败模式"""
# 示例:如果失败模式是"疑问句"
# 则选择"疑问句 + 正确答案"的正样本
pos_features = self._extract_features(positive['input'])

if failure_type == 'interrogative' and '?' in pos_features['structure']:
return True
if failure_type == 'negative' and pos_features['has_negation']:
return True

return False

def _extract_features(self, text: str) -> Dict:
"""提取文本特征"""
return {
'length': len(text),
'structure': self._classify_structure(text),
'has_negation': 'not' in text.lower() or '不' in text,
'sentiment_words': self._count_sentiment_words(text)
}

步骤 4:ICL Prompt 构建

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
def build_enhanced_icl_prompt(query: str, positives: List[Dict],
negatives: List[Dict] = None) -> str:
"""
构建增强的 ICL Prompt

可选格式:
1. 仅正样本(传统)
2. 正样本 + 负样本对比
"""

if negatives is None:
# 传统格式
prompt = "请学习以下示例:\n\n"
for i, pos in enumerate(positives, 1):
prompt += f"示例 {i}:\n"
prompt += f"输入:{pos['input']}\n"
prompt += f"输出:{pos['label']}\n\n"
else:
# 对比格式
prompt = "请学习以下示例,注意正负样本的区别:\n\n"

# 先展示负样本(错误示范)
for i, neg in enumerate(negatives[:2], 1):
prompt += f"❌ 错误示例 {i}:\n"
prompt += f"输入:{neg['input']}\n"
prompt += f"(注意:这类句子容易误判)\n\n"

# 再展示正样本(正确示范)
for i, pos in enumerate(positives, 1):
prompt += f"✓ 正确示例 {i}:\n"
prompt += f"输入:{pos['input']}\n"
prompt += f"输出:{pos['label']}\n\n"

# 添加查询
prompt += f"现在请回答:\n输入:{query}\n输出:"

return prompt

实验结果

实验设置

数据集

  • SST-2:情感分析
  • CoLA:语言可接受性
  • RTE:自然语言推理
  • BoolQ:是非问答

基线方法

  • Random Selection
  • BM25 Retrieval
  • Embedding Similarity
  • KATE(困难样本)

评估指标

  • 准确率(%)
  • F1 分数
  • 改进幅度

主要结果

SST-2 情感分析

方法 k=4 k=8 k=16
Random 78.2% 80.1% 81.5%
BM25 81.5% 83.2% 84.1%
Embedding 82.3% 84.5% 85.2%
KATE 83.5% 85.2% 86.1%
本文方法 86.8% 88.5% 89.2%

提升:vs 最佳基线 +3.1%(k=4)

RTE 自然语言推理

方法 entailment neutral contradiction 平均
Embedding 62.3% 58.1% 65.2% 61.9%
KATE 64.5% 60.2% 67.8% 64.2%
本文方法 69.8% 65.5% 72.1% 69.1%

负样本数量影响

负样本数 SST-2 RTE BoolQ
0(仅正) 85.2% 64.2% 72.1%
2 86.5% 66.8% 74.5%
5 88.5% 69.1% 76.2%
10 88.8% 69.5% 76.5%

最佳:5 个负样本达到最佳平衡


总结

本文证明了负样本在少样本学习中的价值:

核心贡献

  1. 负样本挖掘和失败模式分析
  2. 负样本指导的正样本选择
  3. 对比式 ICL Prompt 构建

实际价值

  • 12-18% 准确率提升
  • 适用于分类、推理、问答任务
  • 无需模型微调

资源


评分: 4.2/5.0 ⭐⭐⭐⭐

推荐度: 推荐。少样本学习的创新方法,实用性强。

© 2026 Generative AI Discovery All Rights Reserved.
Theme by hiero