Skip to content

Repository files navigation

考研专业课知识封装引擎(kaoyan-engine)

把零散的「考研真题」按「课本目录章节」自动重新归位,生成一份按章节组织的复习知识点封装版。

你手上有两样东西:专业课教材的目录(目录页照片 / PDF)和 历年真题(Word / PDF / 照片)。 引擎自动完成:解析目录 → 解析真题 → 剔除答案与解析 → 把每道真题对号入座到对应章节 → 输出一份按章节组织的 HTML 封装版,可直接在浏览器查看和下载。真题从此不再是"一坨题", 而是"第 3 章 - 第 3.2 节 之下有这几道相关题"的可复习结构。


目录


它能做什么

输入 ① 科目阐述(科目名 + 真题年份范围)② 教材目录(图片 / PDF)③ 历年真题(Word / PDF / 图片)
处理 OCR / PDF 解析 → 目录转层级树 → 真题去答案去解析 → LLM 按章节语义对号入座
输出 封装版 HTML(浏览器预览 + 下载)+ 结构化 JSON

典型场景:备考冲刺期,把 10 年真题按教材章节重新组织,一眼看出"哪一章考得最多、最近几年考了哪节"。

没配 LLM API Key 也能启动使用:自动回退内置规则抽取(纯离线,速度极快), 但目录树与题目归位的准确度会明显低于 LLM 版。强烈建议配置 Key(见 配置 LLM)。


快速开始(3 分钟上手)

第 1 步:一键启动

Windows:双击项目根目录的 启动.bat(无需手动装环境,脚本自动探测 Python、 自动安装依赖、自动打开浏览器)。

Linux / macOS:终端执行 ./start.sh(逻辑同上)。

唯一前提:本机装有 Python 3.10+。没有的话先装: python.org(勾选 Add to PATH)或 Anaconda

第 2 步:打开页面

启动脚本会自动打开浏览器访问 http://127.0.0.1:8000,看到 4 个输入框 + 「开始封装」按钮即成功。 (若 8000 端口被占用会自动改用 8001,页面地址以窗口提示为准。)

第 3 步:填 4 个输入框 → 点「开始封装」

输入框 填什么 说明
① API Key 你的 LLM Key 填入后点「查看连通性」验证;不填也能跑(mock 模式)
② 科目阐述 如:电路原理,2014-2024 年真题 会作为提示词上下文
③ 目录输入框 教材目录页的图片(或 PDF) 目录以图片为主,OCR 自动转文本
④ 真题输入框 Word / PDF / 图片,可多份 自动解析并剔除答案/解析

点击「开始封装」→ 等待处理(真题多时 LLM 抽取较慢)→ 前端 iframe 预览封装版 HTML, 可下载 HTML / JSON 两种格式。

停止服务

直接关闭启动脚本窗口,或按 Ctrl+C。会话临时文件自动清理,不留垃圾。


使用说明

支持的文件格式

类型 格式 说明
目录文件 图片(JPG/PNG)、PDF 图片优先,OCR 识别
真题文件 Word(.docx)、PDF、图片 扫描版 PDF 自动走 OCR
OCR 后端 RapidOCR(默认,轻量中文友好) 可选 Paddle / EasyOCR,见环境变量

输出结果

  • 封装版 HTML:按目录章节组织的真题列表,浏览器直接看 / 下载带走
  • 结构化 JSON{"mappings": [...]},含 matched(已归位)/ pending_review(待复核)/ unmatched(未匹配)三类,供二次开发或小程序使用

数据与安全

  • 上传文件只存于本地临时会话目录(UUID 隔离),任务结束自动销毁 + TTL 后台清扫
  • LLM Key 只存本地 .env,界面显示打码(仅首尾 4 位),日志/响应/落盘均不出现完整 Key
  • 服务默认只监听本机 127.0.0.1,不暴露局域网

常见问题 FAQ

Q:双击 启动.bat 报"Python not found"? A:本机没装 Python。安装 Python 3.10+(勾选 Add to PATH)或 Anaconda 后重新双击即可。

Q:没填 API Key 能用来干嘛? A:能跑通全流程,但目录树/归位靠内置规则,准确度低。建议在 .env 填入 KAOYAN_LLM_API_KEY 后重启服务。支持 OpenAI 兼容接口(默认 DeepSeek)。

