跳到主要内容

代码执行(程序化工具调用)

execute_code 工具允许代理编写调用 Hermes 工具的 Python 脚本,将多步骤工作流压缩为单次 LLM 调用。脚本在代理主机上的沙箱子进程中运行,通过 Unix 域套接字 RPC 进行通信。

工作原理

  1. 代理编写使用 from hermes_tools import ... 的 Python 脚本
  2. Hermes 生成一个包含 RPC 函数的 hermes_tools.py 模块存根
  3. Hermes 打开一个 Unix 域套接字并启动 RPC 监听线程
  4. 脚本在子进程中运行 —— 工具调用通过套接字返回到 Hermes
  5. 只有脚本的 print() 输出会被返回给 LLM;中间工具结果永远不会进入上下文窗口
# The agent can write scripts like:
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"]])
# ... filter and process ...
print(summary)

沙箱中可用的工具: web_searchweb_extractread_filewrite_filesearch_filespatchterminal(仅前台模式)。

代理使用此功能的场景

当存在以下情况时,代理会使用 execute_code

  • 3 次及以上工具调用,且调用之间有处理逻辑
  • 大批量数据过滤或条件分支
  • 对结果进行循环处理

主要优势:中间工具结果不会进入上下文窗口 —— 只有最终的 print() 输出返回,显著降低 token 使用量。

实用示例

数据处理流水线

from hermes_tools import search_files, read_file
import json

# Find all config files and extract database settings
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

# Search, extract, and summarize in one turn
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

# Find all Python files using deprecated API and fix them
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

# Run tests, parse results, and report
result = terminal("cd /project && python -m pytest --tb=short -q 2>&1", timeout=120)
output = result.get("output", "")

# Parse test 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))

资源限制

资源限制说明
超时时间5 分钟(300 秒)脚本被发送 SIGTERM,5 秒宽限期后发送 SIGKILL
标准输出50 KB输出截断并附带 [output truncated at 50KB] 提示
标准错误10 KB非零退出时包含在输出中,用于调试
工具调用次数每次执行最多 50 次达到限制时返回错误

所有限制均可通过 config.yaml 配置:

# In ~/.hermes/config.yaml
code_execution:
timeout: 300 # Max seconds per script (default: 300)
max_tool_calls: 50 # Max tool calls per execution (default: 50)

脚本内工具调用的工作机制

当你的脚本调用如 web_search("query") 的函数时:

  1. 调用被序列化为 JSON,并通过 Unix 域套接字发送到父进程
  2. 父进程通过标准的 handle_function_call 处理器进行分发
  3. 结果通过套接字返回
  4. 函数返回解析后的结果

这意味着脚本内的工具调用行为与普通工具调用完全一致 —— 相同的速率限制、相同的错误处理、相同的功能。唯一限制是 terminal() 仅支持前台模式(不支持 backgroundptycheck_interval 参数)。

错误处理

当脚本失败时,代理会收到结构化的错误信息:

  • 非零退出码:stderr 包含在输出中,代理可查看完整堆栈跟踪
  • 超时:脚本被终止,代理看到 "Script timed out after 300s and was killed."
  • 中断:若用户在执行期间发送新消息,脚本被终止,代理看到 [execution interrupted — user sent a new message]
  • 工具调用次数上限:达到 50 次调用限制后,后续工具调用返回错误消息

响应始终包含 status(success/error/timeout/interrupted)、outputtool_calls_madeduration_seconds

安全性

安全模型

子进程以最小环境运行。API 密钥、令牌和凭证默认被移除。脚本仅能通过 RPC 通道访问工具 —— 除非显式允许,否则无法从环境变量读取密钥。

名称中包含 KEYTOKENSECRETPASSWORDCREDENTIALPASSWDAUTH 的环境变量将被排除。仅安全的系统变量(如 PATHHOMELANGSHELLPYTHONPATHVIRTUAL_ENV 等)会被传递。

技能环境变量透传

当某个技能在其 frontmatter 中声明 required_environment_variables 时,这些变量在技能加载后自动透传execute_codeterminal 沙箱。这使得技能可以使用其声明的 API 密钥,同时不削弱对任意代码的安全防护。

对于非技能使用场景,你可以在 config.yaml 中显式白名单变量:

terminal:
env_passthrough:
- MY_CUSTOM_KEY
- ANOTHER_TOKEN

完整详情请参见 安全指南

脚本在临时目录中运行,执行后自动清理。子进程运行在独立的进程组中,可在超时或中断时被干净地终止。

execute_code 与 terminal 对比

使用场景execute_codeterminal
包含工具调用的多步骤工作流
简单的 shell 命令
大量工具输出的过滤/处理
运行构建或测试套件
循环处理搜索结果
交互式/后台进程
需要环境变量中的 API 密钥⚠️ 仅通过 透传✅(大多数情况可透传)

经验法则: 当您需要在调用 Hermes 工具时加入逻辑控制,以程序化方式执行代码时,请使用 execute_code。当您需要运行 shell 命令、构建项目或处理进程时,请使用 terminal

平台支持

代码执行需要 Unix 域套接字,仅在 Linux 和 macOS 上可用。在 Windows 上会自动禁用该功能——代理将回退到常规的顺序工具调用。