我花 7 天用 Vibe Coding 做了一个 AI 外贸数字员工
从询盘分类到报价草稿,完整记录 7 天里的架构决策、三次推倒重来,以及一个让我改掉整个设计的原则:确定性优先。
一句话结论
能用代码判断的,绝不交给模型。模型擅长措辞,不擅长把关。
第 1 天早上我给自己定了一个很具体的验收标准:
收到一封英文询盘邮件,系统能自动判断意图、查库存、生成一份不会报错的报价草稿, 并给出下一步跟进时间。
7 天后这个标准达到了。中间推倒重来三次,第三次重来才是真正的转折点。
第一天:先别写 Agent,先写数据流#
我一开始就想直接上 Agent 框架,写了半天发现根本不知道「好的输出」长什么样。
于是掉头,先手写了 20 条真实的询盘记录,人工标注了意图、优先级、需要的字段:
| 询盘原文片段 | 意图 | 优先级 | 缺失字段 |
|---|---|---|---|
| "Please quote 500pcs, need it by Nov" | 报价 | 高 | 产品型号 |
| "Are you a factory or trading company?" | 资质问询 | 低 | — |
| "Your price is too high, competitor offers..." | 议价 | 高 | 目标价 |
这 20 条成了后面所有决策的基准。没有标注数据之前,任何架构讨论都是空谈。
第二次重来:把 LLM 从「把关人」的位置上拿下来#
最初的版本是这样:询盘进来 → 丢给模型 → 模型判断意图、决定报价、生成回复。
结果误报率 12%。具体是三类错误:
- 低于底价的报价被放行——模型看到了底价,但没算对
- 库存不足时仍生成了可发货的措辞
- 客户在禁运名单上,模型完全没提
问题不在模型能力,在于我把需要精确计算的判断交给了概率系统。
改成三层结构:
第 1 层(代码):硬约束校验
- 报价 >= 底价
- 库存 >= 需求量
- 客户不在禁运名单
→ 任何一条不过,直接拦下,不进模型
第 2 层(模型):意图分类 + 措辞组织
- 读询盘,输出结构化意图
- 基于已校验的报价数字,组织邮件语言
第 3 层(代码):输出校验
- 从模型输出里提取所有数字
- 与第 1 层的计算结果比对
- 不一致则丢弃重生成误报率从 12% 降到 0。
这个改动是整个项目里最重要的一次。它让我意识到: Agent 设计的核心问题不是「怎么让模型更聪明」, 而是「怎么让模型只做它擅长的那部分」。
第 3 层的数字回验尤其关键。模型偶尔会在措辞里「顺手」改一个数字, 让它读起来更顺。这一层就是专门抓这个的:
function verifyNumbers(generated: string, facts: QuoteFacts): boolean {
// 抽出模型输出里所有形如 $1,234.56 / 500pcs 的数字
const mentioned = extractNumbers(generated);
const allowed = new Set([
facts.unitPrice.toFixed(2),
String(facts.quantity),
facts.totalPrice.toFixed(2),
String(facts.leadTimeDays),
]);
// 输出里出现的每个数字,都必须能在事实集合里找到
return mentioned.every((n) => allowed.has(n));
}第三次重来:用 MCP 替换硬编码工具#
工具涨到 9 个之后,注册表开始失控。每个工具都直接写在主流程里:
// 改造前:加一个工具要动主流程代码
const tools = [
classifyInquiry,
checkInventory,
getPriceFloor,
checkSanctions,
draftQuote,
scheduleFollowUp,
// ... 每加一个都要改这里,还要改类型定义
];问题有三个:
- 加工具必须改主流程,风险高
- 工具和主流程共享进程,一个工具卡住全卡住
- 没法单独测试某个工具
迁到 MCP 之后,工具变成可独立部署的服务,主流程只认协议:
// 改造后:工具通过 MCP 协议接入,主流程完全不知道有几个工具
const client = new Client({ name: "quote-agent", version: "1.0.0" });
await client.connect(new StdioTransport({ command: "inventory-server" }));
const tools = await client.listTools();
// 加工具 = 加一个 server,主流程一行不用改迁移成本大概是两天。收益在第二周就回来了:加了 4 个新工具,主流程代码零改动。
第 7 天:最终形态#
询盘邮件
│
├─► [代码] 硬约束层 ── 不过 ──► 人工队列
│ 报价底线 / 库存 / 合规
│
├─► [模型] 意图分类 ──► 结构化 JSON
│
├─► [MCP] 工具调用
│ 库存查询 / 价格计算 / 历史成交
│
├─► [模型] 生成报价草稿
│
├─► [代码] 数字回验 ── 不一致 ──► 丢弃重生成
│
└─► 草稿进入人工确认队列注意最后一步:草稿进的是人工确认队列,不是直接发出。
这一点我犹豫过。全自动的演示效果好得多,但我不信任它。 现在这个版本的正确用法是:业务员早上花 15 分钟过一遍草稿, 改几处措辞,点发送。相比从零写,省下的时间大概是 70%。
现在还不能做什么#
诚实清单:
- 议价环节完全无法放手。 涉及价格谈判必须人工。模型不懂「这个客户去年下了三个柜」这种上下文。
- 多 Agent 之间的上下文传递有信息衰减。 我试过拆成「询盘 Agent + 报价 Agent + 跟进 Agent」,结果是每个 Agent 都要重新理解一遍客户背景,反而更慢。现在退回单 Agent + 多工具。
- 非英语询盘的分类质量不稳定。 西班牙语和阿拉伯语的意图识别准确率明显低于英语,需要人工兜底。
七天的时间分配#
| 阶段 | 天数 | 实际产出 |
|---|---|---|
| 标注 20 条真实数据 | 0.5 | 后面所有决策的基准 |
| 第一次实现(失败) | 1.5 | 发现模型不能当把关人 |
| 三层结构重构 | 2 | 误报率 12% → 0% |
| MCP 工具层迁移 | 2 | 工具可独立部署 |
| 收尾与人工流程对接 | 1 | 可用的东西 |
如果用传统方式写,我估计要三周。Vibe Coding 省下的时间主要在两处: 写样板代码(数据库层、API 路由、类型定义)和调试(把报错直接丢给它)。
但省不掉的恰恰是最重要的那部分:决定什么该交给模型、什么不该。 这个判断只能自己下,而且下错了要推倒重来。
项目现在还在迭代。架构图和 MCP 工具层的设计我在 AI Digital Employee 项目页 里持续更新。