Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+666новых вакансий за сутки·52 265вакансий открыто сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании5 686
РезюмеAIПодготовкаСтатьи
ТарифыТарифы
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 394 кандидата открыты к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python5 973
  • Облачные технологии4 523
  • QA вакансии1 689
  • Android1 143
  • Инженер данных788
  • Продакт-менеджер308

Разработка

  • iOS1 093
  • Backend вакансии1 020
  • Fullstack вакансии448
  • AI вакансии378
  • Frontend вакансии369
  • Mobile вакансии27

По стеку

  • Go3 345
  • Java2 037
  • Kotlin908
  • Node.js746
  • Rust492
  • .NET481
  • PHP278
  • C++213
  • C#199

DevOps и инфраструктура

  • Kubernetes2 562
  • Linux-инфраструктура2 030
  • DevOps вакансии1 855
  • Terraform / IaC1 548
  • CI/CD876
  • Мониторинг и Observability709
  • SRE229
  • Кибербезопасность40

Аналитика и данные

  • Аналитик данных479
  • Data Scientist443
  • Бизнес-аналитик342
  • Системный аналитик50

Другие направления

  • Проджект-менеджер107
  • UI/UX дизайн70
  • Ручное тестирование14

По регионам

  • Вакансии в США24 039
  • Вакансии в Европе9 373
  • Работа в России2 968
  • Вакансии в Канаде2 114

По формату

  • Удалённые вакансии41 595
  • Релокация в США24 039
  • Гибридная работа5 209
  • Офисная работа3 834

По уровню

  • Senior вакансии22 591
  • Middle вакансии12 174
  • Junior вакансии4 013

Сейчас нанимают

Все компании
  • Rakuten189 вакансий
  • ASML163 вакансии
  • Grab134 вакансии
  • Wise81 вакансия
  • Infobip28 вакансий
  • Darktrace17 вакансий
  • Spotify17 вакансий
  • Celonis14 вакансий
  • UiPath13 вакансий
  • Adyen9 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме LangGraphВсе вопросы
LangGraphMiddleКодинг

Как реализовать паттерн map-reduce с помощью LangGraph для параллельной обработки нескольких документов?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Map-reduce в LangGraph реализуется через Send-API: map-узел генерирует список Send-объектов с индивидуальными payload-ами для каждого документа, параллельные узлы обрабатывают их независимо, а reduce-узел с Annotated-reducer собирает результаты.

Полный пример: параллельный анализ документов

import operator
from typing import Annotated
from typing_extensions import TypedDict
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.types import Send

llm = ChatOpenAI(model="gpt-4o-mini")

# --- Схемы состояний ---

class OverallState(TypedDict):
    documents: list[str]          # входные документы
    summaries: Annotated[list[str], operator.add]  # reducer: накапливает результаты
    final_report: str

class DocumentState(TypedDict):
    """State для каждого параллельного map-узла."""
    document: str
    summaries: Annotated[list[str], operator.add]

# --- Узлы ---

def map_documents(state: OverallState) -> list[Send]:
    """Map: создаёт отдельный Send для каждого документа."""
    return [
        Send("summarize_doc", {"document": doc, "summaries": []})
        for doc in state["documents"]
    ]

def summarize_doc(state: DocumentState) -> dict:
    """Обрабатывает один документ — выполняется параллельно для каждого."""
    response = llm.invoke([
        HumanMessage(f"Кратко суммируй этот текст в 1-2 предложениях:\n\n{state['document']}")
    ])
    return {"summaries": [response.content]}

def reduce_summaries(state: OverallState) -> dict:
    """Reduce: объединяет все summaries в финальный отчёт."""
    combined = "\n".join(f"{i+1}. {s}" for i, s in enumerate(state["summaries"]))
    response = llm.invoke([
        HumanMessage(f"На основе этих краткий изложений напиши итоговый вывод:\n\n{combined}")
    ])
    return {"final_report": response.content}

# --- Сборка графа ---

builder = StateGraph(OverallState)
builder.add_node("summarize_doc", summarize_doc)
builder.add_node("reduce_summaries", reduce_summaries)

