Электронная почта → n8n → LangGraph → FastAPI: преобразование бюджетных запросов в оптимизированные портфели капитальных затрат, которые максимизируют рентабельность инвестиций для лиц, принимающих решения.
Делиться
Что, если простое электронное письмобыл ли это пользовательский интерфейс для комплексного планирования бюджета, а ИИ-агент занимался оптимизацией за кулисами?
Если бы я мог просто отправить «Выполнить бюджет 2026 года с XXX лимитами и Y% на устойчивое развитие» и получить ответ, это изменило бы наш обзор бюджета.
Именно так вице-президент по логистике сформулировал проблему, когда мы обсуждали автоматизацию выбора портфеля для ежегодного цикла утверждения капитальных затрат.
Поскольку компании инвестируют в дорогостоящее логистическое оборудование, директора получают заявки на капитальные затраты от операционных групп по краткосрочным и долгосрочным проектам.
Это сложная задача, поскольку вам необходимо найти баланс между окупаемостью инвестиций и долгосрочной стратегией.
Как мы, специалисты по обработке данных, можем поддержать этот процесс принятия решений?
Используя линейное программирование, мы можем помочь решить, какие проекты следует финансировать, чтобы максимизировать рентабельность инвестиций, соблюдая при этом многолетние бюджетные ограничения.
В этой статье мы создадим ИИ-агента для планирования бюджета , который преобразует запросы по электронной почте в оптимизированный портфель капитальных затрат.
Этот рабочий процесс ИИ построен с использованием n8n для оркестровки и LangGraph для создания рассуждающего агента, подключенного к микросервису FastAPI, который выполняет модель линейного программирования.
Мы рассмотрим архитектуру и изучим результаты, используя реальный запрос на оптимизацию бюджета с ограничением в 20%-ное выделение средств на проекты устойчивого развития.
Мы оказываем поддержку директору Азиатско-Тихоокеанского региона крупного стороннего поставщика логистических услуг (3PL), базирующегося в Сингапуре.
Их работа заключается в управлении складскими и транспортными операциями для других компаний в четырех странах Азиатско-Тихоокеанского региона.
Речь идет об операциях по поддержке 48 клиентов, сгруппированных в более чем восьми рыночных вертикалях (предметы роскоши, косметика и т. д.).
Например, они управляют складом площадью 10 000 кв. м для крупного ритейлера быстрой моды в Пекине, осуществляя поставки в 50 магазинов по всему Северному Китаю.
Заведующий складом: Нам нужно 150 тыс. евро на новый конвейер, который увеличит производительность приемки на 20%.
Наш директор получает список проектов, требующих капитальных затрат (CAPEX), от своих 17 менеджеров складов по всему Азиатско-Тихоокеанскому региону.
Для каждого проекта заявка CAPEX включает краткое описание (например, аренда 500 кв. м), трехлетний профиль затрат (год 1: 115 тыс. евро; год 2: 120 тыс. евро; год 3: 150 тыс. евро) и ожидаемую окупаемость инвестиций (например, +50 тыс. евро).
Эти проекты также могут принести дополнительные преимущества:
Развитие бизнеса: получение новых источников дохода (например, возможностей для нового клиента или линейки продуктов)
Устойчивость (сокращение выбросов CO₂): снижение выбросов за счет энергоэффективного оборудования или изменения планировки
Цифровая трансформация: улучшение прозрачности данных, автоматизация повторяющихся задач и принятие решений на основе ИИ
Операционная эффективность: повышение производительности, сокращение дефектов и переделок, сокращение времени переналадки и стабилизация процессов.
Охрана труда, техника безопасности и охрана окружающей среды: снижение риска инцидентов и страховых рисков за счет использования более безопасного оборудования
КСО (корпоративная социальная ответственность): укрепление инициатив сообщества и рабочей силы (например, обучение, доступность)
Например, проект автоматизации склада может сократить использование упаковки (устойчивое развитие), снизить нагрузку на операторов (КСО) и ускорить цифровую трансформацию.
Некоторые из дополнительных преимуществ связаны с рекомендациями высшего руководства, которым должен следовать наш директор.
Директор Азиатско-Тихоокеанского региона: «Как мне следует распределить свой бюджет в размере XX млн евро, чтобы максимизировать рентабельность инвестиций, соблюдая при этом руководящие указания моего высшего руководства?»
Поскольку директор получает более 50 проектов за каждую сессию, мы предложили построить модуль линейного программирования для определения оптимального выбора с учетом внешних ограничений.
В качестве входных данных мы получаем доступный бюджет и цели управления, а также электронную таблицу заявок на капитальные затраты.
Это будет частью входных данных нашего решения.
FastAPI Microservice: оптимизатор смешанного целочисленного типа (0–1) для планирования бюджета капитальных затрат
Для решения этой проблемы мы использовали фреймворк моделирования для задач линейного программирования (LP) и целочисленного программирования (IP), предоставляемый библиотекой PuLP языка Python.
Решение упаковано в микросервис FastAPI, развернутый в облаке.
Переменные решения
Для каждого проекта i мы определяем двоичное значение, которое указывает, выделяем ли мы бюджет или нет:
Целевая функция
Цель — максимизировать общую отдачу от инвестиций портфеля выбранных нами проектов:
Ограничения
Поскольку мы не можем потратить больше, чем выделили на год, нам необходимо учесть бюджетные ограничения на следующие три года.
Директор Азиатско-Тихоокеанского региона: Наш генеральный директор хочет, чтобы мы инвестировали 20% нашего бюджета в проекты, поддерживающие нашу дорожную карту устойчивого развития.
Более того, у нас также могут быть ограничения по минимальному бюджету для конкретных целей управления.
В приведенном выше примере мы гарантируем, что общий объем инвестиций в проекты устойчивого развития будет равен или больше S_min.
Теперь, когда мы определили нашу модель, мы можем упаковать ее как микросервис FastAPI, используя код, представленный в этой статье.
Этот общий рабочий процесс будет принимать конкретную схему, определенную с помощью Pydantic, для проверки и значений по умолчанию.
из pydantic import BaseModel из typing import Необязательный класс LaunchParamsBudget(BaseModel): budget_year1: int = 1250000 budget_year2: int = 1500000 budget_year3: int = 1750000 set_min_budget: bool = False min_budget_objective: Необязательный[str] = 'Устойчивость' min_budget_perc: float = 20 класс EmailRequest(BaseModel): email_text: str
LaunchParamsBudget фиксирует входные данные оптимизации:
Три годовых лимита бюджета (бюджет_год1/2/3 в евро)
Необязательное правило минимального распределения, переключаемое параметром set_min_budget с его целевой целью управления min_budget_objective и требуемой долей min_budget_perc в %.
Нам необходимо убедиться, что агент соблюдает эту схему; в противном случае он не сможет выполнять запросы к API.
Агент получит подробную информацию о выделенном бюджете, включая годовое распределение, а также информацию о выбранных проектах.
С помощью этих результатов и соответствующей системной подсказки наш агент может предоставить краткую сводку распределения бюджета вице-президенту по логистике.
Создание агентного рабочего процесса с помощью LangGraph и n8
Описание сквозного рабочего процесса
Предположим, что наш директор Азиатско-Тихоокеанского региона получил электронную таблицу со всеми заявками на капитальные затраты.
Идея состоит в том, чтобы получать гипотезы относительно суммы бюджета и ограничений на простом английском языке по электронной почте вместе с приложенной электронной таблицей.
На основе этого письма рабочий процесс должен автоматически выбирать проекты для оптимального распределения бюджета.
Но директор также ожидает краткого объяснения сделанного выбора для формирования этого оптимального «инвестиционного портфеля».
Мы можем построить автоматизированный рабочий процесс, используя LangGraph и n8n для оркестровки выполнения этих задач.
Это будет рабочий процесс, состоящий из 4 этапов:
Шаг 1 : Используя узел n8n Gmail, мы отправляем тело письма и электронную таблицу, прикрепленную к бэкэнду FastAPI.
Шаг 2 : Анализатор AI Agent соберет параметры из электронной почты и вызовет другой API для планирования бюджета.
Шаг 3 : Выходные данные будут отправлены в AI Agent Summarizer, который будет использовать их для создания сводки.
Шаг 4 : Пользователь получает ответ по электронной почте с резюме через узел Gmail в n8n.
Основной рабочий процесс агента LangGraph будет реализован в микросервисе FastAPI, который будет упакован в рабочий процесс n8n для оркестровки.
Первые два узла сверху извлекут содержимое электронной таблицы и загрузят его в API.
Затем мы извлекаем содержимое электронной почты в узле Extract Email Body и отправляем его в конечную точку агента с помощью узла Query AI Agent.
Выходные данные API включают в себя:
Подробное объяснение оптимального распределения бюджета, которое отправляется по электронной почте с помощью узла «Ответить»
JSON с распределением по проектам, используемым узлом Update Allocation для добавления ✅ и ❌ в электронную таблицу.
В конечном итоге наш директор получает комплексный анализ оптимального портфеля, включающий три отдельных раздела.
Сводка бюджета содержит подробную информацию о выделенном бюджете и окупаемости инвестиций.
В составе портфеля указано количество проектов, выделенных для достижения каждой цели управления.
Наконец, агент дает рекомендацию , основанную на его понимании цели.
Давайте посмотрим , как мы создали ядро LangGraph Budget Agent, которое анализирует электронное письмо и возвращает полный анализ.
ИИ-агент планирования бюджета с LangGraph
Код, представленный в этом разделе, был значительно упрощен для краткости.
Прежде чем создавать график, давайте построим различные блоки:
EmailParser используется для анализа тела электронного письма, полученного от HTTP-узла n8n, для извлечения параметров API бюджета.
BudgetPlanInterpreter вызовет API, извлечет результаты и сгенерирует сводку.
К вашему сведению, я использовал этот подход с отдельными блоками, поскольку мы повторно используем их в других рабочих процессах, объединяющих несколько агентов.
Блок 1: Анализатор ИИ-агентов
Давайте создадим блок для этого агента, который мы назовем AI Agent Parser :
импорт ведения журнала из langchain.chat_models импорт init_chat_model из app.utils.config_loader импорт load_config из app.models.budagent_models импорт LaunchParamsBudget logger = logging.getLogger(__name__) config = load_config() класс EmailParser: def __init__(self, model_name: str | None = None): model_name = config.get(«budget_agent», {}).get( «model_name», «anthropic:claude-3-7-sonnet-latest» ) self.llm = init_chat_model(model_name) self.params: dict | None = None self.raw_email: str | None = None def parse(self, content: str | None = None) -> dict: «»» Анализ содержимого электронной почты для извлечения параметров для API «»» content = content.strip() system_prompt = config.get(«budget_agent», {}).get( «system_prompt_parser», {} ) structured_llm = self.llm.with_structured_output(LaunchParamsBudget) result = structured_llm.invoke( [ {«role»: «system», «content»: system_prompt}, {«role»: «user», «content»: content}, ] ) payload = result.model_dump() self.params = payload logger.info(f»[BudgetAgent] Проанализированные параметры: {self.params}») return self.params
Мы включаем параметры, которые будут использоваться для переменных состояния графика.
Этот блок EmailParser преобразует текстовое тело письма в типизированные, соответствующие схеме параметры для нашего API бюджетного планирования с использованием LLM.
При инициализации мы загружаем модель чата из конфигурации и строим модель чата LangChain.
Функция parse() принимает необработанное содержимое электронной почты, отправленное HTTP-узлом n8n, и системное приглашение для вызова модели со структурированными выходными данными, определенными с помощью схемы LaunchParamsBudget Pydantic.
Системное приглашение EmailParser, хранящееся в файле конфигурации YAML (минимальная версия для краткости):
budget_agent: system_prompt_parser: | Вы — аналитик бюджетного планирования в LogiGreen. Ваша задача — извлекать структурированные входные параметры из электронных писем с запросами на оптимизацию бюджета. Возвращаемые поля (точно соответствуют схеме): — budget_year1: целое число (годовой лимит на 1-й год) — budget_year2: целое число (годовой лимит на 2-й год) — budget_year3: целое число (годовой лимит на 3-й год) — set_min_budget: логическое значение (true/false) — min_budget_objective: строка (например, «Устойчивость») — min_budget_perc: число (процент от 0 до 100) Выводит ТОЛЬКО эти поля; без дополнительных ключей.
Он включает в себя список полей для анализа, а также краткие пояснения и строгие правила форматирования.
Возвращает сообщение об ошибке в формате HTML, которое будет отправлено узлу Gmail в n8n для уведомления пользователя.
В этом случае для службы поддержки это более практично, поскольку пользователю достаточно просто переслать электронное письмо.
Примечание: в рабочей версии мы добавили run_id, чтобы помочь отслеживать проблемы в журналах.
async def parse_email(state: AgentState) -> AgentState: try: parser = EmailParser(model_name=config[«budget_agent»][«model_name»]) params = parser.parse(state[«email_text»]) if not params or («error» in params and params[«error»]): return {«error»: f»Ошибка анализа: {params.get('error', 'unknown')}»} return {«params»: params} except Exception as e: logger.exception(«[BudgetGraph] parse_email failed») return {«error»: f»Исключение анализа: {e}»}
Функция 2: parse_email(state)
Использует EmailParser для преобразования текста полученного электронного письма в параметры для планирования бюджета в формате JSON.
В случае успеха: возвращает {«params»: …}, используемый для вызова микросервиса FastAPI.
async def run_budget(state: AgentState) -> AgentState: if «error» in state: return {} try: interpreter = BudgetPlanInterpreter( model_name=config[«budget_agent»][«model_name»], session_id=state.get(«session_id», config[«budget_agent»][«session_id»])) results = await interpreter.run_plan(state[«params»]) if «error» in results: return {«error»: f»Выполнение бюджета не удалось: {results['error']}»} return {«budget_results»: results, «interpreter»: interpreter} except Exception as e: logger.exception(«[BudgetGraph] run_budget failed») return {«error»: f»Исключение бюджета: {e}»}
Функция 3: run_budget(state)
Использует BudgetPlanInterpreter для вызова функции run_plan, которая выполнит оптимизацию бюджета через микросервис FastAPI.
В случае успеха: возвращает вывод оптимизатора в формате JSON как budget_results.
Этот вывод может быть использован для формирования сводки распределения бюджета.
async def summary(state: AgentState) -> AgentState: if «error» in state: return {} try: interpreter = state.get(«interpreter») or BudgetPlanInterpreter( model_name=config[«budget_agent»][«model_name»], session_id=state.get(«session_id», config[«budget_agent»][«session_id»]), ) html = await interpreter.interpret(state[«params»], state[«budget_results»]) return {«html_summary»: html} except Exception as e: logger.exception(«[BudgetGraph] summary failed») return {«error»: f»Исключение суммирования: {e}»}
Функция 4: суммировать(состояние)
Повторно использует интерпретатор из состояния (или создает его), затем вызывает interpret()
В случае успеха: возвращает краткую и профессиональную сводку распределения бюджета в формате HTML, готовую к отправке по электронной почте {«html_summary»: …}
Затем этот вывод html_summary возвращается API узлу Gmail на n8n для ответа отправителю.
Теперь, когда у нас есть все функции, мы можем создать узлы и «связать» граф с помощью функции build_budagent_graph(), определенной ниже:
Эти четыре узла соединены с помощью маршрутизаторов:
route_after_parse направит поток на основе вывода анализа электронной почты: если ошибка в состоянии → перейти к «ошибке»; иначе → «выполнить».
route_after_run направит поток на основе выходных данных вызова микросервиса FastAPI: если в состоянии ошибка → перейти к «ошибке»; иначе → «суммировать».
Мы почти закончили!
Нам просто нужно упаковать это в конечную точку FastAPI:
@router.post(«/graph_parse_and_run») async def graph_parse_and_run(request: EmailRequest): «»» Анализирует тело письма, запускает планирование бюджета и возвращает сводку в формате HTML — организовано с помощью LangGraph StateGraph. «»» try: initial_state = { «email_text»: request.email_text, «session_id»: config.get(«budget_agent», {}).get(«session_id», «test_agent»), } final_state = await _graph.ainvoke(initial_state) return { «params»: final_state.get(«params»), «budget_results»: final_state.get(«budget_results»), «html_summary»: final_state.get(«html_summary»), «error»: final_state.get(«error»), } except Exception as e: logger.exception(«[BudAgent] Запуск графика не удался») raise HTTPException(status_code=500, detail=f»Запуск графика не удался: {e}»)
Он будет запрошен узлом API Query Agent нашего рабочего процесса n8n для возврата входных параметров в params, результатов оптимизатора бюджета в budget_results и сводки, сгенерированной интерпретатором агента в html_summary.
Полнофункциональный рабочий процесс на основе ИИ для планирования бюджета
Теперь мы можем активировать рабочий процесс на n8n и протестировать инструмент в различных сценариях.
Что делать, если у нас нет минимального бюджета для достижения каких-либо целей управления?
Я попытаюсь адаптировать письмо так, чтобы set_min_budget было равно False.
Письмо было успешно проанализировано, теперь set_min_budget имеет значение False.
Этот рабочий процесс был представлен команде APAC, которая начала «играться с ним».
Мы узнали, что они используют его для подготовки слайдов с различными сценариями распределения портфеля для заседаний совета директоров.
Это остается «стратегическим инструментом», который используется лишь пару раз в год.
Однако мы планируем повторно использовать ту же архитектуру для более «тактических» инструментов, которые отделы цепочек поставок могут использовать для ABC-анализа, управления запасами или оптимизации цепочек поставок, а также для кадровых ресурсов — для планирования рабочей силы или групп по контролю за бизнесом.
Можем ли мы выйти за рамки этого простого рабочего процесса?
Я все еще не удовлетворен вкладом части Agentic в рабочий процесс.
Действительно, приятно иметь инструмент, который можно активировать с помощью электронного письма и который выдает краткое резюме.
Однако я хотел бы изучить идею о том, чтобы несколько агентов предлагали разные сценарии, которые конкурировали бы друг с другом.
Как повлияет на рентабельность инвестиций, если мы увеличим минимальный бюджет устойчивого развития на 15%?
Например, мы можем попросить агентов запустить несколько сценариев и провести сравнительное исследование.
Мы все еще экспериментируем с различными типами оркестровки, чтобы определить наиболее эффективный подход.
Это будет темой следующих статей.
Другие примеры агентских рабочих процессов?
Это не первый раз, когда я пытаюсь связать инструмент оптимизации (упакованный в микросервис FastAPI) с агентским рабочим процессом.
Моей первой попыткой было создание агента оптимизации планирования производства .
Как и здесь, я упаковал алгоритм оптимизации в микросервис FastAPI, который мне нужно было подключить к рабочему процессу электронной почты.
В отличие от этого, агентская часть рабочего процесса была обработана в n8n с двумя узлами Agent.
Результаты оказались весьма удовлетворительными, как вы можете увидеть в коротком видеоролике, ссылка на который приведена ниже.
Пользовательский опыт был очень удобным.
Однако техническое обслуживание оказалось для команды сложной задачей.
Вот почему мы хотели изучить использование фреймворков Python и TypeScript для агентского рабочего процесса, как здесь.
Что дальше? Агентный подход к бизнес-планированию
В нашем стартапе LogiGreen мы пытаемся (посредством экспериментов, подобных этому) выйти за рамки оптимизации цепочки поставок и охватить процесс принятия бизнес-решений.
В моем плане действий есть инструмент, который я разработал, чтобы помочь малым и средним компаниям оптимизировать свой денежный поток.
В другой статье, опубликованной в журнале Towards Data Science, я рассказал, как использовал Python для моделирования финансовых потоков компании, продающей кофейням стаканчики из возобновляемой бумаги.
«Нам приходится отказываться от заказов, поскольку у нас недостаточно денег, чтобы заплатить поставщикам за пополнение запасов».
Мой близкий друг, владелец небольшого бизнеса, жаловался на проблемы с денежным потоком, ограничивающие развитие его компании.
Я начал с решения проблемы управления запасами с помощью оптимизированного встроенного решения на Python.
Затем я дополнил модель, приняв во внимание стратегию каналов сбыта, условия оплаты и многие другие стратегические бизнес-параметры, чтобы помочь ему найти оптимальный бизнес-план для максимизации прибыльности.
Это решение, вероятно, является следующим кандидатом в нашем эксперименте по использованию агентских рабочих процессов для поддержки принятия деловых и оперативных решений.
Для получения более подробной информации вы можете ознакомиться с этой короткой презентацией инструмента.
В настоящее время он упакован в микросервис FastAPI, подключенный к фронтенду React (и доступен для публичной демонстрации).
Я хотел бы реализовать рабочий процесс на основе искусственного интеллекта, который бы
Возьмите несколько сценариев (например, представленных в видео)
Вызов API для каждого сценария
Соберите и обработайте результаты
Провести сравнительный анализ, чтобы рекомендовать наилучшее решение
По сути, я хотел бы поручить одному (или нескольким агентам) выполнение всего исследования, представленного в статье и видео.
Для этого мы изучаем различные подходы к оркестровке агентов.
Мы поделимся нашими результатами в следующей статье. Следите за новостями!
Обо мне
Давайте общаться в Linkedin и Twitter. Я инженер по цепочке поставок, использующий аналитику данных для оптимизации логистических операций и снижения затрат.
Если вам нужна консультация или совет по аналитике и устойчивой трансформации цепочки поставок, свяжитесь со мной через Logigreen Consulting.
Если вас интересуют аналитика данных и цепочка поставок, посетите мой сайт.
Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…
Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…
Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений. Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…
Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран. Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…