The firstChunkTimeout only wrapped the response-body read, but when the upstream (e.g. DeepSeek under load) stalls before sending response headers, httpClient.post() itself blocks and the withTimeout block is never reached. Every slow request fell through to Ktor's requestTimeoutMillis (120s) and was retried up to retryMax times, causing multi-minute waits before any reply. - Move post() inside withTimeout(firstChunkTimeout) so the entire request-to-first-data-chunk window is bounded and fails fast. - Apply withTimeout(firstChunkTimeout) to each streaming read so a mid-stream stall is also caught quickly instead of waiting on the socket/request backstop. - Drop requestTimeoutMillis so legitimately long streams are no longer killed at 120s; TTFT and inter-token gaps are now governed at the application layer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JChatGPT
JChatGPT 是一个基于 Kotlin 的 Mirai Console 插件,它将大型语言模型(LLM)集成到即时通讯平台中。该插件支持多种 AI 模型和丰富的工具功能,使用户能够在群聊和私聊中与 AI 进行交互。
功能特性
- 多模型支持:支持聊天模型、推理模型和视觉模型
- 丰富的工具系统:包括网络搜索、代码执行、图像识别、群管理等
- 上下文记忆:支持持久化记忆存储
- 用户画像系统:好感度、印象、标签、Bot 自定义代号
- Token消耗统计:按天 × 用户 × 群聚合记录,支持多维度统计查询
- LaTeX 渲染:自动将数学表达式渲染为图片
- 灵活的触发方式:@机器人、关键字触发、回复消息等
- 权限控制:细粒度的权限管理系统
- 历史消息集成:可选的历史消息上下文(需配合 mirai-hibernate-plugin)
用法
基本交互
- 在群内直接 @bot 即可触发对话
- 通过引用群友消息 + @bot 让 Bot 识别引用消息的内容
- 回复 bot 的消息即可引用对应的上下文对话(包括这个回复的历史对话)
- 使用关键字触发(默认为 "[小筱][林淋月玥]",可在配置中修改)
工具调用
AI 可以自动调用多种工具来完成复杂任务:
- 网络搜索(需要配置 SearXNG)
- 代码执行(支持多种语言,需要配置 glot.io token)
- 图像识别(需要配置视觉模型)
- 推理思考(需要配置推理模型)
- 群管理(禁言等,需启用相应权限)
- 记忆管理(添加和修改对话记忆)
- 聊天历史搜索(按关键词、发送者、时间范围检索群聊消息,需启用历史消息上下文)
权限列表
JChatGPT:Chat- 拥有该权限即可使用 bot 与 AI 对话top.jie65535.mirai.jchatgpt:command.jgpt- 拥有该权限即可使用/jgpt相关命令
命令列表
基础命令
/jgpt enable <contact>- 启用目标对话权限/jgpt disable <contact>- 禁用目标对话权限/jgpt reload- 重载配置文件/jgpt clearMemory- 清空所有对话记忆/jgpt clearContextCache- 清空所有对话上下文缓存
好感度管理
/jgpt setFavor <user> <value>- 设置指定用户的好感度值(-100~100)/jgpt clearFavor- 重置所有用户的好感度
Token统计
/jgpt tokens [days]- 查看Token使用简报(默认7天)/jgpt tokensDaily [days]- 查看指定天数的每日Token消耗统计(默认7天)/jgpt tokensUsers [limit]- 查看Token消耗最多的用户排名(默认Top 10)/jgpt tokensGroups [limit]- 查看Token消耗最多的群组排名(默认Top 10)/jgpt tokensQuery [userId] [days]- 查询日聚合记录(每行一天一人,可按用户和时间过滤)/jgpt tokensUserDaily <userId> [days]- 查询指定用户每天的消费统计(默认7天)
配置文件
配置文件位于:./config/top.jie65535.mirai.JChatGPT/Config.yml
# OpenAI API base url
openAiApi: 'https://dashscope.aliyuncs.com/compatible-mode/v1/'
# OpenAI API Token
openAiToken: ''
# Chat模型
chatModel: 'qwen-max'
# Chat模型温度,默认为null
chatTemperature: null
# 推理模型API
reasoningModelApi: 'https://dashscope.aliyuncs.com/compatible-mode/v1/'
# 推理模型Token
reasoningModelToken: ''
# 推理模型
reasoningModel: 'qwq-plus'
# 视觉模型API
visualModelApi: 'https://dashscope.aliyuncs.com/compatible-mode/v1/'
# 视觉模型Token
visualModelToken: ''
# 视觉模型
visualModel: 'qwen-vl-plus'
# 聊天模型额外请求体JSON,会合并到请求体中。例如DeepSeek关闭思维: {"thinking": {"type": "disabled"}}
chatModelExtraBody: ''
# 推理模型额外请求体JSON,会合并到请求体中。例如DeepSeek启用思维: {"thinking": {"type": "enabled"}}
reasoningModelExtraBody: ''
# 视觉模型额外请求体JSON,会合并到请求体中。
visualModelExtraBody: ''
# 百炼平台API KEY
dashScopeApiKey: ''
# 百炼平台图像模型(文生图 + 图像编辑)
imageModel: 'qwen-image-2.0'
# 是否在生成图片右下角添加 Qwen-Image 水印
imageWatermark: false
# 百炼平台TTS模型,qwen3-tts-instruct-flash 支持 instructions 指令控制语气
ttsModel: 'qwen3-tts-instruct-flash'
# Jina API Key
jinaApiKey: ''
# SearXNG 搜索引擎地址,如 http://127.0.0.1:8080/search 必须启用允许json格式返回
searXngUrl: ''
# 在线运行代码 glot.io 的 api token,在官网注册账号即可获取。
glotToken: ''
# 群管理是否自动拥有对话权限,默认是
groupOpHasChatPermission: true
# 好友是否自动拥有对话权限,默认是
friendHasChatPermission: true
# 机器人是否可以禁言别人,默认禁止
canMute: false
# 群荣誉等级权限门槛,达到这个等级相当于自动拥有对话权限。
temperaturePermission: 50
# 等待响应超时时间(整个请求的总超时与socket读超时),单位毫秒,默认60秒
timeout: 60000
# 首块响应超时时间,单位毫秒,默认10秒。若连接建立后在此时间内没收到首块data:则中断走重试
firstChunkTimeout: 10000
# 系统提示词,该字段已弃用,使用提示词文件而不是在这里修改
prompt: '你是一个乐于助人的助手'
# 系统提示词文件路径,相对于插件配置目录
promptFile: 'SystemPrompt.md'
# 创建Prompt时取最近多少分钟内的消息
historyWindowMin: 10
# 创建Prompt时取最多几条消息
historyMessageLimit: 20
# 是否打印Prompt便于调试
logPrompt: false
# 达到需要合并转发消息的阈值
messageMergeThreshold: 150
# 最大循环次数,至少2次
retryMax: 5
# 关键字呼叫,支持正则表达式
callKeyword: '[小筱][林淋月玥]'
# 是否显示工具调用消息,默认是
showToolCallingMessage: true
# 是否启用记忆编辑功能,记忆存在data目录,提示词中需要加上{memory}来填充记忆,每个群都有独立记忆
memoryEnabled: true
# 是否启用好感度系统
enableFavorabilitySystem: true
# 好感度每日基础偏移速度(点/天)
favorabilityBaseShiftSpeed: 2.0
# 聊天记录搜索最大天数
searchHistoryMaxDays: 30
# 聊天记录搜索最大查询条数,防止内存溢出
searchHistoryMaxRecords: 5000
系统提示词
JChatGPT 使用系统提示词来定义 AI 的行为和个性。提示词文件位于插件配置目录下的 SystemPrompt.md 文件中。
提示词结构
系统提示词通常包含以下部分:
- 角色定义:定义 AI 的身份、性格和行为准则
- 功能说明:描述 AI 可以使用的工具和功能
- 交互规则:规定 AI 与用户交互的规则和限制
- 占位符:动态替换的内容,如时间、群信息、记忆等
占位符
系统提示词支持以下占位符,在运行时会被动态替换:
{time}- 当前时间(格式:yyyy年MM月dd E HH:mm:ss){subject}- 当前聊天环境信息(群聊名称或私聊信息){memory}- 当前联系人的记忆内容
示例提示词
以下是一个完整的示例提示词,展示如何构建一个个性化的AI角色:
你是小灵,一个聪明、友善且乐于助人的AI助手。
你被设计为帮助用户解答问题、提供信息和完成各种任务。你具有以下特点:
- 性格开朗、幽默,但保持礼貌和专业
- 喜欢使用轻松的语气,但不会过于随意
- 对技术问题有深入的理解,能够提供准确的信息
- 对于不确定的问题,会坦诚说明而不是编造答案
你可以使用的工具包括:
1. 网络搜索 - 获取最新的信息
2. 代码执行 - 运行和测试代码片段
3. 图像识别 - 理解图片内容
4. 数学计算 - 解决复杂的数学问题
5. 记忆管理 - 保存和回忆重要信息
重要说明:
你所有的输出都是内心思考,用户无法看到。只有当你调用发送消息的工具时,用户才能看到你的回复。
- sendSingleMessage - 发送单条消息(适用于简短回复)
- sendCompositeMessage - 发送组合消息(适用于长内容或代码)
交互规则:
1. 只有当用户@你或在消息中包含你的名字时才会响应
2. 回复应简洁明了,避免长篇大论
3. 对于复杂内容,使用组合消息功能发送
4. 不主动参与与你无关的对话
5. 不会对用户进行人身攻击或使用不当语言
工具使用原则:
- 只在必要时使用工具
- 深度思考工具仅用于复杂问题
- 代码执行工具用于验证技术问题
- **每次对话结束时必须调用 endConversation 工具来结束对话**
- **要发送消息给用户必须使用 sendSingleMessage 或 sendCompositeMessage 工具**
<memory>
{memory}
</memory>
当前的时间是:{time}
你当前在 {subject} 环境中
对话示例:
用户:小灵,今天的天气怎么样?
小灵:让我查一下...
(调用网络搜索工具)
(调用 sendSingleMessage 工具)
小灵:今天天气晴朗,温度在25°C左右,适合外出活动。
(调用 endConversation 工具)
用户:帮我写一个Python函数来计算斐波那契数列
小灵:好的,这是计算斐波那契数列的Python函数:
(调用 sendCompositeMessage 工具发送代码)
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
# 示例使用
print(fibonacci(10)) # 输出55
(调用 endConversation 工具)
用户:你能识别这张图片吗?[图片链接]
小灵:让我看看这张图片...
(调用图像识别工具)
(调用 sendSingleMessage 工具)
小灵:这是一张猫咪的图片,看起来很可爱!
(调用 endConversation 工具)
注意事项:
1. 请勿重复发送相似内容
2. 避免不必要的工具调用以节省资源
3. 保护用户隐私,不泄露敏感信息
4. 遵守法律法规,不传播违法内容
5. **切记:只有通过调用发送消息工具,用户才能看到你的回复**
6. **每次对话结束时都必须调用结束对话工具**
编写建议
- 明确角色定位:清晰定义 AI 的身份和个性,让用户能够建立预期
- 设定行为边界:规定 AI 应该和不应该做的事情,确保安全使用
- 强调工具调用机制:明确说明只有通过调用发送消息工具才能让用户看到回复
- 强调结束对话:每次对话都必须调用 endConversation 工具来结束
- 合理使用工具:指导 AI 何时以及如何使用各种工具,避免滥用
- 优化交互体验:确保对话自然流畅,避免重复和冗余
- 保护隐私安全:确保敏感信息不会被泄露
- 提供具体示例:通过对话示例展示预期的行为模式
- 使用占位符:充分利用时间、环境和记忆占位符提供上下文感知
支持的模型
JChatGPT 默认配置为使用阿里云百炼平台的通义千问系列模型:
- 聊天模型:
qwen-max - 推理模型:
qwq-plus - 视觉模型:
qwen-vl-plus
当然,也可以配置为使用其他兼容 OpenAI API 的模型,如 GPT 系列模型。
工具系统
插件内置了丰富的工具供 AI 调用:
- WebSearch - 使用 SearXNG 进行网络搜索
- RunCode - 在 glot.io 上执行多种编程语言代码
- VisualAgent - 图像识别和理解
- ReasoningAgent - 深度思考和推理
- MemoryAppend/Replace - 对话记忆管理
- GroupManageAgent - 群管理功能(如禁言)
- SendSingleMessage/CompositeMessage - 发送消息
- SendVoiceMessage - 发送语音消息
- ImageAgent - 图像生成与编辑(文生图、单图编辑、多图融合)
- WeatherService - 天气查询
- SearchChatHistory - 按关键词、发送者、时间范围搜索群聊消息历史(依赖 mirai-hibernate-plugin)
用户画像系统
JChatGPT 维护对每位用户的画像,由好感度、Bot 自定义代号、最多 5 个标签和印象文本组成。模型可以通过 adjustUserFavorability 工具在交流后增量更新这些字段(同一次调用可以同时调好感度、加 tag、改印象,不必分开)。
字段
- value(好感度):范围 -100(完全不理会)到 100(非常好的朋友)
- name(代号):Bot 给此人起的内部代号,区别于 QQ 昵称,长度 ≤20
- tags(标签):最多 5 个简短标签,记录身份/职业/偏好/技术栈等
- impression(印象):自由文本,长度 ≤200
- reasons(调整原因):只有 change ≠ 0 的调整才会追加,保留最近 10 条
好感度机制
- 负好感度用户有一定概率不会收到回复,概率 = |好感度| / 100
- 好感度会随时间向 0 偏移:偏移量 = sign(好感度) × (1 - (|好感度| / 100)²) × 基础偏移速度
- 极端值变化缓慢,-100 需要好几天才能回升,100 也不会快速衰减
注入到上下文
- 群聊:列出会话历史中"认识的群友"(name/tags/impression 任一非空)
- 私聊:仅当对方有 name/tags/impression 时注入对方画像
- 仅有好感度数值、其它字段全空的用户不会被列出,避免提示词噪声
管理命令
/jgpt setFavor <user> <value>- 设置指定用户的好感度值(-100~100),不改其他字段/jgpt clearFavor- 清空所有用户画像
配置选项
enableFavorabilitySystem- 是否启用画像系统(默认:true)favorabilityBaseShiftSpeed- 好感度每日基础偏移速度(点/天,默认:2.0)
Token消耗统计
JChatGPT 按 (日期, userId, groupId) 三元组聚合每次对话的 Token 消耗,提供多维度统计查询。
历史版本曾按每次请求逐条记录,但增长不受控(数千条后会触发 mamoe-yamlkt 的编/解码 bug 导致整个 data.yml 无法加载)。现已改为按天聚合并搬到独立的
token_usage.json,data.yml 只保留小规模的 memory / favorability 数据。
功能特性
- 自动记录:每次对话累加到当日聚合行
- 聚合维度:日期 × 用户 × 群(同一人同一天在同一群只占一行)
- 多维统计:支持按日期、用户、群组进行统计
- 灵活查询:支持详细记录查询和过滤
记录内容
每条聚合记录包含:
- 日期(yyyy-MM-dd,本地时区)
- 用户QQ号和最近一次记录到的昵称
- 群组ID(群聊)或null(私聊)
- 当日累计输入Token数(promptTokens)
- 当日累计输出Token数(completionTokens)
- 当日累计总Token数(totalTokens)
- 当日调用次数(callCount)
统计命令
使用简报
/jgpt tokens [days]
- 快速查看指定时间范围内的Token使用概况
- 默认显示最近7天
- 包含总计、今日、最活跃用户/群组
- 输出示例:
📊 Token 使用简报(最近 7 天) 总计: 1,452,279 tokens 今日: 215,432 tokens 活跃用户: 15 人 👤 最活跃用户: 张三 - 523,456 tokens 👥 最活跃群组: 987654321 - 876,543 tokens 📋 详细查询: /jgpt tokensDaily [days] - 每日统计 /jgpt tokensUsers [limit] - 用户排名 /jgpt tokensGroups [limit] - 群组排名 /jgpt tokensQuery [userId] [days] - 详细记录 /jgpt tokensUserDaily <userId> [days] - 用户日统计
每日统计
/jgpt tokensDaily [days]
- 显示指定天数内的每日Token消耗统计
- 默认显示最近7天
- 输出示例:
最近 7 天 Token 使用统计: 2026-03-18: 15,342 tokens 2026-03-17: 12,890 tokens 2026-03-16: 9,567 tokens
用户排名
/jgpt tokensUsers [limit]
- 显示Token消耗最多的用户排名
- 默认显示Top 10
- 输出示例:
Token 使用排名 Top 10: 张三(QQ:123456): 25,430 tokens 李四(QQ:234567): 18,920 tokens 王五(QQ:345678): 12,450 tokens
群组排名
/jgpt tokensGroups [limit]
- 显示Token消耗最多的群组排名
- 默认显示Top 10
- 仅统计群聊对话,不包括私聊
- 输出示例:
群组 Token 使用排名 Top 10: 群 987654321: 45,670 tokens 群 876543210: 32,100 tokens 群 765432109: 28,930 tokens
详细查询
/jgpt tokensQuery [userId] [days]
- 查询日聚合记录(每行 = 某天某人某群的当日合计)
- 可按用户ID过滤(可选)
- 可指定时间范围(默认7天)
- 最多显示20条记录,按日期倒序
- 输出示例:
最近 7 天使用记录(最多显示20条,按日聚合): [2026-03-18] 群987654321 - 张三 调用 12 次, Tokens: 23,450 (输入: 12,340, 输出: 11,110) [2026-03-18] 私聊 - 李四 调用 5 次, Tokens: 8,760 (输入: 4,800, 输出: 3,960)
用户日统计
/jgpt tokensUserDaily <userId> [days]
- 查询指定用户每天的消费统计
- 按天汇总显示,不会刷屏
- 必须提供用户ID(QQ号)
- 可指定时间范围(默认7天)
- 输出示例:
用户 张三 最近 7 天 Token 使用统计: 2026-03-18: 12,450 tokens 2026-03-17: 8,320 tokens 2026-03-16: 15,670 tokens 总计: 36,440 tokens
数据存储
- Token 聚合记录保存在插件数据目录的
token_usage.json文件中 - 由
TokenUsageStore直接管,绕开 mamoe 的 plugin data 系统(避免 yamlkt 在大数据量下的编/解码 bug) - 每次记录后写盘(先写
.tmp再覆盖,避免半文件) - 加载失败会自动备份原文件为
token_usage.json.broken-<timestamp>并从空开始 - 记录永久保存,不会自动删除
- 数据格式为JSON,可手动查看和备份
使用场景
- 成本监控:了解API调用成本,控制预算
- 使用分析:分析哪些用户或群组使用最频繁
- 性能优化:识别高消耗对话,优化提示词
- 趋势分析:观察使用趋势,规划资源
注意事项
- 仅统计聊天模型的Token消耗
- 推理模型和视觉模型的消耗不在统计范围内
- 同一用户同一天在同一群的多次调用合并为一行(callCount 自增)
- 统计数据基于实际API返回的Token数
部署要求
- Java 11 或更高版本
- Mirai Console 2.16.0 或更高版本
- 可选:mirai-hibernate-plugin(用于历史消息上下文)
- 相关 API Tokens(根据需要启用的功能配置)
备注
- 如果默认的 API 调用失败,可以更换为其他兼容的 API 地址
- 可根据需要配置代理设置
- 某些工具需要额外的 API 密钥才能启用
- 插件支持自定义系统提示词,可以通过修改
SystemPrompt.md文件来实现