Agent工坊

【Agent工坊】Statewright 实战:用状态机让 AI Agent 从"随缘输出"到"零失误",本地小模型也能跑 SWE-bench

给 Agent 40+ 工具和开放式任务,它会把同一个文件读五遍、在 Review 阶段调用 Edit、测试没跑完就部署。Statewright 的解法不是换更大的模型,而是用 Rust 状态引擎把问题空间切小——每个阶段只给 5 个工具,拒绝就告诉你该怎么做。研究数据:两个本地小模型从 2/10 正确率干到 10/10。

前言

你和我都有过这种经历:让 Claude Code 修一个 bug,它反复读同一个文件四遍,每次都在"理解代码"和"动手修改"之间来回横跳。你看着 token 燃烧器疯狂运转,心里默默计算这轮对话的花费。

这不是 prompt 写得不好,是架构问题。

一个拥有 40+ 工具、无约束状态的 Agent,本质上是一个在巨大搜索空间里随机游走的对话模型。它不是在"思考",而是在"试"。试错了就回退,回退了再试——直到 token 用完或你手动喊停。

Statewright 的解法简单到令人意外:不要给 Agent 所有工具,只给当前阶段需要的工具。 用确定性的 Rust 状态引擎在 MCP 层面拦截工具调用,这个引擎不依赖任何 LLM——它只做一件事:检查当前状态允许哪些工具,不允许的直接拒绝并告诉你该怎么过渡到下一阶段。

这篇文章带你从零上手 Statewright:安装、配置工作流、理解核心 guardrail 机制、自建自定义工作流,最后上自托管。

背景:为什么 Agent 需要状态机

问题不是模型能力,是搜索空间

当前主流的 AI 编程 Agent——Claude Code、Codex、Cursor——都有一个共同的架构假设:给模型全部工具,让它自己决定什么时候用什么。 这在简单任务上(改一行代码、加一个函数)效果很好,但一旦任务变复杂(修 bug 需要先定位 → 再改 → 再测试 → 可能回退再改),Agent 就会陷入"工具选择瘫痪"。

具体表现:

  • Read-loop death spiral:反复读同一组文件,每次都说"我理解了",然后继续读
  • 跨阶段工具乱用:在 Review 阶段用 Edit 改代码,在 Testing 阶段用 Write 覆盖测试
  • 跳过关键步骤:测试没跑完就标记完成,部署前不检查 lint

更深层的问题是:Agent 没有"阶段"概念。 它只看到一长串对话历史和 40 个工具,无法区分"现在在读代码"和"现在在改代码"应该用不同的工具集和行为约束。

解决方案:确定性的状态约束

Statewright 的核心洞察是:用确定性的代码(而非 LLM prompt)来定义 Agent 的行为边界。

传统做法——在 system prompt 里写"不要在 review 阶段编辑文件"——是软约束,模型可以忽略。Statewright 的做法是硬约束:在 MCP hook 层面拦截工具调用,如果当前状态不允许 Edit,直接返回错误并告诉 Agent 如何过渡。

这相当于给 Agent 装了一个"行为护栏",而不是"行为建议"。护栏是代码,建议是文字——前者一定生效,后者不一定。

Statewright 核心机制拆解

Statewright 插图1

▲ 图1:Statewright 状态机工作流 — planning(只读)→ implementing(编辑)→ testing(测试),每阶段只有3-5个工具,测试失败自动回退到 implementing

1. 状态机定义(Rust 引擎,无 LLM 参与)

Statewright 的核心是一个纯 Rust 实现的状态引擎。它读入一个 JSON 格式的工作流定义,在 Agent 每次工具调用时检查:

当前状态是什么?

  → 这个工具在 allowed_tools 里吗?

    → 是 → 放行

    → 否 → 拒绝,返回:允许的工具列表 + 如何过渡到下一个状态

