返回列表

4th Place Solution

660. Konwinski Prize | konwinski-prize

开始: 2024-12-12 结束: 2025-07-23 基础软件 AI大模型赛
第 4 名解决方案 - Select-Patch-Verify-Test

第 4 名解决方案

作者: Genxxsky
发布日期: 2025-08-02
副标题: Select-Patch-Verify-Test

我想向 Kaggle 团队和竞赛组织者表达我诚挚的感谢,他们创造了这样一个高度引人入胜且智力挑战性的赛事。我也非常感谢 @huikang 通过 Starter Notebook - Select-Patch-VerifyLB 计算器 做出的宝贵贡献。他们的工作为我的方法提供了坚实的基础,并显著增强了整体竞赛体验。

本次竞赛提出了一个独特而复杂的挑战:平衡模型准确性与生成补丁的有效性,就像在能见度有限的情况下走钢丝。随着模型性能的提高,生成看似正确但根本存在缺陷的补丁的风险也随之增加。

概要 (TL;DR)

基于 @huikangStarter Notebook - Select-Patch-Verify 的基础工作,我在最终提交中探索了两种不同的策略,每种策略都有其自身的优势和权衡:

策略 私有排行榜分数 (Private LB) 公共排行榜分数 (Public LB)
Select-Patch-Verify-Test (获胜提交) 0.016571
(4 正确,2 错误,114 跳过)
-0.000097
(1 正确,1 错误,69 跳过)
Select-Patch-Verify-Choose -0.008429
(2 正确,3 错误,115 跳过)
-0.000094
(2 正确,2 错误,67 跳过)
Select-Patch-Verify-Test 流程图
  • Select-Patch-Verify-Test (获胜提交):

    • 通过减少补丁尝试次数和思考时间,优先考虑效率
    • 利用 pytest 代码生成和测试 对每个候选补丁进行验证。
    • 在问题相对简单的情况下表现更好。
    • 代码链接
  • Select-Patch-Verify-Choose:

    • 采用更具探索性的方法。
    • 使用更多 token 尝试生成和验证多个补丁。
    • 基于多维评估选择最佳选项。
    • 涉及更高的计算开销,需要进一步优化。
    • 在更复杂的问题上表现更好,但在某些问题上可能耗时较多。
    • 代码链接

pipeline 中的关键步骤

  • Select (选择): 使用 tree-sitter 搜索相关代码片段。
  • Patch (补丁): 基于选定的代码生成 diff 补丁。
  • Verify (验证): 使用 LLM 自检 验证补丁。
  • Test (测试): 生成并执行 pytest 代码进行测试。
  • Choose (选择): 使用多维评估比较多个补丁选项。

关键改进

增强的代码上下文化

通过利用 tree-sitter 进行函数和类级别的代码分析,我能够为模型检索更丰富的上下文信息。这提高了模型对特定感兴趣行周围代码的理解。

以下是为第 4778 行检索到的代码上下文示例:

[file name]: astroid/nodes/node_classes.py
[terms searched]:
line(4778)
string_to_search(formatted = format(value.value, format_spec.value))
string_to_search(if value is not None:)
[file relevant content begin]

Match #1, lines 4708 to 4791:
  4708|class JoinedStr(NodeNG):
  4709|    """Represents a list of string expressions to be joined.
  4710|
  4711|    >>> import astroid
  4712|    >>> node = astroid.extract_node('f"Format {type_}"')
  4713|    >>> node
  4714|    
  4715|    """
  ...|
  4719|    def __init__(
  4720|        self,
  4721|        lineno: int | None = None,
  4722|        col_offset: int | None = None,
  4723|        parent: NodeNG | None = None,
  4724|        *,
  4725|        end_lineno: int | None = None,
  4726|        end_col_offset: int | None = None,
  4727|    ) -> None:
  ...|
  4773|    @classmethod
  4774|    def _infer_from_values(
  4775|        cls, nodes: list[NodeNG], context: InferenceContext | None = None, **kwargs: Any
  4776|    ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]:
  4777|        if len(nodes) == 1:
  4778|            yield from nodes[0]._infer(context, **kwargs)
  4779|            return
  4780|        uninferable_already_generated = False
  4781|        for prefix in nodes[0]._infer(context, **kwargs):
  4782|            for suffix in cls._infer_from_values(nodes[1:], context, **kwargs):
  4783|                result = ""
  4784|                for node in (prefix, suffix):
  4785|                    if isinstance(node, Const):
  4786|                        result += str(node.value)
  4787|                        continue
  4788|                    result += MISSING_VALUE
  4789|                if MISSING_VALUE in result:
  4790|                    if not uninferable_already_generated:
  4791|                        uninferable_already_generated = True

[file relevant content end]

自动化测试脚本生成

我使模型能够根据问题陈述生成包含两个测试函数的 pytest 脚本

  • test_before_patch: 在问题修复前应通过,修复后应失败。
  • test_after_patch: 在修复前应失败,修复后应通过。

以下是生成的测试脚本示例:

import pytest
from astroid.nodes.node_classes import FormattedValue, Const

def test_before_patch():
    # 测试在没有补丁的情况下,尝试格式化 None 值会引发 TypeError
    value_node = Const(None)
    format_spec_node = Const('.1f')
    formatted_value = FormattedValue(value=value_node, format_spec=format_spec_node)
    try:
        list(formatted_value.infer())
    except TypeError:
        # 如果引发 TypeError,测试通过(补丁前)
        pass
    else:
        # 如果未引发 TypeError,测试失败(补丁后)
        pytest.fail("Expected TypeError was not raised")

def test_after_patch():
    # 测试在有补丁的情况下,格式化 None 值返回 None 且无错误
    value_node = Const(None)
    format_spec_node = Const('.1f')
    formatted_value = FormattedValue(value=value_node, format_spec=format_spec_node)
    inferred = list(formatted_value.infer())
    # 补丁后,结果应为单个值为 None 的 Const
    assert len(inferred) == 1
    assert inferred[0].value is None

其他改进

  • 效率增强: 实施了并行处理token 压缩缓存早停以提高管道效率。
  • 置信度评估: 快速评估模型置信度使得能够优先处理高质量补丁,改善最终输出。
  • 基于规则的 Diff 修复: 使用基于规则的方法调整 diffs 对最终分数产生了随机影响。
  • 代码分析技术: 多方法代码查找、多步分析和跨尝试代码共享等方法并未产生有意义的增益。
  • 提示词和参数变化: 在尝试之间变化提示词或参数,或扩展补丁生成,并未一致地提高性能。
  • 补丁验证方法: 如基于 AST 的检查或重用现有 pytest 函数等技术对性能影响甚微。

反思与经验教训

本次竞赛标志着我获得第一枚 Kaggle 金牌 —— 这是一个激励我巨大的重要里程碑。然而,仍有几个领域需要改进。时间限制限制了对有前景想法的探索,优化期间的重大代码重构导致改进在两种策略中的应用不一致。许多变化缺乏彻底的消融研究,我认识到这是未来工作流程中需要改进的关键领域。

展望未来,我致力于完善这些方法,将获得的见解应用于未来的挑战,并采用更系统、更严格的开发流程,以最大限度地提高性能和创新。

同比赛其他方案