From f069bf05c71e642f863bbe474eca39370b844a97 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 19 Aug 2026 14:02:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(agent):=20=E8=B0=83=E5=A4=A7=E6=91=98?= =?UTF-8?q?=E8=A6=81=E8=BE=93=E5=85=A5=E8=A3=81=E5=89=AA=E4=B8=8A=E9=99=90?= =?UTF-8?q?=EF=BC=8C=E5=87=8F=E5=B0=91=E6=97=A0=E6=B3=95=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LangChain 默认按 4000 token 裁剪待摘要消息,单条超长工具结果或 用户输入会被整体丢弃,直接触发'无法压缩'报错;在 MoviePilot 子类 中覆盖默认上限为 16000,并保持显式传参的兼容性。 --- app/agent/middleware/summarization.py | 40 +++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/agent/middleware/summarization.py b/app/agent/middleware/summarization.py index 7e17bf6a9..07d343295 100644 --- a/app/agent/middleware/summarization.py +++ b/app/agent/middleware/summarization.py @@ -4,15 +4,22 @@ from collections.abc import Awaitable, Callable from importlib import import_module from typing import Any -from langchain.agents.middleware import SummarizationMiddleware +from langchain.agents.middleware.summarization import ( + DEFAULT_SUMMARY_PROMPT, + ContextSize, + SummarizationMiddleware, + TokenCounter, + TriggerClause, +) from langchain.agents.middleware.types import ( AgentMiddleware, ExtendedModelResponse, ModelRequest, ModelResponse, ) +from langchain.chat_models import BaseChatModel from langchain_core.messages import AnyMessage, HumanMessage, RemoveMessage, ToolMessage -from langchain_core.messages.utils import get_buffer_string +from langchain_core.messages.utils import count_tokens_approximately, get_buffer_string from langgraph.graph.message import REMOVE_ALL_MESSAGES from langgraph.types import Command @@ -42,6 +49,35 @@ class ContextPreservingSummarizationMiddleware(SummarizationMiddleware): "会话历史中存在无法压缩的超长内容,原有上下文已保留," "请新建或清空会话后继续" ) + # LangChain 默认按 4000 token 裁剪待摘要消息,单条超长工具结果或用户输入 + # (超长无换行文本、非文本多模态块)会被整体丢弃,直接触发"无法压缩"报错。 + # 调大该上限可容纳更大单条消息,减少误报;16k 相对常见模型窗口仍然安全, + # 摘要模型与主模型同窗口,过大会抬高摘要成本并挤占主模型预算。 + _DEFAULT_TRIM_TOKENS_TO_SUMMARIZE = 16000 + + def __init__( + self, + model: str | BaseChatModel, + *, + trigger: ( + ContextSize | TriggerClause | list[ContextSize | TriggerClause] | None + ) = None, + keep: ContextSize = ("messages", 20), + token_counter: TokenCounter = count_tokens_approximately, + summary_prompt: str = DEFAULT_SUMMARY_PROMPT, + trim_tokens_to_summarize: int | None = _DEFAULT_TRIM_TOKENS_TO_SUMMARIZE, + **deprecated_kwargs: Any, + ) -> None: + """按 MoviePilot 的默认压缩策略构建摘要中间件。""" + super().__init__( + model=model, + trigger=trigger, + keep=keep, + token_counter=token_counter, + summary_prompt=summary_prompt, + trim_tokens_to_summarize=trim_tokens_to_summarize, + **deprecated_kwargs, + ) @classmethod def _require_valid_summary(cls, summary: str) -> str: