Принятие решений коллективом
Пока что у всех наших агентов, даже у команд, есть одна общая черта: они выстраивают единую цепочку рассуждений.
Но LLM-ы — это недетерминированные системы, если запустить один и тот же запрос дважды, можно получить немного разные ответы.
Это может стать проблемой в ситуациях с высокими ставками, когда вам нужен надежный и всесторонний ответ.
Архитектура ансамблевого принятия решений решает эту проблему напрямую. Она основана на принципе «мудрости толпы».
Вместо того чтобы полагаться на одного агента, мы запускаем параллельно несколько независимых агентов, часто с разными «характеристиками», а затем используем заключительного агента-агрегатора для синтеза их результатов в единый, более надежный вывод.
В крупномасштабной системе искусственного интеллекта это основной подход для любой критически важной задачи поддержки принятия решений. Вспомните инвестиционный комитет по ИИ или систему медицинской диагностики. Получение «второго мнения» (или третьего, или четвертого) от разных ИИ-персонажей значительно снижает вероятность того, что предвзятость или иллюзия одного агента приведут к неблагоприятному результату.
Давайте разберемся, как протекает этот процесс.

Ансамбль (создан)
Фарид Хан
)
Параллельное исследование (Fan-Out): Запрос пользователя одновременно отправляется нескольким агентам-специалистам. Этим агентам назначаются разные роли, чтобы стимулировать нестандартное мышление.
Независимая обработка: Каждый агент работает над проблемой изолированно, генерируя собственный полный анализ.
Агрегация (Fan-In): Собираются выходные данные от всех агентов.
Синтез (решение на основе совокупности мнений): Конечный агент-«агрегатор» получает все отдельные отчеты, взвешивает различные точки зрения и синтезирует исчерпывающий окончательный ответ.
Ключ к успешной работе ансамбля — когнитивное разнообразие. Мы создадим трёх агентов-аналитиков, каждый с совершенно разным характером: Bullish Growth Analyst(оптимист), Cautious Value Analyst(скептик) и Quantitative Analyst(сторонник строгих стандартов обработки данных).
class EnsembleState ( TypedDict ):
query: str
analyses: Dict [ str , str ] # Сохраняем выходные данные каждого параллельного агента
final_recommendation: Optional [ Any ]
# Мы снова воспользуемся нашей фабрикой специалистов, но с совершенно другими персонами
bullish_persona = "Аналитик, настроенный оптимистично: Вы чрезвычайно оптимистичны в отношении технологий и инноваций. Сосредоточьтесь на будущем потенциале роста и преуменьшите краткосрочные риски."
bullish_analyst_node = create_specialist_node(bullish_persona, "BullishAnalyst" )
value_persona = "Осторожный аналитик, ориентированный на стоимость: Вы скептически настроенный инвестор, сосредоточенный на фундаментальных показателях и риске. Тщательно изучайте финансовые показатели, конкуренцию и потенциальные сценарии снижения стоимости."
value_analyst_node = create_specialist_node(value_persona, "ValueAnalyst" )
quant_persona = "Количественный аналитик (Quant): Вы руководствуетесь исключительно данными. Игнорируйте описания и сосредоточьтесь только на конкретных цифрах, таких как финансовые показатели и технические индикаторы."
quant_analyst_node = create_specialist_node(quant_persona, "QuantAnalyst" )
Последний и самый важный элемент — это наш агрегатор cio_synthesizer_node. Его задача — обработать эти противоречивые отчеты и составить единую, сбалансированную инвестиционную концепцию.
class FinalRecommendation ( BaseModel ):
"""Окончательный, синтезированный инвестиционный тезис от директора по инвестициям."""
final_recommendation: str
confidence_score: float
synthesis_summary: str
identified_opportunities: List [ str ]
identified_risks: List [ str ]
def cio_synthesizer_node ( state: EnsembleState ) -> Dict [ str , Any ]:
"""Заключительный узел, который синтезирует все анализы в единую рекомендацию."""
console. print ( "--- 🏛️ Звонок главному инвестиционному директору для принятия окончательного решения ---" )
all_analyses = "\n\n---\n\n" .join( ["**Анализ от {name} :**\n {analysis} " for name, analysis in state[ 'analyses' ].items()])
cio_prompt = ChatPromptTemplate.from_messages([
" system" , "Вы — главный инвестиционный директор. Ваша задача — синтезировать эти разнообразные и часто противоречащие друг другу точки зрения в единый, окончательный и действенный инвестиционный тезис. Взвесьте потенциал роста против рисков, чтобы прийти к сбалансированному выводу." ),
( "human" , "Вот отчеты вашей команды по запросу: '{query}'\n\n{analyses}\n\nПредоставьте свой окончательный, синтезированный инвестиционный тезис." )
])
cio_llm = llm.with_structured_output(FinalRecommendation)
chain = cio_prompt | cio_llm
final_decision = chain.invoke({ "query" : state[ 'query' ], "analyses" : all_analyses})
return { "final_recommendation" : final_decision}
Теперь давайте подключим его. LangGraph для этого уникален тем, что имеет «разветвление» , где один узел разветвляется на три параллельных узла, а затем «вход», где эти три узла сходятся на конечном синтезаторе.
workflow = StateGraph(EnsembleState)
# Входной узел просто подготавливает состояние
workflow.add_node( "start_analysis" , lambda state: { "analyses" : {}})
# Добавляем параллельные узлы аналитика и финальный синтезатор
workflow.add_node( "bullish_analyst" , bullish_analyst_node)
workflow.add_node( "value_analyst" , value_analyst_node)
workflow.add_node( "quant_analyst" , quant_analyst_node)
workflow.add_node( "cio_synthesizer" , cio_synthesizer_node)
workflow.set_entry_point( "start_analysis" )
# FAN-OUT: Запускаем все три аналитика параллельно
workflow.add_edge( "start_analysis" , [ "bullish_analyst" , "value_analyst" , "quant_analyst" ])
# ВХОД: После завершения работы всех аналитиков вызовите синтезатор
workflow.add_edge([ "bullish_analyst" , "value_analyst" , "quant_analyst" ], "cio_synthesizer" )
workflow.add_edge( "cio_synthesizer" , END)
ensemble_agent = workflow.compile ( )

