-
Notifications
You must be signed in to change notification settings - Fork 6
Architecture interface design(draft)
| 原则 | 设计要求 |
|---|---|
| 用户输入只有一个主入口 | 文本、图片、音频最终都进入同一条 HTTP 输入提交链路 |
| 母 AI 是业务核心 | 母 AI 负责理解、参数补全、上下文装配、子 Agent 调用和确认落盘编排 |
| 子 Agent 不直接读写数据库 | 子 Agent 只消费母 AI 已装配好的上下文,返回结构化候选或文本结果 |
| 写入必须用户确认 | AI 对话写入与手动表单 CRUD 都必须先生成候选,再确认后落盘 |
| 数据模块只保存事实 | 全局数据模块只负责查询、校验、确认后写入,不做 AI 判断 |
| 前端只承载交互 | 前端负责输入、展示、候选选择和确认动作,不承载复杂业务判断 |
| 前端接口必须鉴权 | 除登录、注册外,所有暴露给前端的 HTTP / WS 接口都必须携带 JWT |
| 系统审计模块暂不实现 | MVP 暂不设计 agent_run_records、audit_events 相关接口和数据库表 |
消息级追踪,不引入 turn_id
|
使用 client_message_id、reply_to_question_id、source_message_id、trace_id 完成幂等、反问关联和链路追踪 |
| 模块类型 | 标准模块名 | 本次接口合并处理 |
|---|---|---|
| AI 编排模块 | 母 AI 编排模块 | 合并感知层和执行层,内部划分为“输入理解阶段”和“执行编排阶段” |
| AI 编排模块 | 反问机制 | 归入母 AI 编排模块内部函数,不单独作为独立服务 |
| 子 Agent | 日程待办 Agent | 提供事项 CRUD 候选生成,不直接落盘 |
| 子 Agent | 反馈 Agent | 提供反馈目标定位和反馈结构化候选,不直接落盘 |
| 子 Agent | 重排 Agent | 提供重排方案生成,不直接应用 |
| 子 Agent | 复盘 Agent | 提供文本复盘结果,默认不写数据库 |
| 子 Agent | 长任务拆分 Agent | 提供宏观规划文本和近期子任务候选,不直接创建正式子任务 |
| 公共基础模块 | 全局数据模块 | 提供事实查询、校验、确认后写入 |
| 公共基础模块 | LLM 管理模块 | 提供结构化模型调用、提示词渲染和模型切换 |
| 公共基础模块 | 系统日志模块 | MVP 暂不实现数据库和接口 |
| 公共基础模块 | 对象存储 | 提供图片、音频上传和 source_url
|
| 公共基础模块 | OCR 识别模块 | 根据 source_url 输出 OCR 文本 |
| 公共基础模块 | ASR 语音识别模块 | 根据 source_url 输出 ASR 文本 |
| 公共基础模块 | 用户账号模块 | 提供注册、登录、当前用户识别和业务用户 ID |
| 公共基础模块 | 全局用户画像管理模块 | 提供全局画像查询和更新 |
| 公共基础模块 | 任务级画像管理模块 | 提供长任务维度画像查询和创建落盘 |
| 公共基础模块 | 弹窗确认机制 | 前端交互能力,后端只接收确认结果 |
| 公共基础模块 | 基础业务模块 | 提供今日事项、长目标、个人主页等基础页面数据 |
| 前端模块 | 消息推送模块 | 前端实现,不进入主 Agent 函数调用链 |
| 前端模块 | 前端交互与展示模块 | 调用 API、建立 WS、展示结果和确认卡片 |
合并后,母 AI 编排模块只有一个模块,不再把“感知层”和“执行层”作为外部并列模块。
内部阶段如下:
| 阶段 | 职责 | 输入 | 输出 | 禁止行为 |
|---|---|---|---|---|
| 输入理解阶段 | 接收用户输入提交、归一化文本、读取最近 20 条对话、识别意图、解析参数、触发反问 | ConversationInputRequest |
PerceptionDecision 或 ClarificationRequest
|
不查询业务候选事项,不调用子 Agent,不写业务事实 |
| 执行编排阶段 | 校验结构化决策、查询必要事实、指代消解、调用目标子 Agent、处理返回、创建确认请求 | ExecutionLayerInput |
MainAgentEvent |
不重新识别意图,不重新补参,不绕过确认写业务事实 |
感知层和执行层的唯一交接对象是:
class ExecutionLayerInput(BaseModel):
target_agent_name: AgentName
target_function_name: str
parsed_params: dict[str, Any]
time_range: TimeRange
raw_input: str
source_message_id: UUID
recent_messages: list[ConversationMessageDTO]
trace_id: str | None = None| 场景 | 处理规则 | 输出 |
|---|---|---|
| 普通任务参数完整 | 根据子 Agent 能力表识别 target_agent_name、target_function_name,解析参数并抽取顶层 time_range
|
ExecutionLayerInput |
| 普通任务参数缺失 | 不进入执行编排阶段,先生成反问 | dialogue.clarification |
| 用户回答反问 | 通过 reply_to_question_id 恢复上一轮问题;如果回答无效,继续反问;如果无法关联,退化为新的普通输入 |
dialogue.decision 或 dialogue.clarification
|
| 长任务拆分 | 命中长任务拆分后先检查最近 20 条对话是否已有可复用问答;没有则一次性生成本次拆分所需问题 |
dialogue.clarification(mode=batch) 或 ExecutionLayerInput
|
| 场景 | 处理规则 | 输出 |
|---|---|---|
| 创建类函数 | 不需要定位已有事项,可直接装配上下文并调用子 Agent | AgentResponseEnvelope |
| 更新 / 删除 / 反馈类函数 | 先按 time_range 和结构化参数粗筛数据库候选,再做范围内指代消解 |
single / range / ambiguous / not_found
|
| 候选唯一 | 直接装配子 Agent 入参 | SubAgentInputBase |
| 候选不唯一 | 通过 WS 返回候选选择,不调用子 Agent | selection.required |
| 母 AI 处理结果需写入 | 创建 write_requests,前端确认后再落盘 |
write.confirmation_required |
所有 WS 消息统一使用同一信封,WS 仅承载结果推送、状态通知和少量交互控制消息。所有业务字段和关联字段全部放入 payload。
class WsEnvelope(BaseModel):
type: str
timestamp: datetime
payload: dict[str, Any]字段说明:
| 字段 | 用途 | 生成方 |
|---|---|---|
type |
消息类型,决定进入哪条流程 | 前端或后端 |
timestamp |
消息产生时间 | 消息发送方 |
payload |
当前消息的业务数据与关联字段 | 消息发送方 |
| 类型 | 方向 | 所属阶段 | 说明 |
|---|---|---|---|
dialogue.clarification |
后端 -> 前端 | 输入理解阶段 | 参数不足、答非所问或长任务拆分需要补充信息 |
dialogue.decision |
后端 -> 前端 | 输入理解阶段 | 母 AI 已识别出目标子 Agent、函数和参数 |
execution.processing |
后端 -> 前端 | 执行编排阶段 | 已进入执行编排,正在查询事实或调用子 Agent |
selection.required |
后端 -> 前端 | 执行编排阶段 | 多候选无法唯一定位,需要用户选择 |
selection.submit |
前端 -> 后端 | 执行编排阶段 | 用户提交候选选择 |
selection.cancel |
前端 -> 后端 | 执行编排阶段 | 用户取消候选选择 |
write.confirmation_required |
后端 -> 前端 | 确认阶段 | 有写入候选,需要用户确认 |
write.decide |
前端 -> 后端 | 确认阶段 | 用户确认或拒绝写入 |
write.applied |
后端 -> 前端 | 确认阶段 | 确认写入已完成 |
execution.result |
后端 -> 前端 | 执行编排阶段 | 查询、复盘等无需写入的展示结果 |
dialogue.error |
后端 -> 前端 | 通用 | 输入理解失败 |
execution.error |
后端 -> 前端 | 通用 | 执行编排失败 |
transport.ping / transport.pong
|
双向 | 传输层 | 心跳 |
transport.resume / transport.snapshot
|
双向 | 传输层 | 连接恢复与状态同步 |
InputModality = Literal["text", "image", "audio"]
class ConversationInputPayload(BaseModel):
client_message_id: str
modality: InputModality
raw_content: str | None = None
reply_to_question_id: str | None = None
source_message_id: UUID | None = None
trace_id: str | None = None说明:POST /api/v1/conversation/inputs 使用统一输入提交语义。文本输入提交 raw_content;图片、音频通过 multipart/form-data 提交 file,后端写入对象存储后生成 source_url,再进入母 AI 编排流程。source_url 由服务端生成并写入消息记录,不作为客户端必填入参。
约束:
| 输入类型 | raw_content |
source_url |
处理方式 |
|---|---|---|---|
text |
必填 | 必须为空 | 直接进入意图识别 |
image |
为空 | 必填 | 后端先存对象存储,再调用 OCR |
audio |
为空 | 必填 | 后端先存对象存储,再调用 ASR |
约束:
| 字段 | 约束 |
|---|---|
client_message_id |
必填,用于客户端幂等 |
reply_to_question_id |
仅在回答反问时可填 |
source_message_id |
仅在恢复、继续或执行链路中可填 |
trace_id |
可空,由后端链路注入 |
落库映射:
| 输入提交字段 |
conversation_messages.metadata 对应字段 |
|---|---|
client_message_id |
client_message_id |
reply_to_question_id |
reply_to_question_id |
trace_id |
trace_id |
target_agent_name / target_function_name
|
同名字段 |
parsed_params / time_range
|
同名字段 |
说明:source_message_id 不进入 metadata;它只作为当前消息主键 conversation_messages.id 的结果引用,或者作为主流程链路中的外部引用字段单独消费,避免和追问状态重复表达。
InputModality = Literal["text", "image", "audio"]
AgentName = Literal[
"schedule_todo_agent",
"feedback_agent",
"replan_agent",
"review_agent",
"long_task_split_agent",
]
AgentDisplayName = Literal[
"日程待办 Agent",
"反馈 Agent",
"重排 Agent",
"复盘 Agent",
"长任务拆分 Agent",
]
说明:程序内部统一使用 `AgentName` 作为分发和提示词映射键,前端展示和文档说明可使用 `AgentDisplayName`。
class TimeRange(BaseModel):
start_at: datetime
end_at: datetime
source: Literal["user_explicit", "agent_inferred", "system_default"]
class ConversationMessageDTO(BaseModel):
id: UUID
user_id: UUID
message_index: int
role: Literal["user", "assistant", "system", "tool"]
modality: InputModality | None
raw_content: str
source_url: str | None
metadata: "ConversationMessageMetadata"
created_at: datetime
class ConversationInputAccepted(BaseModel):
source_message_id: UUID
client_message_id: str
source_url: str | None = None
status: Literal["accepted"]
class ConversationMessageMetadata(BaseModel):
schema_version: int = 1
message_kind: Literal[
"input",
"clarification_question",
"clarification_answer",
"decision",
"execution_processing",
"selection_required",
"selection_submit",
"selection_cancel",
"execution_result",
"confirmation_request",
"confirmation_decision",
"system_notice",
"error",
]
client_message_id: str | None = None
trace_id: str | None = None
question_id: UUID | None = None
question_status: Literal["open", "answered", "expired"] | None = None
question_type: Literal["normal", "long_task_split", "disambiguation", "confirmation"] | None = None
expires_at: datetime | None = None
reply_to_question_id: UUID | None = None
target_agent_name: AgentName | None = None
target_function_name: str | None = None
missing_fields: list[str] = Field(default_factory=list)
parsed_params: dict[str, Any] = Field(default_factory=dict)
time_range: TimeRange | None = None
write_request_id: UUID | None = None
decision: Literal["confirmed", "rejected"] | None = None
class TaskItemDTO(BaseModel):
id: UUID
user_id: UUID
long_goal_id: UUID | None = None
item_type: Literal["schedule", "todo", "subtask"]
title: str
description: str | None = None
start_at: datetime | None = None
end_at: datetime | None = None
due_at: datetime | None = None
status: Literal["planned", "in_progress", "completed", "cancelled", "deferred"]
version: int
class LongGoalDTO(BaseModel):
id: UUID
user_id: UUID
title: str
description: str | None = None
plan_overview: str | None = None
start_at: datetime | None = None
deadline_at: datetime | None = None
status: Literal["active", "completed", "cancelled"]
version: int
class FeedbackDTO(BaseModel):
id: UUID
user_id: UUID
task_item_id: UUID
feedback_status: Literal["completed", "not_completed", "partially_completed", "deferred", "cancelled"]
normalized_feedback: str
duration_minutes: int | None = None
occurred_at: datetime
class TaskProfileSnapshot(BaseModel):
id: UUID
user_id: UUID
long_goal_id: UUID
profile_summary: str
source_message_id: UUID
version: int
class GoalSplitCandidate(BaseModel):
plan_overview: str
task_profile_summary: str
subtasks: list[dict[str, Any]] = Field(default_factory=list)
class WriteDecisionResult(BaseModel):
write_request_id: UUID
status: Literal["confirmed", "rejected", "applied", "expired"]
applied_target_id: UUID | None = None
message: str | None = None
class AgentFunctionDefinition(BaseModel):
agent_name: AgentName
function_name: str
required_fields: list[str]
optional_fields: list[str] = Field(default_factory=list)
description: str
class ClarificationQuestion(BaseModel):
question_id: str
field_name: str
question_text: str
options: list[dict[str, str]] = Field(default_factory=list)
class ClarificationRequest(BaseModel):
reason: Literal["missing_required_params", "invalid_answer", "long_task_split_questions", "ambiguous_reference"]
mode: Literal["single", "batch"]
questions: list[ClarificationQuestion]
original_agent_name: AgentName | None
original_function_name: str | None
class AgentResponseEnvelope(BaseModel):
agent_name: AgentName
function_name: str
isNeedUser: bool
isDisplayResult: bool
isError: bool
result: dict[str, Any] | str | list[Any]
error_message: str | None = None
class PerceptionDecision(BaseModel):
target_agent_name: AgentName
target_function_name: str
parsed_params: dict[str, Any]
time_range: TimeRange
missing_fields: list[str] = Field(default_factory=list)
raw_input: str
source_message_id: UUID
recent_messages: list[ConversationMessageDTO]
trace_id: str | None = None
class MainAgentEvent(BaseModel):
event_type: Literal[
"dialogue.decision",
"dialogue.clarification",
"execution.processing",
"selection.required",
"write.confirmation_required",
"write.applied",
"execution.result",
"dialogue.error",
"execution.error",
]
source_message_id: UUID | None = None
trace_id: str | None = None
payload: dict[str, Any]
class SubAgentInputBase(BaseModel):
user_id: UUID
raw_input: str
time_range: TimeRange
recent_messages: list[ConversationMessageDTO]
parsed_params: dict[str, Any]
candidate_items: list[dict[str, Any]] = Field(default_factory=list)
class ScopeResolutionResult(BaseModel):
decision: Literal["single", "range", "ambiguous", "not_found"]
resolved_item_ids: list[UUID] = Field(default_factory=list)
resolved_item_id: UUID | None = None
question_text: str | None = None| API 名称 | 方法与路径 | 调用方 | 承接模块 | 入参 | 出参 | JWT 认证 | 是否写入 | 说明 |
|---|---|---|---|---|---|---|---|---|
| 注册用户 | POST /api/v1/auth/register |
前端交互与展示模块 | 用户账号模块 |
email、password、display_name
|
user_id、business_user_id、access_token
|
否 | 是 | 创建用户账号,不进入母 AI |
| 登录用户 | POST /api/v1/auth/login |
前端交互与展示模块 | 用户账号模块 |
email、password
|
user_id、business_user_id、access_token
|
否 | 否 | 建立登录态 |
| 获取当前用户 | GET /api/v1/auth/me |
前端交互与展示模块 | 用户账号模块 | 登录凭证 |
user_id、business_user_id、display_name
|
是 | 否 | 页面初始化使用 |
| 提交统一输入 | POST /api/v1/conversation/inputs |
前端交互与展示模块 | 母 AI 编排模块 |
client_message_id、modality=text/image/audio、raw_content?、file?、reply_to_question_id?
|
source_message_id、client_message_id、source_url?、status=accepted
|
是 | 条件写入对话消息 | 文本走 JSON,图片/音频走 multipart/form-data;source_url 进入消息表并回传,便于溯源;HTTP 接收后结束,处理结果通过 WS 推送 |
| 查询会话消息 | GET /api/v1/conversation/messages |
前端交互与展示模块 | 全局数据模块 |
user_id、before_message_id、limit
|
messages: list[ConversationMessageDTO]、has_more
|
是 | 否 | 用于聊天页历史展示 |
| 恢复会话快照 | GET /api/v1/conversation/snapshot |
前端交互与展示模块 | 母 AI 编排模块 |
user_id、last_seen_message_id
|
recent_messages、pending_clarification、last_event
|
是 | 否 | 页面初始化 / 刷新时的静态快照恢复;只负责首屏重建当前可见状态,不补发断线期间的流式事件 |
| 查询时间顺序事项 | GET /api/v1/items/timeline |
前端交互与展示模块 | 基础业务模块 |
user_id、start_at、end_at、item_type?
|
items: list[TaskItemDTO] |
是 | 否 | 时间顺序 Tab 展示 |
| 查询长目标列表 | GET /api/v1/long-goals |
前端交互与展示模块 | 基础业务模块 |
user_id、status?
|
goals: list[LongGoalDTO] |
是 | 否 | 长任务目标管理 Tab |
| 查询长目标详情 | GET /api/v1/long-goals/{goal_id} |
前端交互与展示模块 | 基础业务模块 |
user_id、goal_id
|
goal、subtasks、task_profile
|
是 | 否 | 长目标详情展示 |
| 查询全局用户画像 | GET /api/v1/user/profile |
前端交互与展示模块 | 全局用户画像管理模块 | user_id |
UserProfileDTO |
是 | 否 | 个人主页展示 |
| 创建手动写入请求 | POST /api/v1/write-requests |
前端交互与展示模块 | 全局数据模块 |
action、target_type、target_id?、payload、preview_text
|
write_request_id、payload_hash、confirmation_payload
|
是 | 是,写入请求 | 手动新增、修改、删除事项、长目标或画像时先创建确认门禁 |
| 提交手动确认决定 | POST /api/v1/write-requests/{write_request_id}/decide |
前端交互与展示模块 | 全局数据模块 |
decision、idempotency_key
|
WriteDecisionResult |
是 | 确认时写入 | 手动 CRUD 与 AI 写入走同一套确认和校验流程 |
统一连接地址:
WebSocket /ws/v1/conversation
说明:WS 握手必须携带 JWT;前端建立连接时通过 Authorization: Bearer <token> 或等价握手认证方式完成鉴权,未登录或 token 失效时不允许进入对话链路。
| WS 事件 | 方向 | payload 字段 | JWT 认证 | 是否写入 | 说明 |
|---|---|---|---|---|---|
dialogue.clarification |
后端 -> 前端 |
source_message_id、questions、reason、mode
|
是 | 否 | 返回反问问题或长任务拆分补充问题 |
dialogue.decision |
后端 -> 前端 |
source_message_id、target_agent_name、target_function_name、parsed_params、time_range
|
是 | 否 | 告知前端母 AI 已完成输入理解 |
execution.processing |
后端 -> 前端 |
source_message_id、stage
|
是 | 否 | 告知前端正在进入执行编排 |
selection.required |
后端 -> 前端 |
interaction_id、candidate_items、question_text
|
是 | 否 | 多候选无法唯一定位,需要用户选择 |
selection.submit |
前端 -> 后端 |
interaction_id、selected_candidate_ids
|
是 | 否 | 用户从候选对象中选择 |
selection.cancel |
前端 -> 后端 | interaction_id |
是 | 否 | 取消中间选择 |
write.confirmation_required |
后端 -> 前端 |
write_request_id、confirmation_payload
|
是 | 否 | 有写入候选,需要用户确认 |
write.decide |
前端 -> 后端 |
write_request_id、decision=confirmed/rejected、idempotency_key
|
是 | 确认时写入 | 用户确认或拒绝写入 |
write.applied |
后端 -> 前端 |
write_request_id、status、applied_target_id?
|
是 | 否 | 确认写入已完成 |
execution.result |
后端 -> 前端 |
source_message_id、result
|
是 | 否 | 返回无需写入的展示结果 |
dialogue.error |
后端 -> 前端 |
source_message_id?、error_code、message
|
是 | 否 | 输入理解失败 |
execution.error |
后端 -> 前端 |
source_message_id?、error_code、message
|
是 | 否 | 执行编排失败 |
transport.resume |
前端 -> 后端 | last_seen_message_id |
是 | 否 | WS 重连握手;用于续接同一条长连接,并请求补发断线期间遗漏的流式事件 |
transport.snapshot |
后端 -> 前端 |
recent_messages、pending_clarification、last_event
|
是 | 否 | WS 重连成功后返回当前连接态摘要,仅用于本次连接续接,不替代页面首屏快照 |
说明:client_message_id、reply_to_question_id、source_message_id、trace_id 统一放在 payload 中,不再拆到顶层字段;初始文本和文件输入不通过 WS 发送,统一走 POST /api/v1/conversation/inputs。
恢复边界说明:
| 场景 | 使用接口 | 作用 |
|---|---|---|
| 页面首次打开 / 刷新后恢复界面 | GET /api/v1/conversation/snapshot |
拉取持久化静态快照,重建聊天页、反问卡片和待确认状态 |
| 已建立 WS 连接后发生断线并重连 |
transport.resume + transport.snapshot
|
续接长连接,补发断线期间遗漏的实时事件和当前连接态 |
| 只看历史消息列表 | GET /api/v1/conversation/messages |
仅分页加载消息,不恢复交互态 |
补充说明:conversation/snapshot 负责“页面状态恢复”,基于数据库中的持久化状态生成;transport.resume / transport.snapshot 负责“连接状态恢复”,只处理当前 WS 连接的续接与流式事件补发。前者不替代后者,后者也不承担首屏重建。
| 函数名称 | 调用方 | 入参 | 出参 | 依赖模块 | 是否写入 | 说明 |
|---|---|---|---|---|---|---|
| 处理统一输入提交 | HTTP 输入接口 |
ConversationInputPayload、file?
|
ConversationInputAccepted |
对象存储、OCR 识别模块、ASR 语音识别模块、全局数据模块、LLM 管理模块 | 是,对话消息 | 统一接收文本、图片、音频和反问回复;归一化输入、保存消息、读取最近 20 条对话、识别意图、解析参数 |
| 生成反问请求 | 母 AI 编排模块 |
missing_fields、raw_input、recent_messages、target_agent_name、target_function_name
|
ClarificationRequest |
LLM 管理模块 | 否 | 参数缺失或答非所问时返回追问 |
| 输出执行层输入 | 母 AI 编排模块 |
target_agent_name、target_function_name、parsed_params、time_range、raw_input、source_message_id、recent_messages
|
ExecutionLayerInput |
无 | 否 | 感知阶段到执行阶段的唯一交接对象 |
| 执行主编排流程 | 母 AI 编排模块 | ExecutionLayerInput |
MainAgentEvent |
全局数据模块、目标子 Agent、LLM 管理模块 | 条件写入 | 查询事实、指代消解、调用子 Agent、接收处理结果、创建确认请求、处理返回 |
| 执行范围内指代消解 | 母 AI 编排模块 |
raw_input、candidate_items、time_range、recent_messages
|
ScopeResolutionResult |
LLM 管理模块 | 否 | 只在候选事实范围内判断 single、range、ambiguous、not_found
|
| 调用目标子 Agent | 母 AI 编排模块 |
target_agent_name、target_function_name、SubAgentInputBase
|
AgentResponseEnvelope |
目标子 Agent | 否 | 程序按注册表确定性分发;子 Agent 只做数据处理,不直接查库或写库 |
| 创建待确认写入请求 | 母 AI 编排模块 |
source_message_id、action、target_type、target_id?、payload、preview_text
|
write_request_id、confirmation_payload
|
全局数据模块 | 是,写入请求 | 母 AI 执行层基于处理结果生成确认门禁 |
| 处理写入确认决定 | WS 网关 |
write_request_id、decision、idempotency_key
|
WriteDecisionResult |
全局数据模块 | 确认时写入 | 用户确认后由数据模块事务落盘 |
| 模块 | 函数名称 | 调用方 | 入参 | 出参 | 是否写入 | 说明 |
|---|---|---|---|---|---|---|
| 日程待办 Agent | 生成事项操作候选 | 母 AI 编排模块 |
user_id、raw_input、time_range、recent_messages、action=create/update/delete/query、candidate_items?
|
AgentResponseEnvelope(result=item_operation_candidate) |
否 | 基于母 AI 装配好的候选上下文生成日程、待办、子任务基础 CRUD 结果 |
| 反馈 Agent | 生成执行反馈候选 | 母 AI 编排模块 |
user_id、raw_input、time_range、recent_messages、candidate_items
|
AgentResponseEnvelope(result=feedback_candidate) |
否 | 基于母 AI 提供的候选事实定位目标事项并规范化反馈 |
| 重排 Agent | 生成重排方案 | 母 AI 编排模块 |
user_id、raw_input、time_range、recent_messages、future_items、unfinished_feedbacks、user_profile?、task_profile_snapshot?
|
AgentResponseEnvelope(result=replan_candidate) |
否 | 基于母 AI 提供的事实与画像生成方案,不直接应用 |
| 复盘 Agent | 生成复盘报告 | 母 AI 编排模块 |
user_id、raw_input、time_range、recent_messages、review_facts、review_type
|
AgentResponseEnvelope(result=review_text) |
否 | 基于母 AI 提供的事实数据生成文本复盘 |
| 长任务拆分 Agent | 生成长任务拆分候选 | 母 AI 编排模块 |
user_id、raw_input、time_range、recent_messages、user_profile?
|
AgentResponseEnvelope(result=GoalSplitCandidate) |
否 | 输出宏观规划文本、近期子任务候选和任务级画像总结;确认与落盘由母 AI 执行层完成 |
子 Agent 入参基线:
| 子 Agent | 必填参数 | 条件参数 | 说明 |
|---|---|---|---|
| 日程待办 Agent |
user_id、raw_input、time_range、recent_messages、parsed_params.action
|
candidate_items |
create 不需要候选事项;update/delete/query 的候选范围由执行层预先装配 |
| 反馈 Agent |
user_id、raw_input、time_range、recent_messages、candidate_items
|
无 | 反馈目标必须来自执行层提供的候选事实,子 Agent 不查库 |
| 重排 Agent |
user_id、raw_input、time_range、recent_messages、future_items、unfinished_feedbacks
|
user_profile、task_profile_snapshot
|
time_range 用于限定重排影响范围,未来事项由执行层查询并装配;任务级画像只读取已落盘快照 |
| 复盘 Agent |
user_id、raw_input、time_range、recent_messages、review_facts、review_type
|
long_goal_id |
复盘只基于执行层给定事实生成文本,不默认写库 |
| 长任务拆分 Agent |
user_id、raw_input、time_range、recent_messages、user_profile
|
无 | 输出 plan_overview、近期子任务候选和 task_profile_summary;长期宏观规划与任务级画像由执行层确认落盘 |
子 Agent 出参统一使用 AgentResponseEnvelope。长任务拆分 Agent 还必须额外返回 task_profile_summary,用于在创建长目标时与长目标数据一并落盘。子 Agent 不输出数据库动作,不负责创建 write_requests;若其结果会引发写入,是否进入确认门禁由母 AI 执行层判断。
| 模块 | 函数名称 | 调用方 | 入参 | 出参 | 是否写入 | 说明 |
|---|---|---|---|---|---|---|
| 全局数据模块 | 保存对话消息 | 母 AI 编排模块 |
user_id、role、modality、raw_content、source_url、metadata
|
ConversationMessageDTO |
是 | 保存用户输入、系统追问和主要结果消息 |
| 全局数据模块 | 查询最近对话记录 | 母 AI 编排模块 |
user_id、limit=20、before_message_id?
|
list[ConversationMessageDTO] |
否 | 给母 AI 和子 Agent 提供对话连续性 |
| 全局数据模块 | 查询事项列表 | 母 AI 编排模块、基础业务模块 |
user_id、time_range、item_type?、status?
|
list[TaskItemDTO] |
否 | 用于候选定位、重排、复盘和页面展示 |
| 全局数据模块 | 查询长目标及子任务 | 母 AI 编排模块、基础业务模块 |
user_id、long_goal_id
|
LongGoalDTO、subtasks
|
否 | 用于长任务拆分、重排和详情页 |
| 全局数据模块 | 查询反馈记录 | 母 AI 编排模块 |
user_id、time_range、target_item_ids?
|
list[FeedbackDTO] |
否 | 用于重排和复盘 |
| 全局数据模块 | 查询全局用户画像 | 母 AI 编排模块、全局用户画像管理模块 | user_id |
UserProfileDTO |
否 | 用于长任务拆分和重排 |
| 全局数据模块 | 查询任务级画像 | 母 AI 编排模块、任务级画像管理模块 |
user_id、long_goal_id
|
TaskProfileSnapshot? |
否 | 用于重排阶段读取已落盘快照 |
| 全局数据模块 | 创建写入请求 | 母 AI 编排模块 |
source_message_id、action、target_type、payload、preview_text
|
write_request_id、payload_hash
|
是 | 写入确认门禁 |
| 全局数据模块 | 应用已确认写入 | 母 AI 编排模块 |
write_request_id、decision、idempotency_key、confirmed_by
|
WriteDecisionResult |
是 | 校验确认后事务写入业务事实 |
| LLM 管理模块 | 调用结构化模型 | 母 AI 编排模块、子 Agent |
prompt_name、messages、output_schema、model_config?
|
structured_output、trace_id
|
否 | 所有模型调用统一入口 |
| LLM 管理模块 | 渲染子 Agent 能力提示词 | 母 AI 编排模块 | list[AgentFunctionDefinition] |
prompt_fragment |
否 | 程序维护能力表,渲染注入系统提示词 |
| 对象存储 | 上传原始媒体文件 | 母 AI 编排模块 |
user_id、file、file_type=image/audio
|
source_url、object_key
|
是,对象存储 | 不做识别和业务理解 |
| OCR 识别模块 | 识别图片文本 | 母 AI 编排模块 | source_url |
recognized_text、status
|
否 | 图片到文本 |
| ASR 语音识别模块 | 识别语音文本 | 母 AI 编排模块 | source_url |
recognized_text、status
|
否 | 语音到文本 |
| 用户账号模块 | 获取当前用户 | 前端交互与展示模块、母 AI 编排模块 | 登录凭证 |
user_id、business_user_id
|
否 | 鉴权和用户归属 |
| 全局用户画像管理模块 | 更新全局用户画像 | 前端交互与展示模块 |
user_id、画像字段 |
UserProfileDTO |
是 | 用户主动维护全局画像 |
| 任务级画像管理模块 | 查询任务级画像快照 | 母 AI 编排模块、重排 Agent |
user_id、long_goal_id
|
TaskProfileSnapshot |
否 | 任务级画像只在重排时使用,作为提示词输入 |
| 任务级画像管理模块 | 保存任务级画像快照 | 母 AI 编排模块 |
user_id、long_goal_id、source_message_id、profile_summary、version
|
TaskProfileSnapshot |
是 | 长任务拆分确认落盘时,与长目标创建数据同步写入 |
sequenceDiagram
autonumber
participant U as 用户
participant FE as 前端交互与展示模块
participant API as 统一输入提交接口
participant OSS as 对象存储
participant WS as WebSocket
participant MA as 母AI编排模块
participant ASR as ASR语音识别模块
participant OCR as OCR识别模块
participant DATA as 全局数据模块
participant LLM as LLM管理模块
participant SA as 目标子Agent
alt 文本输入
U->>FE: 输入文本
FE->>API: POST /api/v1/conversation/inputs(text)
else 语音输入
U->>FE: 输入语音
FE->>API: POST /api/v1/conversation/inputs(audio)
else 图片输入
U->>FE: 上传图片
FE->>API: POST /api/v1/conversation/inputs(image)
end
API->>MA: 统一输入提交
alt modality=audio
MA->>OSS: 上传音频
OSS-->>MA: source_url
MA->>ASR: 识别语音(source_url)
ASR-->>MA: recognized_text
else modality=image
MA->>OSS: 上传图片
OSS-->>MA: source_url
MA->>OCR: 识别图片(source_url)
OCR-->>MA: recognized_text
else modality=text
MA->>MA: raw_content 作为 normalized_text
end
MA->>DATA: 保存对话消息(normalized_text, source_url)
DATA-->>MA: source_message_id
API-->>FE: HTTP accepted(source_message_id)
MA->>DATA: 查询最近20条对话(user_id)
DATA-->>MA: recent_messages
MA->>LLM: 意图识别 + 参数解析(能力表, normalized_text, recent_messages)
LLM-->>MA: target_agent_name, target_function_name, parsed_params, time_range, missing_fields
alt 长任务拆分且无可复用问答
MA->>LLM: 生成长任务拆分问题
LLM-->>MA: ClarificationRequest(mode=batch)
MA-->>WS: dialogue.clarification
WS-->>FE: 一次性展示拆分问题
else 参数缺失或回答无效
MA->>LLM: 生成反问(missing_fields)
LLM-->>MA: ClarificationRequest
MA-->>WS: dialogue.clarification
WS-->>FE: 展示追问
else 参数完整
MA-->>WS: dialogue.decision
MA-->>WS: execution.processing
MA->>DATA: 按 time_range 查询候选事实
DATA-->>MA: candidate_facts
opt 存在候选歧义
MA->>LLM: 范围内指代消解(candidate_facts)
LLM-->>MA: single / range / ambiguous / not_found
end
alt 仍需用户选择
MA-->>WS: selection.required
WS-->>FE: 展示候选
U->>FE: 选择候选
FE->>WS: selection.submit
WS->>MA: 继续执行编排
else 可调用子Agent
MA->>SA: 调用目标函数(SubAgentInput)
SA-->>MA: AgentResponseEnvelope
alt 仅展示
MA-->>WS: execution.result
WS-->>FE: 展示结果
else 需要写入确认
MA->>DATA: 创建写入请求
DATA-->>MA: write_request_id
MA-->>WS: write.confirmation_required
WS-->>FE: 展示确认卡片
U->>FE: 确认或拒绝
FE->>WS: write.decide
WS->>MA: 处理确认决定
MA->>DATA: 应用已确认写入
DATA-->>MA: WriteDecisionResult
MA-->>WS: write.applied / execution.result
WS-->>FE: 展示最终结果
end
end
end
| 表名 | 用途 | 保留原因 |
|---|---|---|
users |
用户账号 | 登录、用户归属、业务用户唯一 ID |
user_profiles |
全局用户画像 | 长任务拆分和重排需要读取 |
long_goals |
长目标 | 长任务拆分、目标复盘、任务级画像归属 |
task_items |
统一事项表 | 保存日程、待办、长目标子任务;其中只有 subtask 关联长目标 |
conversation_messages |
对话消息 | 保存文本、ASR 文本、OCR 文本和原始媒体 URL |
feedback_records |
执行反馈 | 反馈、重排、复盘的事实来源 |
task_profile_snapshots |
任务级画像 | 长任务拆分时写入的当前快照 |
write_requests |
待确认写入请求 | 所有 AI 写入候选的确认门禁 |
operation_confirmations |
用户确认记录 | 记录用户确认或拒绝 |
| 表名 | 处理方式 | 原因 |
|---|---|---|
agent_run_records |
MVP 暂不实现 | 用户明确系统审计模块先不实现 |
audit_events |
MVP 暂不实现 | 用户明确系统审计模块先不实现 |
task_profile_observations |
暂不保留 | 任务级画像只保留长任务创建时写入的当前快照,减少冗余来源表 |
replan_proposals |
暂不保留 | 重排候选可存入 write_requests.payload,确认后直接更新事项 |
replan_proposal_changes |
暂不保留 | 变更列表作为写入请求 payload 的一部分 |
replan_applications |
暂不保留 | 应用结果由 write_requests 和业务表状态体现 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
business_user_id |
text |
是 | 业务生成的用户唯一 ID |
email |
text |
是 | 登录邮箱,唯一 |
password_hash |
text |
是 | 密码哈希 |
display_name |
text |
否 | 昵称 |
status |
text |
是 |
active / disabled
|
is_deleted |
boolean |
是 | 软删除标记 |
deleted_at |
timestamptz |
否 | 软删除时间 |
created_at |
timestamptz |
是 | 创建时间 |
updated_at |
timestamptz |
是 | 更新时间 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
profile_data |
jsonb |
是 | 全局画像结构化数据 |
is_deleted |
boolean |
是 | 软删除标记 |
created_at / updated_at
|
timestamptz |
是 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
title |
text |
是 | 长目标标题 |
description |
text |
否 | 目标说明 |
plan_overview |
text |
否 | 全周期粗略规划文本 |
start_at |
timestamptz |
否 | 开始时间 |
deadline_at |
timestamptz |
否 | 截止时间 |
status |
text |
是 |
active / completed / cancelled
|
version |
integer |
是 | 乐观锁版本 |
is_deleted |
boolean |
是 | 软删除标记 |
created_at / updated_at / deleted_at
|
timestamptz |
否 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
long_goal_id |
uuid |
否 | 仅 subtask 允许关联长目标;schedule 和 todo 必须为空 |
item_type |
text |
是 |
schedule / todo / subtask
|
title |
text |
是 | 事项标题 |
description |
text |
否 | 描述 |
start_at |
timestamptz |
否 | 开始时间 |
end_at |
timestamptz |
否 | 结束时间 |
due_at |
timestamptz |
否 | 截止时间 |
status |
text |
是 |
planned / in_progress / completed / cancelled / deferred
|
version |
integer |
是 | 乐观锁版本 |
is_deleted |
boolean |
是 | 软删除标记 |
created_at / updated_at / deleted_at
|
timestamptz |
否 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键,作为 source_message_id 使用 |
user_id |
uuid |
是 | 用户 ID |
message_index |
integer |
是 | 单一对话框内递增序号 |
role |
text |
是 |
user / assistant / system / tool
|
modality |
text |
否 |
text / image / audio
|
raw_content |
text |
是 | 文本原文、ASR 文本或 OCR 文本 |
source_url |
text |
否 | 原始媒体 URL |
metadata |
jsonb |
是 | 统一消息元数据,保存消息类型、追问状态、回填关联和执行上下文 |
created_at |
timestamptz |
是 | 创建时间 |
conversation_messages.metadata 采用扁平化固定键结构,不再额外拆表。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
schema_version |
integer |
是 | 元数据版本,MVP 固定为 1
|
message_kind |
text |
是 |
input / clarification_question / clarification_answer / decision / execution_processing / selection_required / selection_submit / selection_cancel / execution_result / confirmation_request / confirmation_decision / system_notice / error
|
client_message_id |
text |
否 | 客户端幂等标识;用户消息必填,系统消息可空 |
trace_id |
text |
否 | 模型调用或链路追踪标识 |
question_id |
uuid |
否 | 追问消息自身 ID;仅 clarification_question 需要 |
question_status |
text |
否 |
open / answered / expired
|
question_type |
text |
否 |
normal / long_task_split / disambiguation / confirmation
|
expires_at |
timestamptz |
否 | 追问过期时间 |
reply_to_question_id |
uuid |
否 | 用户回答所对应的追问消息 ID |
target_agent_name |
text |
否 | 相关子 Agent 名称 |
target_function_name |
text |
否 | 相关子 Agent 函数名 |
missing_fields |
jsonb |
否 | 仍缺失的字段名列表 |
parsed_params |
jsonb |
否 | 已解析出的结构化参数 |
time_range |
jsonb |
否 | 结构化时间范围 |
write_request_id |
uuid |
否 | 写入请求 ID |
decision |
text |
否 |
confirmed / rejected
|
一致性规则:
| 场景 | 规则 |
|---|---|
| 元数据类型来源 |
message_kind 由 WS type 或后端事件类型派生,不能手填成另一个语义 |
| 用户首次输入 |
message_kind=input,client_message_id 必填 |
| 生成反问 |
message_kind=clarification_question,question_id 必填且等于该消息的 conversation_messages.id,question_status=open,expires_at 必填 |
| 用户回答反问 |
message_kind=clarification_answer,reply_to_question_id 必填且必须指向一条 question_status=open 的 clarification_question
|
| 反问被消费 | 服务端将原 clarification_question.question_status 更新为 answered
|
| 反问过期 | 服务端将原 clarification_question.question_status 更新为 expired
|
| 执行层结果 |
message_kind=decision / execution_result / confirmation_request / confirmation_decision 之一,按结果填充对应字段 |
示例:
{
"schema_version": 1,
"message_kind": "clarification_question",
"client_message_id": "c_001",
"question_id": "b7f0c1d8-8c7a-4a75-9f63-9d2b8be6b2b1",
"question_status": "open",
"question_type": "long_task_split",
"expires_at": "2026-07-23T18:00:00+08:00",
"target_agent_name": "long_task_split_agent",
"target_function_name": "生成长任务拆分候选",
"missing_fields": ["deadline_at", "duration_minutes"]
}{
"schema_version": 1,
"message_kind": "clarification_answer",
"client_message_id": "c_002",
"reply_to_question_id": "b7f0c1d8-8c7a-4a75-9f63-9d2b8be6b2b1",
"parsed_params": {
"deadline_at": "2026-08-01T18:00:00+08:00",
"duration_minutes": 120
}
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
task_item_id |
uuid |
是 | 反馈目标事项 |
source_message_id |
uuid |
否 | 来源对话消息 |
feedback_status |
text |
是 |
completed / not_completed / partially_completed / deferred / cancelled
|
normalized_feedback |
text |
是 | 规范化反馈文本 |
duration_minutes |
integer |
否 | 实际耗时 |
occurred_at |
timestamptz |
是 | 反馈发生时间 |
is_deleted |
boolean |
是 | 软删除标记 |
created_at / updated_at / deleted_at
|
timestamptz |
否 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
long_goal_id |
uuid |
是 | 长目标 ID |
profile_summary |
text |
是 | 长任务拆分 Agent 在创建长任务时输出的任务级画像总结 |
source_message_id |
uuid |
是 | 创建该长目标的来源对话消息 |
version |
integer |
是 | 版本 |
is_deleted |
boolean |
是 | 软删除标记 |
created_at / updated_at / deleted_at
|
timestamptz |
否 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
user_id |
uuid |
是 | 用户 ID |
source_message_id |
uuid |
否 | 来源消息 |
action |
text |
是 |
create / update / delete / feedback / replan / goal_split
|
target_type |
text |
否 |
task_item / long_goal / feedback / profile
|
target_id |
uuid |
否 | 目标对象 ID |
payload |
jsonb |
是 | 待确认写入载荷 |
payload_hash |
text |
是 | 防止前端篡改载荷 |
status |
text |
是 |
pending / confirmed / rejected / applied / expired
|
expires_at |
timestamptz |
否 | 过期时间 |
created_at / updated_at
|
timestamptz |
是 | 时间字段 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
uuid |
是 | 主键 |
write_request_id |
uuid |
是 | 写入请求 ID |
user_id |
uuid |
是 | 用户 ID |
decision |
text |
是 |
confirmed / rejected
|
idempotency_key |
text |
是 | 确认事件幂等键 |
created_at |
timestamptz |
是 | 确认时间 |