Compare commits

...

3 Commits

Author SHA1 Message Date
6c034ab2a7 Add reasoning agent
Update version to v1.5.0
2025-03-06 11:56:28 +08:00
e44ddd0552 Update message history display 2025-02-28 23:48:10 +08:00
de17af77f2 Add message history context 2025-02-28 23:16:07 +08:00
5 changed files with 323 additions and 104 deletions

View File

@ -1,5 +1,5 @@
plugins { plugins {
val kotlinVersion = "1.8.10" val kotlinVersion = "2.0.20"
kotlin("jvm") version kotlinVersion kotlin("jvm") version kotlinVersion
kotlin("plugin.serialization") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion
@ -7,21 +7,29 @@ plugins {
} }
group = "top.jie65535.mirai" group = "top.jie65535.mirai"
version = "1.3.0" version = "1.5.0"
mirai {
jvmTarget = JavaVersion.VERSION_11
}
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://maven.aliyun.com/repository/public") maven("https://maven.aliyun.com/repository/public")
} }
val openaiClientVersion = "3.8.2" val openaiClientVersion = "4.0.1"
val ktorVersion = "2.3.12" val ktorVersion = "3.0.3"
val jLatexMathVersion = "1.0.7" val jLatexMathVersion = "1.0.7"
val commonTextVersion = "1.13.0" val commonTextVersion = "1.13.0"
val hibernateVersion = "2.9.0"
dependencies { dependencies {
implementation("com.aallam.openai:openai-client:$openaiClientVersion") implementation("com.aallam.openai:openai-client:$openaiClientVersion")
implementation("io.ktor:ktor-client-okhttp:$ktorVersion") implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
implementation("org.scilab.forge:jlatexmath:$jLatexMathVersion") implementation("org.scilab.forge:jlatexmath:$jLatexMathVersion")
implementation("org.apache.commons:commons-text:$commonTextVersion") implementation("org.apache.commons:commons-text:$commonTextVersion")
// 聊天记录插件
compileOnly("xyz.cssxsh.mirai:mirai-hibernate-plugin:$hibernateVersion")
} }

View File

