打造个人英语教练skill:飞书 + MiniMax + 本地模型

为什么是飞书语音

做英语学习产品,最大的敌人不是内容,是坚持

传统的英语学习方式——背单词 App、看视频课程——都需要你主动空出一部分时间来专门练习,光是坐下来的心里预设便是一种负担。

与此同时语音消息是一个很自然的载体:

  • 你每天都在用即时通讯工具,收到语音消息→点击播放→回复语音,这是你已经习惯的交互
  • 相比发一个 mp3 附件或者一段文字,语音消息更贴近真实的语言交流
  • AI 主动向你发送一段聊天,回复后,ai再根据你回复的内容完成对话,一切犹如自然呼吸一般,简单到不会成为负担

本文介绍 The English Tutor Skill 的设计思路:一个基于飞书的 AI 英语陪练助手,核心模块全部可替换,方便你按需修改。


整体架构

在这里插入图片描述

设计原则:

  1. 所有凭据选填:填了环境变量 → 启用对应模块;不填 → 静默跳过
  2. 云端优先,本地兜底:有 API Key 用云端服务,没有自动切换本地
  3. 单模块失败不影响全流程: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搜到。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