The post has been translated automatically. Original language: Russian
On September 24, Haystack 3.2.0, deepset's Python framework for RAG systems and LLM agents, was released. There are three notable things in the release: the token budget for one agent launch, compression of the long dialogue history through Sammari, and stricter verification when loading serialized pipelines. There is also a fix and several incompatible changes in release 71.
Token budget and full-time agent stop
The new experimental TokenBudgetHook hook limits the number of tokens an agent can spend in a single launch. When the budget is exhausted, the agent does not make the next call to the model, returns the already accumulated messages and sets exit_reason to "token_budget_exceeded".
The hook is based on the new stop_run status key. Any "hook" can write its reason to it, for example, state.set("stop_run", "search_limit_reached"), and the agent will terminate without another access to the model, and the reason will go to exit_reason. Previously, an exception was thrown for this.
""At the same time, the agent began to report incomplete generation more accurately: when the length is interrupted or the content filter is applied, exit_reason takes the values "length" and "content_filter". In addition, the agent no longer repeats the request if the model returned an empty response with finish_reason equal to "length".
Compressing History through Sammari
Experimental SummarizationCompactor is a new strategy for CompactionHook. The old lines and steps of the agent are replaced by a short retelling, which is written by a separate small and cheap model. Compression goes through four levels (historical_turns, historical_summaries, currenttask_steps, currenttask_summaries) until the story meets the target token budget. The most recent steps, the number of which is set by the min_keep_steps parameter, always remain unchanged.
Deserialization Security
Fixed two issues when loading pipelines from a serialized view:
- arbitrary callables registered as Jinja custom_filters are no longer executed when booting in safe mode.;
- when deserializing called objects on the way through a point, the real module of each object on this path is now checked.
Consequence for users: OutputAdapter and ConditionalRouter with custom_filters are now loaded only via Pipeline.load(..., unsafe=True). The HAYSTACK_UNSAFE_DESERIALIZATION environment variable has also appeared. It enables insecure loading for the entire process at once.
Other changes
- Pipeline.add_components() adds multiple components in a single call, and Pipeline.connect_many() creates multiple connections. Both methods return a pipeline, so the calls can be arranged in a chain.
- DocumentSplitter and DocumentPreprocessor have received the split_by="token" mode: the text is cut according to the number of tokens via tiktoken, the package is placed separately.
- Text, CSV, and Markdown converters read utf-8-sig encoded files by default, and JsonConverter no longer silently skips files with a byte order label.
What does this mean in practice?
Check the code before updating. The "+" operator for combining toolsets has been removed: sets are now passed in a list, for example tools=[toolset_a, toolset_b]. The Toolset.add() method accepts only one tool. The tool_result_offloaded metadata key now stores a list of links rather than a single line, so code that reads it as a string will break.
If the saved pipelines have their own Jinja filters, the download will drop after the update. Do not rush to globally enable HAYSTACK_UNSAFE_DESERIALIZATION: it is better to transmit unsafe=True point-by-point and only for pipelines from a trusted source, otherwise the security fix loses its meaning.
TokenBudgetHook is a convenient fuse against a looping agent, but it is still experimental. """exit_reason" to monitoring: "token_budget_exceeded", "length" and "content_filter" mean that the user has received an incomplete response, and such cases should be considered separately from regular completions.
The draft text was prepared with the participation of AI, the facts are checked against the original source — official release notes of the Haystack project on GitHub
24 сентября вышел Haystack 3.2.0 — Python-фреймворк компании deepset для RAG-систем и LLM-агентов. В релизе три заметные вещи: бюджет токенов на один запуск агента, сжатие длинной истории диалога через саммари и более строгая проверка при загрузке сериализованных пайплайнов. Также в выпуске 71 исправление и несколько несовместимых изменений.
Бюджет токенов и штатная остановка агента
Новый экспериментальный хук TokenBudgetHook ограничивает число токенов, которое агент может потратить за один запуск. Когда бюджет исчерпан, агент не делает следующий вызов модели, возвращает уже накопленные сообщения и выставляет exit_reason в значение «token_budget_exceeded».
Хук построен на новом ключе состояния stop_run. Любой хук может записать в него свою причину, например state.set("stop_run", "search_limit_reached"), и агент завершится без очередного обращения к модели, а причина попадёт в exit_reason. Раньше для этого бросали исключение.
Заодно агент стал точнее сообщать о незавершённой генерации: при обрыве по длине или по фильтру контента exit_reason принимает значения «length» и «content_filter». Кроме того, агент больше не повторяет запрос, если модель вернула пустой ответ с finish_reason, равным «length».
Сжатие истории через саммари
Экспериментальный SummarizationCompactor — новая стратегия для CompactionHook. Старые реплики и шаги агента заменяются кратким пересказом, который пишет отдельная небольшая и дешёвая модель. Сжатие идёт по четырём уровням (historical_turns, historical_summaries, current_task_steps, current_task_summaries), пока история не уложится в целевой бюджет токенов. Самые свежие шаги, число которых задаёт параметр min_keep_steps, всегда остаются без изменений.
Безопасность десериализации
Исправлены две проблемы при загрузке пайплайнов из сериализованного вида:
- произвольные вызываемые объекты, зарегистрированные как Jinja-фильтры custom_filters, больше не выполняются при загрузке в безопасном режиме;
- при десериализации вызываемых объектов по пути через точку теперь проверяется реальный модуль каждого объекта на этом пути.
Следствие для пользователей: OutputAdapter и ConditionalRouter с custom_filters теперь загружаются только через Pipeline.load(..., unsafe=True). Появилась и переменная окружения HAYSTACK_UNSAFE_DESERIALIZATION — она включает небезопасную загрузку сразу для всего процесса.
Другие изменения
- Pipeline.add_components() добавляет несколько компонентов за один вызов, а Pipeline.connect_many() создаёт несколько связей. Оба метода возвращают пайплайн, поэтому вызовы можно выстраивать цепочкой.
- DocumentSplitter и DocumentPreprocessor получили режим split_by="token": текст режется по числу токенов через tiktoken, пакет ставится отдельно.
- Конвертеры текста, CSV и Markdown по умолчанию читают файлы в кодировке utf-8-sig, а JSONConverter больше не пропускает молча файлы с меткой порядка байтов.
Что это значит на практике
Перед обновлением проверьте код. Оператор «+» для объединения наборов инструментов удалён: наборы теперь передаются списком, например tools=[toolset_a, toolset_b]. Метод Toolset.add() принимает только один инструмент. Ключ метаданных tool_result_offloaded теперь хранит список ссылок, а не одну строку, поэтому код, который читает его как строку, сломается.
Если в сохранённых пайплайнах есть свои Jinja-фильтры, загрузка после обновления упадёт. Не спешите глобально включать HAYSTACK_UNSAFE_DESERIALIZATION: лучше передавать unsafe=True точечно и только для пайплайнов из доверенного источника, иначе исправление безопасности теряет смысл.
TokenBudgetHook — удобный предохранитель от зациклившегося агента, но пока экспериментальный. Выведите в мониторинг exit_reason: «token_budget_exceeded», «length» и «content_filter» означают, что пользователь получил неполный ответ, и такие случаи стоит считать отдельно от штатных завершений.
Черновик текста подготовлен с участием ИИ, факты сверены с первоисточником — официальные release notes проекта Haystack на GitHub