pycamp:零依赖构建 Python 闯关训练营
Python 闯关训练营 是一个在线 Python 学习站点:用户在页面上闯关答题、直接在浏览器里跑代码、遇到问题还能和 AI 陪练对话。整条链路没有引入任何一个第三方运行时依赖,全部基于 Python 标准库 + nginx 原生能力。
💡 一句话定位: 「纯静态前端 + 标准库后端微服务 + nginx 智能网关」,AI 能力全部由网关层代理,密钥不出服务器。
- 访问层 — 纯静态 SPA · 原生 HTML/CSS/JS 单文件交付,无框架、无构建工具,闯关交互全在浏览器端完成
- 网关层 — nginx · TLS 终结、静态缓存、
limit_req按 IP 限流、Origin 白名单防脚本直调、三路 AI 反代(密钥托管 / 密钥透传) - 服务层 — Python 标准库微服务 ×2 · 代码执行沙箱(127.0.0.1:8021,按 IP 限额)+ AI 学习服务(127.0.0.1:8022,RAG 答疑 / 代码批改 / SSE 流式)
- 模型层 — 多通道互备 · 智谱 GLM(免费额度,密钥服务端托管)、DeepSeek(用户自带 Key 透传)、OpenCode Zen(免费模型池透传)
整体架构#
浏览器
│
▼
nginx (80/443, TLS 终结)
├── /pycamp/ → 静态 SPA (/www/wwwroot/pycamp)
├── /pycamp/api/ → 127.0.0.1:8021 代码执行沙箱
├── /pycamp/api/learn/ → 127.0.0.1:8022 AI 学习服务 (RAG)
├── /pycamp/api/ai/zhipu/ → open.bigmodel.cn (密钥托管)
├── /pycamp/api/ai/zen/ → opencode.ai/zen (密钥透传)
└── /pycamp/api/ai/ → api.deepseek.com (密钥透传)技术栈清单#
| 层 | 选型 | 说明 |
|---|---|---|
| 前端 | 纯静态 HTML/CSS/JS 单文件 SPA | 无框架、无构建步骤,index.html 单文件交付 |
| 沙箱后端 | Python 标准库 ThreadingHTTPServer | 端口 8021,仅监听 127.0.0.1,执行用户提交的代码 |
| 学习服务 | 标准库 HTTP 服务 + RAG | 端口 8022,答疑 / 代码批改 / 错误画像,SSE 流式输出 |
| AI 模型 | 智谱 GLM / DeepSeek / OpenCode Zen | 免费额度优先,多通道互为备份 |
| 网关 | nginx 反向代理 + limit_req | TLS、静态缓存、限流、AI 反代 |
几个关键设计#
1. AI 密钥不出前端:nginx 托管注入#
智谱通道的 API Key 只存在于 nginx 配置里,由网关注入 Authorization 头,前端代码不含任何密钥:
location ^~ /pycamp/api/ai/zhipu/ {
if ($pycamp_zhipu_ok = 0) { return 403; } # Origin 白名单
limit_req zone=pycamp_ai_zhipu burst=60 nodelay;
proxy_pass https://open.bigmodel.cn/api/paas/v4/;
proxy_set_header Authorization "Bearer <server-side-key>";
proxy_buffering off; # SSE 必须关缓冲
}DeepSeek / Zen 通道则走透传模式:用户在前端填自己的 Key,服务器不保存、不解析,只负责转发绕过 CORS 限制。
2. SSE 流式输出的两个坑#
proxy_buffering off:不关的话回答会整段卡到最后才一次性出现;- 长超时:
proxy_read_timeout 300s,模型思考久一点不会被网关掐断。
3. 滥用防护:三层闸门#
- Origin 白名单:只放行本站页面发起的请求,空 Origin(curl / 脚本直调)一律 403;
- 按 IP 限流:托管通道每分钟 30 次、burst 60,防脚本刷免费额度;
- 真实 IP 透传:沙箱服务按 IP 计配额,nginx 必须传
X-Real-IP,否则所有人共用 127.0.0.1 的份额。
经验:标准库实现并非炫技——学习类工具站的并发量级很小,零依赖意味着零供应链风险、零版本升级负担,部署就是
python3 server.py 一行命令。踩过的坑#
- nginx 正则 location(静态资源缓存那条)会抢走前缀匹配,沙箱路由必须加
^~; - Zen 官方不开放 CORS(预检 404),所以必须有网关转发这一层,浏览器无法直连;
- 限流要区分「托管密钥」和「用户自带密钥」两种严格程度,前者更严。
延伸阅读#
训练营的 AI 陪练靠一套自研检索(29 关切 239 个知识块)来定位答案。检索准不准直接决定回答质量,所以我们给它补了一套 237 题的评测——并因此发现了两个真 bug、选出了三个优化、同时否决了两个"看起来更高级"的想法:
🏷 Python🏷 nginx🏷 SSE🏷 RAG🏷 代码沙箱