UNPKG

answer-book-mcp

Version:

智能问答和决策辅助的 MCP (Model Context Protocol) 服务器

766 lines (673 loc) 22.4 kB
/** * 决策建议工具 * 根据用户描述的情况提供个性化的决策建议 */ import { BaseTool } from './base-tool.js' import { validateGetAdvice } from '../utils/validator.js' import { logger } from '../utils/logger.js' /** * 决策建议工具类 */ export class GetAdviceTool extends BaseTool { constructor(storageManager, config) { super( 'get_advice', '根据您描述的情况和选项,提供个性化的决策建议和分析', { type: 'object', properties: { situation: { type: 'string', description: '详细描述您面临的情况或困境', minLength: 10, maxLength: 2000 }, options: { type: 'array', description: '可选的决策选项(可选)', items: { type: 'string', maxLength: 200 }, maxItems: 10 }, priority: { type: 'string', description: '决策优先级倾向', enum: ['practical', 'emotional', 'balanced', 'risk_averse', 'innovative'], default: 'balanced' }, timeline: { type: 'string', description: '决策时间紧迫性', enum: ['urgent', 'normal', 'flexible'] } }, required: ['situation'] } ) this.storageManager = storageManager this.config = config // 决策框架模板 this.decisionFrameworks = { practical: { name: '实用主义框架', factors: ['成本效益', '可行性', '资源需求', '实施难度', '短期收益'], weight: { cost: 0.3, feasibility: 0.3, resources: 0.2, difficulty: 0.1, benefit: 0.1 } }, emotional: { name: '情感导向框架', factors: ['个人感受', '价值观匹配', '内心声音', '情感满足', '人际关系'], weight: { feeling: 0.3, values: 0.25, intuition: 0.2, satisfaction: 0.15, relationships: 0.1 } }, balanced: { name: '平衡决策框架', factors: ['理性分析', '情感考量', '风险评估', '机会成本', '长期影响'], weight: { rational: 0.25, emotional: 0.2, risk: 0.2, opportunity: 0.15, longterm: 0.2 } }, risk_averse: { name: '风险规避框架', factors: ['安全性', '稳定性', '可预测性', '保障措施', '退路选择'], weight: { safety: 0.3, stability: 0.25, predictability: 0.2, protection: 0.15, backup: 0.1 } }, innovative: { name: '创新导向框架', factors: ['创新潜力', '学习机会', '突破可能', '未来趋势', '差异化优势'], weight: { innovation: 0.3, learning: 0.2, breakthrough: 0.2, trend: 0.15, advantage: 0.15 } } } this.storageManager = storageManager this.config = config // 时间紧迫性影响因子 this.timelineFactors = { urgent: { name: '紧急决策', emphasis: ['快速执行', '现有资源', '简单方案', '风险控制'], multiplier: { speed: 1.5, simplicity: 1.3, resources: 1.2, risk: 0.8 } }, normal: { name: '常规决策', emphasis: ['全面分析', '多方考虑', '充分准备', '平衡选择'], multiplier: { analysis: 1.2, consideration: 1.1, preparation: 1.1, balance: 1.0 } }, flexible: { name: '灵活决策', emphasis: ['深度思考', '创新方案', '长远规划', '最优选择'], multiplier: { thinking: 1.3, innovation: 1.4, planning: 1.3, optimization: 1.2 } } } } /** * 参数验证 */ async validateParams(params) { const cleanParams = await super.validateParams(params) return validateGetAdvice(cleanParams) } /** * 执行决策建议逻辑 */ async run(params) { const { situation, options = [], priority = 'balanced', timeline } = params try { logger.info('开始生成决策建议', { situationLength: situation.length, optionsCount: options.length, priority, timeline }) // 分析情况 const situationAnalysis = await this.analyzeSituation(situation) // 获取相关答案 const answers = await this.storageManager.loadAnswers() const relevantAnswers = await this.findRelevantAnswers(situation, answers) // 生成决策建议 const advice = await this.generateAdvice({ situation, situationAnalysis, options, priority, timeline, relevantAnswers }) // 保存到历史记录 await this.saveAdviceToHistory({ situation, advice, priority, timeline, options }) logger.info('决策建议生成完成', { adviceType: advice.type, optionsAnalyzed: advice.options_analysis?.length || 0 }) return this.createSuccessResponse(advice, '已为您生成决策建议') } catch (error) { logger.error('生成决策建议失败', { error: error.message, situationLength: situation.length }) throw error } } /** * 分析情况 */ async analyzeSituation(situation) { try { const analysis = { keywords: this.extractKeywords(situation), sentiment: this.analyzeSentiment(situation), complexity: this.assessComplexity(situation), domain: await this.identifyDomain(situation), urgency: this.assessUrgency(situation), stakeholders: this.identifyStakeholders(situation), constraints: this.identifyConstraints(situation) } return analysis } catch (error) { logger.warn('情况分析失败', { error: error.message }) return { keywords: [], sentiment: 'neutral', complexity: 'medium', domain: 'general', urgency: 'normal', stakeholders: [], constraints: [] } } } /** * 提取关键词 */ extractKeywords(text) { const words = text.match(/[\u4e00-\u9fa5]+|[a-zA-Z]+/g) || [] const stopWords = new Set([ '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '上', '也', '很', '到', '说', '要', '去', '你', '会', 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were' ]) const keywordFreq = {} words.forEach(word => { const lowerWord = word.toLowerCase() if (word.length > 1 && !stopWords.has(lowerWord)) { keywordFreq[word] = (keywordFreq[word] || 0) + 1 } }) return Object.entries(keywordFreq) .sort(([,a], [,b]) => b - a) .slice(0, 10) .map(([word]) => word) } /** * 情感分析 */ analyzeSentiment(text) { const positiveWords = ['好', '棒', '优秀', '成功', '快乐', '满意', '希望', '机会', 'good', 'great', 'excellent', 'success', 'happy', 'opportunity'] const negativeWords = ['坏', '糟糕', '失败', '困难', '问题', '担心', '焦虑', 'bad', 'terrible', 'failure', 'difficult', 'problem', 'worry', 'anxiety'] const textLower = text.toLowerCase() let positiveScore = 0 let negativeScore = 0 positiveWords.forEach(word => { if (textLower.includes(word)) positiveScore++ }) negativeWords.forEach(word => { if (textLower.includes(word)) negativeScore++ }) if (positiveScore > negativeScore) return 'positive' if (negativeScore > positiveScore) return 'negative' return 'neutral' } /** * 评估复杂度 */ assessComplexity(situation) { const length = situation.length const sentences = situation.split(/[。!?.!?]/).length const keywords = this.extractKeywords(situation).length let score = 0 if (length > 500) score += 2 else if (length > 200) score += 1 if (sentences > 5) score += 2 else if (sentences > 3) score += 1 if (keywords > 8) score += 2 else if (keywords > 5) score += 1 if (score >= 4) return 'high' if (score >= 2) return 'medium' return 'low' } /** * 识别领域 */ async identifyDomain(situation) { try { const result = await this.server.matcher.suggestCategory(situation) return result.category } catch (error) { return 'general' } } /** * 评估紧迫性 */ assessUrgency(situation) { const urgentKeywords = ['紧急', '急需', '马上', '立即', '尽快', 'urgent', 'immediately', 'asap', 'quickly'] const flexibleKeywords = ['考虑', '思考', '计划', '将来', '未来', 'consider', 'think', 'plan', 'future'] const textLower = situation.toLowerCase() const urgentCount = urgentKeywords.filter(keyword => textLower.includes(keyword)).length const flexibleCount = flexibleKeywords.filter(keyword => textLower.includes(keyword)).length if (urgentCount > flexibleCount) return 'urgent' if (flexibleCount > urgentCount) return 'flexible' return 'normal' } /** * 识别利益相关者 */ identifyStakeholders(situation) { const stakeholderPatterns = { '家人': /家人|父母|配偶|孩子|家庭|family|parents|spouse|children/i, '同事': /同事|同事|团队|老板|公司|colleague|team|boss|company/i, '朋友': /朋友|朋友圈|社交|friend|social/i, '客户': /客户|用户|顾客|client|customer|user/i, '合作伙伴': /合作|伙伴|供应商|partner|supplier/i } const stakeholders = [] for (const [stakeholder, pattern] of Object.entries(stakeholderPatterns)) { if (pattern.test(situation)) { stakeholders.push(stakeholder) } } return stakeholders } /** * 识别约束条件 */ identifyConstraints(situation) { const constraintPatterns = { '时间': /时间|期限|截止|deadline|time|schedule/i, '预算': /预算|资金|成本|费用|budget|cost|money/i, '资源': /资源|人力|设备|resource|manpower|equipment/i, '技能': /技能|能力|经验|skill|ability|experience/i, '政策': /政策|规定|法律|policy|regulation|law/i } const constraints = [] for (const [constraint, pattern] of Object.entries(constraintPatterns)) { if (pattern.test(situation)) { constraints.push(constraint) } } return constraints } /** * 查找相关答案 */ async findRelevantAnswers(situation, answers) { try { const matchResult = await this.server.matcher.findBestAnswer( situation, answers, { category: 'decision' } ) // 获取相关的决策类答案 const relevantAnswers = answers .filter(answer => answer.category === 'decision' || answer.category === 'general' ) .sort((a, b) => (b.success_rate || 0.5) - (a.success_rate || 0.5)) .slice(0, 5) return relevantAnswers } catch (error) { logger.warn('查找相关答案失败', { error: error.message }) return [] } } /** * 生成决策建议 */ async generateAdvice(context) { const { situation, situationAnalysis, options, priority, timeline, relevantAnswers } = context const framework = this.decisionFrameworks[priority] const timelineFactor = timeline ? this.timelineFactors[timeline] : null const advice = { type: 'decision_advice', situation_summary: this.summarizeSituation(situation, situationAnalysis), framework_used: framework.name, analysis: { complexity: situationAnalysis.complexity, domain: situationAnalysis.domain, urgency: situationAnalysis.urgency, key_factors: framework.factors, stakeholders: situationAnalysis.stakeholders, constraints: situationAnalysis.constraints }, recommendations: [], options_analysis: [], action_plan: [], considerations: [], related_wisdom: [] } // 生成主要建议 advice.recommendations = this.generateRecommendations( situationAnalysis, framework, timelineFactor ) // 分析选项(如果提供) if (options.length > 0) { advice.options_analysis = this.analyzeOptions( options, situationAnalysis, framework ) } // 生成行动计划 advice.action_plan = this.generateActionPlan( situationAnalysis, timelineFactor ) // 生成考虑要点 advice.considerations = this.generateConsiderations( situationAnalysis, framework ) // 添加相关智慧 advice.related_wisdom = relevantAnswers.map(answer => ({ text: answer.text, category: answer.category, relevance: 'decision_support' })) return advice } /** * 总结情况 */ summarizeSituation(situation, analysis) { const summary = { main_issue: situation.substring(0, 100) + (situation.length > 100 ? '...' : ''), complexity_level: analysis.complexity, primary_domain: analysis.domain, emotional_tone: analysis.sentiment, time_sensitivity: analysis.urgency } return summary } /** * 生成建议 */ generateRecommendations(analysis, framework, timelineFactor) { const recommendations = [] // 基于框架生成建议 if (framework.name === '实用主义框架') { recommendations.push({ priority: 'high', action: '进行成本效益分析', reason: '实用主义决策需要明确的投入产出比', timeline: timelineFactor?.name === '紧急决策' ? '立即执行' : '1-2天内完成' }) recommendations.push({ priority: 'medium', action: '评估可用资源', reason: '确保有足够的资源支持决策实施', timeline: '决策前完成' }) } else if (framework.name === '情感导向框架') { recommendations.push({ priority: 'high', action: '倾听内心声音', reason: '情感导向决策需要与个人价值观保持一致', timeline: '充分思考后决定' }) recommendations.push({ priority: 'medium', action: '考虑对人际关系的影响', reason: '情感决策往往涉及重要的人际关系', timeline: '决策前评估' }) } else if (framework.name === '平衡决策框架') { recommendations.push({ priority: 'high', action: '制作决策矩阵', reason: '平衡决策需要系统性地权衡各个因素', timeline: '决策前1-3天' }) recommendations.push({ priority: 'medium', action: '寻求多方意见', reason: '平衡的决策需要多角度的输入', timeline: '收集意见阶段' }) } // 基于复杂度调整建议 if (analysis.complexity === 'high') { recommendations.push({ priority: 'high', action: '分解复杂问题', reason: '复杂情况需要分步骤处理', timeline: '优先执行' }) } // 基于紧迫性调整建议 if (analysis.urgency === 'urgent') { recommendations.unshift({ priority: 'critical', action: '快速决策', reason: '时间紧迫,需要基于现有信息快速决定', timeline: '立即' }) } return recommendations.slice(0, 5) // 最多5个建议 } /** * 分析选项 */ analyzeOptions(options, analysis, framework) { return options.map((option, index) => { const scores = {} let totalScore = 0 // 基于框架因素评分 framework.factors.forEach(factor => { const score = this.scoreOptionForFactor(option, factor, analysis) scores[factor] = score totalScore += score * (framework.weight[Object.keys(framework.weight)[framework.factors.indexOf(factor)]] || 0.2) }) return { option, index: index + 1, overall_score: Math.round(totalScore * 100) / 100, factor_scores: scores, pros: this.generatePros(option, analysis), cons: this.generateCons(option, analysis), recommendation: totalScore > 0.7 ? 'strongly_recommended' : totalScore > 0.5 ? 'recommended' : totalScore > 0.3 ? 'consider' : 'not_recommended' } }) } /** * 为特定因素评分选项 */ scoreOptionForFactor(option, factor, analysis) { // 简化的评分逻辑,实际项目中可以更复杂 const optionLower = option.toLowerCase() const factorKeywords = { '成本效益': ['便宜', '经济', '节省', 'cheap', 'economic', 'save'], '可行性': ['可行', '容易', '简单', 'feasible', 'easy', 'simple'], '个人感受': ['喜欢', '开心', '满意', 'like', 'happy', 'satisfied'], '风险评估': ['安全', '稳定', '保险', 'safe', 'stable', 'secure'], '创新潜力': ['新', '创新', '突破', 'new', 'innovative', 'breakthrough'] } const keywords = factorKeywords[factor] || [] const matchCount = keywords.filter(keyword => optionLower.includes(keyword)).length return Math.min(1.0, 0.3 + (matchCount * 0.2)) // 基础分0.3,每个匹配关键词+0.2 } /** * 生成优点 */ generatePros(option, analysis) { const pros = [] const optionLower = option.toLowerCase() if (optionLower.includes('快') || optionLower.includes('quick')) { pros.push('执行速度快') } if (optionLower.includes('便宜') || optionLower.includes('cheap')) { pros.push('成本较低') } if (optionLower.includes('安全') || optionLower.includes('safe')) { pros.push('风险较小') } // 如果没有明显优点,添加通用优点 if (pros.length === 0) { pros.push('是一个可考虑的选择') } return pros } /** * 生成缺点 */ generateCons(option, analysis) { const cons = [] const optionLower = option.toLowerCase() if (optionLower.includes('贵') || optionLower.includes('expensive')) { cons.push('成本较高') } if (optionLower.includes('难') || optionLower.includes('difficult')) { cons.push('实施难度大') } if (optionLower.includes('险') || optionLower.includes('risk')) { cons.push('存在一定风险') } // 如果没有明显缺点,添加通用提醒 if (cons.length === 0) { cons.push('需要仔细评估具体细节') } return cons } /** * 生成行动计划 */ generateActionPlan(analysis, timelineFactor) { const plan = [] if (timelineFactor?.name === '紧急决策') { plan.push({ step: 1, action: '收集关键信息', timeline: '30分钟内', description: '快速收集做决策所需的最关键信息' }) plan.push({ step: 2, action: '快速评估选项', timeline: '1小时内', description: '基于现有信息快速评估各个选项' }) plan.push({ step: 3, action: '做出决策', timeline: '2小时内', description: '基于评估结果做出最终决策' }) } else { plan.push({ step: 1, action: '深入分析情况', timeline: '1-2天', description: '全面分析当前情况和各种因素' }) plan.push({ step: 2, action: '收集更多信息', timeline: '2-3天', description: '收集更多相关信息和他人意见' }) plan.push({ step: 3, action: '制定决策方案', timeline: '3-5天', description: '基于分析制定详细的决策方案' }) plan.push({ step: 4, action: '实施决策', timeline: '1周内', description: '开始实施选定的决策方案' }) } return plan } /** * 生成考虑要点 */ generateConsiderations(analysis, framework) { const considerations = [] // 基于利益相关者 if (analysis.stakeholders.length > 0) { considerations.push({ category: '利益相关者', point: `考虑对${analysis.stakeholders.join('、')}的影响`, importance: 'high' }) } // 基于约束条件 if (analysis.constraints.length > 0) { considerations.push({ category: '约束条件', point: `注意${analysis.constraints.join('、')}方面的限制`, importance: 'high' }) } // 基于复杂度 if (analysis.complexity === 'high') { considerations.push({ category: '复杂性管理', point: '问题较为复杂,建议分步骤处理', importance: 'medium' }) } // 基于情感倾向 if (analysis.sentiment === 'negative') { considerations.push({ category: '情绪管理', point: '当前可能存在负面情绪,建议冷静后再做决策', importance: 'medium' }) } return considerations } /** * 保存建议到历史记录 */ async saveAdviceToHistory(data) { try { await this.storageManager.addHistoryRecord({ question: `决策咨询: ${data.situation.substring(0, 50)}...`, answer: `建议类型: ${data.advice.type}`, category: 'decision', confidence: 0.8, source: 'advice', language: 'zh', advice_data: { priority: data.priority, timeline: data.timeline, options_count: data.options.length, recommendations_count: data.advice.recommendations?.length || 0 } }) } catch (error) { logger.warn('保存建议历史失败', { error: error.message }) } } }