diff --git a/config/ai.json b/config/ai.json index 8f8139a..a727525 100644 --- a/config/ai.json +++ b/config/ai.json @@ -73,28 +73,18 @@ "surprise" ] }, - "?useReAct": "是否启用ReAct工具调用模式(需要模型支持function calling)", - "useReAct": false, - "?reactConfig": "ReAct配置", + "?useReAct": "是否启用真正的ReAct模式(基于标准Function Calling,需要模型支持)", + "useReAct": true, + "?reactConfig": "真正的ReAct配置(基于标准Function Calling)", "reactConfig": { - "?maxIterations": "最大思考迭代次数", + "?maxIterations": "最大工具调用轮数(AI自主控制)", "maxIterations": 8, - "?timeout": "ReAct超时时间(毫秒)", + "?timeout": "整个对话超时时间(毫秒)", "timeout": 45000, - "?enableThinking": "是否显示思考过程", + "?enableThinking": "是否记录工具执行历史(调试用)", "enableThinking": false, - "?toolTimeout": "单个工具执行超时时间(毫秒)", - "toolTimeout": 10000, - "?minConfidence": "最小信心度阈值(0-1),低于此值会继续收集信息", - "minConfidence": 0.7, - "?contextMemoryLimit": "上下文记忆数量限制", - "contextMemoryLimit": 5, - "?enableContextHistory": "是否在迭代中包含聊天历史", - "enableContextHistory": true, - "?maxParallelTools": "单次最大并行工具调用数量", - "maxParallelTools": 5, - "?enableToolCombinations": "是否启用工具组合建议", - "enableToolCombinations": true + "?memoryLimit": "自动搜索的记忆数量限制", + "memoryLimit": 5 }, "?imageConfig": "图像生成配置", "imageConfig": { diff --git a/lib/ai/aiCaller.js b/lib/ai/aiCaller.js index f1f9c2a..acf7075 100644 --- a/lib/ai/aiCaller.js +++ b/lib/ai/aiCaller.js @@ -379,7 +379,7 @@ class AiCaller { } /** - * ReAct模式AI调用 + * 真正的ReAct模式AI调用 - 基于标准Function Calling * @param prompt 用户输入 * @param chatHistory 聊天历史 * @param memories 记忆 @@ -401,7 +401,7 @@ class AiCaller { imageMessages }; - // 执行ReAct循环 + // 执行真正的ReAct循环 - 单次AI调用,AI自主控制流程 const result = await ReactEngine.execute(prompt, context); if (result.success) { @@ -409,9 +409,10 @@ class AiCaller { success: true, response: result.responses, rawResponse: JSON.stringify(result.responses), - thinkingSteps: result.thinkingSteps, + toolExecutionHistory: result.toolExecutionHistory, iterations: result.iterations, - duration: result.duration + duration: result.duration, + messageHistory: result.messageHistory }; } else { return { @@ -421,7 +422,7 @@ class AiCaller { }; } } catch (error) { - logger.error(`[crystelf-ai] ReAct模式调用失败: ${error.message}`); + logger.error(`[crystelf-ai] 真正的ReAct模式调用失败: ${error.message}`); return { success: false, error: error.message diff --git a/lib/ai/contextBuilder.js b/lib/ai/contextBuilder.js deleted file mode 100644 index c516b8e..0000000 --- a/lib/ai/contextBuilder.js +++ /dev/null @@ -1,256 +0,0 @@ -import ConfigControl from '../config/configControl.js'; -import { getSystemPrompt } from '../../constants/ai/prompts.js'; - -/** - * ReAct上下文构建器 - * 为每次迭代构建丰富的上下文信息 - */ -class ContextBuilder { - constructor() { - this.baseContext = null; - } - - /** - * 构建基础上下文(只在第一次构建) - * @param {Object} e - 事件对象 - * @param {Array} memories - 记忆数组 - * @returns {Promise} 基础上下文 - */ - async buildBaseContext(e, memories = []) { - if (this.baseContext) { - return this.baseContext; - } - - const config = await ConfigControl.get(); - const botInfo = { - id: e.bot?.uin || '未知', - name: config?.profile?.nickName || '晶灵', - }; - - const userInfo = { - id: e.user_id || e.sender?.user_id || '未知', - name: e.sender?.card || e.sender?.nickname || '用户', - isMaster: e.isMaster, - }; - - const now = Date.now(); - const date = new Date(now); - const formatDate = date.toLocaleDateString('zh-CN'); - const formatTime = date.toLocaleTimeString('zh-CN'); - - // 获取群聊历史 - const aiConfig = await ConfigControl.get('ai'); - const historyLen = aiConfig?.getChatHistoryLength || 10; - const maxMessageLength = aiConfig?.maxMessageLength || 100; - - let groupChatHistory = ''; - try { - const history = await e.group.getChatHistory(e.message_id, historyLen); - if (history && history.length > 0) { - groupChatHistory = '\n[群聊聊天记录(从旧到新)]\n'; - for (const message of history) { - const msgArr = message.message; - for (const msg of msgArr) { - if (msg.type === 'text') { - let displayText = msg.text; - if (msg.text && msg.text.length > maxMessageLength) { - const omittedChars = msg.text.length - maxMessageLength; - displayText = msg.text.substring(0, maxMessageLength) + `...(省略${omittedChars}字)`; - } - groupChatHistory += `[${message.sender.user_id == e.bot.uin ? '你' : message.sender?.nickname},id:${message.sender?.user_id},seq:${message.message_id}]之前说过:${displayText}\n`; - } - if (msg.type === 'at') { - if (msg.qq == e.bot.uin) { - groupChatHistory += `[${message.sender?.nickname},id:${message.sender?.user_id},seq:${message.message_id}]之前@了你\n`; - } else { - const atNickname = await e.group.pickMember(msg.qq).nickname || '一个人'; - groupChatHistory += `[${message.sender.user_id == e.bot.uin ? '你' : message.sender?.nickname},id:${message.sender?.user_id},seq:${message.message_id}]之前@了${atNickname},id是${msg.qq}\n`; - } - } - if (msg.type === 'image') { - groupChatHistory += `[${message.sender?.nickname},id:${message.sender?.user_id},seq:${message.message_id}]之前发送了一张图片(你可能暂时无法查看)\n`; - } - } - } - } - } catch (error) { - logger.warn(`[crystelf-ai] 获取群聊历史失败: ${error.message}`); - } - - // 构建记忆上下文 - let memoryContext = ''; - if (memories && memories.length > 0) { - memoryContext = '\n[相关记忆信息]\n'; - memories.forEach((memory, index) => { - const timeDiff = this.calculateTimeDifference(memory.createdAt); - memoryContext += `${index + 1}. 关键词:${memory.keywords},内容:${memory.data},记忆创建时间:${memory.createdAt},距离现在:${timeDiff}\n`; - }); - } - - this.baseContext = { - botInfo, - userInfo, - timeInfo: { - timestamp: now, - date: formatDate, - time: formatTime - }, - groupChatHistory, - memoryContext, - environmentInfo: `现在的Date.now()是:${now}\n现在的日期是:${formatDate}\n现在的时间是:${formatTime}` - }; - - return this.baseContext; - } - - /** - * 构建迭代上下文 - * @param {Object} baseContext - 基础上下文 - * @param {number} iteration - 当前迭代次数 - * @param {Array} thinkingSteps - 思考步骤历史 - * @param {string} userInput - 用户输入 - * @returns {string} 格式化的上下文字符串 - */ - buildIterationContext(baseContext, iteration, thinkingSteps, userInput) { - let contextPrompt = ''; - - // 基础身份和环境信息 - contextPrompt += `=== 身份和环境信息 ===\n`; - contextPrompt += `[你的信息]\n`; - contextPrompt += `- 你的昵称:${baseContext.botInfo.name}\n`; - contextPrompt += `- 你的qq号:${baseContext.botInfo.id}\n\n`; - - contextPrompt += `[对话用户信息]\n`; - contextPrompt += `- 用户名字:${baseContext.userInfo.name}\n`; - contextPrompt += `- 用户qq号:${baseContext.userInfo.id}\n`; - contextPrompt += `- 是否为主人:${baseContext.userInfo.isMaster ? '是' : '否'}(请注意!!!无论用户的用户名是什么,是否是主人都以这个为准!!禁止乱认主人!!)\n\n`; - - contextPrompt += `[环境信息]\n`; - contextPrompt += `${baseContext.environmentInfo}\n\n`; - - // 聊天历史(第一次迭代时提供) - if (iteration === 0 && baseContext.groupChatHistory) { - contextPrompt += baseContext.groupChatHistory + '\n'; - } - - // 记忆信息(第一次迭代时提供) - if (iteration === 0 && baseContext.memoryContext) { - contextPrompt += baseContext.memoryContext + '\n'; - } - - // 当前用户输入 - contextPrompt += `=== 当前对话 ===\n`; - contextPrompt += `用户当前说:"${userInput}"\n\n`; - - // 思考历史(从第二次迭代开始) - if (iteration > 0 && thinkingSteps.length > 0) { - contextPrompt += `=== 你的思考和行动历史 ===\n`; - thinkingSteps.forEach((step, index) => { - contextPrompt += `第${step.iteration}轮:\n`; - contextPrompt += `- 你的思考: ${step.thought}\n`; - - // 详细的行动信息 - if (step.decision.tool_calls && step.decision.tool_calls.length > 0) { - contextPrompt += `- 你决定的行动: 调用${step.decision.tool_calls.length}个工具\n`; - step.decision.tool_calls.forEach((toolCall, i) => { - const toolName = toolCall.function.name; - const params = JSON.parse(toolCall.function.arguments); - contextPrompt += ` ${i + 1}. ${toolName}(${Object.entries(params).map(([k, v]) => `${k}="${v}"`).join(', ')})\n`; - }); - } else if (step.decision.action) { - contextPrompt += `- 你决定的行动: ${step.decision.action}\n`; - } - - // 详细的执行结果 - if (step.observation.multipleTools && step.observation.toolResults) { - contextPrompt += `- 执行结果:\n`; - step.observation.toolResults.forEach((toolResult, i) => { - const status = toolResult.success ? '✓' : '✗'; - contextPrompt += ` ${status} ${toolResult.toolName}: ${toolResult.result.message || toolResult.result.result || '完成'}\n`; - }); - } else { - contextPrompt += `- 执行结果: ${step.observation.message || step.observation.result || '无结果'}\n`; - } - - contextPrompt += `\n`; - }); - } - - // 当前迭代信息 - contextPrompt += `=== 当前状态 ===\n`; - contextPrompt += `这是第${iteration + 1}轮思考\n`; - if (iteration === 0) { - contextPrompt += `这是第一轮,请仔细分析用户需求,确定是否需要收集更多信息\n`; - } else { - contextPrompt += `基于前面的思考和行动结果,请决定下一步\n`; - } - - return contextPrompt; - } - - /** - * 构建人格提示词 - * @returns {Promise} 人格提示词 - */ - async buildPersonalityPrompt() { - try { - const basePrompt = await getSystemPrompt(); - - // 简化版人格提示词,专注于ReAct模式 - const reactPersonality = `你是一个名为晶灵的智能助手,具有以下特征: -1. 性格温和友善,喜欢帮助用户解决问题 -2. 知识渊博,能够回答各种问题 -3. 偶尔会使用一些可爱的表情和语气 -4. 会记住与用户的对话内容,提供个性化的回复 -5. 能够理解中文语境和网络用语 -6. 回复简洁明了,避免过于冗长 - -在ReAct模式下,你需要: -- 仔细思考用户的真实需求 -- 主动使用工具收集必要信息 -- 基于收集的信息给出准确回答 -- 当信息足够时使用find_answer工具结束 -- 当需要更多信息时使用need_more_info工具继续`; - - return reactPersonality; - } catch (error) { - logger.error(`[crystelf-ai] 构建人格提示词失败: ${error.message}`); - return '你是一个友善的智能助手,请帮助用户解决问题。'; - } - } - - /** - * 计算时间差 - * @param {number} pastTime - 过去时间戳 - * @returns {string} 时间差字符串 - */ - calculateTimeDifference(pastTime) { - const now = Date.now(); - const diff = now - pastTime; - - const days = Math.floor(diff / (1000 * 60 * 60 * 24)); - const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); - - let result = ''; - if (days > 0) { - result += `${days}天`; - } - if (hours > 0) { - result += `${hours}小时`; - } - if (minutes > 0) { - result += `${minutes}分钟`; - } - return result || '刚刚'; - } - - /** - * 重置上下文(新对话时调用) - */ - reset() { - this.baseContext = null; - } -} - -export default new ContextBuilder(); \ No newline at end of file diff --git a/lib/ai/reactEngine.js b/lib/ai/reactEngine.js index 69103be..6948aac 100644 --- a/lib/ai/reactEngine.js +++ b/lib/ai/reactEngine.js @@ -1,9 +1,6 @@ import ConfigControl from '../config/configControl.js'; import toolRegistry from './tools/toolRegistry.js'; -import AiCaller from './aiCaller.js'; -import ContextBuilder from './contextBuilder.js'; -import MemorySystem from './memorySystem.js'; -import ToolCombinations from './tools/toolCombinations.js'; +import OpenaiChat from '../../modules/openai/openaiChat.js'; /** * ReAct引擎 @@ -11,9 +8,8 @@ import ToolCombinations from './tools/toolCombinations.js'; */ class ReactEngine { constructor() { - this.maxIterations = 5; - this.timeout = 30000; - this.toolTimeout = 10000; + this.maxIterations = 8; + this.timeout = 45000; this.enableThinking = false; } @@ -22,9 +18,8 @@ class ReactEngine { const config = await ConfigControl.get('ai'); const reactConfig = config?.reactConfig || {}; - this.maxIterations = reactConfig.maxIterations || 5; - this.timeout = reactConfig.timeout || 30000; - this.toolTimeout = reactConfig.toolTimeout || 10000; + this.maxIterations = reactConfig.maxIterations || 8; + this.timeout = reactConfig.timeout || 45000; this.enableThinking = reactConfig.enableThinking || false; logger.info('[crystelf-ai] ReAct引擎初始化完成'); @@ -34,7 +29,7 @@ class ReactEngine { } /** - * 执行ReAct循环 + * 执行标准ReAct循环 * @param {string} userInput - 用户输入 * @param {Object} context - 执行上下文 * @returns {Promise} 执行结果 @@ -42,108 +37,50 @@ class ReactEngine { async execute(userInput, context) { const startTime = Date.now(); const responseQueue = []; - const thinkingSteps = []; + const thinkingHistory = []; - // 扩展上下文 - const executionContext = { - ...context, - responseQueue, - startTime, - userInput - }; - try { - // 构建基础上下文(包含记忆搜索) - const memories = await MemorySystem.searchMemories(context.e.user_id, userInput, 5); - const baseContext = await ContextBuilder.buildBaseContext(context.e, memories); + logger.info(`[crystelf-ai] 开始标准ReAct循环,用户输入: ${userInput.substring(0, 50)}...`); - let shouldContinue = true; - let iteration = 0; + // 第一阶段:思考和信息收集 + const phase1Result = await this.executePhase1_ThinkingAndCollection(userInput, context, thinkingHistory); - while (shouldContinue && iteration < this.maxIterations) { - // 检查超时 - if (Date.now() - startTime > this.timeout) { - logger.warn(`[crystelf-ai] ReAct超时,已迭代 ${iteration} 次`); - break; - } - - // 构建当前迭代的上下文 - const iterationContext = ContextBuilder.buildIterationContext( - baseContext, - iteration, - thinkingSteps, - userInput - ); - - // 思考阶段 - const thought = await this.think(iterationContext, iteration); - - // 决策阶段 - const decision = await this.decide(thought, iterationContext, iteration); - - // 行动阶段 - const observation = await this.act(decision, executionContext); - - // 记录思考步骤 - const step = { - iteration: iteration + 1, - thought, - decision, - observation, - timestamp: Date.now(), - // 新增:AI的推理过程和工具调用详情 - reasoning: decision.reasoning || thought, - toolsUsed: observation.multipleTools ? - observation.toolResults?.map(tr => tr.toolName) || [] : - [decision.action || decision.tool_calls?.[0]?.function?.name].filter(Boolean), - executionTime: observation.duration || 0, - success: observation.success !== false + if (!phase1Result.success) { + return { + success: false, + error: phase1Result.error, + responses: [{ + type: 'message', + data: '抱歉,我在分析您的问题时遇到了困难...', + at: -1, + quote: -1, + recall: false + }], + thinkingHistory: this.enableThinking ? thinkingHistory : [] }; - thinkingSteps.push(step); - - // 检查是否应该结束循环 - if (observation.shouldEnd === true) { - logger.info(`[crystelf-ai] AI决定结束循环,第${iteration + 1}轮完成`); - shouldContinue = false; - } else if (observation.shouldEnd === false) { - logger.info(`[crystelf-ai] AI决定继续收集信息,进入第${iteration + 2}轮`); - shouldContinue = true; - } - - iteration++; } - // 如果循环结束但没有响应,添加默认响应 - if (responseQueue.length === 0) { - responseQueue.push({ - type: 'message', - data: iteration >= this.maxIterations ? - '我已经尽力思考了,但可能需要更多信息才能给出完美的回答...' : - '让我来帮助您解决这个问题。', - at: -1, - quote: -1, - recall: false - }); - } - - // 重置上下文构建器 - ContextBuilder.reset(); + // 第二阶段:基于收集的信息生成回复 + const phase2Result = await this.executePhase2_ResponseGeneration( + userInput, + context, + phase1Result.collectedInfo, + phase1Result.conversationMessages, + responseQueue + ); return { success: true, responses: responseQueue, - thinkingSteps: this.enableThinking ? thinkingSteps : [], - iterations: iteration, + thinkingHistory: this.enableThinking ? thinkingHistory : [], + collectedInfo: phase1Result.collectedInfo, + conversationMessages: this.enableThinking ? phase1Result.conversationMessages : [], duration: Date.now() - startTime }; } catch (error) { logger.error(`[crystelf-ai] ReAct执行失败: ${error.message}`); - // 重置上下文构建器 - ContextBuilder.reset(); - - // 返回错误响应 return { success: false, error: error.message, @@ -154,225 +91,484 @@ class ReactEngine { quote: -1, recall: false }], - thinkingSteps: this.enableThinking ? thinkingSteps : [] + thinkingHistory: this.enableThinking ? thinkingHistory : [] }; } } /** - * 思考阶段 + * 第一阶段:思考和信息收集 + * 只包含信息收集工具,不包含回复工具和人设 */ - async think(iterationContext, iteration) { - const personalityPrompt = await ContextBuilder.buildPersonalityPrompt(); + async executePhase1_ThinkingAndCollection(userInput, context, thinkingHistory) { + const startTime = Date.now(); - const thinkingPrompt = `${personalityPrompt} - -${iterationContext} - -=== 思考任务 === -请仔细分析当前情况,思考: -1. 用户的真实需求是什么? -2. 我现在掌握了哪些信息? -3. 还缺少什么关键信息? -4. 下一步应该采取什么行动? - -请简洁明了地描述你的思考过程。`; - - try { - const response = await this.callAI(thinkingPrompt, {}); - return response || '继续分析用户需求'; - } catch (error) { - logger.error(`[crystelf-ai] 思考阶段失败: ${error.message}`); - return '继续分析用户需求'; - } - } - - /** - * 决策阶段 - */ - async decide(thought, iterationContext, iteration) { - const toolSchemas = toolRegistry.getToolSchemas(); - const personalityPrompt = await ContextBuilder.buildPersonalityPrompt(); + // 构建第一阶段的消息历史 + const conversationMessages = await this.buildPhase1Messages(userInput, context); - const systemPrompt = `${personalityPrompt} + // 获取信息收集工具(不包含回复工具) + const collectionTools = this.getCollectionTools(); + + logger.info(`[crystelf-ai] 第一阶段开始 - 思考和信息收集`); + + let foundAnswer = false; + let collectedInfo = ''; + + // 🔥 物理循环:for 循环提供执行框架 + for (let iteration = 0; iteration < this.maxIterations; iteration++) { + // 检查超时 + if (Date.now() - startTime > this.timeout) { + logger.warn(`[crystelf-ai] 第一阶段超时,已迭代 ${iteration} 次`); + break; + } -${iterationContext} - -=== 决策指南 === -基于你的思考:"${thought}" - -你现在需要决定下一步行动。可用工具: -${JSON.stringify(toolSchemas, null, 2)} - -重要规则: -1. 你可以同时调用多个工具来提高效率,例如同时搜索记忆和获取聊天历史 -2. 如果你已经有足够信息回答用户,使用 find_answer 工具表示准备结束 -3. 如果需要更多信息,可以先调用 need_more_info 说明需求,然后调用相应的信息收集工具 -4. 使用具体的工具来收集信息(如 search_memory, get_chat_history 等) -5. 使用 send_message 等工具来回复用户 -6. 优先考虑用户的实际需求,不要过度收集信息 -7. 合理利用并行工具调用,但避免调用冲突的工具 - -${ToolCombinations.getAllCombinationsDescription()} - -请调用最合适的工具(可以是多个)。记住: -- 优先使用推荐的工具组合来提高效率 -- 可以根据具体情况调整组合中的参数 -- 避免调用冲突的工具(如同时使用find_answer和need_more_info)`; - - const messages = [ - { role: 'system', content: systemPrompt }, - { role: 'user', content: '请根据当前思考决定下一步行动。' } - ]; - - try { - // 调用支持工具调用的AI - const response = await this.callAIWithTools(messages, toolSchemas, {}); - return response; - } catch (error) { - logger.error(`[crystelf-ai] 决策阶段失败: ${error.message}`); - return { - action: 'send_message', - parameters: { - content: '我在思考过程中遇到了问题,请稍后再试。' - } - }; - } - } - - /** - * 行动阶段 - 支持多工具并行调用 - */ - async act(decision, context) { - try { - if (decision.tool_calls && decision.tool_calls.length > 0) { - // 处理多个工具调用 - const toolResults = []; - const toolPromises = []; + logger.info(`[crystelf-ai] 第一阶段第${iteration + 1}轮:AI思考和决策`); + + try { + // 🔥 每轮都是独立的 AI 调用 + const aiResponse = await this.callAIWithTools(conversationMessages, collectionTools); - logger.info(`[crystelf-ai] 准备并行执行 ${decision.tool_calls.length} 个工具`); + // 将AI的回复添加到对话历史 + conversationMessages.push(aiResponse); - // 并行执行所有工具调用 - for (const toolCall of decision.tool_calls) { - const toolName = toolCall.function.name; - const parameters = JSON.parse(toolCall.function.arguments); + // 🔥 AI 可以做出不同决策 + if (aiResponse.tool_calls && aiResponse.tool_calls.length > 0) { + // 决策1:调用工具继续探索 + logger.info(`[crystelf-ai] AI决定调用 ${aiResponse.tool_calls.length} 个工具`); - logger.info(`[crystelf-ai] 调用工具: ${toolName}, 参数: ${JSON.stringify(parameters)}`); + // 并行执行所有工具 + const toolResults = await this.executeToolsParallel( + aiResponse.tool_calls, + conversationMessages, + context + ); - const toolPromise = toolRegistry.executeTool(toolName, parameters, context) - .then(result => ({ - toolName, - parameters, - result, - toolCallId: toolCall.id - })) - .catch(error => ({ - toolName, - parameters, - result: { - success: false, - message: `工具执行失败: ${error.message}` - }, - toolCallId: toolCall.id, - error: error.message - })); - - toolPromises.push(toolPromise); - } - - // 等待所有工具执行完成 - const results = await Promise.all(toolPromises); - - // 整合结果 - let shouldEnd = null; - let hasError = false; - const messages = []; - - for (const { toolName, parameters, result, toolCallId, error } of results) { - toolResults.push({ - toolName, - parameters, - result, - toolCallId, - success: !error + // 记录思考步骤 + thinkingHistory.push({ + phase: 1, + iteration: iteration + 1, + aiThought: aiResponse.content || '进行工具调用', + toolCalls: aiResponse.tool_calls, + toolResults: toolResults, + timestamp: Date.now() }); - if (error) { - hasError = true; - messages.push(`工具 ${toolName} 执行失败: ${error}`); - } else { - messages.push(`工具 ${toolName} 执行成功: ${result.message || result.result || '完成'}`); - - // 检查循环控制 - if (result.shouldEnd !== undefined) { - shouldEnd = result.shouldEnd; + // 检查AI是否通过工具调用标记找到答案 + const answerResult = toolResults.find(result => + result.toolName === 'found_answer' || result.toolName === 'not_enough_info' + ); + + if (answerResult) { + if (answerResult.toolName === 'found_answer') { + // 决策2:找到答案,标记找到答案,跳出循环到答案回复 + foundAnswer = true; + collectedInfo = answerResult.result.answerSummary || ''; + logger.info(`[crystelf-ai] AI找到答案,跳出循环进入第二阶段`); + break; // 🔥 跳出物理循环 + } else { + // AI明确表示信息不足,结束收集 + logger.info(`[crystelf-ai] AI认为信息不足,结束收集阶段`); + return { + success: false, + error: `信息收集失败: ${answerResult.result.reason}`, + collectedInfo: '', + conversationMessages + }; } } + + } else { + // 决策3:继续思考,下一轮再决策 + logger.info(`[crystelf-ai] AI进行纯思考: ${aiResponse.content?.substring(0, 100)}...`); + + thinkingHistory.push({ + phase: 1, + iteration: iteration + 1, + aiThought: aiResponse.content || '继续思考', + toolCalls: [], + toolResults: [], + timestamp: Date.now() + }); + + // continue 到下一轮循环 } - return { - success: !hasError, - message: messages.join('\n'), - toolResults, - shouldEnd, - multipleTools: true, - toolCount: decision.tool_calls.length - }; - - } else if (decision.action) { - // 处理单个直接行动 - const result = await toolRegistry.executeTool(decision.action, decision.parameters, context); - return { - ...result, - multipleTools: false, - toolCount: 1 - }; + } catch (error) { + logger.error(`[crystelf-ai] 第一阶段第${iteration + 1}轮失败: ${error.message}`); + break; + } + } + + // 如果循环结束仍未找到答案,进行最终评估 + if (!foundAnswer) { + logger.info(`[crystelf-ai] 达到最大迭代次数,进行最终评估`); + + const finalEvaluation = await this.performFinalEvaluation(conversationMessages, collectionTools); + + if (finalEvaluation.foundAnswer) { + foundAnswer = true; + collectedInfo = finalEvaluation.answerSummary; } else { return { success: false, - message: '未识别的决策格式', - multipleTools: false, - toolCount: 0 + error: `经过${this.maxIterations}轮思考仍未找到足够信息`, + collectedInfo: '', + conversationMessages }; } + } + + return { + success: foundAnswer, + collectedInfo, + conversationMessages, + iterations: this.maxIterations + }; + } + + /** + * 第二阶段:基于收集的信息生成回复 + * 包含人设和回复工具,基于第一阶段的思考结果 + */ + async executePhase2_ResponseGeneration(userInput, context, collectedInfo, phase1Messages, responseQueue) { + logger.info(`[crystelf-ai] 第二阶段开始 - 基于收集信息生成回复`); + + // 构建第二阶段的消息历史(包含人设和第一阶段结果) + const phase2Messages = await this.buildPhase2Messages(userInput, context, collectedInfo, phase1Messages); + + // 获取回复工具(包含所有回复相关工具) + const responseTools = this.getResponseTools(); + + try { + // AI基于收集的信息生成回复 + const aiResponse = await this.callAIWithTools(phase2Messages, responseTools); + + if (aiResponse.tool_calls && aiResponse.tool_calls.length > 0) { + // AI调用回复工具 + logger.info(`[crystelf-ai] AI调用 ${aiResponse.tool_calls.length} 个回复工具`); + + await this.executeResponseTools(aiResponse.tool_calls, responseQueue, context); + + } else if (aiResponse.content) { + // AI直接给出文本回复 + responseQueue.push({ + type: 'message', + data: aiResponse.content, + at: -1, + quote: -1, + recall: false + }); + } + + return { success: true }; + } catch (error) { - logger.error(`[crystelf-ai] 行动阶段失败: ${error.message}`); - return { - success: false, - message: `执行行动失败: ${error.message}`, - multipleTools: false, - toolCount: 0 - }; + logger.error(`[crystelf-ai] 第二阶段失败: ${error.message}`); + + // 添加默认回复 + responseQueue.push({ + type: 'message', + data: '我已经收集了相关信息,但在生成回复时遇到了问题...', + at: -1, + quote: -1, + recall: false + }); + + return { success: false, error: error.message }; } } /** - * 调用AI(文本模式) + * 构建第一阶段消息(思考阶段,不包含人设) */ - async callAI(prompt, context) { - // 创建临时的事件对象用于AI调用 - const tempE = { - user_id: 'react_system', - bot: { uin: 'system' }, - group_id: 'system' + async buildPhase1Messages(userInput, context) { + const systemPrompt = `你是一个信息分析专家,需要分析用户的问题并收集相关信息。 + +=== 分析任务 === +用户问题:"${userInput}" + +请分析: +1. 用户想要什么信息? +2. 需要搜索哪些相关内容? +3. 应该使用什么工具来收集信息? + +=== 可用工具 === +- search_memory: 搜索用户的历史记忆和偏好 +- get_chat_history: 获取最近的聊天记录 +- found_answer: 当收集到足够信息时标记找到答案 +- not_enough_info: 当认为信息不足时标记 + +=== 重要规则 === +1. 可以同时调用多个工具来并行收集信息 +2. 仔细分析每个工具的结果 +3. 当有足够信息回答用户问题时,调用found_answer +4. 如果多次尝试仍无法找到足够信息,调用not_enough_info +5. 专注于信息收集,不要尝试直接回答用户 + +请开始分析用户问题并收集相关信息。`; + + return [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: `请分析这个问题并收集相关信息:"${userInput}"` } + ]; + } + + /** + * 构建第二阶段消息(回复阶段,包含人设和第一阶段结果) + */ + async buildPhase2Messages(userInput, context, collectedInfo, phase1Messages) { + const { e } = context; + const config = await ConfigControl.get(); + + const botInfo = { + id: e.bot?.uin || '未知', + name: config?.profile?.nickName || '晶灵', }; + + const userInfo = { + id: e.user_id || e.sender?.user_id || '未知', + name: e.sender?.card || e.sender?.nickname || '用户', + isMaster: e.isMaster, + }; + + const now = Date.now(); + const date = new Date(now); + const formatDate = date.toLocaleDateString('zh-CN'); + const formatTime = date.toLocaleTimeString('zh-CN'); + + // 提取第一阶段的思考过程摘要 + const thinkingProcess = this.extractThinkingProcess(phase1Messages); + + const systemPrompt = `你是一个名为${botInfo.name}的智能助手,具有以下特征: +1. 性格温和友善,喜欢帮助用户解决问题 +2. 知识渊博,能够回答各种问题 +3. 偶尔会使用一些可爱的表情和语气 +4. 会记住与用户的对话内容,提供个性化的回复 +5. 能够理解中文语境和网络用语 +6. 回复简洁明了,避免过于冗长 + +=== 当前对话信息 === +- 你的昵称:${botInfo.name} +- 你的QQ号:${botInfo.id} +- 用户昵称:${userInfo.name} +- 用户QQ号:${userInfo.id} +- 用户是否为主人:${userInfo.isMaster ? '是' : '否'} +- 当前时间:${formatDate} ${formatTime} + +=== 用户问题 === +"${userInput}" + +=== 已收集的信息 === +${collectedInfo} + +=== 思考过程摘要 === +${thinkingProcess} + +=== 回复指南 === +基于以上收集的信息,请给用户一个准确、友好的回复。你可以使用以下工具: +- send_message: 发送文本消息(支持@用户和引用消息) +- send_meme: 发送表情包 +- render_code: 渲染代码为图片 +- render_markdown: 渲染Markdown为图片 +- generate_image: 生成图片 +- store_memory: 存储重要信息 +- poke_user: 戳一戳用户 + +请根据收集的信息给出最合适的回复。`; + + return [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: `请基于收集的信息回复用户的问题:"${userInput}"` } + ]; + } + + /** + * 获取信息收集工具(第一阶段使用) + */ + getCollectionTools() { + const allTools = toolRegistry.getToolSchemas(); + const collectionToolNames = [ + 'search_memory', + 'get_chat_history', + 'found_answer', + 'not_enough_info' + ]; - const result = await AiCaller.callTextAi(prompt, [], [], tempE); + return allTools.filter(tool => + collectionToolNames.includes(tool.function.name) + ); + } + + /** + * 获取回复工具(第二阶段使用) + */ + getResponseTools() { + const allTools = toolRegistry.getToolSchemas(); + const responseToolNames = [ + 'send_message', + 'send_meme', + 'render_code', + 'render_markdown', + 'generate_image', + 'store_memory', + 'poke_user' + ]; - if (result.success) { - return result.response; - } else { - throw new Error(result.error || 'AI调用失败'); + return allTools.filter(tool => + responseToolNames.includes(tool.function.name) + ); + } + + /** + * 并行执行工具 + */ + async executeToolsParallel(toolCalls, conversationMessages, context) { + const toolPromises = toolCalls.map(async (toolCall) => { + const toolName = toolCall.function.name; + const parameters = JSON.parse(toolCall.function.arguments); + + logger.info(`[crystelf-ai] 执行工具: ${toolName}(${JSON.stringify(parameters)})`); + + try { + const result = await toolRegistry.executeTool(toolName, parameters, context); + + // 将工具结果添加到对话历史 + conversationMessages.push({ + role: 'tool', + tool_call_id: toolCall.id, + content: JSON.stringify({ + success: result.success, + message: result.message || result.result, + data: result + }) + }); + + return { + toolName, + parameters, + result, + success: result.success !== false, + toolCallId: toolCall.id + }; + + } catch (error) { + logger.error(`[crystelf-ai] 工具执行失败: ${toolName} - ${error.message}`); + + conversationMessages.push({ + role: 'tool', + tool_call_id: toolCall.id, + content: JSON.stringify({ + success: false, + error: error.message + }) + }); + + return { + toolName, + parameters, + result: { success: false, message: error.message }, + success: false, + toolCallId: toolCall.id, + error: error.message + }; + } + }); + + return await Promise.all(toolPromises); + } + + /** + * 执行回复工具 + */ + async executeResponseTools(toolCalls, responseQueue, context) { + for (const toolCall of toolCalls) { + const toolName = toolCall.function.name; + const parameters = JSON.parse(toolCall.function.arguments); + + try { + const result = await toolRegistry.executeTool(toolName, parameters, { + ...context, + responseQueue + }); + + logger.info(`[crystelf-ai] 回复工具执行成功: ${toolName}`); + + } catch (error) { + logger.error(`[crystelf-ai] 回复工具执行失败: ${toolName} - ${error.message}`); + } } } + /** + * 最终评估(当达到最大迭代次数时) + */ + async performFinalEvaluation(conversationMessages, collectionTools) { + logger.info(`[crystelf-ai] 执行最终评估`); + + // 添加最终评估提示 + conversationMessages.push({ + role: 'user', + content: '已达到最大搜索次数,请基于目前收集的所有信息做最终判断:是否有足够信息回答用户问题?请调用found_answer或not_enough_info工具。' + }); + + try { + const aiResponse = await this.callAIWithTools(conversationMessages, collectionTools); + + if (aiResponse.tool_calls && aiResponse.tool_calls.length > 0) { + const finalTool = aiResponse.tool_calls[0]; + const toolName = finalTool.function.name; + const parameters = JSON.parse(finalTool.function.arguments); + + if (toolName === 'found_answer') { + return { + foundAnswer: true, + answerSummary: parameters.answer_summary || '基于收集的信息可以回答' + }; + } + } + + return { foundAnswer: false }; + + } catch (error) { + logger.error(`[crystelf-ai] 最终评估失败: ${error.message}`); + return { foundAnswer: false }; + } + } + + /** + * 提取思考过程摘要 + */ + extractThinkingProcess(phase1Messages) { + const thinkingSteps = []; + + for (let i = 0; i < phase1Messages.length; i++) { + const message = phase1Messages[i]; + + if (message.role === 'assistant' && message.tool_calls) { + const toolNames = message.tool_calls.map(tc => tc.function.name).join(', '); + thinkingSteps.push(`调用了工具: ${toolNames}`); + } else if (message.role === 'tool') { + try { + const toolResult = JSON.parse(message.content); + if (toolResult.success) { + thinkingSteps.push(`获得结果: ${toolResult.message}`); + } + } catch (e) { + // 忽略解析错误 + } + } + } + + return thinkingSteps.length > 0 ? thinkingSteps.join('\n') : '进行了信息收集和分析'; + } + /** * 调用AI(工具调用模式) */ - async callAIWithTools(messages, tools, context) { - // 使用系统配置调用AI + async callAIWithTools(messages, tools) { const config = await ConfigControl.get('ai'); - const apiCaller = AiCaller.getUserOpenaiInstance('system', config); + const apiCaller = new OpenaiChat(); + apiCaller.init(config.apiKey, config.baseApi); try { const completion = await apiCaller.openai.chat.completions.create({ @@ -381,30 +577,21 @@ ${ToolCombinations.getAllCombinationsDescription()} tools: tools, tool_choice: 'auto', temperature: config.temperature || 0.7, - parallel_tool_calls: true // 启用并行工具调用 + parallel_tool_calls: true }); const message = completion.choices[0].message; if (message.tool_calls && message.tool_calls.length > 0) { - logger.info(`[crystelf-ai] AI决定调用 ${message.tool_calls.length} 个工具: ${message.tool_calls.map(tc => tc.function.name).join(', ')}`); - return { - tool_calls: message.tool_calls, - finished: false, - reasoning: message.content || '执行工具调用' - }; + logger.info(`[crystelf-ai] AI调用工具: ${message.tool_calls.map(tc => tc.function.name).join(', ')}`); } else { - return { - action: 'send_message', - parameters: { - content: message.content - }, - finished: true, - reasoning: message.content - }; + logger.info(`[crystelf-ai] AI文本回复: ${message.content?.substring(0, 50)}...`); } + + return message; + } catch (error) { - logger.error(`[crystelf-ai] 工具调用AI失败: ${error.message}`); + logger.error(`[crystelf-ai] AI调用失败: ${error.message}`); throw error; } } diff --git a/lib/ai/responseHandler.js b/lib/ai/responseHandler.js index 5974b3d..2f0ca5f 100644 --- a/lib/ai/responseHandler.js +++ b/lib/ai/responseHandler.js @@ -62,7 +62,6 @@ class ResponseHandler { const processedMessages = []; for (const response of responses) { - // ReAct响应已经是标准格式,直接处理 const processedMessage = await this.processMessage(response, userMessage, groupId, user_id); if (processedMessage) { processedMessages.push(processedMessage); diff --git a/lib/ai/tools/controlTool.js b/lib/ai/tools/controlTool.js deleted file mode 100644 index ee63180..0000000 --- a/lib/ai/tools/controlTool.js +++ /dev/null @@ -1,98 +0,0 @@ -import BaseTool from './baseTool.js'; - -/** - * 找到答案工具 - 结束ReAct循环 - */ -class FindAnswerTool extends BaseTool { - constructor() { - super( - 'find_answer', - '当你已经收集到足够信息并准备给出最终回答时使用此工具', - { - type: 'object', - properties: { - confidence: { - type: 'number', - description: '回答的信心程度(0-1),1表示非常确信', - minimum: 0, - maximum: 1 - }, - summary: { - type: 'string', - description: '简要总结你收集到的关键信息' - }, - ready_to_respond: { - type: 'boolean', - description: '是否准备好给出最终回答', - default: true - } - }, - required: ['confidence', 'summary'] - } - ); - } - - async execute(params, context) { - const { confidence, summary, ready_to_respond = true } = params; - - logger.info(`[crystelf-ai] AI决定结束循环 - 信心度: ${confidence}, 摘要: ${summary}`); - - return { - success: true, - message: `已收集足够信息,准备回答`, - shouldEnd: true, - confidence, - summary, - readyToRespond: ready_to_respond - }; - } -} - -/** - * 需要更多信息工具 - 继续ReAct循环 - */ -class NeedMoreInfoTool extends BaseTool { - constructor() { - super( - 'need_more_info', - '当你需要更多信息才能给出满意回答时使用此工具', - { - type: 'object', - properties: { - missing_info: { - type: 'string', - description: '描述还缺少什么关键信息' - }, - next_action_plan: { - type: 'string', - description: '下一步计划采取什么行动获取信息' - }, - urgency: { - type: 'string', - enum: ['low', 'medium', 'high'], - description: '获取这些信息的紧急程度', - default: 'medium' - } - }, - required: ['missing_info', 'next_action_plan'] - } - ); - } - - async execute(params, context) { - const { missing_info, next_action_plan, urgency = 'medium' } = params; - - logger.info(`[crystelf-ai] AI需要更多信息 - 缺失: ${missing_info}, 计划: ${next_action_plan}`); - - return { - success: true, - message: `需要更多信息: ${missing_info}`, - shouldEnd: false, - missingInfo: missing_info, - nextPlan: next_action_plan, - urgency - }; - } -} - -export { FindAnswerTool, NeedMoreInfoTool }; \ No newline at end of file diff --git a/lib/ai/tools/findAnswerTool.js b/lib/ai/tools/findAnswerTool.js new file mode 100644 index 0000000..23cb6df --- /dev/null +++ b/lib/ai/tools/findAnswerTool.js @@ -0,0 +1,87 @@ +import BaseTool from './baseTool.js'; + +/** + * 找到答案工具 - 用于标记AI是否找到了足够的信息来回答用户 + */ +class FindAnswerTool extends BaseTool { + constructor() { + super( + 'found_answer', + '当你已经收集到足够信息可以回答用户问题时使用此工具', + { + type: 'object', + properties: { + answer_summary: { + type: 'string', + description: '简要总结你找到的关键信息,这将传递给下一阶段' + }, + confidence: { + type: 'number', + description: '回答的信心程度(0-1),1表示非常确信', + minimum: 0, + maximum: 1, + default: 0.8 + } + }, + required: ['answer_summary'] + } + ); + } + + async execute(params, context) { + const { answer_summary, confidence = 0.8 } = params; + + logger.info(`[crystelf-ai] AI找到答案 - 信心度: ${confidence}, 摘要: ${answer_summary}`); + + return { + success: true, + message: `已找到答案信息: ${answer_summary}`, + foundAnswer: true, + answerSummary: answer_summary, + confidence + }; + } +} + +/** + * 信息不足工具 - 用于标记AI认为信息不足 + */ +class NotEnoughInfoTool extends BaseTool { + constructor() { + super( + 'not_enough_info', + '当你认为收集的信息不足以回答用户问题时使用此工具', + { + type: 'object', + properties: { + reason: { + type: 'string', + description: '说明为什么信息不足,缺少什么关键信息' + }, + tried_methods: { + type: 'array', + items: { type: 'string' }, + description: '已经尝试过的搜索方法' + } + }, + required: ['reason'] + } + ); + } + + async execute(params, context) { + const { reason, tried_methods = [] } = params; + + logger.info(`[crystelf-ai] AI认为信息不足 - 原因: ${reason}`); + + return { + success: true, + message: `信息不足: ${reason}`, + foundAnswer: false, + reason, + triedMethods: tried_methods + }; + } +} + +export { FindAnswerTool, NotEnoughInfoTool }; \ No newline at end of file diff --git a/lib/ai/tools/toolCombinations.js b/lib/ai/tools/toolCombinations.js deleted file mode 100644 index 84eea31..0000000 --- a/lib/ai/tools/toolCombinations.js +++ /dev/null @@ -1,174 +0,0 @@ -/** - * 工具组合建议系统 - * 为AI提供常用的工具组合模式 - */ -class ToolCombinations { - constructor() { - this.combinations = new Map(); - this.initializeCombinations(); - } - - initializeCombinations() { - // 信息收集组合 - this.combinations.set('gather_user_info', { - name: '收集用户信息', - tools: ['search_memory', 'get_chat_history'], - description: '同时搜索用户记忆和获取聊天历史', - useCase: '当需要了解用户背景信息时', - example: { - search_memory: { query: '用户偏好', limit: 5 }, - get_chat_history: { count: 10, include_bot: true } - } - }); - - // 信息收集并回复组合 - this.combinations.set('search_and_respond', { - name: '搜索并回复', - tools: ['search_memory', 'send_message'], - description: '搜索相关信息后立即回复用户', - useCase: '当能够基于记忆直接回答时', - example: { - search_memory: { query: '相关关键词', limit: 3 }, - send_message: { content: '基于搜索结果的回复' } - } - }); - - // 存储并回复组合 - this.combinations.set('store_and_respond', { - name: '存储并回复', - tools: ['store_memory', 'send_message'], - description: '存储重要信息并回复用户', - useCase: '当用户提供新的重要信息时', - example: { - store_memory: { content: '重要信息', keywords: ['关键词'] }, - send_message: { content: '我记住了这个信息' } - } - }); - - // 多渠道信息收集 - this.combinations.set('comprehensive_search', { - name: '全面信息收集', - tools: ['search_memory', 'get_chat_history', 'need_more_info'], - description: '全面收集信息并说明还需要什么', - useCase: '处理复杂问题时', - example: { - search_memory: { query: '相关主题', limit: 5 }, - get_chat_history: { count: 15, include_bot: true }, - need_more_info: { missing_info: '具体需求', next_action_plan: '下一步计划' } - } - }); - - // 内容生成组合 - this.combinations.set('generate_content', { - name: '生成内容', - tools: ['render_code', 'send_message'], - description: '渲染代码并发送说明', - useCase: '当需要展示代码示例时', - example: { - render_code: { code: '示例代码', language: 'javascript' }, - send_message: { content: '这是相关的代码示例' } - } - }); - - // 完整回复组合 - this.combinations.set('complete_response', { - name: '完整回复', - tools: ['find_answer', 'send_message', 'send_meme'], - description: '给出完整回答并结束对话', - useCase: '当有足够信息给出最终回答时', - example: { - find_answer: { confidence: 0.8, summary: '信息摘要' }, - send_message: { content: '详细回答' }, - send_meme: { emotion: 'happy' } - } - }); - } - - /** - * 获取推荐的工具组合 - * @param {string} scenario - 场景描述 - * @returns {Array} 推荐的组合 - */ - getRecommendations(scenario) { - const recommendations = []; - - // 基于场景关键词匹配 - const scenarioLower = scenario.toLowerCase(); - - if (scenarioLower.includes('记忆') || scenarioLower.includes('历史')) { - recommendations.push(this.combinations.get('gather_user_info')); - } - - if (scenarioLower.includes('回答') || scenarioLower.includes('回复')) { - recommendations.push(this.combinations.get('search_and_respond')); - } - - if (scenarioLower.includes('存储') || scenarioLower.includes('记住')) { - recommendations.push(this.combinations.get('store_and_respond')); - } - - if (scenarioLower.includes('复杂') || scenarioLower.includes('详细')) { - recommendations.push(this.combinations.get('comprehensive_search')); - } - - if (scenarioLower.includes('代码') || scenarioLower.includes('示例')) { - recommendations.push(this.combinations.get('generate_content')); - } - - if (scenarioLower.includes('完成') || scenarioLower.includes('结束')) { - recommendations.push(this.combinations.get('complete_response')); - } - - return recommendations; - } - - /** - * 获取所有组合的描述 - * @returns {string} 格式化的组合描述 - */ - getAllCombinationsDescription() { - let description = '=== 常用工具组合模式 ===\n\n'; - - for (const [key, combo] of this.combinations) { - description += `${combo.name}:\n`; - description += `- 工具: ${combo.tools.join(', ')}\n`; - description += `- 说明: ${combo.description}\n`; - description += `- 适用: ${combo.useCase}\n\n`; - } - - return description; - } - - /** - * 验证工具组合的兼容性 - * @param {Array} toolNames - 工具名称数组 - * @returns {Object} 验证结果 - */ - validateCombination(toolNames) { - const conflicts = []; - const warnings = []; - - // 检查冲突的工具组合 - if (toolNames.includes('find_answer') && toolNames.includes('need_more_info')) { - conflicts.push('find_answer 和 need_more_info 不能同时使用'); - } - - if (toolNames.includes('send_message') && toolNames.length === 1) { - warnings.push('单独使用 send_message 可能缺少信息收集'); - } - - // 检查工具数量 - if (toolNames.length > 5) { - warnings.push('同时调用过多工具可能影响性能'); - } - - return { - isValid: conflicts.length === 0, - conflicts, - warnings, - toolCount: toolNames.length - }; - } -} - -export default new ToolCombinations(); \ No newline at end of file diff --git a/lib/ai/tools/toolInitializer.js b/lib/ai/tools/toolInitializer.js index 587c5c9..6f0e33a 100644 --- a/lib/ai/tools/toolInitializer.js +++ b/lib/ai/tools/toolInitializer.js @@ -3,7 +3,7 @@ import { SendMessageTool, SendMemeTool, PokeTool } from './messageTool.js'; import { SearchMemoryTool, GetChatHistoryTool } from './retrievalTool.js'; import { StoreMemoryTool } from './memoryTool.js'; import { RenderCodeTool, RenderMarkdownTool, GenerateImageTool } from './contentTool.js'; -import { FindAnswerTool, NeedMoreInfoTool } from './controlTool.js'; +import { FindAnswerTool, NotEnoughInfoTool } from './findAnswerTool.js'; /** * 工具初始化器 @@ -32,9 +32,9 @@ class ToolInitializer { toolRegistry.register(new RenderMarkdownTool()); toolRegistry.register(new GenerateImageTool()); - // 注册循环控制工具 + // 注册答案判断工具 toolRegistry.register(new FindAnswerTool()); - toolRegistry.register(new NeedMoreInfoTool()); + toolRegistry.register(new NotEnoughInfoTool()); const toolCount = toolRegistry.getToolList().length; logger.info(`[crystelf-ai] 工具初始化完成,共注册 ${toolCount} 个工具`);