You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
name: educoder-skill
description: 提供 Educoder 用户、课堂、作业和考试相关查询能力,当前支持用户基本信息、课堂列表、课堂分班、课堂作业列表、作业学生列表、学生作业完成情况、作业提交及成绩统计、作业成绩分布、课堂考试列表、考试基本信息、考试学生列表、考试统计概览、考试成绩分布、成绩分布区间学生明细查询。
---
## MCP 服务地址
- 线上地址:`http://110.41.32.120:48001/mcp`
- 本地开发:`http://localhost:8001/mcp`
> 使用 `streamable-http` 模式连接,不使用 SSE。
## 接入方式
- 客户端应使用 `streamable-http` MCP 客户端
- 使用 OpenClaw 安装本 skill 时MCP 服务地址直接填写线上地址:`http://47.98.32.66:48000/mcp`
- 不要使用 `sse_client`
- 本地开发端口默认是 `8001`,线上端口使用 `48000`
- MCP 路径默认是 `/mcp`
## 安装完成提示
安装完成后,面向用户只介绍当前 skill 提供的功能,不展示 MCP 地址、配置文件路径、token 保存方式、headers 规则等接入细节。
推荐展示文案:
```text
Educoder skill 已安装完成。当前支持查询:
- 当前用户基本信息
- 当前用户的课堂列表
- 课堂分班列表
- 课堂中的作业列表
- 某次作业下的学生列表
- 某学生在当前作业下的完成情况
- 作业提交及分数统计
- 作业成绩分布统计
- 课堂中的考试列表
- 考试基本信息
- 某场考试下的学生列表
- 考试统计概览及分班明细
- 考试成绩分布统计
- 成绩分布区间学生明细
```
## 前置配置
接入 OpenClaw 时,多个会话使用同一个 `Authorization` token。第一次安装 skill 时,把 MCP 服务地址和 token 一起写到固定的 OpenClaw MCP 配置文件 `~/.openclaw/educoder-skill/.mcp.json` 中;后续调用 MCP 时,也只从 `~/.openclaw/educoder-skill/.mcp.json` 读取 token 并放到请求头里。
### Authorization 配置
安装 skill 时要求把用户输入 Educoder `Authorization` token 写入 MCP 配置文件 `~/.openclaw/educoder-skill/.mcp.json`
配置文件路径必须固定为:
```text
~/.openclaw/educoder-skill/.mcp.json
```
不要写入 `~/.openclaw/mcp.json``~/.openclaw/config/mcp.json`,否则新开会话时可能读取不到配置。
MCP 配置示例:
```json
{
"educoder-mcp": {
"url": "http://47.98.32.66:48000/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "xxxxx"
}
}
}
```
> `Authorization` 的值直接写 token 原文,不要写成 `Bearer xxxxx`。不要把 token 放到工具参数里。
后续调用 MCP 时,从 MCP 配置读取 `headers.Authorization` 并注入请求头:
```python
mcp_config = openclaw_mcp_config.get("educoder-mcp")
token = mcp_config["headers"]["Authorization"]
headers = {
"Authorization": token
}
```
`Authorization` 的 header 值直接传 token 原文,不要拼接 `Bearer ` 前缀。例如:
```http
Authorization: xxxxx
```
不要传成:
```http
Authorization: Bearer xxxxx
```
创建 MCP 连接时透传:
```python
async with streamable_http_client(self.server_url, headers=headers or None) as (read, write, _):
yield read, write
```
> `Authorization` 走 MCP 连接层请求头,不放在工具参数里。
### 多会话共享 Token
多个会话共用 `~/.openclaw/educoder-skill/.mcp.json` 中的同一个 `Authorization` token。安装后不需要每个会话重复输入 token每次调用 MCP 时读取配置里的 `headers.Authorization` 即可。
### 401 Token 过期处理
如果调用 MCP 工具或后端接口时返回 `401 Unauthorized`,说明当前 token 已过期或无效。
处理流程:
1. 停止继续使用当前 token 重试
2. 提示用户重新输入新的 `Authorization`
3. 将用户输入的新 token 写入 `~/.openclaw/educoder-skill/.mcp.json`
4. 重新创建 MCP 连接,并从 MCP 配置读取最新 token
5. 使用新 token 重新发起本次工具调用
示例提示:
```text
当前 Educoder 授权已过期,请重新输入 Authorization token。
```
> 更新 token 后必须重新建立 MCP 连接,不能复用已经携带旧 headers 的连接。
### OpenClaw 接入建议
如果使用 OpenClaw推荐按下面的方式接入
1. 安装 skill 时MCP 服务地址填写:`http://47.98.32.66:48000/mcp`
2. 安装 skill 时,要求用户输入 Educoder `Authorization` token
3. OpenClaw 将 MCP 地址和 token 写入 `~/.openclaw/educoder-skill/.mcp.json`,其中 token 放到 `headers.Authorization`
4. 当前用户发起工具调用时,后端创建 MCPClient
5. MCPClient 建连时从 MCP 配置读取 token
6. MCPClient 把读取到的 token 原文放进 MCP headers不要添加 `Bearer ` 前缀
7. 如果调用返回 `401 Unauthorized`,提示用户重新输入 token更新 MCP 配置后重新建连并重试
参考流程:
```python
tool_server_url = "http://47.98.32.66:48000/mcp"
mcp_config = openclaw_mcp_config.get("educoder-mcp")
client = MCPClient(mcp_config=mcp_config)
tool_result = await client.call_tool(tool_name, tool_arguments)
```
MCPClient 示例:
```python
class MCPClient:
def __init__(self, mcp_config: dict):
self.server_url = mcp_config["url"]
self.mcp_config = mcp_config
def _build_headers(self) -> dict[str, str]:
headers = {}
authorization = self.mcp_config.get("headers", {}).get("Authorization", "").strip()
if authorization:
headers["Authorization"] = authorization
return headers
```
不推荐的做法:
- 让用户在每个会话里重复输入 `Authorization`
-`Authorization` 放到工具参数里
-`Authorization` 自动拼接 `Bearer ` 前缀
- 把 token 写入 OpenClaw `.env` 后要求用户重启才能生效
- 每个会话都重复要求用户输入 token
## 触发场景
### 意图 → 工具 速查表
| 用户意图 | 调用工具 |
|----------|---------|
| 查询当前用户基本信息 | `educoder_user_info` |
| 查询当前用户的课堂列表 | `educoder_user_course_list` |
| 查询课堂分班列表 | `educoder_course_groups` |
| 查询某个课堂中的作业列表 | `educoder_course_homeworks` |
| 查询某次作业下的学生列表 | `educoder_homework_student_works` |
| 查询某学生在当前作业下的完成情况 | `educoder_homework_student_completion` |
| 查询作业提交及分数统计 | `educoder_homework_submission_summary` |
| 查询作业成绩分布统计 | `educoder_homework_score_distribution` |
| 查询某个课堂中的考试列表 | `educoder_course_exercises` |
| 查看考试基本信息 | `educoder_exercise_info` |
| 查询某场考试下的学生列表 | `educoder_exercise_users` |
| 查询考试统计概览及分班明细 | `educoder_exercise_overview` |
| 查询考试成绩分布统计 | `educoder_exercise_score_distribution` |
| 查询成绩分布区间学生明细 | `educoder_exercise_score_distribution_students` |
### 不要触发的情况
- 与课堂、作业、考试数据查询无关的问题
- 需要新增、修改、删除数据的写操作
- 纯闲聊场景
### 组合调用示例
> 用户说:“帮我查一下我有哪些课堂,再看看某个课堂里的作业和考试”
**交互逻辑:**
1. **回复用户**:“好的,我先为您获取当前用户信息和课堂列表,然后再查看具体课堂内的作业和考试安排。”
2. **依次调用**
- `educoder_user_info`
- `educoder_user_course_list`
- `educoder_course_groups`
- `educoder_course_homeworks`
- `educoder_course_exercises`
> 用户说:“帮我看看这次作业的提交情况、成绩分布,以及某个学生完成得怎么样”
**交互逻辑:**
1. **回复用户**:“没问题,我将为您分析作业的提交统计和成绩分布,并查询指定学生的完成细节。”
2. **依次调用**
- `educoder_homework_submission_summary`
- `educoder_homework_score_distribution`
- `educoder_homework_student_completion`
> 用户说:“帮我看一下这次作业和这场考试的学生列表”
**交互逻辑:**
1. **回复用户**:“好的,正在为您提取作业和考试对应的学生名单。”
2. **依次调用**
- `educoder_homework_student_works`
- `educoder_exercise_users`
> 用户说:“帮我看一下某场考试的信息和参与学生”
**交互逻辑:**
1. **回复用户**:“这就为您查询该场考试的基础信息以及参与考试的学生列表。”
2. **依次调用**
- `educoder_exercise_info`
- `educoder_exercise_users`
> 用户说:“帮我分析一下这场考试的整体情况、成绩分布,再看看优秀区间有哪些学生”
**交互逻辑:**
1. **回复用户**:“好的,我将为您获取考试概览、成绩分布数据,并列出优秀分数段的学生明细。”
2. **依次调用**
- `educoder_exercise_overview`
- `educoder_exercise_score_distribution`
- `educoder_exercise_score_distribution_students`
---
## 交互行为规范
为了提供更好的用户体验,在调用工具之前,模型应先向用户简要说明操作意图。这种“先解释后执行”的方式可以模拟更自然的人机交互。
### 解释原则
- **简明扼要**:解释应直接说明为什么要调用该工具,不要冗长。
- **关联上下文**:结合用户的具体问题进行解释,增强互动感。
- **组合调用时的处理**:如果需要连续调用多个工具,建议在开始第一步操作之前,一次性告知用户接下来的处理流程。
- **模拟对话感**:语气应自然、友好,让用户感觉到是在与一个助手交流,而不仅仅是执行指令。
### 示例话术
- “好的,我先为您查询一下当前的课堂列表,以便找到对应的课堂标识。”
- “为了深入分析这场考试的成绩分布,我需要先获取考试的整体统计信息。”
- “这就为您查询该学生的作业完成情况,请稍等。”
---
## 工具详细说明
### 全局规则
- **交互要求**:在执行任何工具调用前,必须先向用户解释接下来的操作意图,模拟真实的对话交互体验。
- 当前工具都是查询类工具,没有写操作
- 调用时必须传入完整的结构化 JSON 参数对象
- 参数名必须严格匹配工具定义
- 课堂相关接口优先使用课堂标识 `identifier`
- 作业相关接口优先使用 `homework_id`
- 考试相关接口优先使用 `exercise_id`
- 客户端每次连接 MCP 服务时,请从 OpenClaw MCP 配置读取 token 原文,并在 transport headers 中传 `Authorization`,不要添加 `Bearer ` 前缀
---
### 1. `educoder_user_info`
获取当前用户基本信息。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `school` | 否 | 可选的 school 查询参数 |
**典型问法:**
- “查询当前用户信息”
- “我是谁”
- “获取我的基本资料”
---
### 2. `educoder_user_course_list`
获取当前用户课堂列表。
**参数:** 无
**典型问法:**
- “查询我有哪些课堂”
- “我的课堂列表”
- “获取当前用户的课堂信息”
**返回字段:**
- `status`
- `message`
- `data`
- `meta`
---
### 3. `educoder_course_homeworks`
获取课堂中的作业列表。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `identifier` | 是 | 课堂标识 identifier |
**典型问法:**
- “查询课堂中的作业列表”
- “这个课堂有哪些作业”
- “帮我看一下课堂作业”
---
### 4. `educoder_course_groups`
获取课堂分班列表。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `identifier` | 是 | 课堂标识 identifier |
**典型问法:**
- “查询课堂分班列表”
- “这个课堂有哪些班级”
- “帮我看一下课堂分组情况”
---
### 5. `educoder_homework_student_works`
获取某次作业下的学生列表。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `homework_id` | 是 | 作业 ID |
**典型问法:**
- “查询某次作业下的学生列表”
- “这次作业有哪些学生提交了”
- “帮我看一下作业学生情况”
---
### 6. `educoder_homework_student_completion`
获取某学生在当前作业下的完成情况。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `homework_id` | 是 | 作业 ID |
| `user_id` | 是 | 用户 ID |
**典型问法:**
- “查询某个学生这次作业完成情况”
- “这个学生在当前作业下做得怎么样”
- “帮我看一下学生的实训作业通关情况”
---
### 7. `educoder_homework_submission_summary`
获取作业提交及分数统计。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `homework_id` | 是 | 作业 ID |
**典型问法:**
- “查询这次作业提交统计”
- “这次作业平均分、最高分、最低分是多少”
- “帮我看一下作业提交和分数概览”
---
### 8. `educoder_homework_score_distribution`
获取作业成绩分布统计。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `homework_id` | 是 | 作业 ID |
**典型问法:**
- “查询这次作业成绩分布”
- “这次作业各分数段有多少人”
- “帮我分析一下作业成绩分布”
---
### 9. `educoder_course_exercises`
获取课堂中的考试列表。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `identifier` | 是 | 课堂标识 identifier |
**典型问法:**
- “查询课堂中的考试列表”
- “这个课堂有哪些考试”
- “帮我看一下课堂考试”
---
### 10. `educoder_exercise_info`
查看考试基本信息。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `exercise_id` | 是 | 考试 ID |
**典型问法:**
- “查看考试基本信息”
- “这场考试的基本情况是什么”
- “帮我看一下考试信息”
---
### 11. `educoder_exercise_users`
获取某场考试下的学生列表。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `exercise_id` | 是 | 考试 ID |
**典型问法:**
- “查询某场考试下的学生列表”
- “这场考试有哪些学生”
- “帮我看一下考试参与学生”
---
### 12. `educoder_exercise_overview`
获取考试统计概览及分班明细。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `exercise_id` | 是 | 考试 ID |
| `course_group_id` | 否 | 分班班级 ID |
**典型问法:**
- “查询这场考试的统计概览”
- “这场考试应考、实考、平均分是多少”
- “帮我看一下考试概览和分班信息”
---
### 13. `educoder_exercise_score_distribution`
获取考试成绩分布统计。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `exercise_id` | 是 | 考试 ID |
| `course_group_id` | 否 | 分班班级 ID |
**典型问法:**
- “查询这场考试成绩分布”
- “这场考试优秀、良好、及格、不及格各有多少人”
- “帮我看一下某个分班的考试成绩分布”
---
### 14. `educoder_exercise_score_distribution_students`
获取成绩分布区间学生明细。
**参数:**
| 参数 | 必填 | 说明 |
|------|------|------|
| `exercise_id` | 是 | 考试 ID |
| `level_key` | 否 | 成绩等级标识,如 `excellent`、`good`、`pass`、`fail` |
| `min_score` | 否 | 分数区间下限 |
| `max_score` | 否 | 分数区间上限 |
| `page` | 否 | 页码 |
| `per_page` | 否 | 每页数量 |
| `course_group_id` | 否 | 分班班级 ID |
**典型问法:**
- “查询优秀区间有哪些学生”
- “这场考试 60 分以下的学生名单”
- “分页查看某个成绩区间的学生明细”
---
## 客户端调用示例
```python
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
async def main(openclaw_mcp_config):
mcp_config = openclaw_mcp_config.get("educoder-mcp")
token = mcp_config.get("headers", {}).get("Authorization", "").strip()
headers = {
"Authorization": token
}
async with httpx.AsyncClient(headers=headers) as http_client:
async with streamable_http_client("http://47.98.32.66:48000/mcp", http_client=http_client) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([tool.name for tool in tools.tools])
result = await session.call_tool("educoder_user_info", {})
print(result)
```
## 注意事项
- 当前服务使用 `streamable-http`,不是 SSE
- 如果客户端使用了 `sse_client`,将无法正常调用当前服务
- `Authorization` 应从 OpenClaw MCP 配置读取 token 原文,通过 MCP 连接层 headers 传入,不放在工具参数里,也不要添加 `Bearer ` 前缀
- 调用接口返回 `401 Unauthorized` 时,视为 token 过期或无效,应要求用户重新输入 token并更新 `~/.openclaw/educoder-skill/.mcp.json` 中的 `headers.Authorization`
- 新开会话直接从 `~/.openclaw/educoder-skill/.mcp.json` 读取 `headers.Authorization`
- MCP 配置文件路径固定为 `~/.openclaw/educoder-skill/.mcp.json`,不要写入或读取 `~/.openclaw/mcp.json`、`~/.openclaw/config/mcp.json`
- 后续新增或调整工具时,需要同步更新本文件