# START -> map_documents (функция-маппер возвращает список Send)
builder.add_conditional_edges(START, map_documents, ["summarize_doc"])
# После всех параллельных summarize_doc -> reduce
builder.add_edge("summarize_doc", "reduce_summaries")
builder.add_edge("reduce_summaries", END)

graph = builder.compile()

# --- Запуск ---

docs = [
    "Python — интерпретируемый язык программирования с динамической типизацией.",
    "FastAPI использует аннотации типов Python для автоматической генерации OpenAPI.",
    "PostgreSQL поддерживает расширения, включая pgvector для векторного поиска.",
]

result = graph.invoke({"documents": docs, "summaries": [], "final_report": ""})
print(result["final_report"])

Паттерн Map-Reduce в LangGraph

LangGraph реализует map-reduce через Send API: вместо статических рёбер узел-маппер возвращает список объектов Send(node_name, state), каждый из которых запускает отдельный экземпляр целевого узла параллельно. Reducer в TypedDict собирает результаты.

Как работает параллелизм

Когда add_conditional_edges получает список Send объектов, LangGraph запускает все целевые узлы конкурентно (через asyncio или ThreadPoolExecutor в sync-режиме). Reducer Annotated[list[str], operator.add] гарантирует, что результаты всех параллельных веток объединяются в один список без гонок.

Вариант с async для высокой нагрузки

import asyncio

async def summarize_doc_async(state: DocumentState) -> dict:
    response = await llm.ainvoke([
        HumanMessage(f"Суммируй: {state['document']}")
    ])
    return {"summaries": [response.content]}

# Использовать ainvoke для параллельного выполнения
result = await graph.ainvoke({"documents": docs, "summaries": [], "final_report": ""})

Подводные камни

  • Без Annotated[list, operator.add] каждый параллельный узел перезапишет summaries вместо того чтобы добавить — получите только последний результат.
  • Порядок результатов в summaries недетерминирован при параллельном выполнении; если порядок важен, добавляйте индекс в payload и сортируйте в reduce-узле.
  • Send создаёт отдельный экземпляр State для каждой ветки — изменения в DocumentState не видны другим параллельным веткам (это хорошо, но неочевидно).
  • При большом числе документов (>100) все LLM-запросы стартуют одновременно — это может превысить rate limit OpenAI; добавьте семафор или батчинг.
  • Ошибка в одном map-узле приводит к отмене всего графа; оборачивайте summarize_doc в try/except и возвращайте fallback-значение.
  • recursion_limit считает суммарное число шагов, включая параллельные; для 50 документов установите лимит явно: graph.invoke(..., config={"recursion_limit": 200}).
  • Checkpoint-ы для Send-ветвлений хранят State каждой ветки отдельно — при большом числе документов это значительно увеличивает объём в checkpointer.
  • В sync-режиме параллелизм реализован через threads, что ограничено GIL для CPU-bound задач; для IO-bound (LLM API) это не проблема, но для CPU-heavy обработки используйте multiprocessing вне графа.

Частые вопросы на собеседовании

  • Как LangGraph представляет состояние с помощью TypedDict и как оно передаётся между узлами?
  • Что является основной абстракцией в LangGraph — что такое nodes, edges и state?
  • Что такое LangGraph и как он расширяет LangChain для построения stateful агентских воркфлоу?
  • В каких data/AI-задачах LangGraph даёт реальный выигрыш, а где лучше выбрать другой инструмент или более простой pipeline?

Типичные ошибки

  • Объяснять map reduce только синтаксисом без shape, dtype, состояния или режима выполнения.
  • Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
  • Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.

Что проверяет интервьюер

  • Может ли связать map reduce с реальным контрактом входов и выходов.
  • Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
  • Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.

Как вы знаете этот вопрос?

Проверить себя по теме LangGraph →

Источники

  • https://docs.langchain.com/oss/python/langgraph/workflows-agents

Связанные темы

LangGraphdata-ailanggraphllm-orchestrationtool-calling