---
name: qshuati-api
description: "Q刷题小程序工具,管理空间、题库、章节和题目。当用户要求创建、查询、修改或删除题库相关资源,管理知识点,搜索题目,或对题库平台执行任何 CRUD 操作时使用。需要 EXAM_API_KEY(API KEY)。"
Q刷题 API
Q刷题小程序命令行工具,用于管理题库资源。本工具通过 exam-api.mjs 脚本与 REST API 交互,支持 JSON 输出,方便脚本化和自动处理。
配置
服务地址
服务地址默认使用 https://www.qshuati.xyz,可通过环境变量 EXAM_API_BASE 或 --base-url 覆盖。
API Key
调用任何命令前需先设置 API Key:
export EXAM_API_KEY="<用户提供的JWT token>"
或通过 --api-key TOKEN 参数传入。脚本路径:本 skill 目录下的 scripts/exam-api.mjs。
运行格式:node <skill目录>/scripts/exam-api.mjs <资源> <操作> [参数]
命令列表
用户
node exam-api.mjs user me # 获取当前用户信息
node exam-api.mjs user stats # 用户统计
node exam-api.mjs user calendar [--year 2026 --month 7] # 学习日历
node exam-api.mjs user update --nickname "新名字" # 更新用户信息
空间
node exam-api.mjs spaces list [--with-stats] # 空间列表
node exam-api.mjs spaces get --id 1 # 空间详情
node exam-api.mjs spaces create --name "名称" [--description "描述"] # 创建空间
node exam-api.mjs spaces update --id 1 --name "新名称" # 更新空间
node exam-api.mjs spaces archive --id 1 # 归档空间
node exam-api.mjs spaces unarchive --id 1 # 取消归档
node exam-api.mjs spaces join --code "ABC123" # 加入空间
node exam-api.mjs spaces members --space-id 1 # 成员列表
node exam-api.mjs spaces stats --id 1 # 空间统计
题库
node exam-api.mjs banks list --space-id 1 [--keyword "数学"] # 空间下的题库列表
node exam-api.mjs banks all # 我的所有题库
node exam-api.mjs banks get --id 1 # 题库详情
node exam-api.mjs banks stats --id 1 # 题库统计
node exam-api.mjs banks create --space-id 1 --name "题库名" [--description ""] [--visibility SPACE|PRIVATE] # 创建题库
node exam-api.mjs banks update --id 1 --name "新名称" # 更新题库
node exam-api.mjs banks delete --id 1 # 删除题库
node exam-api.mjs banks import --code "分享码" --space-id 1 # 通过分享码导入题库
章节
node exam-api.mjs chapters list --bank-id 1 # 章节列表
node exam-api.mjs chapters stats --bank-id 1 # 章节统计
node exam-api.mjs chapters get --id 1 # 章节详情
node exam-api.mjs chapters create --bank-id 1 --name "第一章" [--description ""] [--sort 0] # 创建章节
node exam-api.mjs chapters update --id 1 --name "新名称" # 更新章节
node exam-api.mjs chapters delete --id 1 # 删除章节
题目
node exam-api.mjs questions list --chapter-id 1 [--type SINGLE_CHOICE] [--page 1] [--page-size 20]
node exam-api.mjs questions get --id 1 [--include-answer]
node exam-api.mjs questions create --chapter-id 1 --json '<JSON体>'
node exam-api.mjs questions update --id 1 --json '<JSON体>'
node exam-api.mjs questions delete --id 1
node exam-api.mjs questions search --space-id 1 [--keyword "数学"] [--bank-id 1] [--chapter-id 1] [--type SINGLE_CHOICE] [--difficulty 3]
node exam-api.mjs questions ai-parse --content "题目文本" [--type SINGLE_CHOICE]
内容格式规范
stem(题干)、analysis_text(解析)、answer_text(参考答案)字段均使用 Markdown 格式 存储。导入时必须遵循以下规范。
数学公式(LaTeX)
- 行内公式用单
$包裹:$x^2 + y^2 = z^2$ - 独立公式用双
$$包裹,前后各空一行 - 常用示例:
求极限 $\lim_{x \to 0} \frac{\sin x}{x}$ 的值。
二叉树深度公式:
$$d = \lfloor \log_2 n \rfloor + 1$$
代码块
- 行内代码用反引号:
`int arr[]` - 代码块用三反引号 + 语言名:
```c
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
```
换行与列表
- 题干内换行用
\n(JSON 中写\\n) - 有序列表:
1. xxx\n2. xxx - 无序列表:
- xxx\n- xxx
选项内容
- 选项的
content字段也支持 Markdown,如$x^2$、**加粗**等
题型 JSON 模板
1. 单选题 SINGLE_CHOICE
必填:type、stem、options(≥2项,恰好1个 is_correct: true)
{
"type": "SINGLE_CHOICE",
"stem": "Python 中哪个数据结构是不可变的?",
"options": [
{"label": "A", "content": "tuple", "is_correct": true},
{"label": "B", "content": "list", "is_correct": false},
{"label": "C", "content": "str", "is_correct": false},
{"label": "D", "content": "int", "is_correct": false}
],
"analysis_text": "tuple 是不可变序列,list/str/int 均为可变或不同类型。",
"difficulty": 2
}
2. 多选题 MULTI_CHOICE
必填:type、stem、options(≥2项,≥1个 is_correct: true)
{
"type": "MULTI_CHOICE",
"stem": "以下哪些是合法的 Python 变量名?",
"options": [
{"label": "A", "content": "_name", "is_correct": true},
{"label": "B", "content": "2nd_value", "is_correct": false},
{"label": "C", "content": "myVar", "is_correct": true},
{"label": "D", "content": "class", "is_correct": false}
]
}
3. 填空题 FILL_BLANK
必填:type、stem(含 ____ 占位符)、blanks
{
"type": "FILL_BLANK",
"stem": "二叉树的遍历方式有前序、____和后序三种。",
"blanks": [{"blank_index": 1, "answers": ["中序"]}]
}
4. 判断题 TRUE_FALSE
必填:type、stem、correct_bool
{
"type": "TRUE_FALSE",
"stem": "连续函数一定可导。",
"correct_bool": false,
"analysis_text": "反例:$f(x)=|x|$ 在 $x=0$ 处连续但不可导。"
}
5. 简答/编程题 SHORT_ANSWER
必填:type、stem。可选 answer_text 作为参考答案。
{
"type": "SHORT_ANSWER",
"stem": "编写一个 Python 函数实现冒泡排序:\n\n```python\ndef bubble_sort(arr):\n # TODO: 实现冒泡排序\n pass\n```",
"answer_text": "```python\ndef bubble_sort(arr):\n n = len(arr)\n for i in range(n):\n for j in range(0, n-i-1):\n if arr[j] > arr[j+1]:\n arr[j], arr[j+1] = arr[j+1], arr[j]\n return arr\n```",
"analysis_text": "#### 考点:排序算法\n#### 思路:\n1. 双层循环,外层控制轮数\n2. 内层比较相邻元素,交换位置\n3. 每轮将最大元素移到末尾",
"difficulty": 3
}
6. 综合题 COMPOSITE
必填:type、stem(阅读材料/代码)、sub_questions(子题数组)
{
"type": "COMPOSITE",
"stem": "阅读以下 C 代码:\n\n```c\nvoid reverse(LinkList L) {\n LNode *p = L->next;\n L->next = NULL;\n while (p) {\n LNode *q = p->next;\n p->next = L->next;\n L->next = p;\n p = q;\n }\n}\n```",
"analysis_text": "本题考察链表头插法逆置。",
"sub_questions": [
{
"type": "SINGLE_CHOICE",
"stem": "该算法的时间复杂度是?",
"options": [
{"label": "A", "content": "$O(n)$", "is_correct": true},
{"label": "B", "content": "$O(n^2)$", "is_correct": false},
{"label": "C", "content": "$O(\\log n)$", "is_correct": false}
]
},
{
"type": "SHORT_ANSWER",
"stem": "该算法的空间复杂度是多少?为什么?",
"answer_text": "$O(1)$,只使用了常数个额外指针变量 p 和 q。"
}
]
}
通用可选字段
| 字段 | 类型 | 说明 |
|---|---|---|
score |
string | 分值,默认 "1.00" |
difficulty |
int | 难度 1-5 |
source |
string | 来源 |
tags |
string[] | 标签列表 |
批量导入流程
当用户提供文档(docx/pdf/txt)要求导入时:
- 读取文档内容,按题目类型分组
- 为每种题型构造符合上述模板的 JSON(注意格式规范)
- 调用
questions create --chapter-id <ID> --json '<JSON>'逐题创建 - 对于没有标准答案的题目,使用
SHORT_ANSWER类型导入
输出格式
所有命令输出 JSON 到 stdout。错误输出 JSON 到 stderr({error, code})并以非零退出码退出。
完整示例
# 1. 创建空间
node exam-api.mjs spaces create --name "考研数学"
# 2. 在空间下创建题库
node exam-api.mjs banks create --space-id 1 --name "高等数学"
# 3. 创建章节
node exam-api.mjs chapters create --bank-id 1 --name "第一章 函数与极限"
# 4. 创建单选题(含 LaTeX 公式)
node exam-api.mjs questions create --chapter-id 1 --json '{"type":"SINGLE_CHOICE","stem":"求极限 $\\\\lim_{x \\\\to 0} \\\\frac{\\\\sin x}{x}$ 的值。","options":[{"label":"A","content":"0","is_correct":false},{"label":"B","content":"1","is_correct":true},{"label":"C","content":"$\\\\infty$","is_correct":false}]}'
# 5. 创建判断题
node exam-api.mjs questions create --chapter-id 1 --json '{"type":"TRUE_FALSE","stem":"连续函数一定可导。","correct_bool":false,"analysis_text":"反例:$f(x)=|x|$ 在 $x=0$ 处连续但不可导。"}'
# 6. 创建填空题
node exam-api.mjs questions create --chapter-id 1 --json '{"type":"FILL_BLANK","stem":"二叉树的遍历方式有前序、____和后序三种。","blanks":[{"blank_index":1,"answers":["中序"]}]}'
# 7. 创建编程题
node exam-api.mjs questions create --chapter-id 1 --json '{"type":"SHORT_ANSWER","stem":"用 C 语言实现二分查找:\\n\\n```c\\nint binary_search(int arr[], int n, int target) {\\n // 补充代码\\n}\\n```","answer_text":"```c\\nint binary_search(int arr[], int n, int target) {\\n int low = 0, high = n - 1;\\n while (low <= high) {\\n int mid = (low + high) / 2;\\n if (arr[mid] == target) return mid;\\n else if (arr[mid] < target) low = mid + 1;\\n else high = mid - 1;\\n }\\n return -1;\\n}\\n```"}'
# 8. 创建综合题
node exam-api.mjs questions create --chapter-id 1 --json '{"type":"COMPOSITE","stem":"阅读以下代码回答问题:\\n\\n```c\\nvoid reverse(LinkList L) {\\n LNode *p = L->next;\\n L->next = NULL;\\n while (p) {\\n LNode *q = p->next;\\n p->next = L->next;\\n L->next = p;\\n p = q;\\n }\\n}\\n```","sub_questions":[{"type":"SINGLE_CHOICE","stem":"时间复杂度?","options":[{"label":"A","content":"$O(n)$","is_correct":true},{"label":"B","content":"$O(n^2)$","is_correct":false}]},{"type":"SHORT_ANSWER","stem":"空间复杂度?","answer_text":"$O(1)$"}]}'