关键是最后一步:拒绝不只是说"No",而是告诉 Agent "如果你想用 Edit,需要先过渡到 implementing 状态,触发条件是 READY"。 这比简单的工具拦截要多一层引导。

引擎完全确定性——同一个状态定义、同一个输入,永远得到同一个输出。不依赖任何 LLM 推理。

2. 十层 Guardrail(从工具拦截到环境隔离)

Statewright 提供了 10 层 guardrail,不是让你全部开启,而是按需组合:

Guardrail作用典型场景
Per-state tool enforcement每个状态只暴露允许的工具planning 阶段只有 Read/Grep/Glob
Bash discernment即使 Bash 被允许,也拦截 echo > filerm -rfsed -i、脚本解释器防止"允许跑测试"变成"允许删代码"
Edit guards限制单次 diff 行数、单状态编辑文件数防止 Agent 一次改太多导致回滚困难
Command allow-listsBash 只能跑指定前缀的命令testing 阶段只允许 pytestcargo test
Conditional transitions基于上下文数据判断是否过渡test_result eq pass 才允许从 testing 到 completed
Approval gates某些过渡需要人工确认部署前暂停,等人点"批准"
Interrupts编辑匹配 glob 模式的文件时自动跳转到验证状态改了 .env 立即触发安全检查
Fork/join并行或串行分支,全部完成或任一完成时汇合同时跑单元测试和集成测试
Environment scoping隐藏敏感环境变量,替换为安全值隐藏 PROD_DB_URL,Agent 只能看到 staging URL
Session isolation按 session ID 隔离状态多窗口同时工作互不干扰

3. 工作流定义(JSON,Agent 可自动生成)

工作流用 JSON 定义,结构清晰:

{

  "id": "bugfix",

  "initial": "planning",

  "states": {

    "planning": {

      "allowed_tools": ["Read", "Grep", "Glob"],

      "max_iterations": 8,

      "on": { "READY": "implementing" }

    },

    "implementing": {

      "allowed_tools": ["Read", "Edit", "Write"],

      "max_edit_lines": 20,

      "max_files_per_state": 3,

      "on": { "DONE": "testing" }

    },

    "testing": {

      "allowed_tools": ["Read", "Bash"],

      "allowed_commands": ["pytest", "cargo test", "npm test"],

      "on": {

        "PASS": { "target": "completed", "guard": "tests_passed" },

        "FAIL_TEST": "implementing"

      }

    },

    "completed": { "type": "final" }

  },

  "guards": {

    "tests_passed": { "field": "test_result", "op": "eq", "value": "pass" }

  }

}

这个工作流定义了经典的"修 bug"三阶段:

  1. planning:只能读代码(Read/Grep/Glob),最多迭代 8 次,触发 READY 后进入 implementing
  2. implementing:可以读+编辑(Read/Edit/Write),每次最多改 20 行,每个文件最多改 3 次,完成后进入 testing
  3. testing:只能读+跑测试(Read + 指定测试命令),测试通过则完成,失败则回到 implementing

Workflow 不需要手写——你可以让 Agent 通过 statewright_create_workflow MCP 工具自动生成。扔给它一个任务描述,它会输出完整的 JSON 定义。

上手指南:15 分钟从零到跑通

第一步:安装插件

在 Claude Code 中:

/plugin marketplace add statewright/statewright

/plugin install statewright

浏览器会自动打开 statewright.ai,注册账号 → 生成 API Key → 粘贴回终端 → 完成。

支持的 Agent 及集成方式

Agent集成方式约束类型
Claude CodeHooks + MCP硬约束(工具级拦截)
CodexHooks + MCP硬约束
opencodeTypeScript 插件硬约束(alpha)
PiTypeScript 扩展硬约束(含本地模型优化)
CursorMCP + rules建议约束(MCP 无法拦截 Cursor 原生工具)

注意:Cursor 的 MCP 集成只能注入规则到上下文,无法在工具层拦截——模型可以忽略。如果你用 Cursor 做核心开发,建议搭配 Claude Code 或 Codex 在关键流程中启用硬约束。

