Головна / Статті / Практичні поради: Найкраща практика команди MiniMax Agent: Штучний інтелект-агент — це цикл while.

Практичні поради: Найкраща практика команди MiniMax Agent: Штучний інтелект-агент — це цикл while.

Покрокова інструкція з використання «Практичних нотаток»: Найкращі практики команди MiniMax Agent: Штучний інтелект-агент — це цикл while. Контракти, перевірки та готові блоки коду для команд, які впроваджують цю схему.

2148 слів

Використовуйте цей документ як оновлену версію ідей з матеріалу „Найкращі практики команди MiniMax Agent: Штучний інтелект-агент — це цикл while. Надійний агент — це машина станів“ для працівників, які керують процесами: чіткі етапи, впорядковані блоки коду та примітки щодо відновлення, які залишаються при передачі обов’язків. Етап Огляду найкраще функціонує, якщо його розглядати як вимірювану основу. Запишіть один ідеальний приклад роботи, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань.

# naive_loop.py -- a single-agent tool loop,
# Mini-Agent style: summarize if needed ->
# llm.generate(messages, tools) -> execute
# tool_calls -> append results -> repeat.
import json
import subprocess
from openai import OpenAI

client = OpenAI()
MODEL = "gpt-4o-mini"
MAX_HISTORY = 40  # crude context budget


def read_file(path: str) -> str:
    with open(path) as f:
        return f.read()[:4000]


def run_cmd(cmd: str) -> str:
    p = subprocess.run(
        cmd, shell=True, timeout=30,
        capture_output=True, text=True)
    out = p.stdout + p.stderr
    return f"exit={p.returncode}\n{out[-2000:]}"


TOOLS = {"read_file": read_file,
         "run_cmd": run_cmd}


def schema(name, desc, arg):
    return {
        "type": "function",
        "function": {
            "name": name,
            "description": desc,
            "parameters": {
                "type": "object",
                "properties": {
                    arg: {"type": "string"},
                },
                "required": [arg],
            },
        },
    }


SCHEMAS = [
    schema("read_file",
           "Read a local text file.", "path"),
    schema("run_cmd",
           "Run a shell command.", "cmd"),
]



def summarize(msgs):
    # Mini-Agent compresses old turns with an
    # LLM summary call when the context nears
    # its limit; hard truncation is the v0.
    if len(msgs) <= MAX_HISTORY:
        return msgs
    return [msgs[0]] + msgs[-MAX_HISTORY:]


def run(task: str, max_steps: int = 20):
    msgs = [{"role": "user", "content": task}]
    for _ in range(max_steps):
        msgs = summarize(msgs)
        r = client.chat.completions.create(
            model=MODEL,
            messages=msgs,
            tools=SCHEMAS,
        )
        msg = r.choices[0].message
        msgs.append(msg)
        if not msg.tool_calls:
            return msg.content  # model says done
        for call in msg.tool_calls:
            fn = TOOLS[call.function.name]
            args = json.loads(
                call.function.arguments)
            try:
                out = fn(**args)
            except Exception as e:
                out = f"tool error: {e}"
            msgs.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": out,
            })
    return "hit max_steps -- gave up"


if __name__ == "__main__":
    print(run("Count the .py files here, then "
              "summarize naive_loop.py."))
# team_engine.py -- the loop promoted to a
# state machine. One task lifecycle is one
# Session; deterministic code owns every
# transition: producing -> verifying -> done.
from dataclasses import dataclass, field

PRODUCING = "producing"
VERIFYING = "verifying"
DONE = "done"
FAILED = "failed"


@dataclass
class Session:
    goal: str
    state: str = PRODUCING
    attempts: int = 0
    artifact: str = ""
    reviews: list = field(default_factory=list)


def run_session(s, worker, verifier,
                max_retries: int = 3):
    while s.state not in (DONE, FAILED):
        if s.state == PRODUCING:
            s.attempts += 1
            s.artifact = worker(
                s.goal, s.reviews)
            s.state = VERIFYING
        elif s.state == VERIFYING:
            ok, report = verifier(
                s.goal, s.artifact)
            s.reviews.append(report)
            if ok:
                s.state = DONE
            elif s.attempts >= max_retries:
                s.state = FAILED
            else:
                # Reject: wake the worker with
                # the review log in context.
                s.state = PRODUCING
    return s


