feat: 解藕chat的处理器和请求器 (#772)

This commit is contained in:
RockChinQ
2024-05-14 22:20:31 +08:00
parent 972d3c18af
commit 527ad81d38
17 changed files with 205 additions and 137 deletions
+4 -1
View File
@@ -8,7 +8,10 @@ from ...config import manager as cfg_mgr
@stage.stage_class('BanSessionCheckStage')
class BanSessionCheckStage(stage.PipelineStage):
"""访问控制处理阶段"""
"""访问控制处理阶段
仅检查query中群号或个人号是否在访问控制列表中。
"""
async def initialize(self):
pass
+12 -1
View File
@@ -14,7 +14,18 @@ from .filters import cntignore, banwords, baiduexamine
@stage.stage_class('PostContentFilterStage')
@stage.stage_class('PreContentFilterStage')
class ContentFilterStage(stage.PipelineStage):
"""内容过滤阶段"""
"""内容过滤阶段
前置:
检查消息是否符合规则,不符合则拦截。
改写:
message_chain
后置:
检查AI回复消息是否符合规则,可能进行改写,不符合则拦截。
改写:
query.resp_messages
"""
filter_chain: list[filter_model.ContentFilter]
+1 -1
View File
@@ -8,7 +8,7 @@ from ....config import manager as cfg_mgr
@filter_model.filter_class("ban-word-filter")
class BanWordFilter(filter_model.ContentFilter):
"""根据内容禁言"""
"""根据内容过滤"""
async def initialize(self):
pass
+3
View File
@@ -16,6 +16,9 @@ from ...config import manager as cfg_mgr
@stage.stage_class("LongTextProcessStage")
class LongTextProcessStage(stage.PipelineStage):
"""长消息处理阶段
改写:
- resp_message_chain
"""
strategy_impl: strategy.LongTextStrategy
+12 -3
View File
@@ -9,6 +9,16 @@ from ...plugin import events
@stage.stage_class("PreProcessor")
class PreProcessor(stage.PipelineStage):
"""请求预处理阶段
签出会话、prompt、上文、模型、内容函数。
改写:
- session
- prompt
- messages
- user_message
- use_model
- use_funcs
"""
async def process(
@@ -27,7 +37,7 @@ class PreProcessor(stage.PipelineStage):
query.prompt = conversation.prompt.copy()
query.messages = conversation.messages.copy()
query.user_message = llm_entities.Message(
query.user_message = llm_entities.Message( # TODO 适配多模态输入
role='user',
content=str(query.message_chain).strip()
)
@@ -37,11 +47,10 @@ class PreProcessor(stage.PipelineStage):
query.use_funcs = conversation.use_funcs
# =========== 触发事件 PromptPreProcessing
session = query.session
event_ctx = await self.ap.plugin_mgr.emit_event(
event=events.PromptPreProcessing(
session_name=f'{session.launcher_type.value}_{session.launcher_id}',
session_name=f'{query.session.launcher_type.value}_{query.session.launcher_id}',
default_prompt=query.prompt.messages,
prompt=query.messages,
query=query
+64 -6
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import typing
import time
import traceback
import json
import mirai
@@ -70,17 +71,13 @@ class ChatMessageHandler(handler.MessageHandler):
mirai.Plain(event_ctx.event.alter)
])
query.messages.append(
query.user_message
)
text_length = 0
start_time = time.time()
try:
async for result in query.use_model.requester.request(query):
async for result in self.runner(query):
query.resp_messages.append(result)
self.ap.logger.info(f'对话({query.query_id})响应: {self.cut_str(result.readable_str())}')
@@ -115,4 +112,65 @@ class ChatMessageHandler(handler.MessageHandler):
model_name=query.use_model.name,
response_seconds=int(time.time() - start_time),
retry_times=-1,
)
)
async def runner(
self,
query: core_entities.Query,
) -> typing.AsyncGenerator[llm_entities.Message, None]:
"""执行一个请求处理过程中的LLM接口请求、函数调用的循环
这是临时处理方案,后续可能改为使用LangChain或者自研的工作流处理器
"""
await query.use_model.requester.preprocess(query)
pending_tool_calls = []
req_messages = query.prompt.messages.copy() + query.messages.copy() + [query.user_message]
# 首次请求
msg = await query.use_model.requester.call(query.use_model, req_messages, query.use_funcs)
yield msg
pending_tool_calls = msg.tool_calls
req_messages.append(msg)
# 持续请求,只要还有待处理的工具调用就继续处理调用
while pending_tool_calls:
for tool_call in pending_tool_calls:
try:
func = tool_call.function
parameters = json.loads(func.arguments)
func_ret = await self.ap.tool_mgr.execute_func_call(
query, func.name, parameters
)
msg = llm_entities.Message(
role="tool", content=json.dumps(func_ret, ensure_ascii=False), tool_call_id=tool_call.id
)
yield msg
req_messages.append(msg)
except Exception as e:
# 工具调用出错,添加一个报错信息到 req_messages
err_msg = llm_entities.Message(
role="tool", content=f"err: {e}", tool_call_id=tool_call.id
)
yield err_msg
req_messages.append(err_msg)
# 处理完所有调用,再次请求
msg = await query.use_model.requester.call(query.use_model, req_messages, query.use_funcs)
yield msg
pending_tool_calls = msg.tool_calls
req_messages.append(msg)
+7 -1
View File
@@ -11,7 +11,13 @@ from ...config import manager as cfg_mgr
@stage.stage_class("MessageProcessor")
class Processor(stage.PipelineStage):
"""请求实际处理阶段"""
"""请求实际处理阶段
通过命令处理器和聊天处理器处理消息。
改写:
- resp_messages
"""
cmd_handler: handler.MessageHandler
+4 -1
View File
@@ -11,7 +11,10 @@ from ...core import entities as core_entities
@stage.stage_class("RequireRateLimitOccupancy")
@stage.stage_class("ReleaseRateLimitOccupancy")
class RateLimit(stage.PipelineStage):
"""限速器控制阶段"""
"""限速器控制阶段
不改写query,只检查是否需要限速。
"""
algo: algo.ReteLimitAlgo
+4 -1
View File
@@ -14,9 +14,12 @@ from ...config import manager as cfg_mgr
@stage.stage_class("GroupRespondRuleCheckStage")
class GroupRespondRuleCheckStage(stage.PipelineStage):
"""群组响应规则检查器
仅检查群消息是否符合规则。
"""
rule_matchers: list[rule.GroupRespondRule]
"""检查器实例"""
async def initialize(self):
"""初始化检查器
@@ -31,7 +34,7 @@ class GroupRespondRuleCheckStage(stage.PipelineStage):
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
if query.launcher_type.value != 'group':
if query.launcher_type.value != 'group': # 只处理群消息
return entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
new_query=query
+11 -11
View File
@@ -17,17 +17,17 @@ from .ratelimit import ratelimit
# 请求处理阶段顺序
stage_order = [
"GroupRespondRuleCheckStage",
"BanSessionCheckStage",
"PreContentFilterStage",
"PreProcessor",
"RequireRateLimitOccupancy",
"MessageProcessor",
"ReleaseRateLimitOccupancy",
"PostContentFilterStage",
"ResponseWrapper",
"LongTextProcessStage",
"SendResponseBackStage",
"GroupRespondRuleCheckStage", # 群响应规则检查
"BanSessionCheckStage", # 封禁会话检查
"PreContentFilterStage", # 内容过滤前置阶段
"PreProcessor", # 预处理器
"RequireRateLimitOccupancy", # 请求速率限制占用
"MessageProcessor", # 处理器
"ReleaseRateLimitOccupancy", # 释放速率限制占用
"PostContentFilterStage", # 内容过滤后置阶段
"ResponseWrapper", # 响应包装器
"LongTextProcessStage", # 长文本处理
"SendResponseBackStage", # 发送响应
]
+8 -1
View File
@@ -14,6 +14,13 @@ from ...plugin import events
@stage.stage_class("ResponseWrapper")
class ResponseWrapper(stage.PipelineStage):
"""回复包装阶段
把回复的 message 包装成人类识读的形式。
改写:
- resp_message_chain
"""
async def initialize(self):
pass
@@ -128,4 +135,4 @@ class ResponseWrapper(stage.PipelineStage):
yield entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
new_query=query
)
)