feat: add per-shop persona routing for ai replies

This commit is contained in:
2026-03-02 13:02:07 +08:00
parent 684409686d
commit 4022ed8f7a
3 changed files with 66 additions and 3 deletions

View File

@@ -25,6 +25,7 @@ def build_prompt(
state: Any,
extract_image_url: Callable[[str], str],
shop_type_resolver: Callable[[str, str], str],
shop_persona_resolver: Callable[[str, str], str],
parse_order_info: Callable[[str], dict[str, str]],
build_order_instruction: Callable[[str, str], str],
) -> str:
@@ -58,6 +59,7 @@ def build_prompt(
stage_info += f"\n【客户压价次数】{state.discount_count}"
shop_type = shop_type_resolver(message.acc_id or "", message.goods_name or "")
shop_persona = shop_persona_resolver(message.acc_id or "", message.goods_name or "")
shop_hint = ""
try:
from config.config import CONFIG_DIR
@@ -84,6 +86,8 @@ def build_prompt(
prompt += f"商品名称: {message.goods_name}\n"
if shop_hint:
prompt += f"\n{shop_hint}\n"
if shop_persona:
prompt += f"\n【店铺人设】{shop_persona}\n"
order_paid = False
order_unpaid = False

View File

@@ -234,6 +234,37 @@ def _get_shop_type(acc_id: str = "", goods_name: str = "") -> str:
return "find_image"
def _get_shop_persona(acc_id: str = "", goods_name: str = "") -> str:
"""按店铺返回人设描述优先级shops.persona > type_personas > default_persona。"""
default_persona = "淘宝老店主,说话自然,像真人微信聊天,不官腔、不背模板。"
try:
from config.config import CONFIG_DIR
import json
cfg_path = CONFIG_DIR / "shop_prompts.json"
if not cfg_path.exists():
return default_persona
with open(cfg_path, "r", encoding="utf-8") as f:
cfg = json.load(f)
shops = cfg.get("shops", {})
if acc_id and acc_id in shops:
persona = str(shops[acc_id].get("persona", "")).strip()
if persona:
return persona
shop_type = _get_shop_type(acc_id, goods_name)
type_personas = cfg.get("type_personas", {})
persona = str(type_personas.get(shop_type, "")).strip()
if persona:
return persona
cfg_default = str(cfg.get("default_persona", "")).strip()
return cfg_default or default_persona
except Exception:
return default_persona
def load_skill_map(skills_dir: str = "skills") -> Dict[str, str]:
"""按技能目录名加载 SKILL.md返回 {skill_name: content}。"""
skill_map: Dict[str, str] = {}
@@ -504,9 +535,11 @@ class CustomerServiceAgent:
)
history = self.message_histories.get(message.from_id, [])
pending_req = "".join((state.pending_requirements or [])[-4:]) or ""
persona = _get_shop_persona(message.acc_id or "", message.goods_name or "")
user_prompt = (
"请按下面意图生成给客户的自然回复。\n"
f"场景: {scene}\n"
f"店铺人设: {persona}\n"
f"回复意图: {intent_hint}\n"
f"客户原话: {message.msg}\n"
f"当前已收图片数: {len(state.pending_image_urls)}\n"
@@ -551,9 +584,11 @@ class CustomerServiceAgent:
)
history = self.message_histories.get(message.from_id, [])
pending_req = "".join((state.pending_requirements or [])[-4:]) or ""
persona = _get_shop_persona(message.acc_id or "", message.goods_name or "")
prompt = (
"请把下面这句客服回复润色成更自然的微信聊天口吻,语义必须保持一致。\n"
f"场景: {scene}\n"
f"店铺人设: {persona}\n"
f"客户原话: {message.msg}\n"
f"当前已收图: {len(state.pending_image_urls)}\n"
f"当前需求摘要: {pending_req}\n"
@@ -650,6 +685,7 @@ class CustomerServiceAgent:
_is_political_inquiry = staticmethod(is_political_inquiry)
_is_map_inquiry = staticmethod(is_map_inquiry)
_get_shop_type = staticmethod(_get_shop_type)
_get_shop_persona = staticmethod(_get_shop_persona)
_notify_wechat = staticmethod(_notify_wechat)
_notify_wechat_overdue = staticmethod(_notify_wechat_overdue)
@@ -989,6 +1025,7 @@ class CustomerServiceAgent:
state=state,
extract_image_url=self._extract_image_url,
shop_type_resolver=_get_shop_type,
shop_persona_resolver=_get_shop_persona,
parse_order_info=parse_order_info,
build_order_instruction=build_order_instruction,
)