)
人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用【免费下载链接】KilnBuild, Evaluate, and Optimize AI Systems. Includes evals, RAG, agents, fine-tuning, synthetic data generation, dataset management, MCP, and more.项目地址https://gitcode.com/gh_mirrors/ki/Kiln点击查看免费下载导读本文聚焦 Kiln 开源仓库中deep-cr-cleanup专项治理项目的 Phase 2 实施计划系统讲解评测Eval后端四类正确性问题的成因、修复方案与测试验证Jinja 表达式求值为 PythonNone时未触发跳过、V1 EvalRun 携带outputNone通过校验后引发下游AttributeError、以及一段永远执行不到的except SyntaxError: pass死代码。读完本文你将掌握 Kiln 评测运行时跳过信号SkippedReason的完整语义、V1/V2 评测记录校验器的执行路径以及如何用针对性测试锁定这类回归。一、Phase 2 在 deep-cr-cleanup 中的定位deep-cr-cleanup是一个把深度 Code ReviewCR中发现的积压问题分批治理的专项项目。implementation_plan.md 明确其组织方式每个 Phase 是一个单一关注点的小型提交coding agent → spec-aware CR → commit共分 16 个 Phase覆盖后端正确性、命名重构、数据模型健壮性、API 一致性、前端契约与测试卫生等多个维度。Phase 2 是其中的第二个实施阶段status: complete任务集中在核心 Eval 后端共含四项内容编号关注点结论1aextract_value/check_required_vars只检查 JinjaUndefined未检查 PythonNone修复将None与Undefined一同视为跳过信号1b_filter_output_to_score_keys无匹配时的处理废弃该函数已随 RAG 模板在提交5efc626中删除无需实现1cV1 EvalRun 的outputNone通过校验后引发下游AttributeError修复非跳过 V1 记录增加output is not None守卫5.4CodeEvalProperties.validate_code中存在死代码except SyntaxError: pass修复移除死分支其中 1a、1c 来自 Batch 1正确性批次5.4 来自独立的代码卫生批次。本文按这四条主线展开并结合当前仓库源码给出实现证据。二、修复 1a把 PythonNone纳入跳过信号2.1 问题本质Undefined与None是两种不同的缺失Kiln 的 V2 评测Eval在打分前会用 Jinja2 表达式从EvalTaskInput中提取待评分值。表达式求值可能产生两种无值结果UndefinedJinja 未定义访问了不存在的字段/键例如reference_data中没有声明的键NonePython 空值键存在但值本身是null例如reference_data中某个键的值为None。None与Undefined的区分在底层引擎中是有意设计的。jinja_engine.py 中extract()的 docstring 明确写道Missing keys returnUndefined(notNone, not a raise)Explicit null values returnNone。同一文件里表达式环境使用默认Undefined第 107 行模板环境则使用StrictUndefined第 99 行。问题在于修复前extract_value只把Undefined当作跳过信号表达式解析成None时值会被当作有效继续传递。典型场景是reference_data中某个键存在但其值为null——该数据本应是缺失的却被当作合法值喂给下游 judge造成误判。2.2 修复后的实现extract_value与check_reference_keyPhase 2 计划要求在Undefined检查之后追加None检查命中即返回跳过信号SkippedReason.extraction_failed及描述性消息。当前 v2_eval_helpers.py 中的extract_value第 49–83 行正是这样实现的if isinstance(result, Undefined) or result is None: return ( None, SkippedReason.extraction_failed, fExpression {expression} resolved to {undefined if isinstance(result, Undefined) else None}, ) return result, None, None注意消息文本会区分undefined与None便于在skipped_detail中定位根因。同时无表达式时的兜底第 58–59 行保持原语义expression is None时默认取eval_input.final_message。需要说明的一点Phase 2 计划中提到的check_required_vars函数在当前仓库中已演化为 v2_eval_helpers.py 的check_reference_key第 114–141 行职责是从eval_input.reference_data中按名取参考数据。它同样完成了None处理value eval_input.reference_data[reference_key] if value is None: return ( None, SkippedReason.missing_reference_key, freference_data key {reference_key} is None, )reference_data本身缺失、键缺失、键值为None三种情况统一映射到SkippedReason.missing_reference_key并附带不同细节。SkippedReason枚举定义在 eval.py 第 517–527 行成员包括missing_reference_key、extraction_failed、missing_trace、missing_drive_config、incompatible_input_shape、code_eval_not_trusted、type_not_available以字符串枚举形式存储以保证前后兼容。2.3 跳过信号如何被下游消费以 LLM judge 为例v2_eval_llm_judge.py 的evaluate()第 131–137 行会在渲染模板与调用模型之前遍历props.reference_keysfor reference_key in props.reference_keys: _, skip_reason, skip_detail check_reference_key(reference_key, eval_input) if skip_reason is not None: return V2EvalResult( skipped_reasonskip_reason, skipped_detailskip_detail, )这个声明式参考键前置检查是关键设计一个声明了参考键却取不到数据的 judge 必须响亮地跳过而不是盲评模板可能写得宽松自行守卫查找因此只有声明的要求才能拒绝缺失的 ground truth。确定性 check如 v2_eval_exact_match.py 第 28–33 行同样消费check_reference_key的返回值命中 skip 就返回V2EvalResult(skipped_reason..., skipped_detail...)。一个微妙的语义边界extract_output_valuev2_eval_helpers.py 第 86–111 行对输出字段的缺失处理与参考数据不同——确定性 check 中模型未产出预期结构意味着FAIL 而非跳过跳过仅保留给 ground truth/reference 数据缺失唯missing_trace例外它作为数据可用性问题向上传播为跳过。三、修复 1b确认_filter_output_to_score_keys已被 RAG 清理移除Batch 1 的第 1b 项原本计划当_filter_output_to_score_keys在输出中没有匹配到任何评分键时应抛出no recognized score fields错误而非静默透传。但 Phase 1 验证计划纯验证、零代码改动给出了决定性结论全库grep _filter_output_to_score_keys在.py文件中零命中移除提交5efc626的说明明确写着 Remove _filter_output_to_score_keys (RAG-specific rich JSON filtering)diff 同时删除了函数定义与其调用点v2_eval_llm_judge.py中已无任何filter引用。因此该项被标记为DROPPED / moot——函数随 RAG judge 模板一起被移出 V2.0详见 rag_templates 项目说明无需再实现。这是在动手前先验证目标是否还存在的典型成本规避案例也印证了 implementation_plan 中only if it survived the RAG removal的前置条件。四、修复 1c为 V1 EvalRun 增加output is not None守卫4.1 问题路径校验通过 → 下游AttributeErrorV1legacy评测配置的 EvalRun如果outputNone且未设置跳过原因会通过validate_output_fields校验随后在下游访问输出字段时抛出AttributeError——把本应明确报出的配置错误变成了运行时晦涩的崩溃。4.2 修复后的校验流程eval.py 的validate_output_fields第 1022–1067 行是 Pydantic 的model_validator(modeafter)执行路径如下指针模式早退scored_run_id is not None时直接返回trace 在引用的 TaskRun 上本记录不携带内联数据见validate_record_mode的约束定位父级 Evalparent_eval_config.parent_eval()不存在则直接返回full_trace 守卫非eval_config_eval、未跳过、evaluation_data_type full_trace但task_run_trace is None且非从文件加载时报 full_trace task run eval runs should include traceV2 早退config_type v2直接返回——V2 故意放宽这些检查因为被跳过的运行本就不携带 outputV1 守卫本次新增output is None and skipped_reason is None时抛出ValueError(V1 EvalRun requires output to be set)final_answer 守卫evaluation_data_type final_answer时禁止携带 trace。第 5 步即 Phase 2 的 1c 修复当前实现第 1058–1059 行if self.output is None and self.skipped_reason is None: raise ValueError(V1 EvalRun requires output to be set)关键语义是非跳过才要求 output被跳过的 V1 记录允许outputNone因为跳过本身意味着没有产出可评分的输出。4.3 配套测试矩阵Phase 2 要求在 test_eval_model.py 中补充 V1 守卫测试当前实现为TestV1EvalRunOutputNoneGuard类第 3751–3853 行覆盖四个分支测试场景断言test_v1_eval_run_output_none_raisesV1 outputNone 未跳过pytest.raises(ValueError, matchV1 EvalRun requires output to be set)test_v1_eval_run_output_none_skipped_allowedV1 outputNoneskipped_reasonmissing_reference_key允许run.output is Nonetest_v1_eval_run_output_set_passesV1 正常 output通过output some outputtest_v2_eval_run_output_none_allowedV2 outputNone 跳过允许V2 早退路径V1 与 V2 的对照测试尤其重要它锁死了V1 严格、V2 宽松的共存契约防止后续重构把两边行为搅乱。五、修复 5.4删除validate_code中的死代码5.1 死代码的成因CodeEvalProperties.validate_codeeval.py 第 349–377 行负责校验用户提交的 code_eval 评分器代码。修复前代码结构大致是先用compile()检查语法再用ast.parse()解析并检查是否存在模块级score函数但ast.parse()外层包着一个except SyntaxError: pass——这永远不会触发因为compile()已经捕获并重新抛出SyntaxError转成ValueError能走到ast.parse()的代码必然已通过语法检查。这个永远执行不到的 catch 就是 Phase 2 第 5.4 项要移除的死块。5.2 修复后的校验链当前实现将语法检查与结构检查清晰分层try: compile(self.code, code_eval, exec) except SyntaxError as e: raise ValueError(fCode has a syntax error: {e}) from e tree ast.parse(self.code) has_score_fn any( isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name score for node in ast.iter_child_nodes(tree) ) if not has_score_fn: raise ValueError( Code must define a module-level score function (def score(...)). )要点尺寸上限守卫在语法检查之前执行编码后的字节数超过 64KB 直接报错compile()统一负责语法层SyntaxError被转译为更友好的ValueErrorast.parse()负责结构层仅检查score函数是否存在——同步def score与异步async def score均被接受异步协程由sandbox_worker.execute_scorer_bridged透明 await。5.3 测试验证test_eval_model.py 的TestCodeEvalCodeValidation第 3861–3884 行用四个用例锁定该行为test_valid_code_with_score_fndef score(output, expected)正常通过test_code_missing_score_fn_raises只有def helper()时报ValueError匹配 must define a module-level score function——这正是计划中test_code_eval_no_syntax_error_catch所验证的路径ast.parse分支在无死 catch 的情况下正常工作test_syntax_error_caught_by_compiledef bad(:由compile()捕获报 syntax errortest_async_score_fn_validasync def score被接受。六、实施落地与验证方式6.1 测试文件组织Phase 2 按计划新建了 test_v2_eval_helpers.py集中测试extract_value、extract_output_value、check_reference_key、references_trace、stringify_for_match五个辅助函数extract_value侧默认值走final_message、有效表达式取值、Undefined跳过、None结果通过test_non_none_result_passes保证非 None 正常放行、缺少 trace 时以missing_trace跳过、字符串字面量中的trace不误判为依赖check_reference_key侧键存在且有值、无reference_data、键缺失、键值为None时跳过test_key_value_is_none_skips对应计划中的test_check_reference_key_value_is_none_skips——这是 1a 修复的核心回归用例extract_output_value侧输出提取失败 → FAIL 而非跳过、missing_trace传播为跳过、空 trace[]不当作缺失缺失判定基于is None而非假值。6.2 与 Phase 5 的呼应值得注意的是Phase 2 的None语义修复与 Phase 5 计划 存在呼应由于 V2.0 尚无 UI 路径为EvalInput填充reference_data任何暴露reference_key数据源选择的表单都会在运行时永远静默跳过missing reference data 被当作干净跳过。因此 Phase 5 在每个此类 UI 入口添加TODO注释借助 CI 的 no-TODO-on-main 规则形成强制发货前闸门。这从侧面说明跳过语义必须保持响亮且可解释否则配置错误会被静默吞掉。七、小结Phase 2 的四项工作在正确性层面补齐了评测后端的三个关键契约表达式求值的缺失双语义Undefined键不存在与None值为空统一纳入跳过信号杜绝看似有效实则空值的误判v2_eval_helpers.pyV1 记录的输出完整性非跳过 V1 EvalRun 必须携带output把下游AttributeError前置为清晰的ValueErroreval.py 第 1058–1059 行代码校验的可达性删除永远执行不到的except SyntaxError: pass让语法由 compile 负责、结构由 ast.parse 负责的分层名副其实eval.py 第 357–375 行。同时1b 的 DROPPED 结论展示了一条重要工程原则修复前先验证目标代码是否仍存在避免为一个已被删除的函数实现无用的修复。每个改动都配有针对性测试完整覆盖矩阵见 test_v2_eval_helpers.py 与 test_eval_model.pyTestV1EvalRunOutputNoneGuard、TestCodeEvalCodeValidation相关背景可继续阅读 deep-cr-cleanup 项目总览 与 实施计划。赞分享人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用【免费下载链接】KilnBuild, Evaluate, and Optimize AI Systems. Includes evals, RAG, agents, fine-tuning, synthetic data generation, dataset management, MCP, and more.项目地址https://gitcode.com/gh_mirrors/ki/Kiln点击查看免费下载相关推荐Kiln 后端测试卫生实践eval 测试套件的去重与质量加固deep-cr-cleanup Phase 7 解析Kiln 后端测试卫生实践eval 测试套件的去重与质量加固deep cr cleanup Phase 7 解析 本文以 Kiln 仓库中 deep cr人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsKiln 规范与实现对齐实践Deep CR Cleanup Phase 6 的 code_eval 严格评分校验与 evaluation_data_type 默认值修正Kiln 规范与实现对齐实践Deep CR Cleanup Phase 6 的 code_eval 严格评分校验与 evaluation_data_type人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOpsKiln 数据模型健壮性实战V2 评测的显式属性元组、评分缓存与互斥校验deep-cr-cleanup Phase 4Kiln 数据模型健壮性实战V2 评测的显式属性元组、评分缓存与互斥校验deep cr cleanup Phase 4 本篇技术指南聚焦 Kiln 开源仓人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用MLOps创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考