外贸开发信这事儿,很多人问过我:你们是不是有一套模板库,能一键生成几百封看起来不那么像垃圾邮件的开发信?我早期确实这么干,把以前写得比较好的几封翻出来,改改客户名字和产品关键词,然后群发。结果回复率一年比一年低,不是产品不行,是买家不傻——他一眼扫过去,就知道这是模板。
后来我开始用 LLM 来批量生成外贸开发信,目标是保住个性化的同时把产能拉起来。这一套跑下来,最大的感受是:LLM 的确解决了“批量”和“个性化”之间的矛盾,但前提是你会写提示词、会搭流程,并且真的知道哪些地方绝对不能放手给模型。这篇文章就把我的整套做法、提示词模板、Python 脚本、以及踩过的那些坑一起拆开聊。适合外贸业务员、SOHO、跨境电商运营,也适合所有想把大模型接入客户开发流程的人。
1. 先聊需求:开发信的痛,是一个典型的批量个性化问题
1.1 模板邮件为什么越来越不好使
欧美采购经理和买手,每天收到的 cold email 少则几十封,多则上百封。绝大多数邮件长一个样:Dear Sir or Madam,我们是某某公司,主营某某产品,附上产品目录,期待您的回复。这类邮件在没有被打开之前,就已经被删掉了。更麻烦的是,Gmail、Outlook 这类邮箱服务商也在不断升级垃圾邮件过滤,重复率极高的模板文本很容易被算法识别成垃圾邮件,连进收件箱的机会都没有。
个性化之所以重要,是因为采购方需要一个理由来分配注意力。你提到了他们公司的具体业务,提到他们在某个国家市场上正在推的新品,提到你知道他们近期在扩建仓库,这时候邮件才从“群发广告”变成了“一封有针对性的商务函”。我实测下来,同一个产品用模板发,回复率一般在 1% 以下;把客户公司名、对方角色、一两条真实动态放进去,回复率能到 3% 到 5%。问题是,靠人工逐封去写这 200 个客户,没等写完前面客户已经不需要了。
1.2 LLM 解决的不是“写信”,是“批量写不一样的信”
LLM 的核心能力,是“给定上下文,逐字预测下一个 token”。这听起来很简单,但它意味着你只要给足差异化的输入,就能生成差异化的输出。也就是说,LLM 不太适合用来做一张万能模板,它真正擅长的是按照每封邮件的客户资料,动态生成结构相似、但内容和语气完全不重样的开发信。
这就把一个矛盾转成了工程问题:我需要为每一个客户准备一组“身份信息”和“背景信息”,然后用一套稳定的提示词,让模型把这些信息组织成一封让人觉得“这封邮件是专门写给我”的信。换一个客户,模型输出的开头、正文重点、甚至行动召唤都会不一样。批量生成只是循环调用的问题,难点其实在提示词设计,也就是大家常说的提示词工程。
1.3 三个钥匙:我是谁、我在找什么、我能提供什么
我自己的开发信内容框架,不是套模板,而是按三把钥匙来搭:我是谁、我在找什么、我能提供什么。这个说法其实也可以借用 token 体系里 key、query、value 的关系来理解。
- key(我是谁):发件方是谁,公司定位是什么,产品核心优势是什么,凭什么让买家相信你。
- query(我在找什么):目标客户画像,对方可能的痛点、业务场景、采购需求,也就是你为什么要联系这个人。
- value(我能提供什么):你的价值主张,能解决什么问题,有没有案例、认证、可验证的证据。
一封有效的开发信,本质上是让收件人在十秒内同时看到三个信息:你认识我、你懂我、你能帮到我。大部分模板只有“Key”和笼统的“Value”,没有“Query”,所以读起来就是自嗨。我在给 LLM 写提示词时,会把这三个字段逐项结构化,让模型在有限的篇幅里完成匹配。
2. 提示词工程:把开发信模板变成一套可控生产线
2.1 系统提示词、用户提示词与任务边界
很多人用 LLM 写邮件,随便写一句“帮我写一封开发信给美国客户”,然后结果全靠运气。要让输出稳定,必须把提示词拆成两个层级:系统提示词(system prompt)和用户提示词(user prompt)。用个通俗的类比,系统提示词是公司制度,规定角色、风格、红线;用户提示词是当天的工单,告诉模型这一次具体要处理哪一单。
- 系统提示词示例:你是一名资深国际 B2B 商务顾问,擅长写简洁、专业、有购买驱动力的英文开发信。你必须使用客户所在国家的商务沟通习惯;必须基于事实,不得虚构产品参数;邮件长度不超过 180 字;结尾必须有明确的行动召唤。
- 用户提示词示例:以下是客户资料和产品资料,请基于这些信息写一封开发信,目标是让客户回复。
这样拆分之后,每次换客户只需要替换用户提示词里的客户字段,模型的行为边界完全由系统提示词固定住,输出的风格和稳定性会好很多。这里还要顺带说一句:系统提示词不是 Agent。Agent 是能自己拆任务、调用工具、多步骤执行的东西;系统提示词只是“规则”。如果你用的是普通 API 调用,老老实实靠系统提示词做约束就好,不要指望它自己去查资料。
2.2 上下文工程:客户画像就是你的“记忆库”
提示词工程再往外走一步,就是上下文工程。上下文决定了模型“看到什么”,上下文质量直接决定生成质量。开发信场景里,真正有价值的上下文不是原材料堆砌,而是经过筛选的高密度信息。
我会把给模型的上下文分为两层:客户画像层和产品事实层。客户画像层包括收件人姓名、职位、公司业务、所在国家、近期动态、可能的痛点;产品事实层包括产品类别、关键规格、认证、交货能力、差异化卖点。不要一股脑把所有产品手册都丢进去,Token 是有限的,而且信息噪音会让模型抓不住重点。
如果你维护了一堆产品文档,建议先整理成一个小型知识库,比如行业术语、FAQ、规格说明,再通过 RAG 搜索,把最相关的片段检索出来放进提示词。我见过有人把产品文档做成 LLM Wiki 性质的内部知识库,再配合简单的本体结构来统一术语,模型生成的内容明显规范很多,不会一会儿叫“polybag”一会儿叫“PE bag”。这一步看起来重,但对做消费品、工业品定制的外贸来说很值。
2.3 一次提示词模板的拆解
下面这个模板是我目前在批量场景里用的简化版,你可以直接复制后替换字段。它最大的特点是把“三把钥匙”变成了显式变量。
你是一名专注[行业]的资深国际销售顾问。 请根据以下客户信息与产品信息,写一封英文冷开发信( cold outreach email)。 客户信息: - 收件人姓名:[FirstName LastName] - 收件人职位:[JobTitle] - 公司名称:[Company] - 公司主营:[CompanyMainBusiness] - 所在国家/地区:[CountryOrRegion] - 客户近期动态:[RecentNews,可能留空] - 客户可能痛点:[CustomerPainPoints,可能留空] 产品信息: - 产品名称:[ProductName] - 核心优势:[KeyAdvantages] - 参数或认证:[SpecOrCertification] - 可提供的证明:[ProofExample,如现有客户反馈] 写作要求: 1. 第一句话必须提到收件人所在公司或其业务,绝不允许用“Hope this email finds you well”开头。 2. 说明为什么联系对方,把客户动态与产品优势做关联。 3. 给出一个明确、低门槛的行动召唤,比如“回复是否有兴趣”或“这周为你预留一个样品”。 4. 全文在 120-180 词之间,语气专业但不僵硬。 5. 只能使用上述提供的事实,不得编造任何数据、认证、客户案例。逐段拆解一下:写作要求第 1 条是防模板感的;第 2 条是逼模型做关联推理;第 3 条是转化目标;第 4 条控制篇幅;第 5 条是防幻觉的关键。实际使用中,我还会给模型提供两三个 few-shot 示例,也就是“这是上一个客户写成的样本”,让模型知道你想要的语气长什么样。给示例比自己反复调温度参数管用得多。
2.4 别忘了模型输出格式:结构化的价值
开发信批量生成不能只出正文文本,不然邮件标题、正文、跟进理由没法自动拆分,后续人工审校也会很痛苦。所以我在提示词里会额外要求模型输出 JSON:
{ "subject": "邮件标题", "body": "邮件正文", "personalization_note": "这封信在哪个点实现了对客户的个性化" }这样程序拿到结果后可以直接读字段,还能自动检查 personalization_note 是否存在,作为后续质检的标记。这里也提醒大家,如果你用了 function calling 或者 JSON Schema,请确保提示词里的结构和代码里定义的 schema 完全一致。像用户反馈里经常出现的“llm request failed: provider rejected the request schema or tool payload”,八成就是因为 JSON 字段定义不一致、类型对不上,或者模型返回了未被允许的额外字段。这个问题属于工程侧最常见的坑,后文我会再给一段稳定的重试代码。
3. 从客户数据到批量发送:一套可落地的实操流程
3.1 数据清洗与客户画像字段设计
LLM 输出质量的上限,由输入数据决定。所以批量生成前,最重要的工作不是写提示词,而是把客户数据整理成合适的结构。我一般的字段设计如下:
| 字段 | 是否必备 | 作用 |
|---|---|---|
| 收件人姓名 | 必须 | 个性化第一要素,避免“Dear Sir” |
| 收件人职位 | 必须 | 判断购买角色,系统集成商和采购经理关注点不同 |
| 公司名称 | 必须 | 开头建立关联性 |
| 公司主营产品/服务 | 必须 | 帮助模型判断对方业务场景 |
| 所在国家/地区 | 必须 | 影响语气与时间表述,也能触发文化提示 |
| 公司网址 | 推荐 | 模型可从中提取行业定位 |
| 近期动态 | 推荐 | 如官网新闻、招聘、融资、展会,是最强个性化钩子 |
| 邮箱 | 必须 | 用于发送时拼接 |
| 潜在痛点 | 可选 | 你能推测的,如“小批量采购效率低” |
清洗时要做三件事:去重、过滤无效格式邮箱、避免给同一个公司不同联系人发送同一套文案。我的习惯是保留每个公司最多 2 个联系人,并且给每个联系人设置不同的邮件标题角度,减少同域名多次发送触发的风控。
3.2 用 RAG 和现有知识库支撑产品事实
产品事实的准确性,是 LLM 开发信最大的命门。如果你把产品描述直接丢给模型自由发挥,它很容易写出“我们通过了FDA认证”“我们的材料符合食品级要求”这类内容。一旦客户回复问你要证书,你就只能现编,这是外贸里绝对不能接受的。
我的做法是建一个轻量级产品事实库,把每个产品的规格、材质、认证、最小起订量、正常交期写清楚。批量生成前,用客户所在行业和产品关键词做检索,把最相关的几条事实和产品卖点注入提示词。你说它是 RAG 也好,说它是简单知识库查询也好,本质上都是给模型划定了事实边界。如果你的库比较大,再考虑用向量检索,否则直接用关键词匹配关键词就行,别为了技术而技术。
有团队会直接把产品手册、报价单丢给本地模型,再做一个 LLM wiki 之类的知识库界面。这不失为一个长期方案,但要注意维护成本。对于大部分外贸团队,第一优先级不是把知识库做得多高级,而是确保“模型能查到的事实”和“你实际能提供的事实”是同一套口径。
3.3 批量生成脚本:一个最小可用的 Python 示例
当数据清洗完、提示词写好,批量生成就很简单了。下面是一段顺手就能用的 Python 脚本,假设你有一个 customers.csv,字段在上面表格的基础上多加一列 product_description。
import csv import json import time from openai import OpenAI client = OpenAI(api_key="YOUR_API_KEY", base_url="YOUR_API_BASE") system_prompt = """ 你是一名资深国际B2B销售顾问。 你负责把客户信息和产品信息转化为一封精确、专业的英文开发信。 必须严格遵守写作要求:只基于给定事实,不编造;使用对方国家商务语气;输出JSON。 """ def build_user_prompt(row): return f""" 客户信息: - 收件人:{row['contact_name']} - 职位:{row['job_title']} - 公司:{row['company']} - 主营:{row['company_business']} - 国家:{row['country']} - 最近动态:{row.get('recent_news', '')} 产品信息: - 产品:{row['product_name']} - 核心优势:{row['product_advantage']} - 认证/规格:{row.get('certification', '')} 请按系统提示词的规则完成,返回JSON对象,包含subject, body, personalization_note。 """ def generate_email(row): resp = client.chat.completions.create( model="gpt-4o-mini", temperature=0.7, response_format={"type": "json_object"}, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": build_user_prompt(row)}, ], ) return json.loads(resp.choices[0].message.content) with open("customers.csv", encoding="utf-8") as f: rows = list(csv.DictReader(f)) results = [] for i, row in enumerate(rows): try: result = generate_email(row) results.append({**row, **result}) print(f"[{i+1}/{len(rows)}] OK: {result.get('subject')}") except Exception as e: print(f"[{i+1}/{len(rows)}] FAIL: {str(e)}") results.append({**row, "subject": "", "body": "", "error": str(e)}) time.sleep(0.2) with open("output_emails.json", "w", encoding="utf-8") as f: json.dump(results, f, ensure_ascii=False, indent=2)温度参数我平时设置在 0.6 到 0.8 之间。太低会显得机械,太高会跑题,0.7 是大多数英文商务邮件比较稳的值。max_tokens 不用特别设置,模型默认足够,但如果你担心成本,可以把输出长度限制在 300 到 400,避免它写了 800 词的长文。成本方面,以 gpt-4o-mini 为例,每封邮件输入约 800 token、输出约 250 token,每封邮件的 API 成本基本可以忽略不计,真正成本还是在人审环节。
3.4 发送前的人类审校与邮箱配置
批量生成只是前半程,发送前必须过一道人工质量闸。我给自己定的审核清单是:产品事实是否准确,是否包含编造的认证数据,语气是否符合对方国家,行动召唤是否清晰,邮件标题是否像广告,以及链接是否有效。尤其要警惕只改客户姓名但正文完全没有关联信息的“伪个性化”。
发送基础设施同样重要。用企业邮箱或自己域名下的邮箱,提前配置好 SPF、DKIM 和 DMARC 记录,否则进垃圾箱的概率直线上升。第一次发开发信不要一口气发几千封,建议从每天 20 到 50 封开始做域名预热,再逐渐加量。发送频率上,批量任务最好错开小时级的时间点,避免同一时间出现大量相同域名的邮件。
4. 那些绕不开的坑:LLM 生成的开发信为什么会被秒删
4.1 幻觉与过度承诺
这是所有文本生成场景的头号问题。模型没有“成本概念”和“法律意识”,它只会让句子读起来顺滑,所以你必须在提示词里反复提示“只使用给定事实,不自行补充”。但即便加了提示,模型还是偶尔会发明一个不存在的展会经历、编一个客户案例、给一个听起来很合理的交期。这里我给两条经验:批量生成后,用脚本检索正文和产品字段,做一个简单的关键词交叉验证;涉及价格、认证、产能、交期的句子,直接删掉让运营写死的数据,而不是让模型自由发挥。
过度承诺的另一种表现,是堆“best price”“lowest cost”“top quality”这种绝对化词汇。这种词在美国消费者市场很可能触发虚假宣传风险,在 B2B 沟通里也显得很廉价。我的提示词里会明确禁止使用绝对化形容词,推荐用“competitive price”“reliable quality”这类相对而务实的表达。
4.2 语言和文化差异
同一个产品,写给德国客户和日本客户,表达方式完全不一样。德国采购喜欢逻辑清楚、参数明确、少废话;日本客户重视敬语和委婉,突出长期关系和细节;美国客户则更直接,喜欢以结果和利益开头。如果只是简单翻译成英文,会觉得空洞;要让模型生成时主动适配。
实际操作中,我只需要在系统提示词里加一条“根据客户所在国家/地区,调整语气、称谓和表达倾向”。美国客户可以称呼名字 First Name,德国客户与不太熟的对象通信用 Last Name 加上 Herr/Frau,日本客户一般用“Dear Mr/Ms + 姓氏”最稳妥。这些东西靠模型记忆是可以做到的,但你需要在审校时注意是否用对了。
4.3 垃圾邮件过滤与送达率
LLM 生成的邮件如果提示词过于单一,多封邮件的句式结构会高度相似。垃圾邮件过滤器并不是只查关键词,它还看格式相似度和发送模式。当同一时段发出的 100 封邮件,标题结构都一样、正文结构都一样、链接域名都一样,即使不是垃圾邮件也可能被判定为批量营销。
对策有三个:一是在提示词里引入轮换规则,比如让模型在 10 种不同开头中选择;二是每条客户记录里加入唯一字段,比如客户近期动态,让正文自然产生差异化;三是在发送时打散顺序,用随机延迟而不是固定间隔。还有个小技巧:邮件里不要放太多图片和链接,一封开发信最多一个链接,否则触发图片类垃圾邮件的概率非常高。
4.4 调用错误与工程踩坑
写脚本调用 API 时会遇到很多莫名其妙的报错,最常见的几个:rate limit 超限、上下文超长、tool payload 与 schema 不匹配。前两个好理解,最后一个常发生在你用 JSON Schema 时,模型返回了多余字段,或者把日期、价格写成了字符串而不是数字格式,于是 provider 直接拒绝。
我的建议是在循环外层套一层带重试和退避的封装。示例:
import time from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, max=10)) def generate_email_with_retry(row): resp = client.chat.completions.create( model="gpt-4o-mini", temperature=0.7, response_format={"type": "json_object"}, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": build_user_prompt(row)}, ], ) data = json.loads(resp.choices[0].message.content) if "subject" not in data or "body" not in data: raise ValueError("Missing subject or body") return data重试能解决一部分临时故障,但如果同一条记录连续失败,就不要硬磨,把它单独标记出来人工处理。批量运行时一定要写日志,否则几十条失败记录混在结果里,很容易漏看。对于“llm request failed: provider rejected the request schema or tool payload”这类错误,优先检查 response_format、工具定义和 JSON 字段名称,不要盲目重发。
4.5 别把系统提示词当成 Agent
我知道很多人在朋友圈刷到过“Agent 帮你自动开发客户、自动写邮件、自动跟进”之类的内容,但我建议在外贸开发信这个场景里,先不要贪多。Agent 会自己规划动作,意味着它可能去查一个你控制不了的信息源,可能乱调工具,可能在关键时候给你编一个 CRM 里的客户记录。表面是效率,实际是失控。
我更推荐把流程做成一个受控的“skill”:系统提示词固定角色,用户提示词输入客户数据,程序负责循环和校验。等你已经积累了足够多的成功样例,再逐步加入工具调用,让模型去查新闻、查客户官网。到那个阶段,你再可以讨论 Agent,但在冷开发信这类容错率很低的场景,人在环中永远是第一原则。
4.6 合规与隐私
最后一定要聊合规。外贸开发信本质上是 B2B 商业沟通,相对 C 端营销邮件宽松,但也不是可以随便群发。发送前确认收件读者是公司联系人;邮件里包含真实公司地址和清晰退订方式;不要购买来源不明的“精准邮箱列表”,特别是那种包含个人邮箱的名单。GDPR 与类 GDPR 法规对个人信息的使用有严格要求,如果客户要求删除数据,你需要有简单的处理流程。
合规的意义不仅是防止罚款,更是保护发件域名信誉。一旦你的域名被多个收件方标记为垃圾邮件,后面就算发再好的内容也进不了收件箱。所以,宁可每天少发 50 封,也不要为了“快速出量”把整个域名玩坏。
5. 关于这套流程的最后一句话
批量生成开发信这件事,真正做到位,靠的不是“找一个聪明模型”,而是把数据、提示词、人工审校这三件事串成一条流水线。数据决定了个性化上限,提示词决定了模型发挥稳定性,人工审校决定了最后一道安全网。我跑完几百封之后最大的体会是:把写作时间从一整天压缩到两小时,但压缩出来的时间不是用来玩的,而是用来仔细看那几十封最有潜力的客户回信。
还有一个我觉得很顺手的小技巧:不要一上来就让 LLM 写正文,先让它给你写 20 个邮件标题。因为收件人先看到的是标题,标题决定了正文有没有机会被打开。标题有购买力之后,再让模型按标题对应的角度生成正文,整体回复率会比直接生成正文高一截。这套玩法不需要额外工具,改一改提示词字段就行,值得大家试试。