跳到主要内容
AI教程

使用 HEXIS 将可靠的智能体技能编译为状态机

了解如何安装 HEXIS,将智能体技能编译为扩展有限状态机,根据执行轨迹更新状态机,并通过 CLI 或 Python API 运行。本教程还将介绍状态机概念、验证、工具后端、生成式指南、回退行为以及实用的安全注意事项。

使用 HEXIS 将可靠的智能体技能编译为状态机

什么是 HEXIS?

HEXIS 是一个 Python 软件包和命令行工具,可将由 SKILL.md 文档表示的代理技能编译为扩展有限状态机。HEXIS 不要求语言模型解释整个技能并选择每一个后续步骤,而是使用程序化状态、变量、守卫条件和转换来强制执行操作顺序。

语言模型仍会在相关状态中执行推理和生成。不过,状态机决定下一步运行哪项操作、哪些变量可用、循环何时必须停止,以及最终到达哪个终止结果。这种设计降低了代理跳过、重新排序或错误应用技能中所写要求的风险。

HEXIS 代理技能编译工作流

HEXIS 采用 MIT 许可证发布,目前标记为 alpha 版本软件。它与论文 Compiling Agent Skills into Extended Finite State Machines 配套发布。

核心工作流

典型的 HEXIS 工作流包含三个阶段:

  1. 编译:模型读取技能文档、任务输入、工具定义和技能规则,然后起草一个 efsm-v1 状态机。HEXIS 会检查其架构、守卫条件、可达性、终止性、条款覆盖情况和工具引用。无效草案会返回给模型进行修订。
  2. 更新:新的执行轨迹会被规范化为事件。对于轨迹中的每一步,模型、决策文件或确定性对齐器会决定是匹配现有状态、创建状态、忽略噪声,还是排除该轨迹。
  3. 执行:运行时执行与当前状态关联的操作,记录声明的输出,并选择第一个守卫条件计算结果为真的转换。

只有通过所需检查,并且能够重放新轨迹及所有此前已接受轨迹的更新后状态机,才会被接受。如果验证失败,现有状态机保持不变。

主要功能

  • 兼容 OpenAI 的编译:可通过命令行选择模型、端点和 API 密钥环境变量。
  • 基于轨迹的更新:一次纳入一个决策的成功执行行为,同时不使此前已接受的轨迹失效。
  • 可读的 JSON 状态机:状态机采用纯 JSON 的 efsm-v1 格式,并包含类型化变量和显式转换。
  • 多种操作类型:状态可以执行 tool、model、judge、user 或 end 操作。
  • 有界控制流:有序守卫条件和循环计数器支持分支及重试次数限制。
  • 生成文档:每次正常构建都会包含 GUIDE.md 和 PROMPT.md。
  • 回退行为:回退状态会从最近的工具步骤重试,也可以将任务交给原始技能的解释执行。
  • 工具后端:状态机可以使用 OpenCode 工具、本地 Bash 执行器,或由模型实现的注册表定义工具。
  • 纯环境测试:仓库包含超过 350 个测试,不需要 API 密钥、模型端点或网络连接。

安装和前置条件

从 PyPI 安装

HEXIS 要求 Python 3.11 或 3.12。使用 pip 安装软件包:

pip install hexis-agent

在 Python 中导入该软件包时使用 hexis,而其命令行可执行文件名为 hexis-agent。

从代码检出目录安装

pip install .

如需 pytest、Ruff、build 和 Twine 等开发依赖,请使用可编辑安装:

pip install -e ".[dev]"

运行时要求

编译和运行由模型支持的状态机需要兼容 OpenAI 的聊天端点。默认执行后端还要求 OpenCode 位于 PATH 中。如果状态机只需要 Bash,请选择 --executor local,在本地子进程中运行命令而无需 OpenCode。

尝试离线快速开始

软件包包含一个名为 table_clean 的小型纯环境示例。它使用脚本化模型、脚本化工具和内存文件系统,因此无需网络访问即可运行。

from hexis.execution import runtime
from hexis.examples import table_clean as tc

machine = tc.reference_machine()
task = tc.gen_tasks(1, seed=0)[0]

result = runtime.run_task(
    machine,
    task,
    model=tc.build_model(),
    tools=tc.build_registry(tc.MemFS(task["files"])),
    doc=tc.skill_doc(),
)

print(
    result.stopped,
    " -> ".join(result.path()),
    tc.verify(task, result.trace),
)

该示例应以终止结果结束,打印状态路径,并报告生成的轨迹是否通过示例验证器。这是在配置外部端点之前确认安装成功的实用方法。

配置模型端点

HEXIS 从命令行选项或环境变量中读取模型标识符、基础 URL 和 API 密钥。基本的 shell 配置如下:

