# -*- coding: utf-8 -*- """ Streamlit 前端 v3 - Agent 对话流可视化版本 核心特性: 1. 清晰展示每个 Agent 当前在做什么(任务标签) 2. Agent 之间的对话流(类似聊天室) 3. 实时活动指示器(高亮当前发言的 Agent) 4. 对话历史完整记录 """ import streamlit as st import os import sys from pathlib import Path from datetime import datetime import time from typing import Dict, Any, List import json # 添加项目根目录到路径 sys.path.insert(0, str(Path(__file__).parent.parent)) try: from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager AUTOGEN_AVAILABLE = True except ImportError: AUTOGEN_AVAILABLE = False from config.llm_config import ( get_llm_config, PM_PROMPT, QA_PROMPT, DEV_PROMPT, ORCH_PROMPT ) # 页面配置 st.set_page_config( page_title="AutoGen SDLC - Agent 对话流", page_icon="💬", layout="wide", initial_sidebar_state="expanded" ) # 自定义 CSS 样式 - 突出对话流 st.markdown(""" """, unsafe_allow_html=True) # Agent 配置 AGENT_CONFIG = { "PM_Agent": { "name": "产品经理", "avatar": "📋", "color": "#2196f3", "bubble_class": "pm-bubble", "task_class": "pm-task", "default_task": "待命" }, "QA_Agent": { "name": "测试工程师", "avatar": "✅", "color": "#4caf50", "bubble_class": "qa-bubble", "task_class": "qa-task", "default_task": "待命" }, "Dev_Agent": { "name": "开发工程师", "avatar": "💻", "color": "#ff9800", "bubble_class": "dev-bubble", "task_class": "dev-task", "default_task": "待命" }, "Orchestrator": { "name": "协调器", "avatar": "🎯", "color": "#9c27b0", "bubble_class": "orchestrator-bubble", "task_class": "orchestrator-task", "default_task": "待命" }, "User_Proxy": { "name": "用户代理", "avatar": "👤", "color": "#795548", "bubble_class": "user-bubble", "task_class": "user-task", "default_task": "待命" } } def init_session_state(): """初始化 session state""" if "messages" not in st.session_state: st.session_state.messages = [] if "is_running" not in st.session_state: st.session_state.is_running = False if "current_agent" not in st.session_state: st.session_state.current_agent = None if "agent_tasks" not in st.session_state: st.session_state.agent_tasks = { "PM_Agent": "待命", "QA_Agent": "待命", "Dev_Agent": "待命", "Orchestrator": "待命", "User_Proxy": "待命" } if "agent_stats" not in st.session_state: st.session_state.agent_stats = {agent: 0 for agent in AGENT_CONFIG} def display_agent_status_row(): """显示 Agent 状态行 - 突出当前活动的 Agent""" st.subheader("🎭 Agent 实时状态") cols = st.columns(5) for i, (agent_key, config) in enumerate(AGENT_CONFIG.items()): with cols[i]: is_active = st.session_state.current_agent == agent_key current_task = st.session_state.agent_tasks.get(agent_key, "待命") msg_count = st.session_state.agent_stats.get(agent_key, 0) status_class = "active" if is_active else "" indicator_class = "status-active" if is_active else "status-inactive" st.markdown(f"""
{config['avatar']}
{config['name']}
📝 {current_task}
💬 {msg_count} 条消息
""", unsafe_allow_html=True) def display_active_agent_banner(): """显示当前活动 Agent 的横幅""" if st.session_state.current_agent: config = AGENT_CONFIG.get(st.session_state.current_agent, {}) st.markdown(f"""
{config.get('avatar', '🤖')} 当前发言:{config.get('name', 'Unknown')} - {st.session_state.agent_tasks.get(st.session_state.current_agent, '工作中...')}
""", unsafe_allow_html=True) def display_chat_flow(): """显示 Agent 对话流 - 核心功能""" st.subheader("💬 Agent 对话流") if not st.session_state.messages: st.info("👈 暂无对话,请启动工作流") return # 使用容器显示对话流 chat_container = st.container() for idx, msg in enumerate(st.session_state.messages): agent_key = msg.get("agent_key", "Unknown") config = AGENT_CONFIG.get(agent_key, {"name": "未知", "avatar": "🤖", "bubble_class": ""}) task_class = AGENT_CONFIG.get(agent_key, {}).get("task_class", "") timestamp = msg.get("timestamp", "") if timestamp: time_str = datetime.fromisoformat(timestamp).strftime("%H:%M:%S") else: time_str = datetime.now().strftime("%H:%M:%S") content = msg.get("content", "") task = msg.get("task", "工作中") # 显示对话气泡 st.markdown(f"""
{config['avatar']} {config['name']} {task} {time_str}
{content}
""", unsafe_allow_html=True) # 显示对话流指示器(下一条消息的箭头) if idx < len(st.session_state.messages) - 1: next_msg = st.session_state.messages[idx + 1] next_agent = next_msg.get("agent_key", "") next_config = AGENT_CONFIG.get(next_agent, {}) if next_agent != agent_key: st.markdown(f"""
⬇️
传递给 {next_config.get('name', 'Unknown')}
""", unsafe_allow_html=True) def create_agents(api_key: str, base_url: str, model: str): """创建所有 Agent""" llm_config = get_llm_config(model=model, api_key=api_key, base_url=base_url) pm_agent = AssistantAgent( name="PM_Agent", system_message=PM_PROMPT, llm_config=llm_config, description="资深软件产品经理", human_input_mode="NEVER" ) qa_agent = AssistantAgent( name="QA_Agent", system_message=QA_PROMPT, llm_config=llm_config, description="资深测试工程师", human_input_mode="NEVER" ) dev_agent = AssistantAgent( name="Dev_Agent", system_message=DEV_PROMPT, llm_config=llm_config, description="资深软件工程师", human_input_mode="NEVER" ) orchestrator = AssistantAgent( name="Orchestrator", system_message=ORCH_PROMPT, llm_config=llm_config, description="多智能体协调器", human_input_mode="NEVER" ) user_proxy = UserProxyAgent( name="User_Proxy", human_input_mode="NEVER", max_consecutive_auto_reply=0, code_execution_config={ "work_dir": "workspace", "use_docker": False, }, is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE") ) return pm_agent, qa_agent, dev_agent, orchestrator, user_proxy, llm_config def add_message(agent_key: str, content: str, task: str = "工作中"): """添加消息到对话流""" msg = { "agent_key": agent_key, "content": content, "timestamp": datetime.now().isoformat(), "task": task } st.session_state.messages.append(msg) # 更新统计 st.session_state.agent_stats[agent_key] = st.session_state.agent_stats.get(agent_key, 0) + 1 # 更新当前 Agent st.session_state.current_agent = agent_key # 更新任务 st.session_state.agent_tasks[agent_key] = task def main(): """主应用""" init_session_state() # 标题 st.title("💬 AutoGen SDLC - Agent 对话流可视化") st.markdown("**清晰展示每个 Agent 在做什么 · 实时追踪 Agent 之间的对话交互**") # 侧边栏配置 with st.sidebar: st.title("⚙️ 控制中心") api_key = st.text_input("API Key", type="password", value=os.getenv("DASHSCOPE_API_KEY", "")) base_url = st.text_input("Base URL", value="https://dashscope.aliyuncs.com/compatible-mode/v1") model = st.selectbox("模型选择", ["qwen3.5-flash", "qwen-max", "qwen-plus", "qwen-turbo"], index=0) max_round = st.slider("最大对话轮数", 5, 50, 20) st.divider() col1, col2 = st.columns(2) with col1: start_btn = st.button("▶️ 启动对话流", type="primary", use_container_width=True) with col2: stop_btn = st.button("⏸️ 暂停", use_container_width=True) st.divider() if st.button("🗑️ 清空对话", use_container_width=True): st.session_state.messages = [] st.session_state.current_agent = None st.session_state.agent_tasks = {k: "待命" for k in AGENT_CONFIG} st.session_state.agent_stats = {k: 0 for k in AGENT_CONFIG} st.rerun() if st.button("📥 导出对话", use_container_width=True): if st.session_state.messages: json_str = json.dumps(st.session_state.messages, ensure_ascii=False, indent=2) st.download_button( label="下载 JSON", data=json_str, file_name=f"agent_chat_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", mime="application/json" ) # 主界面 display_agent_status_row() st.divider() display_active_agent_banner() display_chat_flow() # 用户输入 st.divider() user_input = st.chat_input("💡 输入需求,或点击启动按钮开始...") if user_input: add_message("User_Proxy", user_input, "提出需求") st.rerun() # 启动工作流 if start_btn: if not api_key: st.error("请先设置 API Key") st.stop() if not AUTOGEN_AVAILABLE: st.error("请先安装 AutoGen: pip install pyautogen") st.stop() # 获取需求 user_msgs = [m for m in st.session_state.messages if m.get("agent_key") == "User_Proxy"] if not user_msgs: add_message("User_Proxy", "请开发一个电池健康状态预测 API", "提出需求") latest_requirement = user_msgs[-1]["content"] if user_msgs else "请开发一个电池健康状态预测 API" st.session_state.is_running = True # 进度提示 progress_placeholder = st.empty() progress_placeholder.info("🚀 启动 SDLC 工作流,Agent 开始协作...") try: # 创建 Agent pm_agent, qa_agent, dev_agent, orchestrator, user_proxy, llm_config = create_agents( api_key=api_key, base_url=base_url, model=model ) # 添加 Orchestrator 启动消息 add_message("Orchestrator", f"🚀 启动 SDLC 工作流!用户需求:{latest_requirement[:100]}...", "启动流程") # 创建 GroupChat groupchat = GroupChat( agents=[pm_agent, qa_agent, dev_agent, orchestrator, user_proxy], messages=[], max_round=max_round, speaker_selection_method="round_robin" ) manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config) # 初始消息 initial_message = f""" 请启动完整的 SDLC 流程: 【用户需求】 {latest_requirement} 【工作流程】 1. PM_Agent → 生成 SRS 文档 2. QA_Agent → 生成测试用例 3. Dev_Agent → 编写代码 4. User_Proxy → 执行测试 5. Orchestrator → 汇总报告 开始协作!每个步骤完成后请明确说明。 """ # 执行对话 with st.spinner("💬 Agent 们正在协作中,请稍候..."): chat_result = user_proxy.initiate_chat( manager, message=initial_message, max_turns=max_round ) # 记录所有对话 for msg in groupchat.messages: agent_name = msg.get("name", "Unknown") content = msg.get("content", "") # 推断任务 task_map = { "PM_Agent": "需求分析", "QA_Agent": "测试设计", "Dev_Agent": "代码实现", "Orchestrator": "流程协调", "User_Proxy": "测试执行" } task = task_map.get(agent_name, "工作中") add_message(agent_name, content, task) # 完成 add_message("Orchestrator", "✅ SDLC 流程完成!所有任务已完成。", "总结完成") progress_placeholder.success("✅ SDLC 工作流完成!查看上方的对话流了解详情。") st.session_state.is_running = False st.rerun() except Exception as e: st.session_state.is_running = False st.session_state.current_agent = None progress_placeholder.error(f"❌ 错误:{str(e)}") st.error("请检查 API Key 和网络连接") if stop_btn: st.session_state.is_running = False st.session_state.current_agent = None st.info("⏸️ 工作流已暂停") if __name__ == "__main__": main()