Skip to content

Commit cc41b6f

Browse files
committed
feat(ai-gateway): DeepSeek v4 Flash 统一接入与多 Key 轮询 + sync 幂等写入
- 纯文字 AI 功能统一路由至 DeepSeek v4 Flash 0731,支持 DEEPSEEK_API_KEYS 逗号分隔多 Key 轮询(回退兼容 DEEPSEEK_API_KEY) - providers.py 重构:GLM/Qwen/DeepSeek provider 对齐新模型路由;超时预算与流式降级测试同步更新 - 提示词模板统一升级(卡片生成/概念预检/冲突检测/内容分级/错误模式/评估/测验/推荐/摘要) - sync-service 新增 isUniqueViolation(pg 23505)幂等写入错误分类(M6/M7) - 收入模型调整:免费层以本地推理为主 + 低价档付费模型兜底(不依赖供应商免费额度);.env.example 补 DEEPSEEK_API_KEYS 说明
1 parent 38d0427 commit cc41b6f

24 files changed

Lines changed: 279 additions & 283 deletions

‎docs/product/revenue-plan-no-license.md‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
│ 高级模型 / 更高配额 / 多模态课堂助手 │
4646
├─────────────────────────────────────────────────┤
4747
│ 第一层:免费层(永久免费) │
48-
│ 全部核心学习功能 + 基础 AI(GLM 模型/低配额) │
48+
│ 全部核心学习功能 + 基础 AI(本地推理/低配额) │
4949
└─────────────────────────────────────────────────┘
5050
```
5151

@@ -58,7 +58,7 @@
5858
| 闪卡 + 间隔重复(反衰减呼吸) | 核心学习工具 |
5959
| 费曼输出(浮出水面) | 核心学习工具 |
6060
| 学习启动仪式 / 成就系统 | 体验层 |
61-
| 基础 AI 功能(GLM-4-Flash) | 每日 15 次 AI 调用,覆盖摘要/闪卡生成/基础提问 |
61+
| 基础 AI 功能(本地推理为主 + 低价档付费模型兜底) | 每日 15 次 AI 调用,覆盖摘要/闪卡生成/基础提问;**不依赖供应商免费额度**(智谱《服务协议》3.4 条禁止转供他人使用) |
6262
| BYOK(自带 API Key) | 用户自行接入任意模型,不受平台配额限制 |
6363

6464
**设计意图**:免费层已构成完整学习闭环,付费不是"解锁功能"而是"提升 AI 体验上限"。
@@ -67,7 +67,7 @@
6767

6868
| 维度 | Free | Pro(¥12/月 或 ¥99/年) |
6969
|------|------|--------------------------|
70-
| AI 模型 | GLM-4-Flash(轻量) | Qwen-Plus / DeepSeek-Chat / GLM-4(高级) |
70+
| AI 模型 | 本地模型(Ollama)/ 低价档付费模型(轻量) | Qwen-Plus / DeepSeek-Chat / GLM-4(高级,付费档) |
7171
| 每日 AI 调用次数 | 15 次 | 80 次 |
7272
| 每日费用上限 | ¥0.5(平台承担) | ¥2.0(平台承担) |
7373
| 多模态课堂助手 | ❌ | ✅(Qwen-VL 视觉提取) |
@@ -165,15 +165,15 @@
165165

166166
| 用户类型 | 月均 AI 成本 | 说明 |
167167
|----------|:---:|------|
168-
| Free 用户 | ¥0(GLM-4-Flash 免费额度) | 智谱免费层覆盖 |
168+
| Free 用户 | ¥0.5~1.5 | 本地推理为主 + 低价档付费模型兜底(约 300 次/月 × ¥0.003);免费额度仅限开发/内测,不可服务公众用户 |
169169
| Pro 轻度(日均 10 次) | ~¥8 | Qwen-Plus 为主 |
170170
| Pro 重度(日均 50 次) | ~¥35 | 含多模态调用 |
171171

172172
### 盈亏平衡
173173

174-
- 月固定成本 ¥60 + 10 个 Pro 用户 AI 成本 ¥80 = ¥140
174+
- 月固定成本 ¥60 + AI 成本(10 个 Pro × ¥15 + 200 个 Free × ¥1 ≈ ¥350)= ¥410
175175
- 10 个 Pro 用户收入 = ¥120(月付)或 ¥82(年付均摊)
176-
- **盈亏平衡点 ≈ 15 个 Pro 月付用户**(含早鸟预售收入则更快)
176+
- **盈亏平衡点 ≈ 35 个 Pro 月付用户**(含早鸟预售收入则更快;若 Free 层 AI 成本经 BYOK 转嫁用户,回落至 ≈ 25)
177177

178178
---
179179

@@ -199,6 +199,7 @@
199199
| ❌ 爱发电 | 用户明确要求排除 |
200200
| ❌ 需要工商户的支付通道 | 当前阶段约束 |
201201
| ❌ 强制联网验证 | 离线可用是底线;激活码本地缓存验证,7 天离线宽限 |
202+
| ❌ 供应商免费额度转供用户 | 智谱等《服务协议》3.4 条禁止"复制、转让、出售、出租、出借、许可、提供他人使用";免费额度仅限开发/内测(非商业运营) |
202203

203204
---
204205

@@ -207,6 +208,7 @@
207208
| 风险 | 概率 | 应对 |
208209
|------|:---:|------|
209210
| 付费意愿不足(< 10 人早鸟) | 中 | 转向纯赞助模式(GitHub Sponsors + 打赏码),AI 成本由 BYOK 转嫁用户 |
211+
| 供应商免费额度收紧/条款变动 | 中 | 免费层不依赖免费额度(本地推理 + BYOK + 付费低价档);每季度复审各 Provider 服务协议 |
210212
| AI 成本失控(重度用户) | 低 | 日配额硬顶已就绪(budget.py);极端用户单独沟通 |
211213
| 激活码被分享 | 中 | 一码一设备绑定(machineId);超限自动冻结 |
212214
| 平台政策变动(面包多) | 低 | 多通道备份(Gumroad + 个人收款码) |

‎server/.env.example‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ JWT_SECRET=change-this-to-a-random-string-in-production
3636
# (ASR 模型为 qwen3-asr-flash,DashScope OpenAI 兼容模式仅支持该系列做转写)
3737
QWEN_API_KEY=
3838
# DeepSeek:https://platform.deepseek.com
39+
# 主力 Provider(v4 Flash 0731):所有纯文字 AI 功能统一路由至此
40+
# 支持多 Key 轮询(逗号分隔),突破单 Key RPM/TPM 限制
41+
DEEPSEEK_API_KEYS=sk-your-first-key,sk-your-second-key
42+
# 兼容单 Key 配置(DEEPSEEK_API_KEYS 不存在时回退)
3943
DEEPSEEK_API_KEY=
4044
# 智谱 GLM:https://open.bigmodel.cn
4145
# 用途:免费文本/视觉模型 glm-4.6v-flash,同时是 ASR 备选链路(模型 glm-asr)。

‎server/ai-gateway/chains/card_gen_chain.py‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,23 @@ async def _stage_extract(self, note: str) -> list[str]:
7070
list[str]: 提取的知识点列表
7171
"""
7272
extract_prompt = (
73-
"请从以下学习笔记中提取所有核心知识点,每个知识点用一行描述。\n"
74-
"只需要列出知识点,不要编号,不要额外解释。\n\n"
75-
f"笔记内容:\n{note}"
73+
"## 笔记内容\n"
74+
f"{note}\n\n"
75+
"## 提取要求\n"
76+
"请从以上学习笔记中提取所有核心知识点,每行一个知识点。"
77+
"只需要列出知识点,不要编号,不要额外解释。"
7678
)
7779

7880
result = await self.provider.generate(
7981
prompt=extract_prompt,
80-
system_prompt="你是一个教育内容专家,擅长从学习材料中识别核心概念、定义和关键关系。请用中文输出。",
82+
system_prompt=(
83+
"你是一个教育内容专家,擅长从学习材料中识别核心概念、定义和关键关系。\n\n"
84+
"## 输出规范\n"
85+
"- 每行一个知识点\n"
86+
"- 不要编号,不要列表符号\n"
87+
"- 使用简洁准确的表述\n"
88+
"- 用中文输出"
89+
),
8190
model=self.model,
8291
temperature=0.3,
8392
max_tokens=1024,
@@ -129,7 +138,14 @@ async def _stage_generate(
129138

130139
result = await self.provider.generate(
131140
prompt=prompt,
132-
system_prompt="你是一个教育内容专家,擅长从知识点中生成高质量问答闪卡。请务必以JSON格式输出结果。",
141+
system_prompt=(
142+
"你是一个教育内容专家,擅长从知识点中生成高质量问答闪卡。\n\n"
143+
"## 输出规范\n"
144+
"- 必须严格按照 JSON 格式输出\n"
145+
"- 每张卡片包含 front、back、type、confidence 四个字段\n"
146+
"- 确保问题具有区分度,答案准确完整\n"
147+
"- 用中文输出"
148+
),
133149
model=self.model,
134150
temperature=0.4,
135151
max_tokens=2048,

‎server/ai-gateway/chains/evaluation_chain.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,23 @@ async def run(
145145
result = await self.provider.generate(
146146
prompt=prompt,
147147
system_prompt=(
148-
"你是一位友善且专业的学习导师,擅长评估学生对知识概念的理解程度。"
149-
"请使用费曼学习法的评估标准,从准确性、完整性、简洁性、通俗性四个维度进行评分。"
150-
"请注意多给予鼓励,同时给出具体的改进建议。请务必以JSON格式输出。"
148+
"你是一位友善且专业的学习导师,擅长评估学生对知识概念的理解程度。\n"
149+
"请使用费曼学习法的评估标准,从四个维度进行评分。\n\n"
150+
"## 评估维度\n"
151+
"1. 准确性(accuracy):概念理解是否正确,有无事实错误\n"
152+
"2. 完整性(completeness):是否覆盖了概念的核心要点\n"
153+
"3. 简洁性(conciseness):表达是否简洁明了,不冗余\n"
154+
"4. 通俗性(accessibility):是否使用了通俗易懂的语言、生活化类比或举例\n\n"
155+
"## 评分标准\n"
156+
"- 每个维度 0-10 分\n"
157+
"- 综合评分 = 四个维度的加权平均(准确性权重最高)\n\n"
158+
"## 输出格式\n"
159+
"请务必以 JSON 格式输出,包含:overall_score、dimensions(含 dimension/score/feedback)、"
160+
"strengths、improvements、encouragement。\n\n"
161+
"## 注意事项\n"
162+
"- 多给予正面鼓励,保护学习积极性\n"
163+
"- 改进建议要具体可操作\n"
164+
"- 综合评分为四个维度的加权平均(准确性权重最高)"
151165
),
152166
model=self.model,
153167
temperature=0.5,

‎server/ai-gateway/chains/feynman_question_chain.py‎

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,24 @@ async def generate_questions(
5050
)
5151

5252
system_prompt = (
53-
"你是一个对知识充满好奇但了解不多的\u201c小白\u201d。\n"
53+
"你是一个对知识充满好奇但了解不多的「小白」。\n"
5454
"你刚刚听了一位同学对某个概念的讲解,请根据讲解中可能不够清晰、"
5555
"不够深入或存在逻辑跳跃的地方,提出追问。\n"
5656
"追问应该能帮助这位同学更深入地理解概念。\n\n"
57-
"要求:\n"
57+
"## 追问原则\n"
5858
"1. 追问要像好奇的小白:天真但切中要害\n"
5959
"2. 聚焦解释中的薄弱点(模糊表述、缺少具体例子、逻辑跳跃)\n"
6060
"3. 每个追问都要具体,不要泛泛而谈\n"
61-
"4. 以 JSON 格式输出,格式为:\n"
62-
' {"questions": [{"question": "追问内容", "focus": "聚焦的知识点"}]}\n'
63-
"5. 提出 1-3 个追问,不要超过 3 个"
61+
"4. 提出 1-3 个追问,不要超过 3 个\n\n"
62+
"## 输出格式\n"
63+
'请以 JSON 格式输出,格式为:{"questions": [{"question": "追问内容", "focus": "聚焦的知识点"}]}'
6464
)
6565

6666
user_prompt = (
67-
f"这位同学讲解的概念是:「{concept}」\n\n"
68-
f"讲解内容如下:\n{explanation}\n\n"
67+
"## 讲解概念\n"
68+
f"{concept}\n\n"
69+
"## 讲解内容\n"
70+
f"{explanation}\n\n"
6971
"请根据讲解内容中的薄弱点提出追问。"
7072
)
7173

@@ -162,23 +164,26 @@ async def evaluate_answers(
162164
system_prompt = (
163165
"你是一位专业的学习评估导师。\n"
164166
"你需要评估一位同学对追问的回答质量,判断其对概念的理解深度。\n\n"
165-
"请以 JSON 格式输出评估结果,格式为:\n"
167+
"## 评分标准\n"
168+
"- 0-3: 理解肤浅,回答模糊或偏离主题\n"
169+
"- 4-6: 有基本理解,但缺少深度或具体例子\n"
170+
"- 7-8: 理解较好,能用具体例子解释\n"
171+
"- 9-10: 深入理解,能举一反三\n\n"
172+
"## 输出格式\n"
173+
"请以 JSON 格式输出评估结果:\n"
166174
"{\n"
167175
' "understanding_score": 0-10 的数值,\n'
168176
' "feedback": "整体反馈",\n'
169177
' "strong_points": ["理解到位的方面"],\n'
170178
' "weak_points": ["仍需加强的方面"]\n'
171-
"}\n\n"
172-
"评分标准:\n"
173-
"0-3: 理解肤浅,回答模糊或偏离主题\n"
174-
"4-6: 有基本理解,但缺少深度或具体例子\n"
175-
"7-8: 理解较好,能用具体例子解释\n"
176-
"9-10: 深入理解,能举一反三"
179+
"}"
177180
)
178181

179182
user_prompt = (
180-
f"概念:「{concept}」\n\n"
181-
f"以下是该同学对追问的回答:\n{qa_pairs}\n\n"
183+
"## 概念\n"
184+
f"{concept}\n\n"
185+
"## 问答记录\n"
186+
f"{qa_pairs}\n\n"
182187
"请评估该同学对这个概念的理解深度。"
183188
)
184189

‎server/ai-gateway/chains/recommend_chain.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,10 @@ async def run(
207207
result = await self.provider.generate(
208208
prompt=prompt,
209209
system_prompt=(
210-
"你是一个专注力管理助手,擅长根据用户的专注历史数据给出个性化的番茄钟时长建议。"
211-
"请基于数据分析给出科学的推荐。请务必以JSON格式输出。"
210+
"你是一个专注力管理助手,擅长根据用户的专注历史数据给出个性化的番茄钟时长建议。\n"
211+
"请基于数据分析给出科学的推荐。\n\n"
212+
"## 输出格式\n"
213+
"请务必以 JSON 格式输出,包含:recommended_minutes、break_minutes、reason。"
212214
),
213215
model=self.model,
214216
temperature=0.3,

‎server/ai-gateway/chains/summarize_chain.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,14 @@ async def run(
9090
logger.info("SummarizeChain.run: text_length=%d, style=%s", len(processed_text), opts.get("style", "bullet"))
9191
result = await self.provider.generate(
9292
prompt=prompt,
93-
system_prompt="你是一个专业的学习笔记摘要助手,擅长从学习内容中提取核心知识点并生成结构化摘要。请用中文输出。",
93+
system_prompt=(
94+
"你是一个专业的学习笔记摘要助手,擅长从学习内容中提取核心知识点并生成结构化摘要。\n\n"
95+
"## 输出规范\n"
96+
"- 始终用中文输出\n"
97+
"- 提取核心概念、关键定义、重要关系\n"
98+
"- 使用学生能理解的简洁语言\n"
99+
"- 保持教育学习场景的专注性"
100+
),
94101
model=self.model,
95102
temperature=0.3,
96103
max_tokens=1024,

0 commit comments

Comments
 (0)