当ERP遇上DeepSeek:飞书机器人智能问答的落地实践
一、为什么要在ERP里塞一个大模型?
一、为什么要在ERP里塞一个大模型?
做销售生产ERP那会儿,系统功能越堆越多:录订单、查库存、审流程、看报表……每个操作都要翻菜单、点按钮。
运营的同事跟我吐槽:"我就想查个昨天的订单数,至于要点N次鼠标吗?"
这句话点醒了我。ERP功能再多,如果交互门槛高,用户就不爱用。
于是我决定搞一个飞书机器人,背后接上DeepSeek大模型——用户在飞书里用自然语言问一句,机器人听懂意图、识别参数、调接口、返回结果。
二、整体架构
飞书群聊 ──WebSocket──▶ Node.js Bot ◀──HTTP──▶ DeepSeek LLM
│
▼
意图解析 + 函数调用
│
▼
┌─────────┴─────────┐
│ │
Spring Boot API 本地SQLite
(订单/库存/审批) (查询即读)
技术栈: - 飞书开放平台 + 长连接 WebSocket 接收消息 - Node.js Express 作为 Bot 服务(端口 3001) - DeepSeek Chat API 做意图解析和参数提取 - Spring Boot(端口 8080)提供业务 REST API - SQLite 存储结构化业务数据
三、核心思路:用 Function Calling 代替硬编码意图识别
一开始我想自己写意图分类——正则匹配、关键词词典,搞了一周发现:
- "查昨天的订单" 和 "昨天卖了多少钱" 本质是同一个意图,但写法变一下就匹配不上
- 用户说"帮我看看张三最近三天下了哪些单",我人麻了
后来换了一种思路:把所有 ERP 操作封装成函数描述,交给 DeepSeek 去判断该调哪个、参数是什么。
// 定义可用的 "工具" 列表
const tools = [
{
type: "function",
function: {
name: "query_orders",
description: "查询订单列表,可按时间范围、客户名筛选",
parameters: {
type: "object",
properties: {
start_date: { type: "string", description: "开始日期,如 2026-07-01" },
end_date: { type: "string", description: "结束日期,如 2026-07-03" },
customer: { type: "string", description: "客户姓名,可选" },
status: { type: "string", enum: ["待审核", "已通过", "已发货"], description: "订单状态" },
},
required: ["start_date", "end_date"]
}
}
},
{
type: "function",
function: {
name: "query_inventory",
description: "查询商品库存信息",
parameters: {
type: "object",
properties: {
product_name: { type: "string", description: "商品名称,支持模糊匹配" },
},
required: ["product_name"]
}
}
},
{
type: "function",
function: {
name: "approve_order",
description: "审批订单",
parameters: {
type: "object",
properties: {
order_id: { type: "string", description: "订单编号" },
action: { type: "string", enum: ["通过", "驳回"], description: "审批动作" },
comment: { type: "string", description: "审批意见,可选" },
},
required: ["order_id", "action"]
}
}
}
];
四、消息处理流程
收到飞书消息后,处理链路如下:
async function handleMessage(userText, userId) {
// Step 1: 调用 DeepSeek,传入工具定义
const llmResponse = await callDeepSeek([
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: userText }
], tools);
// Step 2: DeepSeek 返回 tool_calls,告诉我们要调哪个函数
const toolCall = llmResponse.choices[0].message.tool_calls[0];
const fnName = toolCall.function.name;
const fnArgs = JSON.parse(toolCall.function.arguments);
// Step 3: 执行对应函数,调用 Spring Boot API
let result;
switch (fnName) {
case "query_orders":
result = await springApi.getOrders(fnArgs);
break;
case "query_inventory":
result = await springApi.getInventory(fnArgs);
break;
case "approve_order":
result = await springApi.approveOrder(fnArgs);
break;
default:
return "抱歉,这个操作我暂时还不支持";
}
// Step 4: 把原始结果再喂给 DeepSeek,让它用自然语言组织回复
const finalResponse = await callDeepSeek([
{ role: "system", content: "你是ERP助手,用简洁的中文把查询结果告诉用户" },
{ role: "user", content: `原始问题:${userText}
查询结果:${JSON.stringify(result)}` }
], []);
return finalResponse.choices[0].message.content;
}
五、让 DeepSeek 理解业务上下文
纯靠 Function Calling 还不够——DeepSeek 不知道你的业务术语。
比如用户说"张三的待审单子",DeepSeek 需要知道: - "待审" → status = "待审核" - "单子" → 查订单表
我的做法:在 System Prompt 里注入业务知识。
const SYSTEM_PROMPT = `你是销售生产ERP系统的智能助手。系统中有以下业务概念:
【订单状态流转】
待审核 → 已通过 → 已发货 → 已完成
(驳回则回到待审核)
【商品名称别名】
- "爱普生打印机" = "EPSON L3251"
- "A4纸" = "得力A4复印纸 70g"
【时间表述理解】
- "昨天" = 当前日期前一天
- "本周" = 周一至今天
- "最近三天" = 当前日期往前推3天
- "上月" = 上个月1号至最后一天
当前日期:${new Date().toISOString().slice(0, 10)}
请根据用户输入判断意图,选择合适的函数并提取参数。`;
这样 DeepSeek 就能把"查查张三最近三天有没有待审的单子"正确解析为:
{
"name": "query_orders",
"arguments": {
"start_date": "2026-07-01",
"end_date": "2026-07-04",
"customer": "张三",
"status": "待审核"
}
}
六、踩过的坑
坑1:时间解析容易出错
DeepSeek 偶尔会把"下周"理解成"下下周",特别是周一的时候。后来我在 System Prompt 里把日期写死(当前日期固定注入),准确率高了很多。
坑2:函数返回数据量太大
有一次用户问"今年卖了哪些货",结果返回 2000 多条记录,DeepSeek 的 context 直接飙到 20K token,回复也要好几秒。
解决方法:在业务层做数据聚合,只返回摘要。比如不返回逐条订单,返回"2026年共 312 笔订单,总金额 ¥847,200"。
坑3:飞书消息 5 秒超时
飞书机器人回复消息有 5 秒超时限制。LLM 调用 + 业务查询经常超过 5 秒。
解决方法:先回复"正在查询,请稍候...",然后异步处理,结果通过飞书"回复消息"接口发回去。用户体感不卡。
// 先快速回复
await feishuApi.replyMessage(msgId, "正在查询,请稍候...");
// 异步处理
setTimeout(async () => {
const answer = await handleMessage(userText, userId);
await feishuApi.replyMessage(msgId, answer);
}, 100);
七、效果与感受
上线跑了一个月,最大的变化是:运营和销售开始主动在飞书群里问数据了。
以前他们要看报表得打开网页、登录系统、选筛选条件——三步走,很多人嫌麻烦。
现在飞书里打一行字:"昨天卖了多少",秒出结果。
几点体会:
- Function Calling 比写死意图识别好太多——维护成本几乎是零,新增功能只需要加一个函数描述
- System Prompt 就是你的"业务词典"——花时间写好它,比调模型参数管用
- 异步回复是刚需——别指望 LLM 能在 5 秒内完成全链路
- 数据要提前聚合——不要直接把几千行数据扔给 LLM,它不是你家的数据仓库
这套方案代码量不大、改造成本低,适合中小团队的 ERP / 内部工具快速接入 AI 能力。如果你也在搞类似的东西,欢迎交流。

浙公网安备 33010602011771号