介绍
通过MCP 配置deepseek 调用自定义接口实现
ai 自然语言识别动作,智能操作与回复
# 🎏 使用场景
# 某电商平台客服部门每天收到大量用户询问订单物流信息的咨询,这类问题占客服工作量的60%以上。为了提高客服处理效率,降低人工成本,需要设计一个AI Agent系统来自动处理用户的物流查询请求。
# 实现逻辑
# 拿到客户输入的自然语言查询,调用deepseek大模型提取订单号
# 如果有订单号,就直接调用物流API获取物流数据 并交给deepseek 润色智能建议回复
# 如果没有订单号,就直接调用DeepSeek的聊天模型根据自然语言生成智能回复
# 实现技术
# 通过node js 配置MCP,接入deepseek 实现智能服务
# 开始前,确保你已准备好:
# Node.js环境:v16.0.0或更⾼版本
# 代码编辑器:VS Code、Sublime Text等任意编辑器
# Cline应⽤:⽀持MCP协议的AI应⽤,
# ⽤于测试服务基础JavaScript知识:能看懂简单代码即
# 创建项⽬⽂件夹
mkdir weather-mcp-server
cd weather-mcp-server
# 初始化npm项⽬npm init -y
# 步骤2:创建package.json
{
"name": "order-mcp-server",
"version": "1.0.0",
"description": "基于订单物流api的MCP服务",
"main": "order-server.js",
"type": "module",
"scripts": {
"start": "node order-server.js",
"dev": "nodemon order-server.js"
},
"keywords": [
"mcp",
"order",
"ai",
"claude",
"cline",
"meizu"
],
"author": "yingzi",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.17.3",
"axios": "^1.11.0",
"dotenv": "^17.2.1",
"express": "^5.1.0",
"node-fetch": "^3.3.2",
"openai": "^5.12.2",
"zod": "^3.25.76"
},
"devDependencies": {
"mockjs": "^1.1.0",
"moment": "^2.30.1",
"nodemon": "^3.0.3"
}
}
注意事项: "type": "module" 是必须的,它让我们可以使⽤现代ES模块语法。
# 步骤3:安装依赖
npm install
# 步骤4:在项⽬根⽬录创建⽂件 demo-server.js
// 导入核心模块
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // MCP服务器核心
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // MCP标准I/O传输
import axios from 'axios'; // HTTP客户端
import express from 'express'; // Web服务器框架
import dotenv from 'dotenv'; // 环境变量管理
import { z } from 'zod'; // 数据验证
import OpenAI from "openai"; //接入deepseek
//逻辑
// 拿到客户输入的自然语言查询,调用deepseek的NLP模型提取订单号
// 如果有订单号,就直接调用物流API获取物流数据
// 如果没有订单号,就直接调用DeepSeek的聊天模型生成回复
// 初始化环境变量 // 获取对应的deepseek 的key, 自行在跟目录创建.env 文件
dotenv.config();
console.log("DeepSeek API Key:", process.env.DEEPSEEK_API_KEY ? "已配置" : "未配置");
// 创建OpenAI客户端(配置为使用DeepSeek)
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com/v1',
timeout: 10000, // 设置超时时间为10秒
apiKey: process.env.DEEPSEEK_API_KEY,
defaultHeaders: {
"Content-Type": "application/json"
}
});
// 创建Express应用和MCP服务器
const app = express();
const server = new McpServer({
name: 'logistics-mcp',
version: '1.2.0',
description: '基于DeepSeek的智能物流查询服务'
});
// 中间件配置
app.use(express.json()); // 解析JSON请求体
/**
* 提取订单号 - 使用DeepSeek NLP
* @param {string} text 用户输入文本
* @returns {Promise<string|null>} 订单号或null
*/
const extractOrderId = async (text) => {
try {
const completion = await openai.chat.completions.create({
model: "deepseek-chat",
messages: [
{
role: "system",
content: `你是订单信息提取助手。请从用户输入中识别并提取订单号。
订单号特征:
- 通常由字母和数字组成
- 长度通常在6-18个字符之间
- 可能包含"订单"、"单号"等前缀
- 只要满足以上条件的重叠的数字都是订单号
回复格式要求:
- 如果找到订单号,直接返回订单号字符串
- 如果没有找到,返回"null"`
},
{
role: "user",
content: text
}
],
temperature: 0.2,
max_tokens: 20
});
const orderId = completion.choices[0].message.content.trim();
// 验证提取结果
if (orderId === "null" || !orderId || orderId.toLowerCase() === "not found") {
return null;
}
// 提取纯订单号(移除可能的前缀)
const match = orderId.match(/(?:订单[号]?[::]?\s*)?([A-Z0-9]{6,18})/i);
return match ? match[1].toUpperCase() : null;
} catch (error) {
console.error('订单提取失败:', error.message);
return null;
}
};
/**
* 获取物流数据 - 调用物流API
* @param {string} orderId 订单号
* @returns {Promise<Object>} 物流数据
*/
const fetchLogisticsData = async (orderId) => {
const API_URL = process.env.LOGISTICS_API_URL || 'http://localhost:3003/api/logistics';
try {
const response = await axios.get(API_URL, {
params: { orderId: orderId }, // 注意参数名是 order_id
timeout: 5000
});
if (response.data.code !== 200) {
throw new Error(response.data.message || '物流查询失败' + orderId);
}
const logisticsData = response.data.data;
return logisticsData;
} catch (error) {
console.error(`物流API调用失败 没有这个订单号[${orderId}]:`, error.message);
throw new Error(`物流查询失败没有这个订单号${orderId}: ${error.response?.data?.message || error.message}`);
}
};
/**
* 生成物流智能回复 - 使用DeepSeek聊天模型
* @param {Object} logisticsData 物流数据
* @param {string} orderId 订单号
* @returns {Promise<string>} 友好回复文本
*/
const generateResponse = async (logisticsData, orderId) => {
try {
// 使用OpenAI SDK生成回复
const completion = await openai.chat.completions.create({
model: "deepseek-chat",
messages: [
{
role: "system",
content: `你是物流客服助手,请用友好中文回复物流查询。要求:
1. 开头用表情符号吸引注意
2. 清晰展示当前状态
3. 提供最新1-3条物流轨迹
4. 状态异常时提供解决方案
5. 结尾添加祝福语`
},
{
role: "user",
content: `请回复以下物流信息:
订单号: ${logisticsData.order_id}
当前快递: ${logisticsData.logistics.logistics_company}
当前状态: ${logisticsData.order_status}
物流轨迹: ${logisticsData.logistics.tracking_info?.join(" → ") || "无"}
预计送达: ${logisticsData.estimatedDelivery || "未知"}
异常信息: ${logisticsData.logistics.estimated_delivery || "无"}
请提供:
1. 当前状态的简单解释
2. 预计送达时间的评估
3. 需要注意的问题(如果有)`
}
],
temperature: 0.7,
max_tokens: 500
});
console.log('生成回复成功:', completion.choices[0].message.content);
return completion.choices[0].message.content;
} catch (error) {
console.error('回复生成失败:', error.message);
// 降级方案:手动构造基础回复
const latest = logisticsData.logistics.tracking_info[0] || {};
return `📦 您的订单 ${orderId} 物流信息:
产品: ${logisticsData.product_name}
状态: ${logisticsData.logistics.current_status}
快递: ${logisticsData.logistics.logistics_company} (${logisticsData.logistics.tracking_number})
最新动态: ${latest.time || ''} ${latest.description || '暂无更新'}`;
}
};
/**
* 生成自然语言智能回复 - 使用DeepSeek聊天模型
* @param {string} user_query 非订单号的自然语言查询
* @returns {Promise<string>} 友好回复文本
*/
const deepseekChatResponse = async (user_query) => {
try {
const completion = await openai.chat.completions.create({
model: "deepseek-chat",
messages: [
{
role: "system",
content: `你是物流客服助手,请用友好中文回复关于订单查询的信息。要求:
1. 询问快递,需要让客户提供订单号
2. 根据语义分析用户查询
3. 如果查询中包含订单号,直接返回相关信息
4. 状态异常时提供解决方案
5. 查询到达时间,需要让客户提供订单号
6. 结尾添加祝福语`
},
{
role: "user",
content: user_query
}
],
temperature: 0.2,
max_tokens: 20
});
console.log('生成回复成功:', completion, completion.choices[0].message.content);
return completion.choices[0].message.content;
} catch (error) {
console.error('回复生成失败:', error.message);
return error.message;
}
};
/**
* 处理错误 - 生成用户友好回复
* @param {Error} error 错误对象
* @returns {string} 友好错误回复
*/
const handleError = (error) => {
// 常见错误映射
const errorMap = {
'订单不存在': '🔍 抱歉,找不到该订单,请确认订单号是否正确',
'网络请求超时': '⏱ 查询超时,请稍后再试',
'物流查询失败': '⚠️ 暂时无法获取物流信息,请提供正确订单号或稍后再试',
'无效的订单号': '❌ 您提供的订单号格式不正确',
'not found': '🔍 订单不存在,请检查订单号'
};
// 检查是否有预定义的错误消息
for (const [key, message] of Object.entries(errorMap)) {
if (error.message.includes(key)) {
return message;
}
}
// 默认错误消息
return `🙏 抱歉,处理您的请求时出错: ${error.message.split(':')[0]}`;
};
/**
* 物流查询核心处理函数 识别是否调用物流还是直接ai 回复
* @param {Object} params 查询参数
* @param {string} [params.user_query] 用户自然语言查询
* @param {string} [params.order_id] 直接提供的订单号
* @returns {Promise<Object>} 查询结果
*/
const logisticsHandler = async ({ user_query }) => {
try {
// 提取订单号如果是unll 表示没有单号,那么就原文发给 DeepSeek
let orderId = await extractOrderId(user_query);
console.log('接受值:', { user_query, orderId });
let logisticsData = user_query
let responseText = ''
if (orderId) { //如果有订单号
console.log('有id:', { orderId });
// 获取物流数据
logisticsData = await fetchLogisticsData(orderId);
console.log('物流数据获取成功', logisticsData);
// 生成智能回复
responseText = await generateResponse(logisticsData, orderId);
} else {
console.log('没有id:', { orderId });
// 自然语言生成智能回复
responseText = await deepseekChatResponse(user_query)
}
return {
content: [{
type: 'text',
text: responseText
}],
};
} catch (error) {
console.error('物流查询错误:', error.message);
return {
content: [{
type: 'text',
text: handleError(error)
}],
isError: true
};
}
};
// 注册物流查询工具到MCP
server.tool(
'query_logistics',
{
user_query: z.string().optional().describe('用户自然语言查询'),
order_id: z.string().optional().describe('直接提供的订单号')
},
logisticsHandler
);
// 配置HTTP路由 可以直接调用 接口api的方式测试
app.post('/query', async (req, res) => {
try {
const { user_query, order_id } = req.body;
console.log('收到查询请求:', { user_query, order_id });
// 验证请求参数
if (!user_query && !order_id) {
return res.status(400).json({
error: '无效请求',
message: '必须提供 user_query 或 order_id'
});
}
// 处理请求
const result = await logisticsHandler({ user_query, order_id });
// 返回结果
res.json(result);
} catch (error) {
console.error('服务器错误:', error);
res.status(500).json({
error: '服务器内部错误',
message: error.message
});
}
});
// 健康检查路由
app.get('/health', (req, res) => {
res.json({
status: 'ok',
version: '1.2.0',
services: {
deepseek: !!process.env.DEEPSEEK_API_KEY,
logistics_api: process.env.LOGISTICS_API_URL || 'default'
}
});
});
// 配置MCP传输层
const transport = new StdioServerTransport();
// 启动HTTP服务器
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`🚀 HTTP服务已启动: http://localhost:${PORT}`);
console.log(`🔧 DeepSeek API: ${process.env.DEEPSEEK_API_KEY ? '已配置' : '未配置!'}`);
console.log(`🔧 物流API: ${process.env.LOGISTICS_API_URL || '使用默认地址'}`);
});
// 连接MCP服务器
server.connect(transport)
.then(() => console.log('✅ MCP服务已连接'))
.catch(error => console.error('❌ MCP连接失败:', error));
# 步骤5:获取对应的deepseek 的key, 自行在跟目录创建.env 文件
# DeepSeek API配置
DEEPSEEK_API_KEY= key
# 本地物流API配置
LOGISTICS_API_URL=http://localhost:3003/api/logistics
# MCP服务地址
MCP_SERVER_URL=http://localhost:3000/mcp
PORT=3002
# 步骤6:通过mockjs 生成 测试数据物流api mock-server.js
import Mock from 'mockjs';
import express from "express";
const app = express();
const port = 3003;
// 模拟用户数据接口
app.get('/api/logistics', (req, res) => {
let ORDER_MAP ={
"2024081301003": "2024081301003",
"2024081301002": "2024081301002",
"2024081301001": "2024081301001",
"12345678": "12345678",
}
let orderID = req.query.orderId || "";
let order_id = ORDER_MAP[orderID];
console.log(order_id)
if (!order_id) {
const data = [{
code:500,
message: `订单不存在`
}];
res.json(data);
}else{
// 生成随机数据
const data = Mock.mock({
code:200,
data:{
"order_id": order_id,
"user_phone": "1366688" + Mock.mock(/\d{4}/),
"product_name": Mock.mock('@pick(["小米14 Ultra 16GB+1TB 白色","iPhone 15 Pro Max 256GB","华为Mate 60 Pro+"])'),
"user_name": Mock.mock('@cname'),
"order_amount": Mock.mock('@float(1000, 10000, 2, 2)'),
"order_status": Mock.mock('@pick(["已发货","配送中","派送异常","已签收"])'),
"create_time": Mock.mock('@datetime("yyyy-MM-dd HH:mm:ss")'),
"logistics": {
"tracking_number": Mock.mock('@pick(["ZTO","SF","STO","YTO"])') + Mock.mock(/\d{10}/),
"logistics_company": Mock.mock('@pick(["中通快递","顺丰速运","申通快递","圆通速递"])'),
"current_status": Mock.mock('@pick(["已发货","配送中","派送异常","已签收"])'),
"estimated_delivery": Mock.mock('@datetime("yyyy-MM-dd HH:mm:ss")'),
"description": function() {
const statusDesc = {
"已揽收": "快递员已揽收包裹",
"运输中": "包裹正在运输途中",
"到达转运中心": "包裹已到达" + this.location + "转运中心",
"派送中": "快递员" + Mock.mock('@cname') + "正在派送",
"派送异常": "派送失败:" + "未知原因",
"已签收": "包裹已被" + Mock.mock('@pick(["本人签收","代收点签收","家人签收"])')
};
return statusDesc[this.status];
},
'tracking_info|2': [
{
"time": Mock.mock('@datetime("yyyy-MM-dd HH:mm:ss")'),
"location": Mock.mock('@county(true)'),
"status|1": ["已揽收","运输中","到达转运中心","派送中","派送异常","已签收"],
"description": "派送失败:收件人地址不详,请联系客服更新地址信息",
}
]
}
}
});
res.json(data);
}
});
app.listen(port, () => {
console.log('虚拟数据服务已启动,监听端口: '+port);
console.log('测试URL: http://localhost:'+port+'/api/logistics?orderId=2024081301001');
});
# 以上步骤完成就可以通过vscode 或者cursor的cline 插件就可以直接测试了
运行服务 node demo-server.js
运行测试接口 node mock-server.js
# 在cline里面导入
{
"mcpServers": {
"order-mcp": {
"autoApprove": [],
"disabled": false,
"timeout": 60,
"type": "stdio",
"command": "node",
"args": [
"E:/objectArr/aiDemo/mcp-orderServer-demo/demo-server.js"
]
"env": {
"DEEPSEEK_API_KEY": ""
}
}
}
}
# 在vue中可以直接使用axios调用
# 或者 node服务命令行调用测试
# 新建test-client.js
import axios from 'axios';
import readline from 'readline';
// 创建readline接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
class LogisticsClient {
constructor() {
this.conversationId = null;
}
async query(text) {
try {
const response = await axios.post('http://localhost:3002/query', {
user_query: text,
conversation_id: this.conversationId
});
this.conversationId = response.data.conversation_id;
return response.data;
} catch (error) {
console.error('请求失败:', error.message);
throw error;
}
}
async prompt(question) {
return new Promise((resolve) => {
rl.question(question, resolve);
});
}
async start() {
console.log('物流查询系统 (输入"exit"退出)\n');
while (true) {
try {
const text = await this.prompt('您: ');
if (text.toLowerCase() === 'exit') break;
const result = await this.query(text);
console.log('助手:', result.content[0].text);
if (result.requiresFollowUp) {
const followUp = await this.prompt('请提供订单号: ');
const finalResult = await this.query(followUp);
console.log('助手:', finalResult.content[0].text);
}
} catch (error) {
console.error('处理出错:', error.message);
}
}
rl.close();
console.log('感谢使用物流查询系统');
}
}
// 启动客户端
const client = new LogisticsClient();
client.start().catch(err => {
console.error('客户端运行出错:', err);
process.exit(1);
});
运行 node test-client.js
ok 以上mcp demo已经完成
