**知识拆解 (Dify)**：管理员上传课程文件（如 PDF、Word）后，Dify 工作流会自动启动，对文档进行深度分析、拆解、提炼，形成结构化的知识点，写入数据库，为后续的动态考试和课程问答提供数据基础。当然也可手动在课程编辑页面的学习资料与知识点管理中，点击重新分析。
注意是每上传一个文件就启动一次

要启动的是一个 dify 工作流
api 服务器：http://dify.ireborn.com.cn/v1
api 密钥：app-LZhZcMO6CiriLMOLB2PwUGHx
workflow_id：80cc2d27-f028-4bf1-9ac0-59742ae1cdab
api 文档地址（可用 mcp 工具查看）：https://dify.ireborn.com.cn/app/6713de7f-d98d-4f0a-8e1d-5ad8b4496211/develop

需要提交的必填参数（全部必填）：

- file（管理员上传的课程文件，单个文件，需上传）
- course_name（即课程主题）
- course_id（即课程 id）
- material_id（资料ID）

该工作流会拆解知识点后直接写入数据库

## 实现经验（2025-09-23）

### 核心实现

- 后端：`app/services/ai/knowledge_analysis.py` - 知识点分析服务
- API：`POST /api/v1/courses/{id}/reanalyze` - 重新分析接口
- 前端：课程编辑页面添加"重新分析"按钮，上传资料后自动触发

### 关键技术点

1. **文件处理**：先上传文件到Dify获取file_id，再调用工作流
2. **调用格式**：

```python
# 1. 上传文件
POST /files/upload (multipart/form-data)
# 2. 调用工作流  
POST /workflows/run (JSON格式，使用upload_file_id)
```

3. **工作流参数（修正：file 为单对象）**：
```json
{
  "inputs": {
    "file": {"type": "document", "transfer_method": "local_file", "upload_file_id": "file_id"},
    "course_name": "课程标题",
    "course_id": 课程ID,
    "material_id": 资料ID
  },
  "response_mode": "blocking",
  "user": "system_user_{course_id}"
}
```

4. **异步处理**：使用BackgroundTasks避免阻塞用户操作
5. **日志规范**：使用f-string格式，避免关键字参数
6. **网络配置**：将dify.ireborn.com.cn加入no proxy列表

### 验证完成

- ✅ 前端按钮正常工作，API调用成功返回200
- ✅ 后台任务正常执行，文件上传到Dify成功
- ✅ Dify工作流成功触发（workflow_run_id已生成）
- ❌ Dify工作流回调失败：尝试调用 `https://aiedu.ireborn.com.cn/dev-api/system/knowledge`

### 关键发现（2025-09-23）

**问题**: Dify工作流成功启动但执行失败
- 工作流ID: `80cc2d27-f028-4bf1-9ac0-59742ae1cdab`
- 错误: `Reached maximum retries (0) for URL http://localhost:8000/api/v1/system/knowledge`（示例）

**原因**: Dify工作流配置的回调URL需与当前环境一致；在本地联调时应使用本地地址

**解决方案**:
1. 修改Dify工作流配置，将回调URL改为本地地址: `http://localhost:8000/api/v1/system/knowledge`
2. 或者在公网环境部署API端点供Dify回调

**已创建回调API**: `POST /api/v1/system/knowledge` - 接收Dify工作流的知识点数据

workflow_id: 80cc2d27-f028-4bf1-9ac0-59742ae1cdab