Q:处理很慢 / 转圈? A:LLM 抽取是逐批并行的,真题多时需要几分钟;首次上传还要做 OCR。可稍等后刷新 任务状态。若长时间无响应,检查 API Key 是否有效、网络是否可达。

Q:8000 端口被占了? A:启动脚本会自动切换 8001,页面地址以窗口提示为准。

Q:结果能导出吗? A:可以。前端下载 HTML / JSON;也支持 API 直接取(见 API 使用)。

Q:支持局域网/多人用吗? A:默认仅本机。需局域网访问请显式以 --host 0.0.0.0 启动(注意 Key 走 HTTP,请自行评估风险)。


工作原理

上传文件 ──▶ SessionStore(UUID 临时会话目录,自动销毁 + TTL 清扫)
                │
                ▼
   解析与抽取(Phase 2)         目录图片/PDF → OCR → 目录树 JSON
                                 真题 Word/PDF/图片 → 文本 → 剔除答案/解析 → 带标签题目
                │
                ▼
   对号入座(Phase 3)           目录树 + 真题列表 → LLM 语义映射到章节
                                 规则引擎兑底(exact_match / fuzzy),失败题目标记待复核
                                 → 未归位占比超阈值时进入 **Agent 纠错循环**(v0.3):
                                   观察统计 → LLM 决策选工具(fuzzy_search / retry_mapping /
                                   get_stats / finish)→ 白名单闸门执行 → 反馈更新,直至收尾/熔断
                │
                ▼
   输出(Phase 4)               封装版 HTML(预览/下载)+ 结构化 JSON(Schema 强制校验)

