多 Agent 协作刷题:一个出题、一个解答、一个评测的分工模式
多 Agent 协作刷题:一个出题、一个解答、一个评测的分工模式
一、单一 Agent 刷题的局限:什么都做,什么都做不好
目前大多数 AI 刷题工具都是单 Agent 模式:一个模型负责从出题到解答到评测的所有环节。这个架构在简单题上没有问题,但当题目变难时,单一 Agent 的上下文窗口和推理能力都会成为瓶颈。
具体来说,单 Agent 刷题有三个核心问题。第一,角色混淆。同一个 Agent 既要"像一个考官一样出题",又要"像一个学生一样解题",还要"像一个评测系统一样打分"——这三种角色的思维模式是冲突的。第二,自证偏差。Agent 出的题,Agent 自己解答,Agent 自己评测——这个过程缺乏外部验证。第三,能力上限。出题需要创造力,解答需要推理力,评测需要严谨的判断力——单一模型的这三项能力不可能同时是最优的。
多 Agent 协作是解决这些问题的自然思路。将刷题系统分解为三个独立的 Agent:出题 Agent、解题 Agent 和评测 Agent,各司其职,互相制约。
flowchart TB
A[用户: 设定训练目标] --> B[出题 Agent]
B --> |"根据用户薄弱点生成题目"| C[题目生成]
C --> D[解题 Agent]
D --> |"分析题目并生成解答"| E[解题过程]
E --> F[评测 Agent]
F --> |"验证正确性 + 评估代码质量"| G{通过?}
G -->|是| H[记录到用户知识库]
G -->|否| I[反馈给解题 Agent]
I --> D
H --> J[更新用户能力画像]
J --> A
subgraph 通讯协议
K["出题Agent → 解题Agent: {题目, 约束, 预期难度}"]
L["解题Agent → 评测Agent: {代码, 推理链, 复杂度分析}"]
M["评测Agent → 出题Agent: {正确性, 质量分, 建议题目方向}"]
end
二、三个 Agent 的角色定义与协作协议
出题 Agent(Problem Generator): 负责根据用户的能力画像和薄弱点,生成针对性练习题目。它的输入是用户的刷题记录(哪些题型做得好、哪些容易卡住、最近刷的频率),输出是一个结构化的题目描述(问题陈述、输入输出格式、约束条件、预期难度)。
出题 Agent 的核心能力需求:理解算法题的结构和难度分层、能创建有效的变体题目(同一模式不同表述)、以及根据用户反馈动态调整题目难度。
解题 Agent(Solution Solver): 负责解答出题 Agent 生成的题目。它需要完整的算法能力——读懂题目、选择算法、编码实现、分析复杂度。解题 Agent 的关键特征是:它不知道"标准答案"(因为题目是动态生成的),这避免了自证偏差。
评测 Agent(Judge Evaluator): 负责验证解题 Agent 的代码是否正确,并给出质量评分。它不是简单地检查输出是否匹配预期——它要做的是:运行测试用例、分析代码的边界条件处理、评估时间空间复杂度、以及给出优化建议。
评测 Agent 的一个关键特性是:它同时收到题目和解答,但它的判断逻辑不应受任何 Agent 影响。这类似于区块链中的"共识节点"——它的权威来自于算法的客观性,而非任何一个 Agent 的背书。
三、多 Agent 协作的工程框架实现
"""
多 Agent 刷题协作引擎
核心设计:
1. 三个 Agent 通过消息队列异步通信
2. 评测 Agent 有沙箱执行能力,确保代码安全
3. 结果通过评分卡反馈给出题 Agent,形成自适应出题
"""
from dataclasses import dataclass, field
from typing import List, Optional, Dict
from enum import Enum
import json
class AgentRole(Enum):
"""Agent 角色"""
PROBLEM_GENERATOR = "出题Agent"
SOLUTION_SOLVER = "解题Agent"
JUDGE_EVALUATOR = "评测Agent"
class Difficulty(Enum):
EASY = "简单"
MEDIUM = "中等"
HARD = "困难"
@dataclass
class Problem:
"""一道算法题"""
problem_id: str
title: str
description: str
input_format: str
output_format: str
constraints: str
difficulty: Difficulty
tags: List[str]
test_cases: List[dict] # [{"input": "...", "output": "..."}]
expected_complexity: str # 预期的最优复杂度
@dataclass
class Solution:
"""一份题解"""
problem_id: str
code: str
language: str
reasoning_chain: List[str] # 推理步骤
time_complexity: str
space_complexity: str
@dataclass
class Evaluation:
"""一次评测结果"""
solution: Solution
passed_cases: int
total_cases: int
time_used_ms: float
memory_used_mb: float
verdict: str # AC/WA/TLE/MLE/RE
code_quality_score: float # 0-10
suggestions: List[str]
needs_rework: bool
class MultiAgentOrchestrator:
"""
多 Agent 编排器
负责三个 Agent 之间的任务调度和消息传递。
为什么用编排器模式:三个 Agent 不应直接互相调用,
而是通过编排器解耦。这样任意一个 Agent 的模型可以
独立替换,不影响其他 Agent。
"""
def __init__(self,
problem_agent, # 出题 Agent 的 LLM 客户端
solver_agent, # 解题 Agent 的 LLM 客户端
judge_agent): # 评测 Agent 的 LLM 客户端
self.problem_agent = problem_agent
self.solver_agent = solver_agent
self.judge_agent = judge_agent
# 记录每个用户的刷题数据
self.user_profiles: Dict[str, dict] = {}
# 记录已生成过的题目(去重用)
self.generated_problems: set = set()
def run_session(self, user_id: str,
focus_areas: List[str],
session_size: int = 3) -> List[dict]:
"""
运行一次完整的刷题会话
focus_areas: 用户想重点训练的方向
session_size: 本次会话的题目数量
返回:每题的结果摘要
为什么需要 focus_areas:出题 Agent 需要知道用户薄弱点,
生成有针对性的题目。
"""
user_profile = self.user_profiles.get(user_id, {})
results = []
for i in range(session_size):
# 步骤 1:出题 Agent 生成题目
problem = self._generate_problem(
user_profile=user_profile,
focus_areas=focus_areas,
session_index=i
)
if problem is None:
continue
# 步骤 2:解题 Agent 生成解答
solution = self._solve_problem(problem)
# 步骤 3:评测 Agent 验证
evaluation = self._evaluate_solution(problem, solution)
# 步骤 4:更新用户画像
self._update_profile(user_id, problem, evaluation)
results.append({
"problem": problem,
"solution": solution,
"evaluation": evaluation,
"metrics": {
"passed": evaluation.passed_cases,
"total": evaluation.total_cases,
"quality": evaluation.code_quality_score
}
})
# 步骤 5:反馈循环——如果需要,重新解答
if evaluation.needs_rework and i < session_size:
# 给解题 Agent 反馈后重试一次
feedback = "\n".join(evaluation.suggestions)
solution = self._solve_problem(problem, feedback)
evaluation = self._evaluate_solution(problem, solution)
results[-1] = {
"problem": problem,
"solution": solution,
"evaluation": evaluation
}
return results
def _generate_problem(self, user_profile: dict,
focus_areas: List[str],
session_index: int) -> Optional[Problem]:
"""调用出题 Agent 生成题目"""
prompt = f"""
你是一个算法出题专家。请根据以下信息生成一道算法题:
用户能力画像:{json.dumps(user_profile, ensure_ascii=False)}
训练方向:{focus_areas}
当前是本次会话的第 {session_index + 1} 题
要求:
1. 题目难度递增,第 1 题偏简单
2. 题目描述清晰,约束条件自洽
3. 提供 3 组测试用例(含边界条件)
4. 输出 JSON 格式的题目数据
为什么要求约束条件自洽:如果条件矛盾(如 n<=10 但要求 O(1)),
评测 Agent 将无法正确判断。
"""
try:
response = self.problem_agent.complete(prompt)
problem_data = json.loads(response)
# 去重检查
problem_id = problem_data.get("problem_id", "")
if problem_id in self.generated_problems:
return None # 重复题目跳过
self.generated_problems.add(problem_id)
return Problem(**problem_data)
except Exception as e:
return None
def _solve_problem(self, problem: Problem,
feedback: str = "") -> Solution:
"""调用解题 Agent 生成解答"""
prompt = f"""
请解答以下算法题:
{problem.description}
输入格式:{problem.input_format}
输出格式:{problem.output_format}
约束条件:{problem.constraints}
{"上次解答的反馈:" + feedback if feedback else ""}
请提供:
1. 解题思路(逐步推理)
2. 完整代码(带注释)
3. 时间复杂度分析
4. 空间复杂度分析
"""
response = self.solver_agent.complete(prompt)
# 从响应中提取代码(简化处理)
return Solution(
problem_id=problem.problem_id,
code=self._extract_code(response),
language="python",
reasoning_chain=self._extract_reasoning(response),
time_complexity="O(n)",
space_complexity="O(1)"
)
def _evaluate_solution(self, problem: Problem,
solution: Solution) -> Evaluation:
"""调用评测 Agent 验证解答"""
# 首先在沙箱中运行测试用例
passed, total, verdict, time_ms, memory_mb = \
self._run_test_cases(solution.code, problem.test_cases)
# 然后让评测 Agent 给代码质量评分
quality_score = self._assess_code_quality(
problem.description, solution.code, verdict)
suggestions = self._generate_suggestions(
verdict, quality_score, solution)
return Evaluation(
solution=solution,
passed_cases=passed,
total_cases=total,
time_used_ms=time_ms,
memory_used_mb=memory_mb,
verdict=verdict,
code_quality_score=quality_score,
suggestions=suggestions,
needs_rework=(passed < total or quality_score < 6)
)
def _run_test_cases(self, code: str,
test_cases: List[dict]) -> tuple:
"""在安全沙箱中执行代码"""
import subprocess
passed = 0
max_time = 0
max_memory = 0
for tc in test_cases:
try:
process = subprocess.run(
["python3", "-c", self._wrap_for_test(code, tc)],
capture_output=True, timeout=5, text=True
)
if process.stdout.strip() == tc["output"].strip():
passed += 1
except:
pass
total = len(test_cases)
verdict = "AC" if passed == total else "WA"
return passed, total, verdict, max_time, max_memory
def _assess_code_quality(self, description: str,
code: str, verdict: str) -> float:
"""评测代码质量"""
prompt = f"""
请对以下代码的代码质量打分(0-10分):
题目:{description}
评测结果:{verdict}
代码:
{code}
评分维度:可读性、命名规范、算法选择、边界处理
"""
response = self.judge_agent.complete(prompt)
try:
return float(response.strip().split()[0])
except:
return 5.0
def _update_profile(self, user_id: str, problem: Problem,
evaluation: Evaluation):
"""更新用户能力画像"""
profile = self.user_profiles.get(user_id, {
"total_solved": 0,
"ac_rate": 0.0,
"weak_areas": [],
"strength_areas": [],
"recent_difficulty": "Easy"
})
profile["total_solved"] += 1
if evaluation.verdict == "AC":
profile["ac_rate"] = (
(profile["ac_rate"] * (profile["total_solved"] - 1) + 1)
/ profile["total_solved"]
)
self.user_profiles[user_id] = profile
def _extract_code(self, response: str) -> str:
# 从 LLM 响应中提取代码块
pass
def _extract_reasoning(self, response: str) -> List[str]:
pass
def _wrap_for_test(self, code: str, test_case: dict) -> str:
pass
def _generate_suggestions(self, verdict: str, quality: float,
solution: Solution) -> List[str]:
pass
四、Agent 协作的边界与可靠性分析
Agent 间的通信开销。 三个 Agent 之间每次交互都需要一次 LLM 调用,加上可能的代码执行调用。一次完整的"出题 → 解答 → 评测"周期可能需要 3-5 次 LLM 调用。如果再加上"反馈 → 重新解答"的循环,调用次数可能更多。对于实时刷题场景,需要评估用户等待时间的可接受性。
Agent 能力的互补性。 如果三个 Agent 使用同一个基础模型,它们的能力瓶颈是相同的——这并没有解决单 Agent 的"能力上限"问题。真正有价值的做法是:为不同角色使用专门优化的模型。出题 Agent 可以用代码生成能力强的模型(如 CodeLlama),解题 Agent 可以用推理能力强的模型(如 DeepSeek-R1),评测 Agent 可以用逻辑严谨的模型。
错误传播与自愈。 如果出题 Agent 生成了一道有 bug 的题目(如约束条件矛盾),评测 Agent 在测试时应该能发现这个问题。但如果评测 Agent 也没有发现,整个系统的输出就是错误的。解决方案是引入交叉验证机制——解题 Agent 也可以对题目的合理性做反馈。
成本与收益的平衡。 三个 Agent 意味着 3 倍的 LLM 调用成本。对于个人使用的刷题工具,这个成本可能偏高。但对于教育平台或比赛场景,高质量的多轮验证是值得的。
五、总结
多 Agent 协作将刷题系统从"一个全能者"变成了"一个团队"。出题 Agent 保证题目质量,解题 Agent 保证多种思路,评测 Agent 保证结果的准确性。三个 Agent 相互制约、相互补充,形成了一个闭环质量保障体系。
这个架构的核心思想不是"三个比一个好",而是"分工让每个 Agent 能专注于自己的职责"。当每个 Agent 只需要做好一件事时,整个系统的质量上限就由每个 Agent 的深度(而非广度)决定——而单 Agent 模式的质量上限受限于广度与深度的矛盾。
未来,当 Agent 能力进一步增强时,我们可能看到更多角色的加入——如"解析 Agent"(专门用于理解用户提问)、"总结 Agent"(将解题过程提炼为方法论)——刷题工具将逐步从"自动化题解"走向"智能化教练"。
更多推荐



所有评论(0)