feat(steward): 拦截业务无关输入返回 off_topic 计划
- schemas/steward.py:StewardPlanResponse 新增 suggested_prompts 字段 - steward_planner.py:新增 STEWARD_BUSINESS_SIGNAL_KEYWORDS 与 _is_business_irrelevant_input 守卫,在 build_plan 入口前置; 新增 _build_off_topic_plan 构造 plan_status=off_topic 的引导计划 - steward_intent_agent.py:system prompt 追加业务无关约束 - test_steward_planner.py:覆盖 123/你好/纯标点走 off_topic, 并验证正常业务输入不受守卫影响
This commit is contained in:
@@ -547,3 +547,69 @@ def test_steward_plan_endpoint_persists_application_and_reimbursement_state() ->
|
||||
assert state["flows"]["travel_reimbursement"]["fields"]["time_range"] == "2026-06-03"
|
||||
assert state["flows"]["travel_reimbursement"]["fields"]["expense_type"] == "transport"
|
||||
assert all("invented_field" not in flow["fields"] for flow in state["flows"].values())
|
||||
|
||||
|
||||
def test_steward_planner_returns_off_topic_for_business_irrelevant_input() -> None:
|
||||
payload = StewardPlanRequest(
|
||||
message="123",
|
||||
client_now_iso="2026-06-04T09:30:00+08:00",
|
||||
)
|
||||
|
||||
result = StewardPlannerService().build_plan(payload)
|
||||
|
||||
assert result.plan_status == "off_topic"
|
||||
assert result.next_action == "none"
|
||||
assert result.tasks == []
|
||||
assert result.attachment_groups == []
|
||||
assert result.confirmation_groups == []
|
||||
assert result.candidate_flows == []
|
||||
assert result.planning_source == "rule_fallback"
|
||||
assert len(result.suggested_prompts) == 3
|
||||
assert result.thinking_events[0].stage == "off_topic"
|
||||
|
||||
|
||||
def test_steward_planner_returns_off_topic_for_pure_greeting() -> None:
|
||||
payload = StewardPlanRequest(
|
||||
message="你好",
|
||||
client_now_iso="2026-06-04T09:30:00+08:00",
|
||||
)
|
||||
|
||||
result = StewardPlannerService().build_plan(payload)
|
||||
|
||||
assert result.plan_status == "off_topic"
|
||||
assert result.next_action == "none"
|
||||
assert result.tasks == []
|
||||
assert result.candidate_flows == []
|
||||
assert result.planning_source == "rule_fallback"
|
||||
assert len(result.suggested_prompts) == 3
|
||||
assert result.thinking_events[0].stage == "off_topic"
|
||||
|
||||
|
||||
def test_steward_planner_returns_off_topic_for_pure_punctuation() -> None:
|
||||
payload = StewardPlanRequest(
|
||||
message="??? !!!",
|
||||
client_now_iso="2026-06-04T09:30:00+08:00",
|
||||
)
|
||||
|
||||
result = StewardPlannerService().build_plan(payload)
|
||||
|
||||
assert result.plan_status == "off_topic"
|
||||
assert result.next_action == "none"
|
||||
assert result.tasks == []
|
||||
assert result.candidate_flows == []
|
||||
assert result.planning_source == "rule_fallback"
|
||||
assert len(result.suggested_prompts) == 3
|
||||
assert result.thinking_events[0].stage == "off_topic"
|
||||
|
||||
|
||||
def test_steward_planner_preserves_normal_business_flow_after_guard() -> None:
|
||||
payload = StewardPlanRequest(
|
||||
message="我要报销昨天的交通费",
|
||||
client_now_iso="2026-06-04T09:30:00+08:00",
|
||||
)
|
||||
|
||||
result = StewardPlannerService().build_plan(payload)
|
||||
|
||||
assert result.plan_status != "off_topic"
|
||||
assert len(result.tasks) >= 1
|
||||
assert [task.task_type for task in result.tasks] == ["reimbursement"]
|
||||
|
||||
Reference in New Issue
Block a user