diff --git a/server/ai/prompt.js b/server/ai/prompt.js index d23b23d..852e530 100644 --- a/server/ai/prompt.js +++ b/server/ai/prompt.js @@ -6,10 +6,24 @@ function buildSystemPrompt(username, isAdmin) { '意图分类:', '- 采购/付款/发票相关(新建):action="purchase",提取字段:purchase_item, quantity(默认1), unit_price(默认0), freight(默认0), payment_method(淘宝默认支付宝), invoice_type(默认无票), status, applicant, remarks, created_time', '- 查询汇总:action="query"', + ' 触发条件:当用户询问“买过什么/有没有买过/查一下/查查看/看看/搜索/找一下/列出/我买过/查查/搜搜”等查询历史采购记录的意图时,必须返回 action="query"。', + ' 示例:', + ' "查查看我买过记账本么?" → {"action":"query"}', + ' "我买过扩展坞吗?" → {"action":"query"}', + ' "绿联拓展坞有没有买过?" → {"action":"query"}', + ' 注意:即使物品名听起来奇怪或可能不存在,也绝对不能返回 ignore,必须返回 query 让系统去匹配。', '- 聊天:action="chat",reply简短回复', '- 删除指定物品:action="delete",delete_item为物品名', '- 清空所有采购数据:action="clear_all"', - '- 忽略(仅当完全无关):action="ignore"' + '- 忽略(仅当完全无关):action="ignore"', + ' 适用场景:纯闲聊(如“你好”“今天天气如何”)或与财务、采购完全无关的话题。', + ' 严禁将任何包含“买过”“查查看”“有没有”“找一下”等查询意图的句子判为 ignore,必须归为 query。' + ].join('\n'); + + const queryPriority = [ + '🔍 查询优先原则:', + '- 用户任何以“查”“找”“看”“搜索”“有没有”“买过”开头的消息,无论是否完整或物品名是否已知,都必须返回 action="query",不得返回 ignore、chat 或 ask。', + '- 系统会自行处理模糊匹配,你无需判断物品是否存在。' ].join('\n'); const permission = [ @@ -60,13 +74,24 @@ function buildSystemPrompt(username, isAdmin) { ' * "发票到/全搞定/完结"等明确有发票或结束意图的 → "已完成"', ' * 新建不指定 → "待付款"', '- 只有明确消费意图(购买/采购/下单/付款/买了/花了)才返回 action="purchase"', - '- 纯陈述 → action="ignore"', + '- 纯陈述且无查询意图 → action="ignore"', + '- 若陈述中包含“查/看/找/搜索/有没有/买过”等查询关键词 → 必须 action="query"', '- 信息不完整 → action="ask" 追问', '- amount 由系统自动计算(quantity × unit_price + freight),AI 无需提供', '- 无法确定物品名 → action="ask" 追问' ].join('\n'); - return [role, intent, permission, deleteRules, attachmentRules, prohibitionRules, modifyGuide, purchaseRules].join('\n'); + return [ + role, + intent, + queryPriority, + permission, + deleteRules, + attachmentRules, + prohibitionRules, + modifyGuide, + purchaseRules + ].join('\n'); } module.exports = { buildSystemPrompt }; diff --git a/server/handlers.js b/server/handlers.js index 7fcf244..28101ba 100644 --- a/server/handlers.js +++ b/server/handlers.js @@ -171,7 +171,11 @@ function handleAIResult(aiResult, roomId, username, originalText, attachments) { broadcastToRoom(roomId, { type: 'query_pending', text: '🔍 正在查询采购数据,请稍候...' }); const purchaseData = db.prepare('SELECT item, amount, payment_method, status, created_at FROM purchases WHERE room_id = ? ORDER BY created_at DESC').all(roomId).map(p => p.created_at + ' ' + p.item + ' ¥' + p.amount + ' ' + (p.payment_method||'') + ' ' + p.status).join('\n'); const summaryPrompt = '根据以下采购记录,用自然语言回答用户查询"' + originalText + '"。采购记录:\n' + (purchaseData || '暂无记录'); - callDeepSeekForSummary(summaryPrompt, username).then(reply => { storeAndBroadcastText(roomId, '小财', reply); addToHistory(roomId, 'assistant', reply); }); + callDeepSeekForSummary(summaryPrompt, username).then(function(reply) { + console.log('🤖 Query汇总回复:', reply.substring(0, 200)); + storeAndBroadcastText(roomId, '小财', reply); + addToHistory(roomId, 'assistant', reply); + }); return; } diff --git a/server/public/js/ws.js b/server/public/js/ws.js index cb965a3..6f4ed79 100644 --- a/server/public/js/ws.js +++ b/server/public/js/ws.js @@ -20,7 +20,7 @@ function initWebSocket() { if (room) { room.last_message = data.room_preview.last_message; room.last_time = data.room_preview.last_time; renderChatList(); } } } else if (data.type === 'query_pending') { - if (Store.currentRoom === roomId) showTempBubble(data.text); + showTempBubble(data.text); } else if (data.type === 'purchase_updated') { if (Store.currentRoom) loadPurchases(); updateSummaryPreview(); diff --git a/server/routes/messages.js b/server/routes/messages.js index 1c0231b..6b2dc98 100644 --- a/server/routes/messages.js +++ b/server/routes/messages.js @@ -69,11 +69,6 @@ async function analyzeWithDeepSeek(text, historyMessages, username, isAdmin, roo messages.push({ role: 'system', content: '当前服务器时间:' + new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', hour12: false }) }); const content = await callDeepSeek(messages, username); console.log('🤖 AI 返回:', content.substring(0, 200)); - // 打印消息结构,方便排查缓存 - console.log('📋 消息结构:', messages.map(function(m, i) { - var preview = m.content.substring(0, 60).split('\n').join(' '); - return '[' + i + '] ' + m.role + ' (' + m.content.length + '字): ' + preview; - }).join('\n')); try { var cleaned = content.replace(/```json|```/g, '').trim(); if (!cleaned) { console.warn('⚠️ AI 返回空内容'); return { action: 'ignore' }; }