9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
9.4 KiB
9.4 KiB
研发工单 v1.3.0 - 03-03 AI 任务拆分服务
父工单:03-会议任务拆分
依赖:03-01(API 契约)、工单 02(
LlmClientService)
一、目标
实现基于 LLM 的会议内容分析服务:接收会议纪要文字,通过 LLM prompt 工程提取行动项,生成结构化的待办项建议列表(含标题、优先级、理由)。
二、范围
包含:
MeetingAiBreakdownService:会议文本 → LLM → 结构化建议列表- 会议拆分专用 prompt 设计与迭代
- AI 拆分 API 端点:
POST /api/meeting/{taskId}/breakdown - 批量创建确认端点:
POST /api/meeting/{taskId}/breakdown/confirm - 在线可用性检测(离线时拒绝 AI 拆分请求)
- 复用工单 02 的
LlmClientService
不包含:
- 单任务拆分(属于工单 02
AI_BREAKDOWN意图) - LLM 基础设施搭建(由工单 02 提供)
- 前端审阅 UI(由 03-04 完成)
三、前置条件
| 条件 | 说明 |
|---|---|
| 03-01 完成 | MeetingController 骨架就绪 |
工单 02 LlmClientService |
LLM 调用封装可用 |
四、详细规格
4.1 MeetingAiBreakdownService
/// <summary>会议 AI 拆分服务,将会议文字内容分析为待办项建议</summary>
public class MeetingAiBreakdownService
{
private readonly ILlmClientService _llmClient;
private readonly MeetingService _meetingService;
private readonly ITaskService _taskService;
public MeetingAiBreakdownService(
ILlmClientService llmClient,
MeetingService meetingService,
ITaskService taskService) { ... }
/// <summary>分析会议内容,返回待办项建议列表</summary>
public async Task<List<MeetingTaskSuggestion>> AnalyzeAsync(
int taskId, string? notes = null, CancellationToken ct = default)
{
// 1. 验证 taskId 为 Meeting 类型
var meeting = await _meetingService.GetMeetingTaskOrThrow(taskId);
// 2. 获取会议文字(参数优先,否则取数据库中的 meetingNotes)
var meetingText = notes ?? meeting.MeetingNotes;
if (string.IsNullOrWhiteSpace(meetingText))
throw new BusinessException("会议内容为空,请先输入纪要或上传录音");
// 3. 构建 prompt,调用 LLM
var prompt = BuildBreakdownPrompt(meetingText, meeting.Title);
var response = await _llmClient.SendAsync(prompt, ct);
// 4. 解析 LLM 返回的 JSON 为建议列表
return ParseSuggestions(response);
}
/// <summary>确认建议并批量创建子任务</summary>
public async Task<BatchCreateResult> ConfirmAndCreateAsync(
int taskId, List<SubTaskCreateItem> subTasks, CancellationToken ct = default)
{
// 1. 验证 taskId 为 Meeting 类型
await _meetingService.GetMeetingTaskOrThrow(taskId);
// 2. 批量创建子任务
var created = new List<TaskDto>();
foreach (var item in subTasks)
{
var dto = new CreateTaskDto
{
Title = item.Title,
Priority = item.Priority,
ParentTaskId = taskId
};
created.Add(await _taskService.CreateTaskAsync(dto));
}
return new BatchCreateResult { CreatedCount = created.Count, SubTasks = created };
}
}
4.2 LLM Prompt 设计
System Prompt:
你是专业的项目管理和会议纪要分析助手。根据用户提供的会议内容,提取所有需要
后续行动的事项,生成待办项建议列表。
要求:
1. 每条建议包含标题(title)、优先级(priority)、原因(reason)
2. 标题应简洁明确(15 字以内),如"整理需求文档"、"安排评审会议"
3. 优先级:High(2)=紧急重要,Medium(1)=一般,Low(0)=可延迟
4. 原因应解释为什么需要这个待办项,引用会议中的具体决策或讨论
5. 只提取明确需要执行的事项,不要生成模糊或无来源的建议
6. 建议数量根据会议内容合理判断,通常 3-10 条
7. 如果会议内容无法提取出明确的行动项,返回空列表
输出格式(只输出 JSON,不要解释):
{
"suggestions": [
{
"title": "待办项标题",
"priority": 1,
"reason": "原因说明"
}
]
}
4.3 DTO 定义
/// <summary>会议任务拆分建议</summary>
public class MeetingTaskSuggestion
{
/// <summary>建议的待办项标题</summary>
public string Title { get; set; } = string.Empty;
/// <summary>建议优先级</summary>
public TaskPriority Priority { get; set; } = TaskPriority.Medium;
/// <summary>拆分原因(LLM 输出,用于 UI 展示)</summary>
public string Reason { get; set; } = string.Empty;
}
/// <summary>拆分请求</summary>
public class BreakdownRequest
{
/// <summary>会议纪要文字(可选,不传则使用已保存的 meetingNotes)</summary>
public string? Notes { get; set; }
}
/// <summary>拆分响应</summary>
public class BreakdownResponse
{
public int TaskId { get; set; }
public List<MeetingTaskSuggestion> Suggestions { get; set; } = new();
}
/// <summary>批量创建请求中的单个子任务</summary>
public class SubTaskCreateItem
{
public string Title { get; set; } = string.Empty;
public TaskPriority Priority { get; set; } = TaskPriority.Medium;
}
/// <summary>批量确认请求</summary>
public class ConfirmBreakdownRequest
{
public List<SubTaskCreateItem> SubTasks { get; set; } = new();
}
/// <summary>批量创建结果</summary>
public class BatchCreateResult
{
public int CreatedCount { get; set; }
public List<TaskDto> SubTasks { get; set; } = new();
}
4.4 API 端点
POST /api/meeting/{taskId}/breakdown
- 接收:
BreakdownRequest - 返回:
ApiResponse<BreakdownResponse> - 处理:
- 获取会议文字(参数优先于数据库)
- 调用
MeetingAiBreakdownService.AnalyzeAsync() - 返回建议列表
- 错误:
- 内容为空 → 400 "会议内容为空"
- 离线 → 503 "AI 拆分仅在线可用"
- taskId 非 Meeting 类型 → 400
POST /api/meeting/{taskId}/breakdown/confirm
- 接收:
ConfirmBreakdownRequest - 返回:
ApiResponse<BatchCreateResult> - 处理:
- 验证 taskId 为 Meeting 类型
- 逐条创建子任务(通过
TaskService.CreateTaskAsync) - 返回创建结果
4.5 LLM 响应解析
/// <summary>解析 LLM 返回的 JSON 为建议列表</summary>
private List<MeetingTaskSuggestion> ParseSuggestions(string llmResponse)
{
// 1. 清理 LLM 响应(移除可能的 markdown 代码块包裹、前后空白)
var json = CleanJsonResponse(llmResponse);
// 2. 反序列化
var result = JsonSerializer.Deserialize<LlBreakdownResponse>(json);
// 3. 验证
if (result?.Suggestions == null || result.Suggestions.Count == 0)
return new List<MeetingTaskSuggestion>();
// 4. 过滤无效条目(标题为空)
return result.Suggestions
.Where(s => !string.IsNullOrWhiteSpace(s.Title))
.Select(s => new MeetingTaskSuggestion
{
Title = s.Title.Trim(),
Priority = s.Priority,
Reason = s.Reason?.Trim() ?? string.Empty
})
.ToList();
}
/// <summary>LLM 原始响应结构</summary>
private class LlBreakdownResponse
{
public List<MeetingTaskSuggestion> Suggestions { get; set; } = new();
}
4.6 错误处理
| 场景 | HTTP 状态码 | message |
|---|---|---|
| 会议文字内容为空 | 400 | 会议内容为空,请先输入纪要或上传录音 |
| taskId 不存在 | 404 | 待办项不存在 |
| taskId 不是 Meeting 类型 | 400 | 该待办项不是会议类型 |
| LLM API 调用失败 | 502 | AI 拆分服务暂时不可用,请稍后重试 |
| LLM 返回格式异常 | 500 | AI 拆分结果解析失败 |
| 离线 | 503 | AI 拆分仅在线可用 |
| 确认时子任务列表为空 | 400 | 请至少选择一个待办项 |
五、验收标准
| 验收项 | 验证方法 | 预期结果 |
|---|---|---|
| 会议内容分析 | 提交一段会议纪要文字 | 返回 3-10 条结构化建议 |
| 建议质量 | 检查建议的标题、优先级、原因 | 标题明确、优先级合理、原因引用会议内容 |
| 空内容拒绝 | 不传 notes 且 meetingNotes 为空 | 返回 400 |
| 非 Meeting 类型拒绝 | 传普通待办项 ID | 返回 400 |
| 在线依赖 | 离线时请求拆分 | 返回 503 |
| 批量创建 | 确认勾选的建议 | 子任务批量创建成功 |
| LLM 异常降级 | 模拟 LLM 调用失败 | 返回 502,不影响其他功能 |
| 空结果处理 | 会议内容无可提取的待办项 | 返回空建议列表 + 提示信息 |
六、风险
| 风险 | 影响 | 应对 |
|---|---|---|
| LLM 返回格式不符 | 建议解析失败 | 增加 JSON 清理逻辑(移除 markdown 包裹、前后文本) |
| LLM Token 限制 | 长会议纪要超出上下文窗口 | 限制文本长度(如 4000 字);超长时截断并告知用户 |
| Prompt 需要迭代 | 建议质量不达预期 | prompt 作为配置项,支持热更新 |
七、Touch List
| 文件路径 | 修改类型 |
|---|---|
src/Hua.Todo.Application/Meeting/MeetingAiBreakdownService.cs |
新增 |
src/Hua.Todo.Application/Meeting/MeetingController.cs |
修改 |
src/Hua.Todo.Application/Meeting/Models/MeetingDtos.cs |
修改 |
工单编号:03-03 标题:AI 任务拆分服务 版本:v1.3.0 创建日期:2026-06-16