export API_KEY=your-key
export MODEL=qwen3.6-flash
export BASE_URL=https://your-endpoint/v1

你也可以将 MODEL、BASE_URL 和 API_KEY 放入 .env 文件。HEXIS 会从工作目录开始向上查找,环境中已存在的变量优先级更高。

如需将可复用的端点参数保存在 shell 变量中:

M="--model qwen3.6-flash --base-url https://your-endpoint/v1"

--api-key-env NAME 选项用于为密钥指定其他环境变量。API 密钥不会通过命令行传递,也不会存储在构建清单中。

将技能编译为机器

将编译器指向技能路径,并选择输出目录:

hexis-agent compile \
  --skill path/to/skill \
  --out build/ \
  $M

技能目录应包含 SKILL.md。它还可以包含 compile.json,用于声明终端、派生事件标签、要求和终端条件。该文件中的每条规则都会引用其派生所依据的句子。

如果不存在 compile.json,编译器会要求模型从技能中提取规则,并根据文档检查引用的文本。随后,有效配置会保存为 rules.json。

构建目录包含的内容

  • machine.json 存储当前机器。
  • machine_init.json 保存初始编译机器。
  • build.json 记录源信息、命令设置、模型详情、结果和令牌使用情况,但绝不会记录 API 密钥。
  • skill/SKILL.md、tools.json 和 rules.json 保存编译输入。
  • traces/ 包含构建所用轨迹的哈希副本。
  • progress.json 记录轨迹结果以及保护机器的已接受轨迹。
  • decisions.jsonl 缓存更新问题及其答案。
  • report.md、context.json 和日志文件提供诊断信息。
  • GUIDE.md 说明输入、工具、状态、转换、循环和回退行为。
  • PROMPT.md 为使用工具的代理提供系统提示,使其能够逐状态执行机器。

理解机器模型

HEXIS 机器是使用 efsm-v1 格式的 JSON 文档。其主要元素包括变量、状态、动作、转换、终端和回退状态。

变量

变量可以通过 init_from 从任务输入字段初始化,也可以通过 init 从常量值初始化。动作只能将结果写入已声明的变量。

动作

  • 模型:根据特定状态的提示和选定的输入变量生成已声明的变量。
  • 工具:调用命名工具。运行时会替换 ${command} 等引用。
  • 判定器:从固定集合中选择一个标签,或返回 abstain 标签。
  • 用户:请求用户输入。
  • 结束:以终端结果停止执行。

转换和守卫条件

状态动作完成后,系统会按顺序评估转换。运行时会采用第一个守卫条件成立的转换。空守卫条件表示无条件转换,应放在最后。转换还可以通过 inc 增加计数器,从而实现有界重试循环。

守卫条件使用由 hexis.machine.cond 实现的受限表达式语言。它支持对互斥性和循环边界等属性进行静态分析,并且不会使用 Python 的 eval。

根据轨迹更新机器

执行轨迹是 JSON Lines 文件。它们以任务元数据和判定结果开头,后面每行包含一个事件。轨迹可以包含工具调用、模型输出和结束事件。

首先预览待处理轨迹,不进行模型调用,也不写入更改:

hexis-agent update \
  --build build/ \
  --traces traces/ \
  --show 3

然后执行更新:

hexis-agent update \
  --build build/ \
  --traces traces/ \
  $M

对于每个轨迹步骤,判定器会选择以下四种结果之一:

  • match 复用现有状态,并在必要时添加转换。
  • new 根据所述目的创建状态。
  • ignore 将测试框架噪声排除在考虑范围之外。
  • exclude 排除整个轨迹。

模型的回答还会标识候选状态,描述该步骤的目的,并可将其关联到某条技能条款。HEXIS 会验证生成的候选机器,并在接受之前重放所有受保护轨迹。

恢复并控制更新成本

模型回答会缓存到 decisions.jsonl 中。重复执行相同命令会复用这些回答;退出状态为 3 的中断运行可以从已保存的进度恢复。只有在明确希望模型重新回答时,才使用 --no-cache。

一次更新通常每个轨迹步骤需要调用模型一次。使用 --max-traces N 限制运行范围。若要使用无模型替代方案,可以通过 --decisions FILE 提供人工或外部决策,或者使用 --decider align 选择确定性对齐。

在处理新轨迹之前,HEXIS 会检查当前机器并重放每条已接受的轨迹。如果手动编辑或工具定义发生变化导致构建损坏,命令会以状态 2 退出,且不会修改构建。

运行已编译的机器

执行前请检查 build/GUIDE.md。其中记录了所需的任务输入、可用工具、状态动作、转换顺序、重试限制和回退行为。

