refactor(backend): update user agent service and tests
- services/user_agent.py: update user agent service - tests/test_orchestrator_service.py: update orchestrator tests
This commit is contained in:
@@ -643,9 +643,9 @@ class UserAgentService:
|
||||
)
|
||||
body_message = self._build_review_body_message(
|
||||
payload,
|
||||
slot_cards=slot_cards,
|
||||
risk_briefs=risk_briefs,
|
||||
can_proceed=can_proceed,
|
||||
draft_payload=draft_payload,
|
||||
missing_slot_labels=[SLOT_LABELS.get(key, key) for key in missing_slot_keys],
|
||||
)
|
||||
|
||||
return UserAgentReviewPayload(
|
||||
@@ -965,19 +965,19 @@ class UserAgentService:
|
||||
draft_payload: UserAgentDraftPayload | None,
|
||||
) -> list[UserAgentReviewAction]:
|
||||
primary_action = UserAgentReviewAction(
|
||||
label="下一步" if can_proceed else "保存草稿",
|
||||
label="继续下一步" if can_proceed else "保存为草稿",
|
||||
action_type="next_step" if can_proceed else "save_draft",
|
||||
description=(
|
||||
"当前识别信息已满足继续流转条件,确认后进入下一步。"
|
||||
"当前识别信息已满足继续处理条件,确认后进入下一步。"
|
||||
if can_proceed
|
||||
else "当前信息仍未补齐,先保存为草稿,后续可继续补充。"
|
||||
else "暂存当前识别结果,后续可以继续补充或修改。"
|
||||
),
|
||||
emphasis="primary",
|
||||
)
|
||||
if len(claim_groups) > 1 and can_proceed:
|
||||
primary_action.description = f"系统建议拆分为 {len(claim_groups)} 张报销单,确认后进入下一步。"
|
||||
primary_action.description = f"系统建议拆分为 {len(claim_groups)} 张报销单,确认后继续下一步。"
|
||||
if draft_payload is not None and draft_payload.claim_no and not can_proceed:
|
||||
primary_action.description = f"会先保存到草稿 {draft_payload.claim_no},缺失信息后续再补。"
|
||||
primary_action.description = f"保存后会生成草稿 {draft_payload.claim_no},后续仍可继续补充。"
|
||||
|
||||
return [
|
||||
UserAgentReviewAction(
|
||||
@@ -1009,20 +1009,23 @@ class UserAgentService:
|
||||
location = slots.get("location")
|
||||
customer = slots.get("customer_name")
|
||||
|
||||
summary = "我先按你当前提供的信息整理出一笔报销。"
|
||||
summary = "我先根据您当前提供的信息整理出一笔报销。"
|
||||
if expense_type and expense_type.value:
|
||||
summary = f"我理解你这次想报销{expense_type.value}。"
|
||||
summary = f"识别到您希望报销一笔“{expense_type.value}”费用。"
|
||||
details: list[str] = []
|
||||
if customer and customer.value:
|
||||
details.append(f"客户名称:{customer.value}")
|
||||
details.append(f"客户为 {customer.value}")
|
||||
if time_range and time_range.value:
|
||||
details.append(f"时间:{time_range.value}")
|
||||
details.append(f"时间为 {time_range.value}")
|
||||
if location and location.value:
|
||||
details.append(f"地点:{location.value}")
|
||||
details.append(f"地点为 {location.value}")
|
||||
if amount and amount.value:
|
||||
details.append(f"金额:{amount.value}")
|
||||
details.append(f"金额为 {amount.value}")
|
||||
reason = slots.get("reason")
|
||||
if reason and reason.value:
|
||||
details.append(f"事由是 {reason.value}")
|
||||
if details:
|
||||
return f"{summary} {';'.join(details)}。"
|
||||
return f"{summary} {','.join(details)}。"
|
||||
return summary
|
||||
|
||||
def _build_review_body_answer(
|
||||
@@ -1048,36 +1051,83 @@ class UserAgentService:
|
||||
if review_action == "save_draft":
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return (
|
||||
f"我已经把本轮识别结果整理好了,右侧可以继续核对。"
|
||||
f"当前先替你保存到草稿 {draft_payload.claim_no},后面把缺的信息补齐就可以继续。"
|
||||
f"已按您当前确认的信息保存为草稿 {draft_payload.claim_no}。"
|
||||
"后续您可以继续补充缺失项,或修改识别结果后再继续提交。"
|
||||
)
|
||||
return "我已经把本轮识别结果整理好了,右侧可以继续核对。当前信息还没补全,我先按你的要求保存为草稿。"
|
||||
return "已按您当前确认的信息保存为草稿。后续您可以继续补充缺失项,或修改识别结果后再继续提交。"
|
||||
if review_action == "next_step":
|
||||
return "我已经把识别到的关键信息整理好了,右侧是本轮识别结果。你确认无误后,可以直接进入下一步。"
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)} "
|
||||
"当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
)
|
||||
if review_action == "edit_review":
|
||||
return "我已经按你修改后的内容重新识别了一遍。右侧是最新结果,下方还有待补信息和注意事项,你继续确认即可。"
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)} "
|
||||
f"{self._build_review_guidance_copy(review_payload, mention_save_draft=True)}"
|
||||
)
|
||||
return review_payload.body_message or None
|
||||
|
||||
def _build_review_body_message(
|
||||
self,
|
||||
payload: UserAgentRequest,
|
||||
*,
|
||||
slot_cards: list[UserAgentReviewSlotCard],
|
||||
risk_briefs: list[UserAgentReviewRiskBrief],
|
||||
can_proceed: bool,
|
||||
draft_payload: UserAgentDraftPayload | None,
|
||||
missing_slot_labels: list[str],
|
||||
) -> str:
|
||||
if can_proceed:
|
||||
return "我已经把识别结果整理在右侧了。当前关键信息基本齐全,你核对无误后可以直接点“下一步”继续处理。"
|
||||
missing_hint = "、".join(missing_slot_labels[:4])
|
||||
missing_message = f"当前还缺少 {missing_hint}。" if missing_hint else "当前仍有信息待补充。"
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return (
|
||||
f"我先根据你当前提供的信息完成了初步识别,右侧是识别结果。{missing_message}"
|
||||
f"如果现在还拿不全,也可以先保存到草稿 {draft_payload.claim_no},后面再补。"
|
||||
)
|
||||
review_payload = UserAgentReviewPayload(
|
||||
intent_summary="",
|
||||
body_message="",
|
||||
scenario=payload.ontology.scenario,
|
||||
intent=payload.ontology.intent,
|
||||
can_proceed=can_proceed,
|
||||
missing_slots=self._resolve_review_missing_slot_labels(slot_cards),
|
||||
risk_briefs=risk_briefs,
|
||||
slot_cards=slot_cards,
|
||||
document_cards=[],
|
||||
claim_groups=[],
|
||||
confirmation_actions=[],
|
||||
edit_fields=[],
|
||||
)
|
||||
return (
|
||||
f"我先根据你当前提供的信息完成了初步识别,右侧是识别结果。{missing_message}"
|
||||
"你可以继续补充;如果暂时不方便提供,也可以先保存草稿。"
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=slot_cards, claim_groups=[])} "
|
||||
f"{self._build_review_guidance_copy(review_payload, mention_save_draft=not can_proceed)}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_review_missing_slot_labels(
|
||||
slot_cards: list[UserAgentReviewSlotCard],
|
||||
) -> list[str]:
|
||||
return [item.label for item in slot_cards if item.status == "missing"]
|
||||
|
||||
@staticmethod
|
||||
def _build_review_guidance_copy(
|
||||
review_payload: UserAgentReviewPayload,
|
||||
*,
|
||||
mention_save_draft: bool,
|
||||
) -> str:
|
||||
missing_count = len(review_payload.missing_slots)
|
||||
reminder_count = len(review_payload.risk_briefs)
|
||||
|
||||
if review_payload.can_proceed:
|
||||
if reminder_count:
|
||||
return (
|
||||
f"当前关键信息已基本齐全,但还有 {reminder_count} 条提醒。"
|
||||
"您可以展开下方卡片查看详情,确认无误后继续下一步。"
|
||||
)
|
||||
return "当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
|
||||
issue_parts: list[str] = []
|
||||
if missing_count:
|
||||
issue_parts.append(f"{missing_count} 项信息待补充")
|
||||
if reminder_count:
|
||||
issue_parts.append(f"{reminder_count} 条提醒")
|
||||
issue_summary = "、".join(issue_parts) if issue_parts else "一些细节还需要进一步确认"
|
||||
|
||||
suffix = ";如果想先暂存,也可以点击下方按钮保存草稿。" if mention_save_draft else "。"
|
||||
return (
|
||||
f"当前还有 {issue_summary}。"
|
||||
f"您可以展开下方卡片查看详情,继续补充或修改{suffix}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -631,9 +631,9 @@ def test_orchestrator_treats_expense_narrative_as_draft_instead_of_ar_query() ->
|
||||
assert payload["trace_summary"]["intent"] == "draft"
|
||||
assert payload["trace_summary"]["tool_count"] == 0
|
||||
assert "应收场景数据" not in payload["result"]["message"]
|
||||
assert payload["result"]["message"].startswith("我先根据你当前提供的信息完成了初步识别")
|
||||
assert payload["result"]["message"].startswith("识别到您希望报销一笔“业务招待费”费用")
|
||||
review_payload = payload["result"]["review_payload"]
|
||||
assert review_payload["intent_summary"].startswith("我理解你这次想报销业务招待费。")
|
||||
assert review_payload["intent_summary"].startswith("识别到您希望报销一笔“业务招待费”费用。")
|
||||
assert review_payload["missing_slots"] == ["客户名称", "参与人员", "票据附件"]
|
||||
slot_map = {item["key"]: item for item in review_payload["slot_cards"]}
|
||||
assert slot_map["time_range"]["raw_value"] == "今天"
|
||||
|
||||
Reference in New Issue
Block a user