-
Notifications
You must be signed in to change notification settings - Fork 19.6k
feat(langchain): (SummarizationMiddleware) support use of model context windows when triggering summarization #33825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 10 commits
b26b3e7
6d2990a
a966b9a
8a6de4b
ee61499
2525c2f
c19a0db
6c49403
c09a563
b23ae7b
6ba36ce
933b8ea
3d8d1f7
8ee5eb9
e208af1
079544f
9c977b1
3f2bc1a
0306f57
119ffa3
6ddb982
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,8 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Summarization middleware.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import uuid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from collections.abc import Callable, Iterable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, cast | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from collections.abc import Callable, Iterable, Mapping | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, Final, cast | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from langchain_core.messages import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AIMessage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -59,6 +59,16 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _SEARCH_RANGE_FOR_TOOL_PAIRS = 5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class _UnsetType: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Sentinel indicating that max tokens should be inferred from the model profile.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def __repr__(self) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "UNSET" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UNSET: Final = _UnsetType() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class SummarizationMiddleware(AgentMiddleware): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Summarizes conversation history when token limits are approached. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -70,22 +80,35 @@ class SummarizationMiddleware(AgentMiddleware): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def __init__( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: str | BaseChatModel, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens_before_summary: int | None = None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens_before_summary: int | None | _UnsetType = UNSET, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages_to_keep: int = _DEFAULT_MESSAGES_TO_KEEP, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| token_counter: TokenCounter = count_tokens_approximately, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summary_prompt: str = DEFAULT_SUMMARY_PROMPT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summary_prefix: str = SUMMARY_PREFIX, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| buffer_tokens: int = 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target_retention_frac: float | None = None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trim_token_limit: int | None = _DEFAULT_TRIM_TOKEN_LIMIT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Initialize the summarization middleware. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: The language model to use for generating summaries. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens_before_summary: Token threshold to trigger summarization. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| If `None`, summarization is disabled. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| If `None`, summarization is disabled. If `UNSET`, limits are inferred | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from the model profile when available. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages_to_keep: Number of recent messages to preserve after summarization. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Used whenever token-based retention is unavailable or disabled. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| token_counter: Function to count tokens in messages. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summary_prompt: Prompt template for generating summaries. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summary_prefix: Prefix added to system message when including summary. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| buffer_tokens: Additional buffer to reserve when estimating token usage. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target_retention_frac: Optional fraction (0, 1) of `max_input_tokens` to retain | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in context. If the model profile is missing or incomplete, this falls | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| back to the `messages_to_keep` strategy. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trim_token_limit: Maximum tokens to keep when preparing messages for the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summarization call. Pass `None` to skip trimming entirely (risking | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| summary model overflows if the history is too long). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super().__init__() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -98,20 +121,25 @@ def __init__( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.token_counter = token_counter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.summary_prompt = summary_prompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.summary_prefix = summary_prefix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.buffer_tokens = buffer_tokens | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.trim_token_limit = trim_token_limit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _create_summary(self, messages_to_summarize: list[AnyMessage]) -> str: | |
| """Generate summary for the given messages.""" | |
| if not messages_to_summarize: | |
| return "No previous conversation history." | |
| trimmed_messages = self._trim_messages_for_summary(messages_to_summarize) | |
| if not trimmed_messages: | |
| return "Previous conversation was too long to summarize." | |
| try: | |
| response = self.model.invoke(self.summary_prompt.format(messages=trimmed_messages)) | |
| return cast("str", response.content).strip() | |
| except Exception as e: # noqa: BLE001 | |
| return f"Error generating summary: {e!s}" | |
| def _trim_messages_for_summary(self, messages: list[AnyMessage]) -> list[AnyMessage]: | |
| """Trim messages to fit within summary generation limits.""" | |
| try: | |
| return trim_messages( | |
| messages, | |
| max_tokens=_DEFAULT_TRIM_TOKEN_LIMIT, | |
| token_counter=self.token_counter, | |
| start_on="human", | |
| strategy="last", | |
| allow_partial=True, | |
| include_system=True, | |
| ) | |
| except Exception: # noqa: BLE001 | |
| return messages[-_DEFAULT_FALLBACK_MESSAGE_COUNT:] |
so this was a minimal change that is not breaking but lets us disable this. lmk if that makes sense or I misunderstood you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this parameter is unused