Практичні нотатки: Посібник з архітектур багатьох агентів
Покрокове керівництво з практичних нотаток: посібник з архітектур багатьох агентів: контракти, перевірки та готові блоки коду для команд, які використовують цю схему.
У цьому посібнику описується процес створення системи від сировини до готового продукту для: Посібника з архітектур багатоагентних систем. Основна увага приділяється конкретним крокам виконання, чітким перевіркам та коду, який можна просто додати до репозиторію, не намагаючись здогадатися про його призначення. На етапі огляду необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись зрозуміти прихований стан системи. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.
1. Ієрархічні багатоагентні системи
Під час роботи над першим етапом «Ієрархічні багатоагентні системи» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ. Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізнішу ланку.
from fundamental_analysis_tools import evaluate_fundamentals
from langchain.agents import create_agent
from technical_analysis_tools import technical_analysis
agent = create_agent(
model=llm,
tools=[technical_analysis, evaluate_fundamentals]
)
Supervisor
├── Technical Analysis Tool
└── Fundamental Analysis Tool
Supervisor
├── Technical Analyst Agent
│ ├── Tool A
│ ├── Tool B
│ └── ...
└── Fundamental Analyst Agent
├── Tool C
├── Tool D
└── ...
from langchain.tools import tool
from langgraph_supervisor import create_supervisor
@tool
def get_weather(city: str) -> str:
"""Use this tool to get the weather of a city or location"""
return f"The weather is sunny in {city}"
weather_expert = create_agent(
model=llm,
tools=[get_weather],
name="weather_expert"
)
technical_analyst_agent = create_agent(
model=llm,
tools=[technical_analysis],
name="technical_analyst"
)
fundamental_analyst_agent = create_agent(
model=llm,
tools=[evaluate_fundamentals],
name="fundamental_analyst"
)
analysis_squad = create_supervisor(
[technical_analyst_agent, fundamental_analyst_agent],
model=llm,
supervisor_name="analysis_supervisor",
prompt=(
"You are a team supervisor managing a fundamental analyst and a "
"technical analyst..."
)
)
analysis_app = analysis_squad.compile(
name="fundamental_and_technical_analyst"
)
supervisor_graph = create_supervisor(
[analysis_app, weather_expert],
model=llm,
prompt=(
"You are a team supervisor managing a fundamental analyst, a "
"technical analyst and a weather expert..."
)
)
supervisor = supervisor_graph.compile()
Коли варто використовувати ієрархічну архітектуру?
Під час роботи над питанням «Коли слід використовувати етап», спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища секретних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Створюйте контрольні точки після дорогих операцій. Система відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізнішу ланку.
2. Явні робочі процеси з кількома агентами
Під час роботи над другою стадією «显式多智能体» спочатку запишіть умови взаємодії: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Створюйте контрольні точки після дорогих операцій. Функція відновлення не повинна знову оплачувати однаковий виклик LLM, коли оператор намагається виконати наступний етап. Під час роботи над другою стадією «显式多智能体» спочатку запишіть умови взаємодії: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цю стадію як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.
def execute_plan(
plan: Plan,
state: State,
) -> Command[
Literal[
"fundamental_analysis_agent",
"technical_analysis_agent",
"respond",
]
]:
gotos = [
Send(
step.action.agent_to_use,
{"query": step.action.query_to_send},
)
for step in plan.steps
]
if not gotos:
gotos.append(
Send("respond", {"messages": state["messages"]})
)
return Command(goto=gotos)
def router(state: State) -> Command[
Literal["fundamental_analysis_agent", "technical_analysis_agent", "respond"]
]:
# Get plan
query = state['messages'][-1].content
response = llm_planner.invoke(query) #invoke planner
return execute_plan(response, state)
Коли використовувати робочі процеси з显式多智能体
Підхід «Коли використовувати явну стадію» найкраще працює, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат на ранньому етапі запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Тримайте стан графа простим та типованим. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють продовження роботи після перерв.
3. Агентське зграя
Етап 3 «Зграя агентів» працює найкраще, якщо його розглядати як вимірювану поверхню. Збережіть один золотий запис, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Тримайте стан графа простим та типованим. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють продовження роботи після перерв.
from langgraph_swarm import (
create_handoff_tool,
create_swarm,
)
## We'll have to redefine our all agents to include the handoff tool
weather_expert = create_agent(
model=llm,
tools=[
get_weather,
create_handoff_tool(
agent_name="technical_analyst",
description="Transfer for technical analysis related questions"
),
create_handoff_tool(
agent_name="fundamental_analyst",
description="Transfer for fundamental analysis related questions"
),
],
name="weather_expert"
)
technical_analyst_agent = ...
fundamental_analyst_agent = ...
swarm_workflow = create_swarm(
[fundamental_analyst_agent, technical_analyst_agent, weather_expert],
default_active_agent="weather_expert" #a default agent must be specified.
)
swarm = swarm_workflow.compile()
Коли варто використовувати зграю?
Підхід «Коли варто використовувати цю стадію» найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зафіксуйте один ідеальний запис, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людські перевірки та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Зберігайте стан графа у простій та типованій формі. Вкладені структури приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють продовження роботи після перерв. Підхід «Коли варто використовувати цю стадію» найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зафіксуйте один ідеальний запис, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Розглядайте цю стадію як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.
4. Системи з багатьма агентами типу Blackboard
Для етапу 4 Blackboard Multi Agent необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовищ до спільних. Встановіть людське схвалення для операцій, які спричиняють витрати чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повності бізнес-функцій.
a. Чорна дошка
Для етапу на дошці оголошень необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь алгоритм. Необхідно передбачити людське схвалення для дій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повноти бізнес-функціоналу.
class Blackboard(TypedDict, total=False):
query: str
# Problem frame
problem_framed: bool
ticker: str | None
location: str | None
wants_technical: bool
wants_fundamental: bool
# Specialist panels
technical: dict | None
fundamental: dict | None
environmental: dict | None
# Integrated solution
synthesis: str | None
# Control state
next_knowledge_source: str | None
cycles: int
b. Джерела знань
На етапі b „Джерела знань“ необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Встановлюйте людське схвалення для тих кроків, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повності функціоналу продукту. На етапі b „Джерела знань“ необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість знову виконати крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Називайте елементи продукту, визначайте критерії успіху та не допускайте безповідомного часткового завершення роботи.
def can_analyse_technicals(board: Blackboard) -> bool:
return (
board.get("ticker") is not None
and board.get("wants_technical", False)
and board.get("technical") is None
)
c. Компонент керування
Під час роботи над етапом c. Компонент керування спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із результатами функціональності. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовища до спільних середовищ. Робіть контрольні пункти після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізніший етап.
def control_component(board: Blackboard) -> dict:
eligible = [
source
for source in KNOWLEDGE_SOURCES #these are subagents
if source.precondition(board)
]
if not eligible:
return {"next_knowledge_source": None}
chosen = max(
eligible,
key=lambda source: source.priority,
)
return {
"next_knowledge_source": chosen.name,
"cycles": board.get("cycles", 0) + 1,
}
inspect → identify eligible specialists → activate one
→ contribute → inspect again
Виконання здійснюється навмисно послідовно
Під час виконання етапу, який є послідовним за своєю природою, спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Робіть контрольні пункти після дорогих операцій. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізнішу ланку.
Коли варто використовувати архітектуру „чорної дошки“?
Під час роботи над етапом «Коли слід використовувати цей підхід», спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Робіть контрольні пункти після дорогих кроків. Система повторного запуску не повинна знову стягувати плату за той самий виклик ШІ, коли оператор намагається виконати наступний етап. Під час роботи над етапом «Коли слід використовувати цей підхід», спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як договір між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.
5. Системи з багатьма агентами типу Actor-Critic (адверсарійні)
5-етапний алгоритм Actor-Critic у форматі конкуренції працює найкраще, коли його розглядають як вимірювану поверхню. Запишіть один ідеальний приклад роботи, один випадок збою та примітки щодо скасування змін перед розширенням обсягу завдань. Фіксуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ. Тримайте стан графа простим та типованим; вкладені структури приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.
actor → critic → judge
↑ |
└──── revise ─────┘
a. Актор
Модель «Актор» працює найкраще, коли її розглядають як вимірювану поверхню. Збережіть один ідеальний приклад роботи, один випадок збою та запис про скасування змін перед розширенням обсягу. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь граф. Тримайте стан графа простим та типованим. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють відновлення роботи після перерв.
def actor(state: AdversarialState) -> dict:
if state.get("latest_critique") is None:
prompt = f"Produce a first draft.\n\nTASK: {state['task']}"
else:
prompt = (
"Revise the current draft.\n\n"
f"TASK:\n{state['task']}\n\n"
f"CURRENT DRAFT:\n{state['draft']}\n\n"
f"CRITIQUE:\n{state['latest_critique']}\n\n"
f"JUDGE'S PRIORITY:\n{state['latest_verdict']['focus']}"
)
draft = llm.invoke(prompt).content
return {
"draft": draft,
"round": state.get("round", 0) + 1,
}
b. Критик
Етап критики функціонує найкраще, коли його розглядають як вимірювану поверхню. Зафіксуйте один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний шляхи роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв. Етап критики функціонує найкраще, коли його розглядають як вимірювану поверхню. Зафіксуйте один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення роботи.
class Issue(BaseModel):
severity: Literal["blocking", "major", "minor"]
description: str
class Critique(BaseModel):
issues: list[Issue]
summary: str
def weighted_issue_score(issues: list[dict]) -> int:
weights = {
"blocking": 5,
"major": 2,
"minor": 1,
}
return sum(
weights[issue["severity"]]
for issue in issues
)
c. Суддя
На етапі судді необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Чітке відображення витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. Встановлюйте людське схвалення для тих кроків, які спричиняють витрати чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повноти бізнес-функціоналу.
class Verdict(BaseModel):
decision: Literal["accept", "revise"]
reasoning: str
focus: str
def judge(state: AdversarialState) -> dict:
verdict = llm.with_structured_output(Verdict).invoke(
[
HumanMessage(
content=(
"Evaluate the critic's findings on their merits. "
"Accept if only minor issues remain. "
"Request revision only for blocking or material problems.\n\n"
f"DRAFT:\n{state['draft']}\n\n"
f"CRITIQUE:\n{state['latest_critique']}"
)
)
]
)
return {
"latest_verdict": verdict.model_dump(),
}
Чому все ще потрібен «сторожовий пес»
Щоб зрозуміти, чому певний етап є критичним, необхідно перед зміною коду визначити вхідні дані, власника цього етапу та критерії завершення. Оператори мають мати можливість перезапустити етап з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Необхідно передбачити людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення елементів під час компіляції не є гарантією повноти бізнес-логіки.
round 1: 12
round 2: 8
round 3: 8
round 4: 9
def watchdog(state: AdversarialState) -> dict:
round_number = state.get("round", 0)
scores = state.get("issue_counts", [])
if round_number >= HARD_ROUND_CAP:
return {
"halt_reason": "hard round cap reached",
}
if len(scores) >= STALEMATE_WINDOW:
window = scores[-STALEMATE_WINDOW:]
if window[-1] >= window[0]:
return {
"halt_reason": (
f"stalemate detected: {window}"
),
}
return {}
Фіналізація має розрізняти успіх та невдачу
Для завершення необхідно визначити етап успіху, вказати вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно задокументувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Встановлюйте людське схвалення для тих кроків, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повності функціоналу продукту. Для завершення необхідно визначити етап успіху, вказати вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Назвіть всі елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення.
Коли варто використовувати архітектуру типу «адверсарій»?
Під час розгляду питання «Коли варто використовувати» спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та наслідки часткової невдачі. Такий перелік допомагає зберігати чесність у подальших змінах коду. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Чітке бачення витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовища до спільних. Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик ШІ, коли оператор перезапускає пізнішу ланку.
Вибір архітектури
Під час виконання етапу вибору архітектури спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Робіть контрольні пункти після дорогих операцій. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізнішу ланку.
Заключні міркування
Під час роботи над етапом «Остаточні міркування» спочатку запишіть умови використання: необхідні дані вхіду, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Документуйте як шлях успішної роботи, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Робіть контрольні пункти після дорогих кроків. Система відновлення не повинна знову стягувати плату за той самий виклик ШІ, коли оператор намагається знову виконати пізнішу операцію. Під час роботи над етапом «Остаточні міркування» спочатку запишіть умови використання: необхідні дані вхіду, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як угоду між даними вхіду та перевіреними результатами. Назвіть створювані елементи, визначте критерії успіху та не допускайте безповідомного часткового завершення роботи.
Контрольний список для експлуатації
Етап перевірки операційних процедур працює найкраще, якщо його розглядати як вимірювану структуру. Збережіть один ідеальний зразок виконання, один випадок збою та запис про скасування дій перед розширенням обсягу роботи.
Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій.
Зберігайте стан графа у вигляді простих, типованих структур. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.
Коли це дозволяють бюджетні обмеження, додайте тест на базову функціональність, який перевіряє критичний шлях у процесі інтеграційного тестування за допомогою фікстур, а не реальних платних API.
Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Назвіть всі створювані елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення роботи.
Зберігайте стан графа у вигляді простих, типованих структур. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.
Перш ніж запускати стек у продакшн, заморозьте версії, збережіть ідеальний запис для критичного шляху та підтвердьте кроки відкату. У спільних середовищах необхідні обмеження швидкості, перевірки прав на використання та чіткий власник для зміни секретів. Віддавайте перевагу надійності перед креативними одноразовими демонстраціями.
Примітка для f6f8c689c406: не включайте ключі постачальника до репозиторію, встановіть ліміт токенів на сеанс та зберігайте записи поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.