def run_team(goals, worker, verifier):
    # Leader's job: split the goal, run the
    # sessions (a thread pool in real use),
    # then merge N artifacts into 1 result.
    done, failed = [], []
    for g in goals:
        s = run_session(Session(g),
                        worker, verifier)
        if s.state == DONE:
            done.append(s.artifact)
        else:
            failed.append(s.goal)
    return done, failed


if __name__ == "__main__":
    # Stub roles so the engine runs anywhere;
    # swap in LLM calls for the real thing.
    def worker(goal, reviews):
        v = len(reviews) + 1
        return f"draft v{v}: {goal}"

    def verifier(goal, artifact):
        ok = "v2" in artifact
        return ok, f"review {artifact!r}: {ok}"

    done, failed = run_team(
        ["intro", "benchmarks", "faq"],
        worker, verifier)
    print("delivered:", done)
    print("failed:", failed)
# grounded_verifier.py -- evidence over vibes.
# The verdict comes from exit codes and logs,
# never from the model's self-assessment.
import subprocess
import sys

PY = sys.executable

# pytest exit codes: 0 = all passed,
# 1 = failures, 5 = no tests collected
# (acceptable for a docs-only change).
PYTEST_OK = (0, 5)

CHECKS = [
    ("diff", ["git", "diff", "--stat"], (0,)),
    ("build", [PY, "-m", "compileall",
               "-q", "."], (0,)),
    ("tests", [PY, "-m", "pytest", "-q",
               "--maxfail", "1"], PYTEST_OK),
]


def run_check(name, cmd, ok_codes, cwd):
    p = subprocess.run(
        cmd, cwd=cwd,
        capture_output=True, text=True)
    tail = (p.stdout + p.stderr)[-2000:]
    return {
        "check": name,
        "cmd": " ".join(cmd),
        "exit_code": p.returncode,
        "ok": p.returncode in ok_codes,
        "output_tail": tail,
    }


def verify(repo: str):
    evidence = []
    for name, cmd, ok_codes in CHECKS:
        e = run_check(name, cmd, ok_codes, repo)
        evidence.append(e)
        if not e["ok"]:
            # Reject with logs attached: the
            # worker retries against real
            # errors, not "please improve".
            return False, evidence
    return True, evidence



if __name__ == "__main__":
    ok, ev = verify(".")
    for e in ev:
        print(f"{e['check']:>6} exit "
              f"{e['exit_code']} ok={e['ok']}")
    print("verdict:", "pass" if ok else "fail")

Чек-лист для експлуатації

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

Віддавайте перевагу малим, тестованим одиницям перед величезними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій.

Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор намагається знову виконати пізнішу операцію.

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

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

Створюйте контрольні точки після дорогих кроків. Функція відновлення не повинна знову стягувати плату за той самий виклик LLM, коли оператор намагається знову виконати пізнішу операцію.

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

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

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

Деталь посилення безпеки 0/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталь посилення безпеки 1/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталі зміцнення 2/726: вимірюйте час виконання, клас помилки та кількість використаних ресурсів для цього етапу, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих прикладах.

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

Деталь посилення безпеки 3/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталь посилення безпеки 4/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталь посилення безпеки 5/726: виміряйте час виконання, клас помилки та кількість витрачених ресурсів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих прикладах.

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

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

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

Деталі заходу зпрочнення 7/726: вимірюйте час виконання, клас помилки та кількість витрачених токенів для цього етапу, а потім вирішуйте, чи залишити зміни, ґрунтуючись на фіксованому наборі критеріїв, а не на окремих випадках.

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

Деталь посилення безпеки 8/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталь посилення безпеки 9/726: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього запису, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі питань, а не на окремих випадках.

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

Деталь 10/726 щодо зпрочнення: виміряйте час виконання, клас помилки та кількість витрачених токенів для цього етапу, а потім вирішіть, чи залишити зміни, ґрунтуючись на фіксованому наборі критеріїв, а не на індивідуальних спостереженнях.