OpenEnv

框架

huggingface/OpenEnv

用于强化学习训练的智能体执行环境框架。

项目简介

OpenEnv 通过类似 Gymnasium 的 API 提供了与智能体执行环境交互的标准。它包含环境创建工具和用于部署的命令行界面,支持隔离、安全且易于使用的 RL 后训练环境。

README 预览

#  OpenEnv: Agentic Execution Environments\n\nAn e2e framework for creating, deploying and using isolated execution environments for agentic RL training, built using Gymnasium style simple APIs.\n\n\n    \n    \n    \n    \n    \n    \n\n\n---\n\n**Featured Example:** Train LLMs to play BlackJack using [torchforge](https://meta-pytorch.org/torchforge/) (PyTorch's agentic RL framework): [`examples/grpo_blackjack/`](examples/grpo_blackjack/)\n\n**Zero to Hero Tutorial:** End to end tutorial from our [GPU Mode](tutorial/README.md) lecture and other hackathons.\n\n## Quick Start\n\nInstall the OpenEnv package:\n\n```bash\npip install openenv\n```\n\nInstall an environment client (e.g., Echo):\n\n```bash\npip install git+https://huggingface.co/spaces/openenv/echo_env\n```\n\nThen use the environment:\n\n```python\nimport asyncio\nfrom echo_env import CallToolAction, EchoEnv\n\nasync def main():\n    # Connect to a running Space (async context manager)\n    async with EchoEnv(base_url="https://openenv-echo-env.hf.space") as client:\n        # Reset the environment\n        result = await client.reset()\n        print(result.observation.echoed_message)  # "Echo environment ready!"\n\n        # Send messages\n        result = await client.step(\n            CallToolAction(\n                tool_name="echo_message",\n                arguments={"message": "Hello, World!"},\n            )\n        )\n        print(result.observation.result)  # "Hello, World!"\n        print(result.reward)\n\nasyncio.run(main())\n```\n\n**Synchronous usage** is also supported via the `.sync()` wrapper:\n\n```python\nfrom echo_env import CallToolAction, EchoEnv\n\n# Use .sync() for synchronous context manager\nwith EchoEnv(base_url="https://openenv-echo-env.hf.space").sync() as client:\n    result = client.reset()\n    result = client.step(\n        CallToolAction(\n            tool_name="echo_message",\n            arguments={"message": "Hello, World!"},\n        )\n    )\n    print(result.obse

常见问题 (5)

故障排除
为什么 MCPToolClient 在 mode="production" 时使用 WebSocket /ws 而不是 HTTP /mcp JSON-RPC?

生产传输标志初始化不正确。在 src/openenv/core/mcp_client.py 中,将 self.use_production_mode = False 替换为:

self.use_production_mode = mode_lower == "production"

这使该标志与规范化后的 _mode 值保持一致。作为临时解决方法,在创建客户端后手动设置它:

client = MCPToolClient(..., mode="production")
client.use_production_mode = True

修复后,list_tools() 应通过 HTTP /mcp 调用 tools/list,call_tool() 应通过 /mcp 调用 tools/call,而模拟模式应继续使用 WebSocket /ws 的 step() 路径。更新回归测试,使其断言所选用的传输方式,而不是仅检查 type="step" 消息。

来源 Issue #1168
故障排除
如何修复 MCPToolClient 在生产模式下使用 WebSocket 而非 HTTP /mcp JSON-RPC 传输的问题?

在 src/openenv/core/mcp_client.py 中,将 MCPToolClient 构造函数里硬编码的 self.use_production_mode = False 替换为:

self.use_production_mode = mode_lower == "production"

这样,当 mode="production" 时,list_tools() 和 call_tool() 将使用 HTTP /mcp JSON-RPC 方法 tools/list 和 tools/call,而模拟模式则继续使用 WebSocket step() 路径。

作为不修改源代码的临时变通方案,可在初始化客户端后立即设置该标志:

client = MCPToolClient(mode="production")
client.use_production_mode = True

更新 tests/core/test_mode_selection.py,断言生产模式会通过 /mcp 调用 tools/list 和 tools/call,并断言模拟模式仍会发送 WebSocket type="step" 消息。

来源 Issue #1157
故障排除
如何修复因 'No such container' 错误文本不同导致 Docker 清理验证在 Docker 29 和 Podman 上失败的问题?

不要依赖匹配 inspect 或 rm 的错误文本。应通过列出容器来验证删除,并将空结果视为成功:

docker ps --all --filter "name=^/<container-name>$" --format '{{.Names}}'

空结果表示容器已被删除;非零退出码表示容器引擎无法访问。对于 Podman,启动容器时请使用:

--stop-timeout 0

这样 docker rm --force 就不会在 SIGKILL 之前等待默认的停止超时时间。此外,避免断言 CapDrop == ["ALL"],因为 Podman 会逐个报告被丢弃的 capability。应改为验证容器的 capability 边界集合(CapBnd)为空;即使边界 capability 仍然存在,非 root 用户的 CapEff 也可能为 0。针对 Docker 29 和 Podman 的输出添加特定于引擎的单元测试。

来源 Issue #1257
informational
OpenEnv RFC 005 的状态是什么?HarnessEnvironment 与 openenv.core.harness 有何不同?

RFC 005 仍然有效,并已在 main 上通过 PR #1097–#1100 实现。对于该 RFC 的多轮外部 harness 模式,请将 HarnessEnvironment 与 AgenticHarnessAdapter 配合使用。外部 harness 在环境内部运行,OpenEnv 通过 MCP 注入工具,每次 step() 调用代表一个对话轮次,而 harness 在 episode 内跨轮次保留上下文。在“Evaluate Claude Code in an Environment”教程和 examples/claude_code_harness_eval 中提供了一个完整的 Claude Code 在 τ²-bench 上的运行示例。

由 #471/#652 在 openenv.core.harness 下引入的 API——如 ResourceSession、HarnessAdapter、MCPHarnessAdapter、CLIHarnessAdapter 和 build_harness_rollout_func——是一个独立的会话/运行时层,而非 RFC 005 的实现。请将它们用于较低层级的会话/资源管理;将 HarnessEnvironment/AgenticHarnessAdapter 用于 RFC 005 风格的多轮 agent-in-environment rollout。更新后的 harness 文档会根据哪个组件拥有 agent loop 来组织这些选项。

来源 Issue #696
故障排除
如何修复 openenv init 之后重复的 Python .venv 层导致 Docker 镜像大小翻倍的问题?

生成的 Dockerfile 先显式复制了 /app/env/.venv,随后又复制了已经包含 .venv 的 /app/env,从而产生了两个约 500 MB 的层。请将 OpenEnv 升级到包含服务端 Dockerfile 模板修复的版本,或者手动修补生成的 Dockerfile。移除单独的 virtualenv 复制步骤,只保留项目复制,并创建一个符号链接:

# 删除这一行:
# COPY --from=builder /app/env/.venv /app/.venv

# 只复制一次项目,包括其内嵌的 .venv:
COPY --from=builder /app/env /app/env

# 为依赖 /app/.venv 路径的情况提供兼容性:
RUN ln -s /app/env/.venv /app/.venv

如果你的模板使用了 --chown,请在保留的 COPY 指令上保留这些标志。不使用缓存重新构建并验证各层:

docker build --no-cache -t your-image .
docker history your-image
# 或者
dive your-image

现在 virtualenv 应该只出现在一个大层中,符号链接增加的体积可以忽略不计。

来源 Issue #1021