Files
012-kaopeilian/知识库/Dify工作流-SQL执行器使用指南.md
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

545 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dify工作流 - SQL执行器使用指南
**API端点**`/api/v1/sql/execute`
**支持DELETE操作**:✅ 是
**自动提交事务**:✅ 是
---
## 📋 API端点信息
### 主要端点
```
POST /api/v1/sql/execute
POST /api/v1/sql/execute-simple (简化认证推荐用于Dify)
```
### 认证方式
#### 方式1标准JWT Token/execute
```bash
Authorization: Bearer {access_token}
```
#### 方式2API Key或长期Token/execute-simple✅ 推荐
```bash
# 方式AAPI Key
X-API-Key: dify-2025-kaopeilian
# 方式B长期Token
Authorization: Bearer permanent-token-for-dify-2025
```
---
## ✅ DELETE权限验证
### 权限状态
-**DELETE语句已支持** - 第224行有警告但不阻止执行
-**自动提交事务** - 第145行`await db.commit()`
-**返回影响行数** - 第146-152行返回 `affected_rows`
-**日志记录** - 第154-158行记录操作日志
### 代码验证
```python
# 位置:/root/aiedu/kaopeilian-backend/app/api/v1/sql_executor.py
# 第143-152行写入操作处理
else:
# 写入操作包括DELETE
await db.commit() # ✅ 自动提交
affected_rows = result.rowcount
response_data = {
"type": "execute",
"affected_rows": affected_rows, # ✅ 返回删除行数
"success": True
}
```
---
## 🚀 在Dify中使用
### 方案1HTTP Request节点推荐
#### 节点配置
```yaml
节点名称: 清空资料知识点
节点类型: HTTP Request
URL: http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple
方法: POST
Headers:
Content-Type: application/json
X-API-Key: dify-2025-kaopeilian
Body (JSON):
{
"sql": "DELETE FROM knowledge_points WHERE material_id = {{material_id}}"
}
```
#### 响应格式
```json
{
"code": 200,
"message": "SQL 执行成功",
"data": {
"type": "execute",
"affected_rows": 6,
"success": true
}
}
```
---
### 方案2Code节点Python
```python
import requests
import json
# 配置
api_url = "http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple"
api_key = "dify-2025-kaopeilian"
material_id = {{material_id}}
# 准备SQL
sql = f"DELETE FROM knowledge_points WHERE material_id = {material_id}"
# 发送请求
response = requests.post(
api_url,
headers={
"Content-Type": "application/json",
"X-API-Key": api_key
},
json={"sql": sql}
)
# 解析结果
result = response.json()
if result.get("code") == 200:
data = result.get("data", {})
affected_rows = data.get("affected_rows", 0)
return {
"success": True,
"deleted_count": affected_rows,
"message": f"已删除 {affected_rows} 个知识点"
}
else:
return {
"success": False,
"error": result.get("message", "未知错误"),
"message": "删除失败"
}
```
---
### 方案3使用参数化查询更安全
```yaml
Body (JSON):
{
"sql": "DELETE FROM knowledge_points WHERE material_id = :material_id",
"params": {
"material_id": {{material_id}}
}
}
```
---
## 📝 完整工作流示例
### Dify工作流配置
```yaml
workflow:
name: "重新生成资料知识点"
nodes:
# 节点1清空旧知识点
- id: "clear_old_kp"
name: "清空旧知识点"
type: "http_request"
config:
url: "http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple"
method: "POST"
headers:
Content-Type: "application/json"
X-API-Key: "dify-2025-kaopeilian"
body:
sql: "DELETE FROM knowledge_points WHERE material_id = {{material_id}}"
outputs:
- deleted_count: "{{response.data.affected_rows}}"
# 节点2验证删除结果
- id: "verify_deletion"
name: "验证删除"
type: "http_request"
config:
url: "http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple"
method: "POST"
headers:
Content-Type: "application/json"
X-API-Key: "dify-2025-kaopeilian"
body:
sql: "SELECT COUNT(*) as count FROM knowledge_points WHERE material_id = {{material_id}}"
outputs:
- remaining_count: "{{response.data.rows[0].count}}"
# 节点3获取资料文件内容
- id: "get_material"
name: "获取资料"
type: "http_request"
config:
url: "http://kaopeilian-backend-dev:8000/api/v1/courses/materials/{{material_id}}"
method: "GET"
# 节点4AI分析生成知识点
- id: "ai_analysis"
name: "AI知识点分析"
type: "llm"
config:
model: "gpt-4"
prompt: |
分析以下课程资料,提取知识点:
文件名: {{get_material.data.name}}
内容: {{file_content}}
请提取:
1. 知识点名称
2. 知识点描述
3. 知识点类型(理论知识/诊断设计/操作步骤/沟通话术/案例分析/注意事项/技巧方法/客诉处理)
4. 与主题的关系
返回JSON格式数组形式。
# 节点5批量保存知识点
- id: "save_kp"
name: "保存知识点"
type: "code"
config:
language: "python"
code: |
import requests
import json
api_url = "http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple"
api_key = "dify-2025-kaopeilian"
knowledge_points = {{ai_analysis.output}}
material_id = {{material_id}}
course_id = {{course_id}}
success_count = 0
for kp in knowledge_points:
# 构造INSERT SQL
sql = """
INSERT INTO knowledge_points
(course_id, material_id, name, description, type, source, topic_relation, created_at)
VALUES
(:course_id, :material_id, :name, :description, :type, 1, :topic_relation, NOW())
"""
params = {
"course_id": course_id,
"material_id": material_id,
"name": kp.get("name"),
"description": kp.get("description"),
"type": kp.get("type", "理论知识"),
"topic_relation": kp.get("relation", "")
}
response = requests.post(
api_url,
headers={
"Content-Type": "application/json",
"X-API-Key": api_key
},
json={"sql": sql, "params": params}
)
if response.json().get("code") == 200:
success_count += 1
return {
"success": True,
"total": len(knowledge_points),
"saved": success_count,
"message": f"成功保存 {success_count}/{len(knowledge_points)} 个知识点"
}
```
---
## 🔍 SQL示例
### 1. 删除单个资料的知识点
```json
{
"sql": "DELETE FROM knowledge_points WHERE material_id = 34"
}
```
### 2. 条件删除仅AI生成的
```json
{
"sql": "DELETE FROM knowledge_points WHERE material_id = 34 AND source = 1"
}
```
### 3. 批量删除
```json
{
"sql": "DELETE FROM knowledge_points WHERE material_id IN (34, 35, 36)"
}
```
### 4. 参数化删除(推荐)
```json
{
"sql": "DELETE FROM knowledge_points WHERE material_id = :material_id",
"params": {
"material_id": 34
}
}
```
### 5. 删除并返回数量
```json
{
"sql": "DELETE FROM knowledge_points WHERE material_id = 34"
}
```
**响应**
```json
{
"code": 200,
"data": {
"type": "execute",
"affected_rows": 6,
"success": true
}
}
```
---
## 🔒 安全特性
### 1. 认证要求
- ✅ 必须提供有效的API Key或Token
- ✅ 所有操作都会记录用户ID和操作日志
### 2. SQL验证
- ⚠️ 第224行检查危险操作DELETE、DROP、TRUNCATE、UPDATE
- ⚠️ 仅作为警告,不阻止执行
- 这是设计行为允许Dify工作流执行必要的DELETE操作
### 3. 事务管理
- ✅ 写入操作自动提交事务第145行
- ✅ 异常时自动回滚第168行
### 4. 日志记录
```python
logger.info(
"sql_execute_success",
user_id=current_user.id,
affected_rows=affected_rows
)
```
---
## ❌ 当前问题分析
### 前端显示81个知识点但数据库只有0个
#### 数据库状态
```sql
SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;
-- 结果0
```
#### 可能原因
**1. 浏览器缓存** ⭐ 最可能
- 前端缓存了旧的API响应
- 解决强制刷新Ctrl+Shift+R
**2. 前端代码缓存**
- localStorage/sessionStorage缓存
- 解决:清除缓存
```javascript
localStorage.clear()
sessionStorage.clear()
location.reload(true)
```
**3. API响应缓存**
- Nginx或后端缓存
- 解决:检查响应头,禁用缓存
**4. 查看错误的资料**
- 可能不是资料34
- 解决确认URL中的资料ID
---
## 🔧 排查步骤
### 1. 确认数据库状态
```bash
docker exec kaopeilian-mysql-dev mysql -u root -p'nj861021' kaopeilian \
-e "SELECT COUNT(*) FROM knowledge_points WHERE material_id = 34;"
```
**当前结果**0
### 2. 直接调用API查看响应
```bash
# 获取access_token
TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' \
| jq -r '.data.access_token')
# 查询知识点
curl -s "http://localhost:8000/api/v1/courses/materials/34/knowledge-points" \
-H "Authorization: Bearer $TOKEN" \
| jq '.data | length'
```
**预期结果**0
### 3. 检查前端Network请求
1. 打开浏览器开发者工具F12
2. 切换到Network标签
3. 勾选"Disable cache"
4. 刷新页面
5. 查找知识点API请求
6. 查看Response内容
### 4. 强制清除缓存
```javascript
// 在浏览器控制台执行
localStorage.clear()
sessionStorage.clear()
// 强制刷新所有缓存
caches.keys().then(keys => keys.forEach(key => caches.delete(key)))
location.reload(true)
```
---
## 📊 测试验证
### 测试脚本
```bash
#!/bin/bash
# 测试SQL执行器DELETE功能
API_URL="http://localhost:8000/api/v1/sql/execute-simple"
API_KEY="dify-2025-kaopeilian"
MATERIAL_ID=34
echo "=== 测试1查看删除前的数量 ==="
curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d "{\"sql\": \"SELECT COUNT(*) as count FROM knowledge_points WHERE material_id = $MATERIAL_ID\"}" \
| jq '.data.rows[0].count'
echo ""
echo "=== 测试2执行DELETE ==="
curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d "{\"sql\": \"DELETE FROM knowledge_points WHERE material_id = $MATERIAL_ID\"}" \
| jq '.data.affected_rows'
echo ""
echo "=== 测试3验证删除结果 ==="
curl -s -X POST "$API_URL" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d "{\"sql\": \"SELECT COUNT(*) as count FROM knowledge_points WHERE material_id = $MATERIAL_ID\"}" \
| jq '.data.rows[0].count'
```
---
## ✅ 权限确认总结
### DELETE权限状态
-**API支持DELETE** - `/api/v1/sql/execute``/api/v1/sql/execute-simple`
-**自动提交事务** - 第145行自动commit
-**返回影响行数** - response.data.affected_rows
-**记录操作日志** - 包含user_id和affected_rows
-**支持参数化查询** - 防止SQL注入
-**简化认证方式** - API Key方式适合Dify长期使用
### 使用建议
1. **推荐使用** `/execute-simple` 端点API Key认证
2. **工作流第一步**DELETE清空旧知识点
3. **工作流最后一步**:验证新知识点已保存
4. **日志监控**:检查系统日志确认操作成功
---
## 📚 相关文档
- **API实现**`/root/aiedu/kaopeilian-backend/app/api/v1/sql_executor.py`
- **路由配置**`/root/aiedu/kaopeilian-backend/app/api/v1/__init__.py` (第63行)
- **数据库架构**`/root/aiedu/kaopeilian-backend/数据库架构-统一版.md`
---
## 🔗 数据库连接信息
```
主机: 120.79.247.16
端口: 3307
数据库: kaopeilian
用户: root
密码: nj861021
```
---
## 💡 快速开始
### Dify中的最简配置
**HTTP Request节点**
```yaml
URL: http://kaopeilian-backend-dev:8000/api/v1/sql/execute-simple
Method: POST
Headers:
Content-Type: application/json
X-API-Key: dify-2025-kaopeilian
Body:
{
"sql": "DELETE FROM knowledge_points WHERE material_id = {{material_id}}"
}
```
**验证响应**
```javascript
// 检查删除是否成功
if (response.code === 200 && response.data.success) {
console.log(`已删除 ${response.data.affected_rows} 个知识点`)
}
```
---
**结论**:✅ DELETE权限已完全支持可以直接在Dify工作流中使用