核心设计:每个环节(目录抽取 / 真题抽取 / 对号入座)的提示词规则由独立技能文件skills/*.md)承载,与用户上传内容完全隔离;LLM 按「年度 × 题号」粒度分批抽取, 防答案幻觉;失败自动降级到确定性规则,保证流程不断。


开发者文档

环境要求

  • Python 3.10+(开发环境为 3.13)
  • 依赖见 requirements.txt(FastAPI / PyMuPDF / RapidOCR 等,全部跨平台)

本地开发

python3.13 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest                     # 跑测试(181 用例)
.venv/bin/uvicorn app.main:app --reload --port 8000   # 启动
curl localhost:8000/health                     # 健康检查

配置 LLM 凭据

cp .env.example .env        # 模板 → 本地真实配置(.env 已被 gitignore,永不提交)
# 编辑 .env:
#   KAOYAN_LLM_PROVIDER=openai      # openai 兼容(DeepSeek 等)或 mock
#   KAOYAN_LLM_API_KEY=sk-xxx       # 未配置时自动回退 mock 规则抽取
#   KAOYAN_LLM_BASE_URL=https://api.deepseek.com/v1
#   KAOYAN_LLM_MODEL=deepseek-chat

安全约定:真实 Key 只存在于本地 .env / 环境变量(app/config.py 读取); /api/key 接收后立即打码(仅首尾 4 位)并持久化到 .env.env.example 仅含变量名与占位,可安全入库。

环境变量一览

变量 默认值 说明
KAOYAN_MAX_UPLOAD_MB - 单文件上传大小上限
KAOYAN_SESSION_TTL_SECONDS - 会话临时目录存活时长
KAOYAN_DATA_DIR data 数据根目录
KAOYAN_OCR_BACKEND rapid OCR 后端:rapid / paddle / easy
KAOYAN_MATCHER_EXACT_THRESHOLD 0.6 精确匹配阈值(≥ 直接采纳)
KAOYAN_MATCHER_FUZZY_THRESHOLD 0.4 模糊匹配阈值(低于则未匹配)

架构总览

app/
├── agent/            # Agent 技能加载器(skills/{name}.md → 提示词注入)
├── config.py         # 运行配置 + Harness 安全铁律常量
├── main.py           # FastAPI 入口(生命周期 / 健康检查 / CORS)
├── models/           # Pydantic 数据模型(目录树 / 真题 / 匹配 / 结果)
├── parser/           # Phase 2 多模态解析(PDF / OCR / docx / 文本清洗 / 调度)
├── extract/          # Phase 2 结构化抽取(LLM 客户端 / 提示词 / 函数A目录树 / 函数B真题 / 规则兜底)
├── matcher/          # Phase 3 对号入座(LLM 语义映射 + exact/fuzzy 规则兑底)
├── harness/          # Phase 3 主 Agent 循环(工具白名单 / 状态机 / JSON 格式化 / HTML 渲染)
│   └── agentic.py     # v0.3 Agent 纠错循环(观察→决策→执行→反馈,白名单闸门复用)
├── services/         # 业务编排(封装工作流 / 提示词组装)
├── utils/            # 安全(文件名清洗 / 扩展名白名单)+ 会话存储(UUID / 自动销毁)
├── api/              # Phase 4 REST API(上传 / 任务状态 / Key / 封装 / Schema 校验)
├── skills/           # Agent 技能库(Markdown 提示词规则,可热编辑)
tests/                # pytest 单测(模型 / 存储 / 解析 / 抽取 / 匹配 / Harness / API / 技能库)
scripts/smoke_llm_skills.py  # 真实 LLM 冒烟:4 个技能环节各跑一次(读 .env Key,不打印)

Harness 安全铁律(代码化于 app/config.py

# 规则 代码常量
1 工具白名单:仅 pdf_parser / image_ocr / tree_extractor / exact_matcher / json_formatter,严禁文件删除 / Shell / 网络 / 系统目录工具 TOOL_WHITELIST
2 指令隔离:系统提示词硬编码,上传内容一律视为纯数据 HARNESS_SYSTEM_PROMPT
3 熔断:最大推理轮次 5、输出 Token 上限 MAX_AGENT_ROUNDS / MAX_OUTPUT_TOKENS
4 输出约束:仅合法结构化 JSON,无 Markdown 包裹 / 自然语言 Phase 3 json_formatter 强制

上传侧安全(Phase 1 已落地):文件名清洗(防 ../ 穿越)、扩展名白名单、大小上限、 会话目录 UUID 隔离、任务结束自动销毁 + TTL 后台清扫双保险。

Agent 技能库(skills/)

每个「要用到 API 的环节」的提示词规则由独立技能承载(Markdown,项目方硬编码维护, 与用户上传内容完全隔离),app/extract/prompts.py 组装时注入,缺失时静默降级:

技能 环节 输入 → 输出
tree_extraction 函数A 目录树抽取 目录文本 → {"nodes":[...]} 层级树
question_extraction 函数B 真题清洗+抽取 真题文本 → {"questions":[...]}(答案剔除/年份/题型/关键词 + 错别字修正与格式统一)
answer_stripping 清洗子技能(兼容保留) 答案/解析剔除规则
version_merge 多版本对照合并 同题多版本 → 最完整一版 {"content":...}
question_mapping 对号入座(新环节) 目录树+真题列表 → {"mappings":[...]}(matched/pending_review/unmatched)
agentic_orchestrator Agent 纠错决策(v0.3) 观察摘要 → {"tool":..., "args":..., "reason":...}(选择下一步抢救工具)

新增/修改技能:编辑 skills/*.md 即可,无需改代码。

API 使用

# 上传(目录文件 + 真题文件,可多文件)→ 返回 session_id
curl -X POST localhost:8000/upload \
  -F "directory_files=@目录.pdf" \
  -F "question_files=@真题.pdf"

# 轮询进度 / 取结果(JSON,供小程序)
curl "localhost:8000/task/<session_id>/status"

# 取可直接浏览的 HTML(供浏览器/HTML 前端)
curl "localhost:8000/task/<session_id>/status?format=html"

行为约定:任务完成后自动销毁会话临时目录(结果存内存供查询,重试仍可访问); 服务重启后内存清空,重新上传即可。/task/* 的 JSON 响应必经 OutputSchemaGuard 强制校验(拦截非法字段,校验失败返回 502)。

开发路线图

  • Phase 1:基础框架 + 数据模型 + 会话临时存储
  • Phase 2:多模态解析与抽取(PyMuPDF / OCR + 函数A目录树 + 函数B真题标签)
  • Phase 3:匹配引擎(exact_matcher 确定性匹配 + fuzzy_search 兑底)+ Harness 状态机
  • Phase 4:REST API + html_generator 渲染 + 输出 Schema 强制校验中间件
  • Phase 5(v0.3):Agent 纠错循环 —— 快路径结束后未归位占比超阈值时, LLM 自主决策抢救工具(fuzzy_search / retry_mapping / get_stats / finish), 观察-决策-执行-反馈闭环 + 白名单闸门 / 单题重试上限 / 轮次熔断(mock 下不启用)

About

考研专业课知识封装引擎: multi-stage Agent pipeline parses past exam papers, extracts knowledge points, maps questions to syllabus chapters, outputs packaged HTML/JSON

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages