mirror of
https://github.com/FuQuan233/nonebot-plugin-llmchat.git
synced 2026-02-05 03:28:05 +00:00
Compare commits
2 commits
4bfcaf3a61
...
59eafc2137
| Author | SHA1 | Date | |
|---|---|---|---|
| 59eafc2137 | |||
| 2d61bd31ae |
5 changed files with 16 additions and 9 deletions
|
|
@ -137,6 +137,7 @@ LLMCHAT__MCP_SERVERS同样为一个dict,key为服务器名称,value配置的
|
||||||
| arg | 否 | [] | stdio服务器MCP命令参数 |
|
| arg | 否 | [] | stdio服务器MCP命令参数 |
|
||||||
| env | 否 | {} | stdio服务器环境变量 |
|
| env | 否 | {} | stdio服务器环境变量 |
|
||||||
| url | sse服务器必填 | 无 | sse服务器地址 |
|
| url | sse服务器必填 | 无 | sse服务器地址 |
|
||||||
|
| headers | 否 | {} | sse模式下http请求头,用于认证或其他设置 |
|
||||||
|
|
||||||
以下为在 Claude.app 的MCP服务器配置基础上增加的字段
|
以下为在 Claude.app 的MCP服务器配置基础上增加的字段
|
||||||
| 配置项 | 必填 | 默认值 | 说明 |
|
| 配置项 | 必填 | 默认值 | 说明 |
|
||||||
|
|
@ -179,7 +180,10 @@ LLMCHAT__MCP_SERVERS同样为一个dict,key为服务器名称,value配置的
|
||||||
"AISearch": {
|
"AISearch": {
|
||||||
"friendly_name": "百度搜索",
|
"friendly_name": "百度搜索",
|
||||||
"additional_prompt": "遇到你不知道的问题或者时效性比较强的问题时,可以使用AISearch搜索,在使用AISearch时不要使用其他AI模型。",
|
"additional_prompt": "遇到你不知道的问题或者时效性比较强的问题时,可以使用AISearch搜索,在使用AISearch时不要使用其他AI模型。",
|
||||||
"url": "http://appbuilder.baidu.com/v2/ai_search/mcp/sse?api_key=Bearer+<your-api-key>"
|
"url": "http://appbuilder.baidu.com/v2/ai_search/mcp/sse?api_key=Bearer+<your-api-key>",
|
||||||
|
"headers": {
|
||||||
|
"Authorization": "<some-api-key>"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"fetch": {
|
"fetch": {
|
||||||
"friendly_name": "网页浏览",
|
"friendly_name": "网页浏览",
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,8 @@ async def process_messages(group_id: int):
|
||||||
while not state.queue.empty():
|
while not state.queue.empty():
|
||||||
event = await state.queue.get()
|
event = await state.queue.get()
|
||||||
logger.debug(f"从队列获取消息 群号:{group_id} 消息ID:{event.message_id}")
|
logger.debug(f"从队列获取消息 群号:{group_id} 消息ID:{event.message_id}")
|
||||||
|
past_events_snapshot = []
|
||||||
|
mcp_client = MCPClient(plugin_config.mcp_servers)
|
||||||
try:
|
try:
|
||||||
systemPrompt = f"""
|
systemPrompt = f"""
|
||||||
我想要你帮我在群聊中闲聊,大家一般叫你{"、".join(list(driver.config.nickname))},我将会在后面的信息中告诉你每条群聊信息的发送者和发送时间,你可以直接称呼发送者为他对应的昵称。
|
我想要你帮我在群聊中闲聊,大家一般叫你{"、".join(list(driver.config.nickname))},我将会在后面的信息中告诉你每条群聊信息的发送者和发送时间,你可以直接称呼发送者为他对应的昵称。
|
||||||
|
|
@ -320,6 +322,7 @@ async def process_messages(group_id: int):
|
||||||
|
|
||||||
# 将机器人错过的消息推送给LLM
|
# 将机器人错过的消息推送给LLM
|
||||||
past_events_snapshot = list(state.past_events)
|
past_events_snapshot = list(state.past_events)
|
||||||
|
state.past_events.clear()
|
||||||
for ev in past_events_snapshot:
|
for ev in past_events_snapshot:
|
||||||
text_content = format_message(ev)
|
text_content = format_message(ev)
|
||||||
content.append({"type": "text", "text": text_content})
|
content.append({"type": "text", "text": text_content})
|
||||||
|
|
@ -345,7 +348,6 @@ async def process_messages(group_id: int):
|
||||||
"timeout": 60,
|
"timeout": 60,
|
||||||
}
|
}
|
||||||
|
|
||||||
mcp_client = MCPClient(plugin_config.mcp_servers)
|
|
||||||
if preset.support_mcp:
|
if preset.support_mcp:
|
||||||
await mcp_client.connect_to_servers()
|
await mcp_client.connect_to_servers()
|
||||||
available_tools = await mcp_client.get_available_tools()
|
available_tools = await mcp_client.get_available_tools()
|
||||||
|
|
@ -397,8 +399,6 @@ async def process_messages(group_id: int):
|
||||||
|
|
||||||
message = response.choices[0].message
|
message = response.choices[0].message
|
||||||
|
|
||||||
await mcp_client.cleanup()
|
|
||||||
|
|
||||||
reply, matched_reasoning_content = pop_reasoning_content(
|
reply, matched_reasoning_content = pop_reasoning_content(
|
||||||
response.choices[0].message.content
|
response.choices[0].message.content
|
||||||
)
|
)
|
||||||
|
|
@ -423,7 +423,6 @@ async def process_messages(group_id: int):
|
||||||
# 请求成功后再保存历史记录,保证user和assistant穿插,防止R1模型报错
|
# 请求成功后再保存历史记录,保证user和assistant穿插,防止R1模型报错
|
||||||
for message in new_messages:
|
for message in new_messages:
|
||||||
state.history.append(message)
|
state.history.append(message)
|
||||||
state.past_events.clear()
|
|
||||||
|
|
||||||
if state.output_reasoning_content and reasoning_content:
|
if state.output_reasoning_content and reasoning_content:
|
||||||
try:
|
try:
|
||||||
|
|
@ -450,11 +449,13 @@ async def process_messages(group_id: int):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.opt(exception=e).error(f"API请求失败 群号:{group_id}")
|
logger.opt(exception=e).error(f"API请求失败 群号:{group_id}")
|
||||||
|
# 如果在处理过程中出现异常,恢复未处理的消息到state中
|
||||||
|
state.past_events.extendleft(reversed(past_events_snapshot))
|
||||||
await handler.send(Message(f"服务暂时不可用,请稍后再试\n{e!s}"))
|
await handler.send(Message(f"服务暂时不可用,请稍后再试\n{e!s}"))
|
||||||
finally:
|
finally:
|
||||||
|
state.processing = False
|
||||||
state.queue.task_done()
|
state.queue.task_done()
|
||||||
|
await mcp_client.cleanup()
|
||||||
state.processing = False
|
|
||||||
|
|
||||||
|
|
||||||
# 预设切换命令
|
# 预设切换命令
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class MCPServerConfig(BaseModel):
|
||||||
args: list[str] | None = Field([], description="stdio模式下MCP命令参数")
|
args: list[str] | None = Field([], description="stdio模式下MCP命令参数")
|
||||||
env: dict[str, str] | None = Field({}, description="stdio模式下MCP命令环境变量")
|
env: dict[str, str] | None = Field({}, description="stdio模式下MCP命令环境变量")
|
||||||
url: str | None = Field(None, description="sse模式下MCP服务器地址")
|
url: str | None = Field(None, description="sse模式下MCP服务器地址")
|
||||||
|
headers: dict[str, str] | None = Field({}, description="sse模式下http请求头,用于认证或其他设置")
|
||||||
|
|
||||||
# 额外字段
|
# 额外字段
|
||||||
friendly_name: str | None = Field(None, description="MCP服务器友好名称")
|
friendly_name: str | None = Field(None, description="MCP服务器友好名称")
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class MCPClient:
|
||||||
for server_name, config in self.server_config.items():
|
for server_name, config in self.server_config.items():
|
||||||
logger.debug(f"正在连接服务器[{server_name}]")
|
logger.debug(f"正在连接服务器[{server_name}]")
|
||||||
if config.url:
|
if config.url:
|
||||||
sse_transport = await self.exit_stack.enter_async_context(sse_client(url=config.url))
|
sse_transport = await self.exit_stack.enter_async_context(sse_client(url=config.url, headers=config.headers))
|
||||||
read, write = sse_transport
|
read, write = sse_transport
|
||||||
self.sessions[server_name] = await self.exit_stack.enter_async_context(ClientSession(read, write))
|
self.sessions[server_name] = await self.exit_stack.enter_async_context(ClientSession(read, write))
|
||||||
await self.sessions[server_name].initialize()
|
await self.sessions[server_name].initialize()
|
||||||
|
|
@ -74,6 +74,7 @@ class MCPClient:
|
||||||
return response.content
|
return response.content
|
||||||
|
|
||||||
def get_friendly_name(self, tool_name: str):
|
def get_friendly_name(self, tool_name: str):
|
||||||
|
logger.debug(tool_name)
|
||||||
server_name, real_tool_name = tool_name.split("___")
|
server_name, real_tool_name = tool_name.split("___")
|
||||||
return (self.server_config[server_name].friendly_name or server_name) + " - " + real_tool_name
|
return (self.server_config[server_name].friendly_name or server_name) + " - " + real_tool_name
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "nonebot-plugin-llmchat"
|
name = "nonebot-plugin-llmchat"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
description = "Nonebot AI group chat plugin supporting multiple API preset configurations"
|
description = "Nonebot AI group chat plugin supporting multiple API preset configurations"
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
authors = ["FuQuan i@fuquan.moe"]
|
authors = ["FuQuan i@fuquan.moe"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue