优化智能选项系统:实现触类旁通能力
- 新增AI智能选项生成功能,支持任何类型问题 - 扩展关键词匹配系统,覆盖12个常见场景 - 优化选项显示逻辑,提供更精准的选项匹配 - 修复重复key错误,提升用户体验 - 改进UI布局,选项按钮更直观易用
This commit is contained in:
parent
3e623c1828
commit
c848b36003
16
README.md
16
README.md
@ -1,23 +1,23 @@
|
||||
# 多 Agent 决策工作坊
|
||||
# AI经理人为你把关
|
||||
|
||||
🤖 **决策智囊团** - 基于AI的多角色辩论辅助决策平台
|
||||
🤖 **专业决策把关系统** - 基于AI的多角色决策辅助平台
|
||||
|
||||
## 项目简介
|
||||
|
||||
这是一个为团队决策者、产品经理和战略规划师设计的AI辅助决策平台。通过4个专业AI代理(技术专家、商业分析师、用户体验师、风险顾问)的多角度辩论,帮助用户全面分析复杂问题并生成结构化决策要点。
|
||||
这是一个为团队决策者、产品经理和战略规划师设计的AI决策辅助平台。通过4个专业AI经理人(技术专家、战略顾问、用户体验师、风险顾问)的多角度把关,帮助用户全面分析复杂问题并生成结构化决策要点。
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 🎯 多角色AI代理辩论
|
||||
### 🎯 多角色AI经理人把关
|
||||
- **技术专家** - 技术可行性、实现难度分析
|
||||
- **商业分析师** - 市场机会、商业模式评估
|
||||
- **战略顾问** - 战略规划、竞争优势评估
|
||||
- **用户体验师** - 用户需求、易用性分析
|
||||
- **风险顾问** - 风险识别、不确定性评估
|
||||
|
||||
### 🔄 实时辩论过程展示
|
||||
- 可视化展示代理间的辩论流程
|
||||
### 🔄 实时把关过程展示
|
||||
- 可视化展示经理人间的把关流程
|
||||
- 实时显示论点、论据和推理过程
|
||||
- 支持辩论过程的交互控制
|
||||
- 支持把关过程的交互控制
|
||||
|
||||
### 📊 智能决策要点生成
|
||||
- 自动总结关键观点和共识
|
||||
|
||||
833
app.py
833
app.py
@ -1,25 +1,35 @@
|
||||
"""
|
||||
多 Agent 决策工作坊 - 主应用
|
||||
基于DeepSeek API的多角色AI代理辩论系统
|
||||
AI经理人为你把关 - 主应用
|
||||
基于DeepSeek API的多角色AI代理决策辅助系统
|
||||
优化版本:同步处理 + 智能缓存
|
||||
"""
|
||||
|
||||
import streamlit as st
|
||||
import os
|
||||
from openai import OpenAI
|
||||
from dotenv import load_dotenv
|
||||
import asyncio
|
||||
import json
|
||||
from typing import List, Dict, Any
|
||||
from datetime import datetime
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
# 加载环境变量 - 确保从当前目录加载
|
||||
env_path = os.path.join(os.path.dirname(__file__), '.env')
|
||||
if os.path.exists(env_path):
|
||||
load_dotenv(env_path)
|
||||
else:
|
||||
# 如果.env文件不存在,尝试从当前工作目录加载
|
||||
load_dotenv()
|
||||
|
||||
class MultiAgentDecisionWorkshop:
|
||||
class AIManagerDecisionAssistant:
|
||||
def __init__(self):
|
||||
"""初始化多代理决策工作坊"""
|
||||
api_key = os.getenv("DEEPSEEK_API_KEY")
|
||||
if not api_key:
|
||||
raise ValueError("DEEPSEEK_API_KEY环境变量未设置")
|
||||
|
||||
self.client = OpenAI(
|
||||
api_key=os.getenv("DEEPSEEK_API_KEY"),
|
||||
api_key=api_key,
|
||||
base_url="https://api.deepseek.com"
|
||||
)
|
||||
|
||||
@ -29,9 +39,9 @@ class MultiAgentDecisionWorkshop:
|
||||
"role": "system",
|
||||
"content": "你是一位资深技术专家,擅长从技术可行性、实现难度、技术风险等角度分析问题。你的观点务实、注重细节。"
|
||||
},
|
||||
"商业分析师": {
|
||||
"战略顾问": {
|
||||
"role": "system",
|
||||
"content": "你是一位经验丰富的商业分析师,擅长从市场机会、商业模式、投资回报等商业角度分析问题。你的观点注重商业价值。"
|
||||
"content": "你是一位经验丰富的战略顾问,擅长从战略规划、竞争优势、长期发展等角度分析问题。你的观点注重战略价值。"
|
||||
},
|
||||
"用户体验师": {
|
||||
"role": "system",
|
||||
@ -39,23 +49,103 @@ class MultiAgentDecisionWorkshop:
|
||||
},
|
||||
"风险顾问": {
|
||||
"role": "system",
|
||||
"content": "你是一位谨慎的风险顾问,擅长识别潜在风险、评估不确定性、提出风险缓解方案。你的观点保守但务实。"
|
||||
"content": "你是一位谨慎的风险顾问,擅长识别潜在风险、评估不确定性、提出风险缓解方案。您的观点保守但务实。"
|
||||
}
|
||||
}
|
||||
|
||||
# 响应缓存
|
||||
self.response_cache = {}
|
||||
self.cache_timeout = 300 # 5分钟缓存
|
||||
|
||||
# 宽泛问题关键词
|
||||
self.broad_question_keywords = [
|
||||
"怎么办", "如何", "是否", "应该", "好不好", "行不行", "对不对",
|
||||
"建议", "意见", "看法", "想法", "决策", "选择", "方向",
|
||||
"策略", "方案", "计划", "未来", "发展", "改进"
|
||||
]
|
||||
|
||||
# 常见决策场景的预定义选项
|
||||
self.predefined_options = {
|
||||
"目标类型": [
|
||||
"提升收入/利润",
|
||||
"降低成本/优化效率",
|
||||
"提升用户体验/满意度",
|
||||
"扩大市场份额/用户规模",
|
||||
"技术创新/产品升级",
|
||||
"风险控制/合规管理"
|
||||
],
|
||||
"时间范围": [
|
||||
"1个月内(紧急)",
|
||||
"1-3个月(短期)",
|
||||
"3-6个月(中期)",
|
||||
"6-12个月(长期)",
|
||||
"1年以上(战略)"
|
||||
],
|
||||
"预算规模": [
|
||||
"10万以内(小规模)",
|
||||
"10-50万(中等规模)",
|
||||
"50-100万(较大规模)",
|
||||
"100万以上(大规模)",
|
||||
"无明确预算限制"
|
||||
],
|
||||
"团队规模": [
|
||||
"1-3人(小团队)",
|
||||
"3-5人(标准团队)",
|
||||
"5-10人(较大团队)",
|
||||
"10人以上(大型团队)",
|
||||
"外包/外部合作"
|
||||
],
|
||||
"优先级": [
|
||||
"最高优先级(立即执行)",
|
||||
"高优先级(尽快处理)",
|
||||
"中等优先级(按计划执行)",
|
||||
"低优先级(有空闲时处理)"
|
||||
],
|
||||
"风险承受度": [
|
||||
"高风险高回报(激进)",
|
||||
"中等风险中等回报(平衡)",
|
||||
"低风险稳定回报(保守)",
|
||||
"零风险(安全第一)"
|
||||
]
|
||||
}
|
||||
|
||||
def initialize_debate(self, question: str) -> Dict[str, Any]:
|
||||
"""初始化辩论话题"""
|
||||
return {
|
||||
"question": question,
|
||||
"rounds": 0,
|
||||
"max_rounds": 3,
|
||||
"max_rounds": 1, # 进一步减少轮次到1轮,确保10秒内完成
|
||||
"current_speaker": "技术专家",
|
||||
"debate_history": [],
|
||||
"start_time": datetime.now()
|
||||
}
|
||||
|
||||
def get_cache_key(self, agent_name: str, context: str) -> str:
|
||||
"""生成缓存键"""
|
||||
content = f"{agent_name}:{context}"
|
||||
return hashlib.md5(content.encode()).hexdigest()
|
||||
|
||||
def get_cached_response(self, agent_name: str, context: str) -> str:
|
||||
"""获取缓存响应"""
|
||||
cache_key = self.get_cache_key(agent_name, context)
|
||||
if cache_key in self.response_cache:
|
||||
cached_time, response = self.response_cache[cache_key]
|
||||
if time.time() - cached_time < self.cache_timeout:
|
||||
return response
|
||||
return None
|
||||
|
||||
def cache_response(self, agent_name: str, context: str, response: str):
|
||||
"""缓存响应"""
|
||||
cache_key = self.get_cache_key(agent_name, context)
|
||||
self.response_cache[cache_key] = (time.time(), response)
|
||||
|
||||
def get_agent_response(self, agent_name: str, debate_context: str) -> str:
|
||||
"""获取单个代理的回应"""
|
||||
# 检查缓存
|
||||
cached_response = self.get_cached_response(agent_name, debate_context)
|
||||
if cached_response:
|
||||
return cached_response
|
||||
|
||||
try:
|
||||
response = self.client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
@ -63,179 +153,593 @@ class MultiAgentDecisionWorkshop:
|
||||
self.agents[agent_name],
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"辩论话题:{debate_context}\n\n请从你的专业角度发表观点,并回应其他代理的论点。"
|
||||
"content": f"辩论话题:{debate_context}\n\n请从你的专业角度发表简要观点(不超过100字)。"
|
||||
}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=500
|
||||
max_tokens=100 # 大幅减少token数量到100
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
result = response.choices[0].message.content
|
||||
|
||||
# 缓存结果
|
||||
self.cache_response(agent_name, debate_context, result)
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"{agent_name}暂时无法回应:{str(e)}"
|
||||
return f"{agent_name}:观点待补充" # 简化错误信息
|
||||
|
||||
def conduct_debate_round(self, debate_state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""进行一轮辩论"""
|
||||
current_speaker = debate_state["current_speaker"]
|
||||
def get_all_responses(self, debate_context: str) -> Dict[str, str]:
|
||||
"""获取所有代理的回应"""
|
||||
response_dict = {}
|
||||
for agent_name in self.agents.keys():
|
||||
response = self.get_agent_response(agent_name, debate_context)
|
||||
response_dict[agent_name] = response
|
||||
|
||||
return response_dict
|
||||
|
||||
def conduct_fast_debate(self, debate_state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""快速辩论模式 - 同步处理"""
|
||||
# 构建辩论上下文
|
||||
context = f"问题:{debate_state['question']}\n"
|
||||
if debate_state["debate_history"]:
|
||||
context += "之前的讨论:\n"
|
||||
for entry in debate_state["debate_history"][-3:]: # 只取最近3条
|
||||
for entry in debate_state["debate_history"][-1:]: # 只取最近1条
|
||||
context += f"{entry['speaker']}:{entry['content']}\n"
|
||||
|
||||
# 获取当前发言者的回应
|
||||
response = self.get_agent_response(current_speaker, context)
|
||||
# 获取所有代理的回应
|
||||
responses = self.get_all_responses(context)
|
||||
|
||||
# 更新辩论历史
|
||||
debate_state["debate_history"].append({
|
||||
"speaker": current_speaker,
|
||||
"content": response,
|
||||
"timestamp": datetime.now().strftime("%H:%M:%S")
|
||||
})
|
||||
|
||||
# 切换到下一个发言者
|
||||
agent_names = list(self.agents.keys())
|
||||
current_index = agent_names.index(current_speaker)
|
||||
next_index = (current_index + 1) % len(agent_names)
|
||||
debate_state["current_speaker"] = agent_names[next_index]
|
||||
for agent_name, response in responses.items():
|
||||
debate_state["debate_history"].append({
|
||||
"speaker": agent_name,
|
||||
"content": response,
|
||||
"timestamp": datetime.now().strftime("%H:%M:%S")
|
||||
})
|
||||
|
||||
debate_state["rounds"] += 1
|
||||
|
||||
return debate_state
|
||||
|
||||
def generate_decision_summary(self, debate_history: List[Dict]) -> str:
|
||||
"""生成决策要点总结"""
|
||||
def generate_decision_summary(self, debate_history: List[Dict]) -> Dict[str, Any]:
|
||||
"""生成决策要点总结和推荐度"""
|
||||
try:
|
||||
# 构建辩论内容摘要
|
||||
debate_content = "辩论记录:\n"
|
||||
for entry in debate_history:
|
||||
debate_content += f"{entry['speaker']}:{entry['content']}\n"
|
||||
|
||||
# 生成详细总结
|
||||
response = self.client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位专业的决策顾问,擅长从多角度辩论中提取关键观点、识别共识与分歧,并生成结构化的决策建议。"
|
||||
"content": "你是一位专业的决策顾问,请基于四位专家的辩论生成决策总结和推荐度。四位专家分别是:技术专家、商业分析师、用户体验师、风险顾问。请综合分析他们的观点,给出五个推荐度等级:\n1. 强烈推荐(★★★★★)- 各方面条件都非常有利\n2. 推荐(★★★★☆)- 大部分条件有利,少量风险\n3. 中立(★★★☆☆)- 利弊相当,需要权衡\n4. 谨慎(★★☆☆☆)- 风险较多,需要谨慎考虑\n5. 不推荐(★☆☆☆☆)- 风险远大于收益\n\n对于实施建议部分,请提供具体、可操作的实行方法和时间规划,包括:\n- 具体实施步骤(分阶段说明)\n- 所需资源和人员配置\n- 时间规划(按周/月划分)\n- 关键里程碑和交付物\n- 风险应对措施"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"请基于以下辩论记录,生成决策要点总结:\n\n{debate_content}\n\n请提供:\n1. 关键观点汇总\n2. 主要共识领域\n3. 重要分歧点\n4. 风险评估\n5. 行动建议"
|
||||
"content": f"请基于以下四位专家的辩论记录,生成决策总结和推荐度:\n\n{debate_content}\n\n请提供:\n1. 综合决策总结(包含关键观点、共识与分歧)\n2. 推荐度等级(1-5星)\n3. 推荐理由\n4. 风险提示\n5. 实施建议(必须包含:具体实施步骤、所需资源、时间规划、关键里程碑、风险应对措施)"
|
||||
}
|
||||
],
|
||||
temperature=0.5,
|
||||
max_tokens=800
|
||||
max_tokens=600
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
|
||||
summary_text = response.choices[0].message.content
|
||||
|
||||
# 提取推荐度等级
|
||||
recommendation_level = self.extract_recommendation_level(summary_text)
|
||||
|
||||
return {
|
||||
"summary": summary_text,
|
||||
"recommendation_level": recommendation_level,
|
||||
"stars": self.get_stars_display(recommendation_level)
|
||||
}
|
||||
except Exception as e:
|
||||
return f"总结生成失败:{str(e)}"
|
||||
return {
|
||||
"summary": "决策要点生成中...",
|
||||
"recommendation_level": 3,
|
||||
"stars": "★★★☆☆"
|
||||
}
|
||||
|
||||
def extract_recommendation_level(self, summary_text: str) -> int:
|
||||
"""从总结文本中提取推荐度等级"""
|
||||
# 更智能的关键词匹配和权重计算
|
||||
positive_keywords = ["强烈推荐", "强烈建议", "非常有利", "★★★★★", "五星", "强烈支持"]
|
||||
positive_weight = sum(1 for keyword in positive_keywords if keyword in summary_text)
|
||||
|
||||
recommend_keywords = ["推荐", "建议", "★★★★☆", "四星", "有利", "支持"]
|
||||
recommend_weight = sum(1 for keyword in recommend_keywords if keyword in summary_text)
|
||||
|
||||
neutral_keywords = ["中立", "★★★☆☆", "三星", "权衡", "利弊相当", "需要评估"]
|
||||
neutral_weight = sum(1 for keyword in neutral_keywords if keyword in summary_text)
|
||||
|
||||
cautious_keywords = ["谨慎", "★★☆☆☆", "二星", "风险", "需要谨慎", "注意"]
|
||||
cautious_weight = sum(1 for keyword in cautious_keywords if keyword in summary_text)
|
||||
|
||||
negative_keywords = ["不推荐", "不建议", "★☆☆☆☆", "一星", "风险大", "反对"]
|
||||
negative_weight = sum(1 for keyword in negative_keywords if keyword in summary_text)
|
||||
|
||||
# 根据权重最高的类别确定推荐度
|
||||
weights = [negative_weight, cautious_weight, neutral_weight, recommend_weight, positive_weight]
|
||||
max_weight = max(weights)
|
||||
|
||||
if max_weight == 0:
|
||||
# 如果没有匹配到关键词,使用AI直接判断
|
||||
return self.ask_ai_for_recommendation(summary_text)
|
||||
|
||||
# 返回权重最高的推荐度(从1到5)
|
||||
return weights.index(max_weight) + 1
|
||||
|
||||
def ask_ai_for_recommendation(self, summary_text: str) -> int:
|
||||
"""当无法自动判断时,使用AI直接判断推荐度"""
|
||||
try:
|
||||
response = self.client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一个推荐度判断专家。请根据决策总结内容,给出1-5的推荐度评分:\n5=强烈推荐,4=推荐,3=中立,2=谨慎,1=不推荐。只返回数字,不要其他内容。"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"请判断以下决策总结的推荐度(1-5):\n\n{summary_text}"
|
||||
}
|
||||
],
|
||||
temperature=0.3,
|
||||
max_tokens=10
|
||||
)
|
||||
|
||||
result = response.choices[0].message.content.strip()
|
||||
# 提取数字
|
||||
import re
|
||||
numbers = re.findall(r'\d+', result)
|
||||
if numbers:
|
||||
level = int(numbers[0])
|
||||
return max(1, min(5, level)) # 确保在1-5范围内
|
||||
return 3 # 默认中立
|
||||
except:
|
||||
return 3 # 默认中立
|
||||
|
||||
def get_stars_display(self, level: int) -> str:
|
||||
"""获取星级显示"""
|
||||
stars = ["★☆☆☆☆", "★★☆☆☆", "★★★☆☆", "★★★★☆", "★★★★★"]
|
||||
return stars[level - 1] if 1 <= level <= 5 else "★★★☆☆"
|
||||
|
||||
def is_broad_question(self, question: str) -> bool:
|
||||
"""判断是否为宽泛问题"""
|
||||
question_lower = question.lower()
|
||||
|
||||
# 检查问题长度(过短的问题通常是宽泛的)
|
||||
if len(question.strip()) < 10:
|
||||
return True
|
||||
|
||||
# 检查是否包含宽泛关键词
|
||||
for keyword in self.broad_question_keywords:
|
||||
if keyword in question_lower:
|
||||
return True
|
||||
|
||||
# 检查是否缺乏具体细节
|
||||
specific_indicators = ["具体", "详细", "数据", "预算", "时间", "人员", "资源"]
|
||||
specific_count = sum(1 for indicator in specific_indicators if indicator in question_lower)
|
||||
|
||||
return specific_count < 1
|
||||
|
||||
def generate_clarification_questions(self, question: str) -> List[str]:
|
||||
"""生成澄清问题以帮助细化问题范围"""
|
||||
try:
|
||||
response = self.client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位专业的决策顾问,擅长帮助用户细化宽泛的决策问题。请根据用户的问题,生成3-5个关键澄清问题,帮助用户明确决策的具体范围、目标和约束条件。"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"用户的问题:{question}\n\n请生成3-5个关键澄清问题,帮助用户明确决策的具体细节。"
|
||||
}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=200
|
||||
)
|
||||
|
||||
questions_text = response.choices[0].message.content
|
||||
# 解析问题列表
|
||||
questions = []
|
||||
lines = questions_text.split('\n')
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line and (line.startswith(('1.', '2.', '3.', '4.', '5.', '-', '•')) or '?' in line):
|
||||
# 清理格式
|
||||
question_text = line.replace('1.', '').replace('2.', '').replace('3.', '').replace('4.', '').replace('5.', '').replace('-', '').replace('•', '').strip()
|
||||
if question_text:
|
||||
questions.append(question_text)
|
||||
|
||||
return questions[:5] # 最多返回5个问题
|
||||
|
||||
except Exception as e:
|
||||
# 默认澄清问题
|
||||
return [
|
||||
"这个决策的具体目标是什么?",
|
||||
"您期望的决策时间范围是多久?",
|
||||
"可用的资源或预算限制是什么?",
|
||||
"决策涉及的主要利益相关者是谁?",
|
||||
"您最关心的关键成功因素是什么?"
|
||||
]
|
||||
|
||||
def refine_question_with_context(self, question: str, clarification_answers: Dict[str, str]) -> str:
|
||||
"""基于澄清回答细化问题"""
|
||||
refined_question = question
|
||||
|
||||
if clarification_answers:
|
||||
context_parts = []
|
||||
for key, value in clarification_answers.items():
|
||||
if value.strip():
|
||||
context_parts.append(f"{key}:{value}")
|
||||
|
||||
if context_parts:
|
||||
refined_question = f"{question}\n\n补充信息:{';'.join(context_parts)}"
|
||||
|
||||
return refined_question
|
||||
|
||||
def get_predefined_options_for_question(self, question: str) -> Dict[str, List[str]]:
|
||||
"""为澄清问题生成对应的预定义选项"""
|
||||
try:
|
||||
# 使用AI智能生成与问题最相关的选项
|
||||
response = self.client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位专业的决策顾问,擅长帮助用户细化问题。请根据用户的问题,生成最相关的3-6个选项类别,每个类别包含4-8个具体选项。请以JSON格式返回:{'问题类别': ['选项1', '选项2', ...]}"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"用户的问题:{question}\n\n请生成最相关的选项类别和具体选项,帮助用户明确决策的具体细节。"
|
||||
}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=300
|
||||
)
|
||||
|
||||
options_text = response.choices[0].message.content
|
||||
|
||||
# 尝试解析AI返回的JSON格式
|
||||
import json
|
||||
import re
|
||||
|
||||
# 提取JSON部分
|
||||
json_match = re.search(r'\{.*\}', options_text, re.DOTALL)
|
||||
if json_match:
|
||||
options_dict = json.loads(json_match.group())
|
||||
return options_dict
|
||||
else:
|
||||
# 如果无法解析JSON,使用智能关键词匹配
|
||||
return self._get_options_by_keywords(question)
|
||||
|
||||
except Exception as e:
|
||||
# 如果AI调用失败,使用关键词匹配
|
||||
return self._get_options_by_keywords(question)
|
||||
|
||||
def _get_options_by_keywords(self, question: str) -> Dict[str, List[str]]:
|
||||
"""基于关键词的智能选项匹配"""
|
||||
question_lower = question.lower()
|
||||
|
||||
# 扩展的关键词库,支持更多场景
|
||||
category_patterns = {
|
||||
"饮食": ["吃什么", "食物", "餐饮", "饮食", "餐厅", "做饭", "点外卖"],
|
||||
"地点": ["去哪里", "地点", "位置", "场所", "地方", "旅游", "出行"],
|
||||
"购物": ["买什么", "购物", "购买", "商品", "购物车", "下单", "消费"],
|
||||
"学习": ["学习", "课程", "培训", "教育", "读书", "学习", "技能"],
|
||||
"娱乐": ["玩什么", "娱乐", "游戏", "电影", "音乐", "休闲", "放松"],
|
||||
"健康": ["健身", "运动", "健康", "养生", "锻炼", "减肥", "保健"],
|
||||
"工作": ["工作", "职业", "项目", "任务", "职场", "升职", "跳槽"],
|
||||
"财务": ["投资", "理财", "赚钱", "收入", "支出", "预算", "储蓄"],
|
||||
"社交": ["朋友", "社交", "聚会", "约会", "家人", "同事", "人际关系"],
|
||||
"时间": ["时间", "期限", "何时", "多久", "截止", "时间表", "进度"],
|
||||
"目标": ["目标", "目的", "想要", "期望", "希望", "追求", "愿景"],
|
||||
"资源": ["团队", "人员", "人力", "资源", "预算", "设备", "工具"]
|
||||
}
|
||||
|
||||
# 匹配最相关的类别
|
||||
matched_category = None
|
||||
max_score = 0
|
||||
|
||||
for category, keywords in category_patterns.items():
|
||||
score = sum(1 for keyword in keywords if keyword in question_lower)
|
||||
if score > max_score:
|
||||
max_score = score
|
||||
matched_category = category
|
||||
|
||||
# 根据类别生成选项
|
||||
if matched_category == "饮食":
|
||||
return {"您想吃什么类型?": ["米饭类", "面条类", "面食类", "西餐", "快餐", "健康轻食", "火锅烧烤", "日韩料理", "中餐厅", "小吃零食"]}
|
||||
elif matched_category == "地点":
|
||||
return {"您想去哪里?": ["商场购物", "公园散步", "电影院", "餐厅用餐", "咖啡厅", "健身房", "旅游景点", "朋友家", "博物馆", "户外运动"]}
|
||||
elif matched_category == "购物":
|
||||
return {"您想购买什么?": ["电子产品", "服装鞋帽", "家居用品", "食品饮料", "书籍文具", "运动器材", "化妆品", "礼品", "汽车用品", "宠物用品"]}
|
||||
elif matched_category == "学习":
|
||||
return {"您想学习什么?": ["编程技术", "语言学习", "职业技能", "兴趣爱好", "考试备考", "在线课程", "书籍阅读", "实践项目", "艺术创作", "科学知识"]}
|
||||
elif matched_category == "娱乐":
|
||||
return {"您想怎么娱乐?": ["看电影", "玩游戏", "听音乐", "阅读书籍", "运动健身", "朋友聚会", "旅游出行", "美食探索", "艺术创作", "户外活动"]}
|
||||
elif matched_category == "健康":
|
||||
return {"您关注哪方面健康?": ["健身锻炼", "饮食营养", "心理健康", "睡眠质量", "体检检查", "疾病预防", "养生保健", "体重管理", "运动康复", "压力管理"]}
|
||||
elif matched_category == "工作":
|
||||
return {"您的工作需求是?": ["项目推进", "团队管理", "技能提升", "职业发展", "工作效率", "工作生活平衡", "薪资待遇", "工作环境", "职业规划", "工作压力"]}
|
||||
elif matched_category == "财务":
|
||||
return {"您的财务目标是?": ["投资理财", "储蓄规划", "消费控制", "收入提升", "债务管理", "退休规划", "保险配置", "税务优化", "创业融资", "房产投资"]}
|
||||
elif matched_category == "社交":
|
||||
return {"您的社交需求是?": ["朋友聚会", "家人团聚", "同事交流", "约会交友", "社区活动", "网络社交", "商务合作", "团队建设", "公益活动", "兴趣小组"]}
|
||||
else:
|
||||
# 通用决策问题
|
||||
return {"请明确具体方向": ["目标设定", "时间规划", "资源分配", "风险评估", "优先级排序", "实施方案", "预期效果", "备选方案"]}
|
||||
|
||||
def main():
|
||||
"""主应用函数"""
|
||||
st.set_page_config(
|
||||
page_title="多 Agent 决策工作坊",
|
||||
page_title="AI经理人为你把关",
|
||||
page_icon="🤖",
|
||||
layout="wide"
|
||||
)
|
||||
|
||||
st.title("🤖 多 Agent 决策工作坊")
|
||||
st.markdown("### 通过AI代理的多角度辩论,助力智能决策")
|
||||
|
||||
# 初始化工作坊
|
||||
if "workshop" not in st.session_state:
|
||||
st.session_state.workshop = MultiAgentDecisionWorkshop()
|
||||
st.session_state.workshop = AIManagerDecisionAssistant()
|
||||
if "debate_state" not in st.session_state:
|
||||
st.session_state.debate_state = None
|
||||
if "debate_in_progress" not in st.session_state:
|
||||
st.session_state.debate_in_progress = False
|
||||
if "ultra_fast_mode" not in st.session_state:
|
||||
st.session_state.ultra_fast_mode = True
|
||||
if "needs_clarification" not in st.session_state:
|
||||
st.session_state.needs_clarification = False
|
||||
if "clarification_questions" not in st.session_state:
|
||||
st.session_state.clarification_questions = []
|
||||
if "clarification_answers" not in st.session_state:
|
||||
st.session_state.clarification_answers = {}
|
||||
if "refined_question" not in st.session_state:
|
||||
st.session_state.refined_question = ""
|
||||
if "predefined_options_map" not in st.session_state:
|
||||
st.session_state.predefined_options_map = {}
|
||||
if "selected_options" not in st.session_state:
|
||||
st.session_state.selected_options = {}
|
||||
|
||||
# 侧边栏 - 控制面板
|
||||
with st.sidebar:
|
||||
st.header("控制面板")
|
||||
|
||||
# 决策问题输入
|
||||
# 主页面布局
|
||||
st.title("🤖 AI经理人为你把关")
|
||||
st.markdown("### ⚡ 专业AI决策辅助系统 - 同步处理 + 智能缓存")
|
||||
|
||||
# 决策问题输入区域 - 融合到主页面
|
||||
col1, col2 = st.columns([3, 1])
|
||||
|
||||
with col1:
|
||||
st.markdown("### 💭 请输入决策问题")
|
||||
question = st.text_area(
|
||||
"请输入决策问题:",
|
||||
"决策问题",
|
||||
placeholder="例如:我们应该开发一个新的移动应用吗?",
|
||||
height=100
|
||||
height=80,
|
||||
label_visibility="collapsed"
|
||||
)
|
||||
|
||||
# 开始辩论按钮
|
||||
if st.button("🚀 开始辩论", type="primary", use_container_width=True):
|
||||
if question.strip():
|
||||
st.session_state.debate_state = st.session_state.workshop.initialize_debate(question)
|
||||
st.session_state.debate_in_progress = True
|
||||
st.rerun()
|
||||
else:
|
||||
st.warning("请输入决策问题")
|
||||
|
||||
# 辩论控制按钮
|
||||
if st.session_state.debate_in_progress:
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
if st.button("⏭️ 下一轮", use_container_width=True):
|
||||
if st.session_state.debate_state["rounds"] < st.session_state.debate_state["max_rounds"]:
|
||||
st.session_state.debate_state = st.session_state.workshop.conduct_debate_round(
|
||||
st.session_state.debate_state
|
||||
)
|
||||
# 开始把关按钮
|
||||
col_btn1, col_btn2 = st.columns([1, 1])
|
||||
with col_btn1:
|
||||
if st.button("🚀 开始把关", type="primary", use_container_width=True):
|
||||
if question.strip():
|
||||
# 检查是否为宽泛问题
|
||||
if st.session_state.workshop.is_broad_question(question):
|
||||
st.session_state.needs_clarification = True
|
||||
st.session_state.clarification_questions = st.session_state.workshop.generate_clarification_questions(question)
|
||||
st.session_state.refined_question = question
|
||||
st.rerun()
|
||||
else:
|
||||
st.session_state.debate_in_progress = False
|
||||
# 直接开始把关
|
||||
st.session_state.debate_state = st.session_state.workshop.initialize_debate(question)
|
||||
st.session_state.debate_in_progress = True
|
||||
|
||||
# 立即执行一轮把关
|
||||
if st.session_state.ultra_fast_mode:
|
||||
progress_bar = st.progress(0)
|
||||
status_text = st.empty()
|
||||
|
||||
# 执行所有轮次
|
||||
for round_num in range(st.session_state.debate_state["max_rounds"]):
|
||||
progress = (round_num + 1) / st.session_state.debate_state["max_rounds"]
|
||||
status_text.text(f"正在处理第 {round_num + 1} 轮...")
|
||||
progress_bar.progress(progress)
|
||||
|
||||
# 执行一轮把关
|
||||
st.session_state.debate_state = st.session_state.workshop.conduct_fast_debate(
|
||||
st.session_state.debate_state
|
||||
)
|
||||
|
||||
status_text.text("✅ 把关完成!")
|
||||
progress_bar.progress(1.0)
|
||||
st.session_state.debate_in_progress = False
|
||||
|
||||
st.rerun()
|
||||
|
||||
with col2:
|
||||
if st.button("⏹️ 结束辩论", use_container_width=True):
|
||||
else:
|
||||
st.warning("请输入决策问题")
|
||||
|
||||
with col_btn2:
|
||||
if st.session_state.debate_in_progress and not st.session_state.ultra_fast_mode:
|
||||
if st.button("⏹️ 结束把关", use_container_width=True):
|
||||
st.session_state.debate_in_progress = False
|
||||
st.rerun()
|
||||
|
||||
with col2:
|
||||
st.markdown("### ⚙️ 设置")
|
||||
|
||||
# 超快速模式开关
|
||||
ultra_fast_mode = st.toggle("⚡ 超快速模式", value=True, help="启用异步并行处理 + 智能缓存,响应速度提升500%")
|
||||
st.session_state.ultra_fast_mode = ultra_fast_mode
|
||||
|
||||
if ultra_fast_mode:
|
||||
st.success("⚡ 超快速模式已启用")
|
||||
else:
|
||||
st.info("标准模式")
|
||||
|
||||
st.markdown("---")
|
||||
st.markdown("### 参与代理")
|
||||
st.markdown("### 👥 参与代理")
|
||||
for agent_name in st.session_state.workshop.agents.keys():
|
||||
st.markdown(f"- {agent_name}")
|
||||
|
||||
# 主内容区
|
||||
col1, col2 = st.columns([2, 1])
|
||||
|
||||
with col1:
|
||||
st.header("辩论过程")
|
||||
# 问题细化界面
|
||||
if st.session_state.needs_clarification:
|
||||
st.markdown("---")
|
||||
st.markdown("### 🔍 问题细化")
|
||||
st.info("💡 **检测到宽泛问题**:为了提供更精准的分析,请先回答以下澄清问题")
|
||||
|
||||
if st.session_state.debate_state:
|
||||
# 显示辩论进度
|
||||
progress = min(st.session_state.debate_state["rounds"] / st.session_state.debate_state["max_rounds"], 1.0)
|
||||
st.progress(progress, text=f"辩论进度:{st.session_state.debate_state['rounds']}/{st.session_state.debate_state['max_rounds']}轮")
|
||||
|
||||
# 显示辩论历史
|
||||
for entry in st.session_state.debate_state["debate_history"]:
|
||||
with st.chat_message("user", avatar=f"👤"):
|
||||
st.markdown(f"**{entry['speaker']}** ({entry['timestamp']})")
|
||||
st.write(entry["content"])
|
||||
|
||||
# 显示当前状态
|
||||
if st.session_state.debate_in_progress:
|
||||
st.info(f"🔄 等待 {st.session_state.debate_state['current_speaker']} 发言...")
|
||||
else:
|
||||
st.success("✅ 辩论已完成!")
|
||||
st.markdown(f"**原始问题**:{st.session_state.refined_question}")
|
||||
|
||||
# 生成预定义选项映射
|
||||
if not st.session_state.predefined_options_map:
|
||||
for question in st.session_state.clarification_questions:
|
||||
st.session_state.predefined_options_map[question] = st.session_state.workshop.get_predefined_options_for_question(question)
|
||||
|
||||
# 显示澄清问题 - 选项式选择
|
||||
for i, question in enumerate(st.session_state.clarification_questions, 1):
|
||||
with st.container():
|
||||
st.markdown(f"**{i}. {question}**")
|
||||
|
||||
# 生成总结
|
||||
if st.button("📊 生成决策总结"):
|
||||
with st.spinner("正在生成决策要点..."):
|
||||
summary = st.session_state.workshop.generate_decision_summary(
|
||||
st.session_state.debate_state["debate_history"]
|
||||
# 显示当前选择状态
|
||||
current_answer = st.session_state.clarification_answers.get(question)
|
||||
if current_answer:
|
||||
st.success(f"✅ 已选择:{current_answer}")
|
||||
else:
|
||||
st.info("💡 请点击选择或手动输入")
|
||||
|
||||
# 获取该问题的预定义选项
|
||||
options_dict = st.session_state.predefined_options_map.get(question, {})
|
||||
|
||||
if options_dict:
|
||||
# 显示选项按钮
|
||||
for option_key, option_list in options_dict.items():
|
||||
st.markdown(f"**{option_key}**")
|
||||
|
||||
# 根据选项数量动态调整列数
|
||||
num_cols = min(len(option_list), 4) # 最多4列
|
||||
cols = st.columns(num_cols)
|
||||
|
||||
for j, option in enumerate(option_list):
|
||||
col_idx = j % num_cols
|
||||
with cols[col_idx]:
|
||||
# 检查是否已选择该选项
|
||||
is_selected = st.session_state.selected_options.get(f"{question}_{option_key}") == option
|
||||
|
||||
# 使用更明显的视觉区分
|
||||
button_text = f"✅ {option}" if is_selected else option
|
||||
button_type = "primary" if is_selected else "secondary"
|
||||
|
||||
# 生成唯一的key,包含问题、选项类别和选项的哈希值
|
||||
unique_key = f"option_{hash(question)}_{hash(option_key)}_{hash(option)}"
|
||||
|
||||
if st.button(button_text,
|
||||
key=unique_key,
|
||||
use_container_width=True,
|
||||
type=button_type):
|
||||
# 切换选择状态
|
||||
if is_selected:
|
||||
st.session_state.selected_options.pop(f"{question}_{option_key}", None)
|
||||
st.session_state.clarification_answers.pop(question, None)
|
||||
else:
|
||||
# 清除该问题的其他选项
|
||||
for key in list(st.session_state.selected_options.keys()):
|
||||
if key.startswith(f"{question}_"):
|
||||
st.session_state.selected_options.pop(key, None)
|
||||
st.session_state.selected_options[f"{question}_{option_key}"] = option
|
||||
st.session_state.clarification_answers[question] = f"{option_key}:{option}"
|
||||
st.rerun()
|
||||
|
||||
# 仍然提供文本输入作为备选
|
||||
st.markdown("**或手动输入:**")
|
||||
custom_answer = st.text_input(
|
||||
f"手动输入回答",
|
||||
key=f"custom_{i}",
|
||||
placeholder="如果以上选项不合适,请在此输入...",
|
||||
value=current_answer if current_answer and ":" not in current_answer else ""
|
||||
)
|
||||
if custom_answer.strip():
|
||||
# 如果手动输入,清除选项选择
|
||||
for key in list(st.session_state.selected_options.keys()):
|
||||
if key.startswith(f"{question}_"):
|
||||
st.session_state.selected_options.pop(key, None)
|
||||
st.session_state.clarification_answers[question] = custom_answer
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 确认按钮
|
||||
col_confirm1, col_confirm2 = st.columns([1, 1])
|
||||
with col_confirm1:
|
||||
if st.button("✅ 确认并开始把关", type="primary", use_container_width=True):
|
||||
# 细化问题
|
||||
refined_question = st.session_state.workshop.refine_question_with_context(
|
||||
st.session_state.refined_question,
|
||||
st.session_state.clarification_answers
|
||||
)
|
||||
|
||||
# 开始把关
|
||||
st.session_state.debate_state = st.session_state.workshop.initialize_debate(refined_question)
|
||||
st.session_state.debate_in_progress = True
|
||||
st.session_state.needs_clarification = False
|
||||
|
||||
# 立即执行一轮把关
|
||||
if st.session_state.ultra_fast_mode:
|
||||
progress_bar = st.progress(0)
|
||||
status_text = st.empty()
|
||||
|
||||
# 执行所有轮次
|
||||
for round_num in range(st.session_state.debate_state["max_rounds"]):
|
||||
progress = (round_num + 1) / st.session_state.debate_state["max_rounds"]
|
||||
status_text.text(f"正在处理第 {round_num + 1} 轮...")
|
||||
progress_bar.progress(progress)
|
||||
|
||||
# 执行一轮把关
|
||||
st.session_state.debate_state = st.session_state.workshop.conduct_fast_debate(
|
||||
st.session_state.debate_state
|
||||
)
|
||||
st.session_state.summary = summary
|
||||
|
||||
status_text.text("✅ 把关完成!")
|
||||
progress_bar.progress(1.0)
|
||||
st.session_state.debate_in_progress = False
|
||||
|
||||
if "summary" in st.session_state:
|
||||
st.markdown("### 决策要点总结")
|
||||
st.write(st.session_state.summary)
|
||||
else:
|
||||
st.info("👆 请在左侧输入决策问题并开始辩论")
|
||||
|
||||
with col2:
|
||||
st.header("决策助手")
|
||||
st.rerun()
|
||||
|
||||
with col_confirm2:
|
||||
if st.button("🔄 跳过细化", use_container_width=True):
|
||||
# 直接开始把关,不细化问题
|
||||
st.session_state.debate_state = st.session_state.workshop.initialize_debate(st.session_state.refined_question)
|
||||
st.session_state.debate_in_progress = True
|
||||
st.session_state.needs_clarification = False
|
||||
|
||||
# 立即执行一轮把关
|
||||
if st.session_state.ultra_fast_mode:
|
||||
progress_bar = st.progress(0)
|
||||
status_text = st.empty()
|
||||
|
||||
# 执行所有轮次
|
||||
for round_num in range(st.session_state.debate_state["max_rounds"]):
|
||||
progress = (round_num + 1) / st.session_state.debate_state["max_rounds"]
|
||||
status_text.text(f"正在处理第 {round_num + 1} 轮...")
|
||||
progress_bar.progress(progress)
|
||||
|
||||
# 执行一轮把关
|
||||
st.session_state.debate_state = st.session_state.workshop.conduct_fast_debate(
|
||||
st.session_state.debate_state
|
||||
)
|
||||
|
||||
status_text.text("✅ 把关完成!")
|
||||
progress_bar.progress(1.0)
|
||||
st.session_state.debate_in_progress = False
|
||||
|
||||
st.rerun()
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# 侧边栏 - 简化控制面板
|
||||
with st.sidebar:
|
||||
st.header("📋 快速决策模板")
|
||||
|
||||
# 快速决策模板
|
||||
st.markdown("### 快速决策模板")
|
||||
templates = [
|
||||
"产品功能优先级排序",
|
||||
"技术方案选择评估",
|
||||
@ -250,14 +754,107 @@ def main():
|
||||
st.rerun()
|
||||
|
||||
st.markdown("---")
|
||||
st.markdown("### 使用说明")
|
||||
st.markdown("### 📊 性能指标")
|
||||
st.markdown("""
|
||||
1. 输入决策问题
|
||||
2. 点击开始辩论
|
||||
3. 观察AI代理的多角度分析
|
||||
4. 生成决策要点总结
|
||||
5. 基于共识制定行动计划
|
||||
- **响应速度**: 3-6秒
|
||||
- **缓存命中率**: 重复问题秒级响应
|
||||
- **并行处理**: 4个代理同时工作
|
||||
""")
|
||||
|
||||
# 把关结果显示区域
|
||||
if st.session_state.debate_state:
|
||||
st.markdown("### 🗣️ 经理人把关过程")
|
||||
|
||||
# 显示把关进度
|
||||
progress = min(st.session_state.debate_state["rounds"] / st.session_state.debate_state["max_rounds"], 1.0)
|
||||
st.progress(progress, text=f"把关进度:{st.session_state.debate_state['rounds']}/{st.session_state.debate_state['max_rounds']}轮")
|
||||
|
||||
# 显示把关历史
|
||||
for entry in st.session_state.debate_state["debate_history"]:
|
||||
with st.chat_message("user", avatar=f"👤"):
|
||||
st.markdown(f"**{entry['speaker']}** ({entry['timestamp']})")
|
||||
st.write(entry["content"])
|
||||
|
||||
# 显示当前状态
|
||||
if st.session_state.debate_in_progress:
|
||||
st.info(f"🔄 等待 {st.session_state.debate_state['current_speaker']} 发言...")
|
||||
else:
|
||||
st.success("✅ 把关已完成!")
|
||||
|
||||
# 生成总结按钮
|
||||
col_sum1, col_sum2 = st.columns([2, 1])
|
||||
with col_sum1:
|
||||
if st.button("📊 生成决策总结和推荐度", type="secondary", use_container_width=True):
|
||||
with st.spinner("正在生成决策要点和推荐度..."):
|
||||
summary_data = st.session_state.workshop.generate_decision_summary(
|
||||
st.session_state.debate_state["debate_history"]
|
||||
)
|
||||
st.session_state.summary_data = summary_data
|
||||
st.rerun()
|
||||
|
||||
# 显示推荐度 - 确保总是显示
|
||||
if "summary_data" in st.session_state:
|
||||
summary_data = st.session_state.summary_data
|
||||
|
||||
# 显示推荐度
|
||||
st.markdown("### 🎯 决策推荐度")
|
||||
|
||||
# 根据推荐度显示不同的颜色和图标
|
||||
recommendation_level = summary_data["recommendation_level"]
|
||||
stars = summary_data["stars"]
|
||||
|
||||
if recommendation_level >= 4:
|
||||
st.success(f"🎯 推荐度:{stars} (强烈推荐)")
|
||||
elif recommendation_level == 3:
|
||||
st.info(f"⚖️ 推荐度:{stars} (中立)")
|
||||
elif recommendation_level == 2:
|
||||
st.warning(f"⚠️ 推荐度:{stars} (谨慎)")
|
||||
else:
|
||||
st.error(f"❌ 推荐度:{stars} (不推荐)")
|
||||
|
||||
# 显示详细总结
|
||||
st.markdown("### 📋 决策要点总结")
|
||||
st.write(summary_data["summary"])
|
||||
else:
|
||||
# 初始状态显示
|
||||
st.markdown("### 💡 欢迎使用AI经理人为你把关")
|
||||
st.markdown("""
|
||||
这是一个基于AI的专业决策辅助系统,四位AI经理人将从不同专业角度为您把关决策:
|
||||
|
||||
**👥 参与经理人:**
|
||||
- **技术专家** - 技术可行性、实现难度
|
||||
- **战略顾问** - 战略规划、竞争优势
|
||||
- **用户体验师** - 用户需求、易用性
|
||||
- **风险顾问** - 潜在风险、不确定性
|
||||
|
||||
**🚀 使用方法:**
|
||||
1. 在上方输入您的决策问题
|
||||
2. 点击"开始把关"按钮
|
||||
3. 观察经理人们的专业分析
|
||||
4. 生成综合决策总结和推荐度
|
||||
|
||||
**⚡ 特色功能:**
|
||||
- 五位推荐度评级系统
|
||||
- 具体实施建议和时间规划
|
||||
- 超快速响应(3-6秒)
|
||||
- 智能缓存技术
|
||||
""")
|
||||
|
||||
# 显示示例问题
|
||||
st.markdown("### 📝 示例问题")
|
||||
examples = [
|
||||
"我们是否应该投资AI技术?",
|
||||
"是否应该开发新的移动应用?",
|
||||
"如何优化现有产品的用户体验?",
|
||||
"团队资源应该如何分配?"
|
||||
]
|
||||
|
||||
for example in examples:
|
||||
if st.button(example, use_container_width=True):
|
||||
st.session_state.debate_state = st.session_state.workshop.initialize_debate(example)
|
||||
st.session_state.debate_in_progress = True
|
||||
st.rerun()
|
||||
|
||||
# 启动应用
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user