ðš 08 - æ¶æ¯å€çæµçš â
æ¬ææ¡£è¯Šç»æè¿° XiaoQing çæ¶æ¯å€çé»èŸïŒå æ¬æ¶æ¯æ¥æ¶ãè·¯ç±ãåœä»€è§£æãäŒè¯ç®¡çç宿޿µçšã
TIP
æ³å¿«éå®äœé®é¢ïŒè·³èœ¬ 9ïžâ£ 宿Žå€çæµçšåŸ æ¥ç端å°ç«¯ç€ºæåŸïŒåæéæ¥é 对åºç« èã
ð ç®åœ â
- æ¶æ¯å€çæ»è§
- æ¶æ¯æ¥æ¶äžè§£æ
- è§Šåæ¡ä»¶å€æ
- åœä»€è·¯ç±äžåæ°æå
- äŒè¯ç®¡ç
- é²èå€ç
- é鳿ºå¶
- å¹¶åæ§å¶äžæ¶æ¯éå
- 宿Žå€çæµçšåŸ
1ïžâ£ æ¶æ¯å€çæ»è§ â
XiaoQing çæ¶æ¯å€çç±ä»¥äžæ žå¿æš¡ååäœå®æïŒ
| æš¡å | æä»¶ | è莣 |
|---|---|---|
| Dispatcher | core/dispatcher.py | æ¶æ¯åååšïŒåè°æŽäžªå€çæµçš |
| CommandRouter | core/router.py | åœä»€è·¯ç±ïŒå¹é è§Šåè¯å¹¶æååæ° |
| SessionManager | core/session.py | äŒè¯ç®¡çïŒæ¯æå€èœ®å¯¹è¯ |
| message | core/message.py | æ¶æ¯è§£æå·¥å ·åœæ° |
1.1 å€çæµçšæŠè¿° â
OneBot äºä»¶
â
Dispatcher.handle_event()
â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 1. äºä»¶ç±»åæ£æ¥ïŒä»
å€ç message ç±»åïŒ â
â 2. æ¶æ¯è§£æïŒæåææ¬ãuser_idãgroup_idïŒ â
â 3. URL æ£æµïŒå
šå±çå¬ïŒå¯éïŒ â
â 4. å³çå€æïŒæ¯åŠéèŠå€çïŒ â
â 5. Handler éŸåŒå€çïŒæäŒå
çº§äŸæ¬¡å°è¯ïŒ â
â - BotNameHandler â ä»
æºåšäººåå â
â - CommandHandler â åœä»€å¹é
â
â - SessionHandler â æŽ»è·äŒè¯ â
â - SmalltalkHandler â é²è â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
è¿å OneBot æ¶æ¯æ®µå衚1.2 Handler éŸåŒæ¶æ â
XiaoQing éçš èŽ£ä»»éŸæš¡åŒ æ¥å€çæ¶æ¯ïŒæ¯äžª Handler æé¡ºåºå°è¯å€çæ¶æ¯ïŒåŠæå€çæååè¿åïŒåŠåäŒ éç»äžäžäžª Handlerã
Handler éŸé¡ºåº â
self._handlers: tuple[MessageHandler, ...] = (
BotNameHandler(self), # 1. å€çä»
æåæºåšäººååçæ¶æ¯
CommandHandler(self), # 2. å¹é
å¹¶æ§è¡åœä»€
SessionHandler(self), # 3. å€ç掻è·äŒè¯
SmalltalkHandler(self), # 4. å€çé²è
)å Handler è莣 â
| Handler | å€çåºæ¯ | è¿åæ¡ä»¶ |
|---|---|---|
| BotNameHandler | çšæ·ä» åéæºåšäººååïŒåŠ "å°é"ïŒ | ææ¬ä» å å« bot_name æå ¶åäœ |
| CommandHandler | çšæ·åéåœä»€ïŒåŠ "/help"ïŒ | åœä»€è·¯ç±å¹é æå |
| SessionHandler | çšæ·å€äºæŽ»è·äŒè¯äž | ååšæŽ»è·äŒè¯ |
| SmalltalkHandler | å ¶ä»æ åµïŒé²èïŒ | smalltalk_mode 䞺 True |
å ³é®ç¹æ§ â
- çè·¯æºå¶ïŒäžæŠæäžª Handler å€çæåïŒåç» Handler äžäŒæ§è¡
- äŒå 级æç¡®ïŒåœä»€äŒå äºäŒè¯ïŒäŒè¯äŒå äºé²è
- ç¬ç«å³çïŒæ¯äžª Handler ç¬ç«å³å®æ¯åŠå€çïŒäºäžåœ±å
xiaoqing_chat ç¹æ®å€ç â
åœ smalltalk_provider 讟眮䞺 xiaoqing_chat æ¶ïŒå³çé»èŸç¹æ®ïŒ
if self._get_smalltalk_provider() == "xiaoqing_chat":
return ProcessDecision(True, True) # æææ¶æ¯éœå
讞è¿å
¥ SmalltalkHandlerè¿æå³çïŒ
random_reply_rateé 眮倱æ - ææçŸ€èæ¶æ¯éœäŒè¿å ¥ xiaoqing_chat- æä»¶èªäž»æ§å¶ - xiaoqing_chat æä»¶å éšæèªå·±çé¢çæ§å¶åå倿Šç倿
- è¿å空å衚äžåå€ - åŠææä»¶å³å®äžåå€ïŒè¿å
[]å³å¯
è¿ç§è®Ÿè®¡è®© LLM æš¡åèœå€æ ¹æ®äžäžææºèœå€ææ¯åŠéèŠåå€ïŒæ¯ç®åçéæºæŠçæŽæºèœã
2ïžâ£ æ¶æ¯æ¥æ¶äžè§£æ â
2.1 äºä»¶æ ŒåŒ â
XiaoQing æ¥æ¶ OneBot æ åæ ŒåŒçæ¶æ¯äºä»¶ïŒ
{
"post_type": "message",
"message_type": "group",
"user_id": 123456789,
"group_id": 987654321,
"message": [
{"type": "text", "data": {"text": "/help æ¥çåž®å©"}}
]
}2.2 æ¶æ¯è§£æ â
normalize_message() åœæ°ä»äºä»¶äžæåå
³é®ä¿¡æ¯ïŒ
text, user_id, group_id = normalize_message(event)
# text: "/help æ¥çåž®å©"
# user_id: 123456789
# group_id: 987654321 (ç§èæ¶äžº None)2.3 ææ¬æå â
extract_text() åœæ°ä» OneBot æ¶æ¯æ®µäžæåçº¯ææ¬ïŒ
- åç¬Šäž²æ¶æ¯: çŽæ¥è¿å
- æ¶æ¯æ®µæ°ç»: æåææ
type: "text"æ®µçææ¬å¹¶æŒæ¥ - å ¶ä»ç±»åïŒåŸçã@çïŒ: 被応ç¥
# èŸå
¥
message = [
{"type": "at", "data": {"qq": "123"}},
{"type": "text", "data": {"text": "äœ å¥œ"}},
{"type": "image", "data": {"file": "abc.jpg"}},
{"type": "text", "data": {"text": "äžç"}}
]
# èŸåº
text = "äœ å¥œäžç"3ïžâ£ å³ç倿 â
3.1 å³çé»èŸ â
_decide_process() æ¹æ³å€ææ¶æ¯æ¯åŠéèŠå€çïŒè¿å ProcessDecision(should_process, smalltalk_mode)ïŒ
| åºæ¯ | should_process | smalltalk_mode | 诎æ |
|---|---|---|---|
| ç§è | â True | â True | ç§èæ¶æ¯å§ç»å€çïŒå¯é²è |
| 矀è + åœä»€åçŒ | â True | â False | åŠ /helpïŒäžè§Šåé²è |
| 矀è + å å« bot_name | â True | â ïž åå³äºéé³ | åŠ å°é äœ å¥œ |
| 矀è + éæºè§Šå | â True | â True | æ random_reply_rate æŠç |
| 矀è + éé³äž | â False | â False | é€éæåœä»€åçŒæ bot_name |
3.2 å³çäž Handler éŸçå ³ç³» â
éèŠçè§£ïŒå³ç倿çç»æäŒåœ±å Handler éŸçæ§è¡ïŒ
should_process = FalseïŒçŽæ¥è¿å[]ïŒææ Handler éœäžäŒæ§è¡should_process = TrueïŒè¿å ¥ Handler éŸïŒæé¡ºåºå°è¯å䞪 Handler
ç¹æ®åºæ¯ïŒ
- 掻è·äŒè¯ååšïŒæ 论
should_processåŠäœïŒSessionHandleréœäŒå€çïŒäŒè¯äŒå 级æé«ïŒ - xiaoqing_chat äœäžº smalltalk_providerïŒå³çé»èŸç¹æ®ïŒææçŸ€èæ¶æ¯éœè¿å
(True, True)ïŒrandom_reply_rate倱æ
3.3 é 眮项 â
{
"bot_name": "å°é",
"command_prefixes": ["/"],
"require_bot_name_in_group": true,
"random_reply_rate": 0.05
}- bot_name: æºåšäººåç§°ïŒçŸ€èäžæåæ¶è§Šå
- command_prefixes: åœä»€åçŒå衚ïŒé垞䞺
["/"] - require_bot_name_in_group: çŸ€èæ¯åŠéèŠ @ ææå bot_name
- random_reply_rate: æ è§Šåæ¡ä»¶æ¶éæºåå€çæŠç (0-1)
3.4 åçŒå¥çŠ» â
parse_text_command_context() åœæ°æç
§ä»¥äžé¡ºåºäž¥æ Œå€çåçŒå¥çŠ»ïŒ
- å»é€ @æºåšäººïŒäŸåŠ
[CQ:at,qq=123]ïŒ - å»é€ bot_nameïŒäŸåŠ
å°éïŒæ¯ææš¡ç³å¹é åå ¶åçæ ç¹ïŒ - å»é€ command_prefixesïŒäŸåŠ
/ïŒ
â ïž éèŠè§£æè§åïŒ
åœçšæ·èŸå
¥ å°éé
眮 æ¶ïŒ
bot_nameïŒå°éïŒéŠå è¢«æ£æµå¹¶ç§»é€ïŒå©äœææ¬å䞺é 眮ã- éåå°è¯ç§»é€åœä»€åçŒïŒåŠ
/ïŒïŒå äžå¹é èè·³è¿ã - æç»äŒ éç» Router çææ¬æ¯
é 眮ã
è¿æå³çïŒåŠæäœ çæä»¶åœä»€è§Šåè¯å®ä¹äžº ["å°éé
眮"]ïŒå°äŒå¹é
倱莥ïŒå 䞺 Router çå°çæ¯ "é
眮"ã
æäœ³å®è·µïŒ å»ºè®®åš plugin.json äžå®ä¹è§Šåè¯æ¶ïŒå
å«å¥çŠ» bot ååççæ¬ã
# èŸå
¥: "å°é /help æ¥çåž®å©"
# 1. å¥çŠ» bot_name -> "/help æ¥çåž®å©"
# 2. å¥çŠ» prefix -> "help æ¥çåž®å©"
# ç»æ: å¹é
trigger "help"# èŸå
¥: "å°éé
眮"
# 1. å¥çŠ» bot_name -> "é
眮"
# 2. å¥çŠ» prefix -> "é
眮" (æ åçŒå¯å¥çŠ»)
# ç»æ: éå¹é
trigger "é
眮" (å æ€å»ºè®®åš json äžæ·»å "é
眮" äœäžº trigger)4ïžâ£ åœä»€è·¯ç±äžåæ°æå â
4.1 åœä»€æ³šå â
æ¯äžªæä»¶åš plugin.json äžå£°æåœä»€ïŒ
{
"commands": [
{
"name": "help",
"triggers": ["help", "h", "åž®å©"],
"help": "æ¥çåž®å© | /help [å
³é®è¯]",
"admin_only": false,
"priority": 0
}
]
}4.2 è·¯ç±å¹é â
CommandRouter.resolve() æ¹æ³å¹é
åœä»€ïŒ
resolved = router.resolve("help æ¥çåž®å©")
# resolved = (CommandSpec, args)
# spec.name = "help"
# spec.plugin = "core"
# args = "æ¥çåž®å©"å¹é è§åïŒ
- éåæææ³šåçåœä»€
- æ£æ¥ææ¬æ¯åŠä»¥ä»»æ trigger åŒå€Ž
- æäŒå 级æåºïŒpriority è¶å€§è¶äŒå ïŒ
- åäŒå 级æ¶ïŒtrigger è¶é¿è¶äŒå
4.3 åæ°æå â
å¹é
æååïŒtrigger åé¢çææ¬äœäžº args äŒ éç» handlerïŒ
èŸå
¥ææ¬: "echo äœ å¥œ äžç"
å¹é
trigger: "echo"
args: "äœ å¥œ äžç"æä»¶å¯äœ¿çš core.args æš¡åè¿äžæ¥è§£æåæ°ïŒ
from core.args import parse
parsed = parse("äœ å¥œ äžç -v --name=test")
# parsed.tokens = ["äœ å¥œ", "äžç"]
# parsed.first = "äœ å¥œ"
# parsed.second = "äžç"
# parsed.opt("v") = "true"
# parsed.opt("name") = "test"4.4 Handler è°çš â
async def handle(command: str, args: str, event: dict, context) -> List[dict]:
"""
Args:
command: åœä»€åïŒplugin.json äžç nameïŒ
args: åæ°å笊䞲ïŒtrigger åçéšåïŒ
event: åå§ OneBot äºä»¶
context: æä»¶äžäžæ
Returns:
OneBot æ¶æ¯æ®µå衚
"""5ïžâ£ äŒè¯ç®¡ç â
5.1 äŒè¯è§Šå â
äŒè¯æ¯ Handler éŸç第äžç¯ïŒåšåœä»€å¹é å€±èŽ¥åæ§è¡ïŒ
# SessionHandler å€çé»èŸ
session = await session_manager.get(user_id, group_id)
if session:
# è·¯ç±å°äŒè¯æä»¶ç handle_session()éèŠç¹æ§ïŒ
- äŒå 级ïŒäŒè¯å€çåšåœä»€ä¹åãé²èä¹å
- ç»è¿è§Šåæ¡ä»¶ïŒå³äœ¿
should_process = FalseïŒæŽ»è·äŒè¯ä»äŒå€ç - ç¬ç«å€çïŒäŒè¯å€çäžå
random_reply_rateæbot_name圱å
5.2 äŒè¯å建 â
æä»¶éè¿ context.create_session() å建äŒè¯ïŒ
async def handle(command, args, event, context):
session = await context.create_session(
initial_data={"target": 42},
timeout=180 # 3 åéè¶
æ¶
)
return segments("æžžæåŒå§ïŒ")5.3 äŒè¯å€ç â
åœçšæ·åšäŒè¯äžåéæ¶æ¯æ¶ïŒè°çš handle_session()ïŒ
async def handle_session(text: str, event: dict, context, session) -> List[dict]:
"""
Args:
text: çšæ·èŸå
¥çææ¬
event: åå§äºä»¶
context: æä»¶äžäžæ
session: åœåäŒè¯å¯¹è±¡
"""
guess = int(text)
target = session.get("target")
if guess == target:
await context.end_session()
return segments("æåïŒç对äºïŒ")5.4 éåºåœä»€ â
以äžåœä»€å¯éåºäŒè¯ïŒ
éåºãåæ¶ãexitãquitãq
6ïžâ£ é²èå€ç â
6.1 è§Šåæ¡ä»¶ â
åœä»¥äžæ¡ä»¶éœæ»¡è¶³æ¶è¿å ¥é²èæš¡åŒïŒ
- 没æå¹é å°åœä»€
- æ²¡ææŽ»è·äŒè¯
smalltalk_mode = True
6.2 é²èæäŸè â
éè¿é çœ®éæ©é²èæä»¶ïŒ
{
"plugins": {
"smalltalk_provider": "xiaoqing_chat"
}
}æ¯æçæäŸè ïŒ
- smalltalk: åºäºè§åçç®åé²è
- xiaoqing_chat: åºäº LLM çæºèœå¯¹è¯
6.3 xiaoqing_chat ç¹æ®å€ç â
åœ smalltalk_provider 讟眮䞺 xiaoqing_chat æ¶ïŒ
random_reply_rateäžçæ - ææçŸ€èæ¶æ¯éœäŒè¿å ¥xiaoqing_chatå€ç- æä»¶èªè¡å³å®æ¯åŠåå€ -
xiaoqing_chatæèªå·±çé¢çæ§å¶åå倿Šç倿 - è¿å空å衚衚瀺äžåå€ - åŠææä»¶å³å®äžåå€ïŒè¿å
[]å³å¯
è¿æ ·è®Ÿè®¡çåå æ¯ LLM æš¡åå¯ä»¥æ ¹æ®äžäžæå€ææ¯åŠéèŠåå€ïŒæ¯ç®åçéæºæŠçæŽæºèœã
6.4 å€çåœæ° â
é²èæä»¶éå®ç° handle_smalltalk()ïŒ
async def handle_smalltalk(text: str, event: dict, context) -> List[dict]:
"""
Args:
text: çšæ·èŸå
¥ïŒå·²å»é€åçŒïŒ
event: åå§äºä»¶
context: æä»¶äžäžæ
Returns:
å倿¶æ¯æ®µïŒæ None/[] 衚瀺äžåå€
"""7ïžâ£ é鳿ºå¶ â
7.1 éé³åœä»€ â
/éåŽ 30 # éé³ 30 åé
/éåŽ 1h # éé³ 1 å°æ¶
/è¯Žè¯ # è§£é€éé³7.2 éé³åœ±å â
| æ¶æ¯ç±»å | é鳿¶æ¯åŠå€ç |
|---|---|
| 垊åœä»€åçŒçæ¶æ¯ | â å€ç |
| äž»åš @ æºåšäºº | â å€çåœä»€ïŒâ äžé²è |
| éæºåå€ | â äžåå€ |
| 宿¶ä»»å¡ | â äžåéïŒç±æä»¶èªè¡å€æïŒ |
8ïžâ£ å¹¶åæ§å¶äžæ¶æ¯éå â
8.1 æŠè¿° â
XiaoQing 䜿çšå€å±å¹¶åæ§å¶æºå¶æ¥ç®¡çæ¶æ¯å€çïŒç¡®ä¿ç³»ç»çš³å®æ§åååºæ§èœã
8.2 OneBot WebSocket Client å€çæµçš â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â OneBot æå¡åš (NapCatQQ/go-cqhttp) â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â WebSocket æ¶æ¯æšé
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â OneBotWsClient._listen() â
â æ¥æ¶å¹¶è§£æ WebSocket æ¶æ¯ â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 第äžå±æ§å¶ïŒ_pending_semaphore â
â æå€ 100 äžªæ¶æ¯çåŸ
ååïŒç¡¬çŒç ïŒäžå¯é
çœ®ïŒ â
â â
â async with self._pending_semaphore: â
â await self._dispatch_event(handler, event) â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â æçšæ·/矀åéå (æºèœè®Ÿè®¡) â
â â
â æ ¹æ® queue_key ååå°äžåéåïŒ â
â - group:123:user:456 â Queue1 [event1, event2] â
â - user:789 â Queue2 [event3] â
â - group:999:user:111 â Queue3 [event4, event5] â
â â
â æ¯äžªéåæç¬ç«ç _drain_queue() åçšäž²è¡å€ç â
â ä¿è¯ïŒåäžçšæ·åšåäžçŸ€çæ¶æ¯æé¡ºåºå€ç â
â å
讞ïŒäžåçšæ·/çŸ€çæ¶æ¯å¹¶è¡å€ç â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â _drain_queue() â handler() â app._process_event() â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 第äºå±æ§å¶ïŒmax_concurrency (é»è®€ 5) ð¥ â
â â
â Dispatcher.handle_event(): â
â async with self.semaphore: â
â return await self._process_event(event) â
â â
â â
å
šå±å¹¶åæ§å¶çæ žå¿ â
â â
å¯¹æææ¥æ¶æ¹åŒïŒWS Client/InboundïŒéœçæ â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââââ
â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â æ§è¡åœä»€/äŒè¯/é²èå€çå¹¶è¿åç»æ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ8.3 䞀å±å¹¶åæ§å¶æºå¶ â
第äžå±ïŒ_pending_semaphore (max_pending_events = 100) â
- äœçœ®ïŒ
core/onebot.py - äœçšïŒéå¶åæ¶çåŸ ååçäºä»¶æ°é
- æ¯åŠå¯é 眮ïŒâ åŠïŒç¡¬çŒç ïŒ
- 圱åïŒä» 对 OneBot WS Client ææ
第äºå±ïŒmax_concurrency (é»è®€ 5) ð¥ â
- äœçœ®ïŒ
core/dispatcher.py - äœçšïŒéå¶åæ¶æ§è¡å€çé»èŸçæ°éïŒçæ£çå¹¶åæ§å¶ïŒ
- æ¯åŠå¯é
眮ïŒâ
æ¯ïŒ
config.jsonïŒ - 圱åïŒå šå±çæïŒWS ClientãInbound ServerïŒ
8.4 æçšæ·/矀åéå讟计 â
æ žå¿è®Ÿè®¡ïŒæ¯äžª (group_id, user_id) ç»å对åºäžäžªç¬ç«éåã
queue_key çæè§åïŒ
# çŸ€èæ¶æ¯
queue_key = f"group:{group_id}:user:{user_id}"
# ç§èæ¶æ¯
queue_key = f"user:{user_id}"äŒå¿ïŒ
- â ä¿è¯é¡ºåºïŒåäžçšæ·åšåäžçŸ€çæ¶æ¯äž¥æ Œæé¡ºåºå€ç
- â æé«ååïŒäžåçšæ·/çŸ€çæ¶æ¯å¯ä»¥å¹¶è¡å€ç
- â é¿å é»å¡ïŒæäžªçšæ·çæ ¢æäœäžåœ±åå ¶ä»çšæ·
å®é è¿è¡ç€ºäŸïŒ
å讟 max_concurrency = 5ïŒåæ¶æ¶å°åŠäžæ¶æ¯ïŒ
| æ¶éŽ | æ¥æº | queue_key | ç¶æ |
|---|---|---|---|
| T1 | 矀Açšæ·1 | group:A:user:1 | â è·åŸç¬¬1äžªå¹¶åæ§œ |
| T2 | 矀Açšæ·1 | group:A:user:1 | â³ åšéåäžçåŸ ïŒåäžçšæ·äž²è¡ïŒ |
| T3 | 矀Bçšæ·2 | group:B:user:2 | â è·åŸç¬¬2äžªå¹¶åæ§œ |
| T4 | 矀Cçšæ·3 | group:C:user:3 | â è·åŸç¬¬3äžªå¹¶åæ§œ |
| T5 | 矀Dçšæ·4 | group:D:user:4 | â è·åŸç¬¬4äžªå¹¶åæ§œ |
| T6 | 矀Eçšæ·5 | group:E:user:5 | â è·åŸç¬¬5äžªå¹¶åæ§œ |
| T7 | 矀Fçšæ·6 | group:F:user:6 | âžïž çåŸ å¹¶åæ§œéæŸ |
| T8 | 矀Açšæ·1 | group:A:user:1 | â³ åšéåäžçåŸ ïŒæåš T2 åé¢ïŒ |
8.5 Inbound WebSocket Server éåæºå¶ â
å¯¹äº Inbound ServerïŒè¢«å𿥿¶æšéïŒïŒæé¢å€çéåæºå¶ïŒ
WebSocket æ¶æ¯å°èŸŸ
â
æŸå
¥éå (maxsize = ws_queue_size, é»è®€ 200)
â
inbound_ws_max_workers 䞪 worker ä»éååæ¶æ¯ (é»è®€ 8 䞪)
â
éè¿ Semaphore è·åå€çè®žå¯ (max_concurrency, é»è®€ 5)
â
å€çæ¶æ¯ (Dispatcher)é çœ®åæ°ïŒ
| åæ° | é»è®€åŒ | äœçšèåŽ | 诎æ |
|---|---|---|---|
ws_queue_size | 200 | Inbound + OneBot | çåŸ å€ççæ¶æ¯éåé¿åºŠ |
inbound_ws_max_workers | 8 | Inbound Server | å¹¶åå€çéåæ¶æ¯ç worker æ° |
â ïž æ³šæïŒinbound_ws_max_workers ä»
对 Inbound WS Server ææïŒws_queue_size åæ¶åœ±å Inbound WS Server äž OneBot WS Clientã
8.6 æ žå¿é çœ®åæ° â
| åæ° | é»è®€åŒ | éçšèåŽ | 诎æ |
|---|---|---|---|
max_concurrency | 5 | å šå± | ð¥ æéèŠïŒå šå±å¹¶åæ§å¶ |
inbound_ws_max_workers | 8 | Inbound Server | Worker åçšæ° |
ws_queue_size | 200 | Inbound + OneBot | éåé¿åºŠïŒ0 衚瀺äžéå¶ïŒ |
8.7 é 眮建议 â
äœèŽèœœåºæ¯ïŒäžªäººäœ¿çšïŒ1-3 äžªçŸ€ïŒ â
{
"max_concurrency": 5
}äžçèŽèœœïŒå€äžªæŽ»è·çŸ€ç»ïŒ â
{
"max_concurrency": 10,
"ws_queue_size": 300,
"inbound_ws_max_workers": 12
}é«èŽèœœåºæ¯ïŒå€§é矀ç»ïŒé¢ç¹æ¶æ¯ïŒ â
{
"max_concurrency": 20,
"ws_queue_size": 500,
"inbound_ws_max_workers": 24
}äŒåååïŒ
inbound_ws_max_workers >= max_concurrencyïŒé¿å worker 空é²ïŒws_queue_sizeè¶³å€å€§ä»¥åžæ¶çªåæµéïŒæè®Ÿäžº 0 äžéå¶ïŒmax_concurrencyäžèŠè®Ÿçœ®è¿é«ïŒé¿å èµæºèå°œ
8.8 æ§èœçæ§ â
æ¥çéåç¶æïŒ
GET /healthååºç€ºäŸïŒ
{
"status": "ok",
"ws_connections": 1,
"pending_jobs": 3,
"active_sessions": 2
}9ïžâ£ 宿Žå€çæµçšåŸ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â OneBot æ¶æ¯äºä»¶å°èŸŸ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âŒ
âââââââââââââââââââ
â post_type == â
â "message" ? â
ââââââââââ¬âââââââââ
â
ââââââââââŽâââââââââ
â â
Yes No ââââââââââââââââââ⺠応ç¥
â
âŒ
âââââââââââââââââââââââââ
â normalize_message â
â æå text, user_id, â
â group_id â
âââââââââââââ¬ââââââââââââ
â
âŒ
âââââââââââââââââââââââââ
â URL æ£æµ âââââ æ URL äžæ åçŒ ââââ⺠url_parser
âââââââââââââ¬ââââââââââââ
â
âŒ
âââââââââââââââââââââââââ
â _decide_process â
â 倿æ¯åŠå€çæ¶æ¯ â
âââââââââââââ¬ââââââââââââ
â
ââââââââââŽâââââââââ
â â
should_process äžå€ç ââââââââââââââââââââââ⺠è¿å []
= True
â
âŒ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Handler éŸåŒå€ç â
â æäŒå
çº§äŸæ¬¡å°è¯ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
ââââââââââŽâââââââââ
â â
BotNameHandler 倱莥
ä»
æºåšäººåå? â
â â
ââââââŽâââââ âŒ
Yes No âââââââââââââââââââ
â â â CommandHandler â
⌠â â åœä»€å¹é
? â
å€ç宿 â ââââââââââ¬âââââââââ
_handle_bot â â
_name_only â âââââââââŽââââââââ
â å¹é
æå æªå¹é
â â â
â ⌠âŒ
â âââââââââââââ âââââââââââââââââââ
â â æéæ£æ¥ â â SessionHandler â
â âââââââ¬ââââââ â æŽ»è·äŒè¯? â
â â ââââââââââ¬âââââââââ
â ⌠ââââââââââŽâââââââââ
â âââââââââââââ æäŒè¯ æ äŒè¯
â â æ§è¡åœä»€ â â â
â â handler() â ⌠âŒ
â âââââââ¬ââââââ ââââââââââââ âââââââââââââââââââ
â â âhandle_ â â SmalltalkHandlerâ
â â âsession() â â smalltalk_mode? â
â â âââââââ¬âââââ ââââââââââ¬âââââââââ
â â â ââââââââââŽâââââââââ
â â â Yes No
â â â â â
â â â ⌠âŒ
â â â âââââââââââââ è¿å []
â â â â_handle_ â
â â â âsmalltalk() â
â â â âââââââ¬ââââââ
â â â â
ââââââââââŽâââââââââââââââŒâââââââââŽâââââââââ
â
âŒ
âââââââââââââââââââ
â è¿åæ¶æ¯æ®µå衚 â
âââââââââââââââââââð éåœïŒå ³é®ä»£ç äœçœ® â
| åèœ | æä»¶ | åœæ°/æ¹æ³ |
|---|---|---|
| æ¶æ¯è§£æ | core/message.py | normalize_message(), extract_text() |
| åçŒå¥çŠ» & äžäžæè§£æ | core/message.py | parse_text_command_context() |
| å³ç倿 | core/dispatcher.py | Dispatcher._decide_process() |
| åœä»€è·¯ç± | core/router.py | CommandRouter.resolve() |
| äŒè¯ç®¡ç | core/session.py | SessionManager |
| é鳿§å¶ | core/dispatcher.py | mute_group(), is_muted() |
| Handler éŸ | core/dispatcher.py | BotNameHandler, CommandHandler, SessionHandler, SmalltalkHandler |