feat(steward): off_topic 场景细分与引导回复
- 将业务无关输入细分为 greeting / meaningless / off_business 三类场景 - 新增 StewardOffTopicAgent,用 function calling 生成管家语气引导回复 - steward endpoint 与 user_agent_application 串联 off_topic 引导话术 - 补充 planner 与 user agent 的 off_topic 覆盖测试
This commit is contained in:
@@ -86,6 +86,25 @@ APPLICATION_TRANSPORT_KEYWORDS = {
|
||||
"火车": ("火车", "高铁", "动车", "铁路", "列车"),
|
||||
"轮船": ("轮船", "船", "客轮", "邮轮", "坐船"),
|
||||
}
|
||||
APPLICATION_TYPE_DISPLAY_LABELS = {
|
||||
"travel": "差旅费用申请",
|
||||
"travel_application": "差旅费用申请",
|
||||
"expense_application": "费用申请",
|
||||
"application": "费用申请",
|
||||
"transport": "交通费用申请",
|
||||
"transportation": "交通费用申请",
|
||||
"traffic": "交通费用申请",
|
||||
"hotel": "住宿费用申请",
|
||||
"accommodation": "住宿费用申请",
|
||||
"meeting": "会务费用申请",
|
||||
"conference": "会务费用申请",
|
||||
"purchase": "采购费用申请",
|
||||
"procurement": "采购费用申请",
|
||||
"training": "培训费用申请",
|
||||
"business_entertainment": "业务招待申请",
|
||||
"entertainment": "业务招待申请",
|
||||
"office": "办公费用申请",
|
||||
}
|
||||
APPLICATION_REASON_VERBS = (
|
||||
"支撑",
|
||||
"支持",
|
||||
@@ -316,6 +335,7 @@ class UserAgentApplicationMixin:
|
||||
if value:
|
||||
facts[key] = value
|
||||
|
||||
facts["application_type"] = self._normalize_application_type_label(facts.get("application_type", ""))
|
||||
context_json = payload.context_json or {}
|
||||
context_time = self._resolve_application_time_from_context(context_json)
|
||||
if context_time and self._should_prefer_context_application_time(facts.get("time", ""), context_time):
|
||||
@@ -476,7 +496,9 @@ class UserAgentApplicationMixin:
|
||||
|
||||
reason = UserAgentApplicationMixin._cleanup_application_reason_candidate(pick("reason"))
|
||||
return {
|
||||
"application_type": pick("applicationType", "application_type"),
|
||||
"application_type": UserAgentApplicationMixin._normalize_application_type_label(
|
||||
pick("applicationType", "application_type")
|
||||
),
|
||||
"time": pick("time", "timeRange", "time_range"),
|
||||
"location": pick("location"),
|
||||
"reason": reason,
|
||||
@@ -842,11 +864,40 @@ class UserAgentApplicationMixin:
|
||||
|
||||
@staticmethod
|
||||
def _resolve_application_type_from_text(message: str) -> str:
|
||||
return UserAgentApplicationMixin._resolve_application_labeled_value(
|
||||
message,
|
||||
("申请类型", "费用类型"),
|
||||
return UserAgentApplicationMixin._normalize_application_type_label(
|
||||
UserAgentApplicationMixin._resolve_application_labeled_value(
|
||||
message,
|
||||
("申请类型", "费用类型"),
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _normalize_application_type_label(value: object, fallback: str = "") -> str:
|
||||
raw_value = str(value or "").strip()
|
||||
if not raw_value:
|
||||
return str(fallback or "").strip()
|
||||
|
||||
normalized_key = raw_value.lower()
|
||||
if normalized_key in APPLICATION_TYPE_DISPLAY_LABELS:
|
||||
return APPLICATION_TYPE_DISPLAY_LABELS[normalized_key]
|
||||
if re.fullmatch(r"(差旅费|差旅|出差)", raw_value):
|
||||
return "差旅费用申请"
|
||||
if re.fullmatch(r"(交通费|交通)", raw_value):
|
||||
return "交通费用申请"
|
||||
if re.fullmatch(r"(住宿费|住宿|酒店)", raw_value):
|
||||
return "住宿费用申请"
|
||||
if re.fullmatch(r"(会务|会议|会务费)", raw_value):
|
||||
return "会务费用申请"
|
||||
if re.fullmatch(r"(采购|采购费|办公用品)", raw_value):
|
||||
return "采购费用申请"
|
||||
if raw_value.endswith("费用申请") or raw_value.endswith("申请"):
|
||||
return raw_value
|
||||
if raw_value.endswith("费用"):
|
||||
return f"{raw_value}申请"
|
||||
if raw_value.endswith("费"):
|
||||
return f"{raw_value[:-1]}费用申请"
|
||||
return raw_value
|
||||
|
||||
@staticmethod
|
||||
def _resolve_application_missing_slots(payload: UserAgentRequest) -> list[str]:
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user