打造个人英语教练skill:飞书 + MiniMax + 本地模型
打造个人英语教练skill:飞书 + MiniMax + 本地模型
为什么是飞书语音
做英语学习产品,最大的敌人不是内容,是坚持。
传统的英语学习方式——背单词 App、看视频课程——都需要你主动空出一部分时间来专门练习,光是坐下来的心里预设便是一种负担。
与此同时语音消息是一个很自然的载体:
- 你每天都在用即时通讯工具,收到语音消息→点击播放→回复语音,这是你已经习惯的交互
- 相比发一个 mp3 附件或者一段文字,语音消息更贴近真实的语言交流
- AI 主动向你发送一段聊天,回复后,ai再根据你回复的内容完成对话,一切犹如自然呼吸一般,简单到不会成为负担
本文介绍 The English Tutor Skill 的设计思路:一个基于飞书的 AI 英语陪练助手,核心模块全部可替换,方便你按需修改。
整体架构

设计原则:
- 所有凭据选填:填了环境变量 → 启用对应模块;不填 → 静默跳过
- 云端优先,本地兜底:有 API Key 用云端服务,没有自动切换本地
- 单模块失败不影响全流程:TTS 挂了照样继续文字对话,ASR 挂了也能切文字输入
TTS 模块:多层降级
TTS 是最直接影响体验的模块——语音好听、语速自然,学习者才愿意跟读。
MiniMax 云端(推荐方案)
由于本人开了minimax 会员,直接使用其 speech-2.8-hd模型,比起本地TTS模型音质更自然:
// agent/config.js
MINIMAX_API_KEY: process.env.MINIMAX_API_KEY || null,
TTS_MODEL: process.env.MINIMAX_TTS_MODEL || null,
TTS_VOICE_ID: process.env.MINIMAX_TTS_VOICE_ID || null,
// agent/minimax.js — 有 Key 时才应用推荐默认值
this.model = model || (apiKey ? 'speech-2.8-hd' : null);
this.voiceId = voiceId || (apiKey ? 'male-qn-qingse' : null);MiniMax TTS 额度用完后会自动降级,使用本地的模型:
// agent/minimax.js
async _checkQuota() {
const { remain } = await checkTokenPlanRemain(this.apiKey);
if (remain <= 0) {
throw new Error('TOKEN_EXHAUSTED'); // 让调用方知道该切换了
}
}
Piper 本地兜底
没有 API Key,或者额度耗尽时,自动切换 Piper:
# scripts/feishu_voice.py
def send_voice(text, user_open_id=None, provider="minimax", **kwargs):
try:
if provider == "piper":
wav = piper_tts(text, kwargs["piper_bin"], kwargs["piper_model"])
audio_path = convert_to_opus(wav)
else:
mp3 = minimax_tts(kwargs["minimax_api_key"], text, ...)
audio_path = convert_to_opus(mp3)
except RuntimeError as e:
if "TOKEN_EXHAUSTED" in str(e) or "TTS error" in str(e):
# 配额耗尽,尝试 Piper 兜底
if kwargs.get("piper_bin") and kwargs.get("piper_model"):
wav = piper_tts(text, kwargs["piper_bin"], kwargs["piper_model"])
audio_path = convert_to_opus(wav)
else:
raise
Piper 是完全离线的 ONNX TTS,音质不如云端,但胜在隐私保护和零成本。支持自由更换其他TTS模型。
ASR 模块:本地优先
语音识别用 SenseVoice,一个完全本地运行的 ASR 模型:
// agent/config.js
SENSE_VOICE_MODEL_DIR: process.env.SENSE_VOICE_MODEL_DIR || null,
// 无配置时静默跳过,agent.js 收到的是转写后的文字
// agent/agent.js
async function asrVoice(voice_url) {
if (!voice_url) return '';
// ASR 由调用方处理,本文件只接收文字
console.warn('[ASR] 请先通过 scripts/transcribe.py 转写语音');
return '';
}
目前各大厂套餐包含ASR语音识别模型比较少,因此选用本地ASR模型。代价是模型下载(约 150MB)首次需要手动处理。
记忆模块:艾宾浩斯 + 多维表格
学习数据存在飞书多维表格,比起数据库更容易监控每日学习进度:
表 1: words(单词表)
| 字段 | 类型 | 说明 |
|---|---|---|
| word | 文本 | 英文单词 |
| user_id | 文本 | 用户标识 |
| first_seen | 时间 | 首次学习 |
| last_review | 时间 | 最近复习 |
| next_review | 时间 | 下次复习 |
| review_count | 数字 | 复习轮次 |
| mastery | 数字 | 掌握程度 0-5 |
表 2: chat_log(对话记录)
| 字段 | 类型 | 说明 |
|---|---|---|
| user_id | 文本 | 用户标识 |
| role | 单选 | ai / user |
| text | 文本 | 对话内容 |
| voice_url | 文本 | 语音 URL |
| created_at | 时间 | 创建时间 |
艾宾浩斯复习间隔硬编码在这里,方便修改:
// agent/memory.js
const ebIntervals = [1, 3, 7, 15]; // 第1次次日、第2次3天后、第3次7天后、第4次15天后
function calcNextReview(reviewCount) {
const interval = ebIntervals[Math.min(reviewCount - 1, ebIntervals.length - 1)];
const next = new Date();
next.setDate(next.getDate() + interval);
return next.toISOString().split('T')[0];
}
替换为 Anki 的间隔算法或添加间隔重复变体,改这个数组即可。
–
如何按需修改
这个 Skill 的设计目标之一是方便二次开发。几个常见的修改方向:
换通信渠道:飞书不是唯一的选择。可以自由配置微信、qq等渠道,但要注意让ai发送语音,而不是文件。
换 TTS 方案:想用其他TTS文件,只需要在 config.js 里改 provider 名字就行。
换记忆存储:不想用飞书多维表格,想接入 Notion、Airtable 或本地 SQLite 时,agent/memory.js 的接口很清晰:
class BitableMemory {
async getReviewRecords(userId) { }
async getTodayNewWords(userId, limit) { }
async upsertWordRecord(userId, word, record) { }
async appendChatLog(userId, aiMsg, userMsg) { }
async getChatHistory(userId, limit) { }
}
实现同样接口,换一个存储后端,全流程照样跑。
配置灵活性
这个 Skill 所有的"功能开关"都是凭据驱动的:
# 最小配置:只有 LLM
MINIMAX_API_KEY=sk-xxx
# 基础语音:LLM + TTS
MINIMAX_API_KEY=sk-xxx
TTS_PROVIDER=minimax
# 完整功能:云端 TTS + 飞书推送 + 多维表格
MINIMAX_API_KEY=sk-xxx
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=xxx
FEISHU_USER_OPEN_ID=ou_xxx
BITABLE_APP_TOKEN=xxx
BITABLE_WORDS_TABLE_ID=xxx
BITABLE_CHAT_TABLE_ID=xxx
# 本地兜底:离线可用
PIPER_BIN=/path/to/piper
PIPER_MODEL=/path/to/model.onnx
SENSE_VOICE_MODEL_DIR=/path/to/sensevoice
定时任务
三个时间段的练习内容有差异:
- 08:00 晨间:通勤场景,生成跟读材料,AI 朗读示范,用户跟读
- 12:00 午间:午休场景,口语问答,自由对话
- 20:00 晚间:复盘 + 旧词复习,强化记忆
// agent/agent.js
function buildSystemPrompt(wordPool, timePeriod) {
const scenes = {
'morning': '通勤场景(早晨出门、上班路上)',
'noon': '午休场景(餐厅、咖啡厅)',
'evening': '居家/购物场景(下班后)',
};
// ...
}
定时任务默认关闭,用户在引导设置里自己选择开启哪些时间段。
项目地址
The-English-Tutor-skill:https://github.com/PandaltsGo/The-English-Tutor-skill
也可直接在clawhub搜到。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)