Ансамбль (создан)
Фарид Хан
)
Давайте зададим нашему инвестиционному комитету сложный, неоднозначный вопрос, по которому ценны разные точки зрения.
запрос = "Судя по последним новостям, финансовым показателям и перспективам на будущее, является ли NVIDIA (NVDA) хорошей долгосрочной инвестицией в середине 2024 года?"
console.print ( f"--- 📈 Запуск инвестиционного комитета для: {query} ---" ) result = ensemble_agent.invoke({ "query" : query}) # ... (код для вывода отдельных отчетов и окончательной рекомендации CIO) ...
Эффективность этой архитектуры становится очевидной сразу же, как только вы видите результаты. Три аналитика дают совершенно разные отчеты: «Бычий» дает восторженную рекомендацию «Покупать», аналитик, ориентированный на стоимость, — осторожную «Держать», а количественный аналитик предоставляет нейтральные данные.
В итоговом отчете CIO не просто усредняют эти данные. В нем проводится настоящий синтез, признающий оптимистичный сценарий, но смягчающий его с учетом опасений относительно стоимости активов.
**Окончательная рекомендация:** Покупка
**Оценка уверенности:** 7,5 / 10
**Краткий обзор:**
Комитет представляет убедительные, но спорные аргументы в пользу NVIDIA. Единодушное мнение разделяет текущее технологическое превосходство компании ... Однако аналитики по стоимостному и количественному анализу поднимают важные, совпадающие вопросы о чрезвычайно высокой оценке акций... Окончательная рекомендация — «Покупка», но с сильным акцентом на долгосрочную позицию и рекомендацией осторожного входа...
**Выявленные возможности:**
* Бесспорное лидерство на рынке ускорителей ИИ.
* ...
**Выявленные риски:**
* Чрезвычайно высокая оценка (коэффициенты P/E и P/S).
* ...
Это гораздо более надежный и заслуживающий доверия ответ, чем тот, который мог бы дать любой отдельный агент. Для его формализации нашему эксперту-магистру права необходимо оценить глубину анализа и сбалансированность.
class EnsembleEvaluation (BaseModel):
analytical_depth_score: int = Field (description= "Оценка от 1 до 10 по глубине анализа." )
nuance_and_balance_score: int = Field (description= "Оценка от 1 до 10 по тому, насколько хорошо окончательный ответ сбалансировал противоречивые точки зрения и представил взвешенный вывод." )
justification: str = Field (description= "Краткое обоснование оценок." )
По результатам оценки, выступление ансамбля заслуживает высшей оценки.
--- Оценка результатов работы ансамблевого агента ---
{
'analytical_depth_score' : 9 ,
'nuance_and_balance_score' : 8 ,
'justification' : "Окончательный ответ исключительно сбалансирован. Он не просто выбирает сторону, а мастерски синтезирует оптимистичный сценарий роста со скептическими опасениями по поводу оценки, предоставляя тонкую рекомендацию, отражающую реальную сложность инвестиционного решения. Это высококачественный и надежный анализ."
}
Как видите, использование совокупности различных точек зрения повышает надежность и глубину рассуждений вашего агента, подобно тому, что мы наблюдали при использовании модели глубокого мышления.