第二步:启动第一个工作流

❯ start the bugfix workflow — fix the failing tests in calc.py

◆ statewright — statewright_start (workflow: bugfix)

◆ [statewright] Workflow activated: bugfix

◆ Current phase: planning. Let me read the code first.

  Read 2 files

  [statewright] planning => implementing

◆ Edit calc.py: 1 line changed

  [statewright] implementing => testing

◆ Bash: pytest -x — 7 passed

  [statewright] testing => completed

◆ [statewright] Workflow complete. 46 seconds.

注意三个关键行为:

  1. 每个阶段开始时,Agent 只能看到当前阶段允许的工具(planning 阶段没有 Edit 和 Bash)
  2. 阶段过渡是 Agent 主动触发的(通过 statewright_transition),不是计时器或外部条件
  3. 过渡时引擎检查 guard 条件,不满足则拒绝过渡

第三步:创建自定义工作流

让 Agent 帮你生成工作流:

Create a workflow for deploying a Python package to PyPI.

Steps: lint → test → build → publish.

lint should allow Read and Bash (only ruff/flake8).

test should allow Read and Bash (only pytest).

build should allow Read, Write, Bash (python -m build).

publish should allow Bash (twine upload) with approval gate.

Agent 会调用 statewright_create_workflow 生成完整 JSON,你可以在 statewright.ai/workflows 的可视化编辑器中微调工具列表、命令白名单和环境变量。

第四步:接入你的项目 CI

把 Statewright 工作流嵌入 CI pipeline:

# .github/workflows/agent-review.yml

name: Agent Code Review

on:

  pull_request:

    types: [opened, synchronize]

jobs:

  review:

    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v4

      - name: Run Statewright review workflow

        run: |

          claude --print "start the code-review workflow for PR #${{ github.event.pull_request.number }}"

这里的关键是:代码审查不再依赖"希望 Agent 按要求做",而是用状态机强制它按阶段执行——先 read-only 分析,再逐文件给出建议,最后输出 review 报告。Agent 不能在分析阶段就修改代码。

研究数据:小模型从 2/10 到 10/10 的秘密

Statewright 插图2

▲ 图2:有无状态约束的对比 — 同样模型、同样硬件、同样任务,加状态约束后从20%正确率提升到100%

Statewright 团队在一个 5 任务 SWE-bench 子集上跑了实验,结果令人印象深刻:

模型大小Bug Fix(26行修改)SWE-bench(5任务)
gemma33.3GB❌ 失败❌ 失败
gemma4:e2b7.2GB✅ 通过*❌ 失败
gpt-oss:20b13.8GB✅ 通过✅ 通过(5/5)
gemma4:31b19.9GB✅ 通过✅ 通过(5/5)
llama3.342.5GB✅ 通过✅ 通过(2/2)†

* 需要专门的 edit_line 工具适配。† 仅测试了 5 个任务中的 2 个。

关键发现:

  • 13GB 是分水岭。低于这个阈值的模型能识别 bug 但无法生成精确的编辑(倾向于重写整个文件)。这是模型能力限制,不是 Statewright 的问题。
  • 两个本地模型(gpt-oss:20b 和 gemma4:31b)开 Statewright 后从 2/10 passing 升到 10/10。同样任务、同样硬件,加了状态约束后正确率从 20% 飙到 100%。
  • 大模型的收益在"结构"层面:即使你用 Claude 4 级别的模型,状态机也能打破 read-loop death spiral,把工具空间缩小到模型能专注推理而非到处试探的程度。

这个结果对 AI 创业者意味着什么?你不需要接入最贵的 API 来获得可靠的 Agent 行为。 用本地小模型 + 正确的状态约束,可以在成本极低的情况下跑通核心工作流。这对一人公司的经济模型意义重大。

自托管方案:不用云服务也能跑

Statewright 插图3

