Головна / Статті / Практичні нотатки: Глибокі агенти в дії: створення багатоагентної системи досліджень

Практичні нотатки: Глибокі агенти в дії: створення багатоагентної системи досліджень

Покрокове керівництво з практичних нотаток: Глибокі агенти в дії: створення багатоагентної системи досліджень – контракти, перевірки та готові блоки коду для команд, які впроваджують цю модель.

3170 слів

У цьому посібнику описується процес створення системи від сировини до готового продукту для проєкту «Deep Agents in Action: Building a Multi-Agent Research System». Основна увага приділяється конкретним крокам виконання, чітким перевіркам та коду, який можна без проблем додати до репозиторію, не здогадуючись про його призначення. На етапі огляду необхідно визначити вхідні дані, відповідальну особу за кожен крок та критерії завершення роботи перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись здогадатися про прихований стан системи. Необхідно одночасно задокументувати оптимальний шлях виконання та шлях відновлення системи у разі проблем. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Вступ: Архітектура Deep Agents

Під час роботи над етапом «Вступ. Глибокі агенти» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Робіть контрольні пункти після дорогих кроків. Система відновлення не повинна знову оплачувати один і той самий виклик LLM, коли оператор намагається виконати пізнішу операцію.

Що таке шаблон Глибоких агентів?

Під час роботи над етапом «Що таке Deep» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання. Робіть перевірки після дорогих кроків. Система відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор намагається виконати наступний етап.

| Single Agent                       | Deep Agents                                       |
| ---------------------------------- | ------------------------------------------------- |
| One context window gets overloaded | Each agent has an isolated, focused context       |
| All reasoning in one prompt        | Specialised reasoning per domain                  |
| Hard to scale                      | Add specialists without changing the orchestrator |
| Hard to debug                      | Full delegation trace for auditability            |

Огляд Deep Agents

Під час праці над етапом огляду Deep Agents спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із результатами функціонування. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ. Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізніший етап. Під час праці над етапом огляду Deep Agents спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте оптимальний та резервний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Основні концепції LangChain Deep Agents

Основні концепції роботи LangChain працюють найкраще, якщо їх розглядати як вимірювану поверхню. Запишіть один ідеальний приклад виконання, один випадок збою та примітку щодо скасування дій перед розширенням обсягу завдань. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якась дія зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Зберігайте стан графа у вигляді простих, типованих структур. Вкладені елементи приховують інформацію про те, який вузол заповнив певне поле, що ускладнює продовження роботи після перерв.

Технічна реалізація

Етап технічної реалізації працює найкраще, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний зразок результату, один випадок збою та примітку щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не погоджуйтесь на мовчазне часткове виконання завдань. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.

Огляд архітектури

Етап огляду архітектури працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-версії до спільних середовищ. Зберігайте стан графа у випрямленому та типованому форматі. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, та ускладнюють продовження роботи після перерв.

User Task
  └─ OrchestratorAgent (Planning & Synthesis)
      ├─ ResearcherAgent (web_search)
      ├─ AnalystAgent (calculator, code_executor)
      └─ WriterAgent (file_reader)

Етап огляду архітектури працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний шляхи роботи разом. Повторні спроби, людські контролі та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Технологічна стек

На етапі технічної структури необхідно визначити вхідні дані, відповідальну особу за кожен крок та критерії завершення перед зміною коду. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Якщо крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Необхідно включати людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Компіляційна налаштування не є гарантією повноти бізнес-функціоналу.

Структура коду

На етапі структури коду необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте елементи проекту, визначте критерії успіху та не допускайте мовчазного часткового завершення. Запровадьте людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Компіляційна налаштування не є гарантією повноти бізнес-процесу.

deepagents-usecase/
├── agents/
│   ├── __init__.py         # Package exports
│   ├── base.py             # Abstract BaseAgent + ReAct loop
│   ├── llm_client.py       # LLM adapter (Ollama/llama.cpp/OpenAI/Anthropic)
│   ├── messages.py         # Typed message protocol
│   ├── orchestrator.py     # OrchestratorAgent (top-level)
│   ├── researcher.py       # ResearcherAgent specialist
│   ├── analyst.py          # AnalystAgent specialist
│   └── writer.py           # WriterAgent specialist
├── tools/
│   ├── __init__.py
│   ├── base.py             # BaseTool + ToolResult
│   ├── calculator.py       # Safe AST-based arithmetic evaluator
│   ├── code_executor.py    # Sandboxed Python execution (exec with allow-list)
│   ├── file_reader.py      # Sandboxed file reading (input/ only)
│   └── web_search.py       # Web search (stub + live Tavily)
├── memory/
│   ├── __init__.py
│   └── store.py            # AgentMemoryStore (short/long-term/episodic)
├── config/
│   ├── __init__.py
│   └── settings.py         # Centralised env-based configuration
├── tests/
│   ├── test_tools.py           # Tool unit tests (71 tests)
│   ├── test_memory.py          # Memory unit tests (24 tests)
│   ├── test_agents.py          # Agent integration tests (92 tests)
│   └── test_code_executor.py   # Code Executor tests (134 tests)
├── input/                  # Input documents (content gitignored)
├── output/                 # Generated reports (content gitignored)
├── memory/                 # Persistent agent memory (JSON files)
├── scripts/
│   ├── start.sh                  # Launch Streamlit in detached mode
│   ├── stop.sh                   # Gracefully stop the application
│   ├── cleanup.sh                # Remove .venv, __pycache__, etc.
│   └── check_code_executor.py    # Standalone Code Executor sanity-check
├── Docs/
│   ├── Architecture.md           # Mermaid architecture diagrams
│   ├── Quickstart.md             # Step-by-step getting started guide
│   ├── API.md                    # Full public API reference
│   └── CodeExecutorVerification.md  # Code Executor test & verification guide
├── app.py                  # Streamlit web UI
├── main.py                 # CLI entry point
├── requirements.txt
├── .env.example            # Environment variable template
└── README.md
# =============================================================================
# Deep Agents System — Environment Configuration
# =============================================================================
# Copy this file to .env and fill in your values.
# NEVER commit the .env file to version control.
#
# Usage:
#   cp .env.example .env
#   # edit .env with your actual keys
# =============================================================================

# ─── LLM Provider ──────────────────────────────────────────────────────────
# Select ONE provider. Comment out the others.

# Option A: Ollama (local, default — no API key needed)
LLM_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2

# Option B: llama.cpp (local)
# LLM_PROVIDER=llamacpp
# LLAMACPP_BASE_URL=http://localhost:9931/v1
# LLAMACPP_MODEL=local-model

# Option C: OpenAI
# LLM_PROVIDER=openai
# OPENAI_API_KEY=sk-...
# OPENAI_MODEL=gpt-4o

# Option D: Anthropic
# LLM_PROVIDER=anthropic
# ANTHROPIC_API_KEY=sk-ant-...
# ANTHROPIC_MODEL=claude-3-5-sonnet-20241022

# ─── Application Settings ──────────────────────────────────────────────────
APP_PORT=8501
APP_HOST=0.0.0.0
LOG_LEVEL=INFO

# ─── Agent Configuration ───────────────────────────────────────────────────
# Maximum reasoning steps per agent (lower = faster on slow local LLMs)
MAX_AGENT_STEPS=8

# Maximum tokens per LLM call (1024 is enough for ReAct; raise for longer reports)
MAX_TOKENS=1024

# Temperature for LLM responses (0.0 = deterministic, 1.0 = creative)
TEMPERATURE=0.1

# ─── Memory & Storage ──────────────────────────────────────────────────────
# Directory for persistent agent memory (relative to project root)
MEMORY_DIR=./memory

# Maximum number of memories to retain per agent
MAX_MEMORY_ENTRIES=100

# ─── Tool Configuration ────────────────────────────────────────────────────
# Enable or disable specific tools (true/false)
TOOL_WEB_SEARCH_ENABLED=true
TOOL_CALCULATOR_ENABLED=true
TOOL_FILE_READER_ENABLED=true
TOOL_CODE_EXECUTOR_ENABLED=true

# Web search stub — set to real Tavily/SerpAPI key for live search
# TAVILY_API_KEY=tvly-...

# ─── Output ────────────────────────────────────────────────────────────────
OUTPUT_DIR=./output

Ключові уривки коду

На етапі Key Code Excerpts необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища. Встановлюйте людське схвалення для кроків, які вимагають фінансових витрат чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повності функціоналу продукту. На етапі Key Code Excerpts необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як оптимальний, так і альтернативний шлях виконання. Повторні спроби, людське схвалення та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Безпечний оцінювач арифметичних операцій AST (tools/calculator.py)

Під час роботи над етапом безпечного оцінювача арифметичних операцій AST спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу малим, тестованим одиницям перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих даних налагодження коду займає години.

# Whitelisted AST operators and math functions
_SAFE_OPERATORS = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
    ast.Pow: operator.pow,
    ast.USub: operator.neg,
}

