1 项目概述与核心价值
1.1 JoyCode Agent 简介
01.产品定义
a.功能说明
a.功能说明
JoyCode Agent 是一个端到端的、由大型语言模型(LLM)驱动的自动化代码修复管道,专为解决真实世界的开源软件问题而设计。它能够自主完成从理解问题、生成补丁、创建测试到验证修复的完整流程,在权威的 SWE-bench 基准测试中表现出色,证明了其在复杂软件工程任务中的卓越能力。
b.代码示例
---
# JoyCode Agent 的核心使命是自动化处理软件仓库中的 issue,
# 以下是一个简化的概念演示,说明其工作流程。
issue = "User login fails with incorrect password."
codebase = "/path/to/project/repository"
# 1. 分析 issue 并定位相关代码
relevant_files = joycode_agent.analyze(issue, codebase)
# 2. 生成修复补丁
patch = joycode_agent.generate_patch(issue, relevant_files)
# 3. 生成并运行测试以验证补丁
test_result = joycode_agent.run_tests(patch, codebase)
# 4. 如果测试通过,则应用补丁
if test_result.passed:
joycode_agent.apply_patch(patch, codebase)
print("Issue resolved successfully!")
else:
print("Patch validation failed. Starting retry process...")
---
02.核心价值
a.提升修复效率
a.功能说明
JoyCode Agent 将传统需要数天甚至数周的人工修复流程缩短至分钟级别。通过自动化的多智能体协作,它能够 7x24 小时不间断地处理软件问题,极大地提升了研发团队的迭代速度和生产力。
b.代码示例
---
# 传统流程 vs. JoyCode Agent 流程
def traditional_bug_fixing():
# 1. 开发人员手动复现和诊断问题
# 2. 手动编写代码并进行单元测试
# 3. 提交代码并等待 CI/CD 流程
# 4. 如果失败,重复上述过程
return "耗时:1-3 天"
def joycode_agent_fixing():
# 1. Agent 自动分析、生成补丁和测试
# 2. 自动完成验证和迭代
# 3. 自动提交高质量的修复方案
return "耗时:10-30 分钟"
---
1.2 核心创新点
01.补丁与测试协同生成
a.机制概述
a.功能说明
JoyCode Agent 的核心创新之一是补丁(Patch)与测试(Test)的协同生成机制。它摒弃了先生成补丁后补充测试的传统模式,转而在理解问题的初期就同步构思修复方案和验证方法。这种协同机制确保了生成的补丁不仅能解决报告的问题(Fail2Pass),还能保证不破坏原有功能(Pass2Pass),从而显著提升修复质量和一次性成功率。
b.代码示例
---
# 协同生成流程示意
def coordinated_generation(issue):
# 基于 issue 同时生成初步的补丁和测试思路
patch_idea = llm.generate_patch_concept(issue)
test_idea = llm.generate_test_concept(issue)
# 在同一个闭环中迭代优化补丁和测试用例
refined_patch, refined_test = refine_in_loop(patch_idea, test_idea)
# 输出高度匹配的补丁和测试集
return refined_patch, refined_test
---
02.多代理架构
a.架构设计
a.功能说明
JoyCode Agent 采用先进的多代理(Multi-Agent)架构,将复杂的修复任务拆解给四个高度专业化的智能体:Testing Agent、Patch Agent、CSR Agent 和 Decision Agent。每个智能体各司其职,通过模仿人类开发团队的“观察-思考-行动”(React)工作流进行高效协作,最终实现高质量的自动化代码修复。
b.代码示例
---
# 多代理协作流程
class MultiAgentTeam:
def __init__(self):
self.testing_agent = TestingAgent()
self.patch_agent = PatchAgent()
self.csr_agent = CSRAgent() # 经验检索代理
self.decision_agent = DecisionAgent()
def fix_issue(self, issue):
# 1. 测试代理生成验证环境
test_env = self.testing_agent.create_test_environment(issue)
# 2. 补丁代理生成候选补丁
patches = self.patch_agent.generate_candidates(issue, test_env)
# 3. 经验检索代理提供历史参考
historical_data = self.csr_agent.retrieve_similar_cases(issue)
# 4. 决策代理投票选出最佳补丁
best_patch = self.decision_agent.vote(patches, historical_data)
return best_patch
---
1.3 性能表现与行业地位
01.SWE-bench 权威认证
a.测试结果
a.功能说明
JoyCode Agent 在软件工程领域的权威基准测试 SWE-bench Verified 中取得了卓越成绩。该测试集通过使用真实世界开源项目中的 Bug 报告和 Issue 来评估 AI 系统从理解问题到自主生成、集成和验证修复代码的完整端到端能力。JoyCode Agent 在此测试中凭借 74.6% 的高通过率,强势登顶全球榜单 Top 3,证明了其在复杂编程问题解决方面的领先水平。
b.代码示例
---
# SWE-bench Verified 基准测试结果对比
results = {
"TRAE": 75.2,
"JoyCode Agent": 74.6, # 在降低 30-50% 成本下达成
"Lingxi-v1.5": 74.6,
"Refact.ai Agent": 74.4
}
print("Code Agent Resolution Rate Comparison (SWE-Bench Verified)")
for agent, score in results.items():
print(f"- {agent}: {score}%")
---
02.高性价比优势
a.成本效益分析
a.功能说明
相较于业内普遍采用的“海量采样+投票”的粗放式策略,JoyCode Agent 通过其精细化的失败归因机制和有针对性的闭环迭代,实现了在显著降低 30%-50% 计算成本的前提下,达到与顶尖水平相当的修复成功率。这一高性价比优势使其在实际应用场景中具备了更强的商业价值和可行性。
b.代码示例
---
# 资源消耗对比
def brute_force_strategy():
# 生成大量候选补丁并进行投票
# 优点:简单直接
# 缺点:计算资源消耗巨大,成本高
return {"cost": "100%", "success_rate": "75%"}
def joycode_agent_strategy():
# 通过智能归因和经验迁移,进行少量、高质量的尝试
# 优点:高效、节约资源
# 缺点:技术实现复杂
return {"cost": "50-70%", "success_rate": "74.6%"}
---
1.4 应用场景与目标用户
01.应用场景
a.自动化软件维护
a.功能说明
JoyCode Agent 可用于大型代码库的持续集成和维护流程中,自动处理新出现的 Bug 报告和 Issue。它可以作为一线“AI 工程师”,先行尝试修复问题,从而减轻人类开发者的负担,使其能更专注于创新性工作。
b.代码示例
---
# CI/CD 流水线集成示例
def on_new_issue_opened(issue):
# 1. 触发 JoyCode Agent 自动修复任务
success = joycode_agent.run_fix_pipeline(issue)
# 2. 如果成功,自动创建 Pull Request
if success:
create_pull_request(issue, agent_patch)
else:
# 3. 如果失败,通知人工处理
notify_human_developer(issue)
---
02.目标用户
a.用户群体
a.功能说明
JoyCode Agent 主要面向以下用户群体:
- **大型企业研发团队**:需要维护庞大、复杂代码库的团队,希望通过自动化工具提升维护效率。
- **开源社区管理者**:希望加速 Issue 处理速度,提升社区活跃度和贡献者积极性的管理者。
- **软件工程研究人员**:从事自动化软件修复、AI 编程等领域研究的学者和学生。
- **AI 辅助编程工具开发者**:希望将先进的代码修复能力集成到其产品中的开发者。
b.代码示例
---
# 用户画像
user_profiles = [
{
"name": "Enterprise Developer",
"pain_point": "大量积压的 bug 和技术债",
"solution": "使用 JoyCode Agent 自动处理低级错误"
},
{
"name": "Open Source Maintainer",
"pain_point": "贡献者流失,issue 响应慢",
"solution": "利用 Agent 快速响应和修复社区报告的问题"
},
{
"name": "AI Researcher",
"pain_point": "缺乏强大的基线模型进行对比实验",
"solution": "基于 JoyCode Agent 开源项目进行二次开发和研究"
}
]
---
2 快速开始指南
2.1 环境要求
01.硬件与软件
a.基本配置
a.功能说明
为了确保 JoyCode Agent 能够顺利运行,您需要准备以下软硬件环境。这些要求旨在保证 Docker 容器的稳定运行以及与大型语言模型(LLM)的高效通信。
- **操作系统**:建议使用主流的 Linux 发行版(如 Ubuntu 20.04+),或 macOS。
- **Python 版本**:必须使用 Python 3.11 或更高版本。
- **Docker**:必须安装并运行 Docker 服务,且当前用户需要有权限执行 Docker 命令。
b.代码示例
---
# 检查环境命令
# 1. 检查 Python 版本
python --version
# 预期输出: Python 3.11.x
# 2. 检查 Docker 是否在运行
docker info
# 如果没有错误信息,则表示 Docker 正在运行
---
02.网络与其他
a.网络要求
a.功能说明
JoyCode Agent 的运行需要稳定的网络连接,以满足以下两个核心需求:
- **访问 LLM API**:需要能够无障碍地访问您所配置的大型语言模型 API 端点,例如 OpenAI、Anthropic 或其他私有化部署的模型服务。
- **拉取 Docker 镜像**:需要能够访问 `docker.1ms.run` 镜像仓库,以下载 SWE-bench 所需的运行环境镜像。
b.代码示例
---
# 检查网络连通性
# 1. 测试对 LLM API 的访问 (以 OpenAI 为例)
curl https://api.openai.com/v1/models
# 2. 测试对 Docker 镜像仓库的访问
docker pull docker.1ms.run/hello-world
# 如果能够成功拉取镜像,则表示网络通畅
---
2.2 安装与配置
01.安装步骤
a.详细流程
a.功能说明
安装过程主要包括克隆项目仓库、创建独立的 Python 环境以及安装所需的依赖包。推荐使用 Conda 来管理 Python 环境,以避免与其他项目产生依赖冲突。
b.代码示例
---
# 完整安装流程
# 1. 克隆 GitHub 仓库
git clone https://github.com/jd-opensource/joycode-agent.git
cd joycode-agent
# 2. 创建并激活 Conda 环境
conda create -n joycode python=3.11
conda activate joycode
# 3. 安装项目依赖
pip install -r requirements.txt
---
02.配置 LLM
a.配置文件说明
a.功能说明
JoyCode Agent 通过一个 JSON 文件来管理所有与大型语言模型相关的配置。您需要编辑 `llm_server/model_config.json` 文件,填入您所使用的 LLM 的 API 密钥(API Key)、基础 URL(Base URL)以及模型名称等信息。您可以为不同的任务(如补丁生成、测试生成等)配置不同的模型。
b.代码示例
---
# llm_server/model_config.json 配置文件示例
{
"patch_generation": {
"api_key": "sk-your_openai_api_key_here",
"base_url": "https://api.openai.com/v1",
"model_name": "gpt-4-turbo-preview",
"max_tokens": 4096,
"temperature": 0.0
},
"test_generation": {
"api_key": "your_anthropic_api_key_here",
"base_url": "https://api.anthropic.com/v1",
"model_name": "claude-3-opus-20240229",
"max_tokens": 4096,
"temperature": 0.0
}
}
---
2.3 快速运行示例
01.处理单个问题
a.命令说明
a.功能说明
您可以让 JoyCode Agent 专注于解决一个特定的问题。通过使用 `--problem-id` 参数并指定 SWE-bench 数据集中的实例 ID,Agent 将会集中所有资源处理这一个任务。这对于调试、复现特定问题或进行详细的案例分析非常有用。
b.代码示例
---
# 运行单个问题实例
# 假设我们要修复 django 项目中的 django-11099 问题
python run_patch_pipeline.py --problem-id django__django-11099 --num-processes 1
# Agent 将会执行以下步骤:
# 1. 拉取对应的 Docker 环境镜像
# 2. 在容器中复现问题
# 3. 调用 LLM 生成补丁和测试
# 4. 验证修复结果
# 5. 将所有日志和产出物保存在 output_files/django__django-11099/ 目录下
---
02.批量处理问题
a.命令说明
a.功能说明
JoyCode Agent 支持批量处理问题,并可通过多进程并行来加速修复过程。您可以指定要处理的问题数量,并设置并行进程的数量。Agent 会从 `instance_id.txt` 文件中读取问题列表,并将其分配给不同的进程进行处理。
b.代码示例
---
# 批量处理 10 个问题,使用 4 个并行进程
# 1. 首先,在 instance_id.txt 文件中定义要处理的问题列表
# django__django-11099
# matplotlib__matplotlib-23562
# sympy__sympy-18189
# ... (更多问题 ID)
# 2. 运行批量处理命令
python run_patch_pipeline.py --num-examples 10 --num-processes 4
# Agent 会启动 4 个进程,并行处理 instance_id.txt 中的前 10 个问题
---
2.4 常见使用模式
01.简单模式(仅生成补丁)
a.命令说明
a.功能说明
在某些场景下,您可能只关心代码的修复补丁,而不需要生成或运行测试。通过启用 `--simple-mode`,Agent 将跳过所有与测试相关的步骤,只执行补丁生成的核心流程。这可以显著加快运行速度,适用于对修复结果有其他验证方式的场景。
b.代码示例
---
# 以简单模式运行,只生成补丁,不进行测试
python run_patch_pipeline.py --problem-id django__django-11099 --simple-mode
# 在此模式下,Agent 将不会执行 Testing Agent 的任何操作
---
02.开启后处理
a.命令说明
a.功能说明
为了进一步提升修复成功率和分析效率,JoyCode Agent 提供了后处理(Post-processing)功能。通过启用 `--enable-post-processing`,Agent 会在修复失败后激活智能重试机制,并对执行过程的日志(Trajectory)进行压缩和相似度匹配,以便进行经验复用。这是在复现 SWE-bench 高分榜单时建议开启的选项。
b.代码示例
---
# 开启后处理功能,以启用智能重试和经验迁移
python run_patch_pipeline.py --num-processes 1 --enable-post-processing
# 如果首次尝试失败,Agent 将:
# 1. 分析失败原因(失败归因)
# 2. 检索相似的成功案例(经验迁移)
# 3. 调整策略并进行重试
# 4. 压缩执行日志以供未来分析
---
3 多代理架构详解
3.1 架构设计理念
01.模仿人类团队协作
a.设计思想
a.功能说明
JoyCode Agent 的多代理架构其核心设计理念是模仿一个高效的人类软件开发团队。在传统的软件开发中,一个复杂的问题通常需要不同角色的专家协同工作,例如,由测试工程师负责复现问题和验证修复,开发工程师负责编写代码,架构师或资深工程师负责提供解决方案和决策。JoyCode Agent 将这一协作模式映射到其智能体设计中,创建了各司其职的专业化智能体,通过明确的分工和高效的协作来解决复杂的软件工程问题。
b.代码示例
---
# 人类团队与 Agent 团队的映射关系
class HumanDevTeam:
def __init__(self):
self.tester = "测试工程师"
self.developer = "开发工程师"
self.architect = "架构师"
def handle_bug_report(self, report):
# 1. 测试工程师复现问题
self.tester.reproduce(report)
# 2. 架构师提供修复思路
solution = self.architect.design_solution(report)
# 3. 开发工程师实现代码
code = self.developer.implement(solution)
# 4. 测试工程师验证修复
self.tester.verify(code)
# JoyCode Agent 的架构正是这种模式的软件实现
# Testing Agent -> 测试工程师
# Patch Agent -> 开发工程师
# CSR/Decision Agent -> 架构师/技术负责人
---
02.React 工作流
a.工作机制
a.功能说明
JoyCode Agent 的所有智能体都遵循一个统一的“观察-思考-行动”(Observe-Think-Act,简称 React)的工作流。这个循环驱动着智能体像人类一样进行迭代式的问题解决。
- **观察 (Observe)**:智能体收集当前状态的所有相关信息,例如错误日志、代码片段、测试结果等。
- **思考 (Think)**:基于观察到的信息,智能体进行推理和规划,决定下一步应该采取什么行动。
- **行动 (Act)**:智能体执行具体的动作,例如调用一个工具、修改一个文件或向另一个智能体请求信息。
这个持续的循环使得 Agent 能够处理动态变化的环境,并根据实时的反馈调整其策略。
b.代码示例
---
# React 工作流伪代码
class BaseAgent:
def run_loop(self, initial_observation):
observation = initial_observation
while not self.is_task_complete(observation):
# 1. 思考:根据当前观察进行决策
thought = self.think(observation)
# 2. 行动:根据决策执行动作
action = self.determine_action(thought)
# 3. 观察:执行动作并获取新的观察结果
observation = self.execute_action(action)
return self.get_final_result(observation)
---
3.2 Testing Agent(测试代理)
01.核心职责
a.功能定位
a.功能说明
Testing Agent 在 JoyCode Agent 团队中扮演着“质量保证工程师”的角色。它的核心职责是为整个修复流程提供自动化测试的约束和保障。它不仅要确保生成的补丁能够解决问题,还要保证补丁不会引入新的问题(即回归错误)。
b.代码示例
---
# Testing Agent 的主要职责
class TestingAgent:
def setup_environment(self, issue):
"""为问题搭建一个隔离的、可复现的测试环境"""
# ...
def generate_fail2pass_test(self, issue):
"""生成一个能够复现原始问题的测试(失败 -> 通过)"""
# ...
def generate_pass2pass_test(self, codebase):
"""生成一组确保核心功能不被破坏的测试(通过 -> 通过)"""
# ...
def validate_patch(self, patch):
"""在一个完整的测试套件中验证补丁的有效性和安全性"""
# ...
---
02.关键能力
a.测试用例生成
a.功能说明
Testing Agent 的一项关键能力是智能生成测试用例。它主要生成两种类型的测试:
- **Fail2Pass (F2P)**:这类测试旨在精确复现用户报告的原始 Bug。一个好的 F2P 测试应该在应用补丁前是失败的,在应用补丁后是通过的。这直接证明了补丁的有效性。
- **Pass2Pass (P2P)**:这类测试是覆盖代码库核心功能的回归测试。它们在应用补丁前后都应该是通过的,用于确保补丁没有破坏任何现有功能。
b.代码示例
---
# 测试用例生成逻辑
def generate_tests(issue, codebase):
# 1. 分析 issue,生成一个能够复现问题的 F2P 测试
f2p_test = create_f2p_test(issue)
# 2. 分析受补丁影响的代码范围,生成一组 P2P 回归测试
p2p_tests = create_p2p_regression_suite(codebase, patch_scope)
return f2p_test, p2p_tests
---
3.3 Patch Agent(补丁代理)
01.核心职责
a.功能定位
a.功能说明
Patch Agent 是团队中的“核心开发工程师”,其主要职责是根据问题描述和代码上下文,生成用于修复问题的代码补丁。它接收来自其他智能体(如 Testing Agent)的信息,理解代码的逻辑和结构,并产出高质量、可应用的 diff 格式补丁。
b.代码示例
---
# Patch Agent 的主要职责
class PatchAgent:
def analyze_code(self, relevant_files):
"""深入分析与问题相关的代码文件"""
# ...
def generate_patch_candidates(self, issue, code_analysis):
"""基于问题描述和代码分析,生成多个候选补丁"""
# ...
def format_patch_as_diff(self, code_changes):
"""将代码变更格式化为标准的 diff 格式"""
# ...
---
02.关键能力
a.代码理解与生成
a.功能说明
Patch Agent 的核心是其强大的代码理解和生成能力。它利用大型语言模型(LLM)对仓库级的代码进行深度分析,理解变量、函数、类以及它们之间的复杂关系。基于这种深度的理解,它能够生成逻辑正确、风格一致且符合项目规范的代码。与简单的代码补全不同,Patch Agent 能够进行跨文件的、涉及复杂逻辑的重构级代码修改。
b.代码示例
---
# 代码生成逻辑
def generate_code_changes(issue, code_context):
# 1. 构建一个包含问题描述、相关代码和上下文的 Prompt
prompt = build_rich_prompt(issue, code_context)
# 2. 调用 LLM 生成修复方案的自然语言描述
solution_text = llm.generate_solution(prompt)
# 3. 将自然语言方案转换为具体的代码修改
code_modifications = llm.translate_to_code(solution_text)
return code_modifications
---
3.4 CSR Agent(经验检索代理)
01.核心职责
a.功能定位
a.功能说明
CSR Agent(Case-based Similarity Retrieval Agent)在团队中扮演“资深架构师”或“技术专家”的角色。它的核心职责是在修复过程中提供历史经验和成功模式的参考。当遇到一个新问题时,CSR Agent 会在历史数据库中检索与之相似的已解决问题,并提取其成功的修复策略和代码模式,为 Patch Agent 提供高质量的参考,从而避免重复“造轮子”,提升修复的效率和质量。
b.代码示例
---
# CSR Agent 的主要职责
class CSRAgent:
def retrieve_similar_cases(self, current_issue):
"""从历史成功案例数据库中检索最相似的案例"""
# 1. 将当前问题向量化
issue_vector = vectorize(current_issue)
# 2. 在数据库中进行相似度搜索
similar_cases = vector_db.search(issue_vector, top_k=3)
return similar_cases
def extract_successful_patterns(self, cases):
"""从相似案例中提取可复用的修复模式和策略"""
# ...
---
02.关键能力
a.相似度匹配与模式提取
a.功能说明
CSR Agent 的关键能力在于其高效的相似度匹配和模式提取技术。它通过先进的向量化技术将代码问题、错误日志、代码片段等信息转化为高维向量,并存储在专门的向量数据库中。当新问题出现时,它能够快速地在海量历史数据中找到最相关的案例。此外,它还能从这些案例中自动提取出核心的修复模式(例如,某种特定的 API 调用方式、一种设计模式的应用等),为当前问题的解决提供直接的、高质量的参考输入。
b.代码示例
---
# 模式提取逻辑
def extract_patterns(similar_cases):
patterns = []
for case in similar_cases:
# 分析案例的补丁和解决方案
analysis = analyze_patch(case.patch)
# 识别其中可复用的设计模式或代码结构
if analysis.contains_pattern:
patterns.append(analysis.pattern)
return patterns
---
3.5 Decision Agent(决策代理)
01.核心职责
a.功能定位
a.功能说明
Decision Agent 是团队的“技术负责人”或“项目经理”,负责在关键节点上做出最优决策。当 Patch Agent 生成了多个候选补丁,或者不同的智能体给出了相互冲突的建议时,Decision Agent 会站出来,综合所有信息进行投票和仲裁,最终选择一个成功率最高、风险最低的方案来执行。
b.代码示例
---
# Decision Agent 的主要职责
class DecisionAgent:
def vote_for_best_patch(self, patch_candidates, context):
"""对多个候选补丁进行评估和投票,选出最优方案"""
scores = []
for patch in patch_candidates:
# 评估每个补丁的质量、风险和与历史经验的匹配度
score = self.evaluate(patch, context)
scores.append(score)
# 返回得分最高的补丁
best_patch = patch_candidates[scores.index(max(scores))]
return best_patch
---
02.关键能力
a.LLM 驱动的投票仲裁
a.功能说明
Decision Agent 的决策过程并非基于简单的规则,而是由大型语言模型(LLM)驱动的。它会将所有候选方案、测试结果、CSR Agent 提供的历史经验、代码复杂度分析等信息,构建成一个复杂的决策上下文,然后请求 LLM 对这些方案进行综合评估和排序。这种方法能够模拟资深开发者的直觉和经验,做出更加智能和可靠的决策。
b.代码示例
---
# LLM 驱动的投票逻辑
def llm_based_voting(candidates, context):
# 1. 构建一个包含所有候选方案和上下文信息的 Prompt
prompt = build_voting_prompt(candidates, context)
# 2. 请求 LLM 返回一个排序后的方案列表或最优方案的索引
response = llm.generate(prompt, response_format="json")
best_choice_index = response["best_choice_index"]
return candidates[best_choice_index]
---
4 补丁-测试协同生成
4.1 协同生成机制概述
01.传统模式的弊端
a.生成与验证脱节
a.功能说明
在传统的自动化修复流程中,补丁生成和测试验证往往是两个独立的、串行的步骤。系统首先会集中精力生成一个它认为正确的补丁,然后再将这个补丁交给测试框架去验证。这种模式的主要弊端在于,生成阶段缺乏来自测试的实时反馈,导致模型可能会在一个错误的方向上“越走越远”,最终产出一个完全不符合测试要求的补丁,从而浪费了大量的计算资源。
b.代码示例
---
# 传统串行流程
def serial_repair_process(issue):
# 步骤 1: 单独生成补丁,不考虑测试细节
patch = generate_patch_in_isolation(issue)
# 步骤 2: 将生成的补丁交给测试系统
# 此时如果补丁方向错误,则所有工作白费
test_result = run_validation_suite(patch)
if not test_result.passed:
# 不得不从头再来
return serial_repair_process(issue)
---
02.协同生成的核心思想
a.将测试作为生成约束
a.功能说明
JoyCode Agent 的协同生成机制彻底改变了这一模式。其核心思想是将“测试”从一个后置的验证环节,前置为生成过程中的一个核心约束。在生成补丁的每一个阶段,Agent 都会同时思考“我应该如何修复?”和“我应该如何验证这个修复?”。测试用例(尤其是能够复现问题的 Fail2Pass 测试)成为指导补丁生成方向的“灯塔”,确保补丁从一开始就朝着解决实际问题的正确方向前进。
b.代码示例
---
# 协同生成流程
def coordinated_repair_process(issue):
# 步骤 1: 首先构思一个能够复现问题的测试
fail2pass_test = conceive_test(issue)
# 步骤 2: 在测试的指导下生成补丁
# LLM 的目标是让这个测试通过
patch = generate_patch_guided_by_test(issue, fail2pass_test)
# 此时的补丁有极大概率是有效的
return patch
---
4.2 智能测试生成(Fail2Pass 和 Pass2Pass)
01.Fail2Pass (F2P) 测试
a.目的与价值
a.功能说明
Fail2Pass (F2P) 测试是专门为复现原始 Bug 而设计的测试用例。它的核心价值在于为补丁的有效性提供了一个明确、可量化的目标。一个高质量的 F2P 测试应该具备以下特点:
- **在应用补丁前必定失败**:这证明了它确实捕捉到了原始问题的核心。
- **在应用补丁后必定通过**:这直接证明了补丁成功解决了这个问题。
通过 F2P 测试,JoyCode Agent 将一个模糊的“修复问题”的任务,转化为一个精确的“让这个测试通过”的任务,极大地降低了 LLM 的理解和推理成本。
b.代码示例
---
# F2P 测试的概念示例
# 问题描述: "当用户密码错误时,登录函数没有返回 False"
# 生成的 F2P 测试
def test_login_with_wrong_password():
# 在应用补丁前,该断言会失败
assert login("test_user", "wrong_password") == False
# Patch Agent 的目标就是修改 login 函数,让上述断言通过
---
02.Pass2Pass (P2P) 测试
a.目的与价值
a.功能说明
Pass2Pass (P2P) 测试本质上是回归测试套件。它的目的是确保补丁在修复一个问题的同时,没有破坏代码库中其他任何已有的功能。在生成补丁时,Agent 会分析代码的依赖关系,智能地选取与修改范围相关的核心功能模块,并为其生成或调用已有的 P2P 测试。这些测试在应用补丁前后都应该保持通过状态。P2P 测试是保证代码质量和系统稳定性的关键防线。
b.代码示例
---
# P2P 测试的概念示例
# 假设 login 函数依赖于一个 user_exists 函数
# 补丁修改了 login 函数
# P2P 测试会确保 user_exists 函数的功能不受影响
def test_user_exists_functionality():
assert user_exists("existing_user") == True
assert user_exists("non_existing_user") == False
# 这个测试在打补丁前后都必须通过
---
4.3 补丁生成策略
01.测试驱动的补丁生成
a.生成过程
a.功能说明
在协同生成机制下,补丁的生成过程是严格由测试驱动的。Patch Agent 在生成代码时,其首要目标不再是模糊地“修复问题”,而是精确地“让 F2P 测试通过,同时保持所有 P2P 测试通过”。这个明确的目标极大地约束了 LLM 的搜索空间,使其能够更专注于产出有效的代码。Agent 会将 F2P 测试的失败信息(如断言错误、异常堆栈等)作为关键输入,指导其进行下一轮的代码修改。
b.代码示例
---
# 测试驱动的生成循环
def test_driven_patch_generation(issue):
f2p_test, p2p_tests = testing_agent.generate_tests(issue)
patch = None
last_error = None
for _ in range(MAX_ATTEMPTS):
# 将测试失败信息一同输入 LLM
patch = patch_agent.generate_patch(issue, last_error)
# 验证新生成的补丁
f2p_result, p2p_results = testing_agent.validate(patch, f2p_test, p2p_tests)
if f2p_result.passed and all(p.passed for p in p2p_results):
return patch # 成功
else:
# 记录新的失败信息,用于下一轮迭代
last_error = f2p_result.error or find_first_error(p2p_results)
return None # 失败
---
02.多候选与预验证
a.策略说明
a.功能说明
为了提升效率,Patch Agent 并非一次只生成一个补丁,而是会生成多个候选补丁。更重要的是,在将这些补丁提交给完整的、耗时较长的测试套件之前,Agent 会进行一次“预验证”(Pre-validation)。预验证通常包括静态代码分析、语法检查、类型检查等轻量级检查。只有通过了预验证的候选补丁,才有资格进入下一轮的完整测试。这个策略能够提前过滤掉大量低质量或明显错误的补丁,节约宝贵的计算资源。
b.代码示例
---
# 预验证流程
def generate_with_pre_validation(issue):
# 1. 生成多个候选补丁
candidates = patch_agent.generate_multiple_candidates(issue, count=5)
validated_candidates = []
for patch in candidates:
# 2. 对每个候选补丁进行轻量级预验证
if pre_validation_check(patch):
validated_candidates.append(patch)
# 3. 只将通过预验证的补丁送去完整测试
return run_full_validation(validated_candidates)
---
4.4 协同验证流程
01.统一的验证环境
a.环境说明
a.功能说明
协同验证流程发生在一个由 Testing Agent 搭建的统一、隔离的验证环境中。这个环境基于 SWE-bench 提供的 Docker 镜像,完整地复刻了原始项目在特定版本下的所有依赖和状态。所有的测试,无论是 F2P 还是 P2P,都在这个环境中执行。这确保了验证结果的确定性和可复现性,避免了因环境不一致导致“在我这里是好的”这类典型问题。
b.代码示例
---
# 验证环境的搭建和使用
def validation_process(patch, tests):
# 1. 启动一个干净的、基于项目镜像的 Docker 容器
container = docker.run(image=project_image, detach=True)
try:
# 2. 在容器中应用补丁
container.exec_run(f"git apply {patch}")
# 3. 在容器中执行所有测试
results = container.exec_run(f"pytest {tests}")
finally:
# 4. 销毁容器,确保环境隔离
container.stop()
container.remove()
return results
---
02.全面的结果评估
a.评估维度
a.功能说明
对于每个补丁的验证结果,系统会进行全面的评估,而不仅仅是看测试是否通过。评估维度包括:
- **F2P 测试状态**:是否从失败转为通过。
- **P2P 测试状态**:是否全部保持通过。
- **代码质量**:补丁是否引入了代码风格问题、复杂度提升等。
- **性能影响**:补丁是否对关键路径的性能产生负面影响(高级功能)。
这些评估结果将作为 Decision Agent 进行最终决策的重要依据。
b.代码示例
---
# 结果评估数据结构
class ValidationReport:
def __init__(self, f2p_result, p2p_results, quality_metrics):
self.f2p_passed = f2p_result.status == "passed"
self.p2p_all_passed = all(r.status == "passed" for r in p2p_results)
self.quality_score = quality_metrics.score
self.is_successful = self.f2p_passed and self.p2p_all_passed
# ...
report = ValidationReport(f2p, p2p, quality)
---
4.5 闭环迭代机制
01.生成-验证-优化循环
a.循环过程
a.功能说明
协同生成与验证构成了一个紧密的闭环迭代系统:“生成 → 验证 → 优化”。如果一次验证失败,其失败信息(如测试报告、错误日志)会立刻被反馈给 Patch Agent,作为下一轮生成任务的关键输入。Agent 会从失败中学习,调整其策略,并生成一个更有可能成功的补丁。这个快速的反馈循环取代了传统的一次性、开环的生成方式,是 JoyCode Agent 高成功率的核心保障。
b.代码示例
---
# 闭环迭代伪代码
def closed_loop_iteration(issue):
context = build_initial_context(issue)
for i in range(MAX_ITERATIONS):
# 生成
patch = patch_agent.generate(context)
# 验证
report = testing_agent.validate(patch)
if report.is_successful:
return patch # 成功退出循环
else:
# 优化:将失败报告加入上下文,进行下一轮迭代
context.add_feedback(report)
return None # 达到最大迭代次数后失败
---
02.智能终止条件
a.终止策略
a.功能说明
这个闭环迭代并非无限进行。JoyCode Agent 设计了智能的终止条件以避免资源浪费。终止条件包括:
- **达到最大迭代次数**:防止在无解的问题上无限循环。
- **连续多次产出相同的无效补丁**:表明 Agent 可能陷入了局部最优,需要更换策略或终止。
- **资源消耗达到预设阈值**:如 Token 消耗、时间消耗等。
- **检测到不可修复的根本性问题**:例如,问题描述本身存在逻辑矛盾。
b.代码示例
---
# 终止条件检查
def should_terminate(iteration_count, history, resource_usage):
if iteration_count >= MAX_ITERATIONS:
return True, "Max iterations reached"
if has_repeated_failures(history, times=3):
return True, "Repeated same failure"
if resource_usage.tokens > TOKEN_LIMIT:
return True, "Token limit exceeded"
return False, ""
---
5 智能失败归因与重试策略
5.1 失败归因机制
01.超越简单的“通过/失败”
a.深层原因分析
a.功能说明
传统的自动化测试只能告诉我们一个补丁是“通过”了还是“失败”了,但无法告知失败的根本原因。JoyCode Agent 的智能失败归因机制旨在解决这个问题。当一次修复尝试失败时,系统不会简单地将其标记为“失败”,而是会启动一个深层原因分析流程,精准地区分失败是由以下哪种情况引起的:
- **补丁逻辑缺陷**:补丁本身的代码逻辑有误。
- **测试用例问题**:用于验证的测试用例本身存在问题。
- **环境错误**:例如依赖项冲突、配置错误等。
- **偶发性错误**:例如网络超时、资源抖动等。
b.代码示例
---
# 失败归因的类型定义
from enum import Enum
class FailureCause(Enum):
PATCH_LOGIC_ERROR = "补丁逻辑错误"
TEST_CASE_ISSUE = "测试用例问题"
ENVIRONMENT_FAILURE = "环境错误"
FLAKY_ERROR = "偶发性错误"
UNKNOWN = "未知原因"
def analyze_failure(failure_log):
if "AssertionError" in failure_log:
return FailureCause.PATCH_LOGIC_ERROR
elif "ModuleNotFoundError" in failure_log:
return FailureCause.ENVIRONMENT_FAILURE
elif "TimeoutException" in failure_log:
return FailureCause.FLAKY_ERROR
# ... more rules
else:
return FailureCause.UNKNOWN
---
02.归因的重要性
a.指导重试策略
a.功能说明
精准的失败归因是制定高效重试策略的基础。如果不知道失败的真正原因,重试就只能是盲目的、重复的。而通过失败归因,JoyCode Agent 可以像一个经验丰富的开发者一样,针对不同的失败原因采取截然不同的重试策略,从而避免在同一个地方反复失败,显著提升重试的成功率。
b.代码示例
---
# 基于归因的策略选择
def select_retry_strategy(failure_cause):
if failure_cause == FailureCause.PATCH_LOGIC_ERROR:
# 策略:修改 Prompt,让 LLM 重新思考解决方案
return "modify_patch_generation_prompt"
elif failure_cause == FailureCause.TEST_CASE_ISSUE:
# 策略:指示 Testing Agent 修复或重写测试用例
return "regenerate_test_case"
elif failure_cause == FailureCause.ENVIRONMENT_FAILURE:
# 策略:检查 Dockerfile 和依赖配置
return "inspect_environment_setup"
elif failure_cause == FailureCause.FLAKY_ERROR:
# 策略:简单地直接重试一次
return "simple_rerun"
---
5.2 根因分析方法
01.日志与堆栈分析
a.自动化分析技术
a.功能说明
JoyCode Agent 实现根因分析的首要技术是自动化日志与异常堆栈(Stack Trace)分析。系统会捕获测试失败时产生的所有输出,包括 stdout、stderr 以及详细的日志文件。然后,它会利用大型语言模型(LLM)和一系列预定义的规则来解析这些文本信息。例如,通过识别堆栈中的特定异常类型(如 `AssertionError`, `NullPointerException`)、错误信息中的关键词以及它们在代码中的位置,Agent 能够初步判断失败的性质和根源。
b.代码示例
---
# 堆栈分析伪代码
def analyze_stack_trace(stack_trace):
# 使用 LLM 分析堆栈信息
prompt = f"""分析以下 Python 异常堆栈,总结失败的根本原因:
{stack_trace}
返回一个 JSON 对象,包含 'error_type', 'file', 'line_number', 'summary'。"""
analysis_result = llm.generate(prompt, response_format="json")
return analysis_result
# 示例分析结果:
# {
# "error_type": "AssertionError",
# "file": "/app/tests/test_login.py",
# "line_number": 42,
# "summary": "在测试 test_login_with_wrong_password 时,断言 login() 返回 False 失败,实际返回了 None。"
# }
---
02.代码与变更对比
a.差异分析
a.功能说明
当日志分析不足以确定问题时,Agent 会进行代码层面的差异分析。它会对比原始代码、生成的补丁以及测试代码,试图从代码变更本身找到问题的线索。例如:
- **补丁分析**:补丁是否修改了与失败日志相关的代码区域?修改的逻辑是否复杂或容易出错?
- **测试分析**:失败的测试用例本身逻辑是否清晰、正确?它是否依赖了某些被补丁修改了的、不稳定的部分?
通过这种方式,Agent 能够更精确地将问题定位到是“补丁写错了”还是“测试写错了”。
b.代码示例
---
# 代码差异分析逻辑
def diff_analysis(original_code, patch, failed_test):
# 1. 定位补丁修改的核心区域
changed_lines = get_changed_lines(patch)
# 2. 定位失败测试的核心逻辑
test_logic_lines = get_test_logic(failed_test)
# 3. 分析两者之间的关联
if is_related(changed_lines, test_logic_lines):
# 如果补丁修改了测试直接依赖的代码,则问题很可能出在补丁上
return FailureCause.PATCH_LOGIC_ERROR
else:
# 否则,问题可能出在测试用例本身
return FailureCause.TEST_CASE_ISSUE
---
5.3 针对性重试策略
01.基于归因的策略选择
a.策略映射
a.功能说明
在完成失败归因后,JoyCode Agent 会根据归因结果,从一个预定义的策略库中选择最合适的重试策略。这种“对症下药”的方式是智能重试的核心。例如:
- **补丁逻辑错误**:Agent 会调整生成补丁的 Prompt,可能会加入更明确的指令、提供失败的测试日志作为上下文,或者要求 LLM 采用不同的方法重新思考解决方案。
- **测试用例问题**:Agent 会指示 Testing Agent 重新生成或修复有问题的测试用例。
- **环境错误**:Agent 会尝试重建 Docker 环境,或检查并修复依赖配置文件。
- **偶发性错误**:Agent 会简单地重新运行一次完全相同的任务。
b.代码示例
---
# 重试策略执行器
def execute_retry_strategy(strategy, context):
if strategy == "modify_patch_generation_prompt":
# 在上下文中加入失败反馈,然后重新调用 Patch Agent
new_context = add_failure_feedback_to_context(context)
return patch_agent.generate(new_context)
elif strategy == "regenerate_test_case":
# 调用 Testing Agent 修复测试
return testing_agent.fix_test(context.failed_test)
elif strategy == "simple_rerun":
# 使用完全相同的上下文再试一次
return patch_agent.generate(context)
# ... 其他策略
---
02.策略的多样性
a.多种重试方法
a.功能说明
JoyCode Agent 的重试策略库不仅包含简单的重新生成,还包括一系列更加精细和多样化的方法,以应对复杂的失败场景。这些策略包括:
- **增加模型创造性 (Temperature)**:如果 Agent 陷入局部最优,可以适当提高 LLM 的 temperature 参数,鼓励其探索更多样化的解决方案。
- **引入历史经验 (CSR)**:如果初步尝试失败,可以调用 CSR Agent,查找相似的成功案例,并将其解决模式作为“提示”输入给 Patch Agent。
- **分解问题**:对于复杂的失败,Agent 可能会尝试将问题分解为更小的子问题,并逐一解决。
b.代码示例
---
# 多样化的重试策略
def advanced_retry(context):
# 如果多次简单重试失败,尝试更高级的策略
if context.retry_count > 2:
# 策略1:提高 temperature
context.llm_config.temperature = 0.5
return patch_agent.generate(context)
if context.retry_count > 4:
# 策略2:引入 CSR 经验
similar_patterns = csr_agent.retrieve_patterns(context.issue)
context.add_prompt_hint(similar_patterns)
return patch_agent.generate(context)
---
5.4 经验迁移与学习
01.CSR 代理的角色
a.提供成功模式
a.功能说明
在智能重试策略中,CSR Agent(经验检索代理)扮演着至关重要的角色。当一个问题经过初步尝试后未能解决时,系统会调用 CSR Agent。它会在历史成功案例数据库中,根据当前问题的特征(如错误类型、涉及的代码模块等),检索出最相似的成功修复案例。然后,它会从这些案例中提取出核心的、可复用的“修复模式”,并将这些模式作为高质量的“灵感”或“提示”,提供给 Patch Agent,指导其进行下一轮的修复尝试。
b.代码示例
---
# CSR Agent 参与重试流程
def retry_with_csr(context):
# 1. 从 CSR Agent 获取相似成功案例的修复模式
patterns = csr_agent.retrieve_successful_patterns(context.issue)
if patterns:
# 2. 将这些模式作为强大的提示加入到 Prompt 中
hint = f"请参考以下成功模式来解决问题:{patterns}"
context.add_hint(hint)
# 3. 基于新的上下文重新生成补丁
return patch_agent.generate(context)
---
02.从失败中学习
a.构建失败案例库
a.功能说明
除了从成功中学习,JoyCode Agent 也会从失败中吸取教训。每一次失败的尝试,其完整的上下文信息(包括问题描述、代码状态、生成的补丁、失败日志、归因结果等)都会被记录下来,形成一个“失败案例库”。在未来的任务中,Agent 可以查询这个库,避免重蹈覆-辙。例如,如果某种类型的补丁在特定模块中被证明是无效的,Agent 在未来遇到类似问题时就会主动避开这种方案。
b.代码示例
---
# 从失败中学习的逻辑
def generate_avoiding_past_failures(context):
# 1. 查询失败案例库,获取已知的无效模式
known_bad_patterns = failure_db.query(context.issue)
if known_bad_patterns:
# 2. 在 Prompt 中明确指示 LLM 避免这些模式
avoidance_instruction = f"请不要使用以下模式,因为它们已被证明是无效的:{known_bad_patterns}"
context.add_instruction(avoidance_instruction)
return patch_agent.generate(context)
---
5.5 资源优化策略
01.避免无效重试
a.智能终止
a.功能说明
智能失败归因的一个直接好处就是能够识别出那些“不可修复”或“无意义重试”的情况,从而避免计算资源的浪费。例如:
- **识别问题本身的缺陷**:如果 Agent 分析发现问题描述含糊不清或存在逻辑矛盾,它会提前终止并请求人类介入,而不是盲目尝试。
- **检测循环依赖**:如果 Agent 发现自己陷入了在两种无效状态之间来回切换的循环,它会主动跳出循环。
- **设置重试上限**:为每个问题设置一个合理的重试次数上限,防止在“无解”问题上投入过多资源。
b.代码示例
---
# 智能终止检查
def intelligent_termination_check(context):
if is_issue_description_ambiguous(context.issue):
return True, "Issue description is ambiguous. Human intervention required."
if detect_cyclic_dependency_in_retries(context.history):
return True, "Cyclic failure detected. Terminating."
if context.retry_count >= MAX_RETRIES_PER_ISSUE:
return True, "Maximum retry limit reached."
return False, ""
---
02.成本控制
a.精细化资源管理
a.功能说明
JoyCode Agent 的策略旨在用最少的资源解决问题,体现了其“质量优先”而非“数量优先”的设计哲学。与通过生成海量候选方案来“暴力破解”的方法不同,JoyCode Agent 的每一次尝试都是经过深思熟虑的。通过测试驱动生成、失败归因、经验迁移等机制,系统确保了大部分计算资源都用在了高质量、高成功率的尝试上,从而在宏观上实现了显著的成本节约。
b.代码示例
---
# 成本控制理念对比
class BruteForceApproach:
def solve(self, issue):
# 生成 100 个候选方案,然后投票
candidates = self.generate(issue, count=100)
return self.vote(candidates)
# 成本高,但对失败的容忍度也高
class JoyCodeAgentApproach:
def solve(self, issue):
# 最多进行 5 次高质量的迭代尝试
for i in range(5):
context = self.analyze(issue, history)
candidate = self.generate_one_high_quality_candidate(context)
if self.validate(candidate):
return candidate
history.add(failure_info)
# 成本低,但要求每一次尝试都非常智能
---
6 LLM 集成与配置
6.1 LLM 配置文件详解
01.配置文件结构
a.文件位置与格式
a.功能说明
JoyCode Agent 的所有大型语言模型(LLM)相关的配置都集中在项目根目录下的 `llm_server/model_config.json` 文件中。这是一个标准的 JSON 文件,其顶层键(Top-level Key)代表了不同的任务或代理,例如 `patch_generation`(补丁生成)、`test_generation`(测试生成)、`decision_making`(决策)等。通过这种方式,您可以为系统中的不同环节配置最适合的模型和参数。
b.代码示例
---
# llm_server/model_config.json 完整结构示例
{
"patch_generation": {
"api_key": "your_api_key_for_patch_generation",
"base_url": "https://api.openai.com/v1",
"model_name": "gpt-4-turbo-preview",
"max_tokens": 4096,
"temperature": 0.0
},
"test_generation": {
"api_key": "your_api_key_for_test_generation",
"base_url": "https://api.anthropic.com/v1",
"model_name": "claude-3-opus-20240229",
"max_tokens": 4096,
"temperature": 0.2
},
"default": {
"api_key": "your_default_api_key",
"base_url": "https://api.example.com/v1",
"model_name": "your-local-model",
"max_tokens": 2048,
"temperature": 0.1
}
}
---
02.核心配置项
a.参数说明
a.功能说明
在每个任务的配置块中,包含以下核心参数:
- **`api_key`**:必需,用于访问该模型服务的 API 密钥。
- **`base_url`**:必需,模型服务的 API 端点 URL。
- **`model_name`**:必需,您希望调用的具体模型名称。
- **`max_tokens`**:可选,控制模型单次生成内容的最大长度(Token 数量)。
- **`temperature`**:可选,控制生成内容的创造性或随机性。值越高(如 0.8),结果越随机、越有创造性;值越低(如 0.1),结果越确定、越保守。默认值通常为 0 或 0.1,以保证结果的稳定性。
b.代码示例
---
# 单个配置块的详细说明
"patch_generation": {
// 用于身份验证的 API Key
"api_key": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
// API 的基础 URL,支持 OpenAI 兼容的任何端点
"base_url": "https://api.openai.com/v1",
// 具体的模型标识符
"model_name": "gpt-4-turbo-preview",
// 生成内容的最大 Token 数,防止内容过长被截断
"max_tokens": 4096,
// 控制结果的随机性,0.0 表示最确定性的输出
"temperature": 0.0
}
---
6.2 支持的模型列表
01.官方兼容模型
a.主流商业模型
a.功能说明
JoyCode Agent 的 LLM 客户端设计遵循 OpenAI 的 API 标准,因此理论上支持所有与 OpenAI API 兼容的模型服务。官方经过充分测试并推荐的主流商业模型包括:
- **OpenAI 系列**:GPT-4, GPT-4 Turbo, GPT-3.5 Turbo 等。
- **Anthropic Claude 系列**:Claude 3 Opus, Claude 3 Sonnet, Claude 3 Haiku 等。
- **其他兼容服务**:例如 Azure OpenAI Service, Groq, Perplexity 等提供的兼容 API。
b.代码示例
---
# 配置 Anthropic Claude 3 Opus 模型示例
"decision_making": {
"api_key": "your_anthropic_api_key",
"base_url": "https://api.anthropic.com/v1", // 注意:实际中可能需要适配器或代理
"model_name": "claude-3-opus-20240229",
"max_tokens": 4096,
"temperature": 0.1
}
---
02.私有化与本地模型
a.本地部署支持
a.功能说明
得益于其标准化的客户端设计,JoyCode Agent 同样可以无缝对接近年来涌现的众多开源和本地化部署的大型语言模型。只要您将本地模型通过工具(如 `vLLM`, `Ollama`, `LocalAI` 等)封装成一个兼容 OpenAI API 的服务,就可以在 `model_config.json` 中直接配置和使用。这为数据隐私要求严格或希望降低 API 成本的企业提供了极大的灵活性。
b.代码示例
---
# 配置本地部署的 Ollama 模型示例
# 假设您已通过 Ollama 在本地运行了 llama3 模型
# 并通过代理将其 API 暴露在 http://localhost:11434
"code_analysis": {
"api_key": "ollama", // Ollama 通常不需要 API Key
"base_url": "http://localhost:11434/v1",
"model_name": "llama3",
"max_tokens": 4096,
"temperature": 0.1
}
---
6.3 模型选择策略
01.任务与模型的匹配
a.策略建议
a.功能说明
不同的任务对模型能力的要求不同,因此,为不同任务选择合适的模型是兼顾效果与成本的关键策略。JoyCode Agent 允许用户对每个环节进行独立的模型配置,以下是一些推荐的策略:
- **核心生成任务 (Patch/Test Generation)**:建议使用能力最强的模型,如 `GPT-4 Turbo` 或 `Claude 3 Opus`,以保证生成代码的质量和逻辑的正确性。
- **分析与决策任务 (Failure Attribution/Decision Making)**:可以使用次一级的模型,如 `GPT-4o` 或 `Claude 3 Sonnet`,这些任务对推理能力要求高,但生成内容较少。
- **辅助性任务 (Log Compression/Summarization)**:可以使用成本更低的轻量级模型,如 `GPT-3.5 Turbo` 或 `Claude 3 Haiku`,甚至是本地的 `Llama3` 模型。
b.代码示例
---
# 任务与模型匹配的配置示例
{
// 使用最强模型保证代码质量
"patch_generation": { "model_name": "gpt-4-turbo-preview", ... },
// 使用推理能力强、速度快的模型进行决策
"decision_making": { "model_name": "claude-3-sonnet-20240229", ... },
// 使用经济型模型处理日志
"log_compression": { "model_name": "gpt-3.5-turbo", ... }
}
---
02.成本与性能的权衡
a.权衡策略
a.功能说明
在模型选择上,需要在成本和性能之间做出明智的权衡。虽然最强大的模型通常效果最好,但其成本也最高。在实际应用中,可以采用“瀑布流”(Waterfall)或“级联”(Cascade)的模型调用策略。即,首先尝试使用一个成本较低、速度较快的模型来解决问题。如果它失败了,再将任务升级,交由一个更强大、但成本也更高的模型来处理。这种策略可以在保证最终成功率的同时,显著降低平均处理成本。
b.代码示例
---
# 级联模型调用策略伪代码
def solve_with_cascade_models(issue):
# 1. 首先尝试使用经济型模型
try:
solution = solve_with_model(issue, model="gpt-3.5-turbo")
return solution
except Exception as e:
print("经济型模型失败,升级到性能型模型...")
# 2. 如果失败,再使用旗舰型模型
try:
solution = solve_with_model(issue, model="gpt-4-turbo")
return solution
except Exception as e2:
print("所有模型均失败")
return None
---
6.4 Token 优化技术
01.上下文压缩
a.技术说明
a.功能说明
大型语言模型的调用成本与其输入的上下文长度(Token 数量)直接相关。JoyCode Agent 在与 LLM 交互的过程中,会产生大量的中间日志和观察结果,即“执行轨迹”(Trajectory)。为了在保证信息完整性的前提下降低 Token 消耗,系统内置了上下文压缩技术。它会在将长篇的执行轨迹作为输入之前,先调用一个轻量级模型对其进行总结和压缩,提取出最核心、最相关的信息,从而在不影响决策质量的情况下,大幅减少发送给核心模型的 Token 数量。
b.代码示例
---
# 上下文压缩流程
def get_compressed_context(full_trajectory_log):
# 1. 定义一个用于压缩的 Prompt
prompt = f"""请总结以下执行日志,提取关键的失败信息和成功尝试,限制在 500 字以内:
{full_trajectory_log}"""
# 2. 使用一个轻量级、经济的模型进行压缩
compressed_log = llm.generate(prompt, model="gpt-3.5-turbo")
return compressed_log
---
02.精简化的 Prompt
a.Prompt 工程
a.功能说明
除了对上下文进行压缩,JoyCode Agent 在 Prompt 设计本身也遵循精简化的原则。通过大量的 Prompt 工程实验,系统内置了一套经过优化的、高度结构化的 Prompt 模板。这些模板能够在最短的篇幅内,最清晰地向 LLM 传达任务目标、约束条件和必要的上下文信息,避免了冗余和不必要的自然语言描述,从而在源头上控制了 Token 的消耗。
b.代码示例
---
# 精简化 Prompt 示例 (对比)
# 反例:冗余的 Prompt
prompt_bad = "你好,语言模型。我希望你能帮我解决一个软件问题。这个问题是关于...,我希望你生成的代码能够...,请注意..."
# 正例:精简、结构化的 Prompt
prompt_good = f"""[TASK] Fix Bug
[ISSUE_DESCRIPTION]
{issue_text}
[CODE_CONTEXT]
{relevant_code}
[CONSTRAINTS]
- Must pass the provided test case.
- Must adhere to PEP8 style guide.
[OUTPUT_FORMAT]
Return only the code diff.
"""
---
6.5 API 调用管理
01.客户端管理器
a.统一管理
a.功能说明
为了方便地管理与不同模型服务的交互,JoyCode Agent 设计了一个 `ClientManager`。这个管理器会负责读取 `model_config.json` 配置文件,并为其中定义的每一个模型任务,初始化一个对应的 API 客户端。当系统中的任何一个 Agent 需要调用 LLM 时,它无需关心具体的 API Key 或 URL,只需向 `ClientManager` 请求一个特定任务的客户端即可。这种设计极大地简化了 API 调用,并使得模型的切换和管理变得非常方便。
b.代码示例
---
# ClientManager 的使用
from llm_server.client_manager import ClientManager
# 1. 初始化管理器,它会自动加载配置文件
client_manager = ClientManager()
# 2. 获取用于补丁生成的客户端
patch_client = client_manager.get_client("patch_generation")
# 3. 使用该客户端进行 API 调用
response = patch_client.generate("some prompt")
# 4. 获取用于决策的客户端
decision_client = client_manager.get_client("decision_making")
---
02.性能监控
a.监控与日志
a.功能说明
JoyCode Agent 内置了对 LLM API 调用的性能监控功能。每一次 API 调用,其耗时、使用的 Token 数量、是否成功等信息都会被详细地记录下来。这些数据对于分析系统的性能瓶颈、控制成本以及评估不同模型的性价比至关重要。用户可以通过日志查看详细的调用记录,从而对整个系统的运行状态有更清晰的了解。
b.代码示例
---
# 性能监控日志示例
# 2026-02-19 14:30:15 INFO [LLM Performance] Task: patch_generation, Model: gpt-4-turbo-preview, Duration: 15.3s, Prompt Tokens: 3102, Completion Tokens: 850, Success: True
# 2026-02-19 14:30:20 INFO [LLM Performance] Task: decision_making, Model: claude-3-sonnet, Duration: 5.1s, Prompt Tokens: 1205, Completion Tokens: 50, Success: True
# 2026-02-19 14:30:22 INFO [LLM Performance] Task: log_compression, Model: gpt-3.5-turbo, Duration: 2.5s, Prompt Tokens: 8192, Completion Tokens: 450, Success: True
---
7 Docker 容器化部署
7.1 容器化架构
01.环境隔离的重要性
a.解决“依赖地狱”
a.功能说明
软件项目的依赖关系可能极其复杂。一个真实世界的软件仓库,其运行不仅依赖于特定版本的编程语言,还可能依赖于数十个甚至上百个特定版本的第三方库。在本地环境中手动配置和管理这些依赖,极易陷入“依赖地狱”,即不同项目或不同任务之间的依赖产生冲突。Docker 容器化技术通过将应用程序及其所有依赖打包到一个轻量级、可移植的容器中,从根本上解决了这个问题。每个 JoyCode Agent 的修复任务都在一个完全隔离的容器中运行,确保了环境的纯净、一致和可复现。
b.代码示例
---
# 传统方式 vs. Docker 方式
# 传统方式:在本地安装所有依赖
# pip install pandas==1.5.3
# pip install numpy==1.23.5
# ... (可能会与其他项目冲突)
# Docker 方式:在 Dockerfile 中定义依赖
# FROM python:3.9
# RUN pip install pandas==1.5.3
# RUN pip install numpy==1.23.5
# ... (所有依赖被封装在镜像中,与宿主机完全隔离)
# 运行任务时,只需启动对应的容器即可
docker run my-project-image
---
02.JoyCode Agent 的容器化方案
a.架构概述
a.功能说明
JoyCode Agent 的核心工作流与 Docker 深度集成。对于 SWE-bench 中的每一个问题实例,都有一个与之对应的预构建 Docker 镜像。这个镜像精确地复刻了该问题所在软件仓库在特定提交(Commit)时的完整环境。当 Agent 处理一个问题时,它会:
1. **拉取**:从镜像仓库拉取对应的 Docker 镜像。
2. **启动**:基于该镜像启动一个全新的、隔离的容器。
3. **交互**:在容器内部执行所有操作,包括检出代码、应用补丁、运行测试等。
4. **销毁**:任务完成后,销毁该容器,不留下任何状态或垃圾文件。
这种“一次性”容器的使用模式,保证了每次任务都在一个绝对干净和标准化的环境中进行。
b.代码示例
---
# Agent 与 Docker 的交互流程
def process_issue_in_container(issue):
# 1. 根据问题 ID 确定所需的镜像名称
image_name = get_docker_image_for_issue(issue.id)
# 2. 启动容器
container = docker.run(image_name, detach=True)
try:
# 3. 在容器内执行所有修复和验证操作
result = agent.run_inside_container(container, issue)
finally:
# 4. 任务结束,确保容器被销毁
container.stop()
container.remove()
return result
---
7.2 SWE-bench 镜像使用
01.镜像仓库与命名
a.镜像来源
a.功能说明
JoyCode Agent 使用的 Docker 镜像是基于 SWE-bench 官方提供的标准镜像。这些镜像托管在 `docker.1ms.run` 这个公共镜像仓库中。每个镜像的命名都遵循一个固定的格式,直接与问题实例的 ID 相关联,格式通常为 `docker.1ms.run/swebench/sweb.eval.x86_64.<repository>___<issue_id>:<tag>`。Agent 会根据要处理的问题 ID,自动构建出需要拉取的镜像全名。
b.代码示例
---
# 根据问题 ID 构建镜像名称
def get_image_name_from_instance_id(instance_id):
# 例如,instance_id 为 "django__django-11099"
repo_name, issue_id = instance_id.split("__")
# 替换仓库名称中的 "/" 为 "__"
repo_name_formatted = repo_name.replace("/", "__")
image_name = f"docker.1ms.run/swebench/sweb.eval.x86_64.{repo_name_formatted}___{issue_id}:latest"
return image_name
# 调用示例
instance_id = "django__django-11099"
print(get_image_name_from_instance_id(instance_id))
# 输出: docker.1ms.run/swebench/sweb.eval.x86_64.django__django-11099:latest
---
02.拉取与管理
a.自动化处理
a.功能说明
用户无需手动管理这些 Docker 镜像。JoyCode Agent 的 `utils/docker_utils.py` 模块中封装了所有与 Docker 相关的操作。在任务开始时,脚本会自动检查本地是否存在所需的镜像。如果镜像不存在,它会自动从远程仓库拉取;如果存在,则直接使用。这种自动化的处理方式极大地简化了用户的使用体验。
b.代码示例
---
# Docker 工具类的使用(伪代码)
from utils.docker_utils import DockerManager
docker_manager = DockerManager()
def ensure_image_is_present(image_name):
if not docker_manager.image_exists_locally(image_name):
print(f"镜像 {image_name} 不存在,正在从远程仓库拉取...")
docker_manager.pull_image(image_name)
else:
print(f"镜像 {image_name} 已存在于本地。")
# 在处理每个问题前,调用此函数即可
image_to_use = get_image_name_from_instance_id("django__django-11099")
ensure_image_is_present(image_to_use)
---
7.3 容器管理工具
01.Docker 工具类
a.功能封装
a.功能说明
JoyCode Agent 将所有底层的 Docker 操作都封装在 `utils/docker_utils.py` 中的 `DockerManager` 类里。这个类提供了一系列高级接口,使得上层逻辑可以像调用普通函数一样来管理容器的整个生命周期,而无需关心具体的 Docker 命令。封装的功能包括:
- 检查镜像是否存在
- 拉取镜像
- 启动容器
- 在运行的容器中执行命令
- 停止和删除容器
- 文件在宿主机与容器间的拷贝
b.代码示例
---
# DockerManager 核心方法示例
class DockerManager:
def pull_image(self, image_name):
# ... 实现 docker pull
def run_container(self, image_name):
# ... 实现 docker run
return container_id
def exec_in_container(self, container_id, command):
# ... 实现 docker exec
return output, exit_code
def stop_and_remove_container(self, container_id):
# ... 实现 docker stop 和 docker rm
---
02.与 Agent 的交互
a.交互流程
a.功能说明
Agent 的核心逻辑通过调用 `DockerManager` 来与容器进行交互。整个流程清晰地分离了“思考”和“执行”。Agent 负责“思考”,决定应该在容器里执行什么命令(例如 `pytest`, `git apply`);而 `DockerManager` 则负责“执行”,将这些命令安全、可靠地发送到隔离的容器环境中,并把执行结果返回给 Agent。Agent 再根据返回的结果(如测试失败的日志)进行下一轮的“思考”。
b.代码示例
---
# Agent 与 DockerManager 的交互伪代码
def agent_workflow(issue):
docker_manager = DockerManager()
container_id = docker_manager.run_container(issue.image)
# 思考:决定第一步是运行测试复现问题
command_to_run = "pytest tests/test_to_reproduce.py"
# 执行:让 DockerManager 在容器中执行命令
output, exit_code = docker_manager.exec_in_container(container_id, command_to_run)
# 思考:根据执行结果,决定下一步是生成补丁
if exit_code != 0:
patch_command = generate_patch_command(output) # output 包含失败日志
# ...
docker_manager.stop_and_remove_container(container_id)
---
7.4 多进程并行处理
01.并行加速
a.并行机制
a.功能说明
为了加速批量处理 SWE-bench 数据集,JoyCode Agent 支持多进程并行。当用户通过 `--num-processes` 参数指定了大于 1 的进程数时,主程序会将待处理的问题列表(从 `instance_id.txt` 读取)平均分配给多个子进程。每个子进程都独立负责处理自己的问题子集,包括创建容器、运行 Agent 等所有步骤。由于每个任务都在独立的 Docker 容器中运行,进程之间不会产生任何干扰,从而实现了安全、高效的并行加速。
b.代码示例
---
# 多进程启动脚本(run_patch_pipeline.py 核心逻辑)
import multiprocessing
def run_pipeline_for_subset(problem_subset):
# 每个子进程执行的函数
for problem_id in problem_subset:
process_issue_in_container(problem_id)
def main():
num_processes = args.num_processes
all_problems = load_problems_from_file()
problem_chunks = split_list(all_problems, num_processes)
with multiprocessing.Pool(processes=num_processes) as pool:
pool.map(run_pipeline_for_subset, problem_chunks)
---
02.资源管理
a.注意事项
a.功能说明
虽然多进程能显著提升处理速度,但它也会消耗更多的系统资源,包括 CPU、内存和磁盘 I/O。用户在设置并行进程数时,需要根据自己机器的硬件配置进行权衡。一个常见的经验法则是,将进程数设置为机器 CPU 核心数的一半到一倍之间。如果设置得过高,可能会因为资源竞争而导致每个进程的速度都变慢,甚至出现内存不足等错误。
b.代码示例
---
# 资源与进程数的关系
# 假设一台机器有 8 个 CPU 核心和 32GB 内存
# 推荐的并行数:
# python run_patch_pipeline.py --num-processes 4 (保守)
# python run_patch_pipeline.py --num-processes 8 (积极)
# 不推荐的并行数:
# python run_patch_pipeline.py --num-processes 16 (可能导致严重性能下降)
# 如果在运行中遇到内存不足的错误,首要的解决方案就是降低 --num-processes 的值。
---
7.5 环境隔离与安全
01.隔离的优势
a.安全性保障
a.功能说明
在容器中执行代码修复任务,本身就是一种重要的安全机制。Agent 生成的代码,尤其是由大型语言模型生成的代码,其行为在理论上是不可完全预测的。如果在宿主机上直接运行这些代码,可能会意外地修改或删除重要文件,甚至执行恶意操作。将所有操作都限制在一次性的 Docker 容器中,可以确保即使生成的代码行为不当,其影响范围也仅限于该容器内部,不会对宿主机系统造成任何损害。任务结束后容器即被销毁,所有潜在风险也随之消除。
b.代码示例
---
# 安全隔离概念
# 场景:LLM 生成了一个错误的补丁,其中包含 `rm -rf /` 命令
def run_safely_in_container(patch_with_malicious_code):
container = docker.run("my-image")
try:
# 在容器内应用并执行代码
container.exec_run(f"apply_and_run({patch_with_malicious_code})")
# `rm -rf /` 只会删除容器内的文件系统,不会影响宿主机
finally:
container.stop()
container.remove() # 容器被销毁,一切恢复原状
def run_unsafely_on_host(patch_with_malicious_code):
# 直接在宿主机上执行,可能导致灾难性后果
os.system(f"apply_and_run({patch_with_malicious_code})")
---
02.文件系统操作
a.受控的交互
a.功能说明
JoyCode Agent 对宿主机与容器之间的文件交互进行了严格的控制。默认情况下,容器内的文件系统与宿主机是完全隔离的。只有在明确需要时,例如将最终生成的补丁文件从容器中拷贝出来,或者将配置文件传入容器时,才会通过 Docker 的 `cp` 命令进行点对点的文件传输。这种受控的交互方式,最大限度地减少了容器与宿主机之间的攻击面,进一步增强了系统的安全性。
b.代码示例
---
# 受控的文件拷贝
# 将最终的补丁文件从容器中拷贝到宿主机的 output 目录
docker_manager.copy_from_container(
container_id=container.id,
container_path="/app/output/predictions.json",
host_path="/home/ubuntu/joycode-agent/output_files/django__django-11099/"
)
# 将本地的配置文件传入容器
docker_manager.copy_to_container(
container_id=container.id,
host_path="/home/ubuntu/joycode-agent/configs/my_config.yaml",
container_path="/app/config.yaml"
)
---
8 补丁投票系统
8.1 投票系统设计
01.解决“方案冲突”
a.设计目的
a.功能说明
在复杂的软件修复任务中,对于同一个问题,往往存在多种可能的修复方案。Patch Agent 可能会生成多个看起来都合理的候选补丁,或者,在使用不同模型、不同 Prompt 进行多次尝试后,会得到多个不同的有效补丁。补丁投票系统(Patch Voting System)的设计目的,就是在这些多个有效或候选方案中,通过一种更智能、更全面的方式,自动评选出“最佳”的一个。它将决策过程从简单的“第一个成功即是最终”模式,升级为“从所有成功方案中选最优”的模式。
b.代码示例
---
# 方案冲突的场景
# 场景1:Patch Agent 一次性生成了 3 个候选补丁
patch_candidate_A = "..."
patch_candidate_B = "..."
patch_candidate_C = "..."
# 场景2:两次独立的运行,分别产出了两个都能通过测试的补丁
run1_result_patch = "..."
run2_result_patch = "..."
# 此时,需要一个机制来决定到底采用哪一个。这就是投票系统的用武之地。
best_patch = voting_system.select_best(candidates=[...])
---
02.投票系统的角色
a.作为最终决策者
a.功能说明
补丁投票系统在整个 JoyCode Agent 工作流中扮演着“最终仲裁者”或“质量总监”的角色。它通常在所有生成和初步验证流程结束之后被调用。它的输入是多个候选补丁,输出是它认为最优秀的一个。这个决策过程不仅仅是随机选择,而是基于一系列复杂的评估标准,由一个专门的、强大的大型语言模型(LLM)来驱动,模拟领域专家的决策过程。
b.代码示例
---
# 投票系统在工作流中的位置
def full_workflow(issue):
# 1. 生成多个候选补丁
candidates = generate_multiple_patches(issue)
# 2. 对每个候选补丁进行基础验证
validated_candidates = []
for patch in candidates:
if basic_validation(patch):
validated_candidates.append(patch)
# 3. 如果有多个通过验证的候选者,调用投票系统
if len(validated_candidates) > 1:
final_choice = voting_system.vote(validated_candidates, issue)
return final_choice
elif len(validated_candidates) == 1:
return validated_candidates[0]
else:
return None
---
8.2 候选补丁比较
01.评估维度
a.多维度评估标准
a.功能说明
投票系统在比较候选补丁时,会从多个维度进行综合评估,而不仅仅是看代码本身。这些评估维度旨在全面地衡量一个补丁的“优劣”。主要维度包括:
- **代码简洁性**:补丁是否以最少的代码改动解决了问题?代码是否清晰易读?
- **可维护性**:补丁是否引入了“技术债”?其逻辑是否易于理解和未来的维护?
- **与项目风格的一致性**:补丁的代码风格、命名规范是否与所在代码库的现有风格保持一致?
- **逻辑的鲁棒性**:补丁的逻辑是否考虑了各种边界情况?是否存在潜在的逻辑漏洞?
- **与问题描述的匹配度**:补丁是否精准地解决了原始 Issue 中描述的核心问题?
b.代码示例
---
# 评估维度的量化(概念)
def evaluate_patch(patch, issue):
metrics = {
"conciseness": calculate_code_churn(patch), # 代码行数变化
"maintainability": run_static_analysis(patch), # 静态分析工具评分
"style_consistency": compare_code_style(patch, codebase),
"robustness": analyze_edge_cases(patch),
"relevance": calculate_semantic_similarity(patch, issue.description)
}
return metrics
---
02.比较方法
a.生成对比报告
a.功能说明
为了让 LLM 能够进行有效的比较,投票系统首先会为每一对候选补丁生成一份详细的“对比报告”。这份报告会并排展示两个补丁的代码差异(Diff),并附上原始的问题描述和相关的代码上下文。然后,系统会请求 LLM 扮演一个资深软件工程师的角色,对这两个补丁进行评审(Code Review),并明确指出它更倾向于哪一个,以及做出这个选择的详细理由。
b.代码示例
---
# 为 LLM 生成对比报告的 Prompt
def create_comparison_prompt(patch_A, patch_B, issue):
prompt = f"""[ROLE] You are a Staff Software Engineer.
[TASK] Compare the two provided patches for the following issue and decide which one is better.
[ISSUE DESCRIPTION]
{issue.description}
--- PATCH A ---
{patch_A.diff}
--- PATCH B ---
{patch_B.diff}
[INSTRUCTIONS]
1. Analyze the pros and cons of each patch.
2. State which patch you prefer (A or B).
3. Provide a detailed justification for your choice.
[OUTPUT_FORMAT] JSON with keys: "preferred_patch" (A/B), "justification" (string).
"""
return prompt
---
8.3 LLM 驱动的决策投票
01.LLM 作为评审员
a.模拟专家评审
a.功能说明
在投票系统中,大型语言模型(LLM)的核心角色是模拟一个经验丰富的代码评审员(Code Reviewer)。系统会利用精心设计的 Prompt,引导 LLM 从专家的视角来审视和评判每一个候选补丁。LLM 需要像人类专家一样,不仅检查代码的正确性,还要评估其设计、可读性、健壮性等更高层次的质量属性。通过利用 LLM 强大的自然语言理解和代码推理能力,投票系统得以实现超越简单规则的、更加智能的决策。
b.代码示例
---
# 引导 LLM 进行专家评审的 Prompt 节选
prompt = """... [INSTRUCTIONS]
As a Staff Engineer with 15 years of experience in this codebase, evaluate the patch.
- Is the solution elegant or a brute-force hack?
- Does it introduce any potential side effects?
- Is it easy for a new developer to understand?
- Does it follow the established design patterns of the project?
Provide your final verdict: 'APPROVE' or 'REJECT' with detailed reasoning.
"""
---
02.投票机制
a.循环赛或淘汰赛
a.功能说明
当存在多个(大于两个)候选补丁时,系统会采用类似“循环赛”或“淘汰赛”的机制来进行多轮比较。例如,在循环赛中,系统会让每个候选补丁与其他所有候选补丁进行一次“一对一”的比较。每个补丁在每次比较中获胜,就能得到一分。最终,得分最高的补丁将被选为最终的胜出者。这种机制确保了每个补丁都得到了充分的评估,使得最终的选择更具说服力。
b.代码示例
---
# 循环赛投票机制伪代码
def tournament_voting(patches, issue):
scores = {patch.id: 0 for patch in patches}
# 进行每一对补丁的比较
for i in range(len(patches)):
for j in range(i + 1, len(patches)):
patch_A = patches[i]
patch_B = patches[j]
# 请求 LLM 比较 A 和 B
result = llm_compare(patch_A, patch_B, issue)
# 根据结果计分
if result.preferred == 'A':
scores[patch_A.id] += 1
else:
scores[patch_B.id] += 1
# 返回得分最高的补丁
winner_id = max(scores, key=scores.get)
return find_patch_by_id(winner_id)
---
8.4 最优方案选择
01.最终决策
a.选出胜者
a.功能说明
经过多轮的 LLM 驱动的比较和投票后,系统会根据最终的得分或淘汰赛的结果,确定唯一的“最优方案”。这个方案被认为是所有候选者中,在代码质量、可维护性、简洁性和健壮性等多个维度上综合表现最好的一个。这个最终被选出的补丁,将作为 JoyCode Agent 这次修复任务的最终产出物,提交给用户或自动创建为 Pull Request。
b.代码示例
---
# 最终决策逻辑
def final_decision(scores):
if not scores:
return None
# 找到得分最高的补丁 ID
top_score = -1
winner_id = None
for patch_id, score in scores.items():
if score > top_score:
top_score = score
winner_id = patch_id
print(f"投票结束。最终选择的补丁是:{winner_id},得分:{top_score}")
return winner_id
---
02.提供决策依据
a.生成投票报告
a.功能说明
为了让最终的决策过程透明化、可追溯,投票系统在选出最优方案的同时,还会生成一份详细的“投票报告”。这份报告会记录下每一次“一对一”比较的完整过程,包括 LLM 对每个补丁的评价、选择的理由等。用户通过查阅这份报告,可以清晰地理解为什么最终会选择这个补丁,而不是其他的候选方案。这极大地增强了系统的可信度和可解释性。
b.代码示例
---
# 投票报告示例(JSON 格式)
{
"winner": "patch_B",
"rounds": [
{
"round": 1,
"comparison": ["patch_A", "patch_B"],
"winner": "patch_B",
"justification": "Patch B is more concise and directly addresses the root cause, while Patch A uses a workaround that might have side effects."
},
{
"round": 2,
"comparison": ["patch_A", "patch_C"],
"winner": "patch_A",
"justification": "Patch A has better test coverage, although Patch C is slightly simpler."
},
{
"round": 3,
"comparison": ["patch_B", "patch_C"],
"winner": "patch_B",
"justification": "Patch B's solution is more robust and handles edge cases that Patch C ignores."
}
],
"final_scores": {
"patch_A": 1,
"patch_B": 2,
"patch_C": 0
}
}
---
8.5 投票系统使用指南
01.输入要求
a.准备输入文件
a.功能说明
要使用补丁投票系统,您需要准备特定的输入文件。该系统通过独立的 `vote.py` 脚本运行。在运行前,您需要先运行 `scripts/prepare_voting_data.py` 脚本,它会帮助您从两次或多次不同的 Agent 运行结果中,整理出符合投票系统要求的输入格式。通常,您需要提供:
- **两个或多个候选补丁文件**:这些文件(通常是 JSON 格式)包含了由 Agent 生成的候选补丁内容。
- **问题实例描述文件**:一个 Parquet 文件,包含了原始的问题描述信息,以便 LLM 在评审时了解上下文。
b.代码示例
---
# 1. 准备投票数据
# 该脚本会从两个不同的输出目录中提取补丁和问题描述
python scripts/prepare_voting_data.py --run1_dir /path/to/run1/outputs --run2_dir /path/to/run2/outputs
# 脚本会生成类似以下的输入文件:
# - voting_inputs/patch_1.json
# - voting_inputs/patch_2.json
# - voting_inputs/test-00000-of-00001.parquet
---
02.运行命令
a.执行投票
a.功能说明
在准备好输入文件后,直接运行 `vote.py` 脚本即可启动投票流程。脚本会自动加载输入文件,执行上文描述的 LLM 驱动的比较和投票过程,并最终将最优补丁的结果和详细的投票报告输出到终端或指定的输出文件中。
b.代码示例
---
# 2. 运行投票脚本
python vote.py
# 脚本会输出类似以下的结果:
# ==================================
# Patch Voting Results
# ==================================
# Round 1: Comparing patch_1 vs patch_2
# Winner: patch_2
# Justification: Patch 2 is more aligned with the project's coding style.
# ...
# Final Winner: patch_2
# Detailed report saved to voting_outputs/report.json
---
9 管道阶段与输出结构
9.1 管道执行流程
01.端到端流程概览
a.从问题到补丁
a.功能说明
JoyCode Agent 的核心是一个端到端的自动化管道(Pipeline),它接收一个软件问题(Issue)作为输入,并最终输出一个经过验证的代码补丁(Patch)。整个管道被划分为一系列清晰、有序的阶段(Stage),每个阶段都负责完成一项特定的子任务。这种分阶段的设计使得整个复杂的修复过程变得结构化、可管理和可观测。
b.代码示例
---
# 管道执行流程(高级伪代码)
def run_patch_pipeline(issue):
# 阶段 1: 容器设置
container = setup_container_stage(issue)
# 阶段 2: 测试生成 (可选)
tests = generate_tests_stage(container, issue)
# 阶段 3: 代理执行
patch = agent_execution_stage(container, issue, tests)
# 阶段 4: 验证
is_valid = validation_stage(container, patch, tests)
# 阶段 5: 后处理 (可选)
if not is_valid:
patch = post_processing_stage(container, issue, tests)
cleanup_stage(container)
return patch
---
02.阶段的顺序与依赖
a.阶段依赖关系
a.功能说明
管道的各个阶段是严格按照顺序执行的,后续阶段的执行依赖于前序阶段的成功产出。例如,必须先成功设置好容器,才能在其中生成测试;必须先生成了测试,才能在代理执行阶段用其来指导补丁的生成。这种明确的依赖关系确保了工作流的逻辑正确性。部分阶段(如测试生成和后处理)是可选的,用户可以通过命令行参数来启用或禁用它们,以适应不同的使用场景。
b.代码示例
---
# 阶段依赖关系图
# [Start]
# ↓
# [Stage 1: Container Setup] (必需)
# ↓
# [Stage 2: Test Generation] (可选, --no-generate-tests 禁用)
# ↓
# [Stage 3: Agent Execution] (必需)
# ↓
# [Stage 4: Validation] (可选, --no-validate-with-tests 禁用)
# ↓
# [Stage 5: Post-processing] (可选, --enable-post-processing 启用)
# ↓
# [End]
---
9.2 容器设置阶段
01.职责与任务
a.环境准备
a.功能说明
这是整个管道的第一个阶段,也是所有后续工作的基础。在此阶段,系统的主要任务是为即将处理的问题实例准备一个干净、隔离且配置正确的运行环境。具体工作包括:
1. 根据问题 ID 解析出需要使用的 Docker 镜像名称。
2. 检查本地是否存在该镜像,如果不存在,则从远程仓库拉取。
3. 基于该镜像启动一个新的 Docker 容器。
4. 在容器内,检出(checkout)问题对应版本的软件仓库代码。
b.代码示例
---
# 容器设置阶段的核心逻辑
def setup_container_stage(issue):
# 1. 获取镜像名
image_name = get_image_name(issue.id)
# 2. 确保镜像存在
docker.ensure_image_present(image_name)
# 3. 启动容器
container = docker.run(image_name)
# 4. 在容器内检出代码
container.exec(f"git checkout {issue.base_commit}")
return container
---
02.产出物
a.阶段输出
a.功能说明
容器设置阶段的主要产出物是一个正在运行的、配置完毕的 Docker 容器实例。这个容器实例的 ID 或句柄将被传递给管道的下一个阶段。所有后续的操作都将在这个容器内部完成。
b.代码示例
---
# 阶段产出
# setup_container_stage(...) 函数返回一个代表容器的对象
class Container:
def __init__(self, id):
self.id = id
def exec(self, command):
# ...
# 这个 container 对象将作为后续阶段的输入
# e.g., generate_tests_stage(container, issue)
---
9.3 测试生成阶段
01.职责与任务
a.生成验证代码
a.功能说明
这是一个可选阶段,由 `--no-generate-tests` 参数控制。如果启用,Testing Agent 将会在此阶段大显身手。它的主要任务是,在对原始代码(即应用任何补丁之前)进行分析的基础上,生成用于后续验证的测试用例。如前所述,这主要包括用于复现问题的 Fail2Pass (F2P) 测试和用于保证回归质量的 Pass2Pass (P2P) 测试。生成的测试用例会被保存在容器内的特定位置,以供后续阶段使用。
b.代码示例
---
# 测试生成阶段的核心逻辑
def generate_tests_stage(container, issue):
if args.no_generate_tests:
return None
# 指示容器内的 Testing Agent 开始工作
result = container.exec("python -m testing_agent --issue_file /app/issue.json")
# 结果包含了生成的测试文件的路径
generated_test_paths = result.output["test_paths"]
return generated_test_paths
---
02.产出物
a.阶段输出
a.功能说明
此阶段的主要产出物是新生成的测试用例文件(通常是 `.py` 文件)在容器内的路径列表。同时,关于测试生成过程的详细日志(`test_generation_logs.txt`)和结果摘要(`test_generation_result.json`)也会被产出并保存,用于调试和分析。
b.代码示例
---
# 阶段产出示例
# 返回值 (generated_test_paths):
# ["/app/tests/test_f2p_django_11099.py", "/app/tests/test_p2p_regression.py"]
# 输出文件 (test_generation_result.json):
# {
# "f2p_test_generated": true,
# "p2p_tests_generated": 5,
# "errors": []
# }
---
9.4 代理执行阶段
01.职责与任务
a.生成修复补丁
a.功能说明
这是整个管道的核心阶段。在此阶段,以 Patch Agent 为首的多代理团队将协同工作,执行“观察-思考-行动”循环,以生成修复问题的代码补丁。这个过程由 `cli.py` 脚本在容器内部驱动。它会接收问题描述、代码上下文以及前一阶段生成的测试用例作为输入,并通过与 LLM 的多次交互,最终产出一个或多个候选补丁。
b.代码示例
---
# 代理执行阶段的核心逻辑
def agent_execution_stage(container, issue, tests):
# 构建 cli.py 的命令行参数
command = f"python cli.py --issue_file /app/issue.json --test_files {tests}"
# 在容器内执行 Agent 核心逻辑
result = container.exec(command)
# 结果中包含了生成的补丁内容
patch = result.output["patch"]
return patch
---
02.产出物
a.阶段输出
a.功能说明
此阶段的主要产出物是 diff 格式的代码补丁。此外,整个多代理执行过程的完整轨迹,包括每一次的观察、思考和行动,都会被记录在 `agent_logs.txt` 文件中。这个日志文件对于理解 Agent 的决策过程和调试问题至关重要。
b.代码示例
---
# 阶段产出示例
# 返回值 (patch):
# """diff --git a/app/main.py b/app/main.py
# --- a/app/main.py
# +++ b/app/main.py
# @@ -10,5 +10,5 @@
# def login(user, password):
# - if user_exists(user):
# + if user_exists(user) and check_password(user, password):
# return True
# return False
# """
# 输出文件 (agent_logs.txt):
# "Observation: Test failed with AssertionError. Thought: The login logic is incorrect... Action: Modify main.py line 11..."
---
9.5 验证阶段
01.职责与任务
a.评估补丁质量
a.功能说明
这是一个可选阶段,由 `--no-validate-with-tests` 参数控制。在此阶段,系统会对上一阶段生成的补丁进行严格的验证。它会将补丁应用到容器内的代码库中,然后运行测试生成阶段产出的完整测试套件(包括 F2P 和 P2P 测试)。只有当 F2P 测试从失败转为通过,并且所有 P2P 测试都保持通过时,该补丁才被认为是有效的。
b.代码示例
---
# 验证阶段的核心逻辑
def validation_stage(container, patch, tests):
if args.no_validate_with_tests:
return True
# 1. 在容器内应用补丁
container.exec(f"git apply {patch}")
# 2. 运行所有测试
result = container.exec(f"pytest {tests}")
# 3. 评估测试结果
return evaluate_test_results(result)
---
02.产出物
a.阶段输出
a.功能说明
此阶段的主要产出物是一个布尔值,表示验证是否成功。同时,详细的测试报告和日志也会被保存下来,作为评估补丁质量和进行失败归因的依据。
b.代码示例
---
# 阶段产出示例
# 返回值 (is_valid):
# True 或 False
# 输出文件 (validation_log.txt):
# "================= test session starts =================
# ...
# ================= 1 passed, 5 deselected in 0.10s ================="
---
9.6 后处理阶段
01.职责与任务
a.智能重试与压缩
a.功能说明
这是一个可选阶段,由 `--enable-post-processing` 参数启用。只有当验证阶段失败时,这个阶段才会被触发。其主要职责是执行智能重试策略,并对执行轨迹进行压缩。
- **智能重试**:如前所述,系统会进行失败归因,并根据原因选择合适的策略(如修改 Prompt、引入 CSR 经验等)再次尝试生成和验证补丁。
- **轨迹压缩**:为了节约存储空间和方便分析,系统会将详细的 `agent_logs.txt` 压缩成一个更短的、只包含关键步骤的 `compressed_trajectory.txt`。
b.代码示例
---
# 后处理阶段的核心逻辑
def post_processing_stage(container, issue, tests):
if not args.enable_post_processing:
return None
# 1. 执行智能重试
new_patch = run_intelligent_retry(container, issue, tests)
# 2. 压缩日志
compress_trajectory(container.get_file("agent_logs.txt"))
return new_patch
---
02.产出物
a.阶段输出
a.功能说明
此阶段的产出物可能是一个新的、最终通过验证的补丁。此外,它还会生成与重试相关的日志(`agent_logs_retry.txt`)和压缩后的轨迹文件(`compressed_trajectory.txt`)。
b.代码示例
---
# 阶段产出示例
# 返回值 (new_patch):
# 可能是一个新的、有效的补丁,或者 None
# 输出文件 (compressed_trajectory.txt):
# "[Attempt 1] Failed: AssertionError. [Retry Strategy] Modify prompt. [Attempt 2] Success."
---
9.7 输出文件结构详解
01.目录结构
a.文件组织方式
a.功能说明
所有 JoyCode Agent 运行的产出物都保存在 `output_files/` 目录下。系统会为每个处理的问题实例创建一个以其 ID 命名的子目录。所有与该问题相关的文件,如生成的补丁、各种日志、测试结果等,都存放在这个子目录中。此外,在 `output_files/` 的根目录下,还会生成一些全局的摘要文件。
b.代码示例
---
# 输出目录结构树
output_files/
├── <instance_id_1>/ # 第一个问题实例的目录
│ ├── predictions.json # 最终生成的补丁和元数据
│ ├── agent_logs.txt # Agent 核心执行日志
│ ├── test_generation_result.json # 测试生成结果
│ ├── test_generation_logs.txt # 测试生成日志
│ ├── agent_logs_retry.txt # 重试过程的日志
│ └── compressed_trajectory.txt # 压缩后的执行轨迹
├── <instance_id_2>/ # 第二个问题实例的目录
│ └── ...
├── successful_cases.txt # 全局成功案例列表
├── failed_cases.txt # 全局失败案例列表
└── empty_diff_cases.txt # 未能生成任何补丁的案例列表
---
02.关键文件说明
a.核心产出物
a.功能说明
在众多输出文件中,以下几个是用户最需要关注的核心产出物:
- **`predictions.json`**:这是最重要的产出文件,其中包含了最终被采纳的代码补丁(`model_patch` 字段)以及其他元数据。如果您只想获取最终的修复代码,读取这个文件即可。
- **`agent_logs.txt`**:这是最详细的日志文件,记录了 Agent 的每一步思考和行动。当您需要深入分析 Agent 的行为或调试问题时,这个文件是关键。
- **`successful_cases.txt` / `failed_cases.txt`**:这两个文件提供了批量运行后的高层摘要,让您可以快速了解哪些问题被成功修复,哪些失败了。
b.代码示例
---
# predictions.json 文件内容示例
{
"instance_id": "django__django-11099",
"model_patch": "diff --git a/app/main.py b/app/main.py...",
"model_name_or_path": "gpt-4-turbo-preview",
"is_generated_by_test_generation": true,
"is_valid_by_test_validation": true
}
---
10 性能优化与故障排查
10.1 性能基准测试结果
01.SWE-bench 表现
a.官方数据
a.功能说明
JoyCode Agent 的性能在权威的 SWE-bench Verified 基准测试中得到了验证。截至 2025 年 9 月,官方提交的结果显示,JoyCode Agent 在该测试集上解决了 373 个问题实例,综合通过率达到了 **74.6%**,位居全球公开榜单的 Top 3。这一成绩证明了其在解决真实世界复杂软件问题上的 state-of-the-art (SOTA) 水平。
b.代码示例
---
# 官方提交的性能摘要
Submission summary for 20250909_JoyCode on SWE-bench verified split
==================================================
Resolved 373 instances (74.6%)
==================================================
---
02.分仓库表现
a.详细数据
a.功能说明
除了总体通过率,JoyCode Agent 在 SWE-bench 包含的多个不同开源项目(仓库)上也表现出了强大的、但各有差异的性能。例如,在 `django`, `pytest`, `scikit-learn` 等大型复杂项目上,其解决率甚至超过了 75%,而在 `pylint-dev`, `psf/requests` 等项目上则表现稍弱。这些数据为分析 Agent 在不同类型代码库上的适应性和能力边界提供了宝贵的参考。
b.代码示例
---
# 按仓库划分的解决率
Resolved by Repository:
- django/django: 178/231 (77.06%)
- sympy/sympy: 57/75 (76.0%)
- sphinx-doc/sphinx: 29/44 (65.91%)
- scikit-learn/scikit-learn: 28/32 (87.5%)
- pytest-dev/pytest: 17/19 (89.47%)
- pydata/xarray: 19/22 (86.36%)
- astropy/astropy: 13/22 (59.09%)
- matplotlib/matplotlib: 25/34 (73.53%)
- pylint-dev/pylint: 2/10 (20.0%)
- psf/requests: 3/8 (37.5%)
- mwaskom/seaborn: 1/2 (50.0%)
- pallets/flask: 1/1 (100.0%)
---
10.2 资源消耗优化
01.Token 效率
a.设计理念
a.功能说明
JoyCode Agent 在设计上高度注重资源,特别是 LLM Token 的使用效率。与依赖海量并行采样来“暴力破解”问题的竞品不同,JoyCode Agent 采用了“质量优先”的策略。它通过智能失败归因、经验迁移和闭环迭代等机制,力求每一次 LLM 调用都是高质量、有针对性的。这种设计使得它能够在达到与 SOTA 相当性能的同时,将计算资源消耗(主要体现为 Token 消耗)降低 30%-50%,展现了极高的性价比。
b.代码示例
---
# 资源消耗对比(概念)
# 竞品A (暴力采样)
# - LLM Calls per issue: ~50-100
# - Total Tokens per issue: ~2,000,000
# - Success Rate: 75%
# JoyCode Agent (智能迭代)
# - LLM Calls per issue: ~5-15
# - Total Tokens per issue: ~1,000,000
# - Success Rate: 74.6%
---
02.内存与 CPU
a.并行度控制
a.功能说明
在批量处理任务时,主要的系统资源瓶颈通常是内存(RAM)和 CPU。JoyCode Agent 通过 `--num-processes` 参数允许用户灵活控制并行度。合理地设置此参数是平衡处理速度和资源消耗的关键。如果机器资源充足,可以适当调高并行数以缩短总耗时;如果资源有限或在运行中出现内存不足的错误,应降低并行数。通常,将并行数设置为机器 CPU 核心数是是一个比较均衡的起点。
b.代码示例
---
# 根据机器资源调整并行度
# 场景1: 高配服务器 (32 核心, 128GB RAM)
# 可以尝试较高的并行度以追求极致速度
python run_patch_pipeline.py --num-processes 16
# 场景2: 标准开发笔记本 (8 核心, 32GB RAM)
# 建议使用与核心数相当的并行度
python run_patch_pipeline.py --num-processes 8
# 场景3: 轻量级虚拟机 (4 核心, 16GB RAM)
# 应使用较低的并行度,甚至单进程运行,以避免内存溢出
python run_patch_pipeline.py --num-processes 2
---
10.3 常见问题诊断
01.问题诊断流程
a.诊断步骤
a.功能说明
当 JoyCode Agent 运行失败或结果不符合预期时,可以遵循一个标准的诊断流程来定位问题:
1. **查看全局摘要**:首先查看 `output_files/` 目录下的 `failed_cases.txt` 和 `empty_diff_cases.txt`,快速了解失败的类型和数量。
2. **定位具体实例**:选择一个失败的问题实例,进入其对应的 `output_files/<instance_id>/` 目录。
3. **阅读核心日志**:打开 `agent_logs.txt` 文件,这是最关键的诊断信息来源。从头到尾阅读,理解 Agent 的决策过程和遇到的障碍。
4. **检查验证日志**:如果问题出在验证阶段,请查看 `validation_log.txt`,其中包含了详细的测试失败报告。
5. **检查环境日志**:如果怀疑是 Docker 或依赖问题,可以查看容器启动和测试生成的日志。
b.代码示例
---
# 诊断流程示例
# 1. 发现 django__django-11099 失败了
cat output_files/failed_cases.txt
# > django__django-11099
# 2. 进入该实例的目录
cd output_files/django__django-11099/
# 3. 查看 Agent 的执行轨迹
less agent_logs.txt
# (在日志中发现 Agent 多次尝试后依然无法通过测试)
# 4. 查看具体的测试失败信息
less validation_log.txt
# (发现是某个断言始终失败)
# 5. 基于以上信息,可以判断是 Patch Agent 的逻辑生成能力遇到了瓶颈
---
02.日志文件分析
a.关键日志解读
a.功能说明
在 `agent_logs.txt` 中,需要重点关注以下信息:
- **`Observation`**:Agent 在每一步观察到的环境状态,例如文件内容、命令输出、错误信息等。
- **`Thought`**:Agent 基于观察进行的思考和推理过程。这是理解其“内心活动”的关键。
- **`Action`**:Agent 决定采取的具体行动,例如执行一个 shell 命令、修改一个文件等。
通过串联起“Observation -> Thought -> Action”的链条,就可以完整地复盘 Agent 的整个工作过程,并找到问题所在。
b.代码示例
---
# agent_logs.txt 片段解读
# ...
# Observation: Running tests failed with the following error:
# > AssertionError: Expected True but got False in test_login.py:42
#
# Thought: The test failed because the login function returned False incorrectly. I need to inspect the logic inside the login function in main.py to understand why. It seems the password check is failing. I will modify the `check_password` call.
#
# Action: (Execute Shell Command)
# > sed -i ... main.py
# ...
---
10.4 Docker 问题排查
01.连接与权限
a.常见 Docker 问题
a.功能说明
与 Docker 相关的问题通常发生在管道的初始阶段。最常见的问题包括:
- **Docker 服务未运行**:系统无法连接到 Docker守护进程。
- **权限不足**:当前用户没有权限执行 Docker 命令。
- **网络问题**:无法从 `docker.1ms.run` 仓库拉取镜像。
JoyCode Agent 的 `README.md` 中提供了一系列用于测试 Docker 连通性和权限的命令。
b.代码示例
---
# Docker 问题诊断命令
# 1. 检查 Docker 服务状态和连接
# 如果此命令长时间无响应或报错,说明 Docker 服务有问题
docker info
# 2. 检查镜像拉取
# 如果此命令失败,说明网络不通或仓库地址有误
docker pull docker.1ms.run/hello-world
# 3. 检查权限 (Linux/macOS)
# 如果当前用户不在 docker 组中,可能会有权限问题
groups
# 解决方法: sudo usermod -aG docker $USER
---
02.镜像问题
a.镜像拉取失败
a.功能说明
如果遇到特定镜像拉取失败的问题,首先应检查问题实例 ID 是否正确,因为镜像是根据 ID 自动匹配的。其次,检查网络连接是否稳定。在极少数情况下,可能是远程仓库本身的问题,可以稍后重试。您也可以尝试手动拉取该镜像,以获取更详细的错误信息。
b.代码示例
---
# 手动拉取特定问题的镜像进行调试
# 假设处理 django__django-11099 失败
# 1. 获取完整的镜像名称
# (参考 7.2 节的方法)
IMAGE_NAME="docker.1ms.run/swebench/sweb.eval.x86_64.django__django-11099:latest"
# 2. 尝试手动拉取
docker pull $IMAGE_NAME
# 观察 docker pull 命令的输出,它会提供关于失败的详细信息
# (例如 "manifest not found", "connection timed out" 等)
---
10.5 LLM 配置问题
01.API 密钥与 URL
a.配置检查
a.功能说明
与大型语言模型(LLM)相关的问题通常是由于 `llm_server/model_config.json` 文件中的配置错误引起的。最常见的原因是:
- **API 密钥错误**:API Key 不正确、已过期或额度不足。
- **Base URL 错误**:API 的端点地址不正确。
- **模型名称错误**:指定的模型名称不被该端点支持。
在开始运行前,请务必仔细检查这些配置项。
b.代码示例
---
# 验证 LLM 配置的命令
# JoyCode Agent 提供了一个简单的命令来检查配置文件是否能被正确解析
python -c "import json; print(json.load(open('llm_server/model_config.json')))"
# 您还可以使用 curl 来直接测试 API Key 和 URL
# (以 OpenAI 为例)
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer YOUR_API_KEY"
# 如果能返回模型列表,说明 Key 和 URL 是正确的
---
02.模型兼容性
a.兼容性问题
a.功能说明
虽然 JoyCode Agent 支持所有 OpenAI 兼容的 API,但不同模型或服务提供商在细节上可能存在微小差异,这可能导致兼容性问题。例如,某些模型可能不支持特定的参数,或者返回的数据格式略有不同。如果在使用非官方推荐的模型时遇到问题,建议:
1. 仔细阅读该模型提供商的 API 文档。
2. 尝试使用最简单的配置(只保留 `api_key`, `base_url`, `model_name`)进行测试。
3. 检查 `llm_server/` 目录下的客户端代码,看是否需要进行微小的适配。
b.代码示例
---
# 简化配置进行测试
# 当遇到兼容性问题时,尝试使用最简化的配置
{
"default": {
"api_key": "your-key",
"base_url": "http://your-local-service/v1",
"model_name": "your-model"
// 暂时移除 max_tokens, temperature 等所有可选参数
}
}
---
10.6 内存问题解决
01.降低并行度
a.首要解决方案
a.功能说明
如果在批量运行过程中遇到与内存相关的错误(如 `OutOfMemoryError`, `Killed` 等),最直接、最有效的解决方案就是降低并行进程数。每个进程都会启动一个 Docker 容器并加载模型,消耗大量内存。通过减少 `--num-processes` 参数的值,可以显著降低系统的总内存占用。
b.代码示例
---
# 遇到内存问题时的调整
# 原始命令,导致内存溢出
# python run_patch_pipeline.py --num-processes 16
# 调整方案:将并行数减半
python run_patch_pipeline.py --num-processes 8
# 如果问题仍然存在,继续降低
python run_patch_pipeline.py --num-processes 4
# 在极端情况下,使用单进程运行以保证任务能完成
python run_patch_pipeline.py --num-processes 1
---
02.系统资源监控
a.使用系统工具
a.功能说明
在运行 JoyCode Agent 时,建议打开系统的资源监控工具,实时观察内存和 CPU 的使用情况。这可以帮助您找到一个最适合您机器配置的并行度设置。
- **Linux**:可以使用 `htop` 或 `top` 命令。
- **macOS**:可以使用“活动监视器”(Activity Monitor)。
- **Windows**:可以使用“任务管理器”(Task Manager)。
关注“可用内存”(Available Memory)指标,确保在运行期间始终保留一定的余量。
b.代码示例
---
# 使用 htop 监控资源
# 1. 安装 htop (如果尚未安装)
# sudo apt-get install htop (Ubuntu)
# 2. 在一个单独的终端窗口中运行 htop
htop
# 3. 在另一个窗口中运行 JoyCode Agent
# python run_patch_pipeline.py ...
# 4. 观察 htop 界面中的 Mem 和 CPU 指标变化
# 如果看到内存使用率持续接近 100%,就应该考虑降低并行度
---
10.7 最佳实践建议
01.调试与开发
a.建议流程
a.功能说明
当您需要对 JoyCode Agent 本身进行开发或调试时,建议遵循以下流程:
1. **从单个实例开始**:使用 `--problem-id` 参数锁定一个简单、已知的问题实例进行调试,避免批量运行带来的复杂性。
2. **禁用可选阶段**:在初期,可以使用 `--simple-mode` 或 `--no-generate-tests` 等参数禁用所有不必要的阶段,专注于核心逻辑的调试。
3. **增加日志输出**:在代码中加入更多的 `print` 或 `logging` 语句,以便更详细地追踪执行流程。
4. **直接在容器内操作**:对于复杂问题,可以手动启动一个容器,并在其中交互式地执行 `cli.py` 的各个部分,以进行更精细的调试。
b.代码示例
---
# 调试时的推荐命令
# 专注于一个问题,并禁用测试和后处理
python run_patch_pipeline.py --problem-id django__django-11099 --num-processes 1 --simple-mode
# 手动进入容器进行调试
# 1. 启动容器并获取 shell
docker run -it --entrypoint /bin/bash <image_name>
# 2. 在容器内,你可以手动执行脚本的各个部分
root@container:/app# python cli.py --issue_file ...
---
02.复现高分结果
a.推荐配置
a.功能说明
如果您希望复现官方在 SWE-bench 上的高分榜单成绩,建议使用以下配置:
- **启用所有阶段**:确保不要使用 `--simple-mode` 或 `--no-generate-tests` 等禁用参数。
- **开启后处理**:必须使用 `--enable-post-processing` 参数来启用智能重试和经验迁移,这是提升成功率的关键。
- **使用强大的 LLM**:为核心的生成和决策任务配置最强大的模型,如 `GPT-4 Turbo` 或 `Claude 3 Opus`。
- **耐心与资源**:复现完整榜单需要处理数百个问题,这是一个非常耗时且消耗资源的过程,请确保有足够的时间和计算预算。
b.代码示例
---
# 复现榜单成绩的推荐命令
# 1. 确保 instance_id.txt 包含了完整的 SWE-bench Verified 问题列表
# 2. 确保 model_config.json 配置了高性能的 LLM
# 3. 运行以下命令 (并行数根据机器配置调整)
python run_patch_pipeline.py --num-processes 8 --enable-post-processing
---