Выполнение кода (программный вызов инструмента)

Инструмент execute_code Позволяет агенту писать скрипты Python, которые программно вызывают инструменты Hermes, превращая многошаговые рабочие процессы в один шаг LLM. Скрипт выполнения в дочернем процессе на хосте-агенте, общий с Hermes через RPC по сокету домена Unix.

Как это работает

  1. Агент пишет Python-скрипт, используя from hermes_tools import...
  2. Hermes текущий модуль-заглушку hermes_tools.py с RPC-функциями
  3. Hermes открывает сокет Unix-домена и запускает поток RPC-слушателя.
  4. Скрипт выполнения в дочернем процессе — вызовы инструментов передаются через сокет обратно в Hermes.
  5. Только вывод print() скрипта возвращает LLM; промежуточные результаты инструментов никогда не остаются в контекстном окне
# Агент может писать скрипты вроде:
from hermes_tools import web_search, web_extract

results = web_search("Python 3.13 features", limit=5)
for r in results["data"]["web"]:
    content = web_extract([r["url"]])
    #... фильтрация и обработка...
print(summary)

Доступные инструменты внутри скриптов: web_search, web_extract, read_file, write_file, search_files, patch, terminal (только передний план).

Когда агент это использует

Агент использует execute_code, когда есть:

Ключевое преимущество: инструменты промежуточных результатов никогда не рассматривают контекстное окно — возвращается только выводной вывод print(), что значительно сокращает использование токенов.

Практические образцы

Конвейер обработки данных

from hermes_tools import search_files, read_file
import json

# Найти все конфигурационные файлы и извлечь настройки базы данных
matches = search_files("database", path=".", file_glob="*.yaml", limit=20)
configs = []
for match in matches.get("matches", []):
    content = read_file(match["path"])
    configs.append({"file": match["path"], "preview": content["content"][:200]})

print(json.dumps(configs, indent=2))

Многошаговое веб-исследование

from hermes_tools import web_search, web_extract
import json

# Поиск, извлечение и обобщение за один шаг
results = web_search("Rust async runtime comparison 2025", limit=5)
summaries = []
for r in results["data"]["web"]:
    page = web_extract([r["url"]])
    for p in page.get("results", []):
        if p.get("content"):
            summaries.append({
                "title": r["title"],
                "url": r["url"],
                "excerpt": p["content"][:500]
            })

print(json.dumps(summaries, indent=2))

Массовый рефакторинг файлов

from hermes_tools import search_files, read_file, patch

# Найти все Python-файлы, использующие устаревший API, и исправить их
matches = search_files("old_api_call", path="src/", file_glob="*.py")
fixed = 0
for match in matches.get("matches", []):
    result = patch(
        path=match["path"],
        old_string="old_api_call(",
        new_string="new_api_call(",
        replace_all=True
    )
    if "error" not in str(result):
        fixed += 1

print(f"Fixed {fixed} files out of {len(matches.get('matches', []))} matches")

Конвейер сборки и тестирования

from hermes_tools import terminal, read_file
import json

# Запустить тесты, разобрать результаты и сообщить
result = terminal("cd /project && python -m pytest --tb=short -q 2>&1", timeout=120)
output = result.get("output", "")

# Разобрать вывод тестов
passed = output.count(" passed")
failed = output.count(" failed")
errors = output.count(" error")

report = {
    "passed": passed,
    "failed": failed,
    "errors": errors,
    "exit_code": result.get("exit_code", -1),
    "summary": output[-500:] if len(output) > 500 else output
}

print(json.dumps(report, indent=2))

Режим выполнения

execute_code имеет два режима выполнения, управляемых code_execution.mode в ~/.hermes/config.yaml:

Режим Рабочий каталог Интерпретатор Python
проект (по умолчанию) Рабочий каталог сеанса (тот же, что и terminal()) Активный VIRTUAL_ENV / CONDA_PREFIX Python, с откатом к собственному Python Hermes
строгий Временный промежуточный каталог, изолированный от пользователя проекта sys.executable (собственный Python Hermes)

Когда остаемся project: вы хотите, чтобы import pandas, from my_project import foo или соответствующие пути, такие как open(".env"), работают так же, как в terminal(). Это почти всегда то, что нужно.

При переключении на «строгое»: вам нужна максимальная воспроизводимость — вам нужен один и тот же интерпретатор в каждом сеансе, независимо от того, какую виртуальную среду активировал пользователь, и вы хотите, чтобы скрипты были изолированы от дерева проекта (нет риска случайного чтения файлов проекта через относительный путь).

