Spaces:
Runtime error
Runtime error
Avi-17 commited on
Commit Β·
cbd6ebe
1
Parent(s): 2fb15fb
readme modified
Browse files- README.md +304 -71
- server/client.py +7 -1
README.md
CHANGED
|
@@ -15,89 +15,322 @@ tags:
|
|
| 15 |
|
| 16 |
# Cashflow Multi-Agent RL Environment
|
| 17 |
|
| 18 |
-
A high-fidelity business simulation
|
| 19 |
|
| 20 |
-
|
| 21 |
-
- **Theme #1: Multi-Agent Interactions**: Features Expenditure, Revenue, Risk, and Vendor agents.
|
| 22 |
-
- **Theme #3.1: World Modeling / Professional Tasks**: Models complex cash-flow workflows with real tools (negotiation, credit lines).
|
| 23 |
-
- **Outcome**: A realistic environment for training a "CFO LLM" to manage company finances.
|
| 24 |
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
```mermaid
|
| 28 |
graph TD
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
CFO[CFO Agent - RL Trained]
|
| 49 |
-
end
|
| 50 |
-
|
| 51 |
-
HW --> ENV
|
| 52 |
-
ENV -->|Partial Obs| EXP
|
| 53 |
-
ENV -->|Partial Obs| REV
|
| 54 |
-
ENV -->|Partial Obs| RSK
|
| 55 |
-
EXP -->|Memo| CFO
|
| 56 |
-
REV -->|Memo| CFO
|
| 57 |
-
RSK -->|Memo| CFO
|
| 58 |
-
CFO -->|Action: Pay/Negotiate| ENV
|
| 59 |
-
ENV -->|Negotiation Call| VND
|
| 60 |
-
VND -->|Response| ENV
|
| 61 |
-
ENV -->|Reward| CFO
|
| 62 |
```
|
| 63 |
|
| 64 |
-
|
| 65 |
|
| 66 |
-
|
| 67 |
-
- `server/cashflowmanager_environment.py`: Core logic for `reset()`, `step()`, and `state()`.
|
| 68 |
-
- `server/data_generator.py`: Synthetic JSON generator for realistic financial scenarios.
|
| 69 |
-
- `server/agents.py`: System prompts and logic for advisory/vendor agents.
|
| 70 |
-
- `scripts/train_sft.py`: Training script for sub-agents using **Unsloth**.
|
| 71 |
-
- `scripts/train_rl.py`: RL training pipeline for the CFO using **HF TRL**.
|
| 72 |
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
```
|
| 79 |
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
```bash
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
```
|
| 84 |
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
#
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
# Cashflow Multi-Agent RL Environment
|
| 17 |
|
| 18 |
+
A high-fidelity business simulation in which an AI agent plays the **CFO** of a company, deciding which invoices to pay, defer, negotiate, or settle on credit each day β under partial observability and a probabilistic world model that can throw cash shocks, payment delays, and audits at it without warning.
|
| 19 |
|
| 20 |
+
Built on top of **OpenEnv**, with a Gradio dashboard for inspection and a multi-agent advisory system (Expenditure / Revenue / Risk β CFO).
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## Quick start
|
| 25 |
+
|
| 26 |
+
```bash
|
| 27 |
+
# 1. Install
|
| 28 |
+
pip install -r requirements.txt
|
| 29 |
+
|
| 30 |
+
# 2. Configure API keys (see "Environment variables" below)
|
| 31 |
+
cp .env.example .env # then edit
|
| 32 |
+
|
| 33 |
+
# 3. Run the server (Gradio dashboard + OpenEnv HTTP endpoints)
|
| 34 |
+
python -m server.app
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
The dashboard is at <http://0.0.0.0:7860/ui>. OpenEnv endpoints (`/reset`, `/step`, `/state`) are mounted on the same FastAPI app.
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
## UI navigation
|
| 42 |
+
|
| 43 |
+
The dashboard has a sidebar (settings + actions) and three tabs in the main panel.
|
| 44 |
+
|
| 45 |
+
### Sidebar β Settings & Actions
|
| 46 |
+
|
| 47 |
+
- **Difficulty**: `easy` / `medium` / `hard`. Controls starting cash, invoice density, interest rates, and receivable reliability.
|
| 48 |
+
- **Seed**: `0` for a random scenario, or a fixed integer for reproducibility.
|
| 49 |
+
- **Preview Scenario** β peek at the initial state without running.
|
| 50 |
+
- **Run Full Simulation** β execute the entire `sim_window` end-to-end.
|
| 51 |
+
- **Start New / Next Day** β initialize a day-by-day run and step through it manually.
|
| 52 |
+
- **Theme toggle** (top-right `π`) β switches between dark and light mode. Buttons stay blue regardless.
|
| 53 |
+
|
| 54 |
+
### Tab 1 β Full Simulation
|
| 55 |
+
|
| 56 |
+
Runs every day in one shot. Two columns:
|
| 57 |
+
|
| 58 |
+
- **Left**: Simulation Summary table (final cash, credit used, invoices paid, late fees, etc.).
|
| 59 |
+
- **Right**: Day-by-Day Metrics chart, an Agent Score banner (with letter grade), and a per-dimension score breakdown.
|
| 60 |
+
|
| 61 |
+
### Tab 2 β Day-by-Day
|
| 62 |
+
|
| 63 |
+
Manually step through the simulation one day at a time.
|
| 64 |
+
|
| 65 |
+
- **Left**: Status table after the most recent day.
|
| 66 |
+
- **Right**: Running Metrics table that grows row-by-row. When the sim completes, the score banner + breakdown appear directly below it.
|
| 67 |
+
|
| 68 |
+
### Tab 3 β Logs
|
| 69 |
+
|
| 70 |
+
A scrollable log of every day, rendered as **cards** with rounded backgrounds and a blue accent border. Each card contains:
|
| 71 |
+
|
| 72 |
+
- Opening cash / credit balance and invoice counts.
|
| 73 |
+
- World events triggered that day (cash shocks, payment delays, etc.).
|
| 74 |
+
- Each advisor's memo, formatted as a blockquote.
|
| 75 |
+
- The CFO's action plan, one line per invoice with an icon for the action type.
|
| 76 |
+
- Closing balances, reward, late fees, and interest.
|
| 77 |
+
|
| 78 |
+
Page-level scrolling is locked β only the logs container scrolls internally, so the sidebar and tab headers stay visible.
|
| 79 |
+
|
| 80 |
+
---
|
| 81 |
+
|
| 82 |
+
## Simulation logic
|
| 83 |
+
|
| 84 |
+
A simulation is a sequence of `sim_window` business days (default `3`). Each day follows the same fixed cycle:
|
| 85 |
+
|
| 86 |
+
```
|
| 87 |
+
Day N:
|
| 88 |
+
1. Activate any incoming invoices scheduled to appear today
|
| 89 |
+
2. Age all unpaid invoices (decrement due_in; mark overdue if past 0)
|
| 90 |
+
3. Collect receivables expected today (probability roll per receivable)
|
| 91 |
+
4. Decide actions:
|
| 92 |
+
(a) Fast path β rule-based, no LLM
|
| 93 |
+
(b) Full path β three advisors in parallel + CFO sequentially
|
| 94 |
+
5. Apply CFO actions (pay / partial / credit / defer)
|
| 95 |
+
6. Charge daily interest on remaining balances
|
| 96 |
+
7. Trigger world events for the day (shocks, delays, fraud, revenue miss)
|
| 97 |
+
8. Compute reward via CashflowRubric β write DayLog
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
### State the CFO sees
|
| 101 |
+
|
| 102 |
+
| Component | Description |
|
| 103 |
+
|---|---|
|
| 104 |
+
| **Cash** | Current balance. Can go negative up to `-credit_limit` before bankruptcy. |
|
| 105 |
+
| **Active Invoices** | Vendor bills with `amount`, `due_in`, `late_fee`, `interest`, `status`. |
|
| 106 |
+
| **Receivables** | Expected customer payments with `expected_in` day and arrival `probability`. |
|
| 107 |
+
| **Credit** | A fixed credit line. Drawing on it boosts cash now but hurts the final score. |
|
| 108 |
+
| **Vendor Profiles** | `trust_score` and `negotiation_flexibility`, used by the `negotiate` action. |
|
| 109 |
+
| **Advisor Memos** | Structured notes from Expenditure / Revenue / Risk agents. |
|
| 110 |
+
| **World Events** | Hidden, probabilistic shocks. The CFO doesn't see them in advance β only the Risk agent gets vague hints (`market_stress`, `upcoming_risk_level`). |
|
| 111 |
+
|
| 112 |
+
### World model β hidden dynamics
|
| 113 |
+
|
| 114 |
+
A `WorldModel` instance is initialized per scenario and generates a private timeline of events:
|
| 115 |
+
|
| 116 |
+
- **Cash shocks** β equipment failure, tax audits, regulatory fines, supplier hikes (8β25% of starting cash each).
|
| 117 |
+
- **Payment delays** β receivables get pushed out by 1β3 days.
|
| 118 |
+
- **Revenue miss** β raises market stress for subsequent days.
|
| 119 |
+
- **Fraud anomalies** β rare, scaled-down cash deductions.
|
| 120 |
+
|
| 121 |
+
Events fire *after* CFO actions each day (the agent decides without seeing tomorrow's shock). The Risk Agent receives partial hints via `world_model.get_risk_hints(day)` so it can warn the CFO of elevated stress without revealing exact amounts.
|
| 122 |
+
|
| 123 |
+
### Dynamic data generation
|
| 124 |
+
|
| 125 |
+
Every scenario is fresh β no fixed test set. The generator:
|
| 126 |
+
|
| 127 |
+
1. Samples vendors, invoices, receivables, and incoming-invoice timelines based on difficulty.
|
| 128 |
+
2. Runs a **solvability check** to guarantee the agent has a feasible path to break-even, then applies a difficulty-specific buffer.
|
| 129 |
+
3. Hands the scenario to the env, which wraps it in a `CashflowmanagerObservation` and a `WorldModel`.
|
| 130 |
+
|
| 131 |
+
| Difficulty | Cash | Credit | Invoices | Receivables |
|
| 132 |
+
|---|---|---|---|---|
|
| 133 |
+
| `easy` | βΉ40kβ50k | βΉ20k | 3β4 | 3β4 (85β95% prob) |
|
| 134 |
+
| `medium` | βΉ25kβ35k | βΉ10k | 4β6 | 2β3 (70β85% prob) |
|
| 135 |
+
| `hard` | βΉ2kβ5k | βΉ2k | 6β8 | 2β3 (60β80% prob) |
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
## Multi-agent architecture
|
| 140 |
|
| 141 |
```mermaid
|
| 142 |
graph TD
|
| 143 |
+
WM[World Model<br/>hidden events]
|
| 144 |
+
ENV[CashflowmanagerEnvironment]
|
| 145 |
+
EXP[Expenditure Agent<br/>llama-3.1-8b key=0]
|
| 146 |
+
REV[Revenue Agent<br/>llama-3.1-8b key=1]
|
| 147 |
+
RSK[Risk Agent<br/>llama-3.1-8b key=2]
|
| 148 |
+
CFO[CFO Agent<br/>llama-3.1-8b key=2]
|
| 149 |
+
GRADIO[Gradio Dashboard /ui]
|
| 150 |
+
HTTP[OpenEnv /reset /step /state]
|
| 151 |
+
|
| 152 |
+
WM --> ENV
|
| 153 |
+
ENV -->|partial obs| EXP
|
| 154 |
+
ENV -->|partial obs| REV
|
| 155 |
+
ENV -->|partial obs + risk hints| RSK
|
| 156 |
+
EXP -->|memo| CFO
|
| 157 |
+
REV -->|memo| CFO
|
| 158 |
+
RSK -->|memo| CFO
|
| 159 |
+
CFO -->|actions| ENV
|
| 160 |
+
ENV --> GRADIO
|
| 161 |
+
ENV --> HTTP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
```
|
| 163 |
|
| 164 |
+
The three advisors run **in parallel** via `ThreadPoolExecutor(max_workers=3)`. The CFO runs sequentially after all three memos arrive, on the Risk agent's key (since Risk has the smallest prompt β most leftover TPM headroom).
|
| 165 |
|
| 166 |
+
### Agent roles
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
|
| 168 |
+
| Agent | Reads | Outputs |
|
| 169 |
+
|---|---|---|
|
| 170 |
+
| **Expenditure** | Active invoices, cash | Payment priority list, critical-invoice flags, recommended action |
|
| 171 |
+
| **Revenue** | Receivables, expected timing | Total expected inflow, reliable vs at-risk receivables, 3-day cash projection |
|
| 172 |
+
| **Risk** | Debt-to-cash ratio, credit util, market stress hints | Risk level (low/moderate/elevated/critical), recommended cash buffer, threats |
|
| 173 |
+
| **CFO** | Full state, history, advisor memos, invoice list | One action per invoice with a confidence score |
|
| 174 |
|
| 175 |
+
---
|
| 176 |
+
|
| 177 |
+
## Reward & scoring
|
| 178 |
+
|
| 179 |
+
Two distinct concepts:
|
| 180 |
+
|
| 181 |
+
### Per-step reward β OpenEnv `Rubric` pattern
|
| 182 |
+
|
| 183 |
+
`CashflowRubric` plugs into `Environment.rubric` and composes independently-weighted sub-rubrics rather than collapsing reward into a single scalar:
|
| 184 |
+
|
| 185 |
+
- on-time payment bonus
|
| 186 |
+
- late-fee / interest penalty
|
| 187 |
+
- credit-draw penalty
|
| 188 |
+
- cash-buffer health
|
| 189 |
+
|
| 190 |
+
This avoids the monolithic-reward trap where one number accidentally rewards the wrong behavior (e.g. an agent that hoards cash to dodge fees but never pays anyone). With independent components, you can see which signal is dominating and tune weights surgically.
|
| 191 |
+
|
| 192 |
+
### End-of-simulation score β five dimensions
|
| 193 |
+
|
| 194 |
+
| Dimension | Weight | Question |
|
| 195 |
+
|---|---|---|
|
| 196 |
+
| Solvency | 25% | Did the company survive without going deeply negative? |
|
| 197 |
+
| Debt Clearance | 30% | What fraction of invoices were fully paid? |
|
| 198 |
+
| Fiscal Discipline | 20% | Were late fees + interest avoided? |
|
| 199 |
+
| Credit Prudence | 10% | Was the credit line used sparingly? |
|
| 200 |
+
| Cash Management | 15% | Did the agent end with more cash than it started? |
|
| 201 |
+
|
| 202 |
+
Final score in `[0, 1]` plus a letter grade (A β₯ 0.90, B β₯ 0.75, C β₯ 0.55, D β₯ 0.35, F otherwise).
|
| 203 |
+
|
| 204 |
+
---
|
| 205 |
+
|
| 206 |
+
## OpenEnv integration
|
| 207 |
+
|
| 208 |
+
The FastAPI app is built via OpenEnv's `create_app(...)` factory:
|
| 209 |
+
|
| 210 |
+
```python
|
| 211 |
+
from openenv.core.env_server.http_server import create_app
|
| 212 |
+
from server.cashflowmanager_environment import (
|
| 213 |
+
CashflowmanagerEnvironment,
|
| 214 |
+
CashflowmanagerAction,
|
| 215 |
+
CashflowmanagerObservation,
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
+
app = create_app(
|
| 219 |
+
CashflowmanagerEnvironment,
|
| 220 |
+
CashflowmanagerAction,
|
| 221 |
+
CashflowmanagerObservation,
|
| 222 |
+
env_name="cashflowmanager",
|
| 223 |
+
max_concurrent_envs=1,
|
| 224 |
+
)
|
| 225 |
```
|
| 226 |
|
| 227 |
+
This automatically wires `/reset`, `/step`, and `/state` HTTP endpoints. The Gradio dashboard mounts on top via `gr.mount_gradio_app(app, ..., path="/ui")`.
|
| 228 |
+
|
| 229 |
+
A remote client can drive the env via `server/client.py`, which extends `openenv.core.EnvClient`.
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## Performance optimizations
|
| 234 |
+
|
| 235 |
+
The ICL flow makes 4 LLM calls per complex day. Without optimization, that easily blows past Groq's free-tier rate limits. The following changes brought a 3-day hard-difficulty sim down to ~10s with zero rate-limit failures.
|
| 236 |
+
|
| 237 |
+
### 1. Rule-based fast path
|
| 238 |
+
|
| 239 |
+
`_try_fast_path()` short-circuits the LLM entirely on trivial days (no overdue invoices, β€3 unpaid bills, enough cash to cover all). On easy / medium difficulty, this skips 30β50% of LLM calls.
|
| 240 |
+
|
| 241 |
+
### 2. Slim prompts
|
| 242 |
+
|
| 243 |
+
Advisor prompts no longer include `serialize_history(past_logs)` (only the CFO does). Each advisor receives a minimal one-line state header plus its own data slice. Prompt size dropped ~55% per call, eliminating `json_validate_failed` truncation errors.
|
| 244 |
+
|
| 245 |
+
### 3. Parallel advisors
|
| 246 |
+
|
| 247 |
+
The three advisors run concurrently via `ThreadPoolExecutor(max_workers=3)`. Per-day wall-clock dropped from ~12s (sequential) to ~4s.
|
| 248 |
+
|
| 249 |
+
### 4. Multi-account API keys
|
| 250 |
+
|
| 251 |
+
Groq's free tier rate-limits at the **organization** level (~6,000 TPM for `llama-3.1-8b-instant`). Multiple keys from the same account share one bucket β they don't multiply capacity.
|
| 252 |
+
|
| 253 |
+
The fix: three keys from **three separate Groq accounts**, with per-agent key isolation (Expenditure β key 0, Revenue β key 1, Risk β key 2, CFO β reuses key 2). Triples the effective TPM ceiling.
|
| 254 |
+
|
| 255 |
+
---
|
| 256 |
+
|
| 257 |
+
## Environment variables
|
| 258 |
+
|
| 259 |
+
Set these in `.env` (or pass at the shell):
|
| 260 |
+
|
| 261 |
```bash
|
| 262 |
+
# API key (single-key mode β fallback)
|
| 263 |
+
GROQ_API_KEY=gsk_...
|
| 264 |
+
|
| 265 |
+
# Multi-key pool (recommended). Comma-separated, no quotes around individual keys.
|
| 266 |
+
# These MUST be from 3 separate Groq accounts to actually multiply TPM.
|
| 267 |
+
GROQ_API_KEYS=gsk_key1,gsk_key2,gsk_key3
|
| 268 |
+
|
| 269 |
+
# Models
|
| 270 |
+
MODEL_NAME=llama-3.1-8b-instant
|
| 271 |
+
CFO_MODEL_NAME=llama-3.1-8b-instant
|
| 272 |
+
ADVISOR_MODEL_NAME=llama-3.1-8b-instant
|
| 273 |
+
EXPENDITURE_MODEL_NAME=llama-3.1-8b-instant
|
| 274 |
+
REVENUE_MODEL_NAME=llama-3.1-8b-instant
|
| 275 |
+
RISK_MODEL_NAME=llama-3.1-8b-instant
|
| 276 |
+
|
| 277 |
+
# Per-agent key indices (override if you have a different mapping)
|
| 278 |
+
EXPENDITURE_KEY_INDEX=0
|
| 279 |
+
REVENUE_KEY_INDEX=1
|
| 280 |
+
RISK_KEY_INDEX=2
|
| 281 |
+
CFO_KEY_INDEX=2
|
| 282 |
+
|
| 283 |
+
# Confidence gate threshold (currently informational)
|
| 284 |
+
CFO_CONFIDENCE_THRESHOLD=0.85
|
| 285 |
+
|
| 286 |
+
# Retry / timeout knobs
|
| 287 |
+
LLM_MAX_RETRIES=5
|
| 288 |
+
LLM_TIMEOUT_SECONDS=20
|
| 289 |
+
|
| 290 |
+
# Set to "true" to load a local Hugging Face model instead of hitting Groq
|
| 291 |
+
USE_LOCAL_HF=false
|
| 292 |
+
LOCAL_MODEL_PATH=unsloth/Llama-3.2-1B-Instruct
|
| 293 |
```
|
| 294 |
|
| 295 |
+
---
|
| 296 |
+
|
| 297 |
+
## Project structure
|
| 298 |
+
|
| 299 |
+
```
|
| 300 |
+
cashflow manager/
|
| 301 |
+
βββ server/
|
| 302 |
+
β βββ app.py # FastAPI + Gradio dashboard, mounts on /ui
|
| 303 |
+
β βββ cashflowmanager_environment.py # CashflowmanagerEnvironment class + sim loop
|
| 304 |
+
β βββ agents.py # Advisor + CFO prompts, per-agent key indices
|
| 305 |
+
β βββ client.py # Groq/OpenAI client wrapper, multi-key parsing
|
| 306 |
+
β βββ data_generator.py # Dynamic scenario generation
|
| 307 |
+
β βββ world_model.py # Hidden event timeline + risk hints
|
| 308 |
+
β βοΏ½οΏ½β reward.py # CashflowRubric (OpenEnv Rubric pattern)
|
| 309 |
+
β βββ scoring.py # End-of-sim five-dimension score
|
| 310 |
+
β βββ state_serializer.py # Prompt-friendly state / history formatters
|
| 311 |
+
β βββ tasks.py
|
| 312 |
+
βββ models.py # Pydantic models (Action, Observation, Invoice, ...)
|
| 313 |
+
βββ inference.py # Single-episode CLI runner that writes transitions.jsonl
|
| 314 |
+
βββ client.py # OpenEnv EnvClient subclass for remote use
|
| 315 |
+
βββ scripts/
|
| 316 |
+
β βββ train_sft.py # SFT training (Unsloth)
|
| 317 |
+
β βββ train_rl.py # RL training (HF TRL)
|
| 318 |
+
β βββ generate_sft_data.py # Expert demonstration data
|
| 319 |
+
β βββ generate_rl_transitions.py # RL transition generator
|
| 320 |
+
βββ data/ # Generated SFT datasets (gitignored)
|
| 321 |
+
βββ images_blog/ # Diagrams used by the blog post
|
| 322 |
+
βββ .env # API keys + model config (gitignored)
|
| 323 |
+
```
|
| 324 |
+
|
| 325 |
+
---
|
| 326 |
+
|
| 327 |
+
## Training pipeline (offline)
|
| 328 |
+
|
| 329 |
+
The runtime app uses ICL only. Training scripts live in `scripts/` and are run separately (typically in Colab / Kaggle for the GPU access):
|
| 330 |
+
|
| 331 |
+
- **SFT** β `scripts/train_sft.py` fine-tunes per-agent SFT models on `data/{agent}_sft.jsonl`. Uses Unsloth for 4-bit quantization.
|
| 332 |
+
- **RL** β `scripts/train_rl.py` runs PPO on top of the SFT-tuned CFO using `transitions.jsonl` from `inference.py`.
|
| 333 |
+
|
| 334 |
+
Set `USE_LOCAL_HF=true` and `LOCAL_MODEL_PATH=...` to point the runtime at a fine-tuned model instead of Groq.
|
| 335 |
+
|
| 336 |
+
---
|
server/client.py
CHANGED
|
@@ -2,7 +2,6 @@ import os
|
|
| 2 |
import json
|
| 3 |
import random
|
| 4 |
import sys
|
| 5 |
-
import torch
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
import time as _time
|
| 8 |
|
|
@@ -19,6 +18,13 @@ try:
|
|
| 19 |
except ImportError:
|
| 20 |
OpenAI = None
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
try:
|
| 23 |
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
| 24 |
except ImportError:
|
|
|
|
| 2 |
import json
|
| 3 |
import random
|
| 4 |
import sys
|
|
|
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
import time as _time
|
| 7 |
|
|
|
|
| 18 |
except ImportError:
|
| 19 |
OpenAI = None
|
| 20 |
|
| 21 |
+
# torch + transformers are only needed when USE_LOCAL_HF=true. Keep them
|
| 22 |
+
# optional so the production Groq-API path doesn't pull in a multi-GB dep.
|
| 23 |
+
try:
|
| 24 |
+
import torch
|
| 25 |
+
except ImportError:
|
| 26 |
+
torch = None
|
| 27 |
+
|
| 28 |
try:
|
| 29 |
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
| 30 |
except ImportError:
|