개요
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.obseFAQ (5)
문제 해결왜 MCPToolClient가 mode="production"일 때 HTTP /mcp JSON-RPC 대신 WebSocket /ws를 사용하나요?
프로덕션 트랜스포트 플래그가 잘못 초기화됩니다. 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" 메시지만 확인하는 대신 선택된 트랜스포트를 검증하도록 회귀 테스트를 업데이트하세요.
문제 해결MCPToolClient 프로덕션 모드에서 HTTP /mcp JSON-RPC transport 대신 WebSocket을 사용하도록 하려면 어떻게 수정해야 하나요?
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를 업데이트하여 프로덕션 모드가 tools/list 및 tools/call을 사용해 /mcp를 호출하는지, 그리고 시뮬레이션 모드가 여전히 WebSocket type="step" 메시지를 전송하는지 확인하세요.
문제 해결Docker 29와 Podman에서 'No such container' 오류 텍스트가 달라 Docker 클린업 검증이 실패하는 문제를 해결하는 방법은?
inspect 또는 rm 오류 텍스트 일치에 의존하지 마세요. 컨테이너를 나열하고 빈 결과를 성공으로 간주하여 삭제를 확인하세요:
docker ps --all --filter "name=^/<container-name>$" --format '{{.Names}}'
빈 결과는 컨테이너가 삭제되었음을 의미하고, 0이 아닌 종료 코드는 컨테이너 엔진에 연결할 수 없음을 의미합니다. Podman의 경우 다음 옵션으로 컨테이너를 시작하세요:
--stop-timeout 0
그래야 docker rm --force가 SIGKILL 전에 기본 중지 타임아웃을 기다리지 않습니다. 또한 Podman은 드롭된 capabilities를 개별적으로 보고하므로 CapDrop == ["ALL"]을 단언하지 마세요. 대신 컨테이너의 capability bounding set(CapBnd)이 비어 있는지 확인하세요. bounding capabilities가 남아 있어도 non-root 사용자의 경우 CapEff가 0일 수 있습니다. Docker 29 및 Podman 출력에 대한 엔진별 단위 테스트를 추가하세요.
informationalOpenEnv RFC 005의 상태는 어떻게 되며, HarnessEnvironment는 openenv.core.harness와 어떻게 다른가요?
RFC 005는 여전히 유효하며, PR #1097–#1100을 통해 main에 구현되었습니다. RFC의 멀티턴 외부 하네스 패턴에는 HarnessEnvironment를 AgenticHarnessAdapter와 함께 사용하세요. 외부 하네스는 환경 내부에서 실행되고, OpenEnv는 MCP를 통해 도구를 주입하며, 각 step() 호출은 하나의 대화 턴을 나타내고 하네스는 에피소드 내에서 턴 전반에 걸쳐 컨텍스트를 유지합니다. τ²-bench에서 Claude Code를 실행하는 완성된 예제는 "환경에서 Claude Code 평가하기" 튜토리얼과 examples/claude_code_harness_eval에서 확인할 수 있습니다. #471/#652에서 openenv.core.harness 하위에 도입된 ResourceSession, HarnessAdapter, MCPHarnessAdapter, CLIHarnessAdapter, build_harness_rollout_func 같은 API는 RFC 005 구현이 아니라 별도의 세션/런타임 계층입니다. 이 API들은 저수준 세션/리소스 관리에 사용하고, RFC 005 스타일의 멀티턴 환경 내 에이전트 롤아웃에는 HarnessEnvironment/AgenticHarnessAdapter를 사용하세요. 업데이트된 하네스 문서는 어떤 컴포넌트가 에이전트 루프를 소유하는지를 기준으로 이러한 옵션들을 정리합니다.
문제 해결openenv init 후에 Docker 이미지 크기를 두 배로 만드는 중복된 Python .venv 레이어를 어떻게 수정하나요?
생성된 Dockerfile은 /app/env/.venv를 명시적으로 복사한 후, 이미 .venv를 포함하고 있는 /app/env를 복사하여 약 500MB 크기의 레이어 두 개를 생성합니다. 서버 Dockerfile 템플릿 수정 사항이 포함된 릴리스로 OpenEnv를 업그레이드하거나, 생성된 Dockerfile을 수동으로 패치하세요. 별도의 virtualenv 복사를 제거하고 프로젝트 복사본만 유지한 다음 심볼릭 링크를 생성하세요:
# Remove this line:
# COPY --from=builder /app/env/.venv /app/.venv
# Copy the project once, including its embedded .venv:
COPY --from=builder /app/env /app/env
# Provide compatibility for paths expecting /app/.venv:
RUN ln -s /app/env/.venv /app/.venv
템플릿에서 --chown을 사용하는 경우, 남은 COPY에서 해당 플래그를 그대로 유지하세요. 캐시 없이 다시 빌드하고 레이어를 확인하세요:
docker build --no-cache -t your-image .
docker history your-image
# or
dive your-image
이제 virtualenv는 하나의 큰 레이어에만 나타나며, 심볼릭 링크는 무시할 수 있을 정도의 크기만 추가합니다.