
最近在浏览 B 站 AI 创造公开赛作品时看到一个很有意思的项目一位开发者用大量 token 训练了一个“AI 德国军官”来监督自己学习。把严肃的 AI 能力和略显中二的“军官监督”人设结合既有趣味性又有技术含量尤其是其中对 token 用量控制、长对话记忆、定时提醒、状态判断的处理对做 AI 应用的开发者来说很值得拆解一遍。这篇文章会从项目背景出发讲清“用 AI 做学习监督”的核心思路再给出一套可复现的本地实现方案包含环境准备、工程代码、token 优化策略、常见报错排查和工程建议。无论你是刚接触大模型 API 的新手还是已经做过 AI Agent 的开发者都能从中找到可以落地的内容。1. 背景与核心概念1.1 什么是“AI 监督学习”项目传统背单词、刷题、番茄钟等学习工具核心逻辑是“用户自我驱动 工具计时提醒”。这种模式有一个天然问题提醒是被动的时间一到响铃但用户是否真的在学、是否走神、是否打开手机刷短视频工具并不知道。“AI 监督学习”的思路则是把大模型当作一个具备观察能力的小助理持续收集你的学习状态判断你是在专注还是在摸鱼然后用人设化的语气提醒你。比如标题里的“AI 德国军官”本质上是一个带有严格、精准、威严人设的 Prompt 设定底层仍然是多模态理解 对话生成 定时任务。这种项目在 AI 创造公开赛里比较讨喜因为上手门槛不高不需要训练模型。趣味性强人设容易出效果。技术延伸空间大可以接摄像头、麦克风、浏览器监控、App 使用记录。涉及 token 优化、上下文管理、API 调用等真实工程问题。1.2 Token 在 AI 应用里到底指什么Token 是大模型处理文本的最基本单位。你可以把它粗略理解成“字的碎片”。英文里一个 token 可能是一个单词的一部分中文里一个 token 通常对应一个或半个汉字。当你调用大模型 API 时你的请求内容、历史对话、模型返回的内容都会按 token 数量计费。以标题为例“70 亿 token”这种量级已经属于大规模训练或大规模数据处理的范畴普通个人项目在 API 调用层面很少会用到这个量级。实际开发中我们更多关心的是每次请求消耗多少 token。上下文窗口能装多少 token。如何减少无效 token 消耗。为了更直观地理解可以看下面这个例子。假设你向模型发送这样一段 Prompt请以德国军官的语气检测我当前是否在认真学习。 如果发现我走神请用严厉的语气提醒我。 我的当前状态正在刷手机。这段文本在常见大模型分词器下大致会消耗 30 到 50 个 token。如果每次监督提醒都携带完整历史记录5 分钟一次一天下来 token 消耗量会相当大。1.3 为什么个人 AI 项目也要关注 Token 优化很多初学者做 AI 应用时最容易忽视的就是 token 成本。刚开始测试时感觉不到一旦做成常驻任务或 Agent 循环请求频率上涨token 量会快速膨胀。以“AI 监督学习”为例假设每 5 分钟调用一次大模型。每次请求上下文 2000 token。一天学习 8 小时共 96 次调用。一天的 token 消耗大约是2000 × 96 192000 token如果换成 1 分钟一次一天就是 96 万 token。这还只是单用户单天的量。所以在做这类项目时至少要考虑三件事控制调用频率。压缩上下文内容。把不发散、不判断的内容交给规则代码处理而不是每次都问大模型。2. 项目设计与技术选型2.1 需求分析参考 B 站公开赛作品的设计思路我们可以把“AI 德国军官监督学习”拆成以下核心需求功能模块需求描述技术实现方式人设对话以德国军官语气与用户互动大模型 API 人设 Prompt状态采集判断用户当前是否专注摄像头画面 / 键盘鼠标记录 / 手动输入定时监督每隔一段时间检查一次状态定时任务调度提醒输出发现走神时发出语音或文字提醒TTS 语音合成 / 桌面通知学习报告汇总当天专注情况本地日志 大模型总结其中“状态采集”是项目能否落地成立的关键。如果只靠用户手动输入状态互动感会差很多如果能接入摄像头或系统活动记录项目就会更像一个真正的 AI 监督助手。2.2 技术选型基于易上手、可快速验证原则建议技术栈如下后端语言Python 3.10生态完善适合快速开发。大模型 APIOpenAI 兼容接口或国内大模型平台具体按你手头的 API 来定。定时调度APScheduler支持 cron 表达式适合按分钟或按小时触发。状态采集OpenCV 读取摄像头简单的人脸检测判断是否有人。语音提醒pyttsx3 或 edge-tts把文本转成语音。日志与报告本地 JSON 文件记录事件每天可生成文本总结。项目目录结构可以设计成下面这样ai-study-supervisor/ ├── main.py # 主入口 ├── config.py # 配置项API Key、监督间隔等 ├── supervisor/ │ ├── __init__.py │ ├── character.py # 人设 Prompt 管理 │ ├── detector.py # 状态采集摄像头/手动输入 │ ├── notifier.py # 提醒模块语音/桌面通知 │ └── scheduler.py # 定时任务调度 ├── logs/ │ └── study_log.json # 学习状态日志 └── requirements.txt3. 环境准备与依赖安装3.1 基础环境说明本文示例以常见环境为例Windows 11 / macOS / Ubuntu 均可运行。版本方面没有特殊限制但建议满足Python 3.10 及以上。pip 已更新到最新版本。拥有一个大模型 API 的访问权限接口格式可以是 OpenAI 兼容格式。如果你使用的是国内云厂商的大模型服务接口通常也兼容 Chat Completions 格式核心代码只需修改 base_url 和 api_key。3.2 安装依赖在项目根目录下创建虚拟环境然后安装依赖。python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate创建 requirements.txtopenai1.30.0 opencv-python4.9.0 apscheduler3.10.4 edge-tts6.1.10 playsound1.3.0安装pip install -r requirements.txt这里需要说明的是openai库不仅是官方 API 的 SDK很多第三方兼容服务也支持用它进行调用只需要修改 base_url。edge-tts是微软 Edge 的免费文本转语音方案网络状况正常时可用如果环境受限可以改为pyttsx3这种本地离线方案。4. 核心代码实现4.1 配置文件先编写 config.py统一管理所有可调参数。# 文件路径config.py import os # 大模型 API 配置 LLM_API_KEY os.getenv(LLM_API_KEY, 你的 API Key) LLM_BASE_URL os.getenv(LLM_BASE_URL, https://api.openai.com/v1) LLM_MODEL os.getenv(LLM_MODEL, gpt-4o-mini) # 监督人设可自由替换 SUPERVISOR_NAME 德国军官 SUPERVISOR_PROMPT 你是威廉·冯·施特赖希曼少校一位严肃、精准、讲究效率的德国军官。 你的任务是监督用户学习发现用户走神或偷懒时用简短、严厉又不失幽默的语气提醒。 每次提醒控制在50字以内。称呼用户为士兵。 # 监督间隔单位秒 CHECK_INTERVAL 30 # 摄像头检测参数 CAMERA_INDEX 0 FACE_CHECK_INTERVAL 10 # 日志路径 LOG_FILE logs/study_log.json配置项集中管理的好处是后期调整人设、模型、频率时不需要改动业务代码。4.2 人设 Prompt 管理在大模型应用中人设就是产品的灵魂。设计时需要注意角色身份要明确。语气风格要具体。响应长度要限制避免生成冗长内容。要规定触发场景和回复方式。在 character.py 中封装# 文件路径supervisor/character.py from config import SUPERVISOR_PROMPT, SUPERVISOR_NAME class Character: 负责拼接人设 Prompt 和用户状态内容 def __init__(self): self.name SUPERVISOR_NAME self.system_prompt SUPERVISOR_PROMPT def build_user_message(self, status: str, recent_log: str ) - str: 根据当前状态构建用户消息 message f当前用户状态{status}。 if recent_log: message f\n近期的监督记录{recent_log} message \n请根据状态决定是否需要提醒如果不需要提醒回答无需提醒。 return message这里的关键设计是给模型一个“无需提醒”的出口否则模型会为了保持人设每次都强行输出一段话token 浪费严重。4.3 状态采集模块状态采集是整个监督系统的前端感知层。最简单可验证的方式是手动输入状态进阶方案是摄像头人脸检测。先实现一个人脸检测模块作用是判断摄像头前是否有人。如果检测不到人脸大概率说明用户离开了书桌。# 文件路径supervisor/detector.py import cv2 import time class FaceDetector: 使用 OpenCV 自带的人脸检测器判断摄像头前是否有人 def __init__(self, camera_index: int 0): self.cap cv2.VideoCapture(camera_index) # 使用 OpenCV 自带的 Haar 级联分类器 self.face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) def is_face_present(self) - bool: 返回 True 表示检测到人脸False 表示未检测到 ret, frame self.cap.read() if not ret: return False gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces self.face_cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(100, 100) ) return len(faces) 0 def release(self): self.cap.release()为了降低摄像头调用频率可以在外层加一个缓存每 10 秒检测一次不阻塞主流程。手动输入状态可以作为备选方案方便在没有摄像头的环境里验证项目# 文件路径supervisor/manual_status.py def get_manual_status() - str: print(请选择当前状态) print(1. 我正在专心学习) print(2. 我在走神/刷手机) print(3. 我不在书桌前) choice input(输入数字) mapping { 1: 用户正在专心学习, 2: 用户可能在走神, 3: 用户不在书桌前, } return mapping.get(choice, 未知状态)4.4 大模型判断模块大模型在这里的角色是“决策者”。每次监督触发时我们把当前状态发送给模型模型判断是否需要提醒。这里有几个优化点历史记录只保留最近几条避免上下文无限膨胀。给模型明确的输出约束减少无效输出。使用低温度参数保证判断稳定。实现代码如下# 文件路径supervisor/llm_client.py from openai import OpenAI from config import LLM_API_KEY, LLM_BASE_URL, LLM_MODEL class LLMClient: def __init__(self): self.client OpenAI(api_keyLLM_API_KEY, base_urlLLM_BASE_URL) self.model LLM_MODEL def chat(self, system_prompt: str, user_message: str) - str: response self.client.chat.completions.create( modelself.model, temperature0.3, messages[ {role: system, content: system_prompt}, {role: user, content: user_message}, ], ) return response.choices[0].message.content.strip()注意如果使用的模型或服务不支持 temperature 参数需要把这个参数删掉或改成对应参数名。4.5 提醒模块当模型返回需要提醒时系统需要把文本变成可感知的提醒。这里支持两种方式桌面通知和语音。# 文件路径supervisor/notifier.py import subprocess import sys def desktop_notify(title: str, message: str): 跨平台桌面通知 if sys.platform win32: # Windows 下使用 powershell 弹窗 subprocess.run([ powershell, -Command, fNew-BurntToastNotification -Text {title}, {message} ]) elif sys.platform darwin: subprocess.run([ osascript, -e, fdisplay notification {message} with title {title} ]) else: subprocess.run([ notify-send, title, message ]) async def voice_notify(text: str): 使用 edge-tts 生成语音提醒 import edge_tts communicate edge_tts.Communicate(text, voicede-DE-ConradNeural) await communicate.save(logs/remind.mp3) # 播放音频 from playsound import playsound playsound(logs/remind.mp3)语音提醒选择德语男声是为了配合“德国军官”人设增加沉浸感。de-DE-ConradNeural是 edge-tts 支持的一种德语男声如果该语音名称在你使用的 edge-tts 版本中不存在可以通过edge-tts --list-voices查询可用语音。4.6 定时调度模块使用 APScheduler 实现定时监督逻辑。因为语音提醒涉及异步操作调度器使用异步版本。# 文件路径supervisor/scheduler.py from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.interval import IntervalTrigger class StudyScheduler: def __init__(self, check_interval: int, job_func): self.scheduler AsyncIOScheduler() self.check_interval check_interval self.job_func job_func def start(self): self.scheduler.add_job( self.job_func, triggerIntervalTrigger(secondsself.check_interval), idstudy_check, replace_existingTrue, max_instances1, # 避免上一轮任务还没结束下一轮就启动 coalesceTrue, # 如果触发多次只执行一次 ) self.scheduler.start() def shutdown(self): self.scheduler.shutdown(waitFalse)max_instances1和coalesceTrue这两个参数非常关键。当检查逻辑因为网络请求耗时过长或者摄像头调用卡住时调度器不会堆积大量重复任务。4.7 主程序整合主程序把所有模块串联起来。# 文件路径main.py import asyncio import json import logging from datetime import datetime from config import CHECK_INTERVAL, LOG_FILE, SUPERVISOR_PROMPT from supervisor.character import Character from supervisor.detector import FaceDetector from supervisor.llm_client import LLMClient from supervisor.scheduler import StudyScheduler logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) character Character() llm_client LLMClient() face_detector FaceDetector() # 记录最近几轮监督状态用于上下文参考 recent_log [] async def check_study_status(): 定时执行的学习状态检查 # 1. 采集状态 if face_detector.is_face_present(): status 用户正在书桌前脸部可见 else: status 摄像头前未检测到人脸用户可能离开了书桌 # 2. 拼接消息 context if recent_log: context | .join(recent_log[-3:]) user_message character.build_user_message(status, context) # 3. 请求大模型判断 try: reply llm_client.chat(SUPERVISOR_PROMPT, user_message) except Exception as e: logger.error(f大模型调用失败{e}) return logger.info(f状态{status}模型回复{reply}) # 4. 记录日志 timestamp datetime.now().isoformat() log_entry {time: timestamp, status: status, reply: reply} recent_log.append(log_entry) save_log(log_entry) # 5. 需要提醒时打印并提示 if 无需提醒 not in reply: print(f[{timestamp}] {reply}) # 这里可以接入语音提醒或桌面通知 # await notifier.voice_notify(reply) def save_log(entry: dict): 把日志追加写入 JSON 文件 try: with open(LOG_FILE, r, encodingutf-8) as f: logs json.load(f) except FileNotFoundError: logs [] logs.append(entry) with open(LOG_FILE, w, encodingutf-8) as f: json.dump(logs, f, ensure_asciiFalse, indent2) async def main(): scheduler StudyScheduler(CHECK_INTERVAL, check_study_status) scheduler.start() print(fAI 学习监督系统已启动每 {CHECK_INTERVAL} 秒检查一次。按 CtrlC 结束。) try: while True: await asyncio.sleep(1) except KeyboardInterrupt: scheduler.shutdown() face_detector.release() print(已退出 AI 学习监督系统) if __name__ __main__: asyncio.run(main())5. 运行与验证5.1 启动项目在项目根目录执行python main.py预期输出AI 学习监督系统已启动每 30 秒检查一次。按 CtrlC 结束。然后你可以通过离开摄像头、遮挡摄像头、或修改 detector 模块观察模型回复的变化。5.2 查看学习日志运行一段时间后打开 logs/study_log.json可以看到类似下面的内容[ { time: 2024-12-01T10:00:01, status: 用户正在书桌前脸部可见, reply: 士兵保持专注很好。 }, { time: 2024-12-01T10:00:31, status: 摄像头前未检测到人脸用户可能离开了书桌, reply: 士兵你不是应该在桌边学习吗马上回来 } ]5.3 如何验证 token 消耗是否合理如果你使用的是 OpenAI 兼容接口响应对象中通常包含usage字段response self.client.chat.completions.create(...) print(response.usage)输出示例CompletionUsage(completion_tokens18, prompt_tokens145, total_tokens163)你可以在每次请求时把这三个数值累计到日志中用于统计一天的 token 总消耗。这部分数据对后续做成本优化非常重要。6. 常见问题与排查思路6.1 API 调用报错 401 Unauthorized问题现象常见原因解决思路401 UnauthorizedAPI Key 错误或已失效检查 config.py 中 key 是否填对403 Forbidden当前网络或地区不支持该服务更换为合规的 API 服务商或检查账户权限404 Model Not Found模型名不被当前服务支持到平台官网确认正确模型名需要特别提醒的是不同大模型服务的接口规范可能存在差异。如果接口返回 403通常不是代码问题而是账号权限、网络环境或服务区域限制导致。建议优先检查服务商的官方文档和账号状态。6.2 摄像头无法打开问题现象常见原因解决思路cap.read() 一直返回 False摄像头被其他程序占用关闭所有使用摄像头的应用启动报错找不到摄像头设备索引不对尝试 CAMERA_INDEX 改为 1 或 -1虚拟机里无画面虚拟机未挂载摄像头在虚拟机设置中连接物理摄像头6.3 定时任务不执行检查是否把 scheduler 放在 async 事件循环里。检查max_instances是否设置过小导致任务被跳过。检查主线程是否被阻塞比如在 while 循环中使用了同步的 input()。6.4 edge-tts 生成语音失败确认网络可以正常访问微软服务。确认语音名称正确使用edge-tts --list-voices查看可用列表。如果想离线使用把voice_notify改成pyttsx3本地合成。7. Token 优化与工程实践7.1 控制上下文长度在“AI 德国军官监督学习”这个场景里上下文策略可以分成三层第一层系统人设固定不变每次请求都携带。第二层最近 3 到 5 条监督记录作为短时记忆帮助模型理解“上一轮我在干嘛”。第三层历史长周期数据不直接发给模型而是通过汇总统计后在每日报告阶段共享。示例def build_daily_summary(logs) - str: total_checks len(logs) focus_count sum(1 for log in logs if 专心 in log[status]) focus_rate focus_count / total_checks * 100 if total_checks else 0 return f今日共监督 {total_checks} 次专注率 {focus_rate:.1f}%7.2 减少模型请求次数不是每一次状态变化都需要大模型介入。可以设计简单规则做前置过滤如果当前状态与上一次相同并且上一次模型判定为“无需提醒”则跳过本轮请求。如果当前状态是“用户正在专心学习”可以直接默认不提醒不调用模型。只有状态从专注切换为走神、或持续走神超过两次时才调用模型生成个性化提醒。这个优化可以把 token 消耗降低 70% 以上。7.3 日志与可观测性生产级 AI 应用必须记录以下信息每次调用的 prompt_tokens / completion_tokens / total_tokens。API 响应延迟。每次状态判断的原始输入和输出。异常调用栈。记录这些数据既能排查线上问题也能为后续优化提供依据。7.4 安全和隐私边界使用摄像头采集人脸信息属于敏感数据。项目在本地运行时要明确两点所有图像数据只在本地内存中处理不发送到云端。调用大模型时只发送文本状态描述不发送原始图片。如果在公开项目或比赛中发布代码应当在 README 中注明隐私策略并默认关闭摄像头自动上传功能。7.5 从比赛作品到可落地产品B 站 AI 创造公开赛里的很多作品创意很好但离产品化还有距离。如果要把“AI 监督学习”做成可长期使用的工具还需要补充用户身份系统与鉴权。多端数据同步。日历与学习计划对接。可视化学习报告。模型调用成本限额与告警。这些内容对新手来说可能有点远但作为方向性规划可以先了解。实际开发时优先把核心闭环跑通再逐步扩展。8. 延伸思考从“AI 监督”到“AI 陪伴”“AI 德国军官监督我学习”这个创意之所以能引起关注是因为它戳中了很多人的痛点自控力不足需要外部监督。传统方法靠闹钟、靠朋友互相监督现在多了一个选择——让 AI 扮演一个“虚拟监督者”。这个方向可以延伸出很多变体AI 健身教练监督你每天运动没完成目标就发语音吐槽。AI 早睡助手到点检测屏幕使用时间催促睡觉。AI 项目管理助手定时检查开发进度并在团队群里播报。这些应用的核心技术链路完全相同状态采集 人设 Prompt 大模型判断 提醒输出 日志沉淀。对开发者来说掌握这条链路之后可以快速复制到不同场景中属于性价比很高的学习路径。9. 总结与下一步建议这篇文章围绕“AI 德国军官监督学习”项目拆解了两个层面一是项目创意层面的设计思路二是工程实现层面的技术细节。在工程上你学会了如何通过配置文件统一管理模型参数、人设和调度频率。如何使用 OpenCV 做基础的状态采集。如何设计大模型 Prompt让模型在“提醒”和“无需提醒”之间稳定切换。如何用 APScheduler 实现可靠的定时任务。如何通过上下文截断和规则过滤来控制 token 消耗。如何记录日志为后续分析和优化提供数据支撑。下一步建议你按下面的顺序继续动手先把最小闭环跑通手动状态 大模型判断 打印提醒。再接入摄像头或系统活动记录增强真实感。加入 token 用量统计分析一天的消耗。根据统计数据优化调用频率和上下文策略。最后加上语音提醒完善人设体验。如果你也正在准备 AI 相关的比赛或作品可以参考这个项目的方式先用一个有趣的人设抓住观众注意力再用扎实的工程实现保证项目能稳定运行。创意和技术缺一不可。写代码去吧士兵。你的 AI 监督官正在盯着你看。