From 5290dd117c8a3440009182cf444a303cf3fbcf36 Mon Sep 17 00:00:00 2001 From: Val-sss <154882199@qq.com> Date: Thu, 7 May 2026 18:37:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20best-of-N=E9=87=87=E6=A0=B7=20=E2=80=94?= =?UTF-8?q?=20=E5=A4=9A=E6=B8=A9=E5=BA=A6=E7=94=9F=E6=88=90=E9=80=89?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E6=AD=A3=E7=A1=AE=E7=9A=84=E5=80=99=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generator不再遇到第一个非空结果就返回,而是: 1. temperature=0.0/0.3/0.6依次生成 2. 每个候选做ast.parse语法检查 3. 第一个语法正确的直接返回(优先确定性低温结果) 4. 全部语法错误时返回第一个候选(让verifier报具体错误) 直接解决"语法错误导致circuit break":temp=0错了,temp=0.4可能对。 513 tests passed. Co-Authored-By: Claude Opus 4.6 (1M context) --- kaiwu/experts/generator.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/kaiwu/experts/generator.py b/kaiwu/experts/generator.py index c5de489..cbb06dc 100644 --- a/kaiwu/experts/generator.py +++ b/kaiwu/experts/generator.py @@ -457,17 +457,46 @@ class GeneratorExpert: if think_cfg.get("think") and self.llm._is_reasoning: base_tokens += think_cfg.get("budget", 0) + # ── Best-of-N采样:生成多个候选,选语法正确的最佳版本 ── + candidates = [] for temp in self.temperatures: raw = self.llm.generate(prompt=prompt, system=system, max_tokens=base_tokens, temperature=temp) - # 审计:记录LLM调用的输入输出 self._log_llm_call(ctx, "generator", prompt, system, raw) modified = self._clean_code_output(raw) if modified and modified != original: - return modified + if self._is_valid_syntax(modified): + # 语法正确,直接返回(优先低温度的确定性结果) + return modified + else: + # 语法错误但有内容,存为候选 + candidates.append(modified) + + # 所有温度都语法错误时,返回第一个候选(让verifier报具体错误) + if candidates: + logger.debug("Generator: no syntax-valid candidate, returning best-effort") + return candidates[0] logger.warning("Generator: all candidates identical to original or empty") return None + @staticmethod + def _is_valid_syntax(code: str) -> bool: + """检查Python代码语法是否正确。非Python代码直接返回True。""" + import ast + stripped = code.strip() + if not stripped: + return False + first_line = stripped.split("\n")[0].strip() + python_indicators = ("def ", "class ", "import ", "from ", "if ", "for ", + "while ", "try:", "with ", "async ", "@") + if not any(first_line.startswith(p) for p in python_indicators): + return True # 非Python代码,跳过语法检查 + try: + ast.parse(code) + return True + except SyntaxError: + return False + @staticmethod def _extract_func_name_from_code(code: str) -> str: """从代码片段中提取函数/类名。"""