silent-failure-detector / developer.md
nevrohelios
feature openenv
5a142dc
|
Raw
History Blame Contribute Delete
6.37 kB
# Developer Guide
---
## 1. Environment Setup
```bash
python -m venv .venv && source .venv/bin/activate
pip install git+https://github.com/meta-pytorch/OpenEnv.git
pip install -r requirements.txt
export API_BASE_URL="https://api.openai.com/v1"
export MODEL_NAME="gpt-4o-mini"
export HF_TOKEN="hf_..."
export ENV_URL="http://localhost:7860"
```
---
## 2. Local Dev
```bash
# Start server
PYTHONPATH=. uvicorn server.app:app --host 0.0.0.0 --port 7860 --reload
# Health check
curl http://localhost:7860/health # {"status":"healthy"}
curl http://localhost:7860/docs # OpenAPI UI
# HTTP reset (for debugging)
curl -X POST http://localhost:7860/reset \
-H "Content-Type: application/json" \
-d '{"task": "easy"}'
# Run baseline
python inference.py
```
---
## 3. Docker
```bash
docker build -t sfd .
docker run -p 7860:7860 --rm sfd
# Run inference against docker
ENV_URL=http://localhost:7860 python inference.py
```
---
## 4. HF Spaces Deployment
### 4a. What to upload
```
models.py
client.py
server/
data/
openenv.yaml
Dockerfile
requirements.txt
README.md
inference.py
```
Do NOT upload: `.venv/`, `__pycache__/`, `.git/`
### 4b. Create Space (Docker SDK)
Go to https://huggingface.co/new-space → Select **Docker** SDK → Create.
Or via CLI:
```bash
pip install huggingface_hub
python -c "
from huggingface_hub import HfApi
HfApi().create_repo('YOUR_USERNAME/silent-failure-detector', repo_type='space', space_sdk='docker')
"
```
### 4c. Push
```bash
git init
git remote add origin https://huggingface.co/spaces/YOUR_USERNAME/silent-failure-detector
git add models.py client.py server/ data/ openenv.yaml Dockerfile requirements.txt README.md inference.py
git commit -m "initial"
git push origin main
```
### 4d. Space Secrets
Settings → Variables and secrets → Add:
| Name | Value |
|---|---|
| `HF_TOKEN` | Your HF token |
| `API_BASE_URL` | LLM provider base URL |
| `MODEL_NAME` | Model name |
### 4e. Verify
```bash
SPACE="https://YOUR_USERNAME-silent-failure-detector.hf.space"
curl -f "$SPACE/health"
# WebSocket reset (what the SDK uses):
python3 -c "
import asyncio
from client import SilentFailureEnv
async def test():
async with SilentFailureEnv(base_url='$SPACE') as env:
r = await env.reset(task='easy')
print('session_id:', r.observation.session_id)
print('total_steps:', r.observation.total_steps)
asyncio.run(test())
"
```
---
## 5. Running Inference Against HF Space
```bash
export ENV_URL="https://your-username-silent-failure-detector.hf.space"
export API_BASE_URL="https://api.openai.com/v1"
export MODEL_NAME="gpt-4o-mini"
export HF_TOKEN="sk-..."
python inference.py
```
Expected runtime: under 10 minutes on vcpu=2, mem=8GB.
---
## 6. Pre-Submission Validation Checklist
- [ ] `GET /health` returns `{"status":"healthy"}`
- [ ] WebSocket `/ws` accepts reset/step messages
- [ ] `POST /reset` works (HTTP fallback)
- [ ] `POST /step` returns reward in [0.0, 1.0] and done bool
- [ ] All 3 tasks (easy/medium/hard) produce graded scores
- [ ] `python inference.py` runs to completion, logs [START]/[STEP]/[END]
- [ ] `docker build -t sfd . && docker run -p 7860:7860 sfd` works
- [ ] `openenv.yaml` present and valid
---
## 7. How the OpenEnv SDK Is Used
The server inherits from the actual OpenEnv `Environment` ABC:
```python
from openenv.core.env_server.interfaces import Environment
from openenv.core.env_server import create_fastapi_app
class SilentFailureEnvironment(Environment[SFDAction, SFDObservation, SFDState]):
def reset(self, task="easy", **kwargs) -> SFDObservation: ...
def step(self, action: SFDAction, **kwargs) -> SFDObservation: ...
@property
def state(self) -> SFDState: ...
app = create_fastapi_app(SilentFailureEnvironment, SFDAction, SFDObservation)
```
`create_fastapi_app` automatically provides:
- `GET /health`
- `POST /reset`, `POST /step`, `GET /state` (HTTP)
- `WS /ws` (WebSocket — primary transport used by the client)
- `GET /docs` (OpenAPI UI)
- `GET /web` (interactive web UI)
The client inherits from `EnvClient` and uses WebSocket:
```python
from openenv.core.env_client import EnvClient
class SilentFailureEnv(EnvClient[SFDAction, SFDObservation, SFDState]):
def _step_payload(self, action): return {"message": action.message}
def _parse_result(self, payload): return StepResult(...)
def _parse_state(self, payload): return SFDState(...)
```
Usage is always async:
```python
async with SilentFailureEnv(base_url="http://localhost:7860") as env:
result = await env.reset(task="medium")
result = await env.step(SFDAction(message='{"flag":true,"confidence":0.9}'))
```
---
## 8. Extending the Dataset
Edit `scripts/generate_dataset.py`, add items to `ITEMS`:
```python
{
"id": "h_wc_013", # unique: {difficulty}_{label_abbrev}_{num}
"domain": "finance", # medicine|law|finance|coding|science|geography|history
"difficulty": "hard", # easy|medium|hard
"label": "wrong_confident", # wrong_confident|correct|wrong_uncertain|correct_misleading
"question": "...",
"ai_response": "...",
}
```
Minimum pool sizes needed: easy ≥10, medium ≥20, hard ≥30.
Target label balance per tier: ~40% wrong_confident, ~35% correct, ~15% wrong_uncertain, ~10% correct_misleading.
Then: `python scripts/generate_dataset.py`
---
## 9. Training an RL Agent with GRPO (TRL)
Install TRL:
```bash
pip install git+https://github.com/huggingface/trl.git
```
The environment is stateless per `session_id` and supports concurrent sessions (`SUPPORTS_CONCURRENT_SESSIONS = True`).
Recommended curriculum:
1. Warm up on `easy` until recall > 0.7
2. Train primarily on `medium`
3. Use `hard` as evaluation benchmark only
Reward is sparse (terminal only). For faster GRPO convergence, consider shaping: give +0.1 for each correctly classified item using the known labels as a secondary signal during training rollouts.
---
## 10. Grader Verification
```python
from server.grader import compute_reward
labels = ["wrong_confident", "correct", "wrong_confident", "wrong_uncertain"]
flags = [True, False, False, False]
confs = [0.9, 0.1, 0.3, 0.2]
reward = compute_reward(labels, flags, confs)
print(reward)
# TP=1, FN=1, TN=2, FP=0
# recall=0.5, specificity=1.0, base=0.5
# calibration_bonus~0.1, reward~0.55
assert 0.0 <= reward <= 1.0
```