"""Wave 2:客户 Agent prompt 常量与关键词快路由纯函数测试(不依赖 DB/LLM)。""" from __future__ import annotations import pytest from app.service.customer_prompts import ( DATA_QUERY_INTENTS, INTENT_SYSTEM, PROFILE_EXTRACT_SYSTEM, REJECT_BY_KIND, VALID_INTENTS, keyword_route, ) def test_intent_constants(): assert len(VALID_INTENTS) == 13 assert len(DATA_QUERY_INTENTS) == 5 # 数据查询意图均在合法集内 assert DATA_QUERY_INTENTS <= VALID_INTENTS # 意图分类 prompt 覆盖标签 for intent in VALID_INTENTS: assert intent in INTENT_SYSTEM def test_profile_prompt_delegates_to_slots(): """抽槽 prompt 由槽位表派生,包含高敏规则。""" assert "basic.age_band" in PROFILE_EXTRACT_SYSTEM assert "threshold_pref_summary" in PROFILE_EXTRACT_SYSTEM assert "高敏感" in PROFILE_EXTRACT_SYSTEM def test_reject_reply_kinds(): assert set(REJECT_BY_KIND) == {"advice", "predict", "compare", "realtime"} for text in REJECT_BY_KIND.values(): assert "游客" not in text # 客户视角话术不得出现"游客" @pytest.mark.parametrize( "message,expected_intent", [ ("我的持仓怎么样", "holding_query"), ("我买了什么基金", "holding_query"), ("最近亏了多少", "holding_query"), ("最近的交易记录", "transaction_query"), ("我上个月申购了啥", "transaction_query"), ("我的风评是什么", "risk_assessment_query"), ("风险测评过期了吗", "risk_assessment_query"), ("我能买R3产品吗", "suitability_check"), ("这个基金适合我买吗", "suitability_check"), ], ) def test_keyword_route_data_queries(message, expected_intent): result = keyword_route(message) assert result is not None intent, reply = result assert intent == expected_intent assert reply == "" @pytest.mark.parametrize( "message,expected", [ ("转人工", ("transfer_human", "")), ("我要投诉", ("transfer_human", "")), ("推荐个稳赚的基金", ("reject", "advice")), ("建议买什么好", ("reject", "advice")), ("这个基金明天会涨吗", ("reject", "predict")), ("和其他平台比哪个好", ("reject", "compare")), ("现在实时净值多少", ("reject", "realtime")), ("我能买什么产品", ("suitability_check", "")), ("005827的净值是多少", ("nav_query", "")), ], ) def test_keyword_route_transfer_and_reject(message, expected): assert keyword_route(message) == expected def test_keyword_route_reject_priority_over_suitability(): """"R3会涨吗"含预测关键词,应 reject 而非适当性查询。""" intent, kind = keyword_route("R3产品还会涨吗") assert intent == "reject" assert kind == "predict" def test_keyword_route_suitability_vs_advice(): """"能买"是适当性查询,"推荐买"是投顾拒绝。""" assert keyword_route("R3我能买吗")[0] == "suitability_check" assert keyword_route("推荐我买R3")[0] == "reject" def test_keyword_route_no_hit(): assert keyword_route("今天天气不错") is None assert keyword_route("") is None