9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
18 KiB
18 KiB
研发工单 v1.3.0 - 02 语音控制与 AI 辅助
一、目标与范围
1.1 目标
实现语音控制 Todo 待办项能力与 AI 辅助任务拆分功能,通过平台原生 STT/TTS 实现语音输入输出,通过 LLM 意图解析处理自然语言指令,离线降级到规则匹配,通过 LLM 提供 AI 拆分建议。
1.2 范围
包含:
- 语音输入(STT):平台原生语音识别 → 文字
- 语音播报(TTS):执行结果语音反馈
- 语音指令解析与执行(CRUD + 子任务操作)
- 指令歧义处理(目标不唯一时返回候选列表)
- AI 辅助任务拆分(LLM 生成子任务建议,用户确认后批量创建)
不包含:
- 语音通话功能(场景不明确,本期不做)
- 前端语音 UI 设计(仅提供能力层与 API)
- 第三方语音服务集成(使用平台原生能力)
二、前置条件
| 条件 | 说明 |
|---|---|
| Hua.Todo v1.2.0 | 已完成,提供基础业务能力 |
| 各平台原生 STT/TTS | Windows(Windows.Media.SpeechRecognition/SpeechSynthesis)、Android(SpeechRecognizer/TextToSpeech)、iOS/macOS(SFSpeechRecognizer/AVSpeechSynthesizer)、Linux(WebKitGTK Web Speech API / vosk 离线模型) |
| LLM API | 在线模式意图解析 + AI 拆分共用;API Key 在 Host 端管理 |
| 工单 01(可选) | MCP 服务就绪后,语音指令与 AI 拆分也可通过 MCP 暴露 |
三、架构设计
3.1 整体链路
平台 STT(语音→文字)
↓
IVoiceInputService(Core 接口,各平台实现)
↓ 回调文字到前端
WebView → POST /api/voice/command { text: "帮我把那个开会的删了吧" }
↓
Host API → IVoiceIntentParser(双策略)
├─ 在线:LlmIntentParser(调 LLM,输出结构化意图+参数)
└─ 离线:RuleIntentParser(关键词规则匹配,覆盖高频指令)
↓
意图 + 参数 → 判断歧义
├─ 无歧义 → 调用 TaskService 执行 → TTS 播报结果
├─ 有歧义 → 返回候选列表 → 前端展示 → 用户确认 → 再执行
└─ UNKNOWN → TTS 播报"没听懂,请再说一次"
3.2 STT/TTS 分层策略
遵循与全局快捷键相同的平台分离模式(接口+平台目录):
| 层 | 职责 | 位置 |
|---|---|---|
IVoiceInputService / IVoiceOutputService |
接口定义 | src/Hua.Todo.Core/Services/ |
| MAUI 平台实现 | 各平台原生 STT/TTS | src/Hua.Todo.Maui/Platforms/{Windows,Android,macOS,iOS}/VoiceInputService.cs |
| Avalonia 平台实现 | Linux 桌面 STT/TTS | src/Hua.Todo.Avalonia/Services/Platforms/VoiceInputService.cs |
| Web 降级方案 | 浏览器 Web Speech API | 前端 voiceInput.ts |
3.3 意图解析双策略(A+C 方案)
采用 LLM 主解析 + 规则降级 的混合方案:
策略 A:在线 — LLM 意图解析(LlmIntentParser)
在线模式下,将用户原始文字发送给 LLM,通过 system prompt 约束输出为结构化 JSON:
System Prompt(精简版):
你是 Hua.Todo 的语音指令解析器。根据用户输入,输出以下 JSON 格式:
{
"intent": "CREATE|UPDATE|DELETE|COMPLETE|UNCOMPLETE|QUERY|ADD_SUBTASK|AI_BREAKDOWN|UNKNOWN",
"params": { ... },
"confidence": 0.0-1.0
}
意图说明:
- CREATE: 创建任务,params: { title, priority? }
- UPDATE: 修改任务,params: { targetTitle, newTitle }
- DELETE: 删除任务,params: { targetTitle }
- COMPLETE: 完成任务,params: { targetTitle }
- UNCOMPLETE: 取消完成,params: { targetTitle }
- QUERY: 查询任务,params: { filter? }
- ADD_SUBTASK: 添加子任务,params: { parentTitle, subTitle }
- AI_BREAKDOWN: AI辅助拆分,params: { targetTitle }
- UNKNOWN: 无法识别
只输出 JSON,不要解释。
示例调用:
输入:"帮我把那个开会的任务删了吧"
LLM 输出:
{
"intent": "DELETE",
"params": { "targetTitle": "开会" },
"confidence": 0.95
}
输入:"这个项目太大了,帮我拆一下"
LLM 输出:
{
"intent": "AI_BREAKDOWN",
"params": { "targetTitle": "这个项目" },
"confidence": 0.88
}
优势:
- 无需维护同义词表,LLM 天然理解各种自然语言表述
- 扩展新意图只需修改 prompt,不改代码
- 歧义场景 LLM 也能判断(如 confidence < 阈值时触发确认)
策略 C:离线 — 规则匹配降级(RuleIntentParser)
离线/嵌入式模式下,降级到关键词规则匹配,只覆盖高频指令:
| 意图 | 匹配规则 | 示例 |
|---|---|---|
CREATE |
正则:`/^(创建 | 新增 |
DELETE |
正则:`/^(删除 | 删掉 |
COMPLETE |
正则:`/^(完成 | 做完)\s*(任务 |
UNCOMPLETE |
正则:`/^(取消完成 | 重新打开 |
UPDATE |
正则:`/^(修改 | 更新 |
QUERY |
正则:`/^(查询 | 查看 |
ADD_SUBTASK |
正则:`/^(给 | 为)\s*(.+?)\s*(添加 |
AI_BREAKDOWN |
正则:`/^(帮我拆分 | AI拆分 |
降级策略:
- 离线模式下
AI_BREAKDOWN意图不可用(需要 LLM),TTS 播报"离线模式不支持 AI 拆分" - 规则匹配失败时返回
UNKNOWN
策略切换逻辑
/// <summary>语音意图解析器接口</summary>
public interface IVoiceIntentParser
{
/// <summary>解析语音指令文本,返回意图与参数</summary>
Task<VoiceIntentResult> ParseAsync(string text, CancellationToken ct = default);
}
/// <summary>双策略解析器:在线走 LLM,离线走规则</summary>
public class HybridVoiceIntentParser : IVoiceIntentParser
{
private readonly LlmIntentParser _llmParser;
private readonly RuleIntentParser _ruleParser;
private readonly IConnectivityService _connectivity;
public async Task<VoiceIntentResult> ParseAsync(string text, CancellationToken ct)
{
if (_connectivity.IsOnline)
{
try
{
var result = await _llmParser.ParseAsync(text, ct);
if (result.Intent != VoiceIntent.UNKNOWN)
return result;
}
catch (Exception)
{
// LLM 调用失败,降级到规则
}
}
return _ruleParser.Parse(text);
}
}
3.4 语音指令处理完整流程
原始文字 → HybridVoiceIntentParser
├─ 在线:LlmIntentParser(LLM 结构化输出)
└─ 离线/降级:RuleIntentParser(关键词正则匹配)
↓
意图 + 参数 + confidence
├─ confidence >= 阈值 且 目标唯一 → 执行 → TTS 播报
├─ 目标匹配多个 → 返回候选列表 → 用户确认 → 执行
├─ confidence < 阈值 → TTS "您是要...吗?" → 用户确认
└─ UNKNOWN → TTS "没听懂,请再说一次"
四、需求规格
4.1 语音输入(STT)
各平台通过原生 API 将语音转为文字,通过 IVoiceInputService 接口统一暴露:
/// <summary>语音输入服务接口,各平台实现原生 STT</summary>
public interface IVoiceInputService
{
/// <summary>是否正在监听</summary>
bool IsListening { get; }
/// <summary>开始语音识别,识别结果通过回调返回</summary>
Task StartListeningAsync(Action<string> onResult, Action<string>? onError = null);
/// <summary>停止语音识别</summary>
Task StopListeningAsync();
}
4.2 语音播报(TTS)
/// <summary>语音输出服务接口,各平台实现原生 TTS</summary>
public interface IVoiceOutputService
{
/// <summary>是否正在播报</summary>
bool IsSpeaking { get; }
/// <summary>播报文本</summary>
Task SpeakAsync(string text);
/// <summary>停止播报</summary>
Task StopSpeakingAsync();
}
4.3 语音指令解析
意图定义
| 意图 (Intent) | 参数 | 说明 |
|---|---|---|
CREATE |
title(必填)、priority(可选:High/Medium/Low) |
创建任务 |
UPDATE |
targetTitle(必填)、newTitle(必填) |
修改任务标题 |
DELETE |
targetTitle(必填) |
删除任务 |
COMPLETE |
targetTitle(必填) |
标记完成 |
UNCOMPLETE |
targetTitle(必填) |
取消完成 |
QUERY |
filter(可选:如"未完成"、"高优先级") |
查询任务 |
ADD_SUBTASK |
parentTitle(必填)、subTitle(必填) |
添加子任务 |
AI_BREAKDOWN |
targetTitle(必填) |
AI 辅助拆分(仅在线) |
UNKNOWN |
无 | 无法识别 |
歧义处理规则
当指令中 targetTitle 匹配到多个 Todo 待办项时:
- 不直接执行,返回歧义结果(包含匹配的候选列表)
- 前端展示候选项,用户点选或语音确认后再执行
- 匹配规则:标题完全匹配优先,包含匹配次之
置信度阈值
- LLM 返回
confidence >= 0.8:直接执行 0.5 <= confidence < 0.8:确认后执行(TTS "您是要...吗?")confidence < 0.5:按 UNKNOWN 处理
4.4 语音指令 API
POST /api/voice/command
请求体:
{
"text": "帮我把那个开会的删了吧" // STT 识别后的原始文字
}
响应体:
{
"intent": "DELETE", // 解析出的意图
"params": { // 提取的参数
"targetTitle": "开会"
},
"confidence": 0.95, // 置信度
"result": { // 执行结果
"success": true,
"message": "已删除任务:开会",
"data": null
}
}
歧义响应:
{
"intent": "COMPLETE",
"params": { "targetTitle": "开会" },
"confidence": 0.92,
"result": {
"success": false,
"message": "找到多个匹配的任务,请确认",
"ambiguity": true,
"candidates": [
{ "id": 1, "title": "开会" },
{ "id": 5, "title": "开会讨论方案" }
]
}
}
用户确认后二次请求:
POST /api/voice/command/confirm
请求体:
{
"intent": "COMPLETE",
"targetId": 5 // 用户选择的候选 ID
}
4.5 AI 辅助任务拆分
POST /api/voice/ai-breakdown
请求体:
{
"taskId": 5 // 要拆分的目标任务 ID
}
响应体:
{
"suggestions": [ // LLM 生成的子任务建议
{ "title": "准备会议议程", "priority": "Medium" },
{ "title": "发送会议邀请", "priority": "High" },
{ "title": "预定会议室", "priority": "Low" }
]
}
用户确认后批量创建:
POST /api/voice/ai-breakdown/confirm
请求体:
{
"parentTaskId": 5,
"subTasks": [ // 用户勾选后的子任务列表
{ "title": "准备会议议程", "priority": "Medium" },
{ "title": "发送会议邀请", "priority": "High" }
]
}
关键约束:
- LLM 调用在 Host 端执行,API Key 不暴露到客户端
- 意图解析与 AI 拆分共用同一 LLM 基础设施
- 建议≠直接执行,必须用户确认后才创建子任务
- 离线模式下 AI 拆分不可用,TTS 播报"离线模式不支持 AI 拆分"
- MCP 服务就绪后,
aiBreakdown可同步暴露为 MCP 工具
五、验收标准
| 验收项 | 验证方法 | 预期结果 |
|---|---|---|
| STT 语音输入 | 说话后检查回调文字 | 文字识别正确 |
| TTS 语音播报 | 执行指令后检查播报 | 播报内容与执行结果一致 |
| 创建任务(在线) | "帮我把开会的任务加上" | LLM 解析为 CREATE,成功创建 |
| 创建任务(离线降级) | "创建任务 测试" | 规则匹配为 CREATE,成功创建 |
| 创建带优先级任务 | "建一个高优先级任务 紧急" | 成功创建高优先级任务 |
| 完成任务指令 | "把那个开会的事标完成" | LLM 解析为 COMPLETE,执行成功 |
| 取消完成指令 | "取消完成 测试" | 任务状态恢复为未完成 |
| 删除任务指令 | "帮我把测试删了" | LLM 解析为 DELETE,删除成功 |
| 更新任务指令 | "把测试改成验收" | 任务标题更新 |
| 查询任务指令 | "有哪些没做完的" | LLM 解析为 QUERY,返回列表 |
| 添加子任务指令 | "给开会加个子任务 准备PPT" | 子任务创建成功 |
| 歧义处理 | 多个任务含"开会"时说"完成开会" | 返回候选列表,不直接执行 |
| AI 拆分建议 | "帮我拆分 开会" | 返回子任务建议列表 |
| AI 拆分确认 | 用户勾选后确认 | 仅创建勾选的子任务 |
| 离线 AI 拆分 | 离线时说"帮我拆分" | 播报"离线模式不支持 AI 拆分" |
| 无法识别指令 | 说出无关内容 | 播报"没听懂,请再说一次" |
| LLM 降级 | 断网时使用语音 | 自动降级到规则匹配,基本 CRUD 可用 |
六、Touch List
| 文件路径 | 修改类型 | 说明 |
|---|---|---|
src/Hua.Todo.Core/Services/IVoiceInputService.cs |
新增 | STT 接口定义 |
src/Hua.Todo.Core/Services/IVoiceOutputService.cs |
新增 | TTS 接口定义 |
src/Hua.Todo.Core/Services/IVoiceIntentParser.cs |
新增 | 意图解析器接口 |
src/Hua.Todo.Application/Voice/LlmIntentParser.cs |
新增 | LLM 意图解析器(在线策略) |
src/Hua.Todo.Application/Voice/RuleIntentParser.cs |
新增 | 规则匹配解析器(离线降级策略) |
src/Hua.Todo.Application/Voice/HybridVoiceIntentParser.cs |
新增 | 双策略解析器(在线走 LLM,离线走规则) |
src/Hua.Todo.Application/Voice/VoiceCommandIntent.cs |
新增 | 意图枚举定义 |
src/Hua.Todo.Application/Voice/VoiceCommandExecutor.cs |
新增 | 意图执行器(分发到 TaskService) |
src/Hua.Todo.Application/Voice/VoiceController.cs |
新增 | 语音指令 API 端点(/api/voice/command、/api/voice/ai-breakdown) |
src/Hua.Todo.Application/Voice/AiBreakdownService.cs |
新增 | AI 辅助拆分服务(调用 LLM 生成建议) |
src/Hua.Todo.Application/Voice/LlmClientService.cs |
新增 | LLM 调用封装(意图解析 + AI 拆分共用) |
src/Hua.Todo.Application/Voice/Models/ |
新增 | 语音相关 DTO(VoiceIntentResult、VoiceCommandRequest 等) |
src/Hua.Todo.Application/Voice/VoiceServiceCollectionExtensions.cs |
新增 | 语音服务 DI 注册 |
src/Hua.Todo.Maui/Platforms/Windows/VoiceInputService.cs |
新增 | Windows STT 实现 |
src/Hua.Todo.Maui/Platforms/Windows/VoiceOutputService.cs |
新增 | Windows TTS 实现 |
src/Hua.Todo.Maui/Platforms/Android/VoiceInputService.cs |
新增 | Android STT 实现 |
src/Hua.Todo.Maui/Platforms/Android/VoiceOutputService.cs |
新增 | Android TTS 实现 |
src/Hua.Todo.Maui/Platforms/MacCatalyst/VoiceInputService.cs |
新增 | macOS STT 实现 |
src/Hua.Todo.Maui/Platforms/MacCatalyst/VoiceOutputService.cs |
新增 | macOS TTS 实现 |
src/Hua.Todo.Maui/Platforms/iOS/VoiceInputService.cs |
新增 | iOS STT 实现 |
src/Hua.Todo.Maui/Platforms/iOS/VoiceOutputService.cs |
新增 | iOS TTS 实现 |
src/Hua.Todo.Avalonia/Services/Platforms/VoiceInputService.cs |
新增 | Linux STT 实现 |
src/Hua.Todo.Avalonia/Services/Platforms/VoiceOutputService.cs |
新增 | Linux TTS 实现 |
src/Hua.Todo.Web/src/api/voice.ts |
新增 | 前端语音 API 模块 |
src/Hua.Todo.Web/src/composables/useVoiceInput.ts |
新增 | 前端语音输入组合式函数(含 Web Speech API 降级) |
工单编号:02 标题:语音控制与 AI 辅助 版本:v1.3.0 修订日期:2026-06-16
七、与其他工单的语音入口衔接
7.1 背景
Hua.Todo 目前有两个功能入口:UI 入口(WebView / 前端界面)和语音控制入口(本工单产出)。后续每项新增功能在需求阶段都必须确认这两个入口的覆盖情况。
7.2 工单 03(会议任务拆分)的语音入口
工单 03 的会议功能需要通过语音控制入口提供以下指令:
| 语音指令 | 意图 | 参数 | 说明 |
|---|---|---|---|
| "新建会议 项目评审" | CREATE_MEETING |
title(必填)、priority(可选) |
创建会议类型任务(TaskType.Meeting) |
| "记录会议内容" | RECORD_MEETING |
targetTitle(必填) |
开始录制当前会议 |
| "停止录制" | STOP_RECORDING |
无 | 停止录制,触发转写 |
| "帮我拆分这个会议" | AI_BREAKDOWN |
targetTitle(必填,目标为会议类型) |
对会议内容进行 AI 拆分(复用 AI_BREAKDOWN 意图,参数携带 TaskType=Meeting) |
| "查看会议待办项" | QUERY |
filter="会议" |
查询所有会议类型任务 |
关键点:
AI_BREAKDOWN意图需扩展以区分普通任务拆分和会议拆分(通过TaskType字段),会议拆分的 prompt 侧重"提取行动项"CREATE_MEETING是CREATE意图的子类型,创建时字段taskType = Meeting,需要 LLM intent parser 的 prompt 增加说明- 录音控制(
RECORD_MEETING/STOP_RECORDING)是新意图,对应前端 MediaRecorder 的启动/停止
7.3 语音入口覆盖检查表
后续每个新增功能/工单,智能体必须在需求讨论阶段输出以下检查表:
| 检查项 | 状态 | 备注 |
|---|---|---|
| UI 入口是否已规划 | ✅ / ❌ | 描述 UI 入口 |
| 语音控制入口是否已规划 | ✅ / ❌ | 描述对应的语音指令与意图 |
| 当前不可覆盖的入口 | 说明原因 | 如:语音控制暂不支持 XX 操作(选项过多/需可视化交互) |
此规则已固化为项目规范,详见 .trae/rules/项目/05-多入口功能同步规范.md。