
刷题 Agent 的工具体系LLM 推理、沙箱执行与评测的三位一体一、单靠 LLM 的输出离可靠题解还有多远用 LLM 生成算法题解最常见的做法是把题目丢给模型等它输出代码。然后你复制粘贴到 LeetCode提交等待判题结果。如果通过了题解可用如果没通过你可能需要再试几次或者去看报错信息手动调整。这个流程的问题在于LLM 的输出与最终验证之间是断裂的。模型不知道自己生成的代码对不对你也不知道——直到手动提交后。这种断裂导致两个后果一是反馈循环长二是纯粹依赖 LLM 的生成质量没有第二道防线。这篇文章讨论的不是 LLM 本身而是围绕 LLM 构建的一套工具体系——让 Agent 不仅能生成代码还能自主执行、验证、修正。二、三位一体的工具架构flowchart TD subgraph LLM推理层 A[题目理解与算法选择] B[代码生成] C[复杂度分析] end subgraph 沙箱执行层 D[代码编译] E[样例测试] F[边界用例测试] G[性能压测] end subgraph 评测反馈层 H[正确性评分] I[性能评分] J[代码质量评分] K[综合报告] end LLM推理层 --|生成代码| 沙箱执行层 沙箱执行层 --|执行结果| 评测反馈层 评测反馈层 --|失败反馈| LLM推理层 评测反馈层 --|通过| L[输出最终题解]这套体系的核心逻辑是「生成-执行-反馈-修正」的闭环。LLM 负责生成沙箱负责验证评测层负责判断和反馈。三个模块独立分工通过消息队列连接。三、Agent 工具注册与调度from typing import Any, Callable from dataclasses import dataclass from enum import Enum class ToolCategory(Enum): 工具分类 LLM llm # 推理类工具 SANDBOX sandbox # 沙箱执行类工具 EVALUATOR evaluator # 评测类工具 dataclass class ToolDef: 工具定义 每个工具包含名称、描述、输入参数 schema、执行函数。 Agent 框架通过函数描述决定何时调用哪个工具。 name: str description: str # 描述给 LLM 阅读帮助它选择合适的工具 category: ToolCategory parameters: dict # JSON Schema 格式的参数定义 handler: Callable # 实际执行函数 class AgentToolRegistry: Agent 工具注册中心 管理所有可用工具提供查询和调用能力。 设计思想类似于 LangChain 的 Tool 体系但更轻量 只关注刷题场景需要的最小工具集。 def __init__(self): self._tools: dict[str, ToolDef] {} def register(self, tool: ToolDef) - None: 注册一个工具 self._tools[tool.name] tool def get_tool_descriptions(self) - str: 生成工具描述文本供 LLM 做工具选择决策 lines [] for tool in self._tools.values(): lines.append( f- {tool.name}: {tool.description} f 参数: {tool.parameters} ) return \n.join(lines) def invoke(self, name: str, **kwargs) - Any: 调用指定工具 tool self._tools.get(name) if not tool: raise ValueError(f未知工具: {name}) return tool.handler(**kwargs) # ---- 工具实现 ---- def llm_generate_solution(problem_desc: str, language: str) - str: LLM 工具生成题解代码 # 实际调用 LLM API # 此处用伪代码示意 return # 生成的代码 def sandbox_run_test(code: str, test_input: str, language: str) - dict: 沙箱工具在隔离环境中执行代码并返回结果 # 实际调用沙箱执行器 return {passed: True, output: ..., time_ms: 42} def evaluator_score(result: dict) - dict: 评测工具根据执行结果生成质量评分 score 100 if result[passed] else 0 return { correctness: score, performance: 100 if result.get(time_ms, 0) 1000 else 70, suggestions: [] if result[passed] else [检查边界条件], } class ProblemSolvingAgent: 刷题 Agent编排 LLM 推理、沙箱执行与评测 工作流程 1. 接收题目调用 LLM 生成初始代码 2. 在沙箱中执行测试用例 3. 评测结果如果通过则输出否则反馈给 LLM 重新生成 4. 最多重试 3 次 MAX_RETRIES 3 def __init__(self): self.registry AgentToolRegistry() # 注册 LLM 工具 self.registry.register(ToolDef( namegenerate_solution, description根据题目描述和目标语言生成算法题解代码, categoryToolCategory.LLM, parameters{ problem_desc: {type: string, description: 题目描述}, language: {type: string, enum: [python, java, cpp]}, }, handlerllm_generate_solution, )) # 注册沙箱工具 self.registry.register(ToolDef( namerun_test, description在沙箱环境中执行代码并返回测试结果, categoryToolCategory.SANDBOX, parameters{ code: {type: string}, test_input: {type: string}, language: {type: string}, }, handlersandbox_run_test, )) # 注册评测工具 self.registry.register(ToolDef( nameevaluate, description根据执行结果评估代码质量并给出改进建议, categoryToolCategory.EVALUATOR, parameters{result: {type: object}}, handlerevaluator_score, )) def solve( self, problem_desc: str, test_cases: list[dict], language: str python, ) - dict: 解决一道题目生成-评测-修正 的完整流程 feedback_history [] # 记录每次失败的反馈供 LLM 参考 for attempt in range(self.MAX_RETRIES): # 第 1 步LLM 生成代码带上之前的失败反馈 prompt problem_desc if feedback_history: prompt f\n\n之前的错误反馈{feedback_history} code self.registry.invoke( generate_solution, problem_descprompt, languagelanguage, ) # 第 2 步沙箱执行所有测试用例 all_passed True test_results [] for tc in test_cases: result self.registry.invoke( run_test, codecode, test_inputtc[input], languagelanguage, ) test_results.append(result) if not result[passed]: all_passed False # 第 3 步评测 eval_result self.registry.invoke( evaluate, result{passed: all_passed, details: test_results} ) if all_passed: return { code: code, passed: True, attempts: attempt 1, eval: eval_result, } # 收集失败信息供下一轮反馈 failures [ f用例{i1}: {t.get(error, 失败)} for i, t in enumerate(test_results) if not t[passed] ] feedback_history.append(f第{attempt1}轮失败{; .join(failures)}) return { code: None, passed: False, attempts: self.MAX_RETRIES, eval: {correctness: 0, suggestions: [超过最大重试次数]}, }四、边界与权衡4.1 重试的上限与策略当前实现重试 3 次每次都完整重跑 LLM 推理。更好的策略是根据失败类型选择不同的修正路径——语法错误可以直接让 LLM 修正逻辑错误需要重新分析题目。不同错误类型的修正成本和策略不同。4.2 工具调用的成本每次 LLM 调用都有延迟和费用。如果沙箱执行只需要 50ms而 LLM 推理需要 2s那么先执行再反馈的延迟主要来自 LLM。优化的方向是尽量减少 LLM 的无效调用——比如在沙箱执行前做一次静态分析排除明显的语法错误。4.3 评测的维度拓展当前评测只关注正确性和性能。完整的评测体系还应该包含代码风格、可读性、边界覆盖度等维度。这些需要通过静态分析工具如 pylint、SonarQube来辅助而非仅依赖沙箱执行结果。4.4 Agent 与流水线的协作Agent 是异步的、面向单题的而流水线是批量的、面向多题的。两者需要一个调度层来协调——流水线批量分配题目给 AgentAgent 完成单题后回传结果流水线汇总生成报告。五、总结刷题 Agent 的工具体系不是让 LLM 更强——LLM 的能力边界是固定的。它的价值在于给 LLM 配上了手和眼睛。有了沙箱LLM 能知道自己的代码能不能跑有了评测LLM 能知道哪里需要改。这种「感知-行动」闭环是让 Agent 真正能在工程场景中落地的关键。