This commit is contained in:
2026-03-12 17:58:15 +08:00
parent cd67c6dac2
commit 7931ce5070
7 changed files with 598 additions and 139 deletions

View File

@@ -7,6 +7,8 @@ import sys
from pathlib import Path
from typing import Dict, Any, Optional, List
import json
import re
from datetime import datetime
# 添加项目根目录到路径
sys.path.insert(0, str(Path(__file__).parent))
@@ -23,6 +25,81 @@ from utils.logger import get_logger
from utils.callback_handler import get_callback_handler
def extract_code(content):
"""从 Markdown 代码块中提取纯代码"""
if "```python" in content:
parts = content.split("```python")
if len(parts) > 1:
code = parts[1].split("```")[0].strip()
return code
elif "```" in content:
parts = content.split("```")
if len(parts) > 1:
code = parts[1].strip()
return code
return content
def save_file_from_content(content: str, agent_name: str, workspace_dir: Path) -> List[str]:
"""
根据 Agent 的内容实时保存文件
Args:
content: Agent 的输出内容
agent_name: Agent 名称
workspace_dir: 工作目录
Returns:
保存的文件路径列表
"""
saved_files = []
# PM Agent 生成 SRS
if agent_name == "PM_Agent" and ("需求" in content or "SRS" in content or "软件需求规格说明书" in content):
file = workspace_dir / "SRS.md"
with open(file, "w", encoding="utf-8") as f:
f.write(f"# 软件需求规格说明书\n\n生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write(content)
saved_files.append(str(file))
print(f"💾 [实时保存] {file}")
# QA Agent 生成测试
elif agent_name == "QA_Agent" and ("test" in content.lower() or "测试" in content or "def test_" in content):
file = workspace_dir / "test_sample.py"
code = extract_code(content)
if code: # 确保有代码内容才保存
with open(file, "w", encoding="utf-8") as f:
f.write(f"# 测试用例\n\n{code}")
saved_files.append(str(file))
print(f"💾 [实时保存] {file}")
# Dev Agent 生成代码 - 支持多个文件
elif agent_name == "Dev_Agent" and ("def " in content or "class " in content or "import " in content):
# 尝试提取带文件名的代码块
code_blocks = re.findall(r'```python\s*\n#(?:\s*File:|\s*filename:)?\s*([^\n]+)\n(.*?)```', content, re.DOTALL)
if code_blocks:
# 保存多个文件
for filename, code_content in code_blocks:
filename = filename.strip()
file_path = workspace_dir / filename
with open(file_path, "w", encoding="utf-8") as f:
f.write(f"# 生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n{code_content}")
saved_files.append(str(file_path))
print(f"💾 [实时保存] {file_path}")
else:
# 没有文件名标记,保存为 src_sample.py
file = workspace_dir / "src_sample.py"
code = extract_code(content)
if code: # 确保有代码内容才保存
with open(file, "w", encoding="utf-8") as f:
f.write(f"# 源代码\n\n{code}")
saved_files.append(str(file))
print(f"💾 [实时保存] {file}")
return saved_files
class AutoGenSDLCSystem:
"""AutoGen SDLC 多智能体协同系统"""
@@ -70,7 +147,43 @@ class AutoGenSDLCSystem:
# 创建 GroupChat
self.groupchat = None
self.manager = None
# 记录已保存的文件
self.saved_files = []
def _on_new_message(self, sender, message, **kwargs):
"""
新消息回调函数 - 实时保存文件
Args:
sender: 发送者
message: 消息内容
**kwargs: 其他参数
"""
try:
agent_name = getattr(sender, 'name', 'Unknown')
content = message.get('content', '') if isinstance(message, dict) else str(message)
# 实时保存文件
saved_files = save_file_from_content(content, agent_name, self.workspace_dir)
# 如果有文件保存,记录并通知回调
if saved_files:
self.saved_files.extend(saved_files)
for file_path in saved_files:
# 确定文件类型
if file_path.endswith('.md'):
file_type = 'markdown'
elif file_path.endswith('.py'):
file_type = 'python'
else:
file_type = 'other'
# 触发回调
self.callback_handler.on_file_created(agent_name, file_path, file_type)
except Exception as e:
print(f"⚠️ 实时保存文件时出错:{e}")
def _create_agents(self):
"""创建所有 Agent"""
# PM Agent
@@ -113,7 +226,7 @@ class AutoGenSDLCSystem:
self.user_proxy = UserProxyAgent(
name="User_Proxy",
human_input_mode="NEVER", # 修复Web 环境不支持 TERMINAL
max_consecutive_auto_reply=0,
max_consecutive_auto_reply=10, # 允许连续自动回复,避免提前终止
code_execution_config={
"work_dir": str(self.workspace_dir),
"use_docker": False,
@@ -167,6 +280,9 @@ class AutoGenSDLCSystem:
# 创建 GroupChat
self.create_groupchat(max_round)
# 重置已保存文件列表
self.saved_files = []
# 构建初始消息
initial_message = f"""
请启动完整的 SDLC 流程,开发以下功能:
@@ -188,7 +304,17 @@ class AutoGenSDLCSystem:
"""
try:
# 启动对话
# 启动对话 - 使用回调函数实时处理消息
print("\n🚀 开始对话...\n")
# 为每个 Agent 注册实时文件保存回调
for agent in [self.pm_agent, self.qa_agent, self.dev_agent, self.orchestrator]:
agent.register_reply(
self._on_new_message,
reply_func_total_count=1,
position=0 # 在最前面执行,确保实时保存
)
chat_result = self.user_proxy.initiate_chat(
self.manager,
message=initial_message,
@@ -215,7 +341,8 @@ class AutoGenSDLCSystem:
"success": True,
"summary": chat_result.summary if hasattr(chat_result, 'summary') else "工作流完成",
"messages": self.groupchat.messages,
"workspace": str(self.workspace_dir)
"workspace": str(self.workspace_dir),
"saved_files": self.saved_files
}
except Exception as e:
@@ -224,57 +351,4 @@ class AutoGenSDLCSystem:
"success": False,
"error": str(e),
"messages": self.groupchat.messages if self.groupchat else []
}
def export_conversation(self, output_path: Optional[str] = None) -> str:
"""导出对话历史"""
return self.logger.export_to_json(output_path)
def export_report(self, output_path: Optional[str] = None) -> str:
"""导出 Markdown 格式报告"""
return self.logger.export_to_markdown(output_path)
def main():
"""主函数 - 演示模式"""
print("=" * 60)
print("AutoGen SDLC 多智能体协同系统")
print("=" * 60)
# 检查 API Key
api_key = os.getenv("DASHSCOPE_API_KEY")
if not api_key:
print("\n❌ 错误:未设置 DASHSCOPE_API_KEY 环境变量")
print("请运行export DASHSCOPE_API_KEY='your_api_key'")
return
# 创建系统实例
system = AutoGenSDLCSystem(api_key=api_key)
# 演示用例
demo_requirement = "我需要一个电池健康状态 (SOH) 预测 API能够接收电池的电压、电流、温度数据输出健康度百分比"
print(f"\n📋 演示需求:{demo_requirement}")
print("\n🚀 启动 SDLC 工作流...\n")
# 运行工作流
result = system.run_workflow(demo_requirement, max_round=15)
# 输出结果
print("\n" + "=" * 60)
if result["success"]:
print("✅ 工作流成功完成!")
print(f"📄 摘要:{result['summary'][:200]}...")
print(f"📂 工作目录:{result['workspace']}")
else:
print(f"❌ 工作流失败:{result.get('error', '未知错误')}")
# 导出报告
report_path = system.export_report()
print(f"📊 对话报告已导出:{report_path}")
print("\n" + "=" * 60)
if __name__ == "__main__":
main()
}