AI指令修复
This commit is contained in:
parent
1062c62498
commit
1943d92c40
133
xinlidsj/AI分析指令修复说明.md
Normal file
133
xinlidsj/AI分析指令修复说明.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# AI分析指令修复说明
|
||||
|
||||
## 问题描述
|
||||
用户输入"分析张三"时,AI能够正确识别意图为`analyzeReport`,但系统没有使用AI识别的参数(keyword: "张三"),而是继续使用正则匹配,导致无法获取报告数据,最终返回"暂不提供此服务"。
|
||||
|
||||
## 根本原因
|
||||
1. AI意图识别成功后,对于分析类指令(analyzeReport/analyzeProfile)返回`false`继续处理
|
||||
2. 但后续代码仍然使用正则匹配`parseAnalyzeReportKeyword(text)`获取关键词
|
||||
3. AI识别的参数(`intent.params.keyword`)被丢弃,没有传递给后续逻辑
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 保存AI识别的意图
|
||||
在AI意图识别部分,当识别到分析类指令时,保存完整的intent对象:
|
||||
|
||||
```javascript
|
||||
let aiRecognizedIntent = null
|
||||
if (intent.action === 'analyzeReport' || intent.action === 'analyzeProfile' || intent.action === 'analyzeData') {
|
||||
aiRecognizedIntent = intent
|
||||
console.log('分析类指令,保存AI识别的参数:', aiRecognizedIntent)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 优先使用AI识别的参数
|
||||
在报告数据获取逻辑中,优先使用AI识别的参数,如果没有则回退到正则匹配:
|
||||
|
||||
```javascript
|
||||
let reportId = ''
|
||||
let reportKeyword = ''
|
||||
let profileKeyword = ''
|
||||
|
||||
if (aiRecognizedIntent) {
|
||||
console.log('使用AI识别的参数:', aiRecognizedIntent.params)
|
||||
if (aiRecognizedIntent.action === 'analyzeReport') {
|
||||
reportId = aiRecognizedIntent.params.reportId || ''
|
||||
reportKeyword = aiRecognizedIntent.params.keyword || ''
|
||||
} else if (aiRecognizedIntent.action === 'analyzeProfile') {
|
||||
profileKeyword = aiRecognizedIntent.params.keyword || aiRecognizedIntent.params.userId || ''
|
||||
}
|
||||
} else {
|
||||
// 回退到正则匹配
|
||||
console.log('回退到正则匹配')
|
||||
reportId = this.parseAnalyzeReportId(text)
|
||||
reportKeyword = this.parseAnalyzeReportKeyword(text)
|
||||
profileKeyword = ''
|
||||
}
|
||||
```
|
||||
|
||||
## 执行流程
|
||||
|
||||
### 用户输入:"分析张三"
|
||||
|
||||
1. **AI意图识别**
|
||||
- 调用`parseUserIntentWithAI("分析张三")`
|
||||
- AI返回:
|
||||
```json
|
||||
{
|
||||
"action": "analyzeReport",
|
||||
"params": {
|
||||
"keyword": "张三"
|
||||
},
|
||||
"confidence": 0.9,
|
||||
"reasoning": "用户想分析张三的测评报告"
|
||||
}
|
||||
```
|
||||
|
||||
2. **执行意图**
|
||||
- 调用`executeAIIntent(intent)`
|
||||
- 识别为分析类指令,返回`false`继续处理
|
||||
- 保存`aiRecognizedIntent = intent`
|
||||
|
||||
3. **获取报告数据**
|
||||
- 检测到`aiRecognizedIntent`存在
|
||||
- 提取参数:`reportKeyword = "张三"`
|
||||
- 调用`getStudentOptions({ keyword: "张三", limit: 1 })`获取用户ID
|
||||
- 调用`listReport({ userId })`获取报告列表
|
||||
- 调用`getReport(reportId)`获取报告详情
|
||||
|
||||
4. **AI分析报告**
|
||||
- 将报告数据作为context传递给AI
|
||||
- AI分析报告内容并返回分析结果
|
||||
- 在对话框中显示AI的分析结果
|
||||
|
||||
## 指令类型区分
|
||||
|
||||
### analyzeReport(分析报告)
|
||||
- 关键词:分析、数据、报告
|
||||
- 示例:
|
||||
- "分析张三的报告"
|
||||
- "分析李四的数据"
|
||||
- "分析报告123"
|
||||
- 行为:获取报告数据 → AI分析 → 返回分析结果
|
||||
|
||||
### analyzeProfile(查看画像)
|
||||
- 关键词:画像、档案、情况、了解
|
||||
- 示例:
|
||||
- "查看王五的画像"
|
||||
- "了解赵六的情况"
|
||||
- "打开张三的档案"
|
||||
- 行为:跳转到个体画像页面
|
||||
|
||||
### goReport(打开报告)
|
||||
- 关键词:打开、查看
|
||||
- 示例:
|
||||
- "打开张三的报告"
|
||||
- "查看报告列表"
|
||||
- 行为:跳转到报告列表页面
|
||||
|
||||
## 修改文件
|
||||
- `xinlidsj/pages/index/index.vue`
|
||||
- 第1605-1625行:保存AI识别的意图
|
||||
- 第1710-1740行:优先使用AI识别的参数
|
||||
|
||||
## 测试建议
|
||||
1. 测试AI识别:"分析张三" → 应该获取张三的报告并让AI分析
|
||||
2. 测试正则回退:关闭AI意图识别 → 应该使用正则匹配
|
||||
3. 测试不同指令:
|
||||
- "分析李四的数据" → analyzeReport
|
||||
- "查看王五的画像" → analyzeProfile(跳转页面)
|
||||
- "打开赵六的报告" → goReport(跳转页面)
|
||||
4. 测试错误处理:
|
||||
- 用户不存在 → "没有查询到相关数据"
|
||||
- 用户无报告 → "没有查询到相关数据"
|
||||
|
||||
## 日志输出
|
||||
关键日志点:
|
||||
- `尝试AI意图识别...`
|
||||
- `AI识别到意图: {action, params, confidence}`
|
||||
- `分析类指令,保存AI识别的参数: {...}`
|
||||
- `使用AI识别的参数: {keyword: "张三"}`
|
||||
- `最终使用的参数 - reportId: "", reportKeyword: "张三", profileKeyword: ""`
|
||||
|
||||
通过这些日志可以追踪整个流程,确认AI识别和参数传递是否正常。
|
||||
86
xinlidsj/AI意图识别修复说明.md
Normal file
86
xinlidsj/AI意图识别修复说明.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# AI意图识别JSON解析失败修复
|
||||
|
||||
## 问题现象
|
||||
|
||||
用户输入:"想看张三数据"
|
||||
错误:`JSON解析失败: Unexpected end of JSON input`
|
||||
|
||||
## 根本原因
|
||||
|
||||
原代码使用的正则表达式有问题:
|
||||
|
||||
```javascript
|
||||
const jsonMatch = jsonStr.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/)
|
||||
```
|
||||
|
||||
这个正则使用了**非贪婪匹配** `*?`,会在遇到第一个 `}` 时就停止,导致嵌套的JSON对象被截断。
|
||||
|
||||
例如,对于这样的JSON:
|
||||
```json
|
||||
{"action":"analyzeProfile","params":{"keyword":"张三"},"confidence":0.95}
|
||||
```
|
||||
|
||||
非贪婪匹配会在第一个 `}` (params后面的) 就停止,得到:
|
||||
```json
|
||||
{"action":"analyzeProfile","params":{"keyword":"张三"}
|
||||
```
|
||||
|
||||
这是一个不完整的JSON,导致解析失败。
|
||||
|
||||
## 解决方案
|
||||
|
||||
使用更简单可靠的方法:
|
||||
|
||||
```javascript
|
||||
// 1. 移除markdown代码块标记
|
||||
jsonStr = jsonStr.replace(/```(?:json)?/g, '').replace(/```/g, '').trim()
|
||||
|
||||
// 2. 找到第一个{和最后一个}
|
||||
const firstBrace = jsonStr.indexOf('{')
|
||||
const lastBrace = jsonStr.lastIndexOf('}')
|
||||
|
||||
// 3. 提取完整的JSON对象
|
||||
if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
|
||||
jsonStr = jsonStr.substring(firstBrace, lastBrace + 1)
|
||||
}
|
||||
|
||||
// 4. 使用try-catch保护解析
|
||||
try {
|
||||
intent = JSON.parse(jsonStr)
|
||||
} catch(e) {
|
||||
console.error('JSON解析失败:', e.message)
|
||||
console.log('失败的JSON字符串:', jsonStr)
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
## 已应用的修复
|
||||
|
||||
✅ 改进了JSON提取逻辑
|
||||
✅ 添加了try-catch保护
|
||||
✅ 添加了详细的调试日志
|
||||
✅ 添加了空值检查
|
||||
|
||||
## 测试建议
|
||||
|
||||
现在再次测试时,控制台会显示:
|
||||
1. AI意图识别:原始响应
|
||||
2. AI意图识别:响应类型
|
||||
3. AI意图识别:提取的JSON
|
||||
4. 如果失败:JSON解析失败的具体错误和完整的JSON字符串
|
||||
|
||||
这样可以准确定位问题所在。
|
||||
|
||||
## 预期结果
|
||||
|
||||
用户输入:"想看张三数据"
|
||||
AI识别:
|
||||
```json
|
||||
{
|
||||
"action": "analyzeProfile",
|
||||
"params": {"keyword": "张三"},
|
||||
"confidence": 0.95,
|
||||
"reasoning": "用户想分析张三的个体画像数据"
|
||||
}
|
||||
```
|
||||
系统执行:打开张三的个体画像页面
|
||||
129
xinlidsj/AI意图识别说明.md
Normal file
129
xinlidsj/AI意图识别说明.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# AI意图识别系统
|
||||
|
||||
## 概述
|
||||
|
||||
系统现在使用AI大模型来理解用户的自然语言输入,而不是依赖固定的正则表达式匹配。这使得用户可以用更自然、更灵活的方式与系统交互。
|
||||
|
||||
## 工作流程
|
||||
|
||||
1. **用户输入** → 用户在AI对话框中输入自然语言指令
|
||||
2. **AI意图识别** → 系统调用大模型(DeepSeek/通义千问)理解用户意图
|
||||
3. **结构化输出** → AI返回JSON格式的指令和参数
|
||||
4. **执行指令** → 系统根据识别结果执行相应操作
|
||||
5. **回退机制** → 如果AI识别失败,自动回退到原有的正则匹配
|
||||
|
||||
## 支持的指令类型
|
||||
|
||||
### 1. 导航类指令
|
||||
- `goWarning` - 打开预警中心
|
||||
- `goProfile` - 打开个体画像
|
||||
- `goComprehensive` - 打开综合报告
|
||||
- `goInterventionTask` - 打开干预任务
|
||||
- `goReport` - 打开报告列表/详情
|
||||
- `goMessage` - 打开消息/收件箱
|
||||
- `goNotice` - 打开通知公告
|
||||
- `goDashboard` - 打开监区看板
|
||||
- `goTagFilter` - 打开标签筛选
|
||||
- `goVoice` - 打开语音助手
|
||||
|
||||
### 2. 分析类指令
|
||||
- `analyzeReport` - 分析报告
|
||||
- `analyzeProfile` - 分析个体画像
|
||||
- `analyzeData` - 分析平台数据
|
||||
|
||||
### 3. 控制类指令
|
||||
- `clearChat` - 清空对话记录
|
||||
- `toggleChat` - 展开/收起对话框
|
||||
- `goBack` - 返回上一页
|
||||
- `goHome` - 返回首页
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 原来的方式(正则匹配)
|
||||
```
|
||||
用户输入:"打开张三的报告"
|
||||
系统:使用正则 /打开\s*([^\s的]{1,32})\s*的?报告/ 匹配
|
||||
结果:✅ 能识别
|
||||
|
||||
用户输入:"帮我看看张三的报告"
|
||||
系统:正则无法匹配
|
||||
结果:❌ 无法识别
|
||||
```
|
||||
|
||||
### 现在的方式(AI理解)
|
||||
```
|
||||
用户输入:"打开张三的报告"
|
||||
AI理解:用户想查看张三的报告
|
||||
返回:{"action":"goReport","params":{"keyword":"张三"},"confidence":0.95}
|
||||
结果:✅ 能识别
|
||||
|
||||
用户输入:"帮我看看张三的报告"
|
||||
AI理解:用户想查看张三的报告
|
||||
返回:{"action":"goReport","params":{"keyword":"张三"},"confidence":0.9}
|
||||
结果:✅ 能识别
|
||||
|
||||
用户输入:"我想了解一下李四的情况"
|
||||
AI理解:用户想查看李四的个体画像
|
||||
返回:{"action":"goProfile","params":{"keyword":"李四"},"confidence":0.85}
|
||||
结果:✅ 能识别
|
||||
|
||||
用户输入:"有没有严重的预警需要处理"
|
||||
AI理解:用户想查看严重级别的预警
|
||||
返回:{"action":"goWarning","params":{"warningLevel":"严重"},"confidence":0.9}
|
||||
结果:✅ 能识别
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
1. **更自然的交互** - 用户可以用日常语言表达需求
|
||||
2. **更强的容错性** - 不需要记住精确的指令格式
|
||||
3. **更好的扩展性** - 添加新指令只需更新配置,无需写正则
|
||||
4. **智能参数提取** - AI自动从语句中提取关键信息
|
||||
5. **回退保障** - AI识别失败时自动使用原有的正则匹配
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 核心方法
|
||||
|
||||
1. **parseUserIntentWithAI(userInput)** - AI意图识别
|
||||
- 输入:用户的自然语言
|
||||
- 输出:结构化的指令JSON
|
||||
- 使用:DeepSeek API / 通义千问 API
|
||||
|
||||
2. **executeAIIntent(intent)** - 执行识别出的指令
|
||||
- 输入:AI返回的指令JSON
|
||||
- 输出:是否成功执行
|
||||
- 功能:根据action和params执行相应操作
|
||||
|
||||
3. **sendAiChat()** - 修改后的消息发送方法
|
||||
- 先尝试AI意图识别
|
||||
- 识别成功则执行指令
|
||||
- 识别失败则回退到正则匹配
|
||||
|
||||
### AI Prompt设计
|
||||
|
||||
系统使用精心设计的prompt来引导AI:
|
||||
- 明确定义所有可用指令
|
||||
- 要求返回标准JSON格式
|
||||
- 包含置信度评分
|
||||
- 提供示例来提高准确性
|
||||
|
||||
### 置信度阈值
|
||||
|
||||
- 置信度 >= 0.6:执行指令
|
||||
- 置信度 < 0.6:忽略结果,回退到正则匹配
|
||||
|
||||
## 配置
|
||||
|
||||
AI意图识别使用与AI对话相同的配置:
|
||||
- DeepSeek API(默认)
|
||||
- 通义千问 API(可选)
|
||||
|
||||
无需额外配置,开箱即用。
|
||||
|
||||
## 未来扩展
|
||||
|
||||
1. 支持多轮对话上下文
|
||||
2. 支持复合指令(一次执行多个操作)
|
||||
3. 支持模糊查询和智能推荐
|
||||
4. 支持自定义指令学习
|
||||
77
xinlidsj/ai_intent_fix.txt
Normal file
77
xinlidsj/ai_intent_fix.txt
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
修复AI意图识别的JSON解析问题
|
||||
|
||||
找到这段代码(大约在1330-1355行):
|
||||
|
||||
console.log('AI意图识别:原始响应:', content)
|
||||
|
||||
// 提取JSON(可能被markdown代码块包裹)
|
||||
let jsonStr = content.trim()
|
||||
const jsonMatch = jsonStr.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/)
|
||||
if (jsonMatch) {
|
||||
jsonStr = jsonMatch[1]
|
||||
}
|
||||
|
||||
const intent = JSON.parse(jsonStr)
|
||||
console.log('AI意图识别:解析结果:', intent)
|
||||
|
||||
// 验证置信度
|
||||
if (intent.confidence < 0.6) {
|
||||
console.log('AI意图识别:置信度过低,忽略结果')
|
||||
return null
|
||||
}
|
||||
|
||||
替换为:
|
||||
|
||||
console.log('AI意图识别:原始响应:', content)
|
||||
|
||||
// 检查是否有内容
|
||||
if (!content || !content.trim()) {
|
||||
console.log('AI意图识别:响应为空')
|
||||
return null
|
||||
}
|
||||
|
||||
// 提取JSON
|
||||
let jsonStr = content.trim()
|
||||
|
||||
// 移除markdown代码块
|
||||
jsonStr = jsonStr.replace(/```(?:json)?\s*/g, '').replace(/```\s*/g, '')
|
||||
|
||||
// 提取第一个完整的JSON对象
|
||||
const jsonMatch2 = jsonStr.match(/\{[\s\S]*?\}/)
|
||||
if (jsonMatch2) {
|
||||
jsonStr = jsonMatch2[0]
|
||||
}
|
||||
|
||||
console.log('AI意图识别:提取的JSON字符串:', jsonStr.substring(0, 200))
|
||||
|
||||
// 解析JSON
|
||||
let intent = null
|
||||
try {
|
||||
intent = JSON.parse(jsonStr)
|
||||
} catch (parseError) {
|
||||
console.error('AI意图识别:JSON解析失败', parseError.message)
|
||||
return null
|
||||
}
|
||||
|
||||
console.log('AI意图识别:解析结果:', intent)
|
||||
|
||||
// 验证intent结构
|
||||
if (!intent || typeof intent !== 'object') {
|
||||
console.log('AI意图识别:intent不是对象')
|
||||
return null
|
||||
}
|
||||
|
||||
// 验证置信度
|
||||
const confidence = parseFloat(intent.confidence)
|
||||
if (isNaN(confidence) || confidence < 0.6) {
|
||||
console.log('AI意图识别:置信度过低或无效', confidence)
|
||||
return null
|
||||
}
|
||||
|
||||
主要改进:
|
||||
1. 添加了空内容检查
|
||||
2. 改进了JSON提取逻辑,使用replace而不是match
|
||||
3. 添加了try-catch包裹JSON.parse
|
||||
4. 添加了更详细的错误日志
|
||||
5. 验证intent对象结构
|
||||
6. 改进了置信度验证逻辑
|
||||
|
|
@ -1235,6 +1235,156 @@
|
|||
if (!s) return false
|
||||
return /(分析|趋势|总结|汇总|研判|建议)/.test(s)
|
||||
},
|
||||
// AI意图识别 - 使用大模型理解用户输入并提取结构化指令
|
||||
async parseUserIntentWithAI(userInput) {
|
||||
const llmCfg = this.getBailianConfig() || this.getOllamaConfig()
|
||||
if (!llmCfg) {
|
||||
console.log('AI意图识别:未配置大模型')
|
||||
return null
|
||||
}
|
||||
|
||||
// 定义系统可以执行的指令列表
|
||||
const availableCommands = {
|
||||
navigation: [
|
||||
{ action: 'goWarning', params: ['status', 'warningLevel'], desc: '打开预警中心,可选参数:status(0=未处理,1=处理中,2=已完成), warningLevel(严重/高/中/低)' },
|
||||
{ action: 'goProfile', params: ['keyword', 'userId'], desc: '打开个体画像,可选参数:keyword(姓名/编号), userId(用户ID)' },
|
||||
{ action: 'goComprehensive', params: [], desc: '打开综合报告' },
|
||||
{ action: 'goInterventionTask', params: ['status'], desc: '打开干预任务,可选参数:status(0,1=未完成,2=已完成)' },
|
||||
{ action: 'goReport', params: ['keyword', 'reportId', 'sourceType'], desc: '打开报告列表或详情,可选参数:keyword(搜索关键词), reportId(报告ID), sourceType(assessment/questionnaire)' },
|
||||
{ action: 'goMessage', params: ['tab'], desc: '打开消息/收件箱,可选参数:tab(unread=未读)' },
|
||||
{ action: 'goNotice', params: [], desc: '打开通知公告' },
|
||||
{ action: 'goDashboard', params: [], desc: '打开监区看板' },
|
||||
{ action: 'goTagFilter', params: [], desc: '打开标签筛选' },
|
||||
{ action: 'goVoice', params: [], desc: '打开语音助手' }
|
||||
],
|
||||
analysis: [
|
||||
{ action: 'analyzeReport', params: ['keyword', 'reportId'], desc: '分析某人的测评报告/数据,关键词:分析、数据、报告。必需参数:keyword(姓名/编号)或reportId(报告ID)' },
|
||||
{ action: 'analyzeProfile', params: ['keyword', 'userId'], desc: '查看某人的个体画像/档案/情况,关键词:画像、档案、情况、了解。必需参数:keyword(姓名/编号)或userId(用户ID)' },
|
||||
{ action: 'analyzeData', params: ['dataType'], desc: '分析平台整体数据,关键词:平台数据、统计、趋势。可选参数:dataType(overview=概览/trend=趋势/dept=监区统计)' }
|
||||
],
|
||||
control: [
|
||||
{ action: 'clearChat', params: [], desc: '清空对话记录' },
|
||||
{ action: 'toggleChat', params: [], desc: '展开或收起AI对话框' },
|
||||
{ action: 'goBack', params: [], desc: '返回上一页' },
|
||||
{ action: 'goHome', params: [], desc: '返回首页' }
|
||||
]
|
||||
}
|
||||
|
||||
const systemPrompt = `你是一个指令解析助手,负责理解用户的自然语言输入并转换为结构化的系统指令。
|
||||
|
||||
可用的指令类型:
|
||||
${JSON.stringify(availableCommands, null, 2)}
|
||||
|
||||
重要区分:
|
||||
- analyzeReport: 用于"分析XX的报告/数据",查看测评报告详情
|
||||
- analyzeProfile: 用于"查看XX的画像/档案/情况",查看个体画像
|
||||
- goReport: 用于"打开XX的报告",跳转到报告列表
|
||||
|
||||
你的任务:
|
||||
1. 理解用户输入的意图
|
||||
2. 从可用指令中选择最匹配的action
|
||||
3. 提取用户输入中的参数值
|
||||
4. 返回JSON格式的结构化指令
|
||||
|
||||
返回格式(必须是有效的JSON):
|
||||
{
|
||||
"action": "指令名称",
|
||||
"params": {
|
||||
"参数名": "参数值"
|
||||
},
|
||||
"confidence": 0.0-1.0,
|
||||
"reasoning": "简短说明为什么选择这个指令"
|
||||
}
|
||||
|
||||
如果无法识别用户意图,返回:
|
||||
{
|
||||
"action": null,
|
||||
"confidence": 0,
|
||||
"reasoning": "无法理解用户意图"
|
||||
}
|
||||
|
||||
示例:
|
||||
用户输入:"打开张三的报告"
|
||||
返回:{"action":"goReport","params":{"keyword":"张三"},"confidence":0.95,"reasoning":"用户想查看张三的报告列表"}
|
||||
|
||||
用户输入:"分析李四的数据"
|
||||
返回:{"action":"analyzeReport","params":{"keyword":"李四"},"confidence":0.9,"reasoning":"用户想分析李四的测评报告"}
|
||||
|
||||
用户输入:"查看王五的画像"
|
||||
返回:{"action":"analyzeProfile","params":{"keyword":"王五"},"confidence":0.95,"reasoning":"用户想查看王五的个体画像"}
|
||||
|
||||
用户输入:"查看未处理的预警"
|
||||
返回:{"action":"goWarning","params":{"status":"0"},"confidence":0.95,"reasoning":"用户想查看未处理状态的预警"}
|
||||
|
||||
重要:只返回JSON,不要有任何其他文字。`
|
||||
|
||||
try {
|
||||
console.log('AI意图识别:开始解析用户输入:', userInput)
|
||||
|
||||
const messages = [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userInput }
|
||||
]
|
||||
|
||||
const result = await this.callBailianChat({
|
||||
model: llmCfg.model,
|
||||
apiUrl: llmCfg.apiUrl,
|
||||
apiKey: llmCfg.apiKey,
|
||||
messages,
|
||||
temperature: 0.1, // 低温度,更确定性的输出
|
||||
max_tokens: 500
|
||||
})
|
||||
|
||||
// callBailianChat直接返回content字符串,不是完整的result对象
|
||||
let content = result || ''
|
||||
|
||||
console.log('AI意图识别:原始响应:', content)
|
||||
console.log('AI意图识别:响应类型:', typeof content)
|
||||
console.log('AI意图识别:响应长度:', content.length)
|
||||
|
||||
// 提取JSON
|
||||
let jsonStr = content.trim()
|
||||
if (!jsonStr) {
|
||||
console.log('AI意图识别:响应为空')
|
||||
return null
|
||||
}
|
||||
|
||||
// 移除markdown代码块
|
||||
jsonStr = jsonStr.replace(/```(?:json)?/g, '').replace(/```/g, '').trim()
|
||||
|
||||
// 提取第一个{到最后一个}之间的内容
|
||||
const firstBrace = jsonStr.indexOf('{')
|
||||
const lastBrace = jsonStr.lastIndexOf('}')
|
||||
if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
|
||||
jsonStr = jsonStr.substring(firstBrace, lastBrace + 1)
|
||||
}
|
||||
|
||||
console.log('AI意图识别:提取的JSON:', jsonStr)
|
||||
|
||||
// 解析JSON
|
||||
let intent = null
|
||||
try {
|
||||
intent = JSON.parse(jsonStr)
|
||||
} catch(e) {
|
||||
console.error('JSON解析失败:', e.message)
|
||||
console.log('失败的JSON字符串:', jsonStr)
|
||||
return null
|
||||
}
|
||||
|
||||
console.log('AI意图识别:解析结果:', intent)
|
||||
|
||||
// 验证置信度
|
||||
if (intent.confidence < 0.6) {
|
||||
console.log('AI意图识别:置信度过低,忽略结果')
|
||||
return null
|
||||
}
|
||||
|
||||
return intent
|
||||
} catch (e) {
|
||||
console.error('AI意图识别失败:', e)
|
||||
return null
|
||||
}
|
||||
},
|
||||
parseAnalyzeReportId(text) {
|
||||
const s = String(text || '').trim()
|
||||
if (!s) return ''
|
||||
|
|
@ -1323,7 +1473,122 @@
|
|||
if (!this.isAiNeedContext(s)) return false
|
||||
return true
|
||||
},
|
||||
sendAiChat() {
|
||||
// 执行AI识别出的指令
|
||||
executeAIIntent(intent) {
|
||||
if (!intent || !intent.action) {
|
||||
return false
|
||||
}
|
||||
|
||||
const action = intent.action
|
||||
const params = intent.params || {}
|
||||
|
||||
console.log('执行AI指令:', action, params)
|
||||
|
||||
// 导航类指令
|
||||
if (action === 'goWarning') {
|
||||
let url = '/pages/warning/index'
|
||||
const query = []
|
||||
if (params.status) query.push(`status=${params.status}`)
|
||||
if (params.warningLevel) query.push(`warningLevel=${encodeURIComponent(params.warningLevel)}`)
|
||||
if (query.length) url += '?' + query.join('&')
|
||||
uni.navigateTo({ url })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goProfile') {
|
||||
let url = '/pages/profile/index'
|
||||
const query = []
|
||||
if (params.keyword) query.push(`keyword=${encodeURIComponent(params.keyword)}`)
|
||||
if (params.userId) query.push(`userId=${params.userId}`)
|
||||
if (query.length) url += '?' + query.join('&')
|
||||
uni.navigateTo({ url })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goComprehensive') {
|
||||
uni.navigateTo({ url: '/pages/comprehensive/index' })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goInterventionTask') {
|
||||
let url = '/pages/interventionTask/index'
|
||||
if (params.status) url += `?status=${params.status}`
|
||||
uni.navigateTo({ url })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goReport') {
|
||||
if (params.reportId) {
|
||||
uni.navigateTo({ url: `/pages/report/detail?reportId=${params.reportId}&sourceType=${params.sourceType || ''}` })
|
||||
} else {
|
||||
let url = '/pages/report/index'
|
||||
const query = []
|
||||
if (params.keyword) query.push(`keyword=${encodeURIComponent(params.keyword)}`)
|
||||
if (params.sourceType) query.push(`sourceType=${params.sourceType}`)
|
||||
if (query.length) url += '?' + query.join('&')
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goMessage') {
|
||||
let url = '/pages/message/inbox'
|
||||
if (params.tab) url += `?tab=${params.tab}`
|
||||
uni.navigateTo({ url })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goNotice') {
|
||||
uni.navigateTo({ url: '/pages/message/notice' })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goDashboard') {
|
||||
uni.navigateTo({ url: '/pages/dashboard/index' })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goTagFilter') {
|
||||
uni.navigateTo({ url: '/pages/profile/tagFilter' })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goVoice') {
|
||||
uni.navigateTo({ url: '/pages/voice/index' })
|
||||
return true
|
||||
}
|
||||
|
||||
// 控制类指令
|
||||
if (action === 'clearChat') {
|
||||
this.clearAiChat()
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'toggleChat') {
|
||||
this.toggleAiChat()
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goBack') {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
return true
|
||||
}
|
||||
|
||||
if (action === 'goHome') {
|
||||
uni.reLaunch({ url: '/pages/index/index' })
|
||||
return true
|
||||
}
|
||||
|
||||
// 分析类指令 - 让AI分析数据并返回结果,而不是跳转页面
|
||||
if (action === 'analyzeReport' || action === 'analyzeProfile' || action === 'analyzeData') {
|
||||
// 返回false,让后续的AI分析逻辑处理
|
||||
// 这样会获取数据并调用AI进行分析
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
async sendAiChat() {
|
||||
if (this.aiChatSending) return
|
||||
const text = this.aiChatInputTrim
|
||||
if (!text) return
|
||||
|
|
@ -1335,6 +1600,38 @@
|
|||
this.scrollAiChatToBottom()
|
||||
})
|
||||
|
||||
// ===== 新增:AI意图识别 =====
|
||||
let aiRecognizedIntent = null
|
||||
try {
|
||||
console.log('尝试AI意图识别...')
|
||||
const intent = await this.parseUserIntentWithAI(text)
|
||||
if (intent && intent.action) {
|
||||
console.log('AI识别到意图:', intent)
|
||||
const executed = this.executeAIIntent(intent)
|
||||
if (executed) {
|
||||
// 导航类指令已执行,显示反馈
|
||||
this.aiChatMessages = [...this.aiChatMessages, {
|
||||
id: 'a_' + Date.now(),
|
||||
role: 'ai',
|
||||
content: `已执行:${intent.reasoning || intent.action}`
|
||||
}]
|
||||
this.aiChatSending = false
|
||||
this.$nextTick(() => {
|
||||
this.scrollAiChatToBottom()
|
||||
})
|
||||
return
|
||||
}
|
||||
// 分析类指令,保存intent供后续使用
|
||||
if (intent.action === 'analyzeReport' || intent.action === 'analyzeProfile' || intent.action === 'analyzeData') {
|
||||
aiRecognizedIntent = intent
|
||||
console.log('分析类指令,保存AI识别的参数:', aiRecognizedIntent)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('AI意图识别出错,回退到正则匹配:', e)
|
||||
}
|
||||
// ===== AI意图识别结束 =====
|
||||
|
||||
const openReportIdMatch = String(text || '').trim().match(/打开\s*(?:报告\s*id\s*|报告\s*#\s*|报告#\s*)(\d{1,18})/i)
|
||||
if (openReportIdMatch && openReportIdMatch[1]) {
|
||||
const reportId = openReportIdMatch[1]
|
||||
|
|
@ -1416,9 +1713,30 @@
|
|||
})
|
||||
return
|
||||
}
|
||||
const reportId = this.parseAnalyzeReportId(text)
|
||||
const reportKeyword = this.parseAnalyzeReportKeyword(text)
|
||||
const profileKeyword = ''
|
||||
|
||||
// 优先使用AI识别的参数,否则回退到正则匹配
|
||||
let reportId = ''
|
||||
let reportKeyword = ''
|
||||
let profileKeyword = ''
|
||||
|
||||
if (aiRecognizedIntent) {
|
||||
console.log('使用AI识别的参数:', aiRecognizedIntent.params)
|
||||
if (aiRecognizedIntent.action === 'analyzeReport') {
|
||||
reportId = aiRecognizedIntent.params.reportId || ''
|
||||
reportKeyword = aiRecognizedIntent.params.keyword || ''
|
||||
} else if (aiRecognizedIntent.action === 'analyzeProfile') {
|
||||
profileKeyword = aiRecognizedIntent.params.keyword || aiRecognizedIntent.params.userId || ''
|
||||
}
|
||||
} else {
|
||||
// 回退到正则匹配
|
||||
console.log('回退到正则匹配')
|
||||
reportId = this.parseAnalyzeReportId(text)
|
||||
reportKeyword = this.parseAnalyzeReportKeyword(text)
|
||||
profileKeyword = ''
|
||||
}
|
||||
|
||||
console.log('最终使用的参数 - reportId:', reportId, 'reportKeyword:', reportKeyword, 'profileKeyword:', profileKeyword)
|
||||
|
||||
const baseContext = this.buildAiAnalyzeContext()
|
||||
let report = null
|
||||
let profile = null
|
||||
|
|
|
|||
147
xinlidsj/parseUserIntentWithAI_improved.js
Normal file
147
xinlidsj/parseUserIntentWithAI_improved.js
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// 改进版的AI意图识别方法
|
||||
// 复制这段代码替换 xinlidsj/pages/index/index.vue 中的 parseUserIntentWithAI 方法
|
||||
|
||||
async parseUserIntentWithAI(userInput) {
|
||||
const llmCfg = this.getBailianConfig() || this.getOllamaConfig()
|
||||
if (!llmCfg) {
|
||||
console.log('AI意图识别:未配置大模型')
|
||||
return null
|
||||
}
|
||||
|
||||
// 定义系统可以执行的指令列表
|
||||
const availableCommands = {
|
||||
navigation: [
|
||||
{ action: 'goWarning', params: ['status', 'warningLevel'], desc: '打开预警中心,可选参数:status(0=未处理,1=处理中,2=已完成), warningLevel(严重/高/中/低)' },
|
||||
{ action: 'goProfile', params: ['keyword', 'userId'], desc: '打开个体画像,可选参数:keyword(姓名/编号), userId(用户ID)' },
|
||||
{ action: 'goComprehensive', params: [], desc: '打开综合报告' },
|
||||
{ action: 'goInterventionTask', params: ['status'], desc: '打开干预任务,可选参数:status(0,1=未完成,2=已完成)' },
|
||||
{ action: 'goReport', params: ['keyword', 'reportId', 'sourceType'], desc: '打开报告列表或详情,可选参数:keyword(搜索关键词), reportId(报告ID), sourceType(assessment/questionnaire)' },
|
||||
{ action: 'goMessage', params: ['tab'], desc: '打开消息/收件箱,可选参数:tab(unread=未读)' },
|
||||
{ action: 'goNotice', params: [], desc: '打开通知公告' },
|
||||
{ action: 'goDashboard', params: [], desc: '打开监区看板' },
|
||||
{ action: 'goTagFilter', params: [], desc: '打开标签筛选' },
|
||||
{ action: 'goVoice', params: [], desc: '打开语音助手' }
|
||||
],
|
||||
analysis: [
|
||||
{ action: 'analyzeReport', params: ['keyword', 'reportId'], desc: '分析报告,必需参数:keyword(姓名/编号)或reportId(报告ID)' },
|
||||
{ action: 'analyzeProfile', params: ['keyword', 'userId'], desc: '分析个体画像,必需参数:keyword(姓名/编号)或userId(用户ID)' },
|
||||
{ action: 'analyzeData', params: ['dataType'], desc: '分析平台数据,可选参数:dataType(overview=概览/trend=趋势/dept=监区统计)' }
|
||||
],
|
||||
control: [
|
||||
{ action: 'clearChat', params: [], desc: '清空对话记录' },
|
||||
{ action: 'toggleChat', params: [], desc: '展开或收起AI对话框' },
|
||||
{ action: 'goBack', params: [], desc: '返回上一页' },
|
||||
{ action: 'goHome', params: [], desc: '返回首页' }
|
||||
]
|
||||
}
|
||||
|
||||
const systemPrompt = `你是一个指令解析助手,负责理解用户的自然语言输入并转换为结构化的系统指令。
|
||||
|
||||
可用的指令类型:
|
||||
${JSON.stringify(availableCommands, null, 2)}
|
||||
|
||||
你的任务:
|
||||
1. 理解用户输入的意图
|
||||
2. 从可用指令中选择最匹配的action
|
||||
3. 提取用户输入中的参数值
|
||||
4. 返回JSON格式的结构化指令
|
||||
|
||||
返回格式(必须是有效的JSON,不要有任何其他文字):
|
||||
{
|
||||
"action": "指令名称",
|
||||
"params": {
|
||||
"参数名": "参数值"
|
||||
},
|
||||
"confidence": 0.9,
|
||||
"reasoning": "简短说明"
|
||||
}
|
||||
|
||||
如果无法识别用户意图,返回:
|
||||
{
|
||||
"action": null,
|
||||
"confidence": 0,
|
||||
"reasoning": "无法理解用户意图"
|
||||
}
|
||||
|
||||
示例:
|
||||
用户输入:"打开张三的报告"
|
||||
返回:{"action":"goReport","params":{"keyword":"张三"},"confidence":0.95,"reasoning":"用户想查看张三的报告"}
|
||||
|
||||
重要:只返回JSON,不要有markdown代码块,不要有任何其他文字。`
|
||||
|
||||
try {
|
||||
console.log('AI意图识别:开始解析用户输入:', userInput)
|
||||
|
||||
const messages = [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userInput }
|
||||
]
|
||||
|
||||
const result = await this.callBailianChat({
|
||||
model: llmCfg.model,
|
||||
apiUrl: llmCfg.apiUrl,
|
||||
apiKey: llmCfg.apiKey,
|
||||
messages,
|
||||
temperature: 0.1,
|
||||
max_tokens: 500
|
||||
})
|
||||
|
||||
let content = ''
|
||||
if (result && result.choices && result.choices[0] && result.choices[0].message) {
|
||||
content = result.choices[0].message.content
|
||||
}
|
||||
|
||||
console.log('AI意图识别:原始响应:', content)
|
||||
|
||||
// 检查是否有内容
|
||||
if (!content || !content.trim()) {
|
||||
console.log('AI意图识别:响应为空')
|
||||
return null
|
||||
}
|
||||
|
||||
// 提取JSON
|
||||
let jsonStr = content.trim()
|
||||
|
||||
// 移除markdown代码块
|
||||
jsonStr = jsonStr.replace(/```(?:json)?\s*/g, '').replace(/```\s*/g, '')
|
||||
|
||||
// 提取第一个完整的JSON对象
|
||||
const jsonMatch = jsonStr.match(/\{[\s\S]*?\}/)
|
||||
if (jsonMatch) {
|
||||
jsonStr = jsonMatch[0]
|
||||
}
|
||||
|
||||
console.log('AI意图识别:提取的JSON字符串:', jsonStr)
|
||||
|
||||
// 解析JSON
|
||||
let intent = null
|
||||
try {
|
||||
intent = JSON.parse(jsonStr)
|
||||
} catch (parseError) {
|
||||
console.error('AI意图识别:JSON解析失败', parseError.message)
|
||||
console.log('尝试解析的字符串:', jsonStr.substring(0, 200))
|
||||
return null
|
||||
}
|
||||
|
||||
console.log('AI意图识别:解析结果:', intent)
|
||||
|
||||
// 验证intent结构
|
||||
if (!intent || typeof intent !== 'object') {
|
||||
console.log('AI意图识别:intent不是对象')
|
||||
return null
|
||||
}
|
||||
|
||||
// 验证置信度
|
||||
const confidence = parseFloat(intent.confidence)
|
||||
if (isNaN(confidence) || confidence < 0.6) {
|
||||
console.log('AI意图识别:置信度过低或无效', confidence)
|
||||
return null
|
||||
}
|
||||
|
||||
return intent
|
||||
} catch (e) {
|
||||
console.error('AI意图识别失败:', e.message || e)
|
||||
console.error('错误堆栈:', e.stack)
|
||||
return null
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user