_SAFE_FUNCTIONS = {
    "abs": abs, "round": round, "sqrt": math.sqrt,
    "sin": math.sin, "cos": math.cos, "log": math.log,
    "pi": math.pi, "e": math.e,
}

def _safe_eval(node: ast.expr) -> float:
    """Recursively evaluate an AST expression node in a safe sandbox."""
    if isinstance(node, ast.Constant):
        if isinstance(node.value, (int, float)):
            return float(node.value)
        raise ValueError(f"Unsupported constant type: {type(node.value).__name__}")

    if isinstance(node, ast.BinOp):
        op_type = type(node.op)
        if op_type not in _SAFE_OPERATORS:
            raise ValueError(f"Unsupported binary operator: {op_type.__name__}")
        left = _safe_eval(node.left)
        right = _safe_eval(node.right)
        return _SAFE_OPERATORS[op_type](left, right)

    if isinstance(node, ast.Call):
        func_name = node.func.id
        if func_name not in _SAFE_FUNCTIONS:
            raise ValueError(f"Function '{func_name}' is not whitelisted.")
        args = [_safe_eval(a) for a in node.args]
        return _SAFE_FUNCTIONS[func_name](*args)

    raise ValueError(f"Unsupported AST node type: {type(node).__name__}")

Виконувач Python-коду в сандбоксі (tools/code_executor.py)

Під час роботи на етапі виконання коду Python у ізольованому середовищі спочатку складіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безповідомного часткового виконання. Записуйте ідентифікатор запиту, ідентифікатор моделі та час виконання за кожним викликом. Без цих записів періодичні помилки постачальника можуть здаватися багами програми.

def _build_exec_namespace() -> dict[str, Any]:
    return {
        "__builtins__": _SAFE_BUILTINS, # Explicit whitelist (no open, __import__, eval)
        "math": math,
        "statistics": statistics,
        "pi": math.pi,
        "e": math.e,
    }

def _execute_code(code: str, timeout: int = 5) -> ToolResult:
    exec_result = _ExecResult()
    captured_io = io.StringIO()

    def _worker():
        namespace = _build_exec_namespace()
        namespace["__builtins__"]["print"] = lambda *args, **kw: print(*args, **{**kw, "file": captured_io})
        try:
            exec(code, namespace)
            exec_result.stdout = captured_io.getvalue()
        except Exception as exc:
            exec_result.error = f"{type(exc).__name__}: {exc}"

    thread = threading.Thread(target=_worker, daemon=True)
    thread.start()
    thread.join(timeout=timeout)
    if thread.is_alive():
        return ToolResult(success=False, error=f"Execution timed out after {timeout}s.")

Безпечний для багатопотокової роботи інтерфейс Streamlit (app.py)

Під час роботи над етапом Thread-Safe Streamlit UI Relay спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ. Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор перезапускає пізнішу ланку. Під час роботи над етапом Thread-Safe Streamlit UI Relay спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність у подальших змінах коду. Одночасно задокументуйте оптимальний шлях виконання та шлях відновлення. Перезапуски, людські перевірки та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

class _PipelineRelay:
    """Thread-safe relay store for the running multi-agent pipeline."""
    def __init__(self) -> None:
        self.lock = threading.RLock()
        self.status_messages: list[dict[str, str]] = []
        self.agent_cards: dict[str, list[str]] = {}
        self.running: bool = False

    def append_status(self, msg_dict: dict[str, str]) -> None:
        with self.lock:
            self.status_messages.append(msg_dict)
            agent_id = msg_dict.get("agent_id", "orchestrator")
            self.agent_cards.setdefault(agent_id, []).append(msg_dict.get("detail", ""))

@st.cache_resource
def _get_relay() -> _PipelineRelay:
    return _PipelineRelay()

Приклад сценарію використання: аналіз змін клімату

Сценарій використання „Клімат“ найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зберігайте один ідеальний запис, один випадок збою та примітку про скасування дій перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям перед складними скриптами. Коли якась дія зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.

Benefits of Renewable Energy and Calculation of 280 Times 42

Benefits of Renewable Energy

