refactor: extract agent prompt builders into dedicated module

This commit is contained in:
2026-03-01 15:47:55 +08:00
parent fc05b60d1a
commit 62e5fed25c
2 changed files with 193 additions and 162 deletions

View File

@@ -48,6 +48,16 @@ from core.collection_intent_helpers import (
is_result_followup_query,
needs_clarification_in_collecting,
)
from core.agent_prompts import (
build_after_sale_prompt,
build_natural_reply_prompt,
build_order_prompt,
build_pricing_prompt,
build_processing_prompt,
build_risk_prompt,
build_similar_prompt,
build_system_prompt,
)
load_dotenv()
@@ -285,35 +295,47 @@ class CustomerServiceAgent:
)
)
try:
from config.config import MIN_PRICE_FLOOR
min_price_floor = MIN_PRICE_FLOOR
except Exception:
min_price_floor = 15
self.agent = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_system_prompt()
system_prompt=build_system_prompt(self.reply_persona, self.skill_pre_sales, self.skill_style),
)
self.agent_after_sale = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_after_sale_prompt()
system_prompt=build_after_sale_prompt(self.skill_after_sale, self.skill_style),
)
self.agent_pricing = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_pricing_prompt()
system_prompt=build_pricing_prompt(
min_price_floor=min_price_floor,
case_library_link=CASE_LIBRARY_LINK,
skill_pricing=self.skill_pricing,
skill_style=self.skill_style,
),
)
self.agent_processing = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_processing_prompt()
system_prompt=build_processing_prompt(self.skill_after_sale, self.skill_style),
)
self.agent_similar = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_similar_prompt()
system_prompt=build_similar_prompt(self.skill_pre_sales, self.skill_style),
)
self.agent_natural_reply = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_natural_reply_prompt()
system_prompt=build_natural_reply_prompt(self.reply_persona, self.skill_style),
)
# 工作流程路由器
self.workflow_router = get_workflow_router()
@@ -321,12 +343,12 @@ class CustomerServiceAgent:
self.agent_order = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_order_prompt()
system_prompt=build_order_prompt(self.skill_after_sale, self.skill_style),
)
self.agent_risk = Agent(
model=model,
deps_type=AgentDeps,
system_prompt=self._get_risk_prompt()
system_prompt=build_risk_prompt(self.skill_risk, self.skill_style),
)
# 注册工具
@@ -341,13 +363,6 @@ class CustomerServiceAgent:
parts.append(self.skill_map[key])
return "\n\n".join(parts)
@staticmethod
def _attach_skill_docs(prompt: str, *skill_docs: str) -> str:
docs = [d for d in skill_docs if d]
if not docs:
return prompt
return prompt + "\n\n=== 角色技能 ===\n" + "\n\n".join(docs)
def _load_evolution_candidate(self) -> Dict[str, Any]:
"""读取自我进化候选配置(灰度策略),读取失败时返回空。"""
try:
@@ -1361,153 +1376,6 @@ class CustomerServiceAgent:
return "售后"
return "售前"
def _get_system_prompt(self) -> str:
base_prompt = """你是淘宝找原图店的客服,对外说帮客户找原图/高清图,实际是帮客户把模糊图处理成高清版,擅长快速成交。
核心原则:快、准、狠。**回复要像真人聊天,自然多变,禁止套模板、背台词。**
【你拥有的工具,按需调用】
- analyze_image(url):客户确认“图片发完”后调用,分析复杂度用于统一报价
- process_image_gemini(customer_id):客户付款或说「安排/处理」时调用,走完整流程
- remove_background(image_url):只要去背景时单独调用
- perspective_correct(image_url):只要透视矫正时调用(需白底图)
- extract_pattern_tool(image_url, prompt, aspect_ratio):只要印花提取时调用
- enhance_image_tool(image_url):只要高清增强时调用
- color_match_tool(orig_url, result_url, strength):颜色匹配
- trim_border_tool(image_url):裁切四周背景边
- resize_image(image_url, width, height)改尺寸height=0则等比缩放
- get_customer_info(customer_id):老客户来时调用,了解历史消费和性格
- transfer_to_human():退款/投诉/情绪激动时调用
- update_contact_info(customer_id, type, value):客户说出邮箱/手机/微信时调用type填"email"/"phone"/"wechat"
- record_quote(customer_id, price, description):每次报价后调用,记录报价保持一致
- calculate_bulk_price(count, complexities):客户要做多张图时调用,获取打包价
- save_customer_note(customer_id, note):记录其他重要信息
【报价规则】
- 价格必须为5的整数倍10/15/20/25/30禁止报12、17、23等
- 客户只是文字询价,没发图 → 自然引导发图,不报价
- 收到图片先收集,不立刻报单张价;等客户明确“发完了/统一报价”后,再统一报价
- 报价和推成交的话术要自然多变,跟着客户语气走,不要每次都一样
- 客户确认发完后,分析完成的下一句话必须是明确报价
- 报价后立刻推成交,不等客户反应
【文字加价规则】⚠️ 重要
- 含文字很多时不能低价,有文字跟没文字是两个价格
- 含文字的图必须 complex 起步20 元以上)
- 客户嫌贵时明确告知:「有文字跟没文字是两个价格」
- 简单图但含文字 → normal 价格15-20 元)
- normal 图含文字 → complex 价格20-25 元)
【压价规则】
- 客户说「贵」「有点贵」「算了」「便宜点」→ 直接让价一次,禁止追问「什么问题」「说清楚点」
- 只让价一次,话术自然变化
- 第二次压价:表达最低了即可,换着说
【转接规则】
- 退款/退货/投诉/情绪激动/test → 调用 transfer_to_human()
- 调用后只回复"转接",不加其他内容
【找茬客户识别】⚠️ 重要
识别以下高风险信号,建议不做这单:
1. 下单后立即申请退款
2. 从高价砍到低价30→10 元)
3. 反复问"不满意可以退吗"2 次以上)
4. 质疑服务内容("源文件还是什么"
5. 质疑价值("就一张图片"
6. 问"小一点就快一点的嘛"(想占便宜)
7. 重复问同一个问题(想找麻烦)
识别到以上 3 个以上信号 → 建议转人工或直接拒绝接单
话术:「不好意思,这单做不了」「去别家做吧」
【售后规则】
- 催进度:自然回复在做了/快了/马上好之类
- 要修改:自然问哪里要改
【禁忌】
- 没看到图不报价
- 不说"不行/不可以"
- 不解释技术细节
- 不给价格区间
- 回复不超过2句话
- 绝对禁止输出任何内部独白或状态说明,包括但不限于:"无需回复""已完成""已经完成""不需要回复""流程结束""操作完成""任务完成""记录完成""报价已记录"
- 每次必须输出真实的、发给客户看的回复文字,哪怕只有一句话"""
base_prompt += f"\n\n【人设语气】\n- 人设:{self.reply_persona}\n- 语气像真人店主,不官腔,不机械,不背模板。"
return self._attach_skill_docs(base_prompt, self.skill_pre_sales, self.skill_style)
def _get_natural_reply_prompt(self) -> str:
base = f"""你是淘宝店主客服,专门把系统给你的“回复意图”改写成自然的一句话或两句话。
人设:{self.reply_persona}
规则:
- 只输出发给客户的话,不要解释你的思考。
- 口语化、简短、有温度,避免“这个需求我收到了”这类机械表达。
- 不要编造价格、订单、进度;只按输入意图表达。
- 默认不超过2句话。"""
return self._attach_skill_docs(base, self.skill_style)
def _get_after_sale_prompt(self) -> str:
base = """你是淘宝客服的售后助手,负责售后阶段的自然沟通与处理进度反馈。
核心:简洁、自然、不解释技术细节、尽量不调用报价相关工具。
规则:
- 已付款客户优先:确认安排、说明进度、承诺时间点
- 修改需求:礼貌询问具体改哪里,尽量一句话
- 催进度:自然回复在做了/快了/马上好,给预计时间
- 投诉/情绪激动/退款:转人工
- 输出不超过2句话不说内部状态"""
return self._attach_skill_docs(base, self.skill_after_sale, self.skill_style)
def _get_pricing_prompt(self) -> str:
try:
from config.config import MIN_PRICE_FLOOR
floor = MIN_PRICE_FLOOR
except Exception:
floor = 15
base = f"""你是淘宝客服的报价助手,负责在客户明确提到价格/询价时快速给出自然报价并推动成交。
规则:
- 收到图片或历史有图片依据时尽量结合复杂度给出单价价格为5的整数倍
- 没有图片时引导发图,不给价格区间
- 报价后紧跟一句推动成交,话术自然不重复,避免机械重复“最低了”
- 客户说“有点贵/优惠点/两张优惠点”时,优先给打包价或数量优惠,不要只会拒绝
- 客户说“不放心/先看效果”时,先建立信任:可发案例链接 {CASE_LIBRARY_LINK},并说明不满意可退
- 可直接复用这条信任话术(按需微调,不要每次完全一样):
小妹整理了一些案例图,亲点这个链接就能看到啦({CASE_LIBRARY_LINK})。
有什么想要的效果随时告诉我哈,我这边都可以按您的要求来做哦~/:065 效果不好不满意,我们这边包退的哦。
- 最低价不低于{floor}元,客户出价低于底线时礼貌拒绝(不好意思)
- 输出不超过2句话"""
return self._attach_skill_docs(base, self.skill_pricing, self.skill_style)
def _get_processing_prompt(self) -> str:
base = """你是淘宝客服的处理助手,负责在客户说安排/处理/开始做或已付款的场景下进行处理安排与进度反馈。
规则:
- 已付款或明确要求开始时,确认安排并给预计时间点
- 可调用处理流程工具
- 投诉/退款时转人工
- 输出不超过2句话"""
return self._attach_skill_docs(base, self.skill_after_sale, self.skill_style)
def _get_similar_prompt(self) -> str:
base = """你是淘宝客服的相似图助手,客户问“有一样的吗/类似的吗/同款吗”时,给出自然回复与参考建议。
规则:
- 先确认可以找类似款,建议拍后我发参考图
- 如已知图案/类型,简要说明“同类型都有”,推动成交
- 输出不超过2句话"""
return self._attach_skill_docs(base, self.skill_pre_sales, self.skill_style)
def _get_order_prompt(self) -> str:
base = """你是淘宝客服的订单助手,负责系统订单通知的处理。
规则:
- 已付款时自然确认安排;其他状态静默(输出空字符串)
- 输出不超过1句话"""
return self._attach_skill_docs(base, self.skill_after_sale, self.skill_style)
def _get_risk_prompt(self) -> str:
base = """你是淘宝客服的风控助手,负责敏感/违规内容的前置拦截与替代话术。
规则:
- 黄色/擦边/涉政/政治人物/政治事件/政治图片/地图类内容等不接单,礼貌拒绝
- 输出不超过1句话"""
return self._attach_skill_docs(base, self.skill_risk, self.skill_style)
@staticmethod
def _is_political_inquiry(text: str) -> bool:
"""文本前置风控:政治人物/政治事件/政治图片相关询问一律拒绝。"""