From 3c77c618e75bef17f51e05d810757815b54f72f8 Mon Sep 17 00:00:00 2001 From: jimi <1847930177@qq.com> Date: Sat, 28 Feb 2026 23:40:17 +0800 Subject: [PATCH] feat: add richer clarification replies for ambiguous customer intent --- core/pydantic_ai_agent.py | 64 ++++++++++++++++++++++++++++++- tests/test_regression_pipeline.py | 27 +++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/core/pydantic_ai_agent.py b/core/pydantic_ai_agent.py index 3b35868..d42a772 100755 --- a/core/pydantic_ai_agent.py +++ b/core/pydantic_ai_agent.py @@ -1534,6 +1534,19 @@ class CustomerServiceAgent: if text_without_urls: self._append_requirement(state, text_without_urls) self._sync_pending_quote_state(message.from_id, state) + # 客户明确“找图,不是做图”时,先澄清意图,不继续报价链路 + if self._is_find_image_not_edit_conflict(text_without_urls): + clarify = self._build_find_image_clarify_reply(state) + state.last_reply_at = datetime.now() + print(f"{self.C_REPLY}[REPLY->CUSTOMER]{self.C_RESET} {clarify}") + return AgentResponse(reply=clarify, should_reply=True, need_transfer=False) + + # 信息不足时先追问,避免误判为“直接报价” + if self._needs_clarification_in_collecting(text_without_urls): + ask = self._build_not_understood_reply() + state.last_reply_at = datetime.now() + print(f"{self.C_REPLY}[REPLY->CUSTOMER]{self.C_RESET} {ask}") + return AgentResponse(reply=ask, should_reply=True, need_transfer=False) if self._is_batch_finish_intent( text=customer_text, state=state, @@ -2202,7 +2215,7 @@ class CustomerServiceAgent: one_templates = [ "这个要求我记住了。你还有图就继续发,不补图我就按这张给你报价。", "明白,这个需求我加上了。你继续发图也行,想直接报价也可以。", - "懂你意思,这种能做。要不先按这张来,我现在就给你报个实在价。", + "我先记下这张。你如果是要我找图,不是做图,直接说一声,我按找图思路给你走。", "这个需求我收到了。你要是就做这张,我现在就给你报。", "你这要求我记下了,后面还有图就发,没有的话我现在直接算价。", "行,我按你这个要求来。继续补图也行,不补我就先报这张。", @@ -2222,6 +2235,55 @@ class CustomerServiceAgent: ] return random.choice(templates).format(n=count) + @staticmethod + def _is_find_image_not_edit_conflict(text: str) -> bool: + """识别客户明确声明“要找图,不是做图”的冲突语义。""" + s = (text or "").strip() + if not s: + return False + find_kw = ("找图", "找原图", "找素材", "找同款") + deny_edit_kw = ("不是让你做图", "不是做图", "不用做图", "不需要做图", "不是修图", "不用修图") + return any(k in s for k in find_kw) and any(k in s for k in deny_edit_kw) + + @staticmethod + def _needs_clarification_in_collecting(text: str) -> bool: + """ + 信息不足时先追问,不急着报价。 + 例:这个也是大图 / 一共几个图 / 啥意思 / 没明白 + """ + s = (text or "").strip() + if not s: + return False + if len(s) <= 4: + return True + vague_kw = ( + "这个也是", "一共几个图", "几个图", "啥意思", "没明白", "什么意思", + "这个呢", "这个可以吗", "然后呢", "咋办", "怎么搞", + ) + return any(k in s for k in vague_kw) + + def _build_find_image_clarify_reply(self, state: ConversationState) -> str: + count = len(state.pending_image_urls or []) + return ( + f"明白,你是要我帮你找图,不是做图。现在我这边先记了{count}张," + "你告诉我具体要找哪种:原图/同款/高清版,我按这个方向给你找。" + ) + + @staticmethod + def _build_not_understood_reply() -> str: + """信息不足时的澄清话术(随机)。""" + templates = [ + "不好意思,不太懂你的意思,你再具体说下哈。", + "抱歉我这边没完全理解,你可以换个说法再说一次吗?", + "我有点没听明白,你是要找图还是要做图呀?", + "不好意思我没抓到重点,你再补一句我就能接着处理。", + "这句我理解得不太准,你再说具体一点我马上给你办。", + "抱歉,这里我没太看懂。你是想让我找原图,还是按图处理?", + "我这边还没完全明白你的意思,麻烦你再具体描述一下。", + "不好意思,这条我没读懂,你再详细说一点我马上跟上。", + ] + return random.choice(templates) + def _append_requirement(self, state: ConversationState, text: str): """追加需求并做去重/截断,减少上下文噪音。""" t = (text or "").strip() diff --git a/tests/test_regression_pipeline.py b/tests/test_regression_pipeline.py index 6bdc89e..449a1e7 100644 --- a/tests/test_regression_pipeline.py +++ b/tests/test_regression_pipeline.py @@ -139,6 +139,33 @@ class RegressionPipelineTest(unittest.IsolatedAsyncioTestCase): self.assertIn("50", resp.reply) agent._quote_pending_images.assert_awaited() + async def test_find_image_not_edit_conflict_triggers_clarification(self): + agent = CustomerServiceAgent() + st = agent._get_conversation_state(self.customer_id) + st.pending_image_urls = ["https://img.alicdn.com/a.jpg"] + st.pending_requirements = [] + agent._sync_pending_quote_state(self.customer_id, st) + agent._quote_pending_images = AsyncMock(return_value={"reply": "不该触发", "need_transfer": False}) + + msg = CustomerMessage( + msg_id="m6", + acc_id="test_shop", + msg="我要你帮我找图,不是让你做图", + from_id=self.customer_id, + from_name="t", + cy_id=self.customer_id, + acc_type="AliWorkbench", + msg_type=0, + cy_name="t", + goods_name="专业找图", + goods_order="", + ) + resp = await agent.process_message(msg) + self.assertTrue(resp.should_reply) + self.assertIn("找图", resp.reply) + self.assertIn("不是做图", resp.reply) + agent._quote_pending_images.assert_not_awaited() + async def test_pending_state_restore(self): db.update_pending_quote_state(self.customer_id, ["u1", "u2"], ["r1"]) agent = CustomerServiceAgent()