触发器
触发器提供自定义的LLM触发时机,除了群聊中通过at或前缀、伪人机制等方式主动触发外,也可以自定义触发时机和处理逻辑。触发器可以在特定时间或事件发生时自动执行,并通过LLM生成相应内容发送给指定目标。
Chaite提供了以下几种基本触发器类型:
- BaseTrigger:所有触发器的基类,提供基本功能
- CronTrigger:基于定时表达式的触发器,可在特定时间点触发
- EventTrigger:基于事件的触发器,响应特定事件发生
定时触发器示例
Section titled “定时触发器示例”定时触发器可以按照设定的时间规则自动执行,例如每天、每小时或特定时间点:
import { Chaite, CronTrigger } from 'chaite'
class HourlyReminderTrigger extends CronTrigger { constructor () { super({ name: '整点报时', description: '每小时整点时在指定群组发送报时消息', cronExpression: '0 * * * *' // 每小时的0分触发 }) }
async execute (context) { try { // 获取当前时间 const currentTime = new Date() const hour = currentTime.getHours() const formattedTime = currentTime.toLocaleTimeString('zh-CN', { hour12: false, timeZone: 'Asia/Shanghai' // 假设使用中国标准时间,可以根据需要调整 })
// 构建要发送给 LLM 的消息,请求生成报时内容 const message = { role: 'user', content: [{ type: 'text', text: `现在是 ${formattedTime},请生成一句简短的整点报时消息,语气友好且自然。` }] }
// 查询 LLM 生成报时消息 const preset = await Chaite.getInstance().getChatPresetManager()?.getInstance('m8fpmwy2xabuxhkmbyr') const response = await this.queryLLM(message, { chatPreset: preset }) const reminderText = response.contents[0].text
// 发送报时消息到指定群组 const GROUP_ID = '1040690625' Bot.pickGroup(GROUP_ID).sendMsg(reminderText) logger.info(`已发送整点报时消息到群组 ${GROUP_ID},时间: ${formattedTime}`) } catch (error) { logger.error('发送整点报时消息时出错:', error) } }}
export default new HourlyReminderTrigger()
import { CronTrigger } from 'chaite'
class DailyReminderTrigger extends CronTrigger { constructor () { super({ name: '每日早安问候', description: '每天早上8点向指定群组发送早安问候', cronExpression: '0 8 * * *' // 每天早上8点触发 }) }
async execute (context) { try { // 获取当前日期 const today = new Date() const dateString = today.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' })
// 构建LLM请求 const message = { role: 'user', content: [{ type: 'text', text: `今天是${dateString},请生成一条温馨的早安问候,内容中包含今日日期,以及简短的积极鼓励。` }] }
// 查询LLM生成内容 const response = await this.queryLLM(message, { model: 'gpt-3.5-turbo' }) const greetingText = response.contents[0].text
// 发送到群组 const TARGET_GROUPS = ['123456789', '987654321'] // 目标群组ID列表
for (const groupId of TARGET_GROUPS) { try { await Bot.pickGroup(groupId).sendMsg(greetingText) logger.info(`已向群组 ${groupId} 发送早安问候`) } catch (err) { logger.error(`向群组 ${groupId} 发送消息失败:`, err) } } } catch (error) { logger.error('执行每日问候触发器时出错:', error) } }}
export default new DailyReminderTrigger()
事件触发器示例
Section titled “事件触发器示例”事件触发器会在特定事件发生时执行,例如群组消息、好友请求或其他系统事件。注意在Miao-Yunzai、TRSS-Yunzai以及Karin中关于Bot的定义各不相同,需要用户根据使用的框架自行编写对应逻辑代码。
import { BaseTrigger } from 'chaite'
class GroupRequestTrigger extends BaseTrigger { constructor (params = {}) { super({ name: '群组申请通知', isOneTime: params.isOneTime || false // 是否为一次性触发器,默认 false }) this.bot = null this.isRegistered = false this.eventHandler = this.handleGroupRequestEvent.bind(this) }
/** * 实现注册方法 */ async registerImpl (context) { if (this.isRegistered) return this.bot = Bot // 假设 Bot 实例全局可用 if (!this.bot) { logger.error(`触发器 ${this.name} 注册失败:找不到 Bot 实例`) return } // 注册群组申请事件监听 this.bot.on('request.group', this.eventHandler) this.isRegistered = true logger.info(`触发器 ${this.name} 已注册,监听群组申请事件`) }
/** * 实现注销方法 */ async unregisterImpl () { if (!this.isRegistered || !this.bot) return this.bot.off('request.group', this.eventHandler) this.isRegistered = false logger.info(`触发器 ${this.name} 已注销`) }
/** * 处理群组申请事件 */ async handleGroupRequestEvent (event) { // 使用 triggerAction 确保一次性触发器的自动清理 await this.triggerAction(async () => { try { logger.info('收到群组申请事件:', JSON.stringify(event, null, 2)) // 获取群组实例 const groupId = event.group_id // 假设事件中包含 group_id 字段 const group = this.bot.pickGroup(groupId) if (!group) { logger.error(`无法找到群组 ${groupId}`) return }
// 获取申请者详细信息(如果事件中包含 user_id) let userInfo = null if (event.user_id) { try { userInfo = Bot.gml.get(groupId).get(event.user_id, false) logger.info(`获取申请者信息 (ID: ${event.user_id}):`, userInfo) } catch (error) { logger.error(`获取申请者信息 (ID: ${event.user_id}) 失败: ${error.message}`) } }
// 构建补充信息对象 const enrichedEvent = { ...event, user_details: userInfo || { error: '无法获取申请者信息' } }
// 将事件及补充信息转换为字符串,发送给 LLM const eventJson = JSON.stringify(enrichedEvent, null, 2) const userMessage = { role: 'user', content: [{ type: 'text', text: `收到一个群组申请事件,请根据以下事件内容生成一段简短的提醒消息,提醒管理员尽快处理,语气自然且友好:\n\n${eventJson}` }] }
// 调用 LLM 获取提醒内容 const response = await this.queryLLM(userMessage, { model: 'gpt-4.1' }) if (response.contents && response.contents.length > 0) { const reminderText = response.contents[0].text if (groupId) { await group.sendMsg(reminderText) logger.info(`已向群组 ${groupId} 发送申请处理提醒消息`) } else { logger.error('事件中未找到 group_id,无法发送提醒消息') } } else { logger.error('生成提醒内容失败:LLM 返回内容为空') if (groupId) { await group.sendMsg('处理群组申请事件时发生错误,无法提醒。') } } } catch (error) { logger.error(`处理群组申请事件失败: ${error.message}`) const groupId = event.group_id if (groupId) { const group = this.bot.pickGroup(groupId) if (group) { await group.sendMsg('处理群组申请事件时发生错误,无法提醒。') } } } }) }}
export default new GroupRequestTrigger()
一次性触发器
Section titled “一次性触发器”触发器可以设置为一次性,触发后会自动销毁:
import { CronTrigger } from 'chaite'
class OneTimeTrigger extends CronTrigger { constructor () { super({ name: '一次性提醒', description: '在特定时间点执行一次后自动销毁', cronExpression: '30 12 * * *', // 每天12:30触发 isOneTime: true // 设置为一次性触发器 }) }
async execute (context) { try { // 执行一次性任务 const message = { role: 'user', content: [{ type: 'text', text: '请生成一条特别的通知消息,提醒用户这是一条一次性通知,不会再次发送。' }] }
const response = await this.queryLLM(message, { model: 'gpt-3.5-turbo' }) const notificationText = response.contents[0].text
// 发送到指定目标 const TARGET_ID = '123456789' await Bot.pickFriend(TARGET_ID).sendMsg(notificationText) logger.info(`已发送一次性通知到 ${TARGET_ID}`)
// 注意:不需要手动处理注销,BaseTrigger.triggerAction 会自动处理 } catch (error) { logger.error('执行一次性触发器时出错:', error) } }}
export default new OneTimeTrigger()
- 明确触发条件:定义清晰的触发条件,避免过于频繁的触发
- 错误处理:在触发器执行逻辑中添加完善的错误处理
- 资源管理:确保触发器在不需要时被正确注销,避免资源泄漏
- 合理使用一次性触发器:针对临时任务使用一次性触发器
- 避免重复触发:设计触发器时注意避免重复触发同一事件