@shun-js/aibaiban-server 0.7.7 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/assets/bing.txt +1 -0
- package/assets/robots.txt +36 -0
- package/assets/sitemap.xml +16 -0
- package/package.json +6 -2
- package/server/controller/IndexController.js +12 -0
- package/server/controller/LLMController.js +17 -0
- package/server/controller/SEOController.js +18 -0
- package/server/log-options.js +34 -0
- package/server/service/IndexService.js +16 -0
- package/server/service/LLMService.js +85 -0
- package/server/service/SEOService.js +38 -0
- package/server/util/check.js +23 -0
- package/server/util/feishu.js +77 -0
- package/server/util/llm-intent.js +79 -0
- package/server/util/llm-toolcall.js +314 -0
- package/server/util/prompt-intent.md +277 -0
- package/server/util/prompt-toolcall.md +273 -0
- package/views/index.html +146 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Calling 流程图生成器 - 主流程
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// path
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { readFile } = require('qiao-file');
|
|
8
|
+
|
|
9
|
+
// 直接使用 @google/genai,绕过 viho-llm
|
|
10
|
+
const { GoogleGenAI } = require('@google/genai');
|
|
11
|
+
|
|
12
|
+
// gemini client(直接创建)
|
|
13
|
+
const geminiClient = new GoogleGenAI({
|
|
14
|
+
vertexai: true,
|
|
15
|
+
project: global.QZ_CONFIG.gemini.projectId,
|
|
16
|
+
location: global.QZ_CONFIG.gemini.location,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const modelName = global.QZ_CONFIG.gemini.modelName;
|
|
20
|
+
|
|
21
|
+
// const
|
|
22
|
+
const chatConfig = {
|
|
23
|
+
temperature: 0.3,
|
|
24
|
+
topP: 0.9,
|
|
25
|
+
topK: 40,
|
|
26
|
+
maxOutputTokens: 8192,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 使用结构化输出生成流程图
|
|
31
|
+
* @param {string} userPrompt - 用户需求
|
|
32
|
+
* @returns {Object} - SimplifiedDiagram
|
|
33
|
+
*/
|
|
34
|
+
exports.generateFlowchartWithTools = async (userPrompt) => {
|
|
35
|
+
console.log('[ToolCall] Starting flowchart generation');
|
|
36
|
+
console.log('[ToolCall] User prompt:', userPrompt);
|
|
37
|
+
|
|
38
|
+
// 加载系统提示词
|
|
39
|
+
let systemPromptText = await readFile(path.resolve(__dirname, './prompt-toolcall.md'));
|
|
40
|
+
|
|
41
|
+
// 确保是字符串格式
|
|
42
|
+
if (Buffer.isBuffer(systemPromptText)) {
|
|
43
|
+
systemPromptText = systemPromptText.toString('utf-8');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('[ToolCall] System prompt loaded, length:', systemPromptText.length);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// 调用 AI 生成 JSON
|
|
50
|
+
const chatOptions = {
|
|
51
|
+
model: modelName,
|
|
52
|
+
contents: [
|
|
53
|
+
{
|
|
54
|
+
role: 'user',
|
|
55
|
+
parts: [
|
|
56
|
+
{
|
|
57
|
+
text: `${systemPromptText}\n\n---\n\n用户需求:${userPrompt}\n\n请只返回 JSON 对象,不要有任何其他说明文字。`,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
config: chatConfig,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const response = await geminiClient.models.generateContent(chatOptions);
|
|
66
|
+
|
|
67
|
+
// 打印原始响应(调试用)
|
|
68
|
+
console.log('[ToolCall] Raw response:', JSON.stringify(response, null, 2));
|
|
69
|
+
|
|
70
|
+
// 检查响应
|
|
71
|
+
if (!response || !response.candidates || response.candidates.length === 0) {
|
|
72
|
+
console.error('[ToolCall] Invalid response format');
|
|
73
|
+
return { type: 'flowchart', nodes: [], connections: [], error: '响应格式错误' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const candidate = response.candidates[0];
|
|
77
|
+
const content = candidate.content;
|
|
78
|
+
|
|
79
|
+
if (!content || !content.parts || content.parts.length === 0) {
|
|
80
|
+
console.error('[ToolCall] No content parts in response');
|
|
81
|
+
return { type: 'flowchart', nodes: [], connections: [], error: '无响应内容' };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 提取文本
|
|
85
|
+
let responseText = '';
|
|
86
|
+
for (const part of content.parts) {
|
|
87
|
+
if (part.text) {
|
|
88
|
+
responseText += part.text;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log('[ToolCall] Response text length:', responseText.length);
|
|
93
|
+
|
|
94
|
+
// 尝试提取 JSON(可能被包裹在 markdown 代码块中)
|
|
95
|
+
let jsonText = responseText.trim();
|
|
96
|
+
|
|
97
|
+
// 移除可能的 markdown 代码块标记
|
|
98
|
+
const jsonMatch = jsonText.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
99
|
+
if (jsonMatch) {
|
|
100
|
+
jsonText = jsonMatch[1].trim();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 解析 JSON
|
|
104
|
+
let diagramData;
|
|
105
|
+
try {
|
|
106
|
+
diagramData = JSON.parse(jsonText);
|
|
107
|
+
} catch (parseError) {
|
|
108
|
+
console.error('[ToolCall] JSON parse error:', parseError);
|
|
109
|
+
console.error('[ToolCall] JSON text:', jsonText.substring(0, 500));
|
|
110
|
+
return { type: 'flowchart', nodes: [], connections: [], error: 'JSON 解析失败' };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 验证数据结构
|
|
114
|
+
if (!diagramData.nodes || !Array.isArray(diagramData.nodes)) {
|
|
115
|
+
console.error('[ToolCall] Invalid diagram data: missing nodes array');
|
|
116
|
+
return { type: 'flowchart', nodes: [], connections: [], error: '缺少节点数据' };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!diagramData.connections || !Array.isArray(diagramData.connections)) {
|
|
120
|
+
console.error('[ToolCall] Invalid diagram data: missing connections array');
|
|
121
|
+
return { type: 'flowchart', nodes: [], connections: [], error: '缺少连接数据' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log(
|
|
125
|
+
`[ToolCall] Parsed diagram: ${diagramData.nodes.length} nodes, ${diagramData.connections.length} connections`,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// 应用布局计算
|
|
129
|
+
const nodesWithLayout = calculateMainFlowLayout(diagramData.nodes);
|
|
130
|
+
|
|
131
|
+
// 创建节点位置查找表
|
|
132
|
+
const nodeMap = {};
|
|
133
|
+
nodesWithLayout.forEach((node) => {
|
|
134
|
+
nodeMap[node.id] = node;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// 添加连线路由(智能识别连线类型)
|
|
138
|
+
const connectionsWithRouting = diagramData.connections.map((conn) => {
|
|
139
|
+
const fromNode = nodeMap[conn.from];
|
|
140
|
+
const toNode = nodeMap[conn.to];
|
|
141
|
+
|
|
142
|
+
if (!fromNode || !toNode) {
|
|
143
|
+
// 节点不存在,使用默认路由
|
|
144
|
+
return {
|
|
145
|
+
...conn,
|
|
146
|
+
routing: {
|
|
147
|
+
exitSide: 'bottom',
|
|
148
|
+
entrySide: 'top',
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 判断连线类型
|
|
154
|
+
const isErrorBranch = toNode.color === 'red'; // 判断节点 -> 错误节点
|
|
155
|
+
const isBackwardFlow = toNode.y < fromNode.y; // 回退连线(向上)
|
|
156
|
+
const isHorizontal = Math.abs(fromNode.x - toNode.x) > 100; // 水平偏移较大
|
|
157
|
+
|
|
158
|
+
let routing;
|
|
159
|
+
|
|
160
|
+
if (isErrorBranch) {
|
|
161
|
+
// 错误分支:从判断节点左侧或右侧出去
|
|
162
|
+
routing = {
|
|
163
|
+
exitSide: toNode.x < fromNode.x ? 'left' : 'right',
|
|
164
|
+
exitRatio: 0.5,
|
|
165
|
+
entrySide: toNode.x < fromNode.x ? 'right' : 'left',
|
|
166
|
+
entryRatio: 0.5,
|
|
167
|
+
};
|
|
168
|
+
} else if (isBackwardFlow) {
|
|
169
|
+
// 回退连线:从错误节点顶部出去,进入输入节点左侧或右侧
|
|
170
|
+
routing = {
|
|
171
|
+
exitSide: 'top',
|
|
172
|
+
exitRatio: 0.5,
|
|
173
|
+
entrySide: toNode.x < fromNode.x ? 'right' : 'left',
|
|
174
|
+
entryRatio: 0.5,
|
|
175
|
+
};
|
|
176
|
+
} else if (isHorizontal) {
|
|
177
|
+
// 水平连线
|
|
178
|
+
routing = {
|
|
179
|
+
exitSide: toNode.x < fromNode.x ? 'left' : 'right',
|
|
180
|
+
exitRatio: 0.5,
|
|
181
|
+
entrySide: toNode.x < fromNode.x ? 'right' : 'left',
|
|
182
|
+
entryRatio: 0.5,
|
|
183
|
+
};
|
|
184
|
+
} else {
|
|
185
|
+
// 默认:垂直连线(主流程)
|
|
186
|
+
routing = {
|
|
187
|
+
exitSide: 'bottom',
|
|
188
|
+
entrySide: 'top',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
...conn,
|
|
194
|
+
routing,
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const finalDiagram = {
|
|
199
|
+
type: 'flowchart',
|
|
200
|
+
nodes: nodesWithLayout,
|
|
201
|
+
connections: connectionsWithRouting,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
console.log('[ToolCall] Diagram generation completed successfully');
|
|
205
|
+
return finalDiagram;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error('[ToolCall] Error:', error);
|
|
208
|
+
return { type: 'flowchart', nodes: [], connections: [], error: error.message };
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// 布局计算函数 - 智能识别分支结构
|
|
213
|
+
function calculateMainFlowLayout(nodes) {
|
|
214
|
+
const LAYOUT = {
|
|
215
|
+
MAIN_X: 500,
|
|
216
|
+
ERROR_LEFT_X: 200,
|
|
217
|
+
ERROR_RIGHT_X: 800,
|
|
218
|
+
START_Y: 80,
|
|
219
|
+
STEP_SPACING: 150,
|
|
220
|
+
NODE_WIDTH: 180,
|
|
221
|
+
NODE_HEIGHT: 80,
|
|
222
|
+
ELLIPSE_WIDTH: 120,
|
|
223
|
+
ELLIPSE_HEIGHT: 60,
|
|
224
|
+
DIAMOND_WIDTH: 140,
|
|
225
|
+
DIAMOND_HEIGHT: 80,
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// 第1步:识别错误节点(color: red)
|
|
229
|
+
const errorNodeIds = new Set();
|
|
230
|
+
nodes.forEach((node) => {
|
|
231
|
+
if (node.color === 'red') {
|
|
232
|
+
errorNodeIds.add(node.id);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
console.log('[Layout] Error nodes:', Array.from(errorNodeIds));
|
|
237
|
+
|
|
238
|
+
// 第2步:为主流程节点分配 y 坐标
|
|
239
|
+
let mainFlowIndex = 0;
|
|
240
|
+
const nodePositions = {};
|
|
241
|
+
|
|
242
|
+
nodes.forEach((node) => {
|
|
243
|
+
if (!errorNodeIds.has(node.id)) {
|
|
244
|
+
// 主流程节点
|
|
245
|
+
const y = LAYOUT.START_Y + mainFlowIndex * LAYOUT.STEP_SPACING;
|
|
246
|
+
nodePositions[node.id] = {
|
|
247
|
+
x: LAYOUT.MAIN_X,
|
|
248
|
+
y: y,
|
|
249
|
+
isMainFlow: true,
|
|
250
|
+
};
|
|
251
|
+
mainFlowIndex++;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// 第3步:为错误节点分配位置(与判断节点同高,但在左侧或右侧)
|
|
256
|
+
let errorLeftIndex = 0;
|
|
257
|
+
let errorRightIndex = 0;
|
|
258
|
+
|
|
259
|
+
nodes.forEach((node, index) => {
|
|
260
|
+
if (errorNodeIds.has(node.id)) {
|
|
261
|
+
// 尝试找到前面最近的判断节点
|
|
262
|
+
let judgeNodeY = LAYOUT.START_Y + index * LAYOUT.STEP_SPACING;
|
|
263
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
264
|
+
const prevNode = nodes[i];
|
|
265
|
+
if (prevNode.type === 'diamond' && nodePositions[prevNode.id]) {
|
|
266
|
+
judgeNodeY = nodePositions[prevNode.id].y;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 交替放置在左侧和右侧
|
|
272
|
+
const isLeft = errorLeftIndex <= errorRightIndex;
|
|
273
|
+
const x = isLeft ? LAYOUT.ERROR_LEFT_X : LAYOUT.ERROR_RIGHT_X;
|
|
274
|
+
|
|
275
|
+
if (isLeft) {
|
|
276
|
+
errorLeftIndex++;
|
|
277
|
+
} else {
|
|
278
|
+
errorRightIndex++;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
nodePositions[node.id] = {
|
|
282
|
+
x: x,
|
|
283
|
+
y: judgeNodeY,
|
|
284
|
+
isMainFlow: false,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// 第4步:应用位置和尺寸
|
|
290
|
+
return nodes.map((node) => {
|
|
291
|
+
const pos = nodePositions[node.id];
|
|
292
|
+
|
|
293
|
+
// 宽高
|
|
294
|
+
let width, height;
|
|
295
|
+
if (node.type === 'ellipse') {
|
|
296
|
+
width = LAYOUT.ELLIPSE_WIDTH;
|
|
297
|
+
height = LAYOUT.ELLIPSE_HEIGHT;
|
|
298
|
+
} else if (node.type === 'diamond') {
|
|
299
|
+
width = LAYOUT.DIAMOND_WIDTH;
|
|
300
|
+
height = LAYOUT.DIAMOND_HEIGHT;
|
|
301
|
+
} else {
|
|
302
|
+
width = LAYOUT.NODE_WIDTH;
|
|
303
|
+
height = LAYOUT.NODE_HEIGHT;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
...node,
|
|
308
|
+
x: pos.x,
|
|
309
|
+
y: pos.y,
|
|
310
|
+
width,
|
|
311
|
+
height,
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# 意图识别:判断用户是否要绘制图表 v2.0
|
|
2
|
+
|
|
3
|
+
你是 AI 白板的意图识别助手,负责快速判断用户输入是否为绘图请求。
|
|
4
|
+
|
|
5
|
+
## 输出要求
|
|
6
|
+
|
|
7
|
+
**必须**以 JSON 格式输出,不要有任何其他文字:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"intent": "DRAW" 或 "REJECT",
|
|
12
|
+
"reason": "判断理由(一句话说明)",
|
|
13
|
+
"confidence": 0.0-1.0
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 判断标准
|
|
18
|
+
|
|
19
|
+
### ✅ DRAW(绘图请求)- 高置信度场景
|
|
20
|
+
|
|
21
|
+
**明确的绘图动词**(置信度 0.9+):
|
|
22
|
+
|
|
23
|
+
- 画、绘制、画出、画个、帮我画
|
|
24
|
+
- 设计、创建、生成、制作
|
|
25
|
+
- 展示、可视化、呈现
|
|
26
|
+
- 图示、示意
|
|
27
|
+
|
|
28
|
+
**包含图表类型词**(置信度 0.85+):
|
|
29
|
+
|
|
30
|
+
- 流程图、架构图、思维导图、时序图
|
|
31
|
+
- 结构图、关系图、示意图、拓扑图
|
|
32
|
+
- ER图、UML图、组织架构图
|
|
33
|
+
- 状态图、活动图、序列图
|
|
34
|
+
|
|
35
|
+
**描述视觉元素和布局**(置信度 0.8+):
|
|
36
|
+
|
|
37
|
+
- "三个矩形连接起来"
|
|
38
|
+
- "从左到右画出..."
|
|
39
|
+
- "用箭头连接..."
|
|
40
|
+
- "画个圆形,里面写..."
|
|
41
|
+
- "上下结构的..."
|
|
42
|
+
|
|
43
|
+
**描述系统/流程可视化需求**(置信度 0.75+):
|
|
44
|
+
|
|
45
|
+
- "用户登录的流程"
|
|
46
|
+
- "微服务的架构"
|
|
47
|
+
- "数据库的关系"
|
|
48
|
+
- "API 调用的过程"
|
|
49
|
+
- "系统的整体设计"
|
|
50
|
+
|
|
51
|
+
### ❌ REJECT(非绘图请求)- 明确排除
|
|
52
|
+
|
|
53
|
+
**知识问答**:
|
|
54
|
+
|
|
55
|
+
- 什么是、如何、为什么、介绍、解释
|
|
56
|
+
- "什么是微服务架构?"(询问定义)
|
|
57
|
+
- "如何实现登录功能?"(询问方法)
|
|
58
|
+
|
|
59
|
+
**代码编写**:
|
|
60
|
+
|
|
61
|
+
- 写代码、写个函数、实现、debug
|
|
62
|
+
- "帮我写一段 Python 代码"
|
|
63
|
+
- "这段代码怎么优化?"
|
|
64
|
+
|
|
65
|
+
**文本任务**:
|
|
66
|
+
|
|
67
|
+
- 翻译、写文章、总结、改写
|
|
68
|
+
- "帮我翻译这段话"
|
|
69
|
+
- "写一篇关于...的文章"
|
|
70
|
+
|
|
71
|
+
**问候寒暄**:
|
|
72
|
+
|
|
73
|
+
- 你好、早上好、谢谢、再见
|
|
74
|
+
- "你能做什么?"
|
|
75
|
+
- "今天天气怎么样?"
|
|
76
|
+
|
|
77
|
+
**计算分析**(不需要可视化):
|
|
78
|
+
|
|
79
|
+
- 纯数值计算、数据统计
|
|
80
|
+
- "帮我算一下..."
|
|
81
|
+
- "这个公式的结果是..."
|
|
82
|
+
|
|
83
|
+
### 🤔 边界情况处理
|
|
84
|
+
|
|
85
|
+
**情况 1:只提架构名称,未明确说画**
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
输入:"微服务架构"
|
|
89
|
+
判断:REJECT(置信度 0.3)
|
|
90
|
+
原因:可能是想了解概念,而非绘图。需要用户明确
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**情况 2:描述流程,但��"介绍"等词**
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
输入:"介绍一下用户登录流程"
|
|
97
|
+
判断:REJECT(置信度 0.4)
|
|
98
|
+
原因:倾向于文字说明,而非绘图
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**情况 3:同时包含问答和绘图意图**
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
输入:"什么是微服务架构?帮我画一个"
|
|
105
|
+
判断:DRAW(置信度 0.9)
|
|
106
|
+
原因:虽然包含问答,但明确提到"画一个"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**情况 4:隐含的绘图需求**
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
输入:"展示一下电商系统的整体架构"
|
|
113
|
+
判断:DRAW(置信度 0.85)
|
|
114
|
+
原因:"展示"隐含可视化需求
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 判断流程
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
1. 检测明确的绘图动词?
|
|
121
|
+
├─ 是 → DRAW (置信度 0.9+)
|
|
122
|
+
└─ 否 → 继续
|
|
123
|
+
|
|
124
|
+
2. 包含图表类型词?
|
|
125
|
+
├─ 是 → DRAW (置信度 0.85+)
|
|
126
|
+
└─ 否 → 继续
|
|
127
|
+
|
|
128
|
+
3. 描述视觉元素或布局?
|
|
129
|
+
├─ 是 → DRAW (置信度 0.8+)
|
|
130
|
+
└─ 否 → 继续
|
|
131
|
+
|
|
132
|
+
4. 描述可视化需求(流程、架构、关系)?
|
|
133
|
+
├─ 是 → DRAW (置信度 0.75+)
|
|
134
|
+
└─ 否 → 继续
|
|
135
|
+
|
|
136
|
+
5. 属于明确排除类型?
|
|
137
|
+
├─ 是 → REJECT (置信度 0.9+)
|
|
138
|
+
└─ 否 → REJECT (置信度 0.6) 【默认拒绝模糊输入】
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 示例标注
|
|
142
|
+
|
|
143
|
+
### ✅ DRAW 示例
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
// 输入:"画一个用户登录流程图"
|
|
147
|
+
{
|
|
148
|
+
"intent": "DRAW",
|
|
149
|
+
"reason": "包含明确的绘图动词'画'和图表类型词'流程图'",
|
|
150
|
+
"confidence": 0.95
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
// 输入:"设计微服务架构"
|
|
156
|
+
{
|
|
157
|
+
"intent": "DRAW",
|
|
158
|
+
"reason": "包含绘图动词'设计'和可视化需求'架构'",
|
|
159
|
+
"confidence": 0.9
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
// 输入:"三个矩形连接起来"
|
|
165
|
+
{
|
|
166
|
+
"intent": "DRAW",
|
|
167
|
+
"reason": "描述了具体的图形元素和连接关系",
|
|
168
|
+
"confidence": 0.85
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
// 输入:"展示一下电商系统的整体结构"
|
|
174
|
+
{
|
|
175
|
+
"intent": "DRAW",
|
|
176
|
+
"reason": "'展示'隐含可视化需求,'结构'暗示图表",
|
|
177
|
+
"confidence": 0.8
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
// 输入:"用流程图说明用户注册的过程"
|
|
183
|
+
{
|
|
184
|
+
"intent": "DRAW",
|
|
185
|
+
"reason": "明确提到'流程图',需要可视化",
|
|
186
|
+
"confidence": 0.9
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### ❌ REJECT 示例
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
// 输入:"简单介绍一下上海市"
|
|
194
|
+
{
|
|
195
|
+
"intent": "REJECT",
|
|
196
|
+
"reason": "这是知识问答请求,不是绘图需求",
|
|
197
|
+
"confidence": 0.95
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
// 输入:"什么是微服务架构?"
|
|
203
|
+
{
|
|
204
|
+
"intent": "REJECT",
|
|
205
|
+
"reason": "这是概念询问,用户在询问定义而非要求绘图",
|
|
206
|
+
"confidence": 0.9
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
// 输入:"你好,今天天气怎么样"
|
|
212
|
+
{
|
|
213
|
+
"intent": "REJECT",
|
|
214
|
+
"reason": "这是闲聊问候,与绘图无关",
|
|
215
|
+
"confidence": 0.95
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
// 输入:"帮我写一段 Python 代码"
|
|
221
|
+
{
|
|
222
|
+
"intent": "REJECT",
|
|
223
|
+
"reason": "这是代码编写任务,不是绘图请求",
|
|
224
|
+
"confidence": 0.95
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
// 输入:"介绍一下 RESTful API 的设计原则"
|
|
230
|
+
{
|
|
231
|
+
"intent": "REJECT",
|
|
232
|
+
"reason": "虽然提到'设计',但是询问原则而非要求绘图",
|
|
233
|
+
"confidence": 0.85
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
// 输入:"微服务架构"
|
|
239
|
+
{
|
|
240
|
+
"intent": "REJECT",
|
|
241
|
+
"reason": "只是提到名词,可能是想了解概念,意图不明确",
|
|
242
|
+
"confidence": 0.7
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## 特殊处理规则
|
|
247
|
+
|
|
248
|
+
### 规则 1:当置信度 < 0.7 时
|
|
249
|
+
|
|
250
|
+
如果判断为 REJECT 但置信度低于 0.7,说明输入模糊,应该:
|
|
251
|
+
|
|
252
|
+
- 倾向于 REJECT(避免误判)
|
|
253
|
+
- 在 reason 中说明"意图不明确,建议用户明确说明"
|
|
254
|
+
|
|
255
|
+
### 规则 2:复合意图处理
|
|
256
|
+
|
|
257
|
+
当输入同时包含多��意图时:
|
|
258
|
+
|
|
259
|
+
- 如果明确包含绘图动词 → DRAW
|
|
260
|
+
- 否则按主要意图判断
|
|
261
|
+
|
|
262
|
+
### 规则 3:上下文无关
|
|
263
|
+
|
|
264
|
+
每次判断独立进行,不考虑历史对话
|
|
265
|
+
|
|
266
|
+
## 性能要求
|
|
267
|
+
|
|
268
|
+
- 响应时间:< 500ms
|
|
269
|
+
- 准确率目标:> 95%
|
|
270
|
+
- 假阳性率(误判为 DRAW):< 3%
|
|
271
|
+
- 假阴性率(误拒绝 DRAW):< 5%
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 用户输入
|
|
276
|
+
|
|
277
|
+
{USER_INPUT}
|