Spaces:
Sleeping
Sleeping
| title: AP Commander | |
| emoji: ποΈ | |
| colorFrom: blue | |
| colorTo: indigo | |
| sdk: docker | |
| pinned: true | |
| license: mit | |
| tags: | |
| - openenv | |
| - reinforcement-learning | |
| - multi-agent | |
| - fleet-ai | |
| - long-horizon | |
| - finance | |
| - enterprise | |
| - oversight | |
| # AP Commander β Multi-Agent RL Environment for Enterprise Financial Operations | |
| **Hackathon:** Meta PyTorch OpenEnv Γ Scaler School of Technology Grand Finale | |
| **Team:** Pathikreet Chowdhury, Anubhav Bhattacharya, Radhika Ravi | |
| **Live environment UI:** https://pathikreet-ap-clerk-env.hf.space | |
| **Environment API + Swagger:** https://pathikreet-ap-clerk-env.hf.space/docs | |
| **Training Space (Gradio UI):** https://huggingface.co/spaces/Pathikreet/ap-commander-training | |
| **Training script (HF Space):** [`training/train.py`](training/train.py) β runs on the Training Space (A10G) | |
| **Colab notebook:** [`training/colab_training.ipynb`](training/colab_training.ipynb) β self-contained GRPO loop, T4-compatible | |
| **Training logs:** [`runs/grpo/`](runs/grpo/) β timestamped per run, nothing overwritten | |
| **Baseline logs:** [`runs/baselines/`](runs/baselines/) β scripted agent + untrained Llama/Qwen evaluations | |
| **Blog / Writeup:** [BLOG.md](BLOG.md) β full writeup: problem, environment, training evidence across 4 runs, reward design | |
| **Presentation (slide deck):** https://canva.link/k7f87ccul4fznaf | |
| **Technical documentation:** [TECHNICAL.md](TECHNICAL.md) β architecture, reward design, agent interactions, flowchart, API reference | |
|  | |
| --- | |
| ## Hackathon Theme Coverage | |
| | Theme | Implementation | Bonus Target | | |
| |---|---|---| | |
| | **#1 Multi-Agent** | AP Clerk agent + Fleet AI Oversight agent (separate action/obs spaces, `/oversight/*` endpoints) + VendorActor / ManagerActor / ComplianceActor responding dynamically to QUERY_VENDOR / ESCALATE / HOLD | Fleet AI Β· Halluminate | | |
| | **#2 Long-Horizon** | 7 tasks with max 10β16 steps requiring sustained multi-step reasoning: dispute resolution, fraud investigation, manager OOO escalation chain, SOX audit trail | Scale AI Labs | | |
| | **#3.1 Professional World Modeling** | ERP-style documents (Invoice, PO, GRN, paid ledger), dynamic company policy, multi-app actor interactions, randomised per episode | Scaler AI Labs | | |
| | **#4 Self-Improvement** | Adaptive curriculum (`/curriculum/next_task`) that escalates difficulty based on session history + `HYPOTHETICAL` action for counterfactual self-play exploration during training | Snorkel AI | | |
| --- | |
| ## The Problem | |
| Every enterprise processes thousands of vendor invoices every month. Each one requires a human to cross-reference purchase orders, verify delivery receipts, apply company policy, and decide whether to pay β and how much. A wrong approval costs money. A wrong rejection damages a vendor relationship. A missed duplicate is fraud. | |
| **LLMs fail at this in specific, measurable ways.** They hallucinate PO numbers, ignore policy caps, approve duplicates, and cannot chain multi-step workflows like *query vendor β get response β escalate to manager β reject*. They treat each step as independent rather than as part of an investigation. There is no RL environment that exposes these failures with a reward signal designed to close the loopholes. | |
| AP Commander is that environment: a multi-agent system that trains an LLM to reason through enterprise Accounts Payable workflows with the rigor a CFO would require, and deploys a second agent to monitor and catch what the first one misses. | |
| --- | |
| ## What the Agent Learns | |
| An **AP Clerk agent** receives a structured observation β invoice, purchase orders, goods receipt notes, company policy β and must decide: | |
| ``` | |
| APPROVE_FULL | APPROVE_PARTIAL | REJECT | ESCALATE | QUERY_VENDOR | HOLD | |
| ``` | |
| It must also justify its decision with specific dollar amounts and a reason code. Getting the decision right but the amount wrong is still penalized. Citing "policy violation" without identifying the violated clause is still penalized. | |
| A second **Oversight agent (Fleet AI)** monitors batches of completed clerk decisions, identifies fraudulent approvals, and explains its reasoning with numeric evidence. It is penalized for false positives. | |
| Three simulated workplace actors generate contextual responses at episode start, revealed progressively as the clerk takes intermediate actions: | |
| - **VendorActor** β reveals response to `QUERY_VENDOR` with one of three personas: honest, fraudulent, or confused | |
| - **ManagerActor** β reveals response to `ESCALATE` based on its budget authority and risk appetite; may be out-of-office, triggering a VP chain | |
| - **ComplianceActor** β reveals response to `HOLD` with a SOX / GDPR / Internal Policy verdict | |
| Episodes run up to **16 steps** on long-horizon tasks β fraud investigations, audit trails, multi-vendor splits β requiring sustained multi-step reasoning to reach the correct terminal decision. | |
| --- | |
| ## How the Data Works | |
| Every episode is **synthetically generated at runtime** β there is no static dataset. When the agent calls `/reset`, the environment produces a fresh, unique financial scenario from scratch using a seeded RNG. | |
| ``` | |
| POST /reset { task_id: "medium_quantity_shortfall", seed: 42 } | |
| βββ tasks.py: generate_medium_quantity_shortfall(seed=42) | |
| βββ Builds everything from scratch: vendor, item, quantities, prices, PO, GRN | |
| ``` | |
| The agent receives a structured `APObservation`: | |
| ``` | |
| APObservation | |
| βββ invoice β vendor name, line items, unit prices, freight, total | |
| βββ purchase_orders β 1 real OPEN PO + 1β2 distractor CLOSED POs (noise) | |
| βββ goods_receipts β 1 real GRN + 1 wrong-vendor distractor GRN (noise) | |
| βββ company_policy β text with randomised freight cap and price tolerance | |
| βββ freight_cap β randomised each episode: $30 / $50 / $75 / $100 | |
| βββ price_tolerance β randomised each episode: 0.5% β 3.0% | |
| βββ paid_invoice_ids β ledger of already-paid invoices (duplicate detection) | |
| ``` | |
| | What | Fixed or random? | Why | | |
| |---|---|---| | |
| | Task *type* (e.g. quantity shortfall) | Fixed by `task_id` | Defines the skill being trained | | |
| | Vendor, item, amounts, IDs | **Random per seed** | Agent cannot memorise β must reason | | |
| | Freight cap & price tolerance | **Random** | Agent must read policy each episode | | |
| | Distractor POs and GRNs | **Always present** | Forces genuine 3-way matching | | |
| **Same seed β identical episode.** This makes training and evaluation reproducible. Different seeds across training episodes prevent the agent from memorising amounts β it must learn the underlying reasoning pattern. | |
| --- | |
| ## Results | |
| ### Run 1 β Qwen2.5-7B-Instruct, 3 Epochs GRPO (2026-04-25) | |
| | Parameter | Value | | |
| |---|---| | |
| | Model | `Qwen/Qwen2.5-7B-Instruct` | | |
| | Quantization | 4-bit NF4 (BitsAndBytes) | | |
| | LoRA | r=16, alpha=16, no dropout | | |
| | Algorithm | GRPO (TRL β₯ 0.15) | | |
| | Epochs | 3 | | |
| | Generations / prompt | 8 | | |
| | Training samples | 50 (10 tasks Γ 5 seeds) | | |
| | Hardware | A10G Small (HF Spaces) | | |
| | Elapsed | 59.5 min | | |
| | Reward calls | 1 200 | | |
| | Format rate | 91.2% | | |
| | Parse failures | 106 / 1 200 (8.8%) | | |
| #### Live training metrics | |
|  | |
|  | |
| > **Recent mean reward 0.746** at step 150. Single-step REJECT tasks learned quickly (Price Discrepancy 0.96, Vendor Mismatch 0.94, Tax Discrepancy 0.92). Multi-step tasks still failing (Duplicate Invoice 0.07, Policy Violation 0.09) β correct action sequences (QUERY_VENDOR β REJECT, ESCALATE β REJECT) require more epochs to discover. | |
| #### Before / After evaluation (10 tasks, seed=99) | |
|  | |
| | Task | Before GRPO | After GRPO | Ξ | | |
| |---|---|---|---| | |
| | easy_perfect_match | 0.500 | **0.990** | +0.490 | | |
| | easy_no_po_found | 0.990 | 0.990 | 0.000 | | |
| | medium_quantity_shortfall | 0.860 | 0.860 | 0.000 | | |
| | medium_price_discrepancy | β | β | β | | |
| | medium_split_delivery | β | β | β | | |
| | medium_vendor_mismatch | β | β | β | | |
| | hard_policy_violation | 0.010 | 0.010 | 0.000 | | |
| | hard_duplicate_invoice | β | β | β | | |
| | hard_partial_po_match | β | β | β | | |
| | hard_tax_discrepancy | β | β | β | | |
| > `easy_perfect_match` improved +0.490 (Qwen was getting the amount or reason code wrong before GRPO). Hard multi-step tasks need more epochs. Full 10-task eval runs from epoch 2 onward. | |
| --- | |
| ### Run 2 β Qwen2.5-7B, 17 tasks, 160 prompts (stopped early at step 235/420) | |
| **Hardware:** A10G Large | **Stopped:** Epoch 3.35 / 6 | |
|  | |
| | Metric | Value | | |
| |---|---| | |
| | Steps completed | 235 / 420 | | |
| | Recent mean reward | 0.516 | | |
| | Format rate | **44.4%** (critical failure) | | |
| | Parse failures | 8 343 / 7 520 reward calls | | |
| | Elapsed | 255.6 min | | |
| #### Per-task means at stop | |
| | Task | Score | Task | Score | | |
| |---|---|---|---| | |
| | easy_no_po_found | **0.99** | hard_policy_violation | 0.45 | | |
| | easy_perfect_match | **0.82** | medium_price_discrepancy | 0.45 | | |
| | medium_vendor_mismatch | 0.55 | long_policy_migration | 0.42 | | |
| | hard_tax_discrepancy | 0.50 | long_manager_chain | 0.38 | | |
| | long_fraud_investigation | 0.49 | long_audit_trail | 0.34 | | |
| | hard_duplicate_invoice | 0.48 | medium_quantity_shortfall | 0.33 | | |
| | | | long_invoice_dispute | 0.33 | | |
| | | | long_batch_reconciliation | 0.28 | | |
| | | | long_split_delivery | 0.24 | | |
| | | | long_multi_vendor_split | 0.22 | | |
| | | | hard_partial_po_match | 0.22 | | |
| #### Issues that caused early stop | |
| 1. **Temperature 1.1 β 55% format failures** β model generated natural language instead of JSON; format reward Β±0.05 too weak to correct this | |
| 2. **Curriculum gating locked hard tasks** β from epoch 3 onward `hard_policy_violation` and other hard tasks were silently redirected to easy tasks; hard/long tasks stopped receiving any gradient signal | |
| 3. **Entropy collapsed to 0.23** β model defaulted to REJECT for 59% of decisions; APPROVE_PARTIAL and QUERY_VENDOR nearly absent | |
| 4. **frac_reward_zero_std = 0.5** β half of all GRPO groups had identical rewards across 16 generations; zero learning signal for those steps | |
| 5. **Negative loss (-0.011) with zero clip_ratio** β policy drifted past reference without PPO correction | |
| #### Run 3 fixes applied | |
| - Temperature: 1.1 β **0.7** | |
| - `beta=0.1` added (prevents entropy collapse; was `kl_coeff` which is not a valid TRL param) | |
| - Format reward: Β±0.05 β **Β±0.15** | |
| - Curriculum gating **disabled** β all 20 tasks train from step 1 | |
| - `NUM_GENERATIONS`: **16** (32 caused CUDA OOM on 7B/A10G during backward pass) | |
| - `gradient_accumulation_steps`: 2 β **1** | |
| - `PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True` to reduce fragmentation | |
| - 3 missing hard tasks registered: `hard_currency_conversion`, `hard_manager_preapproval`, `hard_credit_memo` β restores 322 training prompts | |
| - System prompt updated with concrete JSON example | |
| --- | |
| ### Run 3 β Qwen2.5-1.5B-Instruct, G=16, 322 prompts (paused β insufficient compute) | |
| **Hardware:** A10G Small | **Model:** `Qwen/Qwen2.5-1.5B-Instruct` | **Generations/prompt:** 16 | |
|  | |
|  | |
| > **Mean reward 0.722** at step 113 (up from 0.486 untrained baseline), format rate **94.9%** β entropy collapse and format failures from Run 2 fully resolved. Paused at step 113 due to insufficient compute allocation. See per-task breakdown in [BLOG.md](BLOG.md). | |
| --- | |
| ### Run 4 β Qwen2.5-1.5B-Instruct, G=8, parallel comparison (ongoing) | |
| **Hardware:** A10G Small | **Model:** `Qwen/Qwen2.5-1.5B-Instruct` | **Generations/prompt:** 8 | |
|  | |
|  | |
| > **Mean reward 0.709** at step 179, format rate **93.7%**. Running as a G=8 ablation against Run 3 (G=16) β smaller groups train faster per step; larger groups provide more contrastive signal per prompt. Currently ongoing. | |
| --- | |
| ### Baselines | |
| #### Untrained Qwen2.5-7B-Instruct (4-bit, no LoRA) | |
| Run `training/eval_baseline.py` on the HF Training Space to generate this. Results saved to `runs/baselines/qwen2.5-7b-instruct-DATETIME/`. | |
| | Task | Difficulty | Score (mean, 3 seeds) | | |
| |---|---|---| | |
| | easy_perfect_match | easy | 0.500 | | |
| | easy_no_po_found | easy | 0.990 | | |
| | medium_quantity_shortfall | medium | 0.860 | | |
| | medium_price_discrepancy | medium | β | | |
| | medium_split_delivery | medium | β | | |
| | medium_vendor_mismatch | medium | β | | |
| | hard_policy_violation | hard | 0.010 | | |
| | hard_duplicate_invoice | hard | 0.010 | | |
| | hard_partial_po_match | hard | β | | |
| | hard_tax_discrepancy | hard | β | | |
| > Partial results from the Run 1 pre-training evaluation (seeds 99 only). Full 3-seed baseline generated by `training/eval_baseline.py`. Hard multi-step tasks score near 0.01 β the model cannot discover the ESCALATEβREJECT / QUERY_VENDORβREJECT sequences without training. | |
| #### Optimal Ceiling β scripted agent (all 20 tasks) | |
|  | |
| #### Optimal Ceiling vs Untrained Llama-3-8B (per task) | |
|  | |
| #### Untrained Qwen2.5-7B-Instruct baseline (17 tasks, 3 seeds each) | |
|  | |
| | Task Category | Optimal Ceiling | Untrained Llama-3-8B | Untrained Qwen2.5-7B | After GRPO 3ep | | |
| |---|---|---|---|---| | |
| | Easy (2 tasks) | **0.990** | **0.990** | **0.721** | **0.990** | | |
| | Medium (4 tasks) | **0.907** | **0.712** | **0.691** | **0.860** | | |
| | Hard (4 tasks) | **0.843** | **0.698** | **0.468** | β | | |
| | Long-horizon (7 tasks) | **0.989** | **0.832** | **0.432** | β | | |
| | **Overall** | **0.921** | **0.811** | **0.535** | β | | |
| > **Optimal ceiling** β a hardcoded scripted agent (`baseline.py`) that applies the exact correct rule for every task. Not 1.0 because explanation quality, seed-dependent actor responses, and partial-credit graders penalise even perfect decisions. | |
| > | |
| > **Untrained Llama-3-8B** β `meta-llama/Meta-Llama-3-8B-Instruct` with no fine-tuning. Scores 0.811 overall but drops to 0.698 on hard tasks. | |
| > | |
| > **Untrained Qwen2.5-7B** β `Qwen/Qwen2.5-7B-Instruct` before GRPO, 17 tasks Γ 3 seeds. Mean 0.535 overall; 7/51 parse failures. Hard tasks (0.468) and long-horizon tasks (0.432) near floor β multi-step sequences undiscovered without training. | |
| > | |
| > **After GRPO** β Qwen2.5-7B after 3 epochs. Easy tasks match the ceiling. Hard multi-step tasks need more epochs. | |
| > | |
| > Detailed breakdowns: [`runs/baselines/qwen2-5-7b-instruct-2026-04-25/`](runs/baselines/qwen2-5-7b-instruct-2026-04-25/) | [`runs/baselines/scripted-agent-2026-04-25/`](runs/baselines/scripted-agent-2026-04-25/) | [`runs/grpo/qwen-2.5-7b-3ep-2026-04-25/`](runs/grpo/qwen-2.5-7b-3ep-2026-04-25/) | |
| --- | |
| ## Why It Matters | |
| Enterprise AP automation is a $10B+ market. Current LLM deployments fail silently β a model that confidently approves a duplicate invoice looks identical to one that correctly rejects it, until the reconciliation audit three months later. | |
| The reward signal in AP Commander is specifically engineered to close the shortcuts an untrained model exploits: | |
| - **3-way matching**: Invoice β PO β GRN β amounts, quantities, vendor names must all align | |
| - **Policy compliance**: Freight caps, approval authority limits, and tax rates change per episode; the agent must read policy, not memorise it | |
| - **Multi-step investigation**: `QUERY_VENDOR β ESCALATE β REJECT` is rewarded; skipping to `REJECT` without the investigation is not | |
| - **Scalable oversight**: A second agent monitors completed clerk decisions, flags fraud with numeric evidence, and is penalised for false positives β making oversight trainable, not just bolted on | |
| An agent cannot score well by guessing. It must cite specific dollar amounts, choose the correct reason code, and follow the right sequence. There is no shortcut. | |
| --- | |
| ## Environment Design | |
| ### Reward Signal (AP Clerk) | |
| Scores are partial-credit across five components β composable, not monolithic: | |
| | Component | Weight | What it measures | | |
| |---|---|---| | |
| | Decision accuracy | 38β55% | Correct terminal action | | |
| | Amount accuracy | 20β45% | Within 1% = full credit, within 8% = partial | | |
| | Reason code | 10β30% | Correct classification of why | | |
| | Explanation quality | 10β20% | Specific $ / % citations required | | |
| | Process bonus | 0β15% | Correct intermediate steps before terminal | | |
| An agent that always outputs `APPROVE_FULL` at $0 scores near zero. An agent that gets the decision right but cites the wrong amount scores ~0.40. Full credit requires all five. | |
| ### Reward Signal (Oversight Agent) | |
| | Condition | Score | | |
| |---|---| | |
| | Correctly flag fraudulent episode with numeric evidence | +0.90 | | |
| | Flag fraudulent episode without specific signal | +0.70 | | |
| | False positive (flag a clean episode) | β0.25 | | |
| | Correctly clear a clean episode | +0.01 | | |
| ### Task Library (24 tasks) | |
| **Easy / Medium / Hard (13 tasks, max 1β3 steps)** | |
| | Task | Difficulty | Correct Decision | | |
| |---|---|---| | |
| | `easy_perfect_match` | easy | APPROVE_FULL | | |
| | `easy_no_po_found` | easy | REJECT | | |
| | `medium_quantity_shortfall` | medium | APPROVE_PARTIAL | | |
| | `medium_price_discrepancy` | medium | REJECT | | |
| | `medium_split_delivery` | medium | APPROVE_FULL | | |
| | `medium_vendor_mismatch` | medium | REJECT | | |
| | `hard_policy_violation` | hard | ESCALATE β REJECT | | |
| | `hard_duplicate_invoice` | hard | QUERY_VENDOR β REJECT | | |
| | `hard_partial_po_match` | hard | APPROVE_PARTIAL | | |
| | `hard_tax_discrepancy` | hard | REJECT | | |
| | `hard_currency_conversion` | hard | APPROVE_FULL or REJECT | | |
| | `hard_manager_preapproval` | hard | ESCALATE β APPROVE_FULL | | |
| | `hard_credit_memo` | hard | APPROVE_PARTIAL or REJECT | | |
| **Long-horizon (7 tasks, max 10β16 steps)** | |
| | Task | Steps | Optimal Sequence | | |
| |---|---|---| | |
| | `long_invoice_dispute` | 12 | QUERY_VENDOR β ESCALATE β REJECT | | |
| | `long_policy_migration` | 10 | HOLD β compliance reveals new cap β APPROVE_FULL | | |
| | `long_batch_reconciliation` | 15 | 3-way match in batch context β APPROVE_FULL | | |
| | `long_manager_chain` | 14 | ESCALATE (OOO) β ESCALATE again (VP) β APPROVE_FULL | | |
| | `long_fraud_investigation` | 16 | QUERY_VENDOR β ESCALATE β REJECT | | |
| | `long_audit_trail` | 14 | HOLD β SOX review β APPROVE_FULL with citations | | |
| | `long_multi_vendor_split` | 12 | 3 GRNs, first tranche only β APPROVE_PARTIAL | | |
| **Oversight tasks (4 tasks, via `/oversight/*`)** | |
| `oversight_fraud_detection` Β· `oversight_pattern_recognition` Β· `oversight_false_positive_trap` Β· `oversight_explanation_quality` | |
| ### Adaptive Curriculum | |
| ``` | |
| easy (mean β₯ 0.70) β medium (β₯ 0.65) β hard (β₯ 0.68) β long-horizon (β₯ 0.72) β oversight | |
| ``` | |
| The `/curriculum/next_task` endpoint tracks performance history and recommends the next task automatically. No manual task selection needed during training. | |
| --- | |
| ## Training | |
| **Algorithm:** GRPO (Group Relative Policy Optimization) | |
| **Model:** Qwen2.5-7B-Instruct, 4-bit NF4 quantized, LoRA (r=16) via PEFT | |
| **Framework:** TRL β₯ 0.15 (standard stack β Unsloth dropped due to Python 3.10 / llm_blender dependency conflict on HF Spaces) | |
| **Environment:** Live HF Space serves rewards over HTTP β no static dataset | |
| ``` | |
| HF Training Space (A10G) HF Environment Space | |
| ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ | |
| β Qwen2.5-7B + LoRA ββ(HTTP)βΊβ AP Commander FastAPI server β | |
| β GRPOTrainer ββrewardββ 24 tasks Β· graders Β· actors β | |
| β [env_reward, fmt_reward]β β seeded RNG Β· no static data β | |
| ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ | |
| ``` | |
| ### How it works | |
| 1. **Two independent reward functions** (guide requirement: multiple signals, not one combined): | |
| - `env_reward_fn` β calls `/reset` + `/step` on the live environment, returns the grader score (0.01β0.99) | |
| - `format_reward_fn` β checks JSON validity and enum values (+0.05 / β0.05), independent of task correctness | |
| 2. **Dataset** β built at runtime by calling `/reset` for each task Γ seed combination. No static dataset; every prompt is a fresh synthetically-generated invoice scenario. Run 3: 322 prompts (easyΓ5, mediumΓ8, hardΓ20, longΓ20 seeds across 20 tasks). | |
| 3. **GRPO loop** β for each prompt, 16 completions are sampled. The two reward functions score them independently. Group-relative advantages drive the policy update. `per_device_train_batch_size = num_generations = 16` (TRL requirement). | |
| 4. **Reward hacking mitigations** already in the environment: | |
| - `_explanation_coherence()` penalises keyword dumps (>40% keyword density) | |
| - `_has_numeric_citation()` requires actual dollar amounts, not vague language | |
| - Forged curriculum rejected β server-side history only | |
| - Oversight false-positive penalty is real negative (β0.25), not clamped to zero | |
| 5. **Model save** β LoRA adapters saved directly (4-bit model, no naive upcast merge per guide point 16). Adapters uploaded to `Pathikreet/ap-commander-adapter` on HF Hub after each run. Run artifacts auto-uploaded to `runs/grpo/MODEL-NEP-DATETIME/` in this repo β each run gets its own folder, nothing is overwritten. | |
| ### Monitoring tracked per step | |
| `reward` Β· `format_rate` Β· `parse_failures` Β· `env_errors` Β· `decision_counts` Β· `per_task_mean` Β· `elapsed_min` β written to `metrics_live.json` every reward call; Gradio UI polls every 15s. | |
| The training Space is at `Pathikreet/ap-commander-training`. Open it, paste your HF token (needed for gated models like Llama-3), and click Start Training. The notebook at [`training/colab_training.ipynb`](training/colab_training.ipynb) uses the identical training loop for Colab (T4 GPU). | |
| --- | |
| ## API Reference | |
| ### AP Clerk | |
| | Endpoint | Method | Description | | |
| |---|---|---| | |
| | `/reset` | POST | Start episode: `{ task_id, seed? }` | | |
| | `/step` | POST | Submit action: `{ session_id, action }` | | |
| | `/state` | GET | Session state: `?session_id=...` | | |
| ### Oversight Agent | |
| | Endpoint | Method | Description | | |
| |---|---|---| | |
| | `/oversight/reset` | POST | Start batch: `{ num_episodes?, seed? }` | | |
| | `/oversight/step` | POST | Submit verdict: `{ session_id, action }` | | |
| | `/oversight/state` | GET | Session state | | |
| ### Curriculum + Meta | |
| | Endpoint | Method | Description | | |
| |---|---|---| | |
| | `/curriculum/next_task` | POST | Get next task given session history | | |
| | `/tasks` | GET | List all 24 tasks | | |
| | `/health` | GET | Health check | | |
| | `/docs` | GET | Swagger UI | | |
| --- | |
| ## Run It | |
| ```bash | |
| # Local environment server | |
| pip install -r requirements.txt | |
| uvicorn app.main:app --host 0.0.0.0 --port 7860 | |
| # Docker | |
| docker build -t ap-commander . | |
| docker run -p 7860:7860 ap-commander | |
| # Optimal scripted-agent baseline (all 20 tasks β runs/baselines/scripted-agent-DATETIME/) | |
| python baseline.py | |
| # LLM baseline β untrained model eval (GPU required, run on HF Space or Colab) | |
| # Results β runs/baselines/MODEL-DATETIME/ | |
| MODEL_NAME=Qwen/Qwen2.5-7B-Instruct HF_TOKEN=hf_... python training/eval_baseline.py | |
| # GRPO training (GPU required) | |
| # Results β runs/grpo/MODEL-NEP-DATETIME/ | |
| MODEL_NAME=Qwen/Qwen2.5-7B-Instruct NUM_EPOCHS=3 HF_TOKEN=hf_... python training/train.py | |
| ``` | |
| --- | |
| ## Project Structure | |
| ``` | |
| βββ app/ | |
| β βββ main.py # FastAPI: all endpoints | |
| β βββ environment.py # APClerkEnvironment: reset/step/state | |
| β βββ tasks.py # 24 task generators + graders | |
| β βββ models.py # Pydantic models | |
| β βββ actors/ | |
| β βββ vendor_actor.py # VendorActor (honest/fraudulent/confused) | |
| β βββ manager_actor.py # ManagerActor (budget authority, OOO chain) | |
| β βββ compliance_actor.py # ComplianceActor (SOX/GDPR/Internal Policy) | |
| βββ oversight_environment.py # Fleet AI OversightEnvironment | |
| βββ training/ | |
| β βββ train.py # GRPO training script (TRL, 4-bit, LoRA) | |
| β βββ eval_baseline.py # LLM baseline eval (no fine-tuning) | |
| β βββ colab_training.ipynb # Colab notebook (identical pipeline) | |
| βββ runs/ | |
| β βββ baselines/ | |
| β β βββ scripted-agent-YYYY-MM-DD/ # Optimal scripted agent results | |
| β β βββ qwen2.5-7b-instruct-*/ # Untrained Qwen eval | |
| β β βββ llama-3-8b-*/ # Untrained Llama eval | |
| β βββ grpo/ | |
| β βββ MODEL-NEP-YYYY-MM-DD_HHMM/ # Each GRPO run (timestamped, never overwritten) | |
| β βββ training_results.json | |
| β βββ results.png | |
| β βββ reward_curve.png | |
| β βββ metrics_live.json | |
| β βββ adapter/ # LoRA weights (also on HF Hub) | |
| βββ baseline.py # Scripted optimal agent (saves to runs/baselines/) | |
| βββ inference.py # LLM inference runner | |
| βββ sim_run.py # Demo all tasks | |
| βββ openenv.yaml # Environment manifest | |
| βββ Dockerfile | |
| ``` | |