使用键值形式的任务输入运行机器:

hexis-agent run \
  --machine build/ \
  --input request="Process this task" \
  --workdir work/ \
  --executor local \
  $M

为机器所需的每个输入传递额外的 --input KEY=VALUE 选项。要将执行结果保存为可重复使用的 JSON Lines 跟踪记录,请添加:

--json run-trace.jsonl

默认执行器使用 OpenCode 工具。本地执行器会在子进程中运行 Bash 命令。在运行时,机器只能使用其后端提供的工具或工具注册表中定义的工具;HEXIS 不会静默替换缺失的工具。

从 Python 使用机器

核心运行时入口是 hexis.execution.runtime.run_task。请提供一个已加载的机器、包含 input 对象的任务、模型适配器、工具注册表,以及在回退执行可能需要时使用的技能文档。

from hexis.execution import runtime

result = runtime.run_task(
    machine,
    {"input": {
        "request": "Answer the question",
        "output_path": "answer.txt",
    }},
    model=model,
    tools=tools,
    doc=skill_document,
)

print(result.stopped)
print(result.path())
print(result.trace)

相关 API 包括用于加载机器的 hexis.machine.schema.load_machine、用于配置端点的 hexis.llm.llm_client.client_from_env,以及用于渲染指南、提示词和 Mermaid 图表的 hexis.guide 函数。

使用随附的示例机器

仓库在 examples/machines/ 下包含四个已编译的机器:

  • dabench: 使用计算结果回答关于数据文件的数据分析问题。
  • livemath: 回答基于定理的数学选择题。
  • sealqa: 从本地语料库中回答问题,并提供证据。
  • spreadsheet: 编辑工作簿,同时不改变其结构。

这些机器通常使用模型状态编写 shell 命令,使用工具状态执行命令,根据 returncode 进行受保护的重试,使用工具步骤读回答案,再由判断状态选择已验证或未验证的终端状态。

例如,使用以下命令运行 LiveMath 机器:

hexis-agent run \
  --machine examples/machines/livemath \
  --input request="..." \
  --input output_path=answer.txt \
  --workdir work/ \
  --executor local \
  $M

无需模型即可加载并进行结构检查示例机器,但运行它们需要配置模型端点。

高级提示

重新生成文档

除非使用 --no-guide,否则编译和更新操作会自动生成文档。使用以下命令手动重新生成:

hexis-agent guide --build build/

也可以直接将命令指向 machine.json。如果希望生成的代理提示词包含原始技能,请添加 --embed-skill,这样回退后即可进行解释执行。

提供显式工具定义

当机器使用自定义工具时,传递 --tools registry.json。编译期间,工具名称会被视为不透明标识符。在运行时,注册表定义的工具可以由模型实现为 shell 命令,而原生工具必须由所选后端提供。

调整模型请求

编译和更新支持包括 --temperature、--max-tokens、--llm-timeout、--llm-retries、--stream 和 --extra-body JSON 在内的选项。对于兼容 Qwen 的端点,可以使用 --no-think、--think-budget 和 --judge-think-budget 控制运行时推理。

使用提供商专用的环境变量

--provider NAME 选项会读取 NAME_MODEL、NAME_BASE_URL 和 NAME_API_KEY。MiniMax 和 DeepSeek 提供商名称有内置默认值。

了解退出状态

  • 0 表示成功。
  • 2 表示使用、配置或构建问题。
  • 3 表示模型端点故障或中断;进度会保存以便恢复。

运行开发检查

pytest
ruff check src tests
python -m build && twine check --strict dist/*

测试套件是自包含的。当 opencode 可执行文件不可用时,特定于 OpenCode 的测试会被跳过。

安全与隐私

HEXIS 可以执行由语言模型生成的工具参数,包括 shell 命令。请在隔离环境中运行不受信任的工作负载,并且只使用你信任的机器、技能、注册表和任务文件。

更新过程会将跟踪步骤、缩短后的工具结果和技能条款发送到配置的模型端点。构建目录会保留跟踪副本和模型问题。此外,PROMPT.md 包含完整的机器以及根据技能生成的提示词。分享这些文件前请先进行检查。

运行时会将每次模型调用限制在当前执行状态的提示词范围内,而不是让每次调用都暴露整个机器。

结语

HEXIS 将自然语言代理指令转化为明确且经过验证的工作流。通过在状态中结合模型推理与程序化转换、跟踪重放、有界重试、工具限制、生成式指南和回退处理,它提供了一种让技能执行更加可预测的结构化方式。请从离线示例开始,编译一个小型且可信的技能,检查生成的指南,然后逐步引入跟踪记录,同时监控验证结果。