报告和代码#244
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces task-specific prompt routing, multiple advanced few-shot example selection strategies (M04 to M20), a mixed context length strategy, and robust fallback parsing mechanisms to improve long-context data annotation. The review feedback highlights several critical issues: caching examples_str in the main loop breaks dynamic retrieval and context-length optimization; the <think> tag cleanup is incomplete and can corrupt fallback matching; indexing example['output'][0] on string outputs causes character truncation; the math fallback logic should extract the last number rather than the first; and the build_prompt_cot function is currently dead code as it is omitted from the routing system.
| if examples_str is None: | ||
| examples_str = select_examples(icl_examples, task_description, text2annotate) | ||
| # 使用动态选择的select_examples函数 | ||
| examples_str = select_func(icl_examples, task_description, text2annotate, task_id, sample_idx) |
There was a problem hiding this comment.
🔴 逻辑漏洞:缓存 examples_str 会破坏动态检索和混合上下文长度策略
在当前的实现中,examples_str 在循环外部被初始化为 None,并在第一次迭代(sample_idx == 0)中被赋值后缓存。这会导致两个严重问题:
- 动态检索失效:像
select_examples_M05、select_examples_M19和select_examples_M20这样的高级选择方法依赖于当前样本的text2annotate来计算相似度并检索最相关的 few-shot 示例。缓存examples_str意味着所有后续的测试样本都将重复使用为第一个样本检索的示例,从而完全使动态检索失效。 - 混合上下文长度策略失效:混合上下文长度策略(例如在
select_examples中)使用sample_index < 50来为前 50 个样本分配 30k 的上下文预算,并将其余样本限制为 8k 以提高效率。由于select_func仅在sample_idx = 0时被调用一次,30k 预算的 prompt 被缓存并重复用于所有后续样本,完全绕过了 8k 优化,严重降低了评估性能。
建议:移除 if examples_str is None: 检查,以便为每个样本动态评估 select_func。
# 使用动态选择的select_examples函数
examples_str = select_func(icl_examples, task_description, text2annotate, task_id, sample_idx)| # 第四步:先清理思维链标签 | ||
| cleaned_text = re.sub(r'</think>', '', text) |
There was a problem hiding this comment.
⚠️ Bug:思维链标签(<think>...</think>)清理不彻底
在第四步中,仅移除了结束标签 </think>,而将思考块内部的整个推理内容保留在文本中。
如果模型未能输出 <label> 标签,兜底策略(例如在第五步中搜索 positive 或 negative 等关键字)将搜索整个推理过程。由于推理过程经常讨论备选标签(例如:“虽然它看起来可能是 negative,但实际上是 positive”),这将导致兜底分类极不准确(匹配到推理中首先提到的任何标签)。
建议:在运行兜底检查之前,使用正则表达式完全剥离 <think>...</think> 块及其内容。
| # 第四步:先清理思维链标签 | |
| cleaned_text = re.sub(r'</think>', '', text) | |
| # 第四步:先清理思维链标签及其中间内容 | |
| cleaned_text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL) |
| input_text = example['input'] | ||
| output_text = example['output'][0] |
There was a problem hiding this comment.
⚠️ Bug:当 example['output'] 为字符串时可能导致截断
在 select_examples_M19(以及类似的 select_examples_M09、select_examples_M10、select_examples_M11)中,直接访问了 example['output'][0]。如果 example['output'] 是一个字符串(例如 "Good Review"),example['output'][0] 将仅返回第一个字符("G")。这将导致错误的 token 计数计算和损坏的 few-shot 示例(例如 <label> G </label>)。
其他方法(如 select_examples_M04 和 select_examples_M20)通过以下方式正确处理了此问题:
output_text = example['output'][0] if isinstance(example['output'], list) else example['output']
建议:在此处应用相同的安全提取逻辑以防止截断。
| input_text = example['input'] | |
| output_text = example['output'][0] | |
| input_text = example['input'] | |
| output_text = example['output'][0] if isinstance(example['output'], list) else example['output'] |
| # 第三步:兜底策略2 - 尝试提取数字(针对数学任务) | ||
| number_pattern = r'-?\d+\.?\d*' | ||
| numbers = re.findall(number_pattern, text) | ||
| if numbers: | ||
| return numbers[0] |
There was a problem hiding this comment.
⚠️ 改进:数学任务的数字提取兜底策略过于脆弱
使用 numbers[0] 来提取数学答案非常脆弱。如果模型输出的推理链没有 <label> 标签(例如:“Step 1: we have 12. Step 2: we multiply by 3 to get 36.”),re.findall 将匹配所有数字,而 numbers[0] 将返回 '1'(来自 “Step 1”)或 '12',而不是最终答案 '36'。
建议:由于最终答案通常出现在回答的末尾,提取最后一个匹配的数字(numbers[-1])是数学推理任务中更鲁棒的兜底策略。
| # 第三步:兜底策略2 - 尝试提取数字(针对数学任务) | |
| number_pattern = r'-?\d+\.?\d*' | |
| numbers = re.findall(number_pattern, text) | |
| if numbers: | |
| return numbers[0] | |
| # 第三步:兜底策略2 - 尝试提取数字(针对数学任务,优先取最后一个数字作为答案) | |
| number_pattern = r'-?\d+\.?\d*' | |
| numbers = re.findall(number_pattern, text) | |
| if numbers: | |
| return numbers[-1] |
| if task_id in math_tasks: | ||
| return build_prompt_math(task_description, text2annotate) | ||
| elif task_id in string_tasks: | ||
| return build_prompt_string(task_description, text2annotate) | ||
| elif task_id in classification_tasks: | ||
| return build_prompt_classification(task_description, text2annotate) | ||
| elif task_id in generation_tasks: | ||
| return build_prompt_generation(task_description, text2annotate) | ||
| else: | ||
| return build_prompt(task_description, text2annotate) |
There was a problem hiding this comment.
⚠️ 可维护性:build_prompt_cot 是死代码,从未集成到路由系统中
函数 build_prompt_cot 旨在为任务 3 和任务 8 提供思维链(CoT)提示词。然而,路由函数 build_prompt_by_task_type 将任务 3 路由到 build_prompt_math,将任务 8 路由到 build_prompt_generation,这意味着 build_prompt_cot 永远不会被执行。
建议:将 build_prompt_cot 集成到任务 3 和任务 8 的路由逻辑中。
| if task_id in math_tasks: | |
| return build_prompt_math(task_description, text2annotate) | |
| elif task_id in string_tasks: | |
| return build_prompt_string(task_description, text2annotate) | |
| elif task_id in classification_tasks: | |
| return build_prompt_classification(task_description, text2annotate) | |
| elif task_id in generation_tasks: | |
| return build_prompt_generation(task_description, text2annotate) | |
| else: | |
| return build_prompt(task_description, text2annotate) | |
| if task_id in [3, 8]: | |
| return build_prompt_cot(task_description, text2annotate, task_id) | |
| elif task_id in math_tasks: | |
| return build_prompt_math(task_description, text2annotate) | |
| elif task_id in string_tasks: | |
| return build_prompt_string(task_description, text2annotate) | |
| elif task_id in classification_tasks: | |
| return build_prompt_classification(task_description, text2annotate) | |
| elif task_id in generation_tasks: | |
| return build_prompt_generation(task_description, text2annotate) | |
| else: | |
| return build_prompt(task_description, text2annotate) |
No description provided.