1. 从一次误报说起为什么要在 Codex 里做陌生人闯入监控我住的小区快递柜旁边经常有人晃悠之前用普通摄像头只能事后翻录像等发现丢件已经过去两天。后来我把树莓派上的 OpenCV 检测逻辑接进了 Codex Skills让 Agent 在检测到陌生人脸时自动截屏、上传云端、推送通知整个过程不需要我盯着屏幕。这套方案的核心不是监控本身而是把视觉检测封装成一个可被 Codex 调用的 Skill——你写一次配置之后所有触发、截屏、上传动作都由 Skill 骨架自动串起来。Codex Skills 是 Codex 里用来扩展 Agent 能力的模块化配置你可以把它理解成给 Agent 装一个插件插件里定义触发条件、执行动作、参数。OpenCV 负责图像层面的运动检测和人脸定位Skill 负责把检测结果转成截屏→上传→通知的动作链。适合谁适合手上有树莓派或旧笔记本、想低成本搭一套能自动报警的安防原型、又不想从零写调度框架的开发者。本文交付的是 config.toml 和 settings.json 级别的配置片段以及逐条验证动作你照着改参数就能在本地跑通。2. TaoToken 前置Skill 里调用模型做二次判定的接入准备Skill 骨架本身不依赖大模型也能跑纯 OpenCV 逻辑但如果你想让 Agent 在截屏后做一次这张图里是不是真的有人的二次判定或者让 Agent 生成报警文案就需要一个模型调用入口。我用 TaoToken 来做这一层原因是它的接口格式和主流 SDK 兼容改 base_url 就能接进现有代码不用重写请求层。你需要先拿到 API Key。打开 https://taotoken.net/api-keys 创建密钥注意这个页面是控制台里的密钥管理入口创建后复制保存后面配置里要用。如果你还没注册从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进官网走一遍流程即可。接入文档在 https://taotoken.net/doc 里面写了 base_url 和请求格式。base_url 统一用 https://taotoken.net/api 不要加 UTM 参数否则部分 SDK 会把 query string 带进签名导致 401。模型对话的调试入口在 https://taotoken.net/models 你可以先在网页上试一次请求确认 Key 有效再写进 Skill 配置。注意Skill 里存 Key 不要硬编码在 Python 文件里用环境变量或单独的 settings.json后面配置章节会给具体写法。3. 可复制配置config.toml 与 settings.json 骨架Skill 的配置分两层config.toml 定义 Skill 的元信息和触发参数settings.json 存运行时密钥和上传地址。先建目录结构mkdir -p ~/codex_skills/stranger_guard/{config,screenshots} cd ~/codex_skills/stranger_guard3.1 config.toml定义触发阈值与动作链[skill] name stranger_guard version 1.0.0 description 检测陌生人脸并自动截屏上传 entry guard.py [trigger] # 帧间差异像素阈值低于此值视为静态背景 diff_area_threshold 1000 # 连续多少帧检测到陌生人脸才触发防抖 consecutive_frames 8 # 人脸检测最小窗口太小会误报 face_min_size [30, 30] # Haar 级联分类器路径 cascade_path config/haarcascade_frontalface_default.xml [camera] width 640 height 480 fps 15 device_index 0 [action] # 截屏保存目录 screenshot_dir screenshots # 上传接口地址替换成你自己的对象存储或 HTTP 服务 upload_url https://your-cloud.example.com/api/upload # 是否启用模型二次判定 enable_model_check true # 模型调用配置 model_base_url https://taotoken.net/api model_name gpt-4o-mini3.2 settings.json存密钥与运行时开关{ upload_api_key: your_upload_secret, taotoken_api_key: sk-你的TaoToken密钥, feishu_webhook: https://open.feishu.cn/open-apis/bot/v2/hook/你的webhook, enable_upload: true, enable_notify: true, log_level: INFO }把 settings.json 权限收紧chmod 600 settings.json3.3 读取配置的 Python 片段import tomllib import json import os def load_config(base_dir): with open(os.path.join(base_dir, config.toml), rb) as f: cfg tomllib.load(f) with open(os.path.join(base_dir, settings.json), r) as f: secrets json.load(f) # 环境变量优先方便容器部署 secrets[taotoken_api_key] os.environ.get( TAOTOKEN_API_KEY, secrets.get(taotoken_api_key, ) ) return cfg, secrets这段代码用 tomllibPython 3.11 内置读 TOML用 json 读密钥文件环境变量覆盖文件值这样你在本地调试和服务器部署可以用同一份 config.toml。4. 验证请求跑通截屏与上传链路配置写完后不要急着接摄像头先用一张静态图验证检测→截屏→上传三段链路是否通。4.1 用静态图验证检测逻辑import cv2 import numpy as np def detect_faces(image_path, cascade_path): img cv2.imread(image_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cascade cv2.CascadeClassifier(cascade_path) faces cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(30, 30) ) return img, faces img, faces detect_faces(test.jpg, config/haarcascade_frontalface_default.xml) print(f检测到 {len(faces)} 张人脸) for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) cv2.imwrite(screenshots/verify_detect.jpg, img)跑完后打开 screenshots/verify_detect.jpg如果人脸被绿框标出说明 Haar 模型加载和检测参数没问题。如果一张都没检测到先检查图片是不是正脸、光线是否充足再调 minNeighbors 从 5 降到 3。4.2 验证上传接口import requests def verify_upload(file_path, upload_url, api_key): with open(file_path, rb) as f: files {file: f} headers {Authorization: fBearer {api_key}} resp requests.post(upload_url, filesfiles, headersheaders, timeout10) print(f状态码: {resp.status_code}) print(f响应: {resp.text[:200]}) return resp.status_code 200 verify_upload(screenshots/verify_detect.jpg, https://your-cloud.example.com/api/upload, your_upload_secret)状态码 200 且响应里带图片 URL 就说明上传链路通了。如果返回 401检查 Authorization 头格式返回 413 说明图片太大需要在截屏时压缩。4.3 验证模型二次判定import base64 import requests def model_check(image_path, api_key, base_url, model_name): with open(image_path, rb) as f: b64 base64.b64encode(f.read()).decode() payload { model: model_name, messages: [{ role: user, content: [ {type: text, text: 这张图里是否有人只回答有或没有。}, {type: image_url, image_url: {url: fdata:image/jpeg;base64,{b64}}} ] }] } headers {Authorization: fBearer {api_key}} resp requests.post(f{base_url}/v1/chat/completions, jsonpayload, headersheaders, timeout30) return resp.json() result model_check(screenshots/verify_detect.jpg, sk-你的TaoToken密钥, https://taotoken.net/api, gpt-4o-mini) print(result[choices][0][message][content])如果返回有说明模型调用链路通了。这一步的作用是过滤掉 Haar 的误报——比如海报上的人脸、电视画面里的人脸模型二次判定能显著降低假报警。5. 本篇常见错排查报错一cv2.error: (-215:Assertion failed) !empty() in function detectMultiScale这是 Haar 模型路径不对或文件损坏。检查 config.toml 里的 cascade_path 是否指向实际存在的 xml 文件用ls -la config/确认文件大小在 900KB 左右。如果是从网上下载的重新下载一次。报错二401 Unauthorized调用 TaoToken 接口先确认 base_url 是https://taotoken.net/api不要带任何 query 参数。然后检查 Key 是否从 https://taotoken.net/api-keys 正确复制有没有多余空格。如果用的是 OpenAI SDK确认api_key参数传的是 TaoToken 的 Key 而不是其他平台的。报错三上传成功但飞书没收到通知飞书 Webhook 的 payload 格式对版本敏感。先单独用 curl 测一次curl -X POST https://open.feishu.cn/open-apis/bot/v2/hook/你的webhook \ -H Content-Type: application/json \ -d {msg_type:text,content:{text:测试消息}}如果 curl 能收到说明 webhook 没问题是 Python 里的 payload 结构不对。注意 interactive 卡片里的 img_key 需要先调飞书上传图片接口获取不能直接用外链 URL。报错四树莓派上帧率只有 2-3 FPS先注释掉cv2.imshowGUI 渲染在树莓派上非常耗资源。然后把分辨率从 640x480 降到 320x240帧率能翻倍。如果还不行检查是不是用了opencv-python而不是opencv-python-headless后者省掉了 GUI 依赖内存占用低很多。报错五连续触发报警刷屏config.toml 里的 consecutive_frames 调大从 8 调到 15。同时在触发后加一个冷却时间比如 60 秒内不重复触发import time last_alert_time 0 cooldown 60 def should_alert(): global last_alert_time now time.time() if now - last_alert_time cooldown: return False last_alert_time now return True6. 把 Skill 接进 Codex 工作流配置和验证都跑通后最后一步是让 Codex 能调用这个 Skill。在 Codex 的 Skill 注册文件里加一条指向 config.toml 的路径Agent 就能在对话里触发启动陌生人监控这个动作。如果你想让 Agent 长期跑编码任务的同时兼顾监控可以了解一下 Coding Plan 的并发额度地址是 https://taotoken.net/coding-plan 它适合需要持续调用模型的场景。实际部署时我建议把截屏目录挂到外部存储树莓派的 SD 卡写入寿命有限频繁写截图容易坏卡。上传成功后本地截图可以保留 7 天再自动清理用 cron 加一条 find 命令就行find ~/codex_skills/stranger_guard/screenshots -name *.jpg -mtime 7 -delete整套流程跑下来从摄像头读到帧、检测到陌生人脸、截屏、上传、推送通知在树莓派 4B 上大约 1.5 秒完成。如果你用的是 USB 摄像头注意选支持 UVC 免驱的型号不然 V4L2 可能识别不到。