▲ 图3:Statewright 自托管架构 — Agent 通过 MCP Gateway(Rust 引擎)连接到 PocketBase + Workflow Editor + Docker Compose,全部 Apache 2.0 许可

Statewright 提供了完整的 Docker Compose 自托管方案:

cd self-hosted && docker compose up --build

这个命令会启动三个容器:

  • PocketBase:工作流存储和运行历史
  • MCP Gateway:工具拦截层,所有 Agent 的工具调用经过这里
  • Workflow Editor:可视化编辑器(和云版一样)

核心引擎(crates/engine)和 Agent 层(crates/agent)是 Apache 2.0 许可,可嵌入无运行时依赖。MCP Gateway 是 FSL-1.1-ALv2(2029 年转为 Apache 2.0)。个人开发者和单团队自托管在 FSL 许可下完全免费。

云版定价(statewright.ai):

方案工作流数月过渡次数运行历史价格
Free320072小时$0
Pro102,5007天$29/月
Team3010,00090天$99/月

对于个人 AI 创业者,Free 方案足够日常使用。如果你的 Agent 调用频繁(每天超过 6-7 次过渡),建议上 Pro 或自托管。

边界与注意事项

  1. 需要 Agent 支持 MCP 或 Hooks。如果用的是不支持 MCP 的轻量 Agent,Statewright 无法在工具层拦截。好消息是 Claude Code、Codex、opencode 都原生支持。
  2. 工作流太紧会导致 Agent 卡住。如果你的 max_iterations 设太小或 allowed_tools 太窄,Agent 可能在一个状态下反复尝试但无法完成任务。statewright_deactivate 是逃生舱——随时可以关闭工作流回到自由模式。
  3. Cursor 只有建议约束。因为 Cursor 的架构限制,MCP 无法拦截它的原生工具调用。如果你用 Cursor,Statewright 可以把规则注入上下文但模型可能忽略。
  4. 研究结果来自 5 任务子集,不是完整的 2294 实例 SWE-bench。但这个子集覆盖了典型的修 bug 场景(定位 → 修改 → 验证 → 可能回退),对日常开发有代表意义。
  5. Bash discernment 不等于沙箱。它拦截了已知危险模式(rm -rfecho > filesed -i),但不能替代完整的容器隔离。生产环境建议在 Docker 容器内运行 Agent + Statewright。

实战建议:按场景配置工作流

场景一:日常 Bug 修复(个人开发)

{

  "states": {

    "planning": {"allowed_tools": ["Read", "Grep"], "max_iterations": 5},

    "implementing": {"allowed_tools": ["Read", "Edit"], "max_edit_lines": 30},

    "testing": {"allowed_commands": ["pytest", "npm test"]}

  }

}

场景二:代码审查(团队使用)

{

  "states": {

    "analysis": {"allowed_tools": ["Read", "Grep", "Glob"]},

    "review": {"allowed_tools": ["Read"], "max_iterations": 10},

    "report": {"allowed_tools": ["Write"], "max_files_per_state": 1}

  }

}

注意:Review 状态只有 Read 工具——Agent 可以阅读代码但不能修改。这确保了审查和分析是分离的。

场景三:生产部署(带审批门禁)

{

  "states": {

    "build": {"allowed_tools": ["Read", "Bash"], "allowed_commands": ["docker build"]},

    "test": {"allowed_tools": ["Read", "Bash"], "allowed_commands": ["docker run", "pytest"]},

    "deploy": {"allowed_tools": ["Bash"], "allowed_commands": ["kubectl apply"],

               "requires_approval": true}

  }

}

`requires_approval: true` 意味着从 test 过渡到 deploy 之前会暂停,等人点确认。这在生产环境中是最基本的保险。

场景四:AI 内容创作(一人公司)

