我叫阿杰,是一名独立开发者。去年双十一我帮朋友运营的潮流电商社区 Discord 服务器遇到了大麻烦——促销日同时在线 3000 人,客服完全扛不住。我花了两个周末,用 HolyShehe AI 的 API 给服务器做了一个智能客服机器人,支持多轮对话上下文记忆,还能调用数据库查询订单、自动生成促销码。今天把完整方案分享出来,包含我踩过的坑和调试经验。
一、项目背景与方案选型
当时面临的核心问题是:
- 促销日人工客服响应延迟超过 3 分钟
- 80% 的问题都是重复的(查订单、退换货、优惠码)
- 用户需要跨平台切换(Discord 问完还要去小程序查)
我的解决方案是做一个 Discord AI 助手,核心需求:
需求清单:
├── 多轮对话:记住用户上一轮问过的商品
├── 工具调用:查订单、查库存、生成优惠码
├── 上下文管理:区分不同用户的会话
└── 成本控制:日均 5000 次调用,月预算 < ¥200
为什么选 HolyShehe AI?对比了一圈:
- 价格优势:DeepSeek V3.2 才 $0.42/MTok,GPT-4.1 要 $8/MTok,差了将近 20 倍
- 国内直连:延迟 < 50ms,不需要代理
- 充值方便:微信/支付宝直接充,汇率 ¥1=$1(官方要 ¥7.3=$1)
二、环境准备与项目初始化
先创建项目结构:
mkdir discord-ai-bot && cd discord-ai-bot
npm init -y
npm install discord.js openai-zod-functions dotenv
项目结构如下:
discord-ai-bot/
├── index.js # 主入口
├── services/
│ ├── chat.js # AI 对话服务
│ ├── tools.js # 工具函数定义
│ └── history.js # 会话历史管理
├── .env # 环境变量
└── package.json
三、HolyShehe AI API 接入配置
HolyShehe AI 的接口完全兼容 OpenAI 格式,改个 base_url 就行。立即注册 获取你的 API Key。
# .env 文件
DISCORD_TOKEN=你的Discord机器人Token
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
核心服务封装(services/chat.js):
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseURL: process.env.HOLYSHEEP_BASE_URL,
});
const MODEL = 'gpt-4.1'; // 支持 gpt-4.1 / claude-sonnet-4.5 / deepseek-v3.2
// 可用工具列表
const AVAILABLE_TOOLS = [
{
type: 'function',
function: {
name: 'query_order',
description: '查询用户订单状态',
parameters: {
type: 'object',
properties: {
order_id: { type: 'string', description: '订单ID' },
user_id: { type: 'string', description: '用户Discord ID' },
},
required: ['order_id'],
},
},
},
{
type: 'function',
function: {
name: 'generate_coupon',
description: '为用户生成限时优惠码',
parameters: {
type: 'object',
properties: {
discount_type: {
type: 'string',
enum: ['percentage', 'fixed'],
description: '折扣类型'
},
amount: { type: 'number', description: '折扣值' },
},
required: ['discount_type', 'amount'],
},
},
},
{
type: 'function',
function: {
name: 'check_stock',
description: '查询商品库存',
parameters: {
type: 'object',
properties: {
product_id: { type: 'string', description: '商品ID' },
},
required: ['product_id'],
},
},
},
];
async function chatWithAI(userId, messages) {
const response = await client.chat.completions.create({
model: MODEL,
messages: messages,
tools: AVAILABLE_TOOLS,
tool_choice: 'auto',
temperature: 0.7,
});
const assistantMessage = response.choices[0].message;
// 返回 token 使用量(用于成本计算)
const usage = {
input: response.usage.prompt_tokens,
output: response.usage.completion_tokens,
total: response.usage.total_tokens,
};
return { message: assistantMessage, usage };
}
module.exports = { chatWithAI, AVAILABLE_TOOLS };
四、工具调用函数实现
这里定义真正的业务逻辑(services/tools.js):
// 模拟数据库操作
const mockDatabase = {
orders: new Map(),
stock: new Map(),
coupons: new Map(),
};
// 初始化模拟数据
mockDatabase.stock.set('SNEAKER-001', { name: '限量球鞋', stock: 23 });
mockDatabase.stock.set('HOODIE-002', { name: '联名卫衣', stock: 156 });
async function queryOrder(orderId, userId) {
// 实际项目这里查数据库
const order = mockDatabase.orders.get(orderId);
if (!order) {
return {
success: false,
message: 未找到订单 ${orderId},请确认订单号是否正确。,
};
}
if (order.userId !== userId) {
return {
success: false,
message: '订单信息不匹配,请联系客服核实。',
};
}
return {
success: true,
order_id: order.id,
status: order.status,
amount: order.amount,
items: order.items,
create_time: order.createTime,
};
}
async function generateCoupon(discountType, amount) {
const code = PROMO${Date.now().toString(36).toUpperCase()};
mockDatabase.coupons.set(code, {
type: discountType,
amount: amount,
createTime: new Date().toISOString(),
});
const desc = discountType === 'percentage'
? ${amount}% 折扣
: ¥${amount} 直减;
return {
success: true,
coupon_code: code,
description: desc,
expire_time: '24小时后过期',
};
}
async function checkStock(productId) {
const product = mockDatabase.stock.get(productId);
if (!product) {
return {
success: false,
message: 未找到商品 ${productId},
};
}
return {
success: true,
product_id: productId,
product_name: product.name,
stock: product.stock,
available: product.stock > 0,
};
}
// 工具调度器
const TOOL_HANDLERS = {
query_order: queryOrder,
generate_coupon: generateCoupon,
check_stock: checkStock,
};
module.exports = { TOOL_HANDLERS };
五、会话历史管理
多轮对话的核心是上下文管理,我用的是内存 + 定期清理方案(services/history.js):
class ConversationHistory {
constructor(maxHistory = 20) {
this.history = new Map(); // userId -> messages[]
this.maxHistory = maxHistory;
}
getHistory(userId) {
if (!this.history.has(userId)) {
this.history.set(userId, []);
}
return this.history.get(userId);
}
addMessage(userId, role, content) {
const messages = this.getHistory(userId);
messages.push({ role, content, timestamp: Date.now() });
// 超过上限,删除最早的 5 条
if (messages.length > this.maxHistory) {
messages.splice(0, 5);
}
}
addSystemPrompt(userId, prompt) {
const messages = this.getHistory(userId);
// 确保系统提示在开头
const systemIndex = messages.findIndex(m => m.role === 'system');
if (systemIndex === -1) {
messages.unshift({ role: 'system', content: prompt, timestamp: Date.now() });
} else {
messages[systemIndex].content = prompt;
}
}
clearHistory(userId) {
this.history.delete(userId);
}
// 定时清理,释放内存
cleanup() {
const now = Date.now();
const MAX_AGE = 30 * 60 * 1000; // 30分钟无活动清理
for (const [userId, messages] of this.history.entries()) {
const lastMessage = messages[messages.length - 1];
if (lastMessage && (now - lastMessage.timestamp) > MAX_AGE) {
this.history.delete(userId);
}
}
}
}
module.exports = ConversationHistory;
六、主程序入口
整合所有模块(index.js):
require('dotenv').config();
const { Client, GatewayIntentBits } = require('discord.js');
const { chatWithAI, AVAILABLE_TOOLS } = require('./services/chat');
const { TOOL_HANDLERS } = require('./services/tools');
const ConversationHistory = require('./services/history');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
const conversationHistory = new ConversationHistory(20);
const MAX_TOOL_CALLS = 3; // 防止无限循环
client.once('ready', () => {
console.log(🤖 Bot 已上线: ${client.user.tag});
// 每10分钟清理过期会话
setInterval(() => conversationHistory.cleanup(), 10 * 60 * 1000);
});
client.on('messageCreate', async (message) => {
// 忽略机器人消息和 DM(可按需修改)
if (message.author.bot || !message.guild) return;
if (!message.content.startsWith('!ai ')) return;
const userId = message.author.id;
const userInput = message.content.slice(4).trim();
// 设置系统提示
if (!conversationHistory.getHistory(userId).find(m => m.role === 'system')) {
conversationHistory.addSystemPrompt(userId, `你是电商潮流社区的智能客服助手。
能力:查订单状态、查库存、生成优惠码。
风格:年轻、专业、简洁。
限制:不透露你是AI,不提供虚假信息。`);
}
// 添加用户消息
conversationHistory.addMessage(userId, 'user', userInput);
await message.channel.sendTyping();
try {
let messages = conversationHistory.getHistory(userId);
let toolCallCount = 0;
while (toolCallCount < MAX_TOOL_CALLS) {
const { message: aiMessage, usage } = await chatWithAI(userId, messages);
// 记录 AI 响应
messages.push(aiMessage);
conversationHistory.addMessage(userId, 'assistant',
typeof aiMessage.content === 'string'
? aiMessage.content
: JSON.stringify(aiMessage.content)
);
// 无工具调用,直接返回
if (!aiMessage.tool_calls || aiMessage.tool_calls.length === 0) {
await message.reply(aiMessage.content || '处理完成');
break;
}
// 执行工具调用
for (const toolCall of aiMessage.tool_calls) {
const toolName = toolCall.function.name;
const args = JSON.parse(toolCall.function.arguments);
console.log(🔧 执行工具: ${toolName}, args);
const handler = TOOL_HANDLERS[toolName];
if (!handler) {
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: 错误:未找到工具 ${toolName},
});
continue;
}
const result = await handler(...Object.values(args), userId);
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(result),
});
}
toolCallCount++;
}
// 超出工具调用限制
if (toolCallCount >= MAX_TOOL_CALLS) {
await message.reply('⚠️ 请求处理复杂,请稍后再试或联系人工客服。');
}
} catch (error) {
console.error('❌ 处理失败:', error);
await message.reply(⚠️ 系统错误:${error.message});
}
});
client.login(process.env.DISCORD_TOKEN);
七、部署与成本估算
我把这个 bot 部署在 2核1G 的学生机上,24小时运行。给大家算一笔账:
- DeepSeek V3.2:$0.42/MTok(output),日均 5000 次调用,平均每次 200 token 输出 → $0.42 × 1M × 1 = $0.42/天
- GPT-4.1:$8/MTok,同样场景 → $8/天,差了 19 倍
- HolyShehe AI 充值用微信/支付宝,汇率 ¥1=$1,实付不到 ¥3/天
促销日峰值可能到 2 万次调用,用 DeepSeek V3.2 也才 ¥12 左右,比雇一个临时客服便宜多了。
八、常见报错排查
这个项目我踩了三个大坑,记录一下:
错误1:401 Unauthorized - API Key 无效
# 错误日志
Error: 401 Unauthorized
{
"error": {
"message": "Invalid API key provided",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}
排查步骤
1. 检查 .env 文件是否正确加载
node -e "require('dotenv').config(); console.log(process.env.HOLYSHEEP_API_KEY)"
2. 确认 API Key 没有前后的空格
echo $HOLYSHEEP_API_KEY
3. 检查 base_url 是否正确(很多人漏掉这个)
应该是: https://api.holysheep.ai/v1
不是: https://api.holysheep.ai 或其他路径
错误2:429 Rate Limit - 请求频率超限
# 错误日志
Error: 429 Too Many Requests
{
"error": {
"message": "Rate limit exceeded for...",
"type": "rate_limit_error",
"retry_after": 5
}
}
解决方案:添加限流中间件
const rateLimiter = new Map();
const RATE_LIMIT = { maxRequests: 10, perSeconds: 60 };
async function checkRateLimit(userId) {
const now = Date.now();
const key = rateLimiter.get(userId) || { count: 0, resetAt: now + RATE_LIMIT.perSeconds * 1000 };
if (now > key.resetAt) {
key.count = 0;
key.resetAt = now + RATE_LIMIT.perSeconds * 1000;
}
key.count++;
rateLimiter.set(userId, key);
if (key.count > RATE_LIMIT.maxRequests) {
throw new Error(请求过于频繁,请 ${Math.ceil((key.resetAt - now) / 1000)} 秒后重试);
}
}
错误3:tool_call_id 为空导致死循环
# 问题现象
Bot 反复调用同一个工具,陷入死循环
根因
工具返回结果的 tool_call_id 没有正确传递给下一轮
修复代码
// 在添加工具结果时,确保包含 tool_call_id
messages.push({
role: 'tool',
tool_call_id: toolCall.id, // ← 这个字段必须有
content: JSON.stringify(result),
});
// 同时限制工具调用次数
const MAX_TOOL_CALLS = 3;
let toolCallCount = 0;
// 在循环开始处检查
if (++toolCallCount >= MAX_TOOL_CALLS) break;
错误4:上下文超出 token 限制
# 错误日志
Error: 400 Bad Request
{
"error": {
"message": "This model's maximum context length is 128000 tokens",
"type": "invalid_request_error",
"param": "messages",
"code": "context_length_exceeded"
}
}
解决方案:压缩历史消息
function compressHistory(messages, maxTokens = 60000) {
let totalTokens = 0;
const compressed = [];
// 从最新的消息往前遍历
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i];
const estimatedTokens = Math.ceil(msg.content.length / 4);
totalTokens += estimatedTokens;
if (totalTokens > maxTokens) break;
compressed.unshift(msg);
}
// 保留系统提示
const systemPrompt = messages.find(m => m.role === 'system');
return systemPrompt ? [systemPrompt, ...compressed] : compressed;
}
九、总结
这个方案帮我朋友把促销日客服响应时间从 3 分钟降到了 5 秒以内,同时减少了 70% 的人工干预。最关键的几点:
- 工具调用:让 AI 决定何时查询数据库,而不是把所有数据都塞给模型
- 历史管理:防止 token 爆炸,同时支持跨轮次的上下文
- 成本控制:选对模型很重要,DeepSeek V3.2 在非复杂场景下完全够用
HolyShehe AI 的国内直连和微信充值对我这种个人开发者特别友好,不用折腾信用卡和代理。建议先从免费额度开始测试,觉得 ok 再充值。
完整代码我放在 GitHub 了:holysheep/discord-ai-bot,有问题可以提 issue。