@@ -15,7 +15,7 @@
``` text
老板一句话
-> AiSecretaryAgent 判断意图和上下文
-> 意图归类为 task / reminder / qa / realtime_qa / note / need_more_info / unsupported
-> 意图归类为 task / reminder / qa / realtime_qa / note / need_more_info / unknown / unsupported
-> 稳定 AiSecretaryResponse JSON
-> 生成 AI 草稿 / 追问 / 直接回复
-> 老板确认、补充、取消或转程经理
@@ -23,7 +23,7 @@
- 支持老板通过飞书私聊或平台入口输入文本。
- 统一走 `POST /api/secretary/handle-message` 。
- 判断 `task/reminder/qa/realtime_qa/note/need_more_info/unsupported` 。
- 判断 `task/reminder/qa/realtime_qa/note/need_more_info/unknown/ unsupported` 。
- 生成稳定的 `AiSecretaryResponse` JSON。
- 对任务和提醒只生成可确认草稿,不直接执行。
- 对普通聊天、实时问答兜底、普通记录直接回复或记录。
@@ -62,7 +62,7 @@ POST /api/secretary/handle-message
-> 校验发送人角色
-> 非老板直接固定回复并记录
-> 读取 BotContext,外部 context 只作为参考
-> 判断本次消息是 follow_up / new_request / qa / realtime_qa / note / unsupported / command
-> 判断本次消息是 follow_up / new_request / qa / realtime_qa / note / unknown / unsupported / command
-> 组装 PromptContext
-> 调用模型
-> 校验 AiSecretaryResponse
@@ -105,7 +105,7 @@ cleared
- 每次进入 `awaiting_more_info` 或 `awaiting_confirm` 状态时重置 `expires_at = now + 30 分钟` 。
- 点击或说出“补充/重说”后,30 分钟内下一条消息优先尝试作为上一条草稿的修正。
- 30 分钟内不能无条件吞掉所有消息,必须先判断为 `follow_up / new_request / qa / realtime_qa / note / unsupported / command` 。
- 30 分钟内不能无条件吞掉所有消息,必须先判断为 `follow_up / new_request / qa / realtime_qa / note / unknown / unsupported / command` 。
- 老板说“换成东东”“改到明天”“刚才那个不要了”,优先修正当前草稿。
- 老板说“另外再安排一个”“新建一个”“再帮我记一个”,创建新草稿。
- 老板说“确认”“就这样”“发给他”,确认当前草稿。
@@ -113,7 +113,7 @@ cleared
- 老板问“刚才我说了什么”“总结一下”,做上下文回顾,不修改草稿。
- 超过 30 分钟,上下文标记 `expired` ,下一条默认按新输入处理;如果老板明显仍在说上一条草稿,可先提示“上一条草稿已过期,我按新请求处理”。
- 老板确认、取消或草稿转换为任务/提醒后立即清空上下文,不受 30 分钟窗口约束。
- 30 分钟窗口只绑定未确认草稿;草稿进入 `CONFIRMED / CONVERTED / CANCELLED ` 后,后续“改一下刚才那个”不能再修改原草稿,只能作为已发布任务/提醒变更请求或第一阶段能力外请求处理。
- 30 分钟窗口只绑定未确认草稿;草稿进入 `confirmed / converted / cancelled / superseded / expired ` 后,后续“改一下刚才那个”不能再修改原草稿,只能作为已发布任务/提醒变更请求或第一阶段能力外请求处理。
- 多次 `follow_up` 必须合并到同一个 `pending_draft` ,直到老板确认、取消、过期或明确新建,不得每次补充都新建草稿。
- `BotContext` 只提供上下文候选,不强制绑定消息。当本地规则或模型无法判断是修改当前草稿、新建请求、普通聊天还是取消当前草稿时,必须走 `need_more_info` 追问,不允许默认修改当前草稿。
- 老板可以通过“另外、重新来、换个事、先别管这个、取消、重新安排”等自然语言随时跳出当前上下文。
@@ -143,7 +143,7 @@ cleared
- 3 轮仍补不全,也生成带 `missing_fields` 的草稿,不继续拉扯。
- 每次追问都必须保存一条 `SecretaryMessage` , `intent_type=need_more_info` ,内容为本次给老板的问题。
- 追问轮次写入 `BotContext.follow_up_count` ,并记录 `OperationLog(action=ask_follow_up)` 。
- `follow_up_count` 在以下情况重置为 0:草稿被确认、取消、过期、进入 `PENDING_CONFIRM ` ,或生成带 `missing_fields` 的终态草稿后收到下一条新消息。
- `follow_up_count` 在以下情况重置为 0:草稿被确认、取消、过期、进入 `pending_confirmation ` ,或生成带 `missing_fields` 的终态草稿后收到下一条新消息。
## 5. 数据对象
@@ -224,7 +224,7 @@ PostgreSQL 最小保存三类 AI 记忆数据:
"message_id" : "外部消息ID或内部生成ID" ,
"role" : "boss|assistant|system" ,
"text" : "原始输入或AI回复" ,
"intent" : "task|reminder|qa|realtime_qa|note|need_more_info|unsupported|context_summary" ,
"intent" : "task|reminder|qa|realtime_qa|note|need_more_info|unknown| unsupported|context_summary" ,
"draft_id" : "postgres_ai_draft_id" ,
"bot_context_snapshot" : { } ,
"created_at" : "2026-06-22T10:00:00+08:00"
@@ -246,7 +246,7 @@ PostgreSQL 最小保存三类 AI 记忆数据:
``` json
{
"intent" : "task|reminder|qa|realtime_qa|note|need_more_info|unsupported" ,
"intent" : "task|reminder|qa|realtime_qa|note|need_more_info|unknown| unsupported" ,
"draft_type" : "task|reminder|none" ,
"should_create_draft" : true ,
"route_type" : "none|direct_after_boss_confirm|manager_confirm_required" ,
@@ -278,9 +278,9 @@ PostgreSQL 最小保存三类 AI 记忆数据:
校验规则:
- `task/reminder` 必须 `should_create_draft=true` , `draft_type` 必须对应为 `task` 或 `reminder` 。
- `qa/realtime_qa/note/need_more_info/unsupported` 必须 `should_create_draft=false` , `draft_type=none` 。
- `qa/realtime_qa/note/need_more_info/unknown/ unsupported` 必须 `should_create_draft=false` , `draft_type=none` 。
- `task` 时 `route_type` 必填,只能是 `direct_after_boss_confirm` 或 `manager_confirm_required` 。
- `reminder/qa/realtime_qa/note/need_more_info/unsupported` 时 `route_type=none` 。
- `reminder/qa/realtime_qa/note/need_more_info/unknown/ unsupported` 时 `route_type=none` 。
- `route_type=manager_confirm_required` 时,`draft.need_manager_confirm=true` ;老板主动说“给程经理看看”“让经理确认”时,也必须置为 true。
- `route_type=direct_after_boss_confirm` 时,`draft.need_manager_confirm=false` 。
- `task` 必须有事项内容;时间不是必填项。
@@ -314,6 +314,7 @@ PostgreSQL 最小保存三类 AI 记忆数据:
| realtime_qa | 固定提示需要实时数据查询,第一版暂不作为正式能力 |
| note | 只保存消息记录,不生成草稿、不通知,可用于“刚才说了什么”回顾 |
| need_more_info | 信息不足但属于可处理范围,主动追问 |
| unknown | 暂时无法判断意图,只允许澄清或留痕 |
| unsupported | 超出第一版能力,解释为什么不能做,不追问执行字段 |
优先级和兜底规则:
@@ -322,6 +323,7 @@ PostgreSQL 最小保存三类 AI 记忆数据:
- `realtime_qa.answer` 固定使用模板:“这个需要实时数据查询,第一版暂不作为正式能力;我不会把它生成任务或提醒。”
- 超出第一版能力但不属于实时数据类的输入,归为 `unsupported` 。
- `unsupported.answer` 应说明当前入口只处理老板事项草稿、提醒草稿、普通问答和普通记录,不追问执行字段。
- `unknown.answer` 只能澄清或提示补充,不得创建事项、提醒或通知。
示例:
@@ -332,37 +334,51 @@ PostgreSQL 最小保存三类 AI 记忆数据:
### 5.4 草稿状态
`ai_drafts.status` 只表示已经落 PostgreSQL 草稿表的草稿状态。非草稿 意图(`qa/realtime_qa/note/unsupported` )和纯追问结果(`need_more_info` )不落 `ai_drafts` ,只保存 `SecretaryMessage` 、`BotContext` 和处理结果 。
`ai_drafts.status` 只表示已经落 PostgreSQL 草稿表的草稿状态。非执行 意图(`qa/realtime_qa/note/unknown/ unsupported` )和纯追问结果(`need_more_info` )不得进入事项、提醒或通知闭环;如需留痕 ,只保存 `SecretaryMessage` 、`BotContext` 、 `model_call_logs` 或最小草稿记录 。
`ai_drafts.status` 建议 状态:
`ai_drafts.status` 以 `docs/contracts/状态流转约定.md` 为准,核心 状态:
``` text
PENDING_CONFIRM
NEED_MANAGER_CONFIRM
CONFIRMED
CANCELLED
FAILED
CONVERTED
pending_confirmation
awaiting_follow_up
confirmed
converted
cancelled
answered
superseded
expired
parse_failed
```
对老板可见时可以简化为:待确认、待程经理确认 、已确认、已取消、已失败。
对老板可见时可以简化为:待确认、等待补充 、已确认、已取消、已失效、已完成、已失 败。
状态含义:
- `PENDING_CONFIRM ` :草稿可确认,等待老板确认。
- `NEED_MANAGER_CONFIRM` :老板已确认,但该任务仍需要程经理确认,不能直接转换任务 。
- `CONFIRMED ` :确认链路已完成,可以交给任务或提醒模块转换。
- `CANCELLED` :老板取消草稿 。
- `FAILED` :草稿或 AI 解析过程失败的草稿状态;失败原因写入 `FailureRecord.failure_type` ,例如 `ai_parse_failed` ,两者不能混用 。
- `CONVERTED` :草稿已经成功 转换为任务或提醒。
- `pending_confirmation ` :草稿可确认,等待老板确认、补充/重说或取消 。
- `awaiting_follow_up` :老板点击补充/重说后,等待 30 分钟内下一条消息 。
- `confirmed ` :确认链路已完成,可以交给任务或提醒模块转换。
- `converted` :草稿已经成功转换为任务或提醒;复杂事项已创建 `pending_manager_confirm` 事项壳也视为转换完成 。
- `cancelled` :老板取消草稿 。
- `answered` :已直接回复或留痕,不 转换为任务或提醒。
- `superseded` :已被补充/重说生成的新草稿替代。
- `expired` :补充/重说等待超时,旧确认卡片不可继续使用。
- `parse_failed` :草稿或 AI 解析过程失败,仅用于调试追踪。
非草稿处理状态:
- `need_more_info` :本轮只追问老板,不创建 `ai_drafts` ;追问内容保存为 `SecretaryMessage(intent_type=need_more_info)` ,上下文状态为 `BotContext.status=awaiting_more_info` 。
- `answered` : `qa/realtime_qa/note/context_summary/unsupported` 的处理结果,不转换为任务或提醒,不影响当前有效 `BotContext` 。
- 追问 3 轮仍补不全、但系统决定生成带 `missing_fields` 的草稿时,模型输出必须从 `need_more_info` 转为 `task` 或 `reminder` ,创建 `PENDING_CONFIRM ` 草稿,并由确认阻塞规则控制能否确认。
- `answered` : `qa/realtime_qa/note/context_summary/unknown/ unsupported` 的处理结果,不转换为任务或提醒,不影响当前有效 `BotContext` 。
- 追问 3 轮仍补不全、但系统决定生成带 `missing_fields` 的草稿时,模型输出必须从 `need_more_info` 转为 `task` 或 `reminder` ,创建 `pending_confirmation ` 草稿,并由确认阻塞规则控制能否确认。
`DRAFTING` 不作为第一版 `ai_drafts.status` 持久化枚举。实现中如需表达“AI 已决定生成草稿但还在校验/解析”的过程态,只能作为方法内的内存标记或局部变量;落库状态必须从 `PENDING_CONFIRM` 、 `NEED_MANAGER_CONFIRM` 或 `FAILED` 开始 。
`DRAFTING` 不作为第一版 `ai_drafts.status` 持久化枚举。实现中如需表达“AI 已决定生成草稿但还在校验/解析”的过程态,只能作为方法内的内存标记或局部变量;落库状态必须来自 `状态流转约定.md` 。
草稿确认卡片生命周期:
- 每个草稿同一时间只能有一张有效确认卡片,对应 `active_card_notification_id` 。
- 老板点击“补充/重说”后,原草稿进入 `awaiting_follow_up` ,原确认卡片应失效。
- 30 分钟内收到补充消息后,新草稿 `parent_draft_id` 指向原草稿,原草稿进入 `superseded` 。
- 超过 30 分钟仍未收到补充消息时,原草稿进入 `expired` ,老板下一条消息按新输入处理。
- 飞书回调处理确认、取消、补充/重说前,必须校验回调来自当前有效卡片;旧卡片只记录事件,不写业务对象。
### 5.5 Prompt 硬规则
@@ -467,25 +483,25 @@ POST /api/secretary/handle-message
-> 老板补充
-> 新草稿或修订草稿
-> 老板确认
-> direct_after_boss_confirm: CONFIRMED -> TaskAdapter / ReminderService 转换 -> CONVERTED
-> manager_confirm_required: NEED_MANAGER_CONFIRM -> 程经理确认 -> CONFIRMED -> TaskAdapter 转换 -> CONVERTED
-> direct_after_boss_confirm: confirmed -> TaskAdapter / ReminderService 转换 -> converted
-> manager_confirm_required: confirmed -> 创建 pending_manager_confirm 事项壳 -> converted -> 程经理确认后通知接收人
```
草稿确认后的边界:
- `direct_after_boss_confirm` :老板确认成功后,草稿进入 `CONFIRMED ` 。
- `manager_confirm_required` :老板确认成功后,草稿进入 `NEED_MANAGER_CONFIRM` ,通知或展示给程经理确认;程经理确认后才进入 `CONFIRMED ` 。
- 任务/提醒转换成功后,草稿进入 `CONVERTED` ,并清空 `BotContext` 。
- 任务/提醒转换失败时,不回滚老板确认;草稿保持 `CONFIRMED ` ,写 `FailureRecord(draft_convert_failed)` ,支持后台重试或人工处理。
- 老板确认后,无论进入 `CONFIRMED` 还是 `NEED_MANAGER_CONFIRM` ,都 要清空老板侧 `BotContext` ;后续经理确认不再依赖老板 30 分钟上下文。
- `NEED_MANAGER_CONFIRM / CONFIRMED / CONVERTED ` 后,01 不再直接修改原草稿;老板后续说“把刚才发出去那个改一下”,应识别为任务/提醒变更请求,第一阶段未接入变更能力时回复暂不支持或引导到任务模块。
- `direct_after_boss_confirm` :老板确认成功后,草稿进入 `confirmed` ,转换成功后进入 `converted ` 。
- `manager_confirm_required` :老板确认成功后,草稿进入 `confirmed` ;转换时先创建 `tasks.status=pending_manager_confirm` 的事项壳,并给程经理发送待确认提醒;事项壳创建成功后草稿进入 `converted ` 。
- 程经理确认复杂事项时,补齐接收人、内容和通知信息,使事项进入 `pending_notify` ,再通知接收人 。
- 任务/提醒转换失败时,不回滚老板确认;草稿保持 `confirmed ` ,写 `FailureRecord(draft_convert_failed)` ,支持后台重试或人工处理。
- 老板确认后要清空老板侧 `BotContext` ;后续经理确认不再依赖老板 30 分钟上下文。
- `confirmed / converted / cancelled / superseded / expired ` 后,01 不再直接修改原草稿;老板后续说“把刚才发出去那个改一下”,应识别为任务/提醒变更请求,第一阶段未接入变更能力时回复暂不支持或引导到任务模块。
直接回复流转:
``` text
qa / realtime_qa / note / context_summary
qa / realtime_qa / note / unknown / context_summary
-> answered 处理结果
-> 不落 ai_drafts,不转换 ,不清空当前有效 BotContext
-> 不进入事项、提醒或通知闭环 ,不清空当前有效 BotContext
```
`context_summary` 也必须保存为一条 `SecretaryMessage(intent_type=context_summary)` ,便于调试页回看“老板什么时候要求回顾、系统回了什么”。
@@ -500,17 +516,17 @@ qa / realtime_qa / note / context_summary
JSON 非法 / schema 校验失败
-> 不创建可确认草稿
-> 可选创建 FAILED 草稿仅用于调试
-> 可选创建 parse_failed 草稿仅用于调试;如果无法创建最小草稿,failure_records.target_type 使用 model_call_log
-> FailureRecord(ai_parse_failed)
```
`FAILED ` 草稿不能确认、不能转换为任务/提醒、不能发送通知,只能用于调试追踪。
`parse_failed ` 草稿不能确认、不能转换为任务/提醒、不能发送通知,只能用于调试追踪。
取消流转:
``` text
PENDING_CONFIRM
-> CANCELLED
pending_confirmation
-> cancelled
-> 清空 BotContext
awaiting_more_info 且还没有 ai_drafts
@@ -518,7 +534,7 @@ awaiting_more_info 且还没有 ai_drafts
-> 记录 OperationLog(cancel_context)
```
`NEED_MANAGER_CONFIRM ` 阶段如需取消或退回,归程经理确认模块或任务模块处理;01 只负责展示状态 和记录操作,不再把它当作可补充草稿处理。
复杂事项壳 `pending_manager_confirm ` 阶段如需取消或退回,归程经理确认模块或任务模块处理;01 只负责展示草稿来源 和记录操作,不再把它当作可补充草稿处理。
## 9. 失败和日志
@@ -756,7 +772,7 @@ awaiting_more_info 且还没有 ai_drafts
- 返回 `reply_type=error` 。
- `answer=暂时没处理好,请稍后再试。`
- `failure.type=ai_parse_failed` 。
- 如落 `FAILED ` 草稿,仅用于调试,不能确认或转换。
- 如落 `parse_failed ` 草稿,仅用于调试,不能确认或转换。
### 10.15 低置信度追问
@@ -776,7 +792,7 @@ awaiting_more_info 且还没有 ai_drafts
### 10.16 已发布后修改
前置:上一条草稿已经 `CONVERTED ` , `BotContext` 已清空。
前置:上一条草稿已经 `converted ` , `BotContext` 已清空。
输入:
@@ -864,10 +880,10 @@ awaiting_more_info 且还没有 ai_drafts
期望:
- 老板确认后草稿进入 `NEED_MANAGER_CONFIRM ` 。
- 老板确认后草稿进入 `confirmed ` 。
- 清空老板侧 `BotContext` 。
- 不直接调用 `T askAdapter` 转换任务 。
- 程经理确认后草稿 进入 `CONFIRMED` ,再转换为任务并进入 `CONVERTED ` 。
- 创建 `t asks.status=pending_manager_confirm` 的事项壳,不直接通知最终接收人 。
- 程经理确认后,事项壳 进入 `pending_notify` 并通知接收人;草稿在事项壳创建成功后进入 `converted ` 。
## 11. Review 重点
@@ -880,7 +896,7 @@ awaiting_more_info 且还没有 ai_drafts
- 是否低置信度时追问老板,而不是默认修改当前草稿。
- 是否 `ai_drafts.status` 和非草稿处理状态已经拆清,`need_more_info/answered` 不误落草稿表。
- 是否所有 AI 输出都做 JSON 校验。
- 是否 `qa/realtime_qa/note/need_more_info/unsupported` 没有误生成草稿 。
- 是否 `qa/realtime_qa/note/need_more_info/unknown/ unsupported` 没有误进入事项、提醒或通知闭环 。
- 是否普通任务不强制时间。
- 是否提醒缺时间会追问。
- 是否 AI 只生成草稿,不直接执行。
@@ -907,8 +923,8 @@ awaiting_more_info 且还没有 ai_drafts
- 是否 `secretary_messages` 只追加、`bot_contexts` 可覆盖、`bot_context_snapshot` 不作为最新状态。
- 是否 PostgreSQL 作为唯一事实源,AI 记忆表不替代正式草稿、任务、提醒、通知和反馈表状态。
- 是否 PostgreSQL AI 记忆读写异常时会降级并写 `FailureRecord(memory_store_failed)` 或应用日志/告警。
- 是否草稿 `CONFIRMED / CONVERTED / CANCELLED ` 后立即清空上下文,后续修改不再直接改原草稿。
- 是否 `manager_confirm_required` 走 `NEED_MANAGER_CONFIRM -> 程经理确认 -> CONFIRMED -> CONVERTED ` ,不会绕过程经理确认。
- 是否草稿 `confirmed / converted / cancelled / superseded / expired ` 后立即清空或失效 上下文,后续修改不再直接改原草稿。
- 是否 `manager_confirm_required` 走 `confirmed -> 创建 pending_manager_confirm 事项壳 -> converted -> 程经理确认事项壳 -> pending_notify ` ,不会绕过程经理确认。
- 是否转换失败写 `FailureRecord(draft_convert_failed)` ,且不回滚老板确认。
- 是否上下文回顾默认范围为最近 10 条消息、当前待确认草稿和最近 3 条已确认/已转换草稿。
- 是否 `/api/feishu/callback` 的验签、去重和鉴权没有写进本模块。