aps-agent/tests/golden/test_dialog_clarify.py

90 lines
3.5 KiB
Python
Raw Normal View History

# ============================================================
# M-F 黄金测试:多轮澄清槽位机(低置信 → 澄清卡 → 序号回填)
# ============================================================
from __future__ import annotations
import pytest
from server.agent_core import dialog
from server.contracts import AgentReply, IntentResult
from server.state.seed import seed_world
class FakeStore:
def __init__(self):
self.data = seed_world()
self._counters: dict[str, int] = {}
def next_id(self, kind: str) -> int:
self._counters[kind] = self._counters.get(kind, 0) + 1
return self._counters[kind]
def save(self) -> None:
pass
@pytest.fixture(autouse=True)
def _isolate(monkeypatch):
monkeypatch.setenv("APS_DB_DISABLED", "1")
dialog._SESSIONS.clear()
yield
dialog._SESSIONS.clear()
def test_unknown_intent_with_domain_yields_clarify_card():
store = FakeStore()
intent = IntentResult(intent="unknown", params={}, confidence=0.2, source="RULE_FAST")
reply = dialog.post_route(store, "s1", "那个排产的东西弄一下", intent)
assert isinstance(reply, AgentReply)
assert reply.blocks and reply.blocks[0].type == "clarify"
options = reply.blocks[0].props["options"]
assert any(o["intent"] == "schedule.wizard" for o in options)
assert "1." in reply.text
def test_clarify_resolves_by_index():
store = FakeStore()
intent = IntentResult(intent="unknown", params={}, confidence=0.2, source="RULE_FAST")
dialog.post_route(store, "s2", "订单那块看看", intent)
resolved = dialog.pre_route(store, "s2", "第一个")
assert isinstance(resolved, IntentResult)
assert resolved.intent == "order.pool"
assert resolved.confidence == 1.0
# 回填后澄清态清空
assert dialog._SESSIONS["s2"]["clarify"] is None
def test_clarify_resolves_by_label_keyword():
store = FakeStore()
intent = IntentResult(intent="unknown", params={}, confidence=0.3, source="RULE_FAST")
dialog.post_route(store, "s3", "主数据相关", intent)
resolved = dialog.pre_route(store, "s3", "工时维护情况")
assert isinstance(resolved, IntentResult)
assert resolved.intent == "readiness.query"
def test_clarify_gives_up_after_two_rounds():
store = FakeStore()
intent = IntentResult(intent="unknown", params={}, confidence=0.2, source="RULE_FAST")
assert dialog.post_route(store, "s4", "排产啊", intent) is not None # 第 1 轮
assert dialog.pre_route(store, "s4", "听不懂你说啥") is None # 未回填
assert dialog.post_route(store, "s4", "就是那个啥", intent) is not None # 第 2 轮
assert dialog.pre_route(store, "s4", "还是不懂") is None
# 第 3 轮:放弃澄清 → 回兜底
assert dialog.post_route(store, "s4", "嗯", intent) is None
def test_high_confidence_skips_clarification():
store = FakeStore()
intent = IntentResult(intent="flex.schedule", params={}, confidence=0.95, source="RULE_FAST")
assert dialog.post_route(store, "s5", "柔性排产", intent) is None
def test_mid_confidence_triggers_guess_confirm():
store = FakeStore()
intent = IntentResult(intent="flex.capacity", params={}, confidence=0.6, source="LLM")
reply = dialog.post_route(store, "s6", "产能那个看下", intent)
assert isinstance(reply, AgentReply)
# 首选候选 = 识别出的意图本身(猜测+确认)
assert reply.blocks[0].props["options"][0]["intent"] == "flex.capacity"