@ -1,9 +1,12 @@
package top.jie65535.mirai package top.jie65535.mirai
import com.aallam.openai.api.chat.* import com.aallam.openai.api.chat.ChatCompletionRequest
import com.aallam.openai.api.core.Role import com.aallam.openai.api.chat.ChatMessage
import com.aallam.openai.api.chat.ChatRole
import com.aallam.openai.api.chat.ToolCall
import com.aallam.openai.api.http.Timeout import com.aallam.openai.api.http.Timeout
import com.aallam.openai.api.model.ModelId import com.aallam.openai.api.model.ModelId
import com.aallam.openai.client.Chat
import com.aallam.openai.client.OpenAI import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIHost import com.aallam.openai.client.OpenAIHost
import io.ktor.util.collections.* import io.ktor.util.collections.*
@ -16,10 +19,8 @@ import net.mamoe.mirai.console.permission.PermissionService
import net.mamoe.mirai.console.permission.PermissionService.Companion.hasPermission import net.mamoe.mirai.console.permission.PermissionService.Companion.hasPermission
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.*
import net.mamoe.mirai.contact.MemberPermission.* import net.mamoe.mirai.contact.MemberPermission.*
import net.mamoe.mirai.contact.isOperator
import net.mamoe.mirai.contact.nameCardOrNick
import net.mamoe.mirai.event.GlobalEventChannel import net.mamoe.mirai.event.GlobalEventChannel
import net.mamoe.mirai.event.events.FriendMessageEvent import net.mamoe.mirai.event.events.FriendMessageEvent
import net.mamoe.mirai.event.events.GroupMessageEvent import net.mamoe.mirai.event.events.GroupMessageEvent
@ -28,13 +29,16 @@ import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.MessageSource.Key.quote import net.mamoe.mirai.message.data.MessageSource.Key.quote
import net.mamoe.mirai.message.sourceIds import net.mamoe.mirai.message.sourceIds
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.info
import top.jie65535.mirai.tools.* import top.jie65535.mirai.tools.*
import xyz.cssxsh.mirai.hibernate.MiraiHibernateRecorder
import java.time.Instant
import java.time.OffsetDateTime import java.time.OffsetDateTime
import java.time.format.TextStyle import java.time.ZoneOffset
import java.util.* import java.time.format.DateTimeFormatter
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.collections.*
import kotlin.math.max
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@ -42,12 +46,18 @@ object JChatGPT : KotlinPlugin(
JvmPluginDescription( JvmPluginDescription(
id = "top.jie65535.mirai.JChatGPT", id = "top.jie65535.mirai.JChatGPT",
name = "J ChatGPT", name = "J ChatGPT",
version = "1.3.0", version = "1.5.0",
) { ) {
author("jie65535") author("jie65535")
// dependsOn("xyz.cssxsh.mirai.plugin.mirai-hibernate-plugin", true)
} }
) { ) {
private var openAi: OpenAI? = null private var llm: Chat? = null
/**
* 是否包含历史对话
*/
private var includeHistory: Boolean = false
val chatPermission = PermissionId("JChatGPT", "Chat") val chatPermission = PermissionId("JChatGPT", "Chat")
@ -64,6 +74,14 @@ object JChatGPT : KotlinPlugin(
// 注册插件命令 // 注册插件命令
PluginCommands.register() PluginCommands.register()
// 检查消息记录插件是否存在
includeHistory = try {
MiraiHibernateRecorder
true
} catch (_: Throwable) {
false
}
GlobalEventChannel.parentScope(this) GlobalEventChannel.parentScope(this)
.subscribeAlways<MessageEvent> { event -> onMessage(event) } .subscribeAlways<MessageEvent> { event -> onMessage(event) }
@ -72,22 +90,28 @@ object JChatGPT : KotlinPlugin(
fun updateOpenAiToken(token: String) { fun updateOpenAiToken(token: String) {
val timeout = PluginConfig.timeout.milliseconds val timeout = PluginConfig.timeout.milliseconds
openAi = OpenAI( llm = OpenAI(
token, token,
host = OpenAIHost(baseUrl = PluginConfig.openAiApi), host = OpenAIHost(baseUrl = PluginConfig.openAiApi),
timeout = Timeout(request = timeout, connect = timeout, socket = timeout) timeout = Timeout(request = timeout, connect = timeout, socket = timeout),
// logging = LoggingConfig(LogLevel.All)
) )
reasoningAgent.llm = llm
} }
private val timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss")
.withZone(ZoneOffset.systemDefault())
private val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd E HH:mm:ss")
// private val userContext = ConcurrentMap<Long, MutableList<ChatMessage>>() // private val userContext = ConcurrentMap<Long, MutableList<ChatMessage>>()
private const val REPLAY_QUEUE_MAX = 10 private const val REPLAY_QUEUE_MAX = 10
private val replyMap = ConcurrentMap<Int, MutableList<ChatMessage>>() private val replyMap = ConcurrentMap<Int, MutableList<ChatMessage>>(REPLAY_QUEUE_MAX)
private val replyQueue = mutableListOf<Int>() private val replyQueue = mutableListOf<Int>()
private val requestMap = ConcurrentSet<Long>() private val requestMap = ConcurrentSet<Long>()
private suspend fun onMessage(event: MessageEvent) { private suspend fun onMessage(event: MessageEvent) {
// 检查Token是否设置 // 检查Token是否设置
if (openAi == null) return if (llm == null) return
// 发送者是否有权限 // 发送者是否有权限
if (!event.toCommandSender().hasPermission(chatPermission)) { if (!event.toCommandSender().hasPermission(chatPermission)) {
if (event is GroupMessageEvent) { if (event is GroupMessageEvent) {
@ -147,9 +171,11 @@ object JChatGPT : KotlinPlugin(
prompt.replace(i, i + target.length, replacement()) prompt.replace(i, i + target.length, replacement())
} }
} }
replace("{time}") { replace("{time}") {
"$now ${now.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.CHINA)}" dateTimeFormatter.format(now)
} }
replace("{subject}") { replace("{subject}") {
if (event is GroupMessageEvent) { if (event is GroupMessageEvent) {
"\"${event.subject.name}\" 群聊中" "\"${event.subject.name}\" 群聊中"
@ -157,33 +183,103 @@ object JChatGPT : KotlinPlugin(
"私聊中" "私聊中"
} }
} }
replace("{sender}") {
// replace("{sender}") {
// if (event is GroupMessageEvent) {
// event.sender.specialTitle
// val permissionName = when (event.sender.permission) {
// MEMBER -> "普通群员"
// ADMINISTRATOR -> "管理员"
// OWNER -> "群主"
// }
// "\"${event.senderName}\" 身份:$permissionName"
// } else {
// "\"${event.senderName}\""
// }
// }
replace("{history}") {
if (!includeHistory) {
return@replace "暂无内容"
}
// 一段时间内的消息
val beforeTimestamp = now.minusMinutes(PluginConfig.historyWindowMin.toLong()).toEpochSecond().toInt()
val nowTimestamp = now.toEpochSecond().toInt()
// 最近这段时间的历史对话
val history = MiraiHibernateRecorder[event.subject, beforeTimestamp, nowTimestamp]
.take(PluginConfig.historyMessageLimit) // 只取最近的部分消息,避免上下文过长
.sortedBy { it.time } // 按时间排序
// 构造历史消息
val historyText = StringBuilder()
if (event is GroupMessageEvent) { if (event is GroupMessageEvent) {
event.sender.specialTitle for (record in history) {
val permissionName = when (event.sender.permission) { if (event.bot.id == record.fromId) {
MEMBER -> "普通群员" historyText.append("")
ADMINISTRATOR -> "管理员"
OWNER -> "群主"
}
"\"${event.senderName}\" 身份:$permissionName"
} else { } else {
"\"${event.senderName}\"" val recordSender = event.subject[record.fromId]
if (recordSender != null) {
// 群活跃等级
historyText.append(getNameCard(recordSender))
} else {
// 未知群员
historyText.append("未知群员(").append(record.fromId).append(")")
} }
} }
historyText
.append(" ")
// 发言时间
.append(timeFormatter.format(Instant.ofEpochSecond(record.time.toLong())))
// 消息内容
.append(" 说:").appendLine(record.toMessageChain().joinToString("") {
when (it) {
is At -> {
it.getDisplay(event.subject)
}
is ForwardMessage -> {
it.title + "\n" + it.preview
}
is QuoteReply -> {
">" + it.source.originalMessage.contentToString().replace("\n", "\n> ") + "\n"
}
else -> {
it.contentToString()
}
}
})
}
} else {
// TODO 私聊
}
historyText.toString()
}
return prompt.toString() return prompt.toString()
} }
@OptIn(MiraiExperimentalApi::class)
private suspend fun startChat(event: MessageEvent, context: List<ChatMessage>? = null) { private suspend fun startChat(event: MessageEvent, context: List<ChatMessage>? = null) {
val history = mutableListOf<ChatMessage>() val history = mutableListOf<ChatMessage>()
if (!context.isNullOrEmpty()) { if (!context.isNullOrEmpty()) {
history.addAll(context) history.addAll(context)
} else if (PluginConfig.prompt.isNotEmpty()) { } else if (PluginConfig.prompt.isNotEmpty()) {
history.add(ChatMessage(ChatRole.System, getSystemPrompt(event))) val prompt = getSystemPrompt(event)
if (PluginConfig.logPrompt) {
logger.info("Prompt: $prompt")
}
history.add(ChatMessage(ChatRole.System, prompt))
} }
val msg = event.message.plainText() val msg = event.message.plainText()
if (msg.isNotEmpty()) { if (msg.isNotEmpty()) {
history.add(ChatMessage(ChatRole.User, msg)) history.add(ChatMessage(ChatRole.User, if (event is GroupMessageEvent) {
"${getNameCard(event.sender)} 说:$msg"
} else {
msg
}))
} }
try { try {
@ -192,11 +288,12 @@ object JChatGPT : KotlinPlugin(
return return
} }
var done: Boolean var done = true
var retry = 2 // 至少重试两次
var hasTools = true var retry = max(PluginConfig.retryMax, 2)
do { do {
val reply = chatCompletion(history, hasTools) try {
val reply = chatCompletion(history, retry > 1)
history.add(reply) history.add(reply)
done = true done = true
@ -212,56 +309,68 @@ object JChatGPT : KotlinPlugin(
) )
) )
done = false done = false
hasTools = false
} }
} while (!done && 0 < --retry) } catch (e: Exception) {
if (retry <= 1) {
throw e
} else {
logger.warning("调用llm时发生异常重试中", e)
event.subject.sendMessage(event.message.quote() + "出错了...正在重试...")
}
}
} while (!done && 0 <-- retry)
val content = history.last().content ?: "..." val content = history.last().content ?: "..."
val replyMsg = event.subject.sendMessage( val replyMsg = event.subject.sendMessage(
if (content.length < 128) { if (content.length < PluginConfig.messageMergeThreshold) {
event.message.quote() + toMessage(event.subject, content) event.message.quote() + toMessage(event.subject, content)
} else { } else {
// 消息内容太长则转为转发消息避免刷屏 // 消息内容太长则转为转发消息避免刷屏
event.buildForwardMessage { event.buildForwardMessage {
for (item in history) { event.bot says toMessage(event.subject, content)
if (item.content.isNullOrEmpty())
continue
val temp = toMessage(event.subject, item.content!!)
when (item.role) {
Role.User -> event.sender says temp
Role.Assistant -> event.bot says temp
}
} }
// 检查并移除超出转发消息上限的消息 // 不再将历史对话记录加入其中
var isOverflow = false // event.buildForwardMessage {
var count = 0 // for (item in history) {
for (i in size - 1 downTo 0) { // if (item.content.isNullOrEmpty())
if (count > 4900) { // continue
isOverflow = true // val temp = toMessage(event.subject, item.content!!)
// 删除早期上下文消息 // when (item.role) {
removeAt(i) // Role.User -> event.sender says temp
} else { // Role.Assistant -> event.bot says temp
for (text in this[i].messageChain.filterIsInstance<PlainText>()) { // }
count += text.content.length // }
} //
} // // 检查并移除超出转发消息上限的消息
} // var isOverflow = false
if (count > 5000) { // var count = 0
removeAt(0) // for (i in size - 1 downTo 0) {
} // if (count > 4900) {
if (isOverflow) { // isOverflow = true
// 如果溢出了,插入一条提示到最开始 // // 删除早期上下文消息
add( // removeAt(i)
0, ForwardMessage.Node( // } else {
senderId = event.bot.id, // for (text in this[i].messageChain.filterIsInstance<PlainText>()) {
time = this[0].time - 1, // count += text.content.length
senderName = event.bot.nameCardOrNick, // }
message = PlainText("更早的消息已隐藏,避免超出转发消息上限。") // }
) // }
) // if (count > 5000) {
} // removeAt(0)
} // }
// if (isOverflow) {
// // 如果溢出了,插入一条提示到最开始
// add(
// 0, ForwardMessage.Node(
// senderId = event.bot.id,
// time = this[0].time - 1,
// senderName = event.bot.nameCardOrNick,
// message = PlainText("更早的消息已隐藏,避免超出转发消息上限。")
// )
// )
// }
// }
} }
) )
@ -277,17 +386,20 @@ object JChatGPT : KotlinPlugin(
} }
} catch (ex: Throwable) { } catch (ex: Throwable) {
logger.warning(ex) logger.warning(ex)
event.subject.sendMessage(event.message.quote() + "发生异常,请重试") event.subject.sendMessage(event.message.quote() + "很抱歉,发生异常,请稍后重试")
} finally { } finally {
requestMap.remove(event.sender.id) requestMap.remove(event.sender.id)
} }
// catch (ex: OpenAITimeoutException) {
// event.subject.sendMessage(event.message.quote() + "很抱歉,服务器没响应,请稍后重试")
// }
} }
private val laTeXPattern = Pattern.compile( private val laTeXPattern = Pattern.compile(
"\\\\\\((.+?)\\\\\\)|" + // 匹配行内公式 \(...\) "\\\\\\((.+?)\\\\\\)|" + // 匹配行内公式 \(...\)
"\\\\\\[(.+?)\\\\\\]|" + // 匹配独立公式 \[...\] "\\\\\\[(.+?)\\\\\\]|" + // 匹配独立公式 \[...\]
"\\$\\$([^$]+?)\\$\\$|" + // 匹配独立公式 $$...$$ "\\$\\$([^$]+?)\\$\\$|" + // 匹配独立公式 $$...$$
"\\$(.+?)\\$|" + // 匹配行内公式 $...$ "\\$\\s(.+?)\\s\\$|" + // 匹配行内公式 $...$
"```latex\\s*([^`]+?)\\s*```" // 匹配 ```latex ... ``` "```latex\\s*([^`]+?)\\s*```" // 匹配 ```latex ... ```
, Pattern.DOTALL , Pattern.DOTALL
) )
@ -336,6 +448,8 @@ object JChatGPT : KotlinPlugin(
} }
} }
private val reasoningAgent = ReasoningAgent()
/** /**
* 工具列表 * 工具列表
*/ */
@ -346,6 +460,9 @@ object JChatGPT : KotlinPlugin(
// 运行代码 // 运行代码
RunCode(), RunCode(),
// 推理代理
reasoningAgent,
// 天气服务 // 天气服务
WeatherService(), WeatherService(),
@ -361,7 +478,7 @@ object JChatGPT : KotlinPlugin(
chatMessages: List<ChatMessage>, chatMessages: List<ChatMessage>,
hasTools: Boolean = true hasTools: Boolean = true
): ChatMessage { ): ChatMessage {
val openAi = this.openAi ?: throw NullPointerException("OpenAI Token 未设置,无法开始") val llm = this.llm ?: throw NullPointerException("OpenAI Token 未设置,无法开始")
val availableTools = if (hasTools) { val availableTools = if (hasTools) {
myTools.filter { it.isEnabled }.map { it.tool } myTools.filter { it.isEnabled }.map { it.tool }
} else null } else null
@ -369,19 +486,38 @@ object JChatGPT : KotlinPlugin(
model = ModelId(PluginConfig.chatModel), model = ModelId(PluginConfig.chatModel),
messages = chatMessages, messages = chatMessages,
tools = availableTools, tools = availableTools,
toolChoice = ToolChoice.Auto
) )
logger.info( logger.info("API Requesting... Model=${PluginConfig.chatModel}"
"API Requesting..." + // " Tools=${availableTools?.joinToString(prefix = "[", postfix = "]")}"
" Model=${PluginConfig.chatModel}" +
" Tools=${availableTools?.joinToString(prefix = "[", postfix = "]")}"
) )
val response = openAi.chatCompletion(request) val response = llm.chatCompletion(request)
val message = response.choices.first().message val message = response.choices.first().message
logger.info("Response: $message ${response.usage}") logger.info("Response: $message ${response.usage}")
return message return message
} }
private fun getNameCard(member: Member): String {
val nameCard = StringBuilder()
// 群活跃等级
nameCard.append("【lv").append(member.active.temperature).append(" ")
// 群头衔
if (member.specialTitle.isNotEmpty()) {
nameCard.append(member.specialTitle)
} else {
nameCard.append(
when (member.permission) {
OWNER -> "群主"
ADMINISTRATOR -> "管理员"
MEMBER -> member.temperatureTitle
}
)
}
// 群名片
nameCard.append("").append(member.nameCardOrNick)
// .append(" (").append(recordSender.id).append(")")
return nameCard.toString()
}
private fun MessageChain.plainText() = this.filterIsInstance<PlainText>().joinToString().trim() private fun MessageChain.plainText() = this.filterIsInstance<PlainText>().joinToString().trim()
private suspend fun ToolCall.Function.execute(event: MessageEvent): String { private suspend fun ToolCall.Function.execute(event: MessageEvent): String {
@ -401,11 +537,11 @@ object JChatGPT : KotlinPlugin(
logger.error("Failed to call ${function.name}", e) logger.error("Failed to call ${function.name}", e)
"工具调用失败,请尝试自行回答用户,或如实告知。" "工具调用失败,请尝试自行回答用户,或如实告知。"
} }
logger.info("Result=$result") logger.info("Result=\"$result\"")
// 过会撤回加载消息 // 过会撤回加载消息
if (receipt != null) { if (receipt != null) {
launch { launch {
delay(3.seconds); delay(3.seconds)
try { try {
receipt.recall() receipt.recall()
} catch (e: Throwable) { } catch (e: Throwable) {

View File

@ -12,7 +12,10 @@ object PluginConfig : AutoSavePluginConfig("Config") {
var openAiToken: String by value("") var openAiToken: String by value("")
@ValueDescription("Chat模型") @ValueDescription("Chat模型")
var chatModel: String by value("gpt-3.5-turbo-1106") var chatModel: String by value("qwen-max")
@ValueDescription("推理模型")
var reasoningModel: String by value("qwq-plus")
@ValueDescription("Chat默认提示") @ValueDescription("Chat默认提示")
var prompt: String by value("") var prompt: String by value("")
@ -35,4 +38,18 @@ object PluginConfig : AutoSavePluginConfig("Config") {
@ValueDescription("在线运行代码 glot.io 的 api token在官网注册账号即可获取。") @ValueDescription("在线运行代码 glot.io 的 api token在官网注册账号即可获取。")
val glotToken: String by value("") val glotToken: String by value("")
@ValueDescription("创建Prompt时取最近多少分钟内的消息")
val historyWindowMin: Int by value(10)
@ValueDescription("创建Prompt时取最多几条消息")
val historyMessageLimit: Int by value(20)
@ValueDescription("是否打印Prompt便于调试")
val logPrompt by value(false)
@ValueDescription("达到需要合并转发消息的阈值")
val messageMergeThreshold by value(150)
@ValueDescription("最大重试次数至少2次最后一次请求不会带工具非工具调用相当于正常回复")
val retryMax: Int by value(3)
} }

View File

@ -0,0 +1,58 @@
package top.jie65535.mirai.tools
import com.aallam.openai.api.chat.ChatCompletionRequest
import com.aallam.openai.api.chat.ChatMessage
import com.aallam.openai.api.chat.Tool
import com.aallam.openai.api.core.Parameters
import com.aallam.openai.api.model.ModelId
import com.aallam.openai.client.Chat
import kotlinx.serialization.json.*
import top.jie65535.mirai.PluginConfig
class ReasoningAgent : BaseAgent(
tool = Tool.function(
name = "reasoning",
description = "可通过调用推理模型对问题进行深度思考。",
parameters = Parameters.buildJsonObject {
put("type", "object")
putJsonObject("properties") {
putJsonObject("prompt") {
put("type", "string")
put("description", "用于调用推理模型的提示")
}
}
putJsonArray("required") {
add("question")
}
},
)
) {
var llm: Chat? = null
override val loadingMessage: String
get() = "深度思考中..."
override val isEnabled: Boolean
get() = llm != null
override suspend fun execute(args: JsonObject?): String {
requireNotNull(args)
val llm = llm ?: return "未配置llm无法进行推理。"
val prompt = args.getValue("prompt").jsonPrimitive.content
val answerContent = StringBuilder()
llm.chatCompletions(ChatCompletionRequest(
model = ModelId(PluginConfig.reasoningModel),
messages = listOf(ChatMessage.Companion.User(prompt))
)).collect {
if (it.choices.isNotEmpty()) {
val delta = it.choices[0].delta ?: return@collect
if (!delta.content.isNullOrEmpty()) {
answerContent.append(delta.content)
}
}
}
return answerContent.toString().ifEmpty { "推理出错,结果为空" }
}
}

View File

@ -11,7 +11,7 @@ import top.jie65535.mirai.PluginConfig
class WebSearch : BaseAgent( class WebSearch : BaseAgent(
tool = Tool.function( tool = Tool.function(
name = "search", name = "webSearch",
description = "Provides meta-search functionality through SearXNG," + description = "Provides meta-search functionality through SearXNG," +
" aggregating results from multiple search engines.", " aggregating results from multiple search engines.",
parameters = Parameters.buildJsonObject { parameters = Parameters.buildJsonObject {