feat:进一步优化缓存
This commit is contained in:
@@ -108,30 +108,6 @@ class BaseMaisakaReplyGenerator:
|
||||
del message
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _strip_guided_reply_formatting(content: str) -> str:
|
||||
"""移除 guided_reply 可见文本中的引用包装,仅保留真正回复正文。"""
|
||||
|
||||
normalized_content = content.strip()
|
||||
if not normalized_content:
|
||||
return ""
|
||||
|
||||
reply_body_marker = "[发言内容]"
|
||||
if normalized_content.startswith("[引用]quote_id=") or normalized_content.startswith("[引用消息]"):
|
||||
marker_index = normalized_content.find(reply_body_marker)
|
||||
if marker_index >= 0:
|
||||
return normalized_content[marker_index + len(reply_body_marker) :].strip()
|
||||
|
||||
newline_index = normalized_content.find("\n")
|
||||
if newline_index < 0:
|
||||
return ""
|
||||
normalized_content = normalized_content[newline_index + 1 :].lstrip()
|
||||
|
||||
if normalized_content.startswith(reply_body_marker):
|
||||
normalized_content = normalized_content[len(reply_body_marker) :].lstrip()
|
||||
|
||||
return normalized_content.strip()
|
||||
|
||||
def _extract_guided_bot_reply(self, message: SessionBackedMessage) -> str:
|
||||
# 只能根据结构化来源字段判断是否为 bot 自身写回的历史消息,
|
||||
# 不能依赖昵称/群名片等可控文本,避免误判和提示注入。
|
||||
@@ -140,9 +116,7 @@ class BaseMaisakaReplyGenerator:
|
||||
|
||||
plain_text = message.processed_plain_text.strip()
|
||||
_, body = parse_speaker_content(plain_text)
|
||||
normalized_body = self._strip_guided_reply_formatting(body) or self._strip_guided_reply_formatting(
|
||||
plain_text
|
||||
)
|
||||
normalized_body = body.strip()
|
||||
return self._normalize_content(normalized_body) if normalized_body else ""
|
||||
|
||||
def _build_target_message_block(self, reply_message: Optional[SessionMessage]) -> str:
|
||||
|
||||
@@ -244,7 +244,10 @@ class BuiltinToolRuntimeContext:
|
||||
history_message = SessionBackedMessage.from_session_message(
|
||||
message,
|
||||
raw_message=build_prefixed_message_sequence(message.raw_message, planner_prefix),
|
||||
visible_text=build_session_message_visible_text(message),
|
||||
visible_text=build_session_message_visible_text(
|
||||
message,
|
||||
include_reply_components=source_kind != "guided_reply",
|
||||
),
|
||||
source_kind=source_kind,
|
||||
)
|
||||
self.runtime._chat_history.append(history_message)
|
||||
|
||||
@@ -650,7 +650,6 @@ class MaisakaChatLoopService:
|
||||
|
||||
selected_indices.reverse()
|
||||
selected_history = [filtered_history[index] for index in selected_indices]
|
||||
selected_history, _ = MaisakaChatLoopService._hide_early_assistant_messages(selected_history)
|
||||
selected_history, _ = drop_orphan_tool_results(selected_history)
|
||||
selected_history, _ = normalize_tool_result_order(selected_history)
|
||||
tool_message_count = sum(1 for message in selected_history if isinstance(message, ToolResultMessage))
|
||||
@@ -709,38 +708,3 @@ class MaisakaChatLoopService:
|
||||
return resolve_enable_visual_planner()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _hide_early_assistant_messages(
|
||||
selected_history: List[LLMContextMessage],
|
||||
) -> tuple[List[LLMContextMessage], int]:
|
||||
"""隐藏上下文中最早 50% 的 assistant 文本消息,但保留工具调用链路。"""
|
||||
|
||||
assistant_indices = [
|
||||
index
|
||||
for index, message in enumerate(selected_history)
|
||||
if isinstance(message, AssistantMessage)
|
||||
]
|
||||
hidden_assistant_count = len(assistant_indices) // 2
|
||||
if hidden_assistant_count <= 0:
|
||||
return selected_history, 0
|
||||
|
||||
removed_assistant_indices = set(assistant_indices[:hidden_assistant_count])
|
||||
|
||||
filtered_history: List[LLMContextMessage] = []
|
||||
for index, message in enumerate(selected_history):
|
||||
if index in removed_assistant_indices:
|
||||
if not message.tool_calls:
|
||||
continue
|
||||
filtered_history.append(
|
||||
AssistantMessage(
|
||||
content="",
|
||||
timestamp=message.timestamp,
|
||||
tool_calls=list(message.tool_calls),
|
||||
source_kind=message.source_kind,
|
||||
)
|
||||
)
|
||||
continue
|
||||
filtered_history.append(message)
|
||||
|
||||
return filtered_history, hidden_assistant_count
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
"""Maisaka 历史消息轮次结束后处理。"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from math import ceil
|
||||
|
||||
from .context_messages import AssistantMessage, LLMContextMessage
|
||||
from .history_utils import drop_leading_orphan_tool_results, drop_orphan_tool_results, normalize_tool_result_order
|
||||
|
||||
EARLY_TRIM_RATIO = 0.2
|
||||
EARLY_TRIM_RATIO = 0.3
|
||||
TRIM_THRESHOLD_RATIO = 1.2
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -26,27 +28,32 @@ def process_chat_history_after_cycle(
|
||||
"""在每轮结束后统一执行历史裁切与清理。"""
|
||||
|
||||
processed_history = list(chat_history)
|
||||
removed_assistant_thought_count = _remove_early_assistant_thoughts(processed_history)
|
||||
|
||||
processed_history, orphan_removed_count = drop_orphan_tool_results(processed_history)
|
||||
processed_history, moved_tool_result_count = normalize_tool_result_order(processed_history)
|
||||
remaining_context_count = sum(1 for message in processed_history if message.count_in_context)
|
||||
removed_overflow_count = 0
|
||||
|
||||
while remaining_context_count > max_context_size and processed_history:
|
||||
removed_message = processed_history.pop(0)
|
||||
removed_overflow_count += 1
|
||||
if removed_message.count_in_context:
|
||||
remaining_context_count -= 1
|
||||
|
||||
processed_history, leading_orphan_removed_count = drop_leading_orphan_tool_results(processed_history)
|
||||
removed_overflow_count += leading_orphan_removed_count
|
||||
remaining_context_count = sum(1 for message in processed_history if message.count_in_context)
|
||||
removed_count = (
|
||||
removed_assistant_thought_count
|
||||
+ orphan_removed_count
|
||||
+ removed_overflow_count
|
||||
processed_history, normalized_removed_count, moved_tool_result_count = _normalize_history_structure(
|
||||
processed_history
|
||||
)
|
||||
remaining_context_count = sum(1 for message in processed_history if message.count_in_context)
|
||||
|
||||
compact_removed_count = 0
|
||||
trim_threshold = ceil(max_context_size * TRIM_THRESHOLD_RATIO)
|
||||
if remaining_context_count > trim_threshold:
|
||||
removed_early_message_count = _remove_early_history_messages(processed_history)
|
||||
processed_history, removed_after_message_trim_count, moved_after_message_trim_count = (
|
||||
_normalize_history_structure(processed_history)
|
||||
)
|
||||
removed_assistant_thought_count = _remove_early_assistant_thoughts(processed_history)
|
||||
processed_history, removed_after_thought_trim_count, moved_after_thought_trim_count = (
|
||||
_normalize_history_structure(processed_history)
|
||||
)
|
||||
compact_removed_count = (
|
||||
removed_early_message_count
|
||||
+ removed_after_message_trim_count
|
||||
+ removed_assistant_thought_count
|
||||
+ removed_after_thought_trim_count
|
||||
)
|
||||
moved_tool_result_count += moved_after_message_trim_count + moved_after_thought_trim_count
|
||||
|
||||
remaining_context_count = sum(1 for message in processed_history if message.count_in_context)
|
||||
removed_count = normalized_removed_count + compact_removed_count
|
||||
changed_count = removed_count + moved_tool_result_count
|
||||
return HistoryPostProcessResult(
|
||||
history=processed_history,
|
||||
@@ -56,8 +63,34 @@ def process_chat_history_after_cycle(
|
||||
)
|
||||
|
||||
|
||||
def _normalize_history_structure(
|
||||
chat_history: list[LLMContextMessage],
|
||||
) -> tuple[list[LLMContextMessage], int, int]:
|
||||
"""规范化历史消息结构,保证工具调用链符合 LLM 消息协议。"""
|
||||
|
||||
processed_history, orphan_removed_count = drop_orphan_tool_results(chat_history)
|
||||
processed_history, moved_tool_result_count = normalize_tool_result_order(processed_history)
|
||||
processed_history, leading_orphan_removed_count = drop_leading_orphan_tool_results(processed_history)
|
||||
return (
|
||||
processed_history,
|
||||
orphan_removed_count + leading_orphan_removed_count,
|
||||
moved_tool_result_count,
|
||||
)
|
||||
|
||||
|
||||
def _remove_early_history_messages(chat_history: list[LLMContextMessage]) -> int:
|
||||
"""移除最早 30% 的全部历史消息。"""
|
||||
|
||||
remove_count = int(len(chat_history) * EARLY_TRIM_RATIO)
|
||||
if remove_count <= 0:
|
||||
return 0
|
||||
|
||||
del chat_history[:remove_count]
|
||||
return remove_count
|
||||
|
||||
|
||||
def _remove_early_assistant_thoughts(chat_history: list[LLMContextMessage]) -> int:
|
||||
"""移除最早 20% 的非工具 assistant 思考内容。"""
|
||||
"""移除最早 30% 的非工具 assistant 思考内容。"""
|
||||
|
||||
candidate_indexes = [
|
||||
index
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from src.common.data_models.message_component_data_model import MessageSequence, TextComponent
|
||||
from src.common.data_models.message_component_data_model import MessageSequence, ReplyComponent, TextComponent
|
||||
|
||||
from .context_messages import AssistantMessage, LLMContextMessage, ToolResultMessage
|
||||
from .message_adapter import build_visible_text_from_sequence, clone_message_sequence, format_speaker_content
|
||||
@@ -28,6 +28,8 @@ def build_prefixed_message_sequence(
|
||||
def build_session_message_visible_text(
|
||||
message: "SessionMessage",
|
||||
source_sequence: MessageSequence | None = None,
|
||||
*,
|
||||
include_reply_components: bool = True,
|
||||
) -> str:
|
||||
"""将真实会话消息转换为 Maisaka 可见文本。"""
|
||||
|
||||
@@ -46,6 +48,8 @@ def build_session_message_visible_text(
|
||||
)
|
||||
)
|
||||
for component in clone_message_sequence(normalized_sequence).components:
|
||||
if not include_reply_components and isinstance(component, ReplyComponent):
|
||||
continue
|
||||
visible_sequence.components.append(component)
|
||||
return build_visible_text_from_sequence(visible_sequence).strip()
|
||||
|
||||
|
||||
@@ -233,7 +233,10 @@ class MaisakaHeartFlowChatting:
|
||||
history_message = SessionBackedMessage.from_session_message(
|
||||
message,
|
||||
raw_message=build_prefixed_message_sequence(message.raw_message, planner_prefix),
|
||||
visible_text=build_session_message_visible_text(message),
|
||||
visible_text=build_session_message_visible_text(
|
||||
message,
|
||||
include_reply_components=source_kind != "guided_reply",
|
||||
),
|
||||
source_kind=source_kind,
|
||||
)
|
||||
self._chat_history.append(history_message)
|
||||
|
||||
Reference in New Issue
Block a user