# ~/.hermes/config.yaml
code_execution:
  mode: project   # или "strict"

Поведение отката в режиме project: если VIRTUAL_ENV / CONDA_PREFIX не установлен, сломан или указан на Python старше 3.8, резолвер чисто откатывается к sys.executable — он никогда не оставляет агента без работающего интерпретатора.

Критические для безопасности инварианты происходят в обоих режимах:

Смена режима меняется, где выполняются скрипты, и какой интерпретатор их запускает, при этом нет каких-либо учетных данных, которые они могут видеть, или каких-либо инструментов управления.

Ограничения ресурсов

Ресурс Лимит Примечания
Тайм-аут 5 минут (300 с) Скрипт завершается SIGTERM, затем SIGKILL через 5 с льготным периодом
Стандартный 50 КБ Вывод усекается с).м [вывод обрезан до 50 КБ]
Стдерр 10 КБ Включается в вывод при ненулевом коде вывода для отладки
Вызовы инструменты 50 на выполнение Ошибка возврата при получении лимита

Все лимиты настраиваются через config.yaml:

# В ~/.hermes/config.yaml
code_execution:
  mode: project      # project (по умолчанию) | strict
  timeout: 300       # Макс. секунд на скрипт (по умолчанию: 300)
  max_tool_calls: 50 # Макс. вызовов инструментов на выполнение (по умолчанию: 50)

Как работают вызовы инструментов внутри скриптов

Когда ваш скрипт вызывает функцию, например web_search("query"):

  1. Вызов сериализуется в формате JSON и продается через сокет Unix-домена родительскому процессу.
  2. Родительский процесс диспетчеризуется через стандартный обработчик handle_function_call.
  3. Результат отправляется обратно через сокет.
  4. функция возвращает разобранный результат

Это означает, что инструменты вызовов внутри скриптов ведут себя идентично обычным инструментам вызова — те же ограничения скорости, те же ошибки обработки, те же самые возможности. Единственное ограничение: terminal() работает только на переднем плане (без параметров background или pty).

Обработка ошибок

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

Ответ всегда включает status (успех/ошибка/тайм-аут/прервано), output,tool_calls_made и duration_секунды.

Безопасность:::опасность Модель безопасности

Дочерний результат процесса с минимальным окружением. Ключи API, токены и учетные данные удаляются по умолчанию. Скрипт получает доступ к инструментам исключительно через RPC-канал — он не может читать секреты из окружения протокола, если это явно не разрешено.

Переменные окружения, содержащие KEY, TOKEN, SECRET, PASSWORD, CREDENTIAL, PASSWD или AUTH в своих именах, проверяются. Передаются только системные переменные (PATH, HOME, LANG, SHELL, PYTHONPATH, VIRTUAL_ENV и т.д.).

Проброс приложений окружения

Когда навык объявляет required_environment_variables во вступительной части, эти переменные автоматически передаются как в дочерних процессах execute_code, так и terminal после загрузки навыка. Это позволяет навыкам использовать свои объявленные API-ключи без ослабления безопасности для альтернативного кода.

В случаях, когда нет границ с навыками, вы можете явно разрешить переменные в config.yaml:

terminal:
  env_passthrough:
    - MY_CUSTOM_KEY
    - ANOTHER_TOKEN

См. Руководство по безопасности для полной информации.

Hermes всегда записывает скрипт и автоматически сгенерированную RPC-заглушку hermes_tools.py во временный промежуточный каталог, который очищается после выполнения. В режиме strict скрипт также работает там; в режиме «project» он достигает результатов в сеансе рабочего каталога (промежуточный каталог остается в «PYTHONPATH», поэтому импорт все еще работает). Дочерний процесс прогрессирует в своей группе процессов, чтобы его можно было выполнить чисто по тайм-ауту или прерыванию.

execute_code против терминала

Сценарий код_выполнения терминал
Многошаговые рабочие процессы с вызовами инструментов между шагами
Простая команда обработки
Фильтрация/обработка инструментов для больших выводов
Запуск сборки или набор тестов
Циклы по результатам поиска
Интерактивные/фоновые процессы
Требуются API-ключи в разработке ⚠️ Только через проброс ✅ (большинство предметов)

Эмпирическое правило: Используйте execute_code, когда необходимо программно переключать инструменты Hermes с логикой между вызовами. Используйте «терминал» для запуска команды обработки, сборки и процессов.

Платформа поддержки

Выполнение кода требует сокетов домена Unix и доступно только на Linux и macOS. Оно автоматически отключается в Windows — агент возвращается к аналогичным последовательным вызовам инструментов.