hcm21 / CLAUDE.md
ParetoOptimal's picture
Fix GRPO all-zero rewards: parse JSON actions from completions
1ac70ff
|
Raw
History Blame Contribute Delete
9.1 kB
# HR Productivity Environment β€” AgentX-AgentBeats
## Overview
A fully-implemented HR simulation environment (OpenEnv-compliant) where an LLM agent serves as Chief Human Capital Officer (CHCO), managing a simulated company over 6 quarters. The agent uses Fitz-enz HR Analytics frameworks to optimize human capital metrics through strategic hiring, training, compensation, and retention decisions.
## Repository Structure
```
/tmp/autoresearch/
β”œβ”€β”€ hr_env/
β”‚ └── server/
β”‚ β”œβ”€β”€ environment.py # Main simulation loop (OpenEnv Environment)
β”‚ β”œβ”€β”€ company.py # Company + Department models (Cobb-Douglas production)
β”‚ β”œβ”€β”€ employee.py # Employee dataclass with lifecycle methods
β”‚ β”œβ”€β”€ metrics.py # Fitz-enz metrics: HCVA, HCROI, QIPS, Five Indexes
β”‚ β”œβ”€β”€ scoring.py # Reward computation + final score (normalized [0,1])
β”‚ β”œβ”€β”€ phases.py # HCM:21 phase management (Scanningβ†’Planningβ†’Producingβ†’Controlling)
β”‚ β”œβ”€β”€ events.py # Stochastic quarterly events (market, competitor, etc.)
β”‚ β”œβ”€β”€ data_gen.py # Synthetic company generation (Faker + numpy)
β”‚ └── app.py # OpenEnv server entrypoint
β”œβ”€β”€ agent/
β”‚ β”œβ”€β”€ hr_agent.py # Claude-based CHCO agent with phase-aware prompting
β”‚ β”œβ”€β”€ prompts.py # System prompt, phase prompts, summary prompts
β”‚ └── run.py # Agent runner script
β”œβ”€β”€ tests/ # Test suite
β”œβ”€β”€ openenv.yaml # OpenEnv configuration
β”œβ”€β”€ pyproject.toml # Python project config (uv)
└── Dockerfile # Container build
```
## Development Commands
```bash
# Install dependencies
uv sync
# Run tests
uv run pytest tests/ -v
# Start OpenEnv server
uv run python -m hr_env.server.app
# Run agent against server
uv run python -m agent.run
# Docker build
docker build -t hr-productivity-env .
```
## Architecture
### Simulation Engine
- **Company Model**: 5 departments (Engineering, Sales, Operations, HR, Finance) with Cobb-Douglas production functions
- **Employee Model**: 17 tracked attributes including performance, engagement, flight_risk, promotability
- **Revenue**: `A * headcount^alpha * avg_skill^beta * engagement_mult * market_modifier` per department
- **Turnover**: Stochastic based on flight_risk (logistic function of pay, engagement, tenure, market)
### Fitz-enz Metrics
- **HCVA**: (Revenue - Non-Employment Costs) / FTE
- **HCROI**: Revenue / Employment Cost
- **QIPS**: Quality(0.25) + Innovation(0.25) + Productivity(0.30) + Service(0.20)
- **Five Indexes**: Cost, Time, Quantity, Quality, Human Reactions (% change vs prior quarter)
- **Employee Value**: avg(Productivity + Promotability + Transferability + Retainability)
### HCM:21 Phase System (per quarter)
1. **Scanning** (min 2 actions): query_department, query_employees, calculate_metric, review_financials
2. **Planning** (min 1): set_hiring_target, set_training_budget, set_compensation_policy, set_retention_program
3. **Producing** (min 1): execute_hiring, execute_promotion, execute_transfer, execute_training, execute_termination
4. **Controlling** (min 1): submit_report, calculate_metric β†’ then advance_quarter
### Scoring
- **Quarterly reward**: HCVA improvement (40%) + HCROI (20%) + QIPS (20%) + Five Indexes (20%)
- **Final score** [0,1]: HCVA trajectory (25%) + HCROI improvement (20%) + Employee Value (20%) + QIPS consistency (15%) + Five Indexes cumulative (10%) + Financial health (10%)
### Stochastic Events
MarketDownturn, CompetitorPoaching, ProductLaunch, ExecDeparture, MinWageIncrease, EmployerAward, BudgetCut, TrainingBreakthrough β€” each with independent probability per quarter, max 2 per quarter.
## Databricks Integration
The simulation is adapted into a Databricks notebook (`/tmp/AimpointDigital/01_agentic_wikipedia_aimpoint_interview.ipynb`) with:
- **Wikipedia knowledge layer**: HR theory articles (Fitz-enz, HCM, talent management) indexed into FAISS via BGE-Large embeddings
- **LangGraph orchestration**: StateGraph with 5 nodes (initialize β†’ agent_decide β†’ execute_tools β†’ check_done β†’ summarize)
- **RAG bridge**: `consult_hr_knowledge` tool lets the agent ground decisions in Wikipedia-sourced HR theory
- **Databricks LLM**: `databricks-meta-llama-3-1-8b-instruct` for agent reasoning
## Key Conventions
- Pydantic models for OpenEnv; plain dataclasses/dicts for Databricks adaptation
- Phase-gated action space prevents random action sequences
- Company generation uses Faker (names) + numpy (distributions) with deterministic seeds
- Salary distributions: lognormal; tenure: exponential; engagement: beta(7,3)
- Level distribution: pyramid [0.35, 0.30, 0.20, 0.10, 0.05] for levels 1-5
- Recruiting cost: $8,000/hire; Benefits: 30% of salary; Training: $50/hr/employee
## Databricks Deployment
### Workspace
- **URL**: `https://dbc-c005fe3a-5584.cloud.databricks.com`
- **Org ID**: `7474655330631867`
- **Target Folder ID**: `1876640772048528`
- **Folder URL**: `https://dbc-c005fe3a-5584.cloud.databricks.com/browse/folders/1876640772048528?o=7474655330631867`
- **PAT**: (stored in env / .databrickscfg β€” not committed)
- **User**: `n8.mauer@gmail.com`
- **Edition**: Community Edition (Free)
- **LLM endpoint**: `databricks-meta-llama-3-1-8b-instruct`
- **Embedding endpoint**: `databricks-bge-large-en`
### .env file (for local development)
```
DATABRICKS_HOST=https://dbc-c005fe3a-5584.cloud.databricks.com
DATABRICKS_TOKEN=<your-token>
DATABRICKS_ORG_ID=7474655330631867
```
### Cold-Start Setup
1. `pip install databricks-cli`
2. Write `~/.databrickscfg`:
```ini
[DEFAULT]
host = https://dbc-c005fe3a-5584.cloud.databricks.com
token = <your-token>
```
3. Deploy notebook:
```bash
databricks workspace import \
"/tmp/AimpointDigital/01_agentic_wikipedia_aimpoint_interview.ipynb" \
/Users/n8.mauer@gmail.com/01_agentic_wikipedia_aimpoint_interview \
--format JUPYTER --language PYTHON --overwrite
```
4. Open workspace URL β†’ attach cluster β†’ Run All
### Deploy Script
```bash
./deploy.sh # from /tmp/AimpointDigital/
```
### Runtime Fixes Applied
- **Rate limiting**: `agent_decide` LLM calls wrapped with `backoff.on_exception` (exponential, max 8 retries, 120s) + 1.5s proactive delay between calls. Community Edition has low QPS for foundation model endpoints.
- **MLflow tracing**: `mlflow.langchain.autolog()` added at top of Cell A2 to enable tracing and suppress Databricks "Enhance GenAI observability" hint. `mlflow-skinny[databricks]` already in pip install cell.
### GitHub Repo
- URL: `https://github.com/n8mauer/AimpointDigital`
- Contains: notebook, build script, deploy script, README (runbook + talk track), assignment PDF
## TRL/GRPO Training (`notebooks/hcm21_trl_training.ipynb`)
### Architecture
- **Model**: `unsloth/Qwen3-0.6B` with LoRA (r=16, 4-bit quantization)
- **Method**: GRPO (Group Relative Policy Optimization) via TRL's `GRPOTrainer`
- **Environment**: HCM:21 OpenEnv on HF Spaces (`https://paretooptimal-hcm21.hf.space`)
- **Colab URL**: `https://colab.research.google.com/github/n8mauer/autoresearch/blob/main/notebooks/hcm21_trl_training.ipynb`
### GRPO Reward Strategy (JSON action parsing β€” no environment_factory)
The model generates text completions containing JSON action objects (one per line).
`reward_func` parses these with regex (`\{[^{}]*"action_type"[^{}]*\}`), executes
them in a fresh `HCM21Env` instance, and returns the environment's final score.
**Why not `environment_factory`?**
- TRL's `environment_factory` exposes env methods as tools for tool-calling, but a 0.6B model can't reliably generate structured tool calls
- `environment_factory` requires `transformers>=5.2.0` which conflicts with Unsloth patches
- Disabling Qwen3 thinking mode via `chat_template.replace("enable_thinking", "")` may break tool-calling templates
- Direct JSON parsing in `reward_func` is simpler, more robust, and works with Unsloth
### Key Implementation Details
- `SYSTEM_PROMPT` instructs the model to output 20-40 JSON action objects covering 6 quarters
- `reward_func(completions, **kwargs)` β€” no `environments` param (environments created internally)
- `GRPOTrainer` has NO `environment_factory` argument
- Evaluation (cell 20) generates one completion per seed, parses all actions, executes them
- `tokenizer.apply_chat_template()` may return `BatchEncoding` β€” extract `.input_ids` before using `.shape`
### Training Config
- `per_device_train_batch_size=2`, `gradient_accumulation_steps=4`, `num_generations=4`
- `max_completion_length=2048`, `learning_rate=5e-6`, `fp16=True`
- Dataset: 20 prompts with different episode seeds
### Verification Checklist
After running in Colab, confirm:
- `reward` column shows **non-zero values**
- `reward_std` is **non-zero** (learning signal exists)
- `Training Loss` is **non-zero** (GRPO has gradients)
- Rewards trend upward over training steps