refactor(server): steward 决策链路改用 LangGraph 编排
- 新增 StewardGraphPlannerService,用 LangGraph 状态图编排意图识别→流程判断→模型/规则分支→兜底,替代原 planner 内线性调用 - 新增 StewardGraphRuntimeService 编排运行时决策与槽位决策;StewardActionContracts/Executor 统一动作合约与执行 - steward_intent_agent/application_fact_resolver/runtime_chat 适配图执行器,config 暴露图相关开关 - pyproject/uv.lock 新增 langgraph 依赖 - 新增 graph_planner/graph_runtime/action_executor 测试,更新 intent_agent/planner/fact_resolver/runtime_chat/reimbursement 测试
This commit is contained in:
@@ -4,11 +4,11 @@ from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
StewardTaskType = Literal["expense_application", "reimbursement"]
|
||||
StewardAssignedAgent = Literal["application_assistant", "reimbursement_assistant"]
|
||||
StewardPlanningSource = Literal["llm_function_call", "rule_fallback"]
|
||||
StewardPlanNextAction = Literal["confirm_flow", "confirm_task", "delegate_task", "none"]
|
||||
StewardRequestedAction = Literal["preview", "save_draft", "submit"]
|
||||
StewardSlotDecisionSource = Literal["llm_function_call", "rule_fallback"]
|
||||
StewardSlotNextAction = Literal["ask_user", "render_preview"]
|
||||
StewardRuntimeDecisionSource = Literal["llm_function_call", "rule_fallback"]
|
||||
@@ -22,6 +22,22 @@ StewardRuntimeNextAction = Literal[
|
||||
"cancel_current_action",
|
||||
"no_op",
|
||||
]
|
||||
StewardActionType = Literal[
|
||||
"detect_intent",
|
||||
"fill_application_fields",
|
||||
"build_application_preview",
|
||||
"fill_reimbursement_fields",
|
||||
"build_reimbursement_preview",
|
||||
"validate_required_fields",
|
||||
"run_duplicate_precheck",
|
||||
"save_application_draft",
|
||||
"submit_application",
|
||||
"link_existing_application",
|
||||
"create_reimbursement_draft",
|
||||
"associate_attachments",
|
||||
]
|
||||
StewardActionStatus = Literal["completed", "planned", "pending_confirmation", "blocked"]
|
||||
StewardActionExecutionStatus = Literal["succeeded", "blocked", "needs_confirmation", "failed"]
|
||||
StewardTaskStatus = Literal[
|
||||
"planned",
|
||||
"needs_confirmation",
|
||||
@@ -58,6 +74,17 @@ class StewardThinkingEvent(BaseModel):
|
||||
status: str = Field(default="completed", description="事件状态。")
|
||||
|
||||
|
||||
class StewardActionStep(BaseModel):
|
||||
step_id: str = Field(description="动作步骤 ID。")
|
||||
action_type: StewardActionType = Field(description="白名单动作类型。")
|
||||
label: str = Field(description="用户可见动作名称。")
|
||||
target_task_id: str = Field(default="", description="关联的小财管家任务 ID。")
|
||||
status: StewardActionStatus = Field(default="planned", description="动作规划状态。")
|
||||
requires_confirmation: bool = Field(default=False, description="执行前是否需要用户确认。")
|
||||
depends_on: list[str] = Field(default_factory=list, description="前置动作步骤 ID。")
|
||||
payload: dict[str, Any] = Field(default_factory=dict, description="动作执行需要的确定性载荷。")
|
||||
|
||||
|
||||
class StewardTask(BaseModel):
|
||||
task_id: str = Field(description="小财管家任务 ID。")
|
||||
task_type: StewardTaskType = Field(description="任务类型。")
|
||||
@@ -66,9 +93,11 @@ class StewardTask(BaseModel):
|
||||
summary: str = Field(description="任务摘要。")
|
||||
status: StewardTaskStatus = Field(default="needs_confirmation", description="任务状态。")
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="识别置信度。")
|
||||
requested_action: StewardRequestedAction = Field(default="preview", description="用户希望执行的动作:预览、保存草稿或提交。")
|
||||
ontology_fields: dict[str, str] = Field(default_factory=dict, description="归一化后的业务本体字段。")
|
||||
missing_fields: list[str] = Field(default_factory=list, description="仍缺失的本体字段。")
|
||||
confirmation_required: bool = Field(default=True, description="执行前是否需要用户确认。")
|
||||
action_steps: list[StewardActionStep] = Field(default_factory=list, description="当前任务的白名单动作步骤。")
|
||||
|
||||
|
||||
class StewardAttachmentGroup(BaseModel):
|
||||
@@ -120,6 +149,7 @@ class StewardPlanResponse(BaseModel):
|
||||
summary: str = Field(description="计划摘要。")
|
||||
thinking_events: list[StewardThinkingEvent] = Field(default_factory=list, description="过程摘要事件。")
|
||||
tasks: list[StewardTask] = Field(default_factory=list, description="拆解后的任务。")
|
||||
action_steps: list[StewardActionStep] = Field(default_factory=list, description="本计划的全量白名单动作步骤。")
|
||||
attachment_groups: list[StewardAttachmentGroup] = Field(default_factory=list, description="附件归集建议。")
|
||||
confirmation_groups: list[StewardConfirmationAction] = Field(default_factory=list, description="等待用户确认的动作。")
|
||||
pending_flow_confirmation: StewardPendingFlowConfirmation = Field(
|
||||
@@ -134,6 +164,30 @@ class StewardPlanResponse(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class StewardActionExecuteRequest(BaseModel):
|
||||
action_type: str = Field(description="待执行的白名单动作类型。未知动作会被 executor 阻断。")
|
||||
message: str = Field(default="", description="触发该动作的用户原始话术。")
|
||||
plan_id: str = Field(default="", description="关联的小财管家计划 ID。")
|
||||
conversation_id: str | None = Field(default=None, description="关联会话 ID。")
|
||||
task: StewardTask | None = Field(default=None, description="动作所属任务快照。")
|
||||
action_step: StewardActionStep | None = Field(default=None, description="规划侧生成的动作步骤快照。")
|
||||
confirmed: bool = Field(default=False, description="用户是否已确认执行该动作。")
|
||||
context_json: dict[str, Any] = Field(default_factory=dict, description="前端或运行时补充上下文。")
|
||||
client_trace_id: str = Field(default="", description="前端幂等或追踪 ID。")
|
||||
|
||||
|
||||
class StewardActionExecuteResponse(BaseModel):
|
||||
action_type: str = Field(description="实际处理的动作类型。")
|
||||
status: StewardActionExecutionStatus = Field(description="动作执行状态。")
|
||||
execution_source: str = Field(default="langgraph_action", description="执行来源或兜底来源。")
|
||||
fallback_used: bool = Field(default=False, description="是否走了规则兜底执行。")
|
||||
requires_confirmation: bool = Field(default=False, description="是否仍需用户确认。")
|
||||
message: str = Field(description="面向用户展示的执行结果。")
|
||||
blocked_reasons: list[str] = Field(default_factory=list, description="阻断原因。")
|
||||
result_payload: dict[str, Any] = Field(default_factory=dict, description="业务服务返回的结构化结果。")
|
||||
trace: list[dict[str, Any]] = Field(default_factory=list, description="动作执行轨迹。")
|
||||
|
||||
|
||||
class StewardSlotOption(BaseModel):
|
||||
label: str = Field(description="用户可见选项文案。")
|
||||
value: str = Field(description="写回本体字段的选项值。")
|
||||
|
||||
Reference in New Issue
Block a user