From 55314d2f951c4149e34bab0c0e181f1dc38751b9 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Fri, 4 Sep 2026 09:10:14 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20project-understandin?= =?UTF-8?q?g.md=20=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding.md | 206 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 project-understanding.md diff --git a/project-understanding.md b/project-understanding.md new file mode 100644 index 0000000..561f1e6 --- /dev/null +++ b/project-understanding.md @@ -0,0 +1,206 @@ +一、 +项目定位 +CodeSense是一个面向高校编程教学的AI辅助评测与学习平台 。它把代码提交、受限执行、AI辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 + +主要用户 +1.学生:提交C++程序、查看测试结果和反馈,进入三阶段引导式学习流程,记录自己的思路与解释。 +2.教师:创建和管理作业、组织班级与花名册,查看提交记录、作业完成情况、知识点和能力趋势。 +3.开发者/研究者:在Flask、SQLAlchemy和可替换的AI服务接口上继续扩展评测、教学和数据分析能力。 + +核心问题 +传统OJ的两个痛点正是这个项目要解决的核心问题: +1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense引入受限评测(Causal Sandbox)+ AI辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 +2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense用能力画像(算法、代码风格、功能完整性、执行效率、可读性等维度)和知识点趋势,把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 + +二、 +顶层文件(入口与配置) +run.py:开发启动入口,默认走开发配置 +app.py:应用工厂 +create_app() :注册Blueprint、初始化DB/会话/登录态、ProxyFix、后台任务、访问日志与压缩中间件 +wsgi.py;生产WSGI入口(默认生产配置),配合gunicorn_config.py config.py development / testing / production三套配置,读取.env +models.py:全部ORM模型(见下) +forms.py:Flask-WTF表单定义 +database_maintenance.py:生产一次性建表/迁移/索引维护 +deploy.sh / update.sh / gunicorn_config.py:部署与运维脚本、Gunicorn配置 +routes/ — Web与API路由层(Blueprint) +auth.py:登录/登出/注册/教师邀请,角色认证 +main.py:首页、关于、帮助等基础页面 +assignments.py:作业CRUD、测试用例与提交管理 +thinking.py:三阶段引导式学习(思路/积木/费曼)与阶段Agent API +classes.py:班级、花名册、导入与班级统计 +users.py:用户资料、学生/教师/管理员页面 +grades.py:成绩视图与课程评分 +api.py:提交评测、代码建议、能力分析SSE等REST接口 +services/ — 面向业务的"较厚"服务层 +llm_client.py:智谱/OpenAI多provider客户端、重试、限流与熔断 +ai_evaluator.py:AI评测(含流式能力分析) +api_keys.py:API密钥管理器(不落库明文) +course_grading.py:课程成绩计算 +teacher_analytics.py:教师端班级/知识点学情统计 +teacher_ai_advisor.py:AI学情建议 +demo_database.py / demo_experience.py:公开体验入口的临时SQLite会话隔离与演示数据 +utils/ — 底层工具与核心引擎 +sandbox_runner.py:Causal Sandbox:g++ C++17受限编译/运行、超时与输出限制 +code_evaluator.py:本地ML评分(CodeBERT + TextCNN) +llm_evaluator.py:LLM代码评价 +guidance_generator.py:启发式引导提示生成(不直接给答案) +code_advisor.py:代码建议 +ability_scorer.py / maturity_calculator.py:贝叶斯能力画像与成熟度 +async_tasks.py / sse.py:线程池任务队列+SSE流式推送 +thinking_ai.py:三阶段引导AI交互 +markdown_formatter.py:格式化输出 +prompts.py:提示词模板agents/阶段三费曼/论坛Agent子系统: orchestrator编排、 loop多轮对话、memory、tools、intent/goal/coverage意图与覆盖判定、contracts契约 +auth.py、api.py、validate_testcases.py:认证辅助、通用 API、测试用例校验 +tasks/ — 异步任务 +submission_tasks.py:提交后评测、AI 分析等后台任务; +ability_analysis.py:能力画像的异步计算与分析。 + +前端 +- templates/ :Jinja2页面。含按角色区分的首页/详情页,以及thinking/arena.html (三阶段竞技场)、组件化的多种代码编辑器片段。 +- static/ :CSS、JS(Monaco按需加载、SSE客户端、编辑器/提交/思路对话脚本、安全输出处理器)、图片与第三方库(Sortable、require.min.js)。 +核心模型一览(models.py) +用户与组织:User(学生/教师/管理员)、Class、StudentRoster、InviteToken(教师邀请); +教学资源: Assignment、 AssignmentKnowledgePoint、 TestCase、 AssignmentThinkingPreset(三阶段预设); +学习记录:Submission、ThinkingSession、ThinkingStageLog、StudentQuestion、CodeAdviceRequest ; +画像与学情:AbilityTrend、KnowledgePointScore、TeacherAISuggestion; +平台支撑:SystemLog、SystemConfig、CodeSenseSession(会话持久化)。 +测试(tests/) +覆盖面较广,突出三类特色域:沙箱评测(test_sandbox_features)、演示会话隔离(test_demo_*)、阶段三Agent/论坛(test_stage3_*),另有SSE、成绩、班级花名册、HTTPS代理与性能基线等测试。 +三、核心运行流程、关键数据流或调用链 +1. 应用启动与请求生命周期 +run.py / wsgi.py → app.py 的 create_app() :加载 config 、 db 、注册所有 Blueprint( routes/ )、接入 Flask-Login / Flask-Session、ProxyFix、后台任务队列与压缩/日志中间件。请求进入 Blueprint 路由,经 services/ 编排,落到 utils/ 引擎与数据库。 + +2. 代码提交 → 评测调用链(最重要的一条) +代码提交有两条平行通路: + +A. 网页表单路径(异步,主流) POST /assignments//submit ( routes/assignments.py:483 )→ 创建 Submission(status=pending) → 把任务投进后台线程 evaluate_submission_async() ( tasks/submission_tasks.py )→ 页面跳转到"评测中",由 get_submission_status / SSE 轮询进度。 + +后台线程按序执行(tasks/submission_tasks.py:66-279): +1. AI 基础评估:evaluate_cpp_code()( utils/code_evaluator.py:775 ),内部为启发式评分 calculate_heuristic_score + 可选的LLM反馈,产出 score/feedback ; +2. 沙箱用例评判 : run_test_cases() ( utils/sandbox_runner.py:163 )→ compile_cpp() 用 g++ 按 C++17 编译(15s 超时)→ run_single_test() 逐用例运行(5s 超时、输出长度限制)→ 写回 sandbox_passed/total/detail ; +3. 分数归一 : _normalise_score 把各评测器(0–100/0–10/0–5)统一压到0–5 ; +4. 统计刷新 : _refresh_assignment_stats / _refresh_user_stats 基于全量历史重算,避免种子数据重复累加; +5. 知识点画像 :用作业绑定或 AI 探测出的知识点调 KnowledgePointScore.update_score ; +6. 触发能力分析 : AbilityTrend.mark_as_outdated + trigger_analysis_if_needed() ; +7. 状态置为 evaluated ,写 SystemLog 。 +B. API 路径(同步) POST /api/submit ( routes/api.py:269 ):同步 evaluate_cpp_code + 更新作业统计 + 触发能力分析,直接 JSON 返回 submission_id/score/status 。 + +数据落库: Submission (含 sandbox_* 、 ai_feedback )→ Assignment / User 聚合 → KnowledgePointScore → AbilityTrend 。 + +3. 三阶段引导式学习调用链 +入口 GET /thinking/ ( routes/thinking.py:859 )加载 arena.html : + +1. 会话初始化 : POST /api/start_session 创建 ThinkingSession ,装载 AssignmentThinkingPreset (目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 +2. 阶段一(思路) : /api/stage1/submit → evaluate_description() ( utils/thinking_ai.py )先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 ThinkingStageLog 。 +3. 阶段二(组装) : /api/stage2/verify 验证步骤顺序并把组装结果规整成可编译代码,生成预览;AI 回应统一经 sanitize_response ( utils/thinking_ai.py )做 物理级代码过滤 ——这是提示词约束之外的第二层防泄漏。 +4. 阶段三(费曼/论坛) : /api/stage3/forum/message → Stage3Orchestrator.handle_user_message ( utils/agents/orchestrator.py:50 )→ 意图识别 intent 、目标角色仲裁(学生/教师双 Agent)、 loop 多轮、 tools 追问/探测、 coverage 判定掌握度,SSE 流式返回; /api/stage3/forum/trace 提供轨迹复盘, /api/complete_session 收尾归档。 +5. 全部通过 AI 服务层 SharedLLMClient ( services/llm_client.py ),支持智谱/OpenAI 多 provider 重试、限流、熔断与单飞合并。 +## 4. 能力画像与教师端学情链路 +每次提交都会触发: AbilityTrend.mark_as_outdated → trigger_analysis_if_needed() (防并发 key 去重)→ 后台线程 generate_ability_analysis_async() ( tasks/ability_analysis.py )→ 拉最近 20 条提交 → AIEvaluator.analyze_ability_trend_stream() ( services/ai_evaluator.py:342 )→ 前端经 /api/stream/ability-analysis (SSE, routes/api.py:1195 )流式渲染 Markdown → 结果落回 AbilityTrend 。教师端 teacher_analytics / teacher_ai_advisor 再从班级、知识点维度做聚合视图与建议。 + +AI 统一出口 :所有 AI 请求最终经 services/llm_client.py 的 SharedLLMClient ,避免各调用方各自直连。 +公开体验隔离 : services/demo_database.py 为每次体验建临时 SQLite, demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 +失败可见性 :AI/沙箱失败在体验中一律置 failed ,前端显示"失败/重试",不允许用默认分数伪装成功。 + +四、CodeSense 安装、运行与测试记录 +记录时间 :2026-09-03 环境 :Windows,Python 3.11(项目虚拟环境 .venv ),g++ 16.1.0(MSYS2) 项目 : D:\MyCodesence\CodeSense (CodeSense v1.0.0) + +一、安装 +按 README「快速开始」在项目根目录完成: +py -3.11 -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ +依赖安装成功,共 60 个包,核心版本为 Flask 2.2.3、SQLAlchemy 2.0.52、python-docx 1.2.0、openai 3.7.0、cryptography 41.0.3 等。随后安装 C++ 编译器 g++ 16.1.0(MSYS2),路径 C:\msys64\mingw64\bin\g++.exe ,与项目 utils/sandbox_runner.py 的编译器候选路径一致。 + +过程中遇到的问题与解决 : +1. Python 3.14 兼容性问题 :系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 ast.Str ,启动即报 AttributeError: module 'ast' has no attribute 'Str' 。改用 Python 3.11 创建虚拟环境后解决。 +2. .env 残留 MySQL 配置 : .env 中的 DATABASE_URL 实际仍指向本地 MySQL( user:password@127.0.0.1:3306 ),启动时 db.create_all() 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 +二、运行 +开发配置启动(未设置 DATABASE_URL 时使用本地 SQLite,首次启动自动建表): +.\.venv\Scripts\Activate.ps1 +python run.py +启动结果:数据库初始化成功,异步任务系统初始化成功; Running on http://127.0.0.1:5000 。本机未安装 Redis,会话自动降级为文件系统存储(filesystem),不影响使用。浏览器访问 http://127.0.0.1:5000/login ,登录页提供免注册的学生体验与教师体验入口。 + +说明 :启动日志中的"生产模式:启用 INFO 级别日志"字样由 .env 内 FLASK_DEBUG='False' 引起,实际运行配置为 development (日志显示 Debug mode: on ),不构成问题。 + +三、测试 +安装 pytest 后运行沙箱相关测试: +python -m pytest tests/test_sandbox_features.py -q +结果: 3 passed, 26 warnings in 14.86s 。三项用例全部通过;26 条警告均为框架弃用提示(Flask 2.3 session_cookie_name 、SQLAlchemy Query.get() 等),不影响功能。全量测试集( tests )中的部分用例依赖真实 AI 服务密钥与 Redis,未配置时会失败,属预期行为,未纳入本次验证范围。 + +四、结论 +本项目已在本地 Windows 环境完成安装、成功启动并通过沙箱评测相关测试,代码评测(C++ 编译执行)链路可正常使用;AI 辅助功能需在 .env 配置智谱或 OpenAI 密钥后启用。 + +五、风险疑问和后续需要确定的事项 +1.当前题目中有些错误,如引导式学习的第二部分,给出的题目会多出一些无关内容,且中间完整代码展示处的代码也并不完整,看左侧题目做完后拼凑的代码是完整的,中间的有所缺失,但是能正常运行答出正确问题。 +2.在代码页右侧的ai助手回答会重复 +3.最后代码提交后的评估多是c++的,对c语言的评估不准确 +4.当前codesence的ai响应有点慢,而且用的prompt缘故,回复有点太臃肿感觉,用起来有点卡手:( +5.第二阶段中的请求提示,无法直接确定到我做到哪个题出现了问题,他是根据前面第一阶段给的问题继续从头解释链表并提问的,这样无法直接帮助学生解决当前被卡住的问题,需要到这个问题处才能解释这个问题。我觉得可以把请求提示精确到问题上,直接给这个问题的提示,并提问与当前题目相关的问题辅助学生理解 +6.后续的话我需要学习项目的相关技术栈,逐步了解相关知识。实践经验还是太少了,对项目相关内容好多我看不懂的,希望能逐步赶上学长进度吧 + +六、架构理解 +CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C++ 编程教学」:学生交代码 → 受限沙箱编译运行 → AI 启发式引导学习 → 沉淀能力画像;教师端管理班级/作业并查看学情。架构上采用「路由 → 服务 → 引擎/任务 → 模型」的分层,并配了一套会话级临时 SQLite 的公开演示隔离机制。 + +启动链路与配置 +app.py 是唯一入口,create_app() 应用工厂:加载 config.py(development/testing/production 三套)→ 配置数据库连接池、Session(优先 Redis,失败降级文件系统)→ 初始化 db、Flask-Login、Flask-Session → 注册 8 个蓝图 → 初始化异步任务系统 → 自动建表。 +run.py、wsgi.py、gunicorn_config.py 分别是本地开发、生产 WSGI、Gunicorn 启动配置。 +根级还挂了全局 before_request:单点登录校验和demo 临时库激活(见下)。 +目录分层 +routes/ 蓝图/路由层(页面 + JSON/SSE API):auth、main、assignments、users、classes、api、thinking(三阶段引导式学习)、grades(成绩导出)。只做参数解析、权限校验、编排服务,不写核心逻辑。 +services/ 业务服务层(较新、偏纯逻辑、易单测):LLM 客户端抽象 llm_client.py、AI 评估 ai_evaluator.py、密钥管理 api_keys.py、成绩册 course_grading.py、教师分析 teacher_analytics.py、以及演示数据隔离 demo_database.py + demo_experience.py。 +utils/ 引擎/工具层:代码评测 code_evaluator.py、沙箱执行 sandbox_runner.py、提示词 prompts.py、能力画像 ability_scorer.py、SSE 流 sse.py、权限装饰器 auth.py,以及三阶段 Agent 引擎 utils/agents/。 +tasks/ 后台任务:submission_tasks.py(异步评测)、ability_analysis.py。 +models.py 单一 ORM 文件(~1500 行),约 20 个模型。 +templates/ / static/ Jinja2 模板 + JS/CSS(含 Monaco 编辑器按需加载、SSE 客户端)。 +tests/ pytest 测试,覆盖面很广(sandbox、SSE、demo 隔离、三阶段 agent/forum、成绩路由、性能基线等)。 +关键数据模型(models.py) +角色与组织:User(usertype: 学生/教师/管理员 + RBAC)、Class、StudentRoster(班级花名册)。 +作业与评测:Assignment、TestCase、Submission、AssignmentKnowledgePoint。 +引导式学习:AssignmentThinkingPreset、ThinkingSession、ThinkingStageLog、StudentQuestion。 +画像与分析:AbilityTrend、KnowledgePointScore、TeacherAISuggestion。 +其它:InviteToken、SystemLog、SystemConfig。 +核心子系统 +1.代码评测执行链(Causal Sandbox) +这一段代码评测 +以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、限输出长度、标准化输出比对。调用链大致是: +routes (submit) → tasks/submission_tasks.evaluate_submission_async + → utils/code_evaluator(静态启发式 + 可选 AI 兜底) + → utils/sandbox_runner.run_test_cases(受限编译运行) +注意:仓库已不再依赖本地 CodeBERT/TextCNN 模型(app.py 有明确日志说明),评测走启发式规则 + 已配置 AI 服务。 + +2. AI 服务抽象 +llm_client.py 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;api_keys.py 统一管理密钥。上面的 guidance/advisor/评估都只依赖这一层。 + 对ai助手的回复当前只在thinking_ai.py内做了直接屏蔽,我认为不应该完全屏蔽,可以做一个agent专门监测回复,把和答案直接相关的代码屏蔽掉,而有关知识点的例子代码保留,帮助学生理解,同时可以检查回复是否正确,提高回复的正确率。 + +3. 异步 + SSE +提交后不阻塞请求:任务由线程池执行,前端通过 utils/sse.py 的 SSE 流(如 /api/stream/ability-analysis)拿进度。 + +4. 三阶段引导式学习(thinking) +一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 utils/agents/: + 第三阶段的问答中,我认为可以让老师agent给我一个任务让我给学生agent讲这个知识点,就是直接把我的理解全部讲完。然后让学生agent去提问。如果我给的知识点的大概描述有错误、模糊、缺失的地方,则直接让学生agent提问(即多角度检查)。如果我回答不上来,就可以转向老师agent提问。 + +feynman.py:双角色(教师/学生上下文)Agent 运行时; + 后面我觉得要让这两个智能体共享数据,数据流通模式是俩智能体共享知识,老师给我讲解和提问,我给学生讲解,学生给我提问缺陷处或者难懂处然后给出代码修复,从而构成三元关系,用算法适配 +loop.py Agent 主循环、tools.py 工具、model.py 模型适配; +orchestrator.py 编排、intent.py 意图路由、memory.py 记忆、coverage.py 知识点覆盖评估、goal.py 目标管理、contracts.py 数据契约。 + 自适应学生水平挑选问题的题目可以从咱们设定的ai助手处获取,ai助手给出的回答会生成问题辅助你思考,在此基础上优化题目进题库。然后通过深度学习自适应算法进行分配 +入口路由在 thinking.py,页面在 arena.html。 +5. 公开演示体验隔离(重点设计) +不注册真实账号也能体验:每次进入 /login 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(demo_database.py),由 before_request 按会话激活该库;演示账号(demo:*)走 Flask-Login 的独立 user_loader。demo_experience.py 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除。这就是 AGENTS.md 里 PR worktree 数据隔离约定与之一致的设计。 + +6. 成绩与画像 +作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,ability_scorer + AbilityTrend/KnowledgePointScore)。 + 后续这个网站的情感分析功能(学习态度与积极性)我觉得可以纳入以下几个指标:对ai助手的使用程度评估;对作业开设一个习题复习处,设置复习环节,对复习效果进行评估。最后用算法综合评价该生的学习积极性。 +grades.py + course_grading.py 汇总成绩册并导出 Excel;教师 AI 建议在 teacher_ai_advisor.py。 +安全/运维要点 +权限分三类装饰器:login_required / teacher_required / admin_required。 +单点登录:before_request 比对 session 与库内 current_session_id,发现并发登录强制登出。 +Session 优先 Redis,失败自动降级文件系统;生产强制 SECRET_KEY ≥32、DB_AUTO_INIT=False(需先跑 database_maintenance.py 建表/索引)。 +提供 /healthz、/readyz 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 + +使用的ai工具:trae接入ds-v4-flash +查阅的文件: +https://blog.csdn.net/byxdaz/article/details/147084976?ops_request_misc=elastic_search_misc&request_id=4c0d1eed18c742905a2f455a7e688b3e&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticCommercialInsert~search_v2-1-147084976-null-null.142^v102^pc_search_result_base3&utm_term=msys2&spm=1018.2226.3001.4187 + +https://blog.csdn.net/qq_45712124/article/details/159283588?ops_request_misc=elastic_search_misc&request_id=7e7b8160aaef4b2fc94209e3c3a8befb&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-159283588-null-null.142^v102^pc_search_result_base3&utm_term=git%E5%91%BD%E4%BB%A4&spm=1018.2226.3001.4187 \ No newline at end of file From fde44df5c8c43fc378b26d4c3c376ff947c02c78 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Fri, 4 Sep 2026 22:49:46 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=20project-understandin?= =?UTF-8?q?g.md=EF=BC=9A=E6=8C=89=E8=AF=84=E5=AE=A1=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20AI=20=E8=B0=83=E7=94=A8=E9=93=BE=E4=B8=8E?= =?UTF-8?q?=E8=AF=84=E4=BC=B0=E5=99=A8=E8=A1=A8=E8=BF=B0=E3=80=81=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=20CodeBERT=20=E6=8F=8F=E8=BF=B0=E5=B9=B6=E6=94=B9?= =?UTF-8?q?=E7=94=A8=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84+=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=90=8D=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding.md | 414 ++++++++++++++++++++++----------------- 1 file changed, 232 insertions(+), 182 deletions(-) diff --git a/project-understanding.md b/project-understanding.md index 561f1e6..72c1f6e 100644 --- a/project-understanding.md +++ b/project-understanding.md @@ -1,206 +1,256 @@ -一、 -项目定位 -CodeSense是一个面向高校编程教学的AI辅助评测与学习平台 。它把代码提交、受限执行、AI辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 - -主要用户 -1.学生:提交C++程序、查看测试结果和反馈,进入三阶段引导式学习流程,记录自己的思路与解释。 -2.教师:创建和管理作业、组织班级与花名册,查看提交记录、作业完成情况、知识点和能力趋势。 -3.开发者/研究者:在Flask、SQLAlchemy和可替换的AI服务接口上继续扩展评测、教学和数据分析能力。 - -核心问题 -传统OJ的两个痛点正是这个项目要解决的核心问题: -1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense引入受限评测(Causal Sandbox)+ AI辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 -2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense用能力画像(算法、代码风格、功能完整性、执行效率、可读性等维度)和知识点趋势,把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 - -二、 -顶层文件(入口与配置) -run.py:开发启动入口,默认走开发配置 -app.py:应用工厂 -create_app() :注册Blueprint、初始化DB/会话/登录态、ProxyFix、后台任务、访问日志与压缩中间件 -wsgi.py;生产WSGI入口(默认生产配置),配合gunicorn_config.py config.py development / testing / production三套配置,读取.env -models.py:全部ORM模型(见下) -forms.py:Flask-WTF表单定义 -database_maintenance.py:生产一次性建表/迁移/索引维护 -deploy.sh / update.sh / gunicorn_config.py:部署与运维脚本、Gunicorn配置 -routes/ — Web与API路由层(Blueprint) -auth.py:登录/登出/注册/教师邀请,角色认证 -main.py:首页、关于、帮助等基础页面 -assignments.py:作业CRUD、测试用例与提交管理 -thinking.py:三阶段引导式学习(思路/积木/费曼)与阶段Agent API -classes.py:班级、花名册、导入与班级统计 -users.py:用户资料、学生/教师/管理员页面 -grades.py:成绩视图与课程评分 -api.py:提交评测、代码建议、能力分析SSE等REST接口 -services/ — 面向业务的"较厚"服务层 -llm_client.py:智谱/OpenAI多provider客户端、重试、限流与熔断 -ai_evaluator.py:AI评测(含流式能力分析) -api_keys.py:API密钥管理器(不落库明文) -course_grading.py:课程成绩计算 -teacher_analytics.py:教师端班级/知识点学情统计 -teacher_ai_advisor.py:AI学情建议 -demo_database.py / demo_experience.py:公开体验入口的临时SQLite会话隔离与演示数据 -utils/ — 底层工具与核心引擎 -sandbox_runner.py:Causal Sandbox:g++ C++17受限编译/运行、超时与输出限制 -code_evaluator.py:本地ML评分(CodeBERT + TextCNN) -llm_evaluator.py:LLM代码评价 -guidance_generator.py:启发式引导提示生成(不直接给答案) -code_advisor.py:代码建议 -ability_scorer.py / maturity_calculator.py:贝叶斯能力画像与成熟度 -async_tasks.py / sse.py:线程池任务队列+SSE流式推送 -thinking_ai.py:三阶段引导AI交互 -markdown_formatter.py:格式化输出 -prompts.py:提示词模板agents/阶段三费曼/论坛Agent子系统: orchestrator编排、 loop多轮对话、memory、tools、intent/goal/coverage意图与覆盖判定、contracts契约 -auth.py、api.py、validate_testcases.py:认证辅助、通用 API、测试用例校验 -tasks/ — 异步任务 -submission_tasks.py:提交后评测、AI 分析等后台任务; -ability_analysis.py:能力画像的异步计算与分析。 - -前端 -- templates/ :Jinja2页面。含按角色区分的首页/详情页,以及thinking/arena.html (三阶段竞技场)、组件化的多种代码编辑器片段。 -- static/ :CSS、JS(Monaco按需加载、SSE客户端、编辑器/提交/思路对话脚本、安全输出处理器)、图片与第三方库(Sortable、require.min.js)。 -核心模型一览(models.py) -用户与组织:User(学生/教师/管理员)、Class、StudentRoster、InviteToken(教师邀请); -教学资源: Assignment、 AssignmentKnowledgePoint、 TestCase、 AssignmentThinkingPreset(三阶段预设); -学习记录:Submission、ThinkingSession、ThinkingStageLog、StudentQuestion、CodeAdviceRequest ; -画像与学情:AbilityTrend、KnowledgePointScore、TeacherAISuggestion; -平台支撑:SystemLog、SystemConfig、CodeSenseSession(会话持久化)。 -测试(tests/) -覆盖面较广,突出三类特色域:沙箱评测(test_sandbox_features)、演示会话隔离(test_demo_*)、阶段三Agent/论坛(test_stage3_*),另有SSE、成绩、班级花名册、HTTPS代理与性能基线等测试。 -三、核心运行流程、关键数据流或调用链 -1. 应用启动与请求生命周期 -run.py / wsgi.py → app.py 的 create_app() :加载 config 、 db 、注册所有 Blueprint( routes/ )、接入 Flask-Login / Flask-Session、ProxyFix、后台任务队列与压缩/日志中间件。请求进入 Blueprint 路由,经 services/ 编排,落到 utils/ 引擎与数据库。 - -2. 代码提交 → 评测调用链(最重要的一条) +# CodeSense 项目理解与学习记录 + +## 一、项目定位 + +CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。它把代码提交、受限执行、AI 辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 + +### 主要用户 + +1. 学生:提交 C++ 程序、查看测试结果和反馈,进入三阶段引导式学习流程,记录自己的思路与解释。 +2. 教师:创建和管理作业、组织班级与花名册,查看提交记录、作业完成情况、知识点和能力趋势。 +3. 开发者/研究者:在 Flask、SQLAlchemy 和可替换的 AI 服务接口上继续扩展评测、教学和数据分析能力。 + +### 核心问题 + +传统 OJ 的两个痛点正是这个项目要解决的核心问题: + +1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense 引入受限评测(Causal Sandbox)+ AI 辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 +2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense 用能力画像(算法、代码风格、功能完整性、执行效率、可读性等维度)和知识点趋势,把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 + +## 二、总体结构与目录分层 + +### 顶层文件(入口与配置) + +- `run.py`:开发启动入口,默认走开发配置。 +- `app.py`:应用工厂,`create_app()` 注册 Blueprint、初始化 DB/会话/登录态、ProxyFix、后台任务、访问日志与压缩中间件。 +- `wsgi.py`:生产 WSGI 入口,配合 `gunicorn_config.py`。 +- `config.py`:development / testing / production 三套配置,读取 `.env`。 +- `models.py`:全部 ORM 模型(见下)。 +- `forms.py`:Flask-WTF 表单定义。 +- `database_maintenance.py`:生产一次性建表/迁移/索引维护。 +- `deploy.sh` / `update.sh`:部署与运维脚本。 + +### routes/ — Web 与 API 路由层(Blueprint) + +- `auth.py`:登录/登出/注册/教师邀请,角色认证。 +- `main.py`:首页、关于、帮助等基础页面。 +- `assignments.py`:作业 CRUD、测试用例与提交管理。 +- `thinking.py`:三阶段引导式学习(思路/积木/费曼)与阶段 Agent API。 +- `classes.py`:班级、花名册、导入与班级统计。 +- `users.py`:用户资料、学生/教师/管理员页面。 +- `grades.py`:成绩视图与课程评分。 +- `api.py`:提交评测、代码建议、能力分析 SSE 等 REST 接口。 + +路由层只做参数解析、权限校验与业务编排,不承载核心逻辑。 + +### services/ — 面向业务的"较厚"服务层 + +- `llm_client.py`:统一 LLM 客户端(`SharedLLMClient`),智谱/OpenAI 多 provider 重试、限流与熔断。 +- `ai_evaluator.py`:AI 评测(含流式能力分析)。 +- `api_keys.py`:API 密钥管理器(不落库明文)。 +- `course_grading.py`:课程成绩计算。 +- `teacher_analytics.py`:教师端班级/知识点学情统计。 +- `teacher_ai_advisor.py`:AI 学情建议。 +- `demo_database.py` / `demo_experience.py`:公开体验入口的临时 SQLite 会话隔离与演示数据。 + +### utils/ — 底层工具与核心引擎 + +- `sandbox_runner.py`:Causal Sandbox:g++ C++17 受限编译/运行、超时与输出限制。 +- `code_evaluator.py`:启发式评分 + 可选 LLM 评估叠加。 + (早期版本曾使用 CodeBERT + TextCNN 本地模型评分,当前 main 已移除,相关描述仅见于历史文档/提交。) +- `llm_evaluator.py`:旧版 LLM 评估器 `LLMEvaluator`。注意:它仍自行初始化 provider 客户端并选择 api_type(`zhipu`/`openai`),仅在发请求时委托给 `services/llm_client.py::SharedLLMClient`。 +- `guidance_generator.py`:启发式引导提示生成(不直接给答案)。 +- `code_advisor.py`:代码建议。 +- `ability_scorer.py` / `maturity_calculator.py`:贝叶斯能力画像与成熟度。 +- `async_tasks.py` / `sse.py`:线程池任务队列 + SSE 流式推送。 +- `thinking_ai.py`:三阶段引导 AI 交互。 +- `markdown_formatter.py`:格式化输出。 +- `prompts.py`:提示词模板。 + +### utils/agents/ — 阶段三费曼/论坛 Agent 子系统 + +- `feynman.py`:双角色(教师/学生上下文)Agent 运行时。 +- `loop.py`:Agent 主循环;`tools.py`:工具;`model.py`:模型适配。 +- `orchestrator.py`:编排;`intent.py`:意图路由;`memory.py`:记忆; + `coverage.py`:知识点覆盖判定;`goal.py`:目标管理;`contracts.py`:数据契约。 + +### tasks/ — 异步任务 + +- `submission_tasks.py`:提交后评测、AI 分析等后台任务。 +- `ability_analysis.py`:能力画像的异步计算与分析。 + +### 前端 + +- `templates/`:Jinja2 页面,含按角色区分的首页/详情页,以及 `templates/thinking/arena.html`(三阶段竞技场)、组件化的多种代码编辑器片段。 +- `static/`:CSS、JS(Monaco 按需加载、SSE 客户端、编辑器/提交/思路对话脚本、安全输出处理器)、图片与第三方库(Sortable、require.min.js)。 + +### 核心数据模型一览(models.py) + +- 用户与组织:`User`(学生/教师/管理员 + RBAC)、`Class`、`StudentRoster`、`InviteToken`。 +- 教学资源:`Assignment`、`AssignmentKnowledgePoint`、`TestCase`、`AssignmentThinkingPreset`。 +- 学习记录:`Submission`、`ThinkingSession`、`ThinkingStageLog`、`StudentQuestion`、`CodeAdviceRequest`。 +- 画像与学情:`AbilityTrend`、`KnowledgePointScore`、`TeacherAISuggestion`。 +- 平台支撑:`SystemLog`、`SystemConfig`、`CodeSenseSession`。 + +### 测试(tests/) + +覆盖面较广,突出三类特色域:沙箱评测(`test_sandbox_features`)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理与性能基线等测试。 + +## 三、核心运行流程与调用链 + +### 1. 应用启动与请求生命周期 + +`run.py` / `wsgi.py` → `app.py::create_app`:加载 `config.py`、初始化 db、注册所有 Blueprint(routes/)、接入 Flask-Login / Flask-Session、ProxyFix、后台任务队列与压缩/日志中间件。请求进入 Blueprint 路由,经 services/ 编排,落到 utils/ 引擎与数据库。 + +说明:development 环境在启动时自动建表;production 环境 `DB_AUTO_INIT=False`,需先运行 `database_maintenance.py` 建表/维护索引。 + +### 2. 代码提交 → 评测调用链(最重要的一条) + 代码提交有两条平行通路: -A. 网页表单路径(异步,主流) POST /assignments//submit ( routes/assignments.py:483 )→ 创建 Submission(status=pending) → 把任务投进后台线程 evaluate_submission_async() ( tasks/submission_tasks.py )→ 页面跳转到"评测中",由 get_submission_status / SSE 轮询进度。 +**A. 网页表单路径(异步,主流)** + +`POST /assignments//submit`(`routes/assignments.py::submit_code`)→ 创建 `Submission(status=pending)` → 把任务投进后台线程 `tasks/submission_tasks.py::evaluate_submission_async` → 页面跳转到"评测中",前端经 `get_submission_status`(`routes/api.py`)/ SSE 轮询进度。 + +后台线程按序执行: -后台线程按序执行(tasks/submission_tasks.py:66-279): -1. AI 基础评估:evaluate_cpp_code()( utils/code_evaluator.py:775 ),内部为启发式评分 calculate_heuristic_score + 可选的LLM反馈,产出 score/feedback ; -2. 沙箱用例评判 : run_test_cases() ( utils/sandbox_runner.py:163 )→ compile_cpp() 用 g++ 按 C++17 编译(15s 超时)→ run_single_test() 逐用例运行(5s 超时、输出长度限制)→ 写回 sandbox_passed/total/detail ; -3. 分数归一 : _normalise_score 把各评测器(0–100/0–10/0–5)统一压到0–5 ; -4. 统计刷新 : _refresh_assignment_stats / _refresh_user_stats 基于全量历史重算,避免种子数据重复累加; -5. 知识点画像 :用作业绑定或 AI 探测出的知识点调 KnowledgePointScore.update_score ; -6. 触发能力分析 : AbilityTrend.mark_as_outdated + trigger_analysis_if_needed() ; -7. 状态置为 evaluated ,写 SystemLog 。 -B. API 路径(同步) POST /api/submit ( routes/api.py:269 ):同步 evaluate_cpp_code + 更新作业统计 + 触发能力分析,直接 JSON 返回 submission_id/score/status 。 +1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) +2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时)→ `run_single_test` 逐用例运行(5s 超时、输出长度限制)→ 写回 `sandbox_passed/total/detail`。 +3. 分数归一:`_normalise_score` 把各评测器(0–100/0–10/0–5)统一压到 0–5。 +4. 统计刷新:`_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 +5. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 +6. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`。 +7. 状态置为 evaluated,写 `SystemLog`。 -数据落库: Submission (含 sandbox_* 、 ai_feedback )→ Assignment / User 聚合 → KnowledgePointScore → AbilityTrend 。 +**B. API 路径(同步)** -3. 三阶段引导式学习调用链 -入口 GET /thinking/ ( routes/thinking.py:859 )加载 arena.html : +`POST /api/submit`(`routes/api.py::submit_code`):同步 `evaluate_cpp_code` + 更新作业统计 + 触发能力分析,直接 JSON 返回 submission_id/score/status。 -1. 会话初始化 : POST /api/start_session 创建 ThinkingSession ,装载 AssignmentThinkingPreset (目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 -2. 阶段一(思路) : /api/stage1/submit → evaluate_description() ( utils/thinking_ai.py )先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 ThinkingStageLog 。 -3. 阶段二(组装) : /api/stage2/verify 验证步骤顺序并把组装结果规整成可编译代码,生成预览;AI 回应统一经 sanitize_response ( utils/thinking_ai.py )做 物理级代码过滤 ——这是提示词约束之外的第二层防泄漏。 -4. 阶段三(费曼/论坛) : /api/stage3/forum/message → Stage3Orchestrator.handle_user_message ( utils/agents/orchestrator.py:50 )→ 意图识别 intent 、目标角色仲裁(学生/教师双 Agent)、 loop 多轮、 tools 追问/探测、 coverage 判定掌握度,SSE 流式返回; /api/stage3/forum/trace 提供轨迹复盘, /api/complete_session 收尾归档。 -5. 全部通过 AI 服务层 SharedLLMClient ( services/llm_client.py ),支持智谱/OpenAI 多 provider 重试、限流、熔断与单飞合并。 -## 4. 能力画像与教师端学情链路 -每次提交都会触发: AbilityTrend.mark_as_outdated → trigger_analysis_if_needed() (防并发 key 去重)→ 后台线程 generate_ability_analysis_async() ( tasks/ability_analysis.py )→ 拉最近 20 条提交 → AIEvaluator.analyze_ability_trend_stream() ( services/ai_evaluator.py:342 )→ 前端经 /api/stream/ability-analysis (SSE, routes/api.py:1195 )流式渲染 Markdown → 结果落回 AbilityTrend 。教师端 teacher_analytics / teacher_ai_advisor 再从班级、知识点维度做聚合视图与建议。 +**数据落库**:`Submission`(含 sandbox_*、ai_feedback)→ `Assignment`/`User` 聚合 → `KnowledgePointScore` → `AbilityTrend`。 -AI 统一出口 :所有 AI 请求最终经 services/llm_client.py 的 SharedLLMClient ,避免各调用方各自直连。 -公开体验隔离 : services/demo_database.py 为每次体验建临时 SQLite, demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 -失败可见性 :AI/沙箱失败在体验中一律置 failed ,前端显示"失败/重试",不允许用默认分数伪装成功。 +### 3. 三阶段引导式学习调用链 -四、CodeSense 安装、运行与测试记录 -记录时间 :2026-09-03 环境 :Windows,Python 3.11(项目虚拟环境 .venv ),g++ 16.1.0(MSYS2) 项目 : D:\MyCodesence\CodeSense (CodeSense v1.0.0) +入口 `GET /thinking/`(`routes/thinking.py`)加载 `templates/thinking/arena.html`: + +1. 会话初始化:`POST /api/start_session` 创建 `ThinkingSession`,装载 `AssignmentThinkingPreset`(目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 +2. 阶段一(思路):`POST /api/stage1/submit` → `utils/thinking_ai.py::evaluate_description` 先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 `ThinkingStageLog`。 +3. 阶段二(组装):`POST /api/stage2/verify` 验证步骤顺序并把组装结果规整成可编译代码、生成预览;AI 回应统一经 `utils/thinking_ai.py::sanitize_response` 做物理级代码过滤——这是提示词约束之外的第二层防泄漏。 +4. 阶段三(费曼/论坛):`POST /api/stage3/forum/message` → `utils/agents/orchestrator.py::Stage3Orchestrator.handle_user_message` → intent 意图识别、目标角色仲裁(学生/教师双 Agent)、loop 多轮、tools 追问/探测、coverage 判定掌握度,SSE 流式返回;`POST /api/stage3/forum/trace` 提供轨迹复盘,`POST /api/complete_session` 收尾归档。 + +**AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 + +- 新链路(三阶段对话、能力分析、教师建议等)直接使用 `services/llm_client.py::SharedLLMClient`(多 provider 重试、限流、熔断集中在此)。 +- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。 + +### 4. 能力画像与教师端学情链路 + +每次提交都会触发:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 + +**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 + +**失败可见性**:AI/沙箱失败在体验中一律置 failed,前端显示"失败/重试",不允许用默认分数伪装成功。 + +## 四、架构理解 + +CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C++ 编程教学」:学生交代码 → 受限沙箱编译运行 → AI 启发式引导学习 → 沉淀能力画像;教师端管理班级/作业并查看学情。架构上采用「路由 → 服务 → 引擎/任务 → 模型」的分层,并配了一套会话级临时 SQLite 的公开演示隔离机制。 + +### 分层思路 + +- **routes/**(蓝图/路由层):页面 + JSON/SSE API,只做参数解析、权限校验、编排服务。 +- **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 +- **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 +- **tasks/**:后台任务(异步评测、能力分析)。 +- **models.py**:单一 ORM 文件(约 1500 行,20+ 模型);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 + +### 启动链路与关键机制 + +`app.py` 是唯一入口,`create_app()` 应用工厂:加载 `config.py`(development/testing/production 三套)→ 配置数据库连接池、Session(优先 Redis,失败降级文件系统)→ 初始化 db、Flask-Login、Flask-Session → 注册 8 个蓝图 → 初始化异步任务系统 → 自动建表(development)。根级挂了全局 `before_request`:单点登录校验 + demo 临时库激活。 + +### 核心子系统 + +1. **代码评测执行链(Causal Sandbox)**:以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、限输出长度、标准化输出比对。调用链: + `routes (submit) → tasks/submission_tasks.evaluate_submission_async → utils/code_evaluator(启发式评分 + 可选 LLM 叠加)→ utils/sandbox_runner.run_test_cases(受限编译运行)`。 + 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。 +2. **AI 服务抽象**:`services/llm_client.py::SharedLLMClient` 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;`services/api_keys.py` 统一管理密钥。新链路只依赖这一层;旧评估器 `utils/llm_evaluator.py::LLMEvaluator` 的初始化/选型逻辑仍在旧模块内(见三.3"AI 调用现状")。 +3. **异步 + SSE**:提交后不阻塞请求,任务由线程池执行,前端通过 `utils/sse.py` 的 SSE 流(如 `/api/stream/ability-analysis`)拿进度。 +4. **三阶段引导式学习(thinking)**:一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 `utils/agents/`;入口路由在 `routes/thinking.py`,页面在 `templates/thinking/arena.html`。 +5. **公开演示体验隔离(重点设计)**:不注册真实账号也能体验。每次进入 `/login` 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(`services/demo_database.py`),由 `before_request` 按会话激活该库;演示账号(`demo:*`)走 Flask-Login 的独立 user_loader。`services/demo_experience.py` 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除,与 AGENTS.md 的 PR worktree 数据隔离约定一致。 +6. **成绩与画像**:作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,`ability_scorer` + `AbilityTrend`/`KnowledgePointScore`)。`routes/grades.py` + `services/course_grading.py` 汇总成绩册并导出 Excel;教师 AI 建议在 `services/teacher_ai_advisor.py`。 + +### 安全/运维要点 + +- 权限分三类装饰器:`login_required` / `teacher_required` / `admin_required`。 +- 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 +- Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 +- 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 + +--- + +## 附录 A:个人理解与后续设想(【非现状】,仅代表个人想法) + +> 以下内容不属于当前仓库现状,是学习过程中产生的问题记录与改进设想。 + +1. **对 AI 助手回复过滤的设想**:当前只在 `utils/thinking_ai.py` 内对回复做"物理级代码屏蔽"。我认为不应完全屏蔽:可以做一个 agent 专门监测回复,把与答案直接相关的代码屏蔽掉,而保留与知识点相关的示例代码来帮助学生理解;同时检查回复是否正确,提高回复正确率。 +2. **第三阶段三元角色设想**:目前费曼是"教师/学生"双 Agent。我认为可以让老师 agent 给我一个任务,让我给学生 agent 讲这个知识点,把我的理解完整讲完;学生 agent 再提问。如果我讲的知识点有错误、模糊或缺失,就由学生 agent 多角度追问检查;如果我回答不上来,就转向老师 agent 提问。进一步,希望两个智能体共享数据:老师给我讲解和提问、我给学生讲解、学生指出我讲不清楚处并给出代码修复,构成"老师—我—学生"三元关系,用算法适配这套数据流通。 +3. **自适应选题设想**:可依据 AI 助手互动中生成的追问问题来优化题目并沉淀进题库,再用深度学习/自适应算法按学生水平分配题目。 +4. **情感分析与学习积极性设想**:希望纳入学习态度与积极性评估,指标可包括:对 AI 助手的使用程度;对作业开设习题复习处、设置复习环节并评估复习效果;最后用算法综合评价学生的学习积极性。 +5. **使用中发现的体验问题**: + - 引导式学习第二部分给出的题目会多出一些无关内容,中间完整代码展示处的代码并不完整(左侧按题拼凑的代码完整,中间展示的有所缺失,但能正常运行出正确结果)。 + - 代码页右侧的 AI 助手回答会重复。 + - 代码提交后的评估多是 C++ 向,对 C 语言的评估不够准确。 + - AI 响应较慢,且因 prompt 缘故回复略显臃肿。 + - 第二阶段"请求提示"无法定位学生具体卡在哪个问题:它通常从第一阶段的问题继续从头解释并提问,难以直接帮学生解决当前卡点。设想把请求提示精确到具体问题,直接给该问题的提示并提问与当前题目相关的问题。 +6. **学习计划**:后续需要逐步学习项目相关技术栈,积累实践经验,目前对项目内不少内容理解还不到位,希望能逐步赶上学长进度。 + +## 附录 B:个人安装、运行与测试记录(个人环境备忘) + +- 记录时间:2026-09-03;环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 + +### 安装 -一、安装 按 README「快速开始」在项目根目录完成: + +```powershell py -3.11 -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -依赖安装成功,共 60 个包,核心版本为 Flask 2.2.3、SQLAlchemy 2.0.52、python-docx 1.2.0、openai 3.7.0、cryptography 41.0.3 等。随后安装 C++ 编译器 g++ 16.1.0(MSYS2),路径 C:\msys64\mingw64\bin\g++.exe ,与项目 utils/sandbox_runner.py 的编译器候选路径一致。 +``` + +依赖安装成功,共 60 个包,核心版本为 Flask 2.2.3、SQLAlchemy 2.0.52、python-docx 1.2.0、openai 3.7.0、cryptography 41.0.3 等。随后安装 C++ 编译器 g++ 16.1.0(MSYS2)。 + +过程中遇到的问题与解决: + +1. Python 3.14 兼容性问题:系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 `ast.Str`,启动即报 `AttributeError: module 'ast' has no attribute 'Str'`。改用 Python 3.11 创建虚拟环境后解决。 +2. `.env` 残留 MySQL 配置:`.env` 中的 `DATABASE_URL` 实际仍指向本地 MySQL(user:password@127.0.0.1:3306),启动时 `db.create_all()` 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 + +### 运行 -过程中遇到的问题与解决 : -1. Python 3.14 兼容性问题 :系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 ast.Str ,启动即报 AttributeError: module 'ast' has no attribute 'Str' 。改用 Python 3.11 创建虚拟环境后解决。 -2. .env 残留 MySQL 配置 : .env 中的 DATABASE_URL 实际仍指向本地 MySQL( user:password@127.0.0.1:3306 ),启动时 db.create_all() 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 -二、运行 开发配置启动(未设置 DATABASE_URL 时使用本地 SQLite,首次启动自动建表): + +```powershell .\.venv\Scripts\Activate.ps1 python run.py -启动结果:数据库初始化成功,异步任务系统初始化成功; Running on http://127.0.0.1:5000 。本机未安装 Redis,会话自动降级为文件系统存储(filesystem),不影响使用。浏览器访问 http://127.0.0.1:5000/login ,登录页提供免注册的学生体验与教师体验入口。 +``` -说明 :启动日志中的"生产模式:启用 INFO 级别日志"字样由 .env 内 FLASK_DEBUG='False' 引起,实际运行配置为 development (日志显示 Debug mode: on ),不构成问题。 +启动结果:数据库初始化成功,异步任务系统初始化成功;Running on http://127.0.0.1:5000。本机未安装 Redis,会话自动降级为文件系统存储(filesystem),不影响使用。浏览器访问 http://127.0.0.1:5000/login,登录页提供免注册的学生体验与教师体验入口。 -三、测试 -安装 pytest 后运行沙箱相关测试: +说明:启动日志中的"生产模式:启用 INFO 级别日志"字样由 `.env` 内 `FLASK_DEBUG='False'` 引起,实际运行配置为 development(日志显示 Debug mode: on),不构成问题。 + +### 测试 + +```powershell python -m pytest tests/test_sandbox_features.py -q -结果: 3 passed, 26 warnings in 14.86s 。三项用例全部通过;26 条警告均为框架弃用提示(Flask 2.3 session_cookie_name 、SQLAlchemy Query.get() 等),不影响功能。全量测试集( tests )中的部分用例依赖真实 AI 服务密钥与 Redis,未配置时会失败,属预期行为,未纳入本次验证范围。 +``` -四、结论 -本项目已在本地 Windows 环境完成安装、成功启动并通过沙箱评测相关测试,代码评测(C++ 编译执行)链路可正常使用;AI 辅助功能需在 .env 配置智谱或 OpenAI 密钥后启用。 +结果:3 passed, 26 warnings in 14.86s。三项用例全部通过;26 条警告均为框架弃用提示(Flask 2.3 session_cookie_name、SQLAlchemy Query.get() 等),不影响功能。全量测试集(tests)中的部分用例依赖真实 AI 服务密钥与 Redis,未配置时会失败,属预期行为,未纳入本次验证范围。 -五、风险疑问和后续需要确定的事项 -1.当前题目中有些错误,如引导式学习的第二部分,给出的题目会多出一些无关内容,且中间完整代码展示处的代码也并不完整,看左侧题目做完后拼凑的代码是完整的,中间的有所缺失,但是能正常运行答出正确问题。 -2.在代码页右侧的ai助手回答会重复 -3.最后代码提交后的评估多是c++的,对c语言的评估不准确 -4.当前codesence的ai响应有点慢,而且用的prompt缘故,回复有点太臃肿感觉,用起来有点卡手:( -5.第二阶段中的请求提示,无法直接确定到我做到哪个题出现了问题,他是根据前面第一阶段给的问题继续从头解释链表并提问的,这样无法直接帮助学生解决当前被卡住的问题,需要到这个问题处才能解释这个问题。我觉得可以把请求提示精确到问题上,直接给这个问题的提示,并提问与当前题目相关的问题辅助学生理解 -6.后续的话我需要学习项目的相关技术栈,逐步了解相关知识。实践经验还是太少了,对项目相关内容好多我看不懂的,希望能逐步赶上学长进度吧 +### 结论 -六、架构理解 -CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C++ 编程教学」:学生交代码 → 受限沙箱编译运行 → AI 启发式引导学习 → 沉淀能力画像;教师端管理班级/作业并查看学情。架构上采用「路由 → 服务 → 引擎/任务 → 模型」的分层,并配了一套会话级临时 SQLite 的公开演示隔离机制。 +本项目已在本地 Windows 环境完成安装、成功启动并通过沙箱评测相关测试,代码评测(C++ 编译执行)链路可正常使用;AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用。 + +### 个人工具与参考资料 -启动链路与配置 -app.py 是唯一入口,create_app() 应用工厂:加载 config.py(development/testing/production 三套)→ 配置数据库连接池、Session(优先 Redis,失败降级文件系统)→ 初始化 db、Flask-Login、Flask-Session → 注册 8 个蓝图 → 初始化异步任务系统 → 自动建表。 -run.py、wsgi.py、gunicorn_config.py 分别是本地开发、生产 WSGI、Gunicorn 启动配置。 -根级还挂了全局 before_request:单点登录校验和demo 临时库激活(见下)。 -目录分层 -routes/ 蓝图/路由层(页面 + JSON/SSE API):auth、main、assignments、users、classes、api、thinking(三阶段引导式学习)、grades(成绩导出)。只做参数解析、权限校验、编排服务,不写核心逻辑。 -services/ 业务服务层(较新、偏纯逻辑、易单测):LLM 客户端抽象 llm_client.py、AI 评估 ai_evaluator.py、密钥管理 api_keys.py、成绩册 course_grading.py、教师分析 teacher_analytics.py、以及演示数据隔离 demo_database.py + demo_experience.py。 -utils/ 引擎/工具层:代码评测 code_evaluator.py、沙箱执行 sandbox_runner.py、提示词 prompts.py、能力画像 ability_scorer.py、SSE 流 sse.py、权限装饰器 auth.py,以及三阶段 Agent 引擎 utils/agents/。 -tasks/ 后台任务:submission_tasks.py(异步评测)、ability_analysis.py。 -models.py 单一 ORM 文件(~1500 行),约 20 个模型。 -templates/ / static/ Jinja2 模板 + JS/CSS(含 Monaco 编辑器按需加载、SSE 客户端)。 -tests/ pytest 测试,覆盖面很广(sandbox、SSE、demo 隔离、三阶段 agent/forum、成绩路由、性能基线等)。 -关键数据模型(models.py) -角色与组织:User(usertype: 学生/教师/管理员 + RBAC)、Class、StudentRoster(班级花名册)。 -作业与评测:Assignment、TestCase、Submission、AssignmentKnowledgePoint。 -引导式学习:AssignmentThinkingPreset、ThinkingSession、ThinkingStageLog、StudentQuestion。 -画像与分析:AbilityTrend、KnowledgePointScore、TeacherAISuggestion。 -其它:InviteToken、SystemLog、SystemConfig。 -核心子系统 -1.代码评测执行链(Causal Sandbox) -这一段代码评测 -以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、限输出长度、标准化输出比对。调用链大致是: -routes (submit) → tasks/submission_tasks.evaluate_submission_async - → utils/code_evaluator(静态启发式 + 可选 AI 兜底) - → utils/sandbox_runner.run_test_cases(受限编译运行) -注意:仓库已不再依赖本地 CodeBERT/TextCNN 模型(app.py 有明确日志说明),评测走启发式规则 + 已配置 AI 服务。 - -2. AI 服务抽象 -llm_client.py 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;api_keys.py 统一管理密钥。上面的 guidance/advisor/评估都只依赖这一层。 - 对ai助手的回复当前只在thinking_ai.py内做了直接屏蔽,我认为不应该完全屏蔽,可以做一个agent专门监测回复,把和答案直接相关的代码屏蔽掉,而有关知识点的例子代码保留,帮助学生理解,同时可以检查回复是否正确,提高回复的正确率。 - -3. 异步 + SSE -提交后不阻塞请求:任务由线程池执行,前端通过 utils/sse.py 的 SSE 流(如 /api/stream/ability-analysis)拿进度。 - -4. 三阶段引导式学习(thinking) -一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 utils/agents/: - 第三阶段的问答中,我认为可以让老师agent给我一个任务让我给学生agent讲这个知识点,就是直接把我的理解全部讲完。然后让学生agent去提问。如果我给的知识点的大概描述有错误、模糊、缺失的地方,则直接让学生agent提问(即多角度检查)。如果我回答不上来,就可以转向老师agent提问。 - -feynman.py:双角色(教师/学生上下文)Agent 运行时; - 后面我觉得要让这两个智能体共享数据,数据流通模式是俩智能体共享知识,老师给我讲解和提问,我给学生讲解,学生给我提问缺陷处或者难懂处然后给出代码修复,从而构成三元关系,用算法适配 -loop.py Agent 主循环、tools.py 工具、model.py 模型适配; -orchestrator.py 编排、intent.py 意图路由、memory.py 记忆、coverage.py 知识点覆盖评估、goal.py 目标管理、contracts.py 数据契约。 - 自适应学生水平挑选问题的题目可以从咱们设定的ai助手处获取,ai助手给出的回答会生成问题辅助你思考,在此基础上优化题目进题库。然后通过深度学习自适应算法进行分配 -入口路由在 thinking.py,页面在 arena.html。 -5. 公开演示体验隔离(重点设计) -不注册真实账号也能体验:每次进入 /login 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(demo_database.py),由 before_request 按会话激活该库;演示账号(demo:*)走 Flask-Login 的独立 user_loader。demo_experience.py 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除。这就是 AGENTS.md 里 PR worktree 数据隔离约定与之一致的设计。 - -6. 成绩与画像 -作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,ability_scorer + AbilityTrend/KnowledgePointScore)。 - 后续这个网站的情感分析功能(学习态度与积极性)我觉得可以纳入以下几个指标:对ai助手的使用程度评估;对作业开设一个习题复习处,设置复习环节,对复习效果进行评估。最后用算法综合评价该生的学习积极性。 -grades.py + course_grading.py 汇总成绩册并导出 Excel;教师 AI 建议在 teacher_ai_advisor.py。 -安全/运维要点 -权限分三类装饰器:login_required / teacher_required / admin_required。 -单点登录:before_request 比对 session 与库内 current_session_id,发现并发登录强制登出。 -Session 优先 Redis,失败自动降级文件系统;生产强制 SECRET_KEY ≥32、DB_AUTO_INIT=False(需先跑 database_maintenance.py 建表/索引)。 -提供 /healthz、/readyz 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 - -使用的ai工具:trae接入ds-v4-flash -查阅的文件: -https://blog.csdn.net/byxdaz/article/details/147084976?ops_request_misc=elastic_search_misc&request_id=4c0d1eed18c742905a2f455a7e688b3e&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticCommercialInsert~search_v2-1-147084976-null-null.142^v102^pc_search_result_base3&utm_term=msys2&spm=1018.2226.3001.4187 - -https://blog.csdn.net/qq_45712124/article/details/159283588?ops_request_misc=elastic_search_misc&request_id=7e7b8160aaef4b2fc94209e3c3a8befb&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-159283588-null-null.142^v102^pc_search_result_base3&utm_term=git%E5%91%BD%E4%BB%A4&spm=1018.2226.3001.4187 \ No newline at end of file +- AI 工具:Trae(接入 ds-v4-flash)。 +- 参考资料: + - MSYS2 安装相关: + - Git 命令入门相关: From a44280e098935346bda5acaf2d53c49e2e4ab5b2 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sat, 5 Sep 2026 21:34:46 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20project=E2=80=91unde?= =?UTF-8?q?rstanding.md=20=E9=A1=B9=E7=9B=AE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/project-understanding.md b/project-understanding.md index 72c1f6e..b2c1bdc 100644 --- a/project-understanding.md +++ b/project-understanding.md @@ -15,7 +15,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 传统 OJ 的两个痛点正是这个项目要解决的核心问题: 1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense 引入受限评测(Causal Sandbox)+ AI 辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 -2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense 用能力画像(算法、代码风格、功能完整性、执行效率、可读性等维度)和知识点趋势,把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 +2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense 用两层画像体系沉淀学情:AI 反馈与能力分析文本按算法、代码风格、功能完整性、执行效率、可读性等维度组织(综述存于 `AbilityTrend` 的能力分析内容),可量化的画像则以 C 知识点为单位、经贝叶斯权重更新为 0–100 的 `KnowledgePointScore`。教师端据此把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 ## 二、总体结构与目录分层 @@ -66,6 +66,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 - `thinking_ai.py`:三阶段引导 AI 交互。 - `markdown_formatter.py`:格式化输出。 - `prompts.py`:提示词模板。 +- `auth.py` / `api.py` / `validate_testcases.py`:权限装饰器、通用 API 辅助与测试用例校验。 ### utils/agents/ — 阶段三费曼/论坛 Agent 子系统 @@ -110,17 +111,16 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 **A. 网页表单路径(异步,主流)** -`POST /assignments//submit`(`routes/assignments.py::submit_code`)→ 创建 `Submission(status=pending)` → 把任务投进后台线程 `tasks/submission_tasks.py::evaluate_submission_async` → 页面跳转到"评测中",前端经 `get_submission_status`(`routes/api.py`)/ SSE 轮询进度。 +`POST /submit/`(`routes/assignments.py::submit_code`,蓝图无 url_prefix)→ 创建 `Submission(status=pending)` → 把任务投进后台线程 `tasks/submission_tasks.py::evaluate_submission_async` → 页面跳转到"评测中",前端经 `get_submission_status`(`routes/api.py`)/ SSE 轮询进度。 后台线程按序执行: -1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) -2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时)→ `run_single_test` 逐用例运行(5s 超时、输出长度限制)→ 写回 `sandbox_passed/total/detail`。 -3. 分数归一:`_normalise_score` 把各评测器(0–100/0–10/0–5)统一压到 0–5。 -4. 统计刷新:`_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 -5. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 -6. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`。 -7. 状态置为 evaluated,写 `SystemLog`。 +1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback 并经 `_normalise_score` 统一归一到 0–5。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) +2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时)→ `run_single_test` 逐用例运行(5s 超时、输出长度限制)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分。 +3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 +4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 +5. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`(内部按键去重防并发)。 +6. 写 `SystemLog`(公开体验会话不写正式库审计日志)。 **B. API 路径(同步)** @@ -132,10 +132,10 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 入口 `GET /thinking/`(`routes/thinking.py`)加载 `templates/thinking/arena.html`: -1. 会话初始化:`POST /api/start_session` 创建 `ThinkingSession`,装载 `AssignmentThinkingPreset`(目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 -2. 阶段一(思路):`POST /api/stage1/submit` → `utils/thinking_ai.py::evaluate_description` 先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 `ThinkingStageLog`。 -3. 阶段二(组装):`POST /api/stage2/verify` 验证步骤顺序并把组装结果规整成可编译代码、生成预览;AI 回应统一经 `utils/thinking_ai.py::sanitize_response` 做物理级代码过滤——这是提示词约束之外的第二层防泄漏。 -4. 阶段三(费曼/论坛):`POST /api/stage3/forum/message` → `utils/agents/orchestrator.py::Stage3Orchestrator.handle_user_message` → intent 意图识别、目标角色仲裁(学生/教师双 Agent)、loop 多轮、tools 追问/探测、coverage 判定掌握度,SSE 流式返回;`POST /api/stage3/forum/trace` 提供轨迹复盘,`POST /api/complete_session` 收尾归档。 +1. 会话初始化:`POST /thinking/api/start_session`(thinking 蓝图 `url_prefix='/thinking'`)创建 `ThinkingSession`,装载 `AssignmentThinkingPreset`(目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 +2. 阶段一(思路):`POST /thinking/api/stage1/submit` → `utils/thinking_ai.py::evaluate_description` 先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 `ThinkingStageLog`。 +3. 阶段二(组装):`POST /thinking/api/stage2/verify` 验证步骤顺序并把组装结果规整成可编译代码、生成预览;AI 回应统一经 `utils/thinking_ai.py::sanitize_response` 做物理级代码过滤——这是提示词约束之外的第二层防泄漏。 +4. 阶段三(费曼/论坛):`POST /thinking/api/stage3/forum/message` → `utils/agents/orchestrator.py::Stage3Orchestrator.handle_user_message` → intent 意图识别、目标角色仲裁(学生/教师双 Agent)、loop 多轮、tools 追问/探测、coverage 判定掌握度,SSE 流式返回;`POST /thinking/api/stage3/forum/trace` 提供轨迹复盘,`POST /thinking/api/complete_session` 收尾归档。 **AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 @@ -144,7 +144,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 ### 4. 能力画像与教师端学情链路 -每次提交都会触发:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 +提交评测成功后(异步/同步两通路一致)即触发能力分析刷新:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 **公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 @@ -160,7 +160,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 - **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 - **tasks/**:后台任务(异步评测、能力分析)。 -- **models.py**:单一 ORM 文件(约 1500 行,20+ 模型);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 +- **models.py**:单一 ORM 文件(约 1500 行、19 个模型);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 ### 启动链路与关键机制 From 04cf3e640619cc998f5fd78135eb81ffc9323635 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sat, 5 Sep 2026 22:26:41 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20project-understandin?= =?UTF-8?q?g.md=EF=BC=9A=E6=8C=89=E8=AF=84=E5=AE=A1=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E7=9C=9F=E5=AE=9E=20C++=20=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=AA=8C=E8=AF=81=E5=B9=B6=E6=94=B6=E7=AA=84?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=BB=93=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修正 test_sandbox_features.py 的分类表述:实为演示数据装载/免密登录/生产禁用,不直接覆盖 C++ 编译执行 - 附录 B 补充 2026-09-05 真实 g++ 16.1.0 编译运行验证(3/3 用例通过) - 收窄结论,明确未验证事项(完整 Web 提交链路与 AI 密钥相关测试) --- project-understanding.md | 41 +++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/project-understanding.md b/project-understanding.md index b2c1bdc..00f75d1 100644 --- a/project-understanding.md +++ b/project-understanding.md @@ -95,7 +95,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 ### 测试(tests/) -覆盖面较广,突出三类特色域:沙箱评测(`test_sandbox_features`)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理与性能基线等测试。 +覆盖面较广,突出三类特色域:沙箱演示特性(`test_sandbox_features`,实为演示数据装载/免密登录/生产禁用三项用例,见附录 B,不直接覆盖 C++ 编译执行)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理与性能基线等测试。 ## 三、核心运行流程与调用链 @@ -204,7 +204,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C ## 附录 B:个人安装、运行与测试记录(个人环境备忘) -- 记录时间:2026-09-03;环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 +- 记录时间:2026-09-03(2026-09-05 按 PR 评审意见补充真实 C++ 编译运行验证与范围说明);环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 ### 安装 @@ -238,15 +238,46 @@ python run.py ### 测试 +**1. 沙箱演示特性自动化测试(pytest)** + ```powershell -python -m pytest tests/test_sandbox_features.py -q +.\.venv\Scripts\python.exe -m pytest tests/test_sandbox_features.py -q +``` + +结果:3 passed, 26 warnings(2026-09-05 本机复测约 60s)。三项用例分别为 `test_seed_demo_data_creation`(演示数据装载)、`test_sandbox_login_flows`(免密登录)、`test_security_prevents_sandbox_in_production`(生产环境禁用沙箱),属于"沙箱(演示)登录与安全特性"测试,**并未调用 g++ 编译运行代码**。另经核对,`tests/test_demo_submission_isolation.py` 中同样对 `run_test_cases` 做了 mock,即 tests/ 目录当前不存在覆盖真实 C++ 编译运行链路的端到端用例。因此此前"通过沙箱评测相关测试即可说明代码评测链路可用"的表述不准确,见下方补充验证。 + +**2. 真实 C++ 编译运行链路验证(2026-09-05 补充,回应评审意见)** + +直接调用 `utils/sandbox_runner.py::run_test_cases`,对一段 C++17 加法程序(`cin` 读入、`cout` 输出)用本机 g++ 编译后运行 3 个用例(含公开与隐藏用例),结果: + +```text +compiler = C:\msys64\mingw64\bin\g++.exe # g++ (MSYS2) 16.1.0,与沙箱候选路径一致 +compiler_available = true, compile_success = true, compile_error = "" +passed 3 / total 3, status = passed +# 各用例 actual_output 与 expected_output 经 _normalize_output 比对一致,单例运行 33–510ms +``` + +验证方式为临时脚本(用后即删): + +```python +from utils.sandbox_runner import run_test_cases + +source = '''#include +using namespace std; +int main() { int a, b; cin >> a >> b; cout << a + b << endl; return 0; }''' + +run_test_cases(source, [ + {'input_data': '3 5\n', 'expected_output': '8', 'id': 1, 'is_public': True}, + {'input_data': '-1 1\n', 'expected_output': '0', 'id': 2, 'is_public': False}, + {'input_data': '100 200\n', 'expected_output': '300', 'id': 3, 'is_public': False}, +]) ``` -结果:3 passed, 26 warnings in 14.86s。三项用例全部通过;26 条警告均为框架弃用提示(Flask 2.3 session_cookie_name、SQLAlchemy Query.get() 等),不影响功能。全量测试集(tests)中的部分用例依赖真实 AI 服务密钥与 Redis,未配置时会失败,属预期行为,未纳入本次验证范围。 +由此可确认:在具备 g++ 的本机环境下,C++17 源码可经沙箱完成编译→运行→输出标准化比对→判定。该验证覆盖引擎层单次编译与运行,**未覆盖完整 Web 提交→后台任务→SSE/轮询→落库链路**(该链路中的 AI 叠加评分依赖真实 AI 密钥)。 ### 结论 -本项目已在本地 Windows 环境完成安装、成功启动并通过沙箱评测相关测试,代码评测(C++ 编译执行)链路可正常使用;AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用。 +本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 ### 个人工具与参考资料 From 8f83c6d71b60a664816cbd6dd67b09e578dce2e6 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sat, 5 Sep 2026 23:41:37 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E6=8C=89=E8=AF=84=E5=AE=A1=E6=84=8F?= =?UTF-8?q?=E8=A7=81=E4=BF=AE=E8=AE=A2=E6=96=87=E6=A1=A3=EF=BC=9A=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E8=B0=83=E7=94=A8=E9=93=BE=E3=80=81=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E8=BF=87=E6=97=B6=E6=8F=8F=E8=BF=B0=E3=80=81=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E4=BB=93=E5=BA=93=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/project-understanding.md b/project-understanding.md index 00f75d1..a45daea 100644 --- a/project-understanding.md +++ b/project-understanding.md @@ -55,7 +55,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 ### utils/ — 底层工具与核心引擎 -- `sandbox_runner.py`:Causal Sandbox:g++ C++17 受限编译/运行、超时与输出限制。 +- `sandbox_runner.py`:Causal Sandbox:g++ C++17 受限编译/运行,15s 编译 / 5s 运行超时,stdout/stderr 各有界读取(各 4096 字节上限、超限即终止进程),用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error` 等)。 - `code_evaluator.py`:启发式评分 + 可选 LLM 评估叠加。 (早期版本曾使用 CodeBERT + TextCNN 本地模型评分,当前 main 已移除,相关描述仅见于历史文档/提交。) - `llm_evaluator.py`:旧版 LLM 评估器 `LLMEvaluator`。注意:它仍自行初始化 provider 客户端并选择 api_type(`zhipu`/`openai`),仅在发请求时委托给 `services/llm_client.py::SharedLLMClient`。 @@ -95,7 +95,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 ### 测试(tests/) -覆盖面较广,突出三类特色域:沙箱演示特性(`test_sandbox_features`,实为演示数据装载/免密登录/生产禁用三项用例,见附录 B,不直接覆盖 C++ 编译执行)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理与性能基线等测试。 +覆盖面较广,突出三类特色域:沙箱演示特性(`test_sandbox_features`,实为演示数据装载/免密登录/生产禁用三项用例,见附录 B,不直接覆盖 C++ 编译执行)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理、性能基线,以及沙箱输出限制的有界进程测试(`test_sandbox_output_limits.py`,mock 编译器、不触发真实 g++,见附录 B)等测试。 ## 三、核心运行流程与调用链 @@ -116,7 +116,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 后台线程按序执行: 1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback 并经 `_normalise_score` 统一归一到 0–5。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) -2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时)→ `run_single_test` 逐用例运行(5s 超时、输出长度限制)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分。 +2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分。 3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 5. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`(内部按键去重防并发)。 @@ -168,9 +168,9 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C ### 核心子系统 -1. **代码评测执行链(Causal Sandbox)**:以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、限输出长度、标准化输出比对。调用链: +1. **代码评测执行链(Causal Sandbox)**:以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、stdout/stderr 各有界读取(各 4096 字节上限,超限即终止进程,不视为正常结束)、标准化输出比对,用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error`)。调用链: `routes (submit) → tasks/submission_tasks.evaluate_submission_async → utils/code_evaluator(启发式评分 + 可选 LLM 叠加)→ utils/sandbox_runner.run_test_cases(受限编译运行)`。 - 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。 + 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。沙箱输出有界化来自上游提交 `fix: bound C++ sandbox stdout and stderr`,配套测试 `tests/test_sandbox_output_limits.py`(mock 编译器、用 Python 解释器进程验证有界进程行为,见附录 B)。 2. **AI 服务抽象**:`services/llm_client.py::SharedLLMClient` 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;`services/api_keys.py` 统一管理密钥。新链路只依赖这一层;旧评估器 `utils/llm_evaluator.py::LLMEvaluator` 的初始化/选型逻辑仍在旧模块内(见三.3"AI 调用现状")。 3. **异步 + SSE**:提交后不阻塞请求,任务由线程池执行,前端通过 `utils/sse.py` 的 SSE 流(如 `/api/stream/ability-analysis`)拿进度。 4. **三阶段引导式学习(thinking)**:一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 `utils/agents/`;入口路由在 `routes/thinking.py`,页面在 `templates/thinking/arena.html`。 @@ -183,6 +183,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 - Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 - 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 +- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示(如"请稍后重试");评测页前端轮询设 60 次上限,超限或队列不可用时明确提示"任务状态暂不可用"。 --- @@ -204,7 +205,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C ## 附录 B:个人安装、运行与测试记录(个人环境备忘) -- 记录时间:2026-09-03(2026-09-05 按 PR 评审意见补充真实 C++ 编译运行验证与范围说明);环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 +- 记录时间:2026-09-03(2026-09-05 按 PR 评审意见补充真实 C++ 编译运行验证与范围说明,并随分支 rebase 至上游 main 后复核新版沙箱引擎);环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 ### 安装 @@ -244,17 +245,17 @@ python run.py .\.venv\Scripts\python.exe -m pytest tests/test_sandbox_features.py -q ``` -结果:3 passed, 26 warnings(2026-09-05 本机复测约 60s)。三项用例分别为 `test_seed_demo_data_creation`(演示数据装载)、`test_sandbox_login_flows`(免密登录)、`test_security_prevents_sandbox_in_production`(生产环境禁用沙箱),属于"沙箱(演示)登录与安全特性"测试,**并未调用 g++ 编译运行代码**。另经核对,`tests/test_demo_submission_isolation.py` 中同样对 `run_test_cases` 做了 mock,即 tests/ 目录当前不存在覆盖真实 C++ 编译运行链路的端到端用例。因此此前"通过沙箱评测相关测试即可说明代码评测链路可用"的表述不准确,见下方补充验证。 +结果:3 passed, 26 warnings(2026-09-05 本机复测约 60s)。三项用例分别为 `test_seed_demo_data_creation`(演示数据装载)、`test_sandbox_login_flows`(免密登录)、`test_security_prevents_sandbox_in_production`(生产环境禁用沙箱),属于"沙箱(演示)登录与安全特性"测试,**并未调用 g++ 编译运行代码**。另经核对,`tests/test_demo_submission_isolation.py` 中同样对 `run_test_cases` 做了 mock;上游 main 新增的 `tests/test_sandbox_output_limits.py`(2026-09-05 本机复测 5 passed in 1.01s)同样把编译器 patch 掉、改用 Python 解释器子进程验证 stdout/stderr 有界截断、超时与退出码等有界进程行为。因此 tests/ 目录当前不存在覆盖真实 C++ 编译运行链路的端到端用例,此前"通过沙箱评测相关测试即可说明代码评测链路可用"的表述不准确,见下方补充验证。 **2. 真实 C++ 编译运行链路验证(2026-09-05 补充,回应评审意见)** -直接调用 `utils/sandbox_runner.py::run_test_cases`,对一段 C++17 加法程序(`cin` 读入、`cout` 输出)用本机 g++ 编译后运行 3 个用例(含公开与隐藏用例),结果: +直接调用 `utils/sandbox_runner.py::run_test_cases`,对一段 C++17 加法程序(`cin` 读入、`cout` 输出)用本机 g++ 编译后运行 3 个用例(含公开与隐藏用例)。该验证在合并上游新版沙箱引擎(有界管道读取,提交 `fix: bound C++ sandbox stdout and stderr`)后于 2026-09-05 复测一致,结果: ```text compiler = C:\msys64\mingw64\bin\g++.exe # g++ (MSYS2) 16.1.0,与沙箱候选路径一致 compiler_available = true, compile_success = true, compile_error = "" passed 3 / total 3, status = passed -# 各用例 actual_output 与 expected_output 经 _normalize_output 比对一致,单例运行 33–510ms +# 各用例 termination_reason = null(正常完成),输出经 _normalize_output 比对一致,单例运行 31–186ms ``` 验证方式为临时脚本(用后即删): @@ -277,7 +278,7 @@ run_test_cases(source, [ ### 结论 -本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 +本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;上游 main 新增的沙箱输出限制有界进程测试 5 项通过(mock 编译器);并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用(合并上游新版沙箱引擎后复测一致)。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 ### 个人工具与参考资料 From 2a6dffbb381e8eb1d6a2ab79af98f9e336f5d086 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 00:03:16 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=20project-understandin?= =?UTF-8?q?g.md=EF=BC=9A=E6=8C=89=E5=AE=9E=E9=99=85=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=B8=E5=AF=B9=E4=BF=AE=E6=AD=A3=203=20=E5=A4=84=E8=A1=A8?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按当前代码核对:_normalise_score 定义于 tasks/submission_tasks.py(非 code_evaluator 内部);评测页轮询超限/队列不可用提示改为代码真实文案(页面标题为任务状态暂时不可用);models.py 澄清为 18 个 ORM 模型 + CodeSenseSession 会话存储类、共 19 个类。 --- project-understanding.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project-understanding.md b/project-understanding.md index a45daea..882d744 100644 --- a/project-understanding.md +++ b/project-understanding.md @@ -115,7 +115,7 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 后台线程按序执行: -1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback 并经 `_normalise_score` 统一归一到 0–5。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) +1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback(统一归一到 0–5 由后续 `tasks/submission_tasks.py` 中的 `_normalise_score` 完成)。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) 2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分。 3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 @@ -160,7 +160,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 - **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 - **tasks/**:后台任务(异步评测、能力分析)。 -- **models.py**:单一 ORM 文件(约 1500 行、19 个模型);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 +- **models.py**:单一 ORM 文件(约 1470 行;含 18 个 ORM 模型与 `CodeSenseSession` 会话存储类,共 19 个类);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 ### 启动链路与关键机制 @@ -183,7 +183,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 - Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 - 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 -- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示(如"请稍后重试");评测页前端轮询设 60 次上限,超限或队列不可用时明确提示"任务状态暂不可用"。 +- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示;评测页前端轮询设 60 次上限(`maxPollAttempts=60`,间隔 2s),超限或队列不可用即停止轮询并提示——超限显示"暂时无法确认评测结果,请稍后刷新或重新提交",队列不可用显示"评测队列暂时不可用,请稍后刷新或重新提交",页面标题均显示"任务状态暂时不可用"。 --- From 0a4b0bab9b9c37d8284d39aa718e1eda65053adc Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 00:11:15 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=20project-understandin?= =?UTF-8?q?g=20=E6=96=87=E6=A1=A3=E5=B9=B6=E6=9B=B4=E5=90=8D=E4=B8=BA=20pr?= =?UTF-8?q?oject-understanding=5Fwjh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按评审意见修正 3 处与代码不符的表述: - _normalise_score 归属:定义于 submission_tasks.py,AI 评估后与沙箱重算后各调用一次 - 评测页轮询 60 次上限及两条真实提示文案 - models.py 为 18 个 db.Model + 1 个 CodeSenseSession 会话类 --- project-understanding.md => project-understanding_wjh.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename project-understanding.md => project-understanding_wjh.md (95%) diff --git a/project-understanding.md b/project-understanding_wjh.md similarity index 95% rename from project-understanding.md rename to project-understanding_wjh.md index 882d744..7dd0f51 100644 --- a/project-understanding.md +++ b/project-understanding_wjh.md @@ -115,8 +115,8 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 后台线程按序执行: -1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分 `calculate_heuristic_score` + 可选 LLM 反馈,产出 score/feedback(统一归一到 0–5 由后续 `tasks/submission_tasks.py` 中的 `_normalise_score` 完成)。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) -2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分。 +1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分(`calculate_heuristic_score` 用局部变量 `normalized_score` 归一到 0–5)+ 可选 LLM 反馈,产出 score/feedback;回到任务层 `tasks/submission_tasks.py` 后再经 `_normalise_score` 兜底归一到 0–5(该函数定义于 submission_tasks.py,能按 0–5 / 0–10 / 0–100 三种量纲归一后取整)。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) +2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分(沙箱重算结果同样再走一次 `_normalise_score` 后才落库)。 3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 5. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`(内部按键去重防并发)。 @@ -160,7 +160,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 - **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 - **tasks/**:后台任务(异步评测、能力分析)。 -- **models.py**:单一 ORM 文件(约 1470 行;含 18 个 ORM 模型与 `CodeSenseSession` 会话存储类,共 19 个类);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 +- **models.py**:单一 ORM 文件(约 1500 行,含 18 个 `db.Model` 数据表模型 + 1 个 `CodeSenseSession` 会话存储类——后者继承 FlaskSQLAlchemySession,非 ORM 表,合计 19 个 class);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 ### 启动链路与关键机制 @@ -183,7 +183,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C - 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 - Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 - 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 -- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示;评测页前端轮询设 60 次上限(`maxPollAttempts=60`,间隔 2s),超限或队列不可用即停止轮询并提示——超限显示"暂时无法确认评测结果,请稍后刷新或重新提交",队列不可用显示"评测队列暂时不可用,请稍后刷新或重新提交",页面标题均显示"任务状态暂时不可用"。 +- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示(如"请稍后重试");评测页前端轮询设 60 次上限(`maxPollAttempts = 60`,间隔 2s),轮询超限时提示"暂时无法确认评测结果,请稍后刷新或重新提交",评测队列不可用时提示"评测队列暂时不可用,请稍后刷新或重新提交"。 --- From dab5f0603813856ce9b619b6777d1deefe3594a7 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 00:34:25 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20CodeSense=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=90=86=E8=A7=A3=E6=96=87=E6=A1=A3=20projec?= =?UTF-8?q?t-understanding=5Fwjh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_UNDERSTANDING.md | 370 --------------------------------------- project-understanding.md | 288 ++++++++++++++++++++++++++++++ 2 files changed, 288 insertions(+), 370 deletions(-) delete mode 100644 PROJECT_UNDERSTANDING.md create mode 100644 project-understanding.md diff --git a/PROJECT_UNDERSTANDING.md b/PROJECT_UNDERSTANDING.md deleted file mode 100644 index 09fddf7..0000000 --- a/PROJECT_UNDERSTANDING.md +++ /dev/null @@ -1,370 +0,0 @@ -# CodeSense 项目理解(阶段一) - -> 本文是对当前仓库实现的维护者视角梳理,目标是建立后续开发、评审和部署前排查的共同上下文。 -> -> 观察基线:`main` 分支 HEAD `5bd66e7`(2026-09-02)。本阶段只新增文档,不修改业务代码、数据库模型或运行逻辑。 - -## 1. 文档范围与结论口径 - -本文结论主要来自以下入口和实现: - -- 应用装配:`app.py`、`config.py`、`run.py`、`wsgi.py`、`gunicorn_config.py`; -- 数据模型:`models.py`; -- HTTP 路由:`routes/` 下的认证、作业、用户、班级、API、三阶段学习和成绩路由; -- 业务服务与后台任务:`services/`、`tasks/`; -- 代码评测、SSE、提示词和阶段三 Agent:`utils/`; -- 运行与容量说明:`README.md`、`README.en.md`、`PERFORMANCE_CAPACITY.md`; -- 回归测试:`tests/`。 - -文中使用“已确认”表示可以直接从当前代码或配置读到;使用“推断”表示根据调用关系得到的架构判断;使用“未知/待验证”表示仓库本身没有足够证据,需要在目标部署环境或后续需求中确认。 - -## 2. 一句话结论 - -CodeSense 是一个以 Flask 单体应用为核心的高校编程教学平台:学生提交 C++ 作业后,系统进行受限编译运行、AI 反馈和学习记录;学生还可以通过“思路描述 → 步骤组装 → 费曼教学”的三阶段流程完成引导式练习;教师通过作业、班级、花名册、提交记录和能力分析页面观察学习情况。 - -它目前不是拆分后的微服务系统,而是“Flask 路由 + SQLAlchemy 模型 + 业务服务 + 进程内异步任务 + 外部数据库/Redis/LLM”的组合。评测和 AI 功能已经有一定容错设计,但任务队列和 C++ 执行仍然依赖当前 Web 进程与主机边界,这是部署时最需要优先确认的部分。 - -## 3. 项目概况 - -### 3.1 产品边界 - -| 使用者 | 核心能力 | 主要状态数据 | -| --- | --- | --- | -| 学生 | 登录、浏览作业、提交 C++、查看评测与反馈、完成三阶段引导、查看个人学习画像 | `User`、`Submission`、`ThinkingSession`、`ThinkingStageLog`、`KnowledgePointScore`、`AbilityTrend` | -| 教师 | 创建/编辑作业、维护班级与花名册、查看提交和班级统计、生成学情建议 | `Assignment`、`TestCase`、`Class`、`StudentRoster`、`TeacherAISuggestion` | -| 管理员 | 用户、系统设置、全局成绩与数据导出等管理能力 | `SystemLog`、`SystemConfig` 及上述业务数据 | -| 访客 | 通过公开入口体验学生或教师演示流程 | 当前浏览器会话对应的临时 SQLite 数据库 | - -### 3.2 核心学习闭环 - -```mermaid -flowchart LR - A[教师创建作业与测试用例] --> B[学生描述思路] - B --> C[步骤/代码结构组装] - C --> D[提交 C++ 代码] - D --> E[AI 评估 + 受限编译运行] - E --> F[结果、反馈、知识点与能力记录] - F --> G[学生修正、解释或再次提交] - G --> D - F --> H[教师班级与作业分析] -``` - -这里有三种不同的“得分/状态”需要分开理解:作业提交得分持久化为 0–5;阶段一思路匹配度使用 0–100;知识点和能力画像也使用 0–100。提交评测最终以沙箱测试结果为主,AI 反馈承担解释和辅导作用。 - -## 4. 运行时架构 - -```mermaid -flowchart TB - Browser[浏览器] - - subgraph App[Flask 单体应用] - Factory[app.create_app] - Blueprints[Blueprint 路由] - Services[services 业务服务] - Models[models.py / SQLAlchemy] - Tasks[tasks + 进程内线程队列] - Utils[utils 评测、SSE、提示词、Agent] - Factory --> Blueprints - Blueprints --> Services - Blueprints --> Utils - Services --> Models - Services --> Tasks - Utils --> Services - end - - DB[(SQLite / MySQL)] - Redis[(Redis,可选)] - LLM[智谱或 OpenAI,可选] - Compiler[g++ / C++17] - - Browser -->|HTTP / JSON / SSE| Blueprints - Models --> DB - Factory --> Redis - Services -. AI 请求 .-> LLM - Tasks -. AI 分析 .-> LLM - Tasks --> Compiler -``` - -### 4.1 应用装配顺序 - -`app.py` 在导入时创建全局 `app`,`create_app()` 负责: - -1. 根据 `FLASK_CONFIG` 加载 development/testing/production 配置; -2. 配置反向代理头、数据库 engine 及连接池参数; -3. 优先连接 Redis 作为 Flask-Session 后端,失败时降级到文件会话; -4. 初始化 Flask-SQLAlchemy、Flask-Session、Flask-Login; -5. 注册 `auth`、`main`、`assignments`、`users`、`api`、`classes`、`thinking`、`grades` 八个 Blueprint; -6. 注册 `/healthz` 和 `/readyz`; -7. 开发/测试模式按配置执行 `db.create_all()`、历史列兼容处理和索引维护;生产模式默认要求先执行 `database_maintenance.py`; -8. 清理过期公开体验临时库,并按配置启动进程内异步任务系统。 - -因此,导入 `app` 不是纯粹的静态对象加载,可能触发数据库连接、Redis 探测、日志初始化、临时体验清理和后台线程启动。测试、Gunicorn worker 和一次性维护命令都需要考虑这个副作用。 - -## 5. 代码结构 - -### 5.1 根目录入口与配置 - -| 路径 | 作用 | 备注 | -| --- | --- | --- | -| `app.py` | Flask 应用工厂、扩展初始化、Blueprint 注册、健康检查和全局请求钩子 | 当前实际装配中心 | -| `config.py` | development/testing/production 配置 | 生产要求 `DATABASE_URL` 和 `SECRET_KEY` | -| `run.py` | 开发启动包装器 | 导入 `app` 后监听 `0.0.0.0:5000` | -| `wsgi.py` | WSGI 入口 | 默认将 `FLASK_CONFIG` 设为 production,导出对象名为 `application` | -| `gunicorn_config.py` | Gunicorn 运行参数 | 默认 2 worker、每 worker 4 threads,绑定 `127.0.0.1:5000` | -| `database_maintenance.py` | 生产部署前的一次性建表、补列和索引维护 | 不启动 Web 服务和后台 AI 任务 | -| `.env.example` | 环境变量模板 | 包含数据库、AI、Redis、连接池和任务参数 | -| `requirements.txt` | Python 依赖锁定/范围声明 | Flask、SQLAlchemy、AI SDK、Redis、数据导入导出等 | - -### 5.2 路由层 - -路由层采用 Flask Blueprint。页面通常由 Jinja 模板渲染,交互型功能通过 JSON 接口或 SSE 增量返回。 - -| 模块 | 主要职责 | 代表入口 | -| --- | --- | --- | -| `routes/auth.py` | 登录、注册、教师邀请、登出、公开体验入口 | `/login`、`/register`、`/demo-login/` | -| `routes/main.py` | 首页、学生/教师/管理员仪表盘、个人资料、导出、系统设置 | `/home`、`/teacher_dashboard`、`/admin_dashboard` | -| `routes/assignments.py` | 作业 CRUD、作业分配、学生作业列表、提交页面、提交历史 | `/assignments`、`/submit/` | -| `routes/users.py` | 用户管理、学生/教师详情、头像、密码、能力分析刷新 | `/users`、`/view_student_details/` | -| `routes/classes.py` | 班级绑定、教师邀请码、花名册导入、班级统计 | `/classes/`、`/classes//import-students` | -| `routes/grades.py` | 成绩统计与 Excel 导出 | `/grades`、`/grades/export` | -| `routes/api.py` | 作业/提交查询、代码提交 API、AI 指导、代码建议、趋势和测试用例 API | `/api/submit`、`/api/code_advice` | -| `routes/thinking.py` | 三阶段引导、SSE 对话、阶段三双 Agent、会话恢复和开发追踪 | `/thinking/`、`/thinking/api/stage1/*`、`/thinking/api/stage3/*` | - -权限主要在路由层通过 Flask-Login、`login_required` 和角色/班级检查实现;模型层本身不是独立的授权边界。新增 API 时需要同时核对“是否登录”“是否属于该学生/班级”“是否允许教师或管理员操作”。 - -### 5.3 数据模型 - -所有模型集中在 `models.py`,当前没有独立的 `models/` 包。 - -| 分组 | 关键模型 | 关系要点 | -| --- | --- | --- | -| 身份与组织 | `User`、`Class`、`StudentRoster`、`InviteToken` | `User.usertype` 区分学生/教师/管理员;班级同时保留 `class_id` 和历史兼容的 `class_name` | -| 作业与评测 | `Assignment`、`TestCase`、`Submission` | 作业拥有测试用例和提交;提交保存 AI 反馈、沙箱状态、通过数和明细 JSON | -| 学习记录 | `ThinkingSession`、`ThinkingStageLog`、`StudentQuestion`、`CodeAdviceRequest` | 记录阶段状态、对话/提示/步骤事件及代码快照 | -| 学习分析 | `KnowledgePointScore`、`AssignmentKnowledgePoint`、`AbilityTrend` | 知识点从作业或 AI 检测得到,能力分析保存 Markdown/状态 | -| 教学分析 | `TeacherAISuggestion`、`SystemLog`、`SystemConfig` | 保存班级 AI 建议、审计日志和站点配置 | -| 阶段三预设 | `AssignmentThinkingPreset` | 保存参考代码、关键步骤、代码块、题目和难度配置等 JSON/文本 | - -模型末尾集中声明性能索引,并由开发启动或 `database_maintenance.py` 检查创建。数据库结构兼容目前通过 `init_db()` 中的 `create_all()`、缺列检测和 `ALTER TABLE` 实现,仓库中未见一套独立的迁移版本目录;这使生产变更需要更谨慎地验证。 - -### 5.4 服务、任务与工具 - -| 目录/文件 | 作用 | -| --- | --- | -| `services/llm_client.py` | 共享 LLM 客户端;provider 选择、有限重试、熔断、并发上限、Redis/本地缓存和 single-flight 去重 | -| `services/ai_evaluator.py` | 代码评估、作业文本格式化、能力趋势、知识点检测等 AI 业务封装 | -| `services/course_grading.py` | 将正式提交与引导式学习证据组合为课程成绩/成绩册数据 | -| `services/teacher_analytics.py` | 班级提交趋势、作业完成矩阵、学生风险标签和教师首页数据 | -| `services/teacher_ai_advisor.py` | 班级薄弱点、重点学生和推荐练习的 AI/规则建议 | -| `services/demo_database.py` | 创建、激活、销毁和清理每个公开体验会话的临时 SQLite 库 | -| `services/demo_experience.py` | 向已激活的临时库幂等填充学生/教师演示数据、作业、历史提交和预设 | -| `tasks/submission_tasks.py` | 提交后的 AI 评估、C++ 测试、统计刷新、知识点评分和能力分析触发 | -| `tasks/ability_analysis.py` | 按学生和 demo run 去重的异步能力趋势生成 | -| `utils/async_tasks.py` | 进程内有界队列和后台线程,处理能力趋势、批量趋势和阶段预设任务 | -| `utils/sandbox_runner.py` | 查找 g++、C++17 编译、逐用例运行、超时和输出规范化 | -| `utils/code_evaluator.py`、`utils/llm_evaluator.py` | 评测结果与 AI/启发式反馈的兼容层 | -| `utils/sse.py` | SSE 响应包装和阻塞函数的流式事件封装 | -| `utils/thinking_ai.py` | 阶段一/二提示、陪伴式对话和输出过滤辅助 | -| `utils/agents/` | 阶段三 Agent 合约、事件记忆、意图、目标、覆盖度、工具注册和双角色运行时 | - -前端没有独立构建工程:`templates/` 保存 Jinja 页面和组件,`static/` 保存 CSS、原生 JavaScript、编辑器、SSE 客户端、图表和图片资源。 - -## 6. 关键流程 - -### 6.1 开发启动与生产启动 - -**开发路径:** - -```text -python run.py - -> 导入 app.py 的全局 app - -> 默认 development 配置 - -> 默认 SQLite(除非设置 DATABASE_URL/DEV_DATABASE_URL) - -> 按配置建表、补历史列、建索引 - -> 初始化会话、Blueprint 和进程内任务 - -> Flask 开发服务器 :5000 -``` - -**生产路径:** - -```text -python database_maintenance.py - -> FLASK_CONFIG=production、关闭启动期任务 - -> 使用 DATABASE_URL 完成一次性表结构/索引维护 - -gunicorn -c gunicorn_config.py wsgi:application - -> wsgi.py 默认 production - -> 每个 worker 独立初始化数据库连接、Redis 客户端和 AI 客户端 - -> 通常由 Nginx 终止 HTTPS,再转发到本机 Gunicorn -``` - -部署后应先检查 `/healthz`(不访问数据库的存活检查)和 `/readyz`(执行 `SELECT 1` 的数据库就绪检查)。 - -### 6.2 登录、会话与单点登录 - -普通登录将用户交给 Flask-Login,并在数据库与会话中保存当前 session id。`app.py` 的请求前钩子会在业务查询前检查当前 session id 是否仍与用户记录一致;发现其他地方登录后,旧会话会被强制退出。 - -公开体验则走另一条路径:`/demo-login/` 先创建随机 run id 对应的临时 SQLite 文件,再激活该数据库、填充演示数据并登录临时用户。后续请求根据 session 中的 run id 在 Flask-Login/业务查询前切换 SQLAlchemy scoped session;登出或过期清理时销毁该临时库。设计目标是让演示写入不进入正式库,且临时会话失效时绝不回退查询正式库。 - -### 6.3 学生提交与评测 - -```text -POST /submit/ 或 /api/submit - -> 校验登录身份、作业和代码长度 - -> 创建 Submission(status=pending) - -> 触发 evaluate_submission_async - -> evaluate_cpp_code:生成 AI/启发式分数与反馈 - -> run_test_cases:g++ -std=c++17 -O2 -Wall,逐测试用例运行 - -> 保存 sandbox_status、通过数、总数和 JSON 明细 - -> 以沙箱通过比例折算 0–5 提交分数 - -> 刷新作业和用户汇总统计 - -> 更新作业关联知识点/学生知识点分数 - -> 标记能力分析过期并触发异步能力分析 - -> 正式账户写入系统日志;公开体验只写入当前临时库 -``` - -`routes/assignments.py` 负责页面提交并跳转到评测等待页;`routes/api.py` 提供 API 形式的提交和状态查询。评测任务会把 demo run id 一路传递到后台线程,并在关键写入前再次确认临时库仍然有效。 - -沙箱当前明确实现了:编译 15 秒超时、单用例运行 5 秒超时、标准输出截断到 4096 字符、换行/行尾空白规范化、临时工作目录和用例级结果。它没有实现操作系统级的权限、网络、文件系统、内存或进程数隔离。 - -### 6.4 三阶段引导式学习 - -1. **阶段一:思路描述** - - `ThinkingSession` 绑定学生和作业; - - `/thinking/api/stage1/submit` 根据 `AssignmentThinkingPreset.key_steps` 评估自然语言描述; - - 得分达到阈值后推进到阶段二,并写入 `ThinkingStageLog`; - - `/stage1/hint` 可通过 JSON 或 SSE 请求提示,提示结果经过 `sanitize_response`。 - -2. **阶段二:步骤/积木组装** - - 前端提交选择/填空答案; - - 服务端先做规范化字符串比较,再通过 `check_quiz_equivalence` 判断合理等价答案; - - 通过后保存步骤状态,推进到阶段三并生成初始问题;失败则记录错误步骤和解释。 - -3. **阶段三:费曼教学** - - 传统入口 `/stage3/chat` 和 `/stage3/teach` 分别使用教师 Agent、学生 Agent; - - 论坛入口 `/stage3/forum/message` 要求显式目标角色; - - `DualFeynmanRuntime` 使用事件记忆、状态归约、覆盖度/目标判定和工具注册,控制追问、代码生成、修复评估和完成条件; - - `/stage3/write_code` 生成带陷阱的尝试,`/stage3/fix_code` 评估学生修复; - - `/complete_session` 只有在服务端确认阶段三完成条件后才允许完成,并可在演示场景生成临时五分制提交。 - -三阶段的前端交互同时支持普通 JSON 和 SSE。SSE 主要解决 AI 首 token 和增量文本展示问题,不改变最终业务状态仍由服务端落库的事实。 - -### 6.5 能力分析与教师视图 - -提交完成后会将 `AbilityTrend` 标记为过期,再由 `tasks/ability_analysis.py` 读取最近提交,调用统一 LLM 客户端生成分析 Markdown;失败时明确记录 failed 状态,不应继续展示陈旧的成功文案。教师首页由 `teacher_analytics.py` 聚合学生活跃度、提交数、作业完成矩阵和风险标签,教师 AI 建议由 `teacher_ai_advisor.py` 异步生成并保存。 - -`utils/async_tasks.py` 另有一个进程内有界队列,当前支持能力趋势、批量趋势和思维预设生成。它与提交评测/能力分析中的直接线程不是同一个统一任务系统。 - -## 7. 运行方式 - -### 7.1 本地开发 - -环境要求:Python 3.8+、可选 Redis、C++ 评测所需的 `g++`,以及 AI 功能所需的智谱或 OpenAI API Key。 - -```powershell -python -m venv .venv -.venv\Scripts\Activate.ps1 -python -m pip install -r requirements.txt -Copy-Item .env.example .env -python run.py -``` - -默认打开 。开发环境没有配置 `DATABASE_URL` 时使用 SQLite;Redis 不可用时会话和部分缓存降级到文件/进程内实现;没有 AI Key 时基础页面和非 AI 功能仍可检查,但 AI 相关功能会失败或不可用。 - -### 7.2 测试 - -```powershell -python -m pytest tests -q -``` - -测试同时使用 pytest 和 unittest 风格。涉及 C++ 评测的用例需要 `g++`;涉及真实 provider 的用例需要对应环境配置,单元测试通常通过 mock 隔离外部 AI 服务。当前仓库未看到明确的 CI 工作流,因此本地回归结果不能自动等同于 GitHub Checks 结果。 - -### 7.3 生产 - -生产环境至少需要: - -1. 设置随机且足够长的 `SECRET_KEY`; -2. 设置独立的 `DATABASE_URL`,并先执行 `python database_maintenance.py`; -3. 线上 HTTPS 打开 `SECURE_COOKIES=true`,Nginx 反向代理场景配置 `TRUST_PROXY_HEADERS=true` 并核对代理层数; -4. 配置 Redis 会话/缓存或确认文件会话目录具备隔离、持久化和清理策略; -5. 安装 `g++`,并为代码执行节点建立额外隔离; -6. 通过 `gunicorn -c gunicorn_config.py wsgi:application` 启动,再由 Nginx 或其他反向代理对外提供服务; -7. 持续监控 CPU、内存、数据库连接、任务队列、AI provider 配额、临时文件和日志磁盘。 - -### 7.4 本次接管环境实测记录 - -以下是 2026-09-03 在当前工作区的实际尝试,不代表目标生产环境结论: - -| 尝试 | 结果 | -| --- | --- | -| `python -m pip install -r requirements.txt` | 未执行安装;PowerShell 报错:`The term 'python' is not recognized as a name of a cmdlet, function, script file, or executable program.` | -| `python run.py` | 未启动;同样因为系统找不到 `python` 失败 | -| `python -m pytest tests -q` | 未执行测试;同样因为系统找不到 `python` 失败 | -| 工作区内置 Python `--version` | 可用,版本为 `Python 3.12.13` | -| 工作区内置 Python `-m pytest tests -q` | 失败:`No module named pytest` | -| `g++` PATH 检查 | 失败:`g++ not found on PATH`;因此无法验证 C++ 沙箱的真实编译运行 | -| 工作区内置 Python `-m compileall -q app.py routes services tasks utils` | 通过,退出码 `0`;这只是语法检查,不等价于应用启动或功能回归 | - -本次没有创建 `.env`、没有填入任何密钥,也没有连接正式数据库。要完成可运行验证,需要提供可安装依赖的 Python 环境(或在工作区内安装 `requirements.txt`)、`pytest`、C++ 编译器,以及按环境选择的 SQLite/MySQL、Redis 和 AI provider 配置。 - -## 8. 风险清单 - -| 优先级 | 风险 | 影响 | 当前缓解/后续方向 | -| --- | --- | --- | --- | -| 高 | C++ 沙箱是应用层 subprocess 限制,不是强隔离 | 恶意代码可能利用宿主机权限、文件、网络或资源;公网开放存在高风险 | 上线前增加容器/虚拟机、低权限用户、网络禁用、CPU/内存/进程/磁盘配额,并单独部署评测 worker | -| 高 | 后台任务主要在进程内运行 | 重启可能丢任务;多 worker 各自拥有队列、线程、缓存和去重状态,可能重复执行或任务不可见 | 迁移到持久化队列(如 Celery/RQ/消息队列),建立幂等键、重试、死信和可观测状态 | -| 高 | AI 输出和 AI 生成预设不是确定性事实 | 评分、提示、能力画像和阶段三判定可能受 provider、提示注入、上下文截断或模型升级影响 | 保留沙箱作为程序事实来源;固定评测协议和模型版本;增加人工复核、敏感数据脱敏、提示注入测试和结果审计 | -| 高 | 学生代码、对话、代码快照和 AI 结果包含学习隐私 | 数据库、日志、Redis、LLM provider 和导出文件都可能成为数据泄露面 | 明确数据保留/删除策略,限制日志内容和导出权限,生产密钥与数据库分离,核对第三方 AI 数据处理政策 | -| 中 | 数据库结构演进依赖 `create_all`、补列和索引检查 | 复杂变更、回滚和多版本并行发布缺少清晰迁移轨迹 | 建立版本化迁移、备份/恢复演练和生产前升级验证;不要把启动期自动维护当成完整迁移方案 | -| 中 | 授权逻辑分散在路由与查询组合中 | 新增 API 可能只做登录检查而漏掉对象归属、班级范围或角色边界 | 抽取可复用的角色/资源授权函数,补充越权矩阵测试 | -| 中 | 公开体验使用临时 SQLite 与后台线程交互 | 浏览器退出、文件锁、worker 生命周期和清理时序可能造成残留或失败 | 保持 run id 显式传递;在多进程环境验证锁和清理;为失败清理提供告警和定期维护 | -| 中 | 观测以日志和轻量探针为主 | 任务延迟、AI 首 token、熔断、队列堆积和沙箱资源消耗缺少完整指标 | 接入结构化指标、trace/request id、任务状态面板和 provider 用量监控 | -| 低 | 文档存在运行参数口径差异的可能 | 开发者可能使用错误的 WSGI 对象名、端口或代理配置 | 以 `wsgi.py`、`gunicorn_config.py` 和实际部署清单为准,后续统一 README、脚本和运维配置 | - -## 9. 未知项与下一步核对项 - -以下问题无法只通过当前代码确定,适合在阶段二或部署评审中补齐: - -| 问题 | 为什么未知 | 建议验证方式 | -| --- | --- | --- | -| 目标生产环境的 Nginx、HTTPS、进程管理和备份拓扑 | 仓库只提供应用侧配置,不能代表真实服务器 | 获取部署清单,验证 forwarded headers、Cookie、超时和优雅退出 | -| 实际使用的数据库类型、版本、字符集和迁移历史 | 代码同时支持 SQLite/MySQL,历史库结构未随仓库提供 | 对脱敏数据库执行维护命令和升级演练,记录耗时与回滚方案 | -| AI provider、模型版本、限额和数据留存策略 | 配置可选,provider 行为由外部服务决定 | 建立 provider 配置表、脱敏请求样本、限流/失败演练和成本上限 | -| C++ 评测是否允许公网用户触发 | 代码提供公开体验和代码执行,但部署访问范围不在仓库内 | 在网络边界文档中明确“课程内受控”还是“公网可用”,并按威胁模型验收沙箱 | -| 多 worker 下临时库绑定、会话、Redis 和后台任务的完整行为 | 单进程测试不能覆盖跨进程时序 | 用至少 2 个 worker 做并发登录、提交、登出、过期清理和 worker 重启测试 | -| 真实数据规模与查询容量 | 仅有估算报告,没有可复现的目标数据集和压测脚本 | 用脱敏数据压测登录、作业列表、提交状态、班级统计和 AI/SSE 峰值 | -| 成绩策略是否继续采用 0–5、知识点/能力采用 0–100 | 当前实现和 README 已采用该口径,但产品/教学规则可能变化 | 与课程负责人确认规则,并将规则写成可测试的策略文档 | -| 是否需要 CI、自动安全扫描和依赖更新策略 | 仓库未见明确 CI 工作流 | 确定 GitHub Actions、Python 版本矩阵、测试分层和依赖漏洞处理责任 | - -## 10. 阶段一结论与非目标 - -### 已形成的理解 - -- 这是一个以 Flask 单体为中心的教学平台,核心状态在 SQLAlchemy 模型中; -- 学生主链路由引导式学习、代码提交、C++ 受限执行、AI 反馈和能力分析共同构成; -- 阶段三已经从单纯文本对话扩展为带事件记忆、工具、覆盖度和完成条件的双 Agent 运行时; -- 公开体验通过临时数据库和显式 run id 做业务数据隔离; -- 当前小规模课堂/演示是较符合实现边界的使用场景,正式公网部署前必须优先补强沙箱和异步任务基础设施。 - -### 本阶段明确不做 - -- 不修改业务逻辑、路由行为、模型字段、提示词或前端交互; -- 不改变数据库结构、运行参数或部署脚本; -- 不把本文中的推断当成生产承诺; -- 不用文档替代安全评审、压测、迁移演练或真实环境验收。 - -后续修改应以本文的模块边界和未知项为检查清单,先补可验证的测试/运行证据,再进入业务代码变更。 - -## 11. 本次文档 PR 状态与阻塞 - -本地已创建分支 `docs/project-understanding`;分支相对 `main` 只有本文档一个新增文件,当前本地提交可直接用于后续推送。 - -尝试推送和创建远程分支时使用了以下操作: - -```text -git push -u origin docs/project-understanding -``` - -GitHub 返回:`remote: Permission to XiaoCow666/CodeSense.git denied to ggboyxkw666.`,HTTP `403`。随后通过 GitHub 连接器创建同名远程分支,返回:`Resource not accessible by integration`,HTTP `403`。检查发现当前账号没有目标仓库 push 权限,且没有可用的 `ggboyxkw666/CodeSense` fork,因此当前环境无法生成 PR 链接。 - -所需协助:为当前账号授予目标仓库分支写权限,或提供一个当前账号可推送的 fork。权限到位后,推送现有分支并以 `main` 为目标分支创建 PR 即可;不需要重新编写本文档。 diff --git a/project-understanding.md b/project-understanding.md new file mode 100644 index 0000000..7dd0f51 --- /dev/null +++ b/project-understanding.md @@ -0,0 +1,288 @@ +# CodeSense 项目理解与学习记录 + +## 一、项目定位 + +CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。它把代码提交、受限执行、AI 辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 + +### 主要用户 + +1. 学生:提交 C++ 程序、查看测试结果和反馈,进入三阶段引导式学习流程,记录自己的思路与解释。 +2. 教师:创建和管理作业、组织班级与花名册,查看提交记录、作业完成情况、知识点和能力趋势。 +3. 开发者/研究者:在 Flask、SQLAlchemy 和可替换的 AI 服务接口上继续扩展评测、教学和数据分析能力。 + +### 核心问题 + +传统 OJ 的两个痛点正是这个项目要解决的核心问题: + +1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense 引入受限评测(Causal Sandbox)+ AI 辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 +2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense 用两层画像体系沉淀学情:AI 反馈与能力分析文本按算法、代码风格、功能完整性、执行效率、可读性等维度组织(综述存于 `AbilityTrend` 的能力分析内容),可量化的画像则以 C 知识点为单位、经贝叶斯权重更新为 0–100 的 `KnowledgePointScore`。教师端据此把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 + +## 二、总体结构与目录分层 + +### 顶层文件(入口与配置) + +- `run.py`:开发启动入口,默认走开发配置。 +- `app.py`:应用工厂,`create_app()` 注册 Blueprint、初始化 DB/会话/登录态、ProxyFix、后台任务、访问日志与压缩中间件。 +- `wsgi.py`:生产 WSGI 入口,配合 `gunicorn_config.py`。 +- `config.py`:development / testing / production 三套配置,读取 `.env`。 +- `models.py`:全部 ORM 模型(见下)。 +- `forms.py`:Flask-WTF 表单定义。 +- `database_maintenance.py`:生产一次性建表/迁移/索引维护。 +- `deploy.sh` / `update.sh`:部署与运维脚本。 + +### routes/ — Web 与 API 路由层(Blueprint) + +- `auth.py`:登录/登出/注册/教师邀请,角色认证。 +- `main.py`:首页、关于、帮助等基础页面。 +- `assignments.py`:作业 CRUD、测试用例与提交管理。 +- `thinking.py`:三阶段引导式学习(思路/积木/费曼)与阶段 Agent API。 +- `classes.py`:班级、花名册、导入与班级统计。 +- `users.py`:用户资料、学生/教师/管理员页面。 +- `grades.py`:成绩视图与课程评分。 +- `api.py`:提交评测、代码建议、能力分析 SSE 等 REST 接口。 + +路由层只做参数解析、权限校验与业务编排,不承载核心逻辑。 + +### services/ — 面向业务的"较厚"服务层 + +- `llm_client.py`:统一 LLM 客户端(`SharedLLMClient`),智谱/OpenAI 多 provider 重试、限流与熔断。 +- `ai_evaluator.py`:AI 评测(含流式能力分析)。 +- `api_keys.py`:API 密钥管理器(不落库明文)。 +- `course_grading.py`:课程成绩计算。 +- `teacher_analytics.py`:教师端班级/知识点学情统计。 +- `teacher_ai_advisor.py`:AI 学情建议。 +- `demo_database.py` / `demo_experience.py`:公开体验入口的临时 SQLite 会话隔离与演示数据。 + +### utils/ — 底层工具与核心引擎 + +- `sandbox_runner.py`:Causal Sandbox:g++ C++17 受限编译/运行,15s 编译 / 5s 运行超时,stdout/stderr 各有界读取(各 4096 字节上限、超限即终止进程),用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error` 等)。 +- `code_evaluator.py`:启发式评分 + 可选 LLM 评估叠加。 + (早期版本曾使用 CodeBERT + TextCNN 本地模型评分,当前 main 已移除,相关描述仅见于历史文档/提交。) +- `llm_evaluator.py`:旧版 LLM 评估器 `LLMEvaluator`。注意:它仍自行初始化 provider 客户端并选择 api_type(`zhipu`/`openai`),仅在发请求时委托给 `services/llm_client.py::SharedLLMClient`。 +- `guidance_generator.py`:启发式引导提示生成(不直接给答案)。 +- `code_advisor.py`:代码建议。 +- `ability_scorer.py` / `maturity_calculator.py`:贝叶斯能力画像与成熟度。 +- `async_tasks.py` / `sse.py`:线程池任务队列 + SSE 流式推送。 +- `thinking_ai.py`:三阶段引导 AI 交互。 +- `markdown_formatter.py`:格式化输出。 +- `prompts.py`:提示词模板。 +- `auth.py` / `api.py` / `validate_testcases.py`:权限装饰器、通用 API 辅助与测试用例校验。 + +### utils/agents/ — 阶段三费曼/论坛 Agent 子系统 + +- `feynman.py`:双角色(教师/学生上下文)Agent 运行时。 +- `loop.py`:Agent 主循环;`tools.py`:工具;`model.py`:模型适配。 +- `orchestrator.py`:编排;`intent.py`:意图路由;`memory.py`:记忆; + `coverage.py`:知识点覆盖判定;`goal.py`:目标管理;`contracts.py`:数据契约。 + +### tasks/ — 异步任务 + +- `submission_tasks.py`:提交后评测、AI 分析等后台任务。 +- `ability_analysis.py`:能力画像的异步计算与分析。 + +### 前端 + +- `templates/`:Jinja2 页面,含按角色区分的首页/详情页,以及 `templates/thinking/arena.html`(三阶段竞技场)、组件化的多种代码编辑器片段。 +- `static/`:CSS、JS(Monaco 按需加载、SSE 客户端、编辑器/提交/思路对话脚本、安全输出处理器)、图片与第三方库(Sortable、require.min.js)。 + +### 核心数据模型一览(models.py) + +- 用户与组织:`User`(学生/教师/管理员 + RBAC)、`Class`、`StudentRoster`、`InviteToken`。 +- 教学资源:`Assignment`、`AssignmentKnowledgePoint`、`TestCase`、`AssignmentThinkingPreset`。 +- 学习记录:`Submission`、`ThinkingSession`、`ThinkingStageLog`、`StudentQuestion`、`CodeAdviceRequest`。 +- 画像与学情:`AbilityTrend`、`KnowledgePointScore`、`TeacherAISuggestion`。 +- 平台支撑:`SystemLog`、`SystemConfig`、`CodeSenseSession`。 + +### 测试(tests/) + +覆盖面较广,突出三类特色域:沙箱演示特性(`test_sandbox_features`,实为演示数据装载/免密登录/生产禁用三项用例,见附录 B,不直接覆盖 C++ 编译执行)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理、性能基线,以及沙箱输出限制的有界进程测试(`test_sandbox_output_limits.py`,mock 编译器、不触发真实 g++,见附录 B)等测试。 + +## 三、核心运行流程与调用链 + +### 1. 应用启动与请求生命周期 + +`run.py` / `wsgi.py` → `app.py::create_app`:加载 `config.py`、初始化 db、注册所有 Blueprint(routes/)、接入 Flask-Login / Flask-Session、ProxyFix、后台任务队列与压缩/日志中间件。请求进入 Blueprint 路由,经 services/ 编排,落到 utils/ 引擎与数据库。 + +说明:development 环境在启动时自动建表;production 环境 `DB_AUTO_INIT=False`,需先运行 `database_maintenance.py` 建表/维护索引。 + +### 2. 代码提交 → 评测调用链(最重要的一条) + +代码提交有两条平行通路: + +**A. 网页表单路径(异步,主流)** + +`POST /submit/`(`routes/assignments.py::submit_code`,蓝图无 url_prefix)→ 创建 `Submission(status=pending)` → 把任务投进后台线程 `tasks/submission_tasks.py::evaluate_submission_async` → 页面跳转到"评测中",前端经 `get_submission_status`(`routes/api.py`)/ SSE 轮询进度。 + +后台线程按序执行: + +1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分(`calculate_heuristic_score` 用局部变量 `normalized_score` 归一到 0–5)+ 可选 LLM 反馈,产出 score/feedback;回到任务层 `tasks/submission_tasks.py` 后再经 `_normalise_score` 兜底归一到 0–5(该函数定义于 submission_tasks.py,能按 0–5 / 0–10 / 0–100 三种量纲归一后取整)。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) +2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分(沙箱重算结果同样再走一次 `_normalise_score` 后才落库)。 +3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 +4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 +5. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`(内部按键去重防并发)。 +6. 写 `SystemLog`(公开体验会话不写正式库审计日志)。 + +**B. API 路径(同步)** + +`POST /api/submit`(`routes/api.py::submit_code`):同步 `evaluate_cpp_code` + 更新作业统计 + 触发能力分析,直接 JSON 返回 submission_id/score/status。 + +**数据落库**:`Submission`(含 sandbox_*、ai_feedback)→ `Assignment`/`User` 聚合 → `KnowledgePointScore` → `AbilityTrend`。 + +### 3. 三阶段引导式学习调用链 + +入口 `GET /thinking/`(`routes/thinking.py`)加载 `templates/thinking/arena.html`: + +1. 会话初始化:`POST /thinking/api/start_session`(thinking 蓝图 `url_prefix='/thinking'`)创建 `ThinkingSession`,装载 `AssignmentThinkingPreset`(目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 +2. 阶段一(思路):`POST /thinking/api/stage1/submit` → `utils/thinking_ai.py::evaluate_description` 先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 `ThinkingStageLog`。 +3. 阶段二(组装):`POST /thinking/api/stage2/verify` 验证步骤顺序并把组装结果规整成可编译代码、生成预览;AI 回应统一经 `utils/thinking_ai.py::sanitize_response` 做物理级代码过滤——这是提示词约束之外的第二层防泄漏。 +4. 阶段三(费曼/论坛):`POST /thinking/api/stage3/forum/message` → `utils/agents/orchestrator.py::Stage3Orchestrator.handle_user_message` → intent 意图识别、目标角色仲裁(学生/教师双 Agent)、loop 多轮、tools 追问/探测、coverage 判定掌握度,SSE 流式返回;`POST /thinking/api/stage3/forum/trace` 提供轨迹复盘,`POST /thinking/api/complete_session` 收尾归档。 + +**AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 + +- 新链路(三阶段对话、能力分析、教师建议等)直接使用 `services/llm_client.py::SharedLLMClient`(多 provider 重试、限流、熔断集中在此)。 +- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。 + +### 4. 能力画像与教师端学情链路 + +提交评测成功后(异步/同步两通路一致)即触发能力分析刷新:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 + +**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 + +**失败可见性**:AI/沙箱失败在体验中一律置 failed,前端显示"失败/重试",不允许用默认分数伪装成功。 + +## 四、架构理解 + +CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C++ 编程教学」:学生交代码 → 受限沙箱编译运行 → AI 启发式引导学习 → 沉淀能力画像;教师端管理班级/作业并查看学情。架构上采用「路由 → 服务 → 引擎/任务 → 模型」的分层,并配了一套会话级临时 SQLite 的公开演示隔离机制。 + +### 分层思路 + +- **routes/**(蓝图/路由层):页面 + JSON/SSE API,只做参数解析、权限校验、编排服务。 +- **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 +- **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 +- **tasks/**:后台任务(异步评测、能力分析)。 +- **models.py**:单一 ORM 文件(约 1500 行,含 18 个 `db.Model` 数据表模型 + 1 个 `CodeSenseSession` 会话存储类——后者继承 FlaskSQLAlchemySession,非 ORM 表,合计 19 个 class);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 + +### 启动链路与关键机制 + +`app.py` 是唯一入口,`create_app()` 应用工厂:加载 `config.py`(development/testing/production 三套)→ 配置数据库连接池、Session(优先 Redis,失败降级文件系统)→ 初始化 db、Flask-Login、Flask-Session → 注册 8 个蓝图 → 初始化异步任务系统 → 自动建表(development)。根级挂了全局 `before_request`:单点登录校验 + demo 临时库激活。 + +### 核心子系统 + +1. **代码评测执行链(Causal Sandbox)**:以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、stdout/stderr 各有界读取(各 4096 字节上限,超限即终止进程,不视为正常结束)、标准化输出比对,用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error`)。调用链: + `routes (submit) → tasks/submission_tasks.evaluate_submission_async → utils/code_evaluator(启发式评分 + 可选 LLM 叠加)→ utils/sandbox_runner.run_test_cases(受限编译运行)`。 + 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。沙箱输出有界化来自上游提交 `fix: bound C++ sandbox stdout and stderr`,配套测试 `tests/test_sandbox_output_limits.py`(mock 编译器、用 Python 解释器进程验证有界进程行为,见附录 B)。 +2. **AI 服务抽象**:`services/llm_client.py::SharedLLMClient` 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;`services/api_keys.py` 统一管理密钥。新链路只依赖这一层;旧评估器 `utils/llm_evaluator.py::LLMEvaluator` 的初始化/选型逻辑仍在旧模块内(见三.3"AI 调用现状")。 +3. **异步 + SSE**:提交后不阻塞请求,任务由线程池执行,前端通过 `utils/sse.py` 的 SSE 流(如 `/api/stream/ability-analysis`)拿进度。 +4. **三阶段引导式学习(thinking)**:一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 `utils/agents/`;入口路由在 `routes/thinking.py`,页面在 `templates/thinking/arena.html`。 +5. **公开演示体验隔离(重点设计)**:不注册真实账号也能体验。每次进入 `/login` 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(`services/demo_database.py`),由 `before_request` 按会话激活该库;演示账号(`demo:*`)走 Flask-Login 的独立 user_loader。`services/demo_experience.py` 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除,与 AGENTS.md 的 PR worktree 数据隔离约定一致。 +6. **成绩与画像**:作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,`ability_scorer` + `AbilityTrend`/`KnowledgePointScore`)。`routes/grades.py` + `services/course_grading.py` 汇总成绩册并导出 Excel;教师 AI 建议在 `services/teacher_ai_advisor.py`。 + +### 安全/运维要点 + +- 权限分三类装饰器:`login_required` / `teacher_required` / `admin_required`。 +- 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 +- Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 +- 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 +- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示(如"请稍后重试");评测页前端轮询设 60 次上限(`maxPollAttempts = 60`,间隔 2s),轮询超限时提示"暂时无法确认评测结果,请稍后刷新或重新提交",评测队列不可用时提示"评测队列暂时不可用,请稍后刷新或重新提交"。 + +--- + +## 附录 A:个人理解与后续设想(【非现状】,仅代表个人想法) + +> 以下内容不属于当前仓库现状,是学习过程中产生的问题记录与改进设想。 + +1. **对 AI 助手回复过滤的设想**:当前只在 `utils/thinking_ai.py` 内对回复做"物理级代码屏蔽"。我认为不应完全屏蔽:可以做一个 agent 专门监测回复,把与答案直接相关的代码屏蔽掉,而保留与知识点相关的示例代码来帮助学生理解;同时检查回复是否正确,提高回复正确率。 +2. **第三阶段三元角色设想**:目前费曼是"教师/学生"双 Agent。我认为可以让老师 agent 给我一个任务,让我给学生 agent 讲这个知识点,把我的理解完整讲完;学生 agent 再提问。如果我讲的知识点有错误、模糊或缺失,就由学生 agent 多角度追问检查;如果我回答不上来,就转向老师 agent 提问。进一步,希望两个智能体共享数据:老师给我讲解和提问、我给学生讲解、学生指出我讲不清楚处并给出代码修复,构成"老师—我—学生"三元关系,用算法适配这套数据流通。 +3. **自适应选题设想**:可依据 AI 助手互动中生成的追问问题来优化题目并沉淀进题库,再用深度学习/自适应算法按学生水平分配题目。 +4. **情感分析与学习积极性设想**:希望纳入学习态度与积极性评估,指标可包括:对 AI 助手的使用程度;对作业开设习题复习处、设置复习环节并评估复习效果;最后用算法综合评价学生的学习积极性。 +5. **使用中发现的体验问题**: + - 引导式学习第二部分给出的题目会多出一些无关内容,中间完整代码展示处的代码并不完整(左侧按题拼凑的代码完整,中间展示的有所缺失,但能正常运行出正确结果)。 + - 代码页右侧的 AI 助手回答会重复。 + - 代码提交后的评估多是 C++ 向,对 C 语言的评估不够准确。 + - AI 响应较慢,且因 prompt 缘故回复略显臃肿。 + - 第二阶段"请求提示"无法定位学生具体卡在哪个问题:它通常从第一阶段的问题继续从头解释并提问,难以直接帮学生解决当前卡点。设想把请求提示精确到具体问题,直接给该问题的提示并提问与当前题目相关的问题。 +6. **学习计划**:后续需要逐步学习项目相关技术栈,积累实践经验,目前对项目内不少内容理解还不到位,希望能逐步赶上学长进度。 + +## 附录 B:个人安装、运行与测试记录(个人环境备忘) + +- 记录时间:2026-09-03(2026-09-05 按 PR 评审意见补充真实 C++ 编译运行验证与范围说明,并随分支 rebase 至上游 main 后复核新版沙箱引擎);环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 + +### 安装 + +按 README「快速开始」在项目根目录完成: + +```powershell +py -3.11 -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ +``` + +依赖安装成功,共 60 个包,核心版本为 Flask 2.2.3、SQLAlchemy 2.0.52、python-docx 1.2.0、openai 3.7.0、cryptography 41.0.3 等。随后安装 C++ 编译器 g++ 16.1.0(MSYS2)。 + +过程中遇到的问题与解决: + +1. Python 3.14 兼容性问题:系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 `ast.Str`,启动即报 `AttributeError: module 'ast' has no attribute 'Str'`。改用 Python 3.11 创建虚拟环境后解决。 +2. `.env` 残留 MySQL 配置:`.env` 中的 `DATABASE_URL` 实际仍指向本地 MySQL(user:password@127.0.0.1:3306),启动时 `db.create_all()` 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 + +### 运行 + +开发配置启动(未设置 DATABASE_URL 时使用本地 SQLite,首次启动自动建表): + +```powershell +.\.venv\Scripts\Activate.ps1 +python run.py +``` + +启动结果:数据库初始化成功,异步任务系统初始化成功;Running on http://127.0.0.1:5000。本机未安装 Redis,会话自动降级为文件系统存储(filesystem),不影响使用。浏览器访问 http://127.0.0.1:5000/login,登录页提供免注册的学生体验与教师体验入口。 + +说明:启动日志中的"生产模式:启用 INFO 级别日志"字样由 `.env` 内 `FLASK_DEBUG='False'` 引起,实际运行配置为 development(日志显示 Debug mode: on),不构成问题。 + +### 测试 + +**1. 沙箱演示特性自动化测试(pytest)** + +```powershell +.\.venv\Scripts\python.exe -m pytest tests/test_sandbox_features.py -q +``` + +结果:3 passed, 26 warnings(2026-09-05 本机复测约 60s)。三项用例分别为 `test_seed_demo_data_creation`(演示数据装载)、`test_sandbox_login_flows`(免密登录)、`test_security_prevents_sandbox_in_production`(生产环境禁用沙箱),属于"沙箱(演示)登录与安全特性"测试,**并未调用 g++ 编译运行代码**。另经核对,`tests/test_demo_submission_isolation.py` 中同样对 `run_test_cases` 做了 mock;上游 main 新增的 `tests/test_sandbox_output_limits.py`(2026-09-05 本机复测 5 passed in 1.01s)同样把编译器 patch 掉、改用 Python 解释器子进程验证 stdout/stderr 有界截断、超时与退出码等有界进程行为。因此 tests/ 目录当前不存在覆盖真实 C++ 编译运行链路的端到端用例,此前"通过沙箱评测相关测试即可说明代码评测链路可用"的表述不准确,见下方补充验证。 + +**2. 真实 C++ 编译运行链路验证(2026-09-05 补充,回应评审意见)** + +直接调用 `utils/sandbox_runner.py::run_test_cases`,对一段 C++17 加法程序(`cin` 读入、`cout` 输出)用本机 g++ 编译后运行 3 个用例(含公开与隐藏用例)。该验证在合并上游新版沙箱引擎(有界管道读取,提交 `fix: bound C++ sandbox stdout and stderr`)后于 2026-09-05 复测一致,结果: + +```text +compiler = C:\msys64\mingw64\bin\g++.exe # g++ (MSYS2) 16.1.0,与沙箱候选路径一致 +compiler_available = true, compile_success = true, compile_error = "" +passed 3 / total 3, status = passed +# 各用例 termination_reason = null(正常完成),输出经 _normalize_output 比对一致,单例运行 31–186ms +``` + +验证方式为临时脚本(用后即删): + +```python +from utils.sandbox_runner import run_test_cases + +source = '''#include +using namespace std; +int main() { int a, b; cin >> a >> b; cout << a + b << endl; return 0; }''' + +run_test_cases(source, [ + {'input_data': '3 5\n', 'expected_output': '8', 'id': 1, 'is_public': True}, + {'input_data': '-1 1\n', 'expected_output': '0', 'id': 2, 'is_public': False}, + {'input_data': '100 200\n', 'expected_output': '300', 'id': 3, 'is_public': False}, +]) +``` + +由此可确认:在具备 g++ 的本机环境下,C++17 源码可经沙箱完成编译→运行→输出标准化比对→判定。该验证覆盖引擎层单次编译与运行,**未覆盖完整 Web 提交→后台任务→SSE/轮询→落库链路**(该链路中的 AI 叠加评分依赖真实 AI 密钥)。 + +### 结论 + +本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;上游 main 新增的沙箱输出限制有界进程测试 5 项通过(mock 编译器);并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用(合并上游新版沙箱引擎后复测一致)。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 + +### 个人工具与参考资料 + +- AI 工具:Trae(接入 ds-v4-flash)。 +- 参考资料: + - MSYS2 安装相关: + - Git 命令入门相关: From 9e475105057302ac51cb35b657de793ffc5ecda9 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 15:00:13 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E4=B8=BB=E5=B9=B2=20PR?= =?UTF-8?q?OJECT=5FUNDERSTANDING.md=20=E5=B9=B6=E7=A7=BB=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=20project-understanding.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_UNDERSTANDING.md | 370 +++++++++++++++++++++++++++++++++++++++ project-understanding.md | 288 ------------------------------ 2 files changed, 370 insertions(+), 288 deletions(-) create mode 100644 PROJECT_UNDERSTANDING.md delete mode 100644 project-understanding.md diff --git a/PROJECT_UNDERSTANDING.md b/PROJECT_UNDERSTANDING.md new file mode 100644 index 0000000..09fddf7 --- /dev/null +++ b/PROJECT_UNDERSTANDING.md @@ -0,0 +1,370 @@ +# CodeSense 项目理解(阶段一) + +> 本文是对当前仓库实现的维护者视角梳理,目标是建立后续开发、评审和部署前排查的共同上下文。 +> +> 观察基线:`main` 分支 HEAD `5bd66e7`(2026-09-02)。本阶段只新增文档,不修改业务代码、数据库模型或运行逻辑。 + +## 1. 文档范围与结论口径 + +本文结论主要来自以下入口和实现: + +- 应用装配:`app.py`、`config.py`、`run.py`、`wsgi.py`、`gunicorn_config.py`; +- 数据模型:`models.py`; +- HTTP 路由:`routes/` 下的认证、作业、用户、班级、API、三阶段学习和成绩路由; +- 业务服务与后台任务:`services/`、`tasks/`; +- 代码评测、SSE、提示词和阶段三 Agent:`utils/`; +- 运行与容量说明:`README.md`、`README.en.md`、`PERFORMANCE_CAPACITY.md`; +- 回归测试:`tests/`。 + +文中使用“已确认”表示可以直接从当前代码或配置读到;使用“推断”表示根据调用关系得到的架构判断;使用“未知/待验证”表示仓库本身没有足够证据,需要在目标部署环境或后续需求中确认。 + +## 2. 一句话结论 + +CodeSense 是一个以 Flask 单体应用为核心的高校编程教学平台:学生提交 C++ 作业后,系统进行受限编译运行、AI 反馈和学习记录;学生还可以通过“思路描述 → 步骤组装 → 费曼教学”的三阶段流程完成引导式练习;教师通过作业、班级、花名册、提交记录和能力分析页面观察学习情况。 + +它目前不是拆分后的微服务系统,而是“Flask 路由 + SQLAlchemy 模型 + 业务服务 + 进程内异步任务 + 外部数据库/Redis/LLM”的组合。评测和 AI 功能已经有一定容错设计,但任务队列和 C++ 执行仍然依赖当前 Web 进程与主机边界,这是部署时最需要优先确认的部分。 + +## 3. 项目概况 + +### 3.1 产品边界 + +| 使用者 | 核心能力 | 主要状态数据 | +| --- | --- | --- | +| 学生 | 登录、浏览作业、提交 C++、查看评测与反馈、完成三阶段引导、查看个人学习画像 | `User`、`Submission`、`ThinkingSession`、`ThinkingStageLog`、`KnowledgePointScore`、`AbilityTrend` | +| 教师 | 创建/编辑作业、维护班级与花名册、查看提交和班级统计、生成学情建议 | `Assignment`、`TestCase`、`Class`、`StudentRoster`、`TeacherAISuggestion` | +| 管理员 | 用户、系统设置、全局成绩与数据导出等管理能力 | `SystemLog`、`SystemConfig` 及上述业务数据 | +| 访客 | 通过公开入口体验学生或教师演示流程 | 当前浏览器会话对应的临时 SQLite 数据库 | + +### 3.2 核心学习闭环 + +```mermaid +flowchart LR + A[教师创建作业与测试用例] --> B[学生描述思路] + B --> C[步骤/代码结构组装] + C --> D[提交 C++ 代码] + D --> E[AI 评估 + 受限编译运行] + E --> F[结果、反馈、知识点与能力记录] + F --> G[学生修正、解释或再次提交] + G --> D + F --> H[教师班级与作业分析] +``` + +这里有三种不同的“得分/状态”需要分开理解:作业提交得分持久化为 0–5;阶段一思路匹配度使用 0–100;知识点和能力画像也使用 0–100。提交评测最终以沙箱测试结果为主,AI 反馈承担解释和辅导作用。 + +## 4. 运行时架构 + +```mermaid +flowchart TB + Browser[浏览器] + + subgraph App[Flask 单体应用] + Factory[app.create_app] + Blueprints[Blueprint 路由] + Services[services 业务服务] + Models[models.py / SQLAlchemy] + Tasks[tasks + 进程内线程队列] + Utils[utils 评测、SSE、提示词、Agent] + Factory --> Blueprints + Blueprints --> Services + Blueprints --> Utils + Services --> Models + Services --> Tasks + Utils --> Services + end + + DB[(SQLite / MySQL)] + Redis[(Redis,可选)] + LLM[智谱或 OpenAI,可选] + Compiler[g++ / C++17] + + Browser -->|HTTP / JSON / SSE| Blueprints + Models --> DB + Factory --> Redis + Services -. AI 请求 .-> LLM + Tasks -. AI 分析 .-> LLM + Tasks --> Compiler +``` + +### 4.1 应用装配顺序 + +`app.py` 在导入时创建全局 `app`,`create_app()` 负责: + +1. 根据 `FLASK_CONFIG` 加载 development/testing/production 配置; +2. 配置反向代理头、数据库 engine 及连接池参数; +3. 优先连接 Redis 作为 Flask-Session 后端,失败时降级到文件会话; +4. 初始化 Flask-SQLAlchemy、Flask-Session、Flask-Login; +5. 注册 `auth`、`main`、`assignments`、`users`、`api`、`classes`、`thinking`、`grades` 八个 Blueprint; +6. 注册 `/healthz` 和 `/readyz`; +7. 开发/测试模式按配置执行 `db.create_all()`、历史列兼容处理和索引维护;生产模式默认要求先执行 `database_maintenance.py`; +8. 清理过期公开体验临时库,并按配置启动进程内异步任务系统。 + +因此,导入 `app` 不是纯粹的静态对象加载,可能触发数据库连接、Redis 探测、日志初始化、临时体验清理和后台线程启动。测试、Gunicorn worker 和一次性维护命令都需要考虑这个副作用。 + +## 5. 代码结构 + +### 5.1 根目录入口与配置 + +| 路径 | 作用 | 备注 | +| --- | --- | --- | +| `app.py` | Flask 应用工厂、扩展初始化、Blueprint 注册、健康检查和全局请求钩子 | 当前实际装配中心 | +| `config.py` | development/testing/production 配置 | 生产要求 `DATABASE_URL` 和 `SECRET_KEY` | +| `run.py` | 开发启动包装器 | 导入 `app` 后监听 `0.0.0.0:5000` | +| `wsgi.py` | WSGI 入口 | 默认将 `FLASK_CONFIG` 设为 production,导出对象名为 `application` | +| `gunicorn_config.py` | Gunicorn 运行参数 | 默认 2 worker、每 worker 4 threads,绑定 `127.0.0.1:5000` | +| `database_maintenance.py` | 生产部署前的一次性建表、补列和索引维护 | 不启动 Web 服务和后台 AI 任务 | +| `.env.example` | 环境变量模板 | 包含数据库、AI、Redis、连接池和任务参数 | +| `requirements.txt` | Python 依赖锁定/范围声明 | Flask、SQLAlchemy、AI SDK、Redis、数据导入导出等 | + +### 5.2 路由层 + +路由层采用 Flask Blueprint。页面通常由 Jinja 模板渲染,交互型功能通过 JSON 接口或 SSE 增量返回。 + +| 模块 | 主要职责 | 代表入口 | +| --- | --- | --- | +| `routes/auth.py` | 登录、注册、教师邀请、登出、公开体验入口 | `/login`、`/register`、`/demo-login/` | +| `routes/main.py` | 首页、学生/教师/管理员仪表盘、个人资料、导出、系统设置 | `/home`、`/teacher_dashboard`、`/admin_dashboard` | +| `routes/assignments.py` | 作业 CRUD、作业分配、学生作业列表、提交页面、提交历史 | `/assignments`、`/submit/` | +| `routes/users.py` | 用户管理、学生/教师详情、头像、密码、能力分析刷新 | `/users`、`/view_student_details/` | +| `routes/classes.py` | 班级绑定、教师邀请码、花名册导入、班级统计 | `/classes/`、`/classes//import-students` | +| `routes/grades.py` | 成绩统计与 Excel 导出 | `/grades`、`/grades/export` | +| `routes/api.py` | 作业/提交查询、代码提交 API、AI 指导、代码建议、趋势和测试用例 API | `/api/submit`、`/api/code_advice` | +| `routes/thinking.py` | 三阶段引导、SSE 对话、阶段三双 Agent、会话恢复和开发追踪 | `/thinking/`、`/thinking/api/stage1/*`、`/thinking/api/stage3/*` | + +权限主要在路由层通过 Flask-Login、`login_required` 和角色/班级检查实现;模型层本身不是独立的授权边界。新增 API 时需要同时核对“是否登录”“是否属于该学生/班级”“是否允许教师或管理员操作”。 + +### 5.3 数据模型 + +所有模型集中在 `models.py`,当前没有独立的 `models/` 包。 + +| 分组 | 关键模型 | 关系要点 | +| --- | --- | --- | +| 身份与组织 | `User`、`Class`、`StudentRoster`、`InviteToken` | `User.usertype` 区分学生/教师/管理员;班级同时保留 `class_id` 和历史兼容的 `class_name` | +| 作业与评测 | `Assignment`、`TestCase`、`Submission` | 作业拥有测试用例和提交;提交保存 AI 反馈、沙箱状态、通过数和明细 JSON | +| 学习记录 | `ThinkingSession`、`ThinkingStageLog`、`StudentQuestion`、`CodeAdviceRequest` | 记录阶段状态、对话/提示/步骤事件及代码快照 | +| 学习分析 | `KnowledgePointScore`、`AssignmentKnowledgePoint`、`AbilityTrend` | 知识点从作业或 AI 检测得到,能力分析保存 Markdown/状态 | +| 教学分析 | `TeacherAISuggestion`、`SystemLog`、`SystemConfig` | 保存班级 AI 建议、审计日志和站点配置 | +| 阶段三预设 | `AssignmentThinkingPreset` | 保存参考代码、关键步骤、代码块、题目和难度配置等 JSON/文本 | + +模型末尾集中声明性能索引,并由开发启动或 `database_maintenance.py` 检查创建。数据库结构兼容目前通过 `init_db()` 中的 `create_all()`、缺列检测和 `ALTER TABLE` 实现,仓库中未见一套独立的迁移版本目录;这使生产变更需要更谨慎地验证。 + +### 5.4 服务、任务与工具 + +| 目录/文件 | 作用 | +| --- | --- | +| `services/llm_client.py` | 共享 LLM 客户端;provider 选择、有限重试、熔断、并发上限、Redis/本地缓存和 single-flight 去重 | +| `services/ai_evaluator.py` | 代码评估、作业文本格式化、能力趋势、知识点检测等 AI 业务封装 | +| `services/course_grading.py` | 将正式提交与引导式学习证据组合为课程成绩/成绩册数据 | +| `services/teacher_analytics.py` | 班级提交趋势、作业完成矩阵、学生风险标签和教师首页数据 | +| `services/teacher_ai_advisor.py` | 班级薄弱点、重点学生和推荐练习的 AI/规则建议 | +| `services/demo_database.py` | 创建、激活、销毁和清理每个公开体验会话的临时 SQLite 库 | +| `services/demo_experience.py` | 向已激活的临时库幂等填充学生/教师演示数据、作业、历史提交和预设 | +| `tasks/submission_tasks.py` | 提交后的 AI 评估、C++ 测试、统计刷新、知识点评分和能力分析触发 | +| `tasks/ability_analysis.py` | 按学生和 demo run 去重的异步能力趋势生成 | +| `utils/async_tasks.py` | 进程内有界队列和后台线程,处理能力趋势、批量趋势和阶段预设任务 | +| `utils/sandbox_runner.py` | 查找 g++、C++17 编译、逐用例运行、超时和输出规范化 | +| `utils/code_evaluator.py`、`utils/llm_evaluator.py` | 评测结果与 AI/启发式反馈的兼容层 | +| `utils/sse.py` | SSE 响应包装和阻塞函数的流式事件封装 | +| `utils/thinking_ai.py` | 阶段一/二提示、陪伴式对话和输出过滤辅助 | +| `utils/agents/` | 阶段三 Agent 合约、事件记忆、意图、目标、覆盖度、工具注册和双角色运行时 | + +前端没有独立构建工程:`templates/` 保存 Jinja 页面和组件,`static/` 保存 CSS、原生 JavaScript、编辑器、SSE 客户端、图表和图片资源。 + +## 6. 关键流程 + +### 6.1 开发启动与生产启动 + +**开发路径:** + +```text +python run.py + -> 导入 app.py 的全局 app + -> 默认 development 配置 + -> 默认 SQLite(除非设置 DATABASE_URL/DEV_DATABASE_URL) + -> 按配置建表、补历史列、建索引 + -> 初始化会话、Blueprint 和进程内任务 + -> Flask 开发服务器 :5000 +``` + +**生产路径:** + +```text +python database_maintenance.py + -> FLASK_CONFIG=production、关闭启动期任务 + -> 使用 DATABASE_URL 完成一次性表结构/索引维护 + +gunicorn -c gunicorn_config.py wsgi:application + -> wsgi.py 默认 production + -> 每个 worker 独立初始化数据库连接、Redis 客户端和 AI 客户端 + -> 通常由 Nginx 终止 HTTPS,再转发到本机 Gunicorn +``` + +部署后应先检查 `/healthz`(不访问数据库的存活检查)和 `/readyz`(执行 `SELECT 1` 的数据库就绪检查)。 + +### 6.2 登录、会话与单点登录 + +普通登录将用户交给 Flask-Login,并在数据库与会话中保存当前 session id。`app.py` 的请求前钩子会在业务查询前检查当前 session id 是否仍与用户记录一致;发现其他地方登录后,旧会话会被强制退出。 + +公开体验则走另一条路径:`/demo-login/` 先创建随机 run id 对应的临时 SQLite 文件,再激活该数据库、填充演示数据并登录临时用户。后续请求根据 session 中的 run id 在 Flask-Login/业务查询前切换 SQLAlchemy scoped session;登出或过期清理时销毁该临时库。设计目标是让演示写入不进入正式库,且临时会话失效时绝不回退查询正式库。 + +### 6.3 学生提交与评测 + +```text +POST /submit/ 或 /api/submit + -> 校验登录身份、作业和代码长度 + -> 创建 Submission(status=pending) + -> 触发 evaluate_submission_async + -> evaluate_cpp_code:生成 AI/启发式分数与反馈 + -> run_test_cases:g++ -std=c++17 -O2 -Wall,逐测试用例运行 + -> 保存 sandbox_status、通过数、总数和 JSON 明细 + -> 以沙箱通过比例折算 0–5 提交分数 + -> 刷新作业和用户汇总统计 + -> 更新作业关联知识点/学生知识点分数 + -> 标记能力分析过期并触发异步能力分析 + -> 正式账户写入系统日志;公开体验只写入当前临时库 +``` + +`routes/assignments.py` 负责页面提交并跳转到评测等待页;`routes/api.py` 提供 API 形式的提交和状态查询。评测任务会把 demo run id 一路传递到后台线程,并在关键写入前再次确认临时库仍然有效。 + +沙箱当前明确实现了:编译 15 秒超时、单用例运行 5 秒超时、标准输出截断到 4096 字符、换行/行尾空白规范化、临时工作目录和用例级结果。它没有实现操作系统级的权限、网络、文件系统、内存或进程数隔离。 + +### 6.4 三阶段引导式学习 + +1. **阶段一:思路描述** + - `ThinkingSession` 绑定学生和作业; + - `/thinking/api/stage1/submit` 根据 `AssignmentThinkingPreset.key_steps` 评估自然语言描述; + - 得分达到阈值后推进到阶段二,并写入 `ThinkingStageLog`; + - `/stage1/hint` 可通过 JSON 或 SSE 请求提示,提示结果经过 `sanitize_response`。 + +2. **阶段二:步骤/积木组装** + - 前端提交选择/填空答案; + - 服务端先做规范化字符串比较,再通过 `check_quiz_equivalence` 判断合理等价答案; + - 通过后保存步骤状态,推进到阶段三并生成初始问题;失败则记录错误步骤和解释。 + +3. **阶段三:费曼教学** + - 传统入口 `/stage3/chat` 和 `/stage3/teach` 分别使用教师 Agent、学生 Agent; + - 论坛入口 `/stage3/forum/message` 要求显式目标角色; + - `DualFeynmanRuntime` 使用事件记忆、状态归约、覆盖度/目标判定和工具注册,控制追问、代码生成、修复评估和完成条件; + - `/stage3/write_code` 生成带陷阱的尝试,`/stage3/fix_code` 评估学生修复; + - `/complete_session` 只有在服务端确认阶段三完成条件后才允许完成,并可在演示场景生成临时五分制提交。 + +三阶段的前端交互同时支持普通 JSON 和 SSE。SSE 主要解决 AI 首 token 和增量文本展示问题,不改变最终业务状态仍由服务端落库的事实。 + +### 6.5 能力分析与教师视图 + +提交完成后会将 `AbilityTrend` 标记为过期,再由 `tasks/ability_analysis.py` 读取最近提交,调用统一 LLM 客户端生成分析 Markdown;失败时明确记录 failed 状态,不应继续展示陈旧的成功文案。教师首页由 `teacher_analytics.py` 聚合学生活跃度、提交数、作业完成矩阵和风险标签,教师 AI 建议由 `teacher_ai_advisor.py` 异步生成并保存。 + +`utils/async_tasks.py` 另有一个进程内有界队列,当前支持能力趋势、批量趋势和思维预设生成。它与提交评测/能力分析中的直接线程不是同一个统一任务系统。 + +## 7. 运行方式 + +### 7.1 本地开发 + +环境要求:Python 3.8+、可选 Redis、C++ 评测所需的 `g++`,以及 AI 功能所需的智谱或 OpenAI API Key。 + +```powershell +python -m venv .venv +.venv\Scripts\Activate.ps1 +python -m pip install -r requirements.txt +Copy-Item .env.example .env +python run.py +``` + +默认打开 。开发环境没有配置 `DATABASE_URL` 时使用 SQLite;Redis 不可用时会话和部分缓存降级到文件/进程内实现;没有 AI Key 时基础页面和非 AI 功能仍可检查,但 AI 相关功能会失败或不可用。 + +### 7.2 测试 + +```powershell +python -m pytest tests -q +``` + +测试同时使用 pytest 和 unittest 风格。涉及 C++ 评测的用例需要 `g++`;涉及真实 provider 的用例需要对应环境配置,单元测试通常通过 mock 隔离外部 AI 服务。当前仓库未看到明确的 CI 工作流,因此本地回归结果不能自动等同于 GitHub Checks 结果。 + +### 7.3 生产 + +生产环境至少需要: + +1. 设置随机且足够长的 `SECRET_KEY`; +2. 设置独立的 `DATABASE_URL`,并先执行 `python database_maintenance.py`; +3. 线上 HTTPS 打开 `SECURE_COOKIES=true`,Nginx 反向代理场景配置 `TRUST_PROXY_HEADERS=true` 并核对代理层数; +4. 配置 Redis 会话/缓存或确认文件会话目录具备隔离、持久化和清理策略; +5. 安装 `g++`,并为代码执行节点建立额外隔离; +6. 通过 `gunicorn -c gunicorn_config.py wsgi:application` 启动,再由 Nginx 或其他反向代理对外提供服务; +7. 持续监控 CPU、内存、数据库连接、任务队列、AI provider 配额、临时文件和日志磁盘。 + +### 7.4 本次接管环境实测记录 + +以下是 2026-09-03 在当前工作区的实际尝试,不代表目标生产环境结论: + +| 尝试 | 结果 | +| --- | --- | +| `python -m pip install -r requirements.txt` | 未执行安装;PowerShell 报错:`The term 'python' is not recognized as a name of a cmdlet, function, script file, or executable program.` | +| `python run.py` | 未启动;同样因为系统找不到 `python` 失败 | +| `python -m pytest tests -q` | 未执行测试;同样因为系统找不到 `python` 失败 | +| 工作区内置 Python `--version` | 可用,版本为 `Python 3.12.13` | +| 工作区内置 Python `-m pytest tests -q` | 失败:`No module named pytest` | +| `g++` PATH 检查 | 失败:`g++ not found on PATH`;因此无法验证 C++ 沙箱的真实编译运行 | +| 工作区内置 Python `-m compileall -q app.py routes services tasks utils` | 通过,退出码 `0`;这只是语法检查,不等价于应用启动或功能回归 | + +本次没有创建 `.env`、没有填入任何密钥,也没有连接正式数据库。要完成可运行验证,需要提供可安装依赖的 Python 环境(或在工作区内安装 `requirements.txt`)、`pytest`、C++ 编译器,以及按环境选择的 SQLite/MySQL、Redis 和 AI provider 配置。 + +## 8. 风险清单 + +| 优先级 | 风险 | 影响 | 当前缓解/后续方向 | +| --- | --- | --- | --- | +| 高 | C++ 沙箱是应用层 subprocess 限制,不是强隔离 | 恶意代码可能利用宿主机权限、文件、网络或资源;公网开放存在高风险 | 上线前增加容器/虚拟机、低权限用户、网络禁用、CPU/内存/进程/磁盘配额,并单独部署评测 worker | +| 高 | 后台任务主要在进程内运行 | 重启可能丢任务;多 worker 各自拥有队列、线程、缓存和去重状态,可能重复执行或任务不可见 | 迁移到持久化队列(如 Celery/RQ/消息队列),建立幂等键、重试、死信和可观测状态 | +| 高 | AI 输出和 AI 生成预设不是确定性事实 | 评分、提示、能力画像和阶段三判定可能受 provider、提示注入、上下文截断或模型升级影响 | 保留沙箱作为程序事实来源;固定评测协议和模型版本;增加人工复核、敏感数据脱敏、提示注入测试和结果审计 | +| 高 | 学生代码、对话、代码快照和 AI 结果包含学习隐私 | 数据库、日志、Redis、LLM provider 和导出文件都可能成为数据泄露面 | 明确数据保留/删除策略,限制日志内容和导出权限,生产密钥与数据库分离,核对第三方 AI 数据处理政策 | +| 中 | 数据库结构演进依赖 `create_all`、补列和索引检查 | 复杂变更、回滚和多版本并行发布缺少清晰迁移轨迹 | 建立版本化迁移、备份/恢复演练和生产前升级验证;不要把启动期自动维护当成完整迁移方案 | +| 中 | 授权逻辑分散在路由与查询组合中 | 新增 API 可能只做登录检查而漏掉对象归属、班级范围或角色边界 | 抽取可复用的角色/资源授权函数,补充越权矩阵测试 | +| 中 | 公开体验使用临时 SQLite 与后台线程交互 | 浏览器退出、文件锁、worker 生命周期和清理时序可能造成残留或失败 | 保持 run id 显式传递;在多进程环境验证锁和清理;为失败清理提供告警和定期维护 | +| 中 | 观测以日志和轻量探针为主 | 任务延迟、AI 首 token、熔断、队列堆积和沙箱资源消耗缺少完整指标 | 接入结构化指标、trace/request id、任务状态面板和 provider 用量监控 | +| 低 | 文档存在运行参数口径差异的可能 | 开发者可能使用错误的 WSGI 对象名、端口或代理配置 | 以 `wsgi.py`、`gunicorn_config.py` 和实际部署清单为准,后续统一 README、脚本和运维配置 | + +## 9. 未知项与下一步核对项 + +以下问题无法只通过当前代码确定,适合在阶段二或部署评审中补齐: + +| 问题 | 为什么未知 | 建议验证方式 | +| --- | --- | --- | +| 目标生产环境的 Nginx、HTTPS、进程管理和备份拓扑 | 仓库只提供应用侧配置,不能代表真实服务器 | 获取部署清单,验证 forwarded headers、Cookie、超时和优雅退出 | +| 实际使用的数据库类型、版本、字符集和迁移历史 | 代码同时支持 SQLite/MySQL,历史库结构未随仓库提供 | 对脱敏数据库执行维护命令和升级演练,记录耗时与回滚方案 | +| AI provider、模型版本、限额和数据留存策略 | 配置可选,provider 行为由外部服务决定 | 建立 provider 配置表、脱敏请求样本、限流/失败演练和成本上限 | +| C++ 评测是否允许公网用户触发 | 代码提供公开体验和代码执行,但部署访问范围不在仓库内 | 在网络边界文档中明确“课程内受控”还是“公网可用”,并按威胁模型验收沙箱 | +| 多 worker 下临时库绑定、会话、Redis 和后台任务的完整行为 | 单进程测试不能覆盖跨进程时序 | 用至少 2 个 worker 做并发登录、提交、登出、过期清理和 worker 重启测试 | +| 真实数据规模与查询容量 | 仅有估算报告,没有可复现的目标数据集和压测脚本 | 用脱敏数据压测登录、作业列表、提交状态、班级统计和 AI/SSE 峰值 | +| 成绩策略是否继续采用 0–5、知识点/能力采用 0–100 | 当前实现和 README 已采用该口径,但产品/教学规则可能变化 | 与课程负责人确认规则,并将规则写成可测试的策略文档 | +| 是否需要 CI、自动安全扫描和依赖更新策略 | 仓库未见明确 CI 工作流 | 确定 GitHub Actions、Python 版本矩阵、测试分层和依赖漏洞处理责任 | + +## 10. 阶段一结论与非目标 + +### 已形成的理解 + +- 这是一个以 Flask 单体为中心的教学平台,核心状态在 SQLAlchemy 模型中; +- 学生主链路由引导式学习、代码提交、C++ 受限执行、AI 反馈和能力分析共同构成; +- 阶段三已经从单纯文本对话扩展为带事件记忆、工具、覆盖度和完成条件的双 Agent 运行时; +- 公开体验通过临时数据库和显式 run id 做业务数据隔离; +- 当前小规模课堂/演示是较符合实现边界的使用场景,正式公网部署前必须优先补强沙箱和异步任务基础设施。 + +### 本阶段明确不做 + +- 不修改业务逻辑、路由行为、模型字段、提示词或前端交互; +- 不改变数据库结构、运行参数或部署脚本; +- 不把本文中的推断当成生产承诺; +- 不用文档替代安全评审、压测、迁移演练或真实环境验收。 + +后续修改应以本文的模块边界和未知项为检查清单,先补可验证的测试/运行证据,再进入业务代码变更。 + +## 11. 本次文档 PR 状态与阻塞 + +本地已创建分支 `docs/project-understanding`;分支相对 `main` 只有本文档一个新增文件,当前本地提交可直接用于后续推送。 + +尝试推送和创建远程分支时使用了以下操作: + +```text +git push -u origin docs/project-understanding +``` + +GitHub 返回:`remote: Permission to XiaoCow666/CodeSense.git denied to ggboyxkw666.`,HTTP `403`。随后通过 GitHub 连接器创建同名远程分支,返回:`Resource not accessible by integration`,HTTP `403`。检查发现当前账号没有目标仓库 push 权限,且没有可用的 `ggboyxkw666/CodeSense` fork,因此当前环境无法生成 PR 链接。 + +所需协助:为当前账号授予目标仓库分支写权限,或提供一个当前账号可推送的 fork。权限到位后,推送现有分支并以 `main` 为目标分支创建 PR 即可;不需要重新编写本文档。 diff --git a/project-understanding.md b/project-understanding.md deleted file mode 100644 index 7dd0f51..0000000 --- a/project-understanding.md +++ /dev/null @@ -1,288 +0,0 @@ -# CodeSense 项目理解与学习记录 - -## 一、项目定位 - -CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。它把代码提交、受限执行、AI 辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 - -### 主要用户 - -1. 学生:提交 C++ 程序、查看测试结果和反馈,进入三阶段引导式学习流程,记录自己的思路与解释。 -2. 教师:创建和管理作业、组织班级与花名册,查看提交记录、作业完成情况、知识点和能力趋势。 -3. 开发者/研究者:在 Flask、SQLAlchemy 和可替换的 AI 服务接口上继续扩展评测、教学和数据分析能力。 - -### 核心问题 - -传统 OJ 的两个痛点正是这个项目要解决的核心问题: - -1. 对学生:只看到"对/错",不知道问题出在哪。传统评测只给二元结果,学生无法定位问题究竟在思路、实现、边界条件还是调试过程。CodeSense 引入受限评测(Causal Sandbox)+ AI 辅导,并把一次练习拆成三阶段,强制学生先讲思路、再组装步骤、最后用自己的话解释(费曼教学),让"理解"过程可见、可评估。 -2. 对教师:反馈零散、共性问题难发现。教师要在大量提交记录里人工找共性问题,再把零散反馈整理成教学安排,成本高。CodeSense 用两层画像体系沉淀学情:AI 反馈与能力分析文本按算法、代码风格、功能完整性、执行效率、可读性等维度组织(综述存于 `AbilityTrend` 的能力分析内容),可量化的画像则以 C 知识点为单位、经贝叶斯权重更新为 0–100 的 `KnowledgePointScore`。教师端据此把学生表现沉淀为可统计、可下钻的学情数据,辅助教师定位需要补练的内容。 - -## 二、总体结构与目录分层 - -### 顶层文件(入口与配置) - -- `run.py`:开发启动入口,默认走开发配置。 -- `app.py`:应用工厂,`create_app()` 注册 Blueprint、初始化 DB/会话/登录态、ProxyFix、后台任务、访问日志与压缩中间件。 -- `wsgi.py`:生产 WSGI 入口,配合 `gunicorn_config.py`。 -- `config.py`:development / testing / production 三套配置,读取 `.env`。 -- `models.py`:全部 ORM 模型(见下)。 -- `forms.py`:Flask-WTF 表单定义。 -- `database_maintenance.py`:生产一次性建表/迁移/索引维护。 -- `deploy.sh` / `update.sh`:部署与运维脚本。 - -### routes/ — Web 与 API 路由层(Blueprint) - -- `auth.py`:登录/登出/注册/教师邀请,角色认证。 -- `main.py`:首页、关于、帮助等基础页面。 -- `assignments.py`:作业 CRUD、测试用例与提交管理。 -- `thinking.py`:三阶段引导式学习(思路/积木/费曼)与阶段 Agent API。 -- `classes.py`:班级、花名册、导入与班级统计。 -- `users.py`:用户资料、学生/教师/管理员页面。 -- `grades.py`:成绩视图与课程评分。 -- `api.py`:提交评测、代码建议、能力分析 SSE 等 REST 接口。 - -路由层只做参数解析、权限校验与业务编排,不承载核心逻辑。 - -### services/ — 面向业务的"较厚"服务层 - -- `llm_client.py`:统一 LLM 客户端(`SharedLLMClient`),智谱/OpenAI 多 provider 重试、限流与熔断。 -- `ai_evaluator.py`:AI 评测(含流式能力分析)。 -- `api_keys.py`:API 密钥管理器(不落库明文)。 -- `course_grading.py`:课程成绩计算。 -- `teacher_analytics.py`:教师端班级/知识点学情统计。 -- `teacher_ai_advisor.py`:AI 学情建议。 -- `demo_database.py` / `demo_experience.py`:公开体验入口的临时 SQLite 会话隔离与演示数据。 - -### utils/ — 底层工具与核心引擎 - -- `sandbox_runner.py`:Causal Sandbox:g++ C++17 受限编译/运行,15s 编译 / 5s 运行超时,stdout/stderr 各有界读取(各 4096 字节上限、超限即终止进程),用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error` 等)。 -- `code_evaluator.py`:启发式评分 + 可选 LLM 评估叠加。 - (早期版本曾使用 CodeBERT + TextCNN 本地模型评分,当前 main 已移除,相关描述仅见于历史文档/提交。) -- `llm_evaluator.py`:旧版 LLM 评估器 `LLMEvaluator`。注意:它仍自行初始化 provider 客户端并选择 api_type(`zhipu`/`openai`),仅在发请求时委托给 `services/llm_client.py::SharedLLMClient`。 -- `guidance_generator.py`:启发式引导提示生成(不直接给答案)。 -- `code_advisor.py`:代码建议。 -- `ability_scorer.py` / `maturity_calculator.py`:贝叶斯能力画像与成熟度。 -- `async_tasks.py` / `sse.py`:线程池任务队列 + SSE 流式推送。 -- `thinking_ai.py`:三阶段引导 AI 交互。 -- `markdown_formatter.py`:格式化输出。 -- `prompts.py`:提示词模板。 -- `auth.py` / `api.py` / `validate_testcases.py`:权限装饰器、通用 API 辅助与测试用例校验。 - -### utils/agents/ — 阶段三费曼/论坛 Agent 子系统 - -- `feynman.py`:双角色(教师/学生上下文)Agent 运行时。 -- `loop.py`:Agent 主循环;`tools.py`:工具;`model.py`:模型适配。 -- `orchestrator.py`:编排;`intent.py`:意图路由;`memory.py`:记忆; - `coverage.py`:知识点覆盖判定;`goal.py`:目标管理;`contracts.py`:数据契约。 - -### tasks/ — 异步任务 - -- `submission_tasks.py`:提交后评测、AI 分析等后台任务。 -- `ability_analysis.py`:能力画像的异步计算与分析。 - -### 前端 - -- `templates/`:Jinja2 页面,含按角色区分的首页/详情页,以及 `templates/thinking/arena.html`(三阶段竞技场)、组件化的多种代码编辑器片段。 -- `static/`:CSS、JS(Monaco 按需加载、SSE 客户端、编辑器/提交/思路对话脚本、安全输出处理器)、图片与第三方库(Sortable、require.min.js)。 - -### 核心数据模型一览(models.py) - -- 用户与组织:`User`(学生/教师/管理员 + RBAC)、`Class`、`StudentRoster`、`InviteToken`。 -- 教学资源:`Assignment`、`AssignmentKnowledgePoint`、`TestCase`、`AssignmentThinkingPreset`。 -- 学习记录:`Submission`、`ThinkingSession`、`ThinkingStageLog`、`StudentQuestion`、`CodeAdviceRequest`。 -- 画像与学情:`AbilityTrend`、`KnowledgePointScore`、`TeacherAISuggestion`。 -- 平台支撑:`SystemLog`、`SystemConfig`、`CodeSenseSession`。 - -### 测试(tests/) - -覆盖面较广,突出三类特色域:沙箱演示特性(`test_sandbox_features`,实为演示数据装载/免密登录/生产禁用三项用例,见附录 B,不直接覆盖 C++ 编译执行)、演示会话隔离(`test_demo_*`)、阶段三 Agent/论坛(`test_stage3_*`),另有 SSE、成绩、班级花名册、HTTPS 代理、性能基线,以及沙箱输出限制的有界进程测试(`test_sandbox_output_limits.py`,mock 编译器、不触发真实 g++,见附录 B)等测试。 - -## 三、核心运行流程与调用链 - -### 1. 应用启动与请求生命周期 - -`run.py` / `wsgi.py` → `app.py::create_app`:加载 `config.py`、初始化 db、注册所有 Blueprint(routes/)、接入 Flask-Login / Flask-Session、ProxyFix、后台任务队列与压缩/日志中间件。请求进入 Blueprint 路由,经 services/ 编排,落到 utils/ 引擎与数据库。 - -说明:development 环境在启动时自动建表;production 环境 `DB_AUTO_INIT=False`,需先运行 `database_maintenance.py` 建表/维护索引。 - -### 2. 代码提交 → 评测调用链(最重要的一条) - -代码提交有两条平行通路: - -**A. 网页表单路径(异步,主流)** - -`POST /submit/`(`routes/assignments.py::submit_code`,蓝图无 url_prefix)→ 创建 `Submission(status=pending)` → 把任务投进后台线程 `tasks/submission_tasks.py::evaluate_submission_async` → 页面跳转到"评测中",前端经 `get_submission_status`(`routes/api.py`)/ SSE 轮询进度。 - -后台线程按序执行: - -1. AI 基础评估:`utils/code_evaluator.py::evaluate_cpp_code`,内部为启发式评分(`calculate_heuristic_score` 用局部变量 `normalized_score` 归一到 0–5)+ 可选 LLM 反馈,产出 score/feedback;回到任务层 `tasks/submission_tasks.py` 后再经 `_normalise_score` 兜底归一到 0–5(该函数定义于 submission_tasks.py,能按 0–5 / 0–10 / 0–100 三种量纲归一后取整)。(LLM 叠加经 `utils/llm_evaluator.py::LLMEvaluator`,其网络请求再委托 `services/llm_client.py::SharedLLMClient`。) -2. 沙箱用例评判:`utils/sandbox_runner.py::run_test_cases` → `compile_cpp` 用 g++ 按 C++17 编译(15s 超时、编译器的 stdout/stderr 输出同样受限)→ `run_single_test` 逐用例运行(5s 超时;内部经有界管道线程 `_BoundedPipeReader` 以 stdout/stderr 各 4096 字节为上限边跑边读,超限立即终止进程并记 `termination_reason`,超时/运行错误同样有明确终止原因,超限结果一律不判通过)→ 写回 `sandbox_passed/total/detail`;存在测试用例时以沙箱通过率重算最终 0–5 分(沙箱重算结果同样再走一次 `_normalise_score` 后才落库)。 -3. 状态置为 evaluated,并 `_refresh_assignment_stats` / `_refresh_user_stats` 基于全量历史重算,避免种子数据重复累加。 -4. 知识点画像:用作业绑定或 AI 探测出的知识点调 `KnowledgePointScore.update_score`。 -5. 触发能力分析:`AbilityTrend.mark_as_outdated` + `trigger_analysis_if_needed()`(内部按键去重防并发)。 -6. 写 `SystemLog`(公开体验会话不写正式库审计日志)。 - -**B. API 路径(同步)** - -`POST /api/submit`(`routes/api.py::submit_code`):同步 `evaluate_cpp_code` + 更新作业统计 + 触发能力分析,直接 JSON 返回 submission_id/score/status。 - -**数据落库**:`Submission`(含 sandbox_*、ai_feedback)→ `Assignment`/`User` 聚合 → `KnowledgePointScore` → `AbilityTrend`。 - -### 3. 三阶段引导式学习调用链 - -入口 `GET /thinking/`(`routes/thinking.py`)加载 `templates/thinking/arena.html`: - -1. 会话初始化:`POST /thinking/api/start_session`(thinking 蓝图 `url_prefix='/thinking'`)创建 `ThinkingSession`,装载 `AssignmentThinkingPreset`(目标、关键步骤、提示语);无预设时走 AI 生成并 lazy 回填。 -2. 阶段一(思路):`POST /thinking/api/stage1/submit` → `utils/thinking_ai.py::evaluate_description` 先做本地快速检查、必要时请求 AI,按 key_steps 匹配打分;≥50 分放行至阶段二,逐条写 `ThinkingStageLog`。 -3. 阶段二(组装):`POST /thinking/api/stage2/verify` 验证步骤顺序并把组装结果规整成可编译代码、生成预览;AI 回应统一经 `utils/thinking_ai.py::sanitize_response` 做物理级代码过滤——这是提示词约束之外的第二层防泄漏。 -4. 阶段三(费曼/论坛):`POST /thinking/api/stage3/forum/message` → `utils/agents/orchestrator.py::Stage3Orchestrator.handle_user_message` → intent 意图识别、目标角色仲裁(学生/教师双 Agent)、loop 多轮、tools 追问/探测、coverage 判定掌握度,SSE 流式返回;`POST /thinking/api/stage3/forum/trace` 提供轨迹复盘,`POST /thinking/api/complete_session` 收尾归档。 - -**AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 - -- 新链路(三阶段对话、能力分析、教师建议等)直接使用 `services/llm_client.py::SharedLLMClient`(多 provider 重试、限流、熔断集中在此)。 -- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。 - -### 4. 能力画像与教师端学情链路 - -提交评测成功后(异步/同步两通路一致)即触发能力分析刷新:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 - -**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 - -**失败可见性**:AI/沙箱失败在体验中一律置 failed,前端显示"失败/重试",不允许用默认分数伪装成功。 - -## 四、架构理解 - -CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C++ 编程教学」:学生交代码 → 受限沙箱编译运行 → AI 启发式引导学习 → 沉淀能力画像;教师端管理班级/作业并查看学情。架构上采用「路由 → 服务 → 引擎/任务 → 模型」的分层,并配了一套会话级临时 SQLite 的公开演示隔离机制。 - -### 分层思路 - -- **routes/**(蓝图/路由层):页面 + JSON/SSE API,只做参数解析、权限校验、编排服务。 -- **services/**:业务服务层,偏纯逻辑、易单测(LLM 客户端抽象、AI 评估、密钥管理、成绩册、教师分析、演示数据隔离)。 -- **utils/**:引擎/工具层(代码评测、沙箱执行、提示词、能力画像、SSE、权限装饰器,以及三阶段 Agent 引擎 `utils/agents/`)。 -- **tasks/**:后台任务(异步评测、能力分析)。 -- **models.py**:单一 ORM 文件(约 1500 行,含 18 个 `db.Model` 数据表模型 + 1 个 `CodeSenseSession` 会话存储类——后者继承 FlaskSQLAlchemySession,非 ORM 表,合计 19 个 class);**templates/**、**static/**:Jinja2 模板与前端资源;**tests/**:pytest 测试。 - -### 启动链路与关键机制 - -`app.py` 是唯一入口,`create_app()` 应用工厂:加载 `config.py`(development/testing/production 三套)→ 配置数据库连接池、Session(优先 Redis,失败降级文件系统)→ 初始化 db、Flask-Login、Flask-Session → 注册 8 个蓝图 → 初始化异步任务系统 → 自动建表(development)。根级挂了全局 `before_request`:单点登录校验 + demo 临时库激活。 - -### 核心子系统 - -1. **代码评测执行链(Causal Sandbox)**:以 g++ C++17 编译,15s 编译 / 5s 运行超时、临时工作目录、stdout/stderr 各有界读取(各 4096 字节上限,超限即终止进程,不视为正常结束)、标准化输出比对,用例结果带 `termination_reason`(`stdout_limit`/`stderr_limit`/`timeout`/`runtime_error`)。调用链: - `routes (submit) → tasks/submission_tasks.evaluate_submission_async → utils/code_evaluator(启发式评分 + 可选 LLM 叠加)→ utils/sandbox_runner.run_test_cases(受限编译运行)`。 - 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。沙箱输出有界化来自上游提交 `fix: bound C++ sandbox stdout and stderr`,配套测试 `tests/test_sandbox_output_limits.py`(mock 编译器、用 Python 解释器进程验证有界进程行为,见附录 B)。 -2. **AI 服务抽象**:`services/llm_client.py::SharedLLMClient` 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;`services/api_keys.py` 统一管理密钥。新链路只依赖这一层;旧评估器 `utils/llm_evaluator.py::LLMEvaluator` 的初始化/选型逻辑仍在旧模块内(见三.3"AI 调用现状")。 -3. **异步 + SSE**:提交后不阻塞请求,任务由线程池执行,前端通过 `utils/sse.py` 的 SSE 流(如 `/api/stream/ability-analysis`)拿进度。 -4. **三阶段引导式学习(thinking)**:一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 `utils/agents/`;入口路由在 `routes/thinking.py`,页面在 `templates/thinking/arena.html`。 -5. **公开演示体验隔离(重点设计)**:不注册真实账号也能体验。每次进入 `/login` 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(`services/demo_database.py`),由 `before_request` 按会话激活该库;演示账号(`demo:*`)走 Flask-Login 的独立 user_loader。`services/demo_experience.py` 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除,与 AGENTS.md 的 PR worktree 数据隔离约定一致。 -6. **成绩与画像**:作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,`ability_scorer` + `AbilityTrend`/`KnowledgePointScore`)。`routes/grades.py` + `services/course_grading.py` 汇总成绩册并导出 Excel;教师 AI 建议在 `services/teacher_ai_advisor.py`。 - -### 安全/运维要点 - -- 权限分三类装饰器:`login_required` / `teacher_required` / `admin_required`。 -- 单点登录:`before_request` 比对 session 与库内 `current_session_id`,发现并发登录强制登出。 -- Session 优先 Redis,失败自动降级文件系统;生产强制 `SECRET_KEY` ≥32、`DB_AUTO_INIT=False`(需先跑 `database_maintenance.py` 建表/索引)。 -- 提供 `/healthz`、`/readyz` 探针、ProxyFix 反代协议还原、gzip 压缩与慢请求日志。 -- 提交评测错误处理已加固(上游提交 `fix: harden submission error handling`):后端与日志不再回显完整异常及堆栈(只记异常类型名),用户侧统一返回通用提示(如"请稍后重试");评测页前端轮询设 60 次上限(`maxPollAttempts = 60`,间隔 2s),轮询超限时提示"暂时无法确认评测结果,请稍后刷新或重新提交",评测队列不可用时提示"评测队列暂时不可用,请稍后刷新或重新提交"。 - ---- - -## 附录 A:个人理解与后续设想(【非现状】,仅代表个人想法) - -> 以下内容不属于当前仓库现状,是学习过程中产生的问题记录与改进设想。 - -1. **对 AI 助手回复过滤的设想**:当前只在 `utils/thinking_ai.py` 内对回复做"物理级代码屏蔽"。我认为不应完全屏蔽:可以做一个 agent 专门监测回复,把与答案直接相关的代码屏蔽掉,而保留与知识点相关的示例代码来帮助学生理解;同时检查回复是否正确,提高回复正确率。 -2. **第三阶段三元角色设想**:目前费曼是"教师/学生"双 Agent。我认为可以让老师 agent 给我一个任务,让我给学生 agent 讲这个知识点,把我的理解完整讲完;学生 agent 再提问。如果我讲的知识点有错误、模糊或缺失,就由学生 agent 多角度追问检查;如果我回答不上来,就转向老师 agent 提问。进一步,希望两个智能体共享数据:老师给我讲解和提问、我给学生讲解、学生指出我讲不清楚处并给出代码修复,构成"老师—我—学生"三元关系,用算法适配这套数据流通。 -3. **自适应选题设想**:可依据 AI 助手互动中生成的追问问题来优化题目并沉淀进题库,再用深度学习/自适应算法按学生水平分配题目。 -4. **情感分析与学习积极性设想**:希望纳入学习态度与积极性评估,指标可包括:对 AI 助手的使用程度;对作业开设习题复习处、设置复习环节并评估复习效果;最后用算法综合评价学生的学习积极性。 -5. **使用中发现的体验问题**: - - 引导式学习第二部分给出的题目会多出一些无关内容,中间完整代码展示处的代码并不完整(左侧按题拼凑的代码完整,中间展示的有所缺失,但能正常运行出正确结果)。 - - 代码页右侧的 AI 助手回答会重复。 - - 代码提交后的评估多是 C++ 向,对 C 语言的评估不够准确。 - - AI 响应较慢,且因 prompt 缘故回复略显臃肿。 - - 第二阶段"请求提示"无法定位学生具体卡在哪个问题:它通常从第一阶段的问题继续从头解释并提问,难以直接帮学生解决当前卡点。设想把请求提示精确到具体问题,直接给该问题的提示并提问与当前题目相关的问题。 -6. **学习计划**:后续需要逐步学习项目相关技术栈,积累实践经验,目前对项目内不少内容理解还不到位,希望能逐步赶上学长进度。 - -## 附录 B:个人安装、运行与测试记录(个人环境备忘) - -- 记录时间:2026-09-03(2026-09-05 按 PR 评审意见补充真实 C++ 编译运行验证与范围说明,并随分支 rebase 至上游 main 后复核新版沙箱引擎);环境:Windows,Python 3.11(项目虚拟环境 .venv),g++ 16.1.0(MSYS2,路径位于 MSYS2 的 mingw64/bin 下,与 `utils/sandbox_runner.py` 的编译器候选路径一致);项目:CodeSense(v1.0.0)。 - -### 安装 - -按 README「快速开始」在项目根目录完成: - -```powershell -py -3.11 -m venv .venv -.\.venv\Scripts\Activate.ps1 -python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -``` - -依赖安装成功,共 60 个包,核心版本为 Flask 2.2.3、SQLAlchemy 2.0.52、python-docx 1.2.0、openai 3.7.0、cryptography 41.0.3 等。随后安装 C++ 编译器 g++ 16.1.0(MSYS2)。 - -过程中遇到的问题与解决: - -1. Python 3.14 兼容性问题:系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 `ast.Str`,启动即报 `AttributeError: module 'ast' has no attribute 'Str'`。改用 Python 3.11 创建虚拟环境后解决。 -2. `.env` 残留 MySQL 配置:`.env` 中的 `DATABASE_URL` 实际仍指向本地 MySQL(user:password@127.0.0.1:3306),启动时 `db.create_all()` 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 - -### 运行 - -开发配置启动(未设置 DATABASE_URL 时使用本地 SQLite,首次启动自动建表): - -```powershell -.\.venv\Scripts\Activate.ps1 -python run.py -``` - -启动结果:数据库初始化成功,异步任务系统初始化成功;Running on http://127.0.0.1:5000。本机未安装 Redis,会话自动降级为文件系统存储(filesystem),不影响使用。浏览器访问 http://127.0.0.1:5000/login,登录页提供免注册的学生体验与教师体验入口。 - -说明:启动日志中的"生产模式:启用 INFO 级别日志"字样由 `.env` 内 `FLASK_DEBUG='False'` 引起,实际运行配置为 development(日志显示 Debug mode: on),不构成问题。 - -### 测试 - -**1. 沙箱演示特性自动化测试(pytest)** - -```powershell -.\.venv\Scripts\python.exe -m pytest tests/test_sandbox_features.py -q -``` - -结果:3 passed, 26 warnings(2026-09-05 本机复测约 60s)。三项用例分别为 `test_seed_demo_data_creation`(演示数据装载)、`test_sandbox_login_flows`(免密登录)、`test_security_prevents_sandbox_in_production`(生产环境禁用沙箱),属于"沙箱(演示)登录与安全特性"测试,**并未调用 g++ 编译运行代码**。另经核对,`tests/test_demo_submission_isolation.py` 中同样对 `run_test_cases` 做了 mock;上游 main 新增的 `tests/test_sandbox_output_limits.py`(2026-09-05 本机复测 5 passed in 1.01s)同样把编译器 patch 掉、改用 Python 解释器子进程验证 stdout/stderr 有界截断、超时与退出码等有界进程行为。因此 tests/ 目录当前不存在覆盖真实 C++ 编译运行链路的端到端用例,此前"通过沙箱评测相关测试即可说明代码评测链路可用"的表述不准确,见下方补充验证。 - -**2. 真实 C++ 编译运行链路验证(2026-09-05 补充,回应评审意见)** - -直接调用 `utils/sandbox_runner.py::run_test_cases`,对一段 C++17 加法程序(`cin` 读入、`cout` 输出)用本机 g++ 编译后运行 3 个用例(含公开与隐藏用例)。该验证在合并上游新版沙箱引擎(有界管道读取,提交 `fix: bound C++ sandbox stdout and stderr`)后于 2026-09-05 复测一致,结果: - -```text -compiler = C:\msys64\mingw64\bin\g++.exe # g++ (MSYS2) 16.1.0,与沙箱候选路径一致 -compiler_available = true, compile_success = true, compile_error = "" -passed 3 / total 3, status = passed -# 各用例 termination_reason = null(正常完成),输出经 _normalize_output 比对一致,单例运行 31–186ms -``` - -验证方式为临时脚本(用后即删): - -```python -from utils.sandbox_runner import run_test_cases - -source = '''#include -using namespace std; -int main() { int a, b; cin >> a >> b; cout << a + b << endl; return 0; }''' - -run_test_cases(source, [ - {'input_data': '3 5\n', 'expected_output': '8', 'id': 1, 'is_public': True}, - {'input_data': '-1 1\n', 'expected_output': '0', 'id': 2, 'is_public': False}, - {'input_data': '100 200\n', 'expected_output': '300', 'id': 3, 'is_public': False}, -]) -``` - -由此可确认:在具备 g++ 的本机环境下,C++17 源码可经沙箱完成编译→运行→输出标准化比对→判定。该验证覆盖引擎层单次编译与运行,**未覆盖完整 Web 提交→后台任务→SSE/轮询→落库链路**(该链路中的 AI 叠加评分依赖真实 AI 密钥)。 - -### 结论 - -本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;上游 main 新增的沙箱输出限制有界进程测试 5 项通过(mock 编译器);并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用(合并上游新版沙箱引擎后复测一致)。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 - -### 个人工具与参考资料 - -- AI 工具:Trae(接入 ds-v4-flash)。 -- 参考资料: - - MSYS2 安装相关: - - Git 命令入门相关: From 22f93d4176410434f0bfdc760eda45605901a53d Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 15:09:31 +0800 Subject: [PATCH 10/12] =?UTF-8?q?docs:=20=E6=8C=89=E5=A4=8D=E5=AE=A1=20P3?= =?UTF-8?q?=20=E6=84=8F=E8=A7=81=E4=BF=AE=E6=AD=A3=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E8=AF=84=E6=B5=8B=E8=8C=83=E5=9B=B4=E5=8F=8A=20Python=203.14?= =?UTF-8?q?=20ast.Str=20=E7=A7=BB=E9=99=A4=E7=89=88=E6=9C=AC=E8=A1=A8?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding_wjh.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project-understanding_wjh.md b/project-understanding_wjh.md index 7dd0f51..fc91917 100644 --- a/project-understanding_wjh.md +++ b/project-understanding_wjh.md @@ -172,7 +172,7 @@ CodeSense 是一个 Flask 单体 Web 应用(Python),核心是「C 语言/C `routes (submit) → tasks/submission_tasks.evaluate_submission_async → utils/code_evaluator(启发式评分 + 可选 LLM 叠加)→ utils/sandbox_runner.run_test_cases(受限编译运行)`。 注意:当前 main 的 `code_evaluator.py` 模块说明为"启发式评分和大模型评估",不再依赖本地 CodeBERT/TextCNN 模型(后者为早期版本实现,仅见于 AGENTS.md 等历史描述)。沙箱输出有界化来自上游提交 `fix: bound C++ sandbox stdout and stderr`,配套测试 `tests/test_sandbox_output_limits.py`(mock 编译器、用 Python 解释器进程验证有界进程行为,见附录 B)。 2. **AI 服务抽象**:`services/llm_client.py::SharedLLMClient` 统一封装智谱/OpenAI,含 provider 健康状态、故障切换、退避重试;`services/api_keys.py` 统一管理密钥。新链路只依赖这一层;旧评估器 `utils/llm_evaluator.py::LLMEvaluator` 的初始化/选型逻辑仍在旧模块内(见三.3"AI 调用现状")。 -3. **异步 + SSE**:提交后不阻塞请求,任务由线程池执行,前端通过 `utils/sse.py` 的 SSE 流(如 `/api/stream/ability-analysis`)拿进度。 +3. **异步评测 + SSE**:异步不阻塞仅适用于网页表单提交路径——`POST /submit/`(`routes/assignments.py::submit_code`)提交后即返回,评测任务由后台线程池执行(`tasks/submission_tasks.py::evaluate_submission_async`),前端经 `get_submission_status`/SSE 轮询进度;而 API 路径 `POST /api/submit`(`routes/api.py::submit_code`)为同步评测、直接 JSON 返回结果(两通路详见三.2 的 A/B)。能力分析等流式进度经 `utils/sse.py` 提供(如 `/api/stream/ability-analysis`)。 4. **三阶段引导式学习(thinking)**:一次练习 = 思路描述 → 步骤组装 → 费曼教学(stage3)。费曼部分是一套较重的多角色 Agent 系统,全在 `utils/agents/`;入口路由在 `routes/thinking.py`,页面在 `templates/thinking/arena.html`。 5. **公开演示体验隔离(重点设计)**:不注册真实账号也能体验。每次进入 `/login` 的体验入口会生成一个带随机 run_id 的独立临时 SQLite(`services/demo_database.py`),由 `before_request` 按会话激活该库;演示账号(`demo:*`)走 Flask-Login 的独立 user_loader。`services/demo_experience.py` 负责向临时库播种演示学生/作业/提交等数据,退出或超时(空闲 1h / 最长 2h)即删除,与 AGENTS.md 的 PR worktree 数据隔离约定一致。 6. **成绩与画像**:作业提交分 0–5 分;知识点/能力 0–100 分(贝叶斯权重,`ability_scorer` + `AbilityTrend`/`KnowledgePointScore`)。`routes/grades.py` + `services/course_grading.py` 汇总成绩册并导出 Excel;教师 AI 建议在 `services/teacher_ai_advisor.py`。 @@ -221,7 +221,7 @@ python -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/sim 过程中遇到的问题与解决: -1. Python 3.14 兼容性问题:系统 Python 为 3.14,Flask 依赖的 Werkzeug 2.2.3 使用已被 3.12+ 移除的 `ast.Str`,启动即报 `AttributeError: module 'ast' has no attribute 'Str'`。改用 Python 3.11 创建虚拟环境后解决。 +1. Python 3.14 兼容性问题:本机系统 Python 为 3.14,在其上运行即报 `AttributeError: module 'ast' has no attribute 'Str'`。原因:`ast.Str`(连同 `ast.Num`/`ast.Bytes`/`ast.NameConstant`/`ast.Ellipsis`)自 Python 3.8 起弃用、到 **Python 3.14 才真正移除**(3.12、3.13 仍保留该兼容类);而项目依赖的 Werkzeug 2.2.3 在 `werkzeug/routing/rules.py::_compile_builder` 中仍使用 `ast.Str` 生成 URL 构建函数——该归因已在本机 Python 3.14 下复现验证,报错堆栈即指向上述文件。改用 Python 3.11 创建虚拟环境后恢复。 2. `.env` 残留 MySQL 配置:`.env` 中的 `DATABASE_URL` 实际仍指向本地 MySQL(user:password@127.0.0.1:3306),启动时 `db.create_all()` 连接 MySQL 被拒(WinError 10061)。注释该行后回退到本地 SQLite 数据库。 ### 运行 From d18243aaaefdd29b22b39919a80d2d459ad49a2a Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 15:13:51 +0800 Subject: [PATCH 11/12] =?UTF-8?q?docs:=20=E6=AD=A3=E6=96=87=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E7=BB=93=E8=AE=BA=E6=A0=87=E6=B3=A8(=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E7=A1=AE=E8=AE=A4/=E8=BF=90=E8=A1=8C=E9=AA=8C?= =?UTF-8?q?=E8=AF=81)=E4=B8=8E=E9=99=84=E5=BD=95B=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E6=BE=84=E6=B8=85,=20=E5=9B=9E=E5=BA=94=E5=A4=8D=E5=AE=A1P3?= =?UTF-8?q?=E6=84=8F=E8=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding_wjh.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/project-understanding_wjh.md b/project-understanding_wjh.md index fc91917..6f36907 100644 --- a/project-understanding_wjh.md +++ b/project-understanding_wjh.md @@ -1,5 +1,7 @@ # CodeSense 项目理解与学习记录 +> 结论标注约定:本文正文的机制性结论统一按证据强度标注——**【源码确认】**=依据所注源码位置(路径/函数)与提交 SHA(默认本仓库 main HEAD `22f93d4`,即 PR #14 当前 head)静态核对得出;**【源码推断】**=仅由调用关系或注释推断、未逐行核实;**【运行验证】**=对应附录 B 中本人实际运行/测试的记录。未附“运行验证”字样的机制性断言均属源码静态分析结论,其运行级验证范围与边界见附录 B「范围澄清」。 + ## 一、项目定位 CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。它把代码提交、受限执行、AI 辅导、分阶段练习、学情分析放进同一条学习链路。核心定位是:引导学生自己学会,而不是替学生写出答案。 @@ -140,13 +142,13 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 **AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 - 新链路(三阶段对话、能力分析、教师建议等)直接使用 `services/llm_client.py::SharedLLMClient`(多 provider 重试、限流、熔断集中在此)。 -- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。 +- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。(结论标注:**源码确认**,未经真实 AI 请求运行验证。依据:`utils/llm_evaluator.py::LLMEvaluator._chat_completions_create` 将实际网络请求委托给 `services/llm_client.py::SharedLLMClient`,而 `_init_client` 仍在本模块完成客户端初始化与 api_type 选型;源码基线本仓库 main HEAD `22f93d4`,运行级验证见附录 B「范围澄清」。) ### 4. 能力画像与教师端学情链路 提交评测成功后(异步/同步两通路一致)即触发能力分析刷新:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 -**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。 +**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。(结论标注:**源码确认**,未做运行验证。依据:`services/demo_database.py::activate_demo_run`/`activate_demo_request_database` 的临时库切换,`tasks/submission_tasks.py::evaluate_submission_async` 的 docstring 注明“demo_run_id 为空时才使用正式数据库”且线程内二次校验会话存活,配套用例为 `tests/test_demo_submission_isolation.py` 等 `tests/test_demo_*`;源码基线本仓库 main HEAD `22f93d4`。附录 B 未复跑 demo 用例,此隔离保证的运行级验证待补。) **失败可见性**:AI/沙箱失败在体验中一律置 failed,前端显示"失败/重试",不允许用默认分数伪装成功。 @@ -280,6 +282,8 @@ run_test_cases(source, [ 本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;上游 main 新增的沙箱输出限制有界进程测试 5 项通过(mock 编译器);并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用(合并上游新版沙箱引擎后复测一致)。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 +范围澄清(回应复审 P3 意见):附录 B 的**运行验证**仅覆盖上文所列事项——沙箱(演示)特性测试 3 项、沙箱输出限制有界进程测试 5 项、真实 g++ 16.1.0 编译运行 3 例、`python run.py` 启动。正文中“AI 实际网络请求统一委托 SharedLLMClient”“公开体验绝不写正式库”等**源码确认**结论,均仅依据本仓库 main HEAD `22f93d4` 的源码静态核对得出:前者未使用真实 AI 密钥触发过 LLM 调用,后者对应的 `tests/test_demo_*` 隔离用例未在附录 B 复跑。这两类机制结论的运行级验证待后续补充,读到时请勿视为已被实跑确认。 + ### 个人工具与参考资料 - AI 工具:Trae(接入 ds-v4-flash)。 From 3c6b644fbcc9069a033e7b6974bd8bad34700a21 Mon Sep 17 00:00:00 2001 From: Swan1127 <3444176319@qq.com> Date: Sun, 6 Sep 2026 15:19:13 +0800 Subject: [PATCH 12/12] =?UTF-8?q?docs:=20=E5=B0=86=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E6=A0=B8=E5=AF=B9=E5=9F=BA=E7=BA=BF=E5=9B=BA=E5=AE=9A=E4=B8=BA?= =?UTF-8?q?=E5=8D=95=E4=B8=80=E5=AE=9A=E4=B9=89(22f93d4)=E5=B9=B6=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=85=A8=E6=96=87=E5=BC=95=E7=94=A8,=20=E4=B8=8EPR=20?= =?UTF-8?q?head=E8=A7=A3=E8=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project-understanding_wjh.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/project-understanding_wjh.md b/project-understanding_wjh.md index 6f36907..7f7ef45 100644 --- a/project-understanding_wjh.md +++ b/project-understanding_wjh.md @@ -1,6 +1,6 @@ # CodeSense 项目理解与学习记录 -> 结论标注约定:本文正文的机制性结论统一按证据强度标注——**【源码确认】**=依据所注源码位置(路径/函数)与提交 SHA(默认本仓库 main HEAD `22f93d4`,即 PR #14 当前 head)静态核对得出;**【源码推断】**=仅由调用关系或注释推断、未逐行核实;**【运行验证】**=对应附录 B 中本人实际运行/测试的记录。未附“运行验证”字样的机制性断言均属源码静态分析结论,其运行级验证范围与边界见附录 B「范围澄清」。 +> 结论标注约定:本文正文的机制性结论统一按证据强度标注——**【源码确认】**=依据固定的「源码核对基线」提交(`22f93d4`,本仓库 main 上的固定提交,可在仓库按 SHA 定位;其源码文件与本次修订相比无代码改动,仅本文档自身有修订)静态核对得出,标注中另给出对应源码位置;**【源码推断】**=仅由调用关系或注释推断、未逐行核实;**【运行验证】**=对应附录 B 中本人实际运行/测试的记录。重要:**「源码核对基线」是固定历史快照,不代表 PR 当前 head**——PR head 会随文档修订继续移动,基线不随之变更,也不会因替换 SHA 而声称重新核对;后文所有“源码核对基线(见文首)”均指向此同一提交,正文与附录 B 不再重复给出 SHA 或“main HEAD/当前 head”等易过期表述。未附“运行验证”字样的机制性断言均属源码静态分析结论,其运行级验证范围与边界见附录 B「范围澄清」。 ## 一、项目定位 @@ -142,13 +142,13 @@ CodeSense 是一个面向高校编程教学的 AI 辅助评测与学习平台。 **AI 调用现状(重点)**:仓库当前处于新老两层并存的迁移状态。 - 新链路(三阶段对话、能力分析、教师建议等)直接使用 `services/llm_client.py::SharedLLMClient`(多 provider 重试、限流、熔断集中在此)。 -- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。(结论标注:**源码确认**,未经真实 AI 请求运行验证。依据:`utils/llm_evaluator.py::LLMEvaluator._chat_completions_create` 将实际网络请求委托给 `services/llm_client.py::SharedLLMClient`,而 `_init_client` 仍在本模块完成客户端初始化与 api_type 选型;源码基线本仓库 main HEAD `22f93d4`,运行级验证见附录 B「范围澄清」。) +- 旧链路(提交评测中的 LLM 叠加)仍先经 `utils/llm_evaluator.py::LLMEvaluator`:该对象在 `_init_client` 里自行初始化 ZhipuAI/OpenAI 客户端并选择 api_type,仅真正发请求的 `_chat_completions_create` 委托给 `SharedLLMClient`。因此"所有 AI 请求统一出口为 SharedLLMClient"的表述不完整,准确说法是:**实际网络请求统一委托 SharedLLMClient,但旧评估器的对象初始化/选型逻辑仍保留在 LLMEvaluator**。(结论标注:**源码确认**,未经真实 AI 请求运行验证。依据:`utils/llm_evaluator.py::LLMEvaluator._chat_completions_create` 将实际网络请求委托给 `services/llm_client.py::SharedLLMClient`,而 `_init_client` 仍在本模块完成客户端初始化与 api_type 选型;源码核对基线见文首;运行级验证见附录 B「范围澄清」。) ### 4. 能力画像与教师端学情链路 提交评测成功后(异步/同步两通路一致)即触发能力分析刷新:`AbilityTrend.mark_as_outdated` → `trigger_analysis_if_needed()`(防并发 key 去重)→ 后台线程 `tasks/ability_analysis.py::generate_ability_analysis_async` → 拉最近 20 条提交 → `services/ai_evaluator.py::AIEvaluator.analyze_ability_trend_stream` → 前端经 `/api/stream/ability-analysis`(SSE,`routes/api.py::stream_ability_analysis`)流式渲染 Markdown → 结果落回 `AbilityTrend`。教师端 `teacher_analytics` / `teacher_ai_advisor` 再从班级、知识点维度做聚合视图与建议。 -**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。(结论标注:**源码确认**,未做运行验证。依据:`services/demo_database.py::activate_demo_run`/`activate_demo_request_database` 的临时库切换,`tasks/submission_tasks.py::evaluate_submission_async` 的 docstring 注明“demo_run_id 为空时才使用正式数据库”且线程内二次校验会话存活,配套用例为 `tests/test_demo_submission_isolation.py` 等 `tests/test_demo_*`;源码基线本仓库 main HEAD `22f93d4`。附录 B 未复跑 demo 用例,此隔离保证的运行级验证待补。) +**公开体验隔离**:`services/demo_database.py` 为每次体验建临时 SQLite,demo_run_id 沿提交、沙箱、能力分析各后台线程传递;线程执行前二次校验会话存活,退出即清理,绝不写正式库。(结论标注:**源码确认**,未做运行验证。依据:`services/demo_database.py::activate_demo_run`/`activate_demo_request_database` 的临时库切换,`tasks/submission_tasks.py::evaluate_submission_async` 的 docstring 注明“demo_run_id 为空时才使用正式数据库”且线程内二次校验会话存活,配套用例为 `tests/test_demo_submission_isolation.py` 等 `tests/test_demo_*`;源码核对基线见文首。附录 B 未复跑 demo 用例,此隔离保证的运行级验证待补。) **失败可见性**:AI/沙箱失败在体验中一律置 failed,前端显示"失败/重试",不允许用默认分数伪装成功。 @@ -282,7 +282,7 @@ run_test_cases(source, [ 本项目已在本地 Windows 环境完成安装、成功启动;沙箱(演示)登录与安全特性 3 项自动化测试通过;上游 main 新增的沙箱输出限制有界进程测试 5 项通过(mock 编译器);并额外经真实 g++ 16.1.0 编译运行验证了 `utils/sandbox_runner` 的 C++17 编译/运行/输出比对链路可用(合并上游新版沙箱引擎后复测一致)。AI 辅助功能需在 `.env` 配置智谱或 OpenAI 密钥后启用;Web 端完整提交评测链路(含 LLM 叠加评分)与依赖真实 AI 密钥的部分测试不在本次验证范围内,属未验证事项。 -范围澄清(回应复审 P3 意见):附录 B 的**运行验证**仅覆盖上文所列事项——沙箱(演示)特性测试 3 项、沙箱输出限制有界进程测试 5 项、真实 g++ 16.1.0 编译运行 3 例、`python run.py` 启动。正文中“AI 实际网络请求统一委托 SharedLLMClient”“公开体验绝不写正式库”等**源码确认**结论,均仅依据本仓库 main HEAD `22f93d4` 的源码静态核对得出:前者未使用真实 AI 密钥触发过 LLM 调用,后者对应的 `tests/test_demo_*` 隔离用例未在附录 B 复跑。这两类机制结论的运行级验证待后续补充,读到时请勿视为已被实跑确认。 +范围澄清(回应复审 P3 意见):附录 B 的**运行验证**仅覆盖上文所列事项——沙箱(演示)特性测试 3 项、沙箱输出限制有界进程测试 5 项、真实 g++ 16.1.0 编译运行 3 例、`python run.py` 启动。正文中“AI 实际网络请求统一委托 SharedLLMClient”“公开体验绝不写正式库”等**源码确认**结论,均仅依据文首「源码核对基线」提交的源码静态核对得出(基线定义与固定 SHA 见文首结论标注约定,该基线不代表 PR 当前 head):前者未使用真实 AI 密钥触发过 LLM 调用,后者对应的 `tests/test_demo_*` 隔离用例未在附录 B 复跑。这两类机制结论的运行级验证待后续补充,读到时请勿视为已被实跑确认。 ### 个人工具与参考资料