外贸询盘分级引擎·专业版
输入 / 输出
输入:subject(主题)、body(正文)、country(国别,可选)、existing_customer(是否老客户,默认 False)、sender_email(发件邮箱,可选)。
输出 report 字典:grade(A/B/C/D)、score(正向信号数)、signals(命中信号列表)、risks(风险原因)、only_catalog(是否只索要目录)、response_sla(响应时限)、quote_strategy(报价策略)。
使用示例
from inquiry_grading import grade_inquiry
r = grade_inquiry(
subject="Quotation for 1000 pcs of model X-200",
body="We are ABC Co.,Ltd. Please quote FOB Shanghai, target price USD 3.5/pc, "
"payment T/T, delivery within 25 days.",
sender_email="buyer@abc-foam.com")
print(r["grade"]) # A
print(r["response_sla"]) # 2小时内(工作时间)
引擎代码:inquiry_grading.py
# -*- coding: utf-8 -*-
"""外贸询盘分级引擎:A/B/C/D 四级 + 响应时限 + 报价策略。
确定性规则(不依赖模型,可断言):
信号(正向):
product 明确产品/规格(型号、规格、材质、数量单位等)
quantity 明确数量(数字 + pcs/ton/套/吨 等单位,或 qty/MOQ/采购量)
target 目标价/预算/明确询价口径
deal 交期/付款方式(delivery/lead time/T/T/L/C/FOB/CIF)
company 公司信息(Co.,Ltd/Inc/企业官网/非公共邮箱)
existing 老客户(历史往来)
风险(D 级,一票否决):
诈骗模式(western union/moneygram/overpay/barrister/widow/inheritance/gold bar)
免费样品且无数量无公司(套样品)
无产品无数量无公司、正文极短或纯群发(无实质信息)
分级:
A = 产品 + 数量 + 其余正向信号(deal/target/company/existing) ≥2
B = 产品 + 数量(其余信号不足) 或 产品 + 其余信号 ≥2
C = 有产品但缺数量,或只要目录/价目表(泛询,需培育)
D = 命中风险,或无实质信息
"""
import re
# ---- 正向信号正则 ----
RE_PRODUCT = re.compile(
r"(model\s*[:#]?|spec(?:ification)?s?|size|dimension|material|grade|colour|color"
r"|型号|规格|尺寸|材质|参数|牌号|颜色|产品型号|具体型号)", re.I)
# 数量:数字+单位,或 qty/moq/采购量等
RE_QTY = re.compile(
r"(\d[\d,\.]*\s*(?:pcs|pieces|units|set|sets|tons?|kg|kgs|mts|meters?|ctns"
r"|个|件|套|吨|公斤|千克|箱|台|米)\b"
r"|\b(?:qty|quantity|moq|order quantity|采购量|数量|订货量)\b)", re.I)
RE_TARGET = re.compile(
r"(target price|budget|price per|best price|unit price"
r"|目标价|预算|单价|报价|价格区间|每(?:吨|件|套|个)多少钱)", re.I)
RE_DEAL = re.compile(
r"(delivery|lead ?time|payment|t/t|l/c|letter of credit|fob|cif|cfr|exw|d/p|d/a"
r"|交期|交货期|付款方式|信用证|预付|定金|贸易术语)", re.I)
RE_COMPANY = re.compile(
r"(co\.?,?\s*ltd|co\.?\s*,?\s*limited|\binc\.?|\bcorp\.?|\bgmbh\b|\bllc\b|\bs\.?a\.?\b"
r"|公司|企业|集团|工厂|官网|https?://(?!mail|www\.gmail|www\.yahoo)|website)", re.I)
# 免费样品
RE_FREE_SAMPLE = re.compile(r"(free sample|free samples|send sample for free|免费样品|免费寄样|免费试样)", re.I)
# ---- 风险(诈骗)正则 ----
RE_SCAM = re.compile(
r"(western union|money\s?gram|personal account|overpay|over payment|refund the balance"
r"|barrister|widow|inheritance|bequeath|gold bar|gold dust|cotonou|benin|urgent confidential"
r"|pay you (?:extra|more) and you (?:send|transfer)|私人账户|西联汇款|多付款|遗产|金条)", re.I)
def _has(pattern, text):
return bool(pattern.search(text))
def grade_inquiry(subject, body, country=None, existing_customer=False, sender_email=None):
"""对外贸询盘做 A/B/C/D 分级。返回 report 字典。"""
text = f"{subject or ''} {body or ''}".strip()
low = text.lower()
email = (sender_email or "").lower()
# 免费公共邮箱
free_mail = bool(re.search(r"@(gmail|yahoo|hotmail|outlook|qq|163|126|foxmail)\.", email))
signals = {
"product": _has(RE_PRODUCT, low),
"quantity": _has(RE_QTY, low),
"target": _has(RE_TARGET, low),
"deal": _has(RE_DEAL, low),
"company": _has(RE_COMPANY, low),
"existing": bool(existing_customer),
}
# 企业邮箱(自有域名,非公共邮箱)算公司信号
if email and not free_mail and "@" in email:
signals["company"] = True
risks = []
if _has(RE_SCAM, low):
risks.append("诈骗模式")
if _has(RE_FREE_SAMPLE, low) and not signals["quantity"] and not signals["company"]:
risks.append("免费样品无数量无公司(套样品)")
# 无实质信息:无产品、无数量、无公司、无交易条件,且正文极短
meaningful = sum(signals.values())
if meaningful == 0:
risks.append("无实质信息/纯群发")
# 只索要目录/价目表(泛询)
only_catalog = bool(re.search(
r"(send.*(?:catalog|catalogue|price list)|price list|catalog|catalogue"
r"|目录|价目表|产品清单|报价单模板)", low)) and not signals["quantity"]
# ---- 分级 ----
other = sum([signals["target"], signals["deal"], signals["company"], signals["existing"]])
if risks:
grade = "D"
elif signals["product"] and signals["quantity"] and other >= 2:
grade = "A"
elif signals["product"] and signals["quantity"]:
grade = "B"
elif signals["product"] and other >= 2:
grade = "B"
elif signals["product"] or only_catalog or meaningful >= 1:
grade = "C"
else:
grade = "D"
score = meaningful
sla = {
"A": "2小时内(工作时间)",
"B": "8小时内(当日回复)",
"C": "24小时内,发公司介绍+目录培育",
"D": "不报价;标记归档,必要时礼貌模板回复",
}[grade]
strategy = {
"A": "直接报实价/给方案,附规格书与交期,重点跟进争取成单",
"B": "报区间价,追问具体数量/目标价/交期,补全信息后转 A",
"C": "发企业介绍+产品目录,引导对方补充型号、数量、用途",
"D": "不投入报价资源,警惕诈骗/套样品;垃圾可拉黑",
}[grade]
hit = [k for k, v in signals.items() if v]
return {
"grade": grade,
"score": score,
"signals": hit,
"risks": risks,
"only_catalog": only_catalog,
"response_sla": sla,
"quote_strategy": strategy,
}
if __name__ == "__main__":
import sys
import json
# 简单自测入口
demo = grade_inquiry(
"Quotation for 1000 pcs of your model X-200",
"We are ABC Co.,Ltd. Please quote FOB Shanghai, target price USD 3.5/pc, "
"payment T/T 30% deposit, delivery within 25 days. Company: www.abc-foam.com",
sender_email="buyer@abc-foam.com")
print(json.dumps(demo, ensure_ascii=False, indent=2))
边界处理(已覆盖)
- 诈骗模式(western union/moneygram/私人账户/多付款/遗产金条等)直接判 D;
- 免费样品且无数量、无公司信息判 D(套样品);
- 空主题、空正文判 D,不报错;
- 只有"hello/hi"等无实质信息判 D;
- 有产品无数量判 C;只索要目录/价目表判 C;
- 企业自有域名邮箱(非 gmail/yahoo 等公共邮箱)自动计入公司信号;
- 公共邮箱不单独作为判 D 依据,需结合其他风险。
断言测试结果
已通过 6 正例(A 级黄金询盘、B 级有效询盘、C 级目录泛询、老客户复购、诈骗询盘、套样品询盘)+ 4 边界(无实质信息、空输入、有产品无数量、字段完整性),全部通过。
批量接入建议
- 邮箱/客服系统收到新邮件后自动调用,按级别打标签;
- A 级即时通知业务员、B 级进入当日待办、C 级进培育序列、D 级归档;
- 分级结果回写 CRM,沉淀"询盘级别→成交率"转化漏斗,持续校准规则。