fix(agent): 하드코딩 '재원부족' 와일드카드 제거
_pick_wildcard 가 실제 선택 와일드카드와 매핑되지 않은 채 '와일드카드를 하나라도 골랐으면' 조건만으로 wild_card_budget(재원부족)을 반환해, 선택하지 않은 재원부족 멘트가 노출되는 오작동이 있었다. - 재원부족 분기 삭제 → 해당 구간은 일반 가격협상으로 폴백. 와일드카드는 앵커<제시가≤앵커*1.02 구간의 1% 인하(wild_card_1pct)만 발동한다. - wildcard_used 마킹을 1% 분기 안으로 이동 — 가격협상으로 돌아갈 때도 마킹하면 이후 라운드의 정당한 1% 카드까지 억제되는 부작용 방지. - test_p7_chat: 와일드카드 발동 단언을 wild_card_1pct 로 교체. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
98df5e2608
commit
c2760c804f
@ -173,20 +173,24 @@ class ChatEngine:
|
|||||||
return "가격협상"
|
return "가격협상"
|
||||||
|
|
||||||
def _pick_wildcard(self, session: ChatSession) -> str:
|
def _pick_wildcard(self, session: ChatSession) -> str:
|
||||||
"""앵커가 살짝 초과 구간에서 인하 압박 카드 선택.
|
"""앵커가에 아주 근접(≤ anchor*1.02)한 구간에서만 1% 인하 요청(wild_card_1pct)으로
|
||||||
- 앵커가에 아주 근접(≤ anchor*1.02): 1% 인하 요청(wild_card_1pct) → 앵커가 이하로 유도.
|
앵커가 이하로 유도한다. 그 외 구간은 일반 가격협상(카드 플레이)으로 돌린다.
|
||||||
- 그 외: 목표 매입가 맞춰달라(wild_card_budget).
|
|
||||||
|
과거 여기서 반환하던 '재원부족'(wild_card_budget) 하드코딩 카드는 제거했다 —
|
||||||
|
견적에서 실제 선택한 와일드카드(중간값 절충·목표가 선제안 등)와 매핑되지 않은 채
|
||||||
|
'와일드카드를 하나라도 골랐으면' 조건만으로 발동해, 선택하지도 않은 재원부족 멘트가
|
||||||
|
노출되는 오작동이 있었다.
|
||||||
"""
|
"""
|
||||||
ctx = session.context
|
ctx = session.context
|
||||||
price = ctx.get("input_price", 0)
|
price = ctx.get("input_price", 0)
|
||||||
anchor = ctx.get("anchor_price", 0)
|
anchor = ctx.get("anchor_price", 0)
|
||||||
ctx["wildcard_used"] = True
|
|
||||||
if anchor > 0 and price <= anchor * 1.02:
|
if anchor > 0 and price <= anchor * 1.02:
|
||||||
|
# 와일드카드는 실제로 노출할 때만 '사용됨'으로 마킹한다 — 가격협상으로 돌아가는
|
||||||
|
# 경우에도 마킹하면 이후 라운드에서 정당한 1% 카드까지 억제된다.
|
||||||
|
ctx["wildcard_used"] = True
|
||||||
ctx["offer_1pct"] = int(round(price * 0.99)) # 1% 인하가
|
ctx["offer_1pct"] = int(round(price * 0.99)) # 1% 인하가
|
||||||
return "wild_card_1pct"
|
return "wild_card_1pct"
|
||||||
if not ctx.get("allow_selected_wildcards", True):
|
return "가격협상"
|
||||||
return "가격협상"
|
|
||||||
return "wild_card_budget"
|
|
||||||
|
|
||||||
# ---- render --------------------------------------------------------
|
# ---- render --------------------------------------------------------
|
||||||
def vars_for(self, session: ChatSession) -> Dict[str, Any]:
|
def vars_for(self, session: ChatSession) -> Dict[str, Any]:
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
1. 전체 대화: 서비스안내→담당자확인→협상품목안내→가격협상→와일드카드→협상완료→협상종료(chat_end).
|
1. 전체 대화: 서비스안내→담당자확인→협상품목안내→가격협상→와일드카드→협상완료→협상종료(chat_end).
|
||||||
2. 가격협상 턴에서 카드 선택 + 학습(card_id, updated_q).
|
2. 가격협상 턴에서 카드 선택 + 학습(card_id, updated_q).
|
||||||
3. 와일드카드 발동(wild_card_budget) + 종료 보상(success).
|
3. 와일드카드 발동(wild_card_1pct) + 종료 보상(success).
|
||||||
4. 브랜드 치환 테넌트별(데모상사 A/B), 클린룸(스크립트에 KT 흔적 없음).
|
4. 브랜드 치환 테넌트별(데모상사 A/B), 클린룸(스크립트에 KT 흔적 없음).
|
||||||
5. 경험로그 적재 + 종료 후 진행 시 에러.
|
5. 경험로그 적재 + 종료 후 진행 시 에러.
|
||||||
6. (HTTP) 헤더로 새 세션 시작 + 한 턴 진행.
|
6. (HTTP) 헤더로 새 세션 시작 + 한 턴 진행.
|
||||||
@ -46,8 +46,9 @@ async def test_full_conversation_reaches_completion(db_engine):
|
|||||||
reset_sessions()
|
reset_sessions()
|
||||||
eng = await _reg().get_engine("ktcommerce")
|
eng = await _reg().get_engine("ktcommerce")
|
||||||
svc = ChatService()
|
svc = ChatService()
|
||||||
# anchor=9900, target=10000(기본). 11000(>10395)→가격협상(카드), 10200(9900~10395)→와일드카드, 9800(≤anchor)→우선협상
|
# anchor=9900, target=10000(기본). 11000(>anchor*1.02)→가격협상(카드),
|
||||||
turns = [None, "확인", "예", "확인", "11000", "예", "10200", "예", "9800", "예",
|
# 10000(anchor<p≤anchor*1.02)→1% 와일드카드→수락하면 협상완료.
|
||||||
|
turns = [None, "확인", "예", "확인", "11000", "예", "10000", "예", "예",
|
||||||
"협상 내용을 확인했으며, 이의가 없음에 동의합니다."]
|
"협상 내용을 확인했으며, 이의가 없음에 동의합니다."]
|
||||||
out = await _run(svc, eng, turns)
|
out = await _run(svc, eng, turns)
|
||||||
steps = [r.step for r in out]
|
steps = [r.step for r in out]
|
||||||
@ -61,8 +62,8 @@ async def test_full_conversation_reaches_completion(db_engine):
|
|||||||
assert nego and nego[0].card_id and nego[0].card_id.startswith("NGC-A")
|
assert nego and nego[0].card_id and nego[0].card_id.startswith("NGC-A")
|
||||||
assert nego[0].updated_q is not None
|
assert nego[0].updated_q is not None
|
||||||
|
|
||||||
# 와일드카드 발동
|
# 와일드카드 발동 (1% 인하)
|
||||||
assert any(r.step == "wild_card_budget" for r in out)
|
assert any(r.step == "wild_card_1pct" for r in out)
|
||||||
|
|
||||||
# 종료 보상(success)
|
# 종료 보상(success)
|
||||||
done = [r for r in out if r.outcome == "success"]
|
done = [r for r in out if r.outcome == "success"]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user