{

  "states": {

    "research": {"allowed_tools": ["web_search", "web_extract"], "max_iterations": 8},

    "outline": {"allowed_tools": ["Read", "Write"], "max_files_per_state": 1},

    "draft": {"allowed_tools": ["Read", "Write", "Edit"], "max_edit_lines": 50},

    "review": {"allowed_tools": ["Read"], "max_iterations": 3},

    "publish": {"allowed_tools": ["Bash"], "allowed_commands": ["python3 scripts/publish"],

                "requires_approval": true}

  }

}

常见问题(FAQ)

Q1:Statewright 和 prompt engineering 有什么区别?

Prompt engineering 是软约束——你在 system prompt 里写"不要做 X",模型可以忽略。Statewright 是硬约束——在 MCP hook 层拦截工具调用,模型根本看不到被禁止的工具。软约束靠运气,硬约束靠确定性代码。

Q2:我的 Agent 没有 MCP 支持,还能用吗?

当前支持的 Agent 列表:Claude Code(Hooks + MCP)、Codex(Hooks + MCP)、opencode(TypeScript 插件)、Pi(TypeScript 扩展)。如果你的 Agent 不在此列但支持任意 Hook 系统,可以提 Feature Request 或参考现有插件自行适配。核心引擎是 Apache 2.0,适配难度不高。

Q3:工作流定义太复杂,我不会写 JSON 怎么办?

你不需要手写 JSON。让 Agent(Claude Code 或 Codex)调用 statewright_create_workflow,用自然语言描述你的工作流,Agent 会输出完整的 JSON。然后到 statewright.ai/workflows 的可视化编辑器中微调。

Q4:状态机会不会限制 Agent 的创造力?

取决于你的场景。修 bug 不需要创造力——需要的是正确性。代码审查需要的是系统性,不是发散思维。在这些场景下,约束不是限制,是保障。如果你需要 Agent 做创造性探索(如架构设计),可以不用状态机,或者在探索阶段用更宽松的工作流(只限制危险操作,不限制读/写工具)。

Q5:自托管和云版的功能差异?

功能上完全一样。云版多了运行历史、团队协作和自动备份(PocketBase 数据库)。自托管需要你自行管理 PocketBase 实例和数据备份。核心引擎和 Agent 层代码完全相同。

总结:Agent 可靠性不是靠更大模型解决的

Statewright 给 AI 创业者的启示很清楚:

  1. Agent 的不可靠不是模型能力问题,是架构问题。 给 40+ 工具无约束地跑,无论多大模型都会 flail。
  2. 确定性的代码约束 > 不确定的 prompt 建议。 状态引擎没有概率,只有 true/false。
  3. 小模型 + 好架构 > 大模型 + 烂架构。 研究数据已经证明了这一点——13GB 本地模型开状态机后跑通 SWE-bench,成本是 Claude API 的零头。
  4. 硬约束在 MCP/hook 层实现,不是 prompt 层。 这是 Statewright 和其他"Agent 护栏"方案的本质区别。

对于正在搭 Agent 工作流的一人公司创业者,Statewright 值得立刻加入你的工具栈。从 Free 方案开始,用一个 bugfix 工作流跑两周,你会发现 Agent 的行为从"需要盯着"变成"可以信任"——这种信任感,是 AI Agent 从实验品变成生产力工具的关键一步。


风险提示:Statewright 仍处于早期阶段(2026 年 5 月首次公开发布),API 和插件接口可能变动。生产环境使用前建议在 staging 环境充分测试。自托管需要 Docker 环境和基本的运维能力。研究数据来自受限测试集,实际项目效果以你的实际使用为准。


参考来源

  • Statewright GitHub 仓库(github.com/statewright/statewright)
  • Statewright 官方文档(docs.statewright.ai)
  • HN 讨论:Show HN: Statewright – Visual state machines that make AI agents reliable(126 points,2026-05-12)
  • Statewright 研究简报(statewright.ai/research)
  • HN 评论区多位开发者的实战反馈

本文由AI辅助创作,经人工审核编辑发布