feat: 提取/评估提示词建材化(规格自由文本+标准单列)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,30 +1,35 @@
|
||||
你是一个客户意向评估助手。根据对话中收集到的客户信息,判断这个客户的购买意向。
|
||||
你是一个客户意向评估助手。根据对话中收集到的客户信息,判断这个客户的管道采购意向。
|
||||
|
||||
## 评估标准
|
||||
|
||||
### interested(有意向)
|
||||
必须满足以下所有条件:
|
||||
- 明确表达了购车需求(有预算或目标车型/品牌)
|
||||
- 明确了目标国家/地区或采购用途
|
||||
- 明确表达了管道采购需求(有明确意向品类/规格要求,或有采购数量、预算)
|
||||
- 明确了目标国家或用途/项目类型
|
||||
- 提供了至少一种联系方式(手机/WhatsApp/邮箱/微信)
|
||||
- 对话至少进行了3轮以上(客户说了3条以上消息)
|
||||
- 客户表现出真实采购意向而非简单咨询
|
||||
- 客户询问价格、优惠、运费或试驾/交付安排,应视为意向积极信号(有真实购买兴趣)
|
||||
- 客户询问价格、优惠、运费或样品/交期安排,应视为意向积极信号(有真实采购兴趣)
|
||||
- 客户主动索要我方联系方式(WhatsApp/邮箱/电话),视为最强意向信号之一
|
||||
|
||||
### not_interested(无意向)
|
||||
客户表现出以下特征:
|
||||
- 明确表示不买、只是随便看看
|
||||
- 明确表示不买、没有采购计划、只是随便看看
|
||||
- 态度冷淡,不愿多聊
|
||||
- 表示已经从其他渠道购买了
|
||||
- 表示已经从其他渠道采购了
|
||||
|
||||
### pending(待定)
|
||||
以下情况都应标记为pending:
|
||||
- 对话轮次少于3轮
|
||||
- 还未收集到联系方式
|
||||
- 客户信息不够充分(缺少预算、车型、数量等关键信息)
|
||||
- 客户信息不够充分(仅泛泛浏览品类,缺少规格要求、采购数量等关键信息)
|
||||
- 客户还在比较或犹豫阶段
|
||||
|
||||
## 快速示例
|
||||
- 客户说明确的品类+规格+数量(如 "HDPE PE100 DN110 SDR11, 5000 meters, water project in Kenya")并留了联系方式 → interested
|
||||
- 客户仅泛泛浏览("what pipes do you have"),没给规格、数量或联系方式 → pending
|
||||
- 客户明确无采购计划("just looking" / 已从别家采购)→ not_interested
|
||||
|
||||
## 严格规则
|
||||
1. info_sufficient 必须为 true 时,intent_level 才可以是 interested 或 not_interested
|
||||
2. 如果对话轮次少于3轮,info_sufficient 必须为 false,intent_level 必须为 pending
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
你是一个信息提取助手。请从以下对话历史中提取客户相关信息,输出JSON格式。
|
||||
你是一个信息提取助手。请从以下对话历史中提取客户(管道采购)相关信息,输出JSON格式。
|
||||
|
||||
## 输出格式
|
||||
返回一个JSON对象,包含你能从对话中识别到的所有信息字段。字段名用中文。示例字段:
|
||||
目标国家/地区、采购用途、预算、意向品牌、意向车型、采购数量、车况要求、年份要求、运输方式、联系方式、其他备注。
|
||||
目标国家、意向品类、规格要求、标准要求、采购数量、用途、项目类型、预算提及、联系方式、其他备注。
|
||||
|
||||
字段说明:
|
||||
- 意向品类:客户想采购的管道品类(如 HDPE给水管、PVC排水管、PPR管、双壁波纹管、球墨铸铁管等)
|
||||
- 规格要求:自由文本,保留客户原话(如 "DN110 PE100 SDR11"、"4 inch SCH40"、"PN16")——不拆分、不翻译、不过度结构化,客户怎么说就怎么记
|
||||
- 标准要求:客户提到的执行标准(如 ISO4427、ASTM、EN12201、SCH40/SCH80 系列)——客户提到才记,没提到不要猜
|
||||
- 采购数量:数量或工程量(如 "5000米"、"3x40HQ"、"20000条")
|
||||
- 用途:管道用途(给水/燃气/排污/灌溉等)
|
||||
- 项目类型:市政工程/农田灌溉/房建项目/经销商备货等
|
||||
- 目标国家:客户所在或项目所在的国家/地区
|
||||
- 预算提及:客户提到的预算或目标价(有才记,原样保留)
|
||||
|
||||
其中联系方式如果有的话格式为:{"手机": "xxx", "WhatsApp": "xxx", "邮箱": "xxx", "微信": "xxx"}
|
||||
- 如果对话中客户更正了此前提供的联系方式(如 wrong number / 号码错了 / use this / 换成 / 又给了一个新号),联系方式必须以客户最后提供的值为准覆盖旧值
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
1. **产品信息**(品类/口径/压力等级/标准/材质/应用场景/管道知识):直接热情介绍。
|
||||
- 公司情况(品牌/覆盖市场/出口经验/运作模式)按系统提供的事实卡简短作答建立信任——但不因此报价、承诺或跳过留资引导
|
||||
- 认证(certificate)按事实卡简短作答(ISO 三体系);证书编号、完整认证清单、检测报告细节 → 转客户经理(同第2类话术)
|
||||
2. **价格、优惠、折扣、MOQ(起订量)、交期 lead time、装柜方案 container loading、样品费 sample fee、运费、关税、质保 warranty/after-sales 类**:一律不直接回答,用迂回话术(解释一句 + 固定英文短句收尾):
|
||||
2. **价格、优惠、折扣、MOQ(起订量)、交期 lead time、装柜方案 container loading、样品费 sample fee、运费、关税、质保 warranty/after-sales 类**:一律不直接回答,用迂回话术(解释一句 + 引导留资模板句收尾,见语言规则):
|
||||
- "Prices depend on the specification, quantity and destination — Please leave your contact and our manager will send the full quotation."
|
||||
- "Lead time depends on your order and the production schedule — Please leave your contact and our manager will send the full quotation."
|
||||
- "MOQ differs by product line — Please leave your contact and our manager will send the full quotation."
|
||||
|
||||
@@ -152,7 +152,7 @@ git add -A && git commit -m "feat: HESUPIPE 公司事实卡(官网硬事实+防
|
||||
**Files:**
|
||||
- Modify: `app/prompts/system.md`(整篇重写,框架保留)
|
||||
|
||||
- [ ] **Step 1: 重写 system.md**
|
||||
- [x] **Step 1: 重写 system.md**
|
||||
|
||||
保留参考项目的六段结构,逐段建材化:
|
||||
|
||||
@@ -163,20 +163,20 @@ git add -A && git commit -m "feat: HESUPIPE 公司事实卡(官网硬事实+防
|
||||
5. **对话推进**:预算路径改为 `"Which application? Water supply, gas, drainage or irrigation?"`;规格追问(口径/压力/标准);围绕已说品类推进
|
||||
6. **好差示例**:6-8 组管道场景(例:客户说 "PE100 water pipe DN110",差:泛问 what do you need;好:确认 SDR11/SDR17? + 询问工程量;中文话术示例同步改管道语境)
|
||||
|
||||
- [ ] **Step 2: 自查清单**
|
||||
- [x] **Step 2: 自查清单**
|
||||
|
||||
- [ ] 所有汽车词(car/vehicle/BYD/Toyota/test drive/提车/试驾/续航)已清零:`grep -in "car\b\|vehicle\|byd\|toyota\|test drive\|试驾\|提车\|续航" app/prompts/system.md` 预期无输出
|
||||
- [ ] 红线覆盖:MOQ、lead time、container loading、sample fee、certificate、price range
|
||||
- [ ] 固定英文拒绝短句原样出现(与 boundary_filter 的 DEFLECTIONS 措辞协调但不冲突——prompt 是"含义",墙是"兜底")
|
||||
|
||||
- [ ] **Step 3: 跑全量测试(system.md 变更影响的测试)**
|
||||
- [x] **Step 3: 跑全量测试(system.md 变更影响的测试)**
|
||||
|
||||
```bash
|
||||
python -m pytest -q
|
||||
```
|
||||
预期:PASS(若有断言 system.md 内容的测试,同步更新)
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
- [x] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add -A && git commit -m "feat: 系统提示词建材化(管道外贸人设+多语言拒绝短句)"
|
||||
|
||||
@@ -33,11 +33,14 @@ def test_facts_concatenated_between_system_and_context():
|
||||
|
||||
def test_facts_absent_from_extractor_prompt():
|
||||
# extractor/evaluator 不拼事实卡(它们有自己的 prompt,不该看到公司事实)
|
||||
# Task 4 起 extractor/evaluator 含通用品类词(HDPE/PVC等字段示例)——
|
||||
# 隔离断言只针对品牌/公司事实标记(HESUPIPE),不再卡通用品类词
|
||||
from app.services.ai_service import EVALUATOR_PROMPT, EXTRACTOR_PROMPT
|
||||
assert "HESUPIPE" not in EXTRACTOR_PROMPT
|
||||
assert "HDPE" not in EXTRACTOR_PROMPT
|
||||
assert "HESUPIPE" not in EVALUATOR_PROMPT
|
||||
assert "HDPE" not in EVALUATOR_PROMPT
|
||||
# 河南和硕/和硕集团 等公司主体信息同样不得泄入
|
||||
assert "和硕" not in EXTRACTOR_PROMPT
|
||||
assert "和硕" not in EVALUATOR_PROMPT
|
||||
|
||||
|
||||
def test_facts_no_auto_words():
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
"""提取/评估提示词建材化: 字段与占位符静态断言(Task 4)。"""
|
||||
from app.services.ai_service import EVALUATOR_PROMPT, EXTRACTOR_PROMPT
|
||||
|
||||
# 建材字段清单(与 system.md "关注的信息"节口径一致)
|
||||
PIPE_FIELDS = (
|
||||
"意向品类", # HDPE给水管/PVC排水管/PPR…
|
||||
"规格要求", # 自由文本保留客户原话
|
||||
"标准要求", # ISO4427/ASTM/EN/SCH 单列
|
||||
"采购数量",
|
||||
"用途", # 给水/燃气/排污/灌溉…
|
||||
"项目类型",
|
||||
"目标国家", # email_service.send_lead_email 按此键取国家
|
||||
"预算提及",
|
||||
"联系方式",
|
||||
)
|
||||
|
||||
# 汽车项目遗留字段——建材化后不得残留
|
||||
AUTO_WORDS = ("车型", "意向品牌", "车况要求", "年份要求", "运输方式", "购车", "试驾")
|
||||
|
||||
|
||||
def test_extractor_has_pipe_fields():
|
||||
for field in PIPE_FIELDS:
|
||||
assert field in EXTRACTOR_PROMPT, field
|
||||
|
||||
|
||||
def test_extractor_no_auto_fields():
|
||||
for word in AUTO_WORDS:
|
||||
assert word not in EXTRACTOR_PROMPT, word
|
||||
|
||||
|
||||
def test_extractor_spec_is_free_text():
|
||||
# 规格要求 = 自由文本保留客户原话,不拆分不过度结构化
|
||||
assert "原话" in EXTRACTOR_PROMPT
|
||||
assert "不拆分" in EXTRACTOR_PROMPT
|
||||
|
||||
|
||||
def test_extractor_standard_only_when_mentioned():
|
||||
# 标准要求客户提到才记,不猜测
|
||||
assert "客户提到才记" in EXTRACTOR_PROMPT
|
||||
|
||||
|
||||
def test_extractor_placeholders_and_contact_contract_intact():
|
||||
# 占位符(ai_service.replace 依赖)与联系方式四层合并的 extractor 层契约
|
||||
assert "$existing_info" in EXTRACTOR_PROMPT
|
||||
assert "$messages" in EXTRACTOR_PROMPT
|
||||
assert '{"手机": "xxx", "WhatsApp": "xxx", "邮箱": "xxx", "微信": "xxx"}' in EXTRACTOR_PROMPT
|
||||
assert "整条消息只有号码" in EXTRACTOR_PROMPT
|
||||
|
||||
|
||||
def test_evaluator_keeps_three_levels_and_placeholders():
|
||||
for level in ("interested", "not_interested", "pending"):
|
||||
assert level in EVALUATOR_PROMPT, level
|
||||
assert "$profile" in EVALUATOR_PROMPT
|
||||
assert "$recent_messages" in EVALUATOR_PROMPT
|
||||
# _normalize_evaluation 消费的输出字段
|
||||
for key in ("intent_level", "reasoning", "contact_info", "info_sufficient"):
|
||||
assert key in EVALUATOR_PROMPT, key
|
||||
|
||||
|
||||
def test_evaluator_no_auto_fields():
|
||||
for word in AUTO_WORDS:
|
||||
assert word not in EVALUATOR_PROMPT, word
|
||||
|
||||
|
||||
def test_evaluator_pipe_procurement_examples():
|
||||
# 管道采购语义示例: 品类+规格+数量=interested; 泛泛浏览=pending; 无采购计划=not_interested
|
||||
assert "采购需求" in EVALUATOR_PROMPT
|
||||
assert "随便看看" in EVALUATOR_PROMPT # not_interested: 明确不买
|
||||
assert "泛泛" in EVALUATOR_PROMPT # pending: 仅泛泛浏览
|
||||
Reference in New Issue
Block a user