918bbed0fc
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service) - 移除登录页面上的明文密码提示 - 改进前端错误处理,避免数据加载失败导致登录显示错误
411 lines
10 KiB
JavaScript
411 lines
10 KiB
JavaScript
/**
|
|
* Linus 三问决策框架
|
|
*
|
|
* 实现工程审慎决策逻辑
|
|
* 来源: Linus Torvalds "Talk Like a Kernel Developer"
|
|
*/
|
|
|
|
/**
|
|
* 三问枚举
|
|
*/
|
|
export const QuestionType = {
|
|
REAL_PROBLEM: '这是现实问题还是想象问题?',
|
|
NEEDS_SOLUTION: '这个问题真的需要解决吗?',
|
|
SOLUTION_VIABLE: '这个方案真的能解决问题吗?'
|
|
}
|
|
|
|
/**
|
|
* Linus 三问决策器类
|
|
*/
|
|
export class LinusTriadDecision {
|
|
constructor() {
|
|
this.questions = [
|
|
QuestionType.REAL_PROBLEM,
|
|
QuestionType.NEEDS_SOLUTION,
|
|
QuestionType.SOLUTION_VIABLE
|
|
]
|
|
this.answers = []
|
|
this.reasoning = []
|
|
}
|
|
|
|
/**
|
|
* 执行完整的 Linus 三问
|
|
*
|
|
* @param {string} taskDescription - 任务描述
|
|
* @param {Object} options - 选项
|
|
* @returns {Promise<Object>} 决策结果
|
|
*/
|
|
async ask(taskDescription, options = {}) {
|
|
const { interactive = false, context = null } = options
|
|
|
|
// 清空之前的答案
|
|
this.answers = []
|
|
this.reasoning = []
|
|
|
|
log('🤔 开始 Linus 三问决策...')
|
|
log(`📋 任务: ${taskDescription}`)
|
|
|
|
// 第一问:现实问题还是想象问题?
|
|
const q1Result = await this.isRealProblem(taskDescription, context)
|
|
this.answers.push(q1Result.answer)
|
|
this.reasoning.push(q1Result.reasoning)
|
|
|
|
if (!q1Result.answer) {
|
|
log('❌ 第一问未通过:这不是现实问题')
|
|
return this.createResult(false, '第一问未通过:这不是现实问题', q1Result.reasoning)
|
|
}
|
|
log('✅ 第一问通过:这是现实问题')
|
|
|
|
// 第二问:这个问题真的需要解决吗?
|
|
const q2Result = await this.needsSolution(taskDescription, context)
|
|
this.answers.push(q2Result.answer)
|
|
this.reasoning.push(q2Result.reasoning)
|
|
|
|
if (!q2Result.answer) {
|
|
log('❌ 第二问未通过:这个问题不需要解决')
|
|
return this.createResult(false, '第二问未通过:这个问题不需要解决', [
|
|
this.reasoning[0],
|
|
q2Result.reasoning
|
|
])
|
|
}
|
|
log('✅ 第二问通过:这个问题需要解决')
|
|
|
|
// 第三问:这个方案真的能解决问题吗?
|
|
const q3Result = await this.solutionViable(taskDescription, context)
|
|
this.answers.push(q3Result.answer)
|
|
this.reasoning.push(q3Result.reasoning)
|
|
|
|
if (!q3Result.answer) {
|
|
log('❌ 第三问未通过:这个方案不能解决问题')
|
|
return this.createResult(false, '第三问未通过:这个方案不能解决问题', [
|
|
this.reasoning[0],
|
|
this.reasoning[1],
|
|
q3Result.reasoning
|
|
])
|
|
}
|
|
log('✅ 第三问通过:这个方案能解决问题')
|
|
|
|
log('✅ Linus 三问全部通过!')
|
|
|
|
return this.createResult(true, 'Linus 三问全部通过', this.reasoning)
|
|
}
|
|
|
|
/**
|
|
* 第一问:这是现实问题还是想象问题?
|
|
*
|
|
* 拒绝条件:
|
|
* - "可能需要"、"也许将来"
|
|
* - 纯粹的假设性场景
|
|
* - "以防万一"
|
|
*/
|
|
async isRealProblem(taskDescription, context) {
|
|
log(`\n📌 第一问:${QuestionType.REAL_PROBLEM}`)
|
|
|
|
const answer = await this.evaluateQuestion(taskDescription, context, {
|
|
positiveIndicators: [
|
|
'用户反馈',
|
|
'生产问题',
|
|
'线上错误',
|
|
'性能瓶颈',
|
|
'安全漏洞',
|
|
'bug',
|
|
'错误',
|
|
'失败',
|
|
'崩溃',
|
|
'无法',
|
|
'必须',
|
|
'紧急',
|
|
'关键'
|
|
],
|
|
negativeIndicators: [
|
|
'可能需要',
|
|
'也许将来',
|
|
'以防万一',
|
|
'考虑未来',
|
|
'如果发生',
|
|
'假设',
|
|
'理论上',
|
|
'或许',
|
|
'可能'
|
|
],
|
|
analysisPrompt: `判断以下任务是否是现实问题:
|
|
"${taskDescription}"
|
|
|
|
回答 JSON:
|
|
{
|
|
"isRealProblem": true|false,
|
|
"reasoning": "判断理由",
|
|
"evidence": ["证据1", "证据2"],
|
|
"verdict": "这是现实问题/这是想象问题"
|
|
}`
|
|
})
|
|
|
|
return {
|
|
answer: answer.isRealProblem,
|
|
reasoning: answer.reasoning,
|
|
evidence: answer.evidence,
|
|
verdict: answer.verdict
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 第二问:这个问题真的需要解决吗?
|
|
*
|
|
* 拒绝条件:
|
|
* - 边缘场景
|
|
* - 伪需求
|
|
* - 性价比极低
|
|
*/
|
|
async needsSolution(taskDescription, context) {
|
|
log(`\n📌 第二问:${QuestionType.NEEDS_SOLUTION}`)
|
|
|
|
const answer = await this.evaluateQuestion(taskDescription, context, {
|
|
positiveIndicators: [
|
|
'影响用户体验',
|
|
'影响性能',
|
|
'影响安全',
|
|
'影响稳定性',
|
|
'阻塞功能',
|
|
'影响核心',
|
|
'高频',
|
|
'重要',
|
|
'必要',
|
|
'必须'
|
|
],
|
|
negativeIndicators: [
|
|
'边缘',
|
|
'小众',
|
|
'罕见',
|
|
'偶尔',
|
|
'理论上',
|
|
'可以接受',
|
|
'不是必需',
|
|
'可选项',
|
|
'优化项',
|
|
'锦上添花'
|
|
],
|
|
analysisPrompt: `判断以下问题是否真的需要解决:
|
|
"${taskDescription}"
|
|
|
|
回答 JSON:
|
|
{
|
|
"needsSolution": true|false,
|
|
"reasoning": "判断理由",
|
|
"impact": "高/中/低",
|
|
"verdict": "这个问题需要解决/这个问题不需要解决"
|
|
}`
|
|
})
|
|
|
|
return {
|
|
answer: answer.needsSolution,
|
|
reasoning: answer.reasoning,
|
|
impact: answer.impact,
|
|
verdict: answer.verdict
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 第三问:这个方案真的能解决问题吗?
|
|
*
|
|
* 拒绝条件:
|
|
* - 理论上可行但无验证
|
|
* - 缺少实施路径
|
|
* - 技术栈不匹配
|
|
*/
|
|
async solutionViable(taskDescription, context) {
|
|
log(`\n📌 第三问:${QuestionType.SOLUTION_VIABLE}`)
|
|
|
|
const answer = await this.evaluateQuestion(taskDescription, context, {
|
|
positiveIndicators: [
|
|
'明确方案',
|
|
'具体步骤',
|
|
'已有先例',
|
|
'可验证',
|
|
'可测试',
|
|
'有计划',
|
|
'有路径',
|
|
'可行'
|
|
],
|
|
negativeIndicators: [
|
|
'理论上',
|
|
'应该可以',
|
|
'可能需要',
|
|
'待研究',
|
|
'不确定',
|
|
'猜测',
|
|
'假设',
|
|
'无从验证'
|
|
],
|
|
analysisPrompt: `判断以下方案是否真的能解决问题:
|
|
"${taskDescription}"
|
|
|
|
如果有具体方案,请评估其可行性。如果没有方案,请判断是否可以制定有效方案。
|
|
|
|
回答 JSON:
|
|
{
|
|
"solutionViable": true|false,
|
|
"reasoning": "判断理由",
|
|
"hasConcretePlan": true|false,
|
|
"verdict": "这个方案能解决问题/这个方案不能解决问题"
|
|
}`
|
|
})
|
|
|
|
return {
|
|
answer: answer.solutionViable,
|
|
reasoning: answer.reasoning,
|
|
hasConcretePlan: answer.hasConcretePlan,
|
|
verdict: answer.verdict
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 评估问题(使用 Agent 进行分析)
|
|
*/
|
|
async evaluateQuestion(taskDescription, context, config) {
|
|
// 如果有上下文信息,使用它
|
|
const fullContext = context ? `上下文: ${context}\n` : ''
|
|
|
|
// 使用 Plan Agent 进行分析
|
|
try {
|
|
const analysis = await agent({
|
|
subagent_type: 'Plan',
|
|
prompt: `${fullContext}${config.analysisPrompt}`,
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
isRealProblem: { type: 'boolean' },
|
|
needsSolution: { type: 'boolean' },
|
|
solutionViable: { type: 'boolean' },
|
|
reasoning: { type: 'string' },
|
|
evidence: { type: 'array', items: { type: 'string' } },
|
|
impact: { type: 'string' },
|
|
hasConcretePlan: { type: 'boolean' },
|
|
verdict: { type: 'string' }
|
|
}
|
|
}
|
|
})
|
|
|
|
return analysis
|
|
} catch (error) {
|
|
log(`⚠️ Agent 分析失败: ${error.message}`)
|
|
// 回退到简单关键词检测
|
|
return this.fallbackEvaluation(taskDescription, config)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 回退评估(基于关键词)
|
|
*/
|
|
fallbackEvaluation(taskDescription, config) {
|
|
const text = taskDescription.toLowerCase()
|
|
const { positiveIndicators, negativeIndicators } = config
|
|
|
|
let positiveScore = 0
|
|
let negativeScore = 0
|
|
|
|
for (const indicator of positiveIndicators) {
|
|
if (text.includes(indicator.toLowerCase())) {
|
|
positiveScore++
|
|
}
|
|
}
|
|
|
|
for (const indicator of negativeIndicators) {
|
|
if (text.includes(indicator.toLowerCase())) {
|
|
negativeScore++
|
|
}
|
|
}
|
|
|
|
const answer = positiveScore > negativeScore
|
|
const reasoning = `基于关键词检测:正面指标 ${positiveScore} 个,负面指标 ${negativeScore} 个`
|
|
|
|
return {
|
|
isRealProblem: answer,
|
|
needsSolution: answer,
|
|
solutionViable: answer,
|
|
reasoning,
|
|
verdict: answer ? '通过关键词检测' : '未通过关键词检测'
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建决策结果
|
|
*/
|
|
createResult(passed, message, reasoning) {
|
|
return {
|
|
passed,
|
|
message,
|
|
reasoning: Array.isArray(reasoning) ? reasoning : [reasoning],
|
|
answers: this.answers,
|
|
timestamp: new Date().toISOString()
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 快速函数:执行 Linus 三问
|
|
*
|
|
* @param {string} taskDescription - 任务描述
|
|
* @param {Object} options - 选项
|
|
* @returns {Promise<Object>} 决策结果
|
|
*/
|
|
export async function askLinusTriad(taskDescription, options = {}) {
|
|
const decision = new LinusTriadDecision()
|
|
return await decision.ask(taskDescription, options)
|
|
}
|
|
|
|
/**
|
|
* 检查任务是否通过 Linus 三问
|
|
*
|
|
* @param {string} taskDescription - 任务描述
|
|
* @returns {Promise<boolean>} 是否通过
|
|
*/
|
|
export async function passesLinusTriad(taskDescription) {
|
|
const result = await askLinusTriad(taskDescription)
|
|
return result.passed
|
|
}
|
|
|
|
/**
|
|
* 生成拒绝响应
|
|
*
|
|
* @param {Object} decisionResult - 决策结果
|
|
* @returns {string} 拒绝消息
|
|
*/
|
|
export function generateRejectionMessage(decisionResult) {
|
|
let message = `## ❌ 任务未通过 Linus 三问决策\n\n`
|
|
message += `**原因**: ${decisionResult.message}\n\n`
|
|
message += `### 决策过程\n\n`
|
|
|
|
for (let i = 0; i < decisionResult.reasoning.length; i++) {
|
|
message += `**${i + 1}. ${decisionResult.reasoning[i]}**\n\n`
|
|
}
|
|
|
|
message += `### 建议\n\n`
|
|
message += `- 请重新审视任务需求\n`
|
|
message += `- 确保这是需要解决的现实问题\n`
|
|
message += `- 提供明确的解决方案\n`
|
|
message += `- 如有疑问,请使用 deep-interview 进行需求澄清\n\n`
|
|
|
|
message += `---\n`
|
|
message += `**决策时间**: ${decisionResult.timestamp}\n`
|
|
|
|
return message
|
|
}
|
|
|
|
/**
|
|
* 辅助函数:日志输出
|
|
*/
|
|
function log(message) {
|
|
console.log(`[LinusTriad] ${message}`)
|
|
}
|
|
|
|
/**
|
|
* 导出
|
|
*/
|
|
export default {
|
|
LinusTriadDecision,
|
|
askLinusTriad,
|
|
passesLinusTriad,
|
|
generateRejectionMessage,
|
|
QuestionType
|
|
}
|