Renewable energy reduces greenhouse gas emissions, contributing to climate change mitigation (Source: [National Renewable Energy Laboratory](https://www.nrel.gov/renewables/energy-benefits.html)). This is a key finding supported by credible sources, including the International Renewable Energy Agency (2020) and the World Health Organization (2020).

Renewable energy creates jobs and stimulates local economies (Source: [International Renewable Energy Agency](https://www.irena.org/publications/2020/Jun/Global-Status-Report-2020)). This is a significant benefit highlighted by the International Energy Agency (2020) and the National Bureau of Economic Research (2020).

Renewable energy improves air quality and public health (Source: [World Health Organization](https://www.who.int/news-room/fact-sheets/detail/air-pollution)). This is a critical aspect of renewable energy, supported by the National Renewable Energy Laboratory (n.d.).

The global renewable energy market is projected to reach 30% of total energy production by 2025 (Source: [International Energy Agency](https://www.iea.org/news/pressrelease/2020/june/global-renewables-report-2020/)). This growth is expected to reduce energy costs by 10-30% compared to fossil fuels (Source: [National Bureau of Economic Research](https://www.nber.org/papers/w28822)).

Calculation of 280 Times 42

The calculation of 280 times 42 yields 11,840. This result is supported by the Data Analysis report, which provides a detailed calculation of the product (280 * 42 = 11,760).

Trend Analysis

The global renewable energy market is expected to grow significantly, with a projected 30% share of total energy production by 2025. This growth is expected to have a significant impact on the environment and the economy.

Key Insights

1. Renewable energy can significantly reduce greenhouse gas emissions and improve air quality.
2. Renewable energy can create jobs and stimulate local economies.

Limitations

The data provided is based on projections and may not reflect actual outcomes.

Sources

1. National Renewable Energy Laboratory. (n.d.). Energy Benefits of Renewable Energy. Retrieved from <https://www.nrel.gov/renewables/energy-benefits.html>
2. International Renewable Energy Agency. (2020). Global Status Report 2020. Retrieved from <https://www.irena.org/publications/2020/Jun/Global-Status-Report-2020>
3. World Health Organization. (2020). Air pollution. Retrieved from <https://www.who.int/news-room/fact-sheets/detail/air-pollution>
4. International Energy Agency. (2020). Global Renewables Report 2020. Retrieved from <https://www.iea.org/news/pressrelease/2020/june/global-renewables-report-2020/>
5. National Bureau of Economic Research. (2020). The Economics of Renewable Energy. Retrieved from <https://www.nber.org/papers/w28822>

Додавання нового спеціалізованого агента

Етап додавання нового спеціаліста найкраще функціонує, якщо його розглядати як вимірювану поверхню. Зафіксуйте один ідеальний приклад роботи, один випадок невдачі та примітку про скасування змін перед розширенням обсягу завдань. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив яке поле, що ускладнює продовження роботи після перерв.

from agents.base import BaseAgent

class MySpecialistAgent(BaseAgent):
    def __init__(self, llm_client=None, on_status=None):
        super().__init__(
            agent_id="my_specialist",
            tools=[my_custom_tool],
            llm_client=llm_client,
            on_status=on_status,
        )

    @property
    def role_description(self) -> str:
        return "You are a specialist that does X…"

Висновок

Етап Висновків працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу від демо-середовища до спільних середовищ. Зберігайте стан графа у простому та типованому вигляді. Вкладені блоки приховують інформацію про те, який вузол записав яке поле, і ускладнюють продовження роботи після перерв. Етап Висновків працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний шляхи роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Посилання

На етапі „Лінки“ необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Встановлюйте людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повноти бізнес-функціоналу.

Чек-лист операцій

Етап чек-листу операцій працює найкраще, якщо його розглядати як вимірювану поверхню. Зберігайте один ідеальний зразок виконання, один випадок невдачі та примітки щодо скасування змін перед розширенням обсягу роботи.

Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, яке оператори можуть перевірити, не читаючи весь кодовий граф.

Зберігайте стан графа у вигляді плоскої структури з типованими даними. Вкладені блоки приховують інформацію про те, який вузол заповнив певне поле, і ускладнюють продовження роботи після перерв.

Додайте тест на базову функціональність, який перевіряє критичний шлях у процесі інтеграційного тестування за допомогою фікстур, а не реальних платних API, коли це дозволяють бюджетні обмеження.

Одночасно задокументуйте успішний та відновлювальний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Зберігайте стан графа у вигляді плоскої структури з типованими даними. Вкладені блоки приховують інформацію про те, який вузол заповнив певне поле, і ускладнюють продовження роботи після перерв.

Перед підвищенням версії стека заморозьте існуючі версії, зафіксуйте ідеальний запис дій для критичного шляху та підтвердьте кроки для відкату. У спільних середовищах необхідні обмеження на кількість запитів, перевірки прав доступу та чіткий власник для зміни секретів. Віддавайте перевагу надійності перед креативними одноразовими демонстраціями.

Примітка до пакету 60e98c93fde5: не включайте ключі постачальників у репозиторій, встановіть ліміт токенів на сеанс та зберігайте транскрипції поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.