File size: 12,924 Bytes
c3c368c
ea9e5f8
 
 
 
c3c368c
ea9e5f8
 
c3c368c
 
ea9e5f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
---
title: Closed-Form RAG API
emoji: 🧮
colorFrom: gray
colorTo: blue
sdk: docker
app_port: 7860
short_description: Closed-form, LLM-free routing for agentic RAG APIs
---

# Closed-Form Agentic RAG — Docker API

**A runnable FastAPI gateway, not an LLM model checkpoint.** The controller scores
calibrated macro-actions in **O(number of actions)** time. The inference calls
are made against external OpenAI-compatible chat APIs: HF Inference Providers,
HF Inference Endpoints, vLLM, TGI, an appropriately configured provider gateway,
etc. The Docker Space needs **no GPU**, even when the remote models are 8B,
32B, 70B or larger.

> Scientific qualification: This is a finite contextual macro-action relaxation
> of the full POMDP. There is **no claim of globally optimal POMDP planning** or
> of superior accuracy on untested modern LLMs. Accuracy forecasts must be
> calibrated for the exact deployed model, prompt, retrieval backend and
> population. The earlier Qwen-0.5B training statistics should **not** be
> reused with newer models.

## API surface

| Endpoint | Function | Any controller LLM calls? |
|---|---|---|
| `GET /health` | Liveness | No |
| `GET /ready` | Configuration status (no secrets) | No |
| `GET /docs` | Auto-generated OpenAPI/Swagger | No |
| `POST /v1/route` | Select the best **provided**, forecast-feasible action | **No** |
| `POST /v1/answer` | Retrieval → select macro → execute 1–2 remote model calls | **No extra** orchestration calls |

### Route-only request (works without provider keys or calibration)

```bash
curl -s -X POST 'https://YOUR-SPACE.hf.space/v1/route' \
  -H "Authorization: Bearer $API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "candidates": [
      {"id":"rag-8b", "predicted_accuracy":0.78,
       "expected_cost_usd":0.0006,"latency_p95_ms":950,"llm_calls":1},
      {"id":"rag-70b", "predicted_accuracy":0.89,
       "expected_cost_usd":0.006,"latency_p95_ms":2100,"llm_calls":1},
      {"id":"iterative-70b", "predicted_accuracy":0.93,
       "expected_cost_usd":0.012,"latency_p95_ms":3800,"llm_calls":2}
    ],
    "budgets":{"max_expected_cost_usd":0.01,"deadline_ms":3000,
               "max_llm_calls":2,"price_per_usd":5,"price_per_second":0.01}
  }'
```

*Those input accuracies, dollar amounts and latencies are **illustrative
request values**, not benchmark results or provider price quotations.* The
service will return the chosen action, scores, rejected actions, and reasons.

### Real RAG inference request

1. Configure both remote model backends using Space secrets/variables.
2. Configure a real search backend implementing the `/search` interface below.
3. Fit a calibration policy on **real LLM traces** from the deployed models.
4. Add the generated `config/policy.json` to the Space before rebuilding,
   or supply explicit `action_forecasts` in your API request for an
   **uncalibrated, operator-estimate** first deployment.

```bash
curl -s -X POST 'https://YOUR-SPACE.hf.space/v1/answer' \
  -H "Authorization: Bearer $API_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"question":"Which city is the capital of Japan?",
       "budgets":{"deadline_ms":12000,"max_llm_calls":2,
                  "max_retrieval_calls":2,"max_expected_cost_usd":0.02,
                  "price_per_usd":5,"price_per_second":0.02}}'
```

Unlike `/v1/route`, `/v1/answer` actually calls your retriever and selected
LLM(s). The response records chosen action, numerical scores, token usage and
provider-reported cost estimates, measured elapsed time and call counts.

If you do **not** have a trained calibration table yet, send an explicit
`action_forecasts` object in the request instead, using the action names in
`config/actions.json`. Each value must have the same fields as the route-only
`candidates` above. These forecasts are supplied by the operator, **not**
learned by this deployment, and must never be reported as measured accuracy.
Example:

```json
{"action_forecasts": {
  "retrieve_fast": {"id":"retrieve_fast","predicted_accuracy":0.72,
    "expected_cost_usd":0.001,"latency_p95_ms":1500,"llm_calls":1,"retrieval_calls":0},
  "retrieve_strong": {"id":"retrieve_strong","predicted_accuracy":0.83,
    "expected_cost_usd":0.006,"latency_p95_ms":2800,"llm_calls":1,"retrieval_calls":0},
  "iterative_strong": {"id":"iterative_strong","predicted_accuracy":0.87,
    "expected_cost_usd":0.011,"latency_p95_ms":4200,"llm_calls":2,"retrieval_calls":1}
}}
```

These numbers are fictitious **schema examples** and must be replaced with
real operator predictions before assessing effectiveness.

## First-start safeguard

**Do not configure `CALIBRATION_FILE` until `config/policy.json` actually exists.**
The repository intentionally does not include fabricated calibration numbers. The
route-only endpoint can run without model keys or calibration; `/v1/answer`
requires a retriever, model endpoints and either fitted calibration or
request-supplied forecasts. Setting `CALIBRATION_FILE=config/policy.json` before
creating the file prevents the application from starting.

## Set up as a Hugging Face Docker Space

1. Create a new Space, choosing **Docker** SDK (requires appropriate account
   eligibility for compute Spaces). Keep the YAML header above in `README.md`.
2. Upload **all** files at the root of this repository (including `service/`,
   `config/`, `requirements.txt`, `Dockerfile`).
3. Set the environment variables in `ENVIRONMENT.example` in the Space's
   **Settings → Variables/Secrets**, especially a strong random `API_TOKEN`.
   All model API tokens belong in **Secrets** only.
4. Set **FAST_LLM_BASE_URL** and **STRONG_LLM_BASE_URL** to the relevant
   OpenAI-compatible `/v1` URLs. Set `FAST_LLM_MODEL` and `STRONG_LLM_MODEL`
   to the model IDs supplied by those providers. Set `FAST_LLM_KEY_ENV` and
   `STRONG_LLM_KEY_ENV` to the names of the secret variables (e.g. `HF_TOKEN`).
5. Set `RETRIEVAL_URL` to your search service's full HTTPS URL.
6. Calibrate and upload `config/policy.json` (see below). Without it, the
   `/v1/answer` endpoint requires explicit `action_forecasts` supplied by the
   operator; otherwise it responds **503** rather than fake an
   accuracy/cost/latency forecast. `/v1/route` works independently.
7. Wait for the build to finish and use `https://YOUR-SPACE.hf.space/docs`.

HF Docker Spaces expose port **7860** by default. `uvicorn` listens on
`0.0.0.0:7860`; the model weights remain in external serving infrastructure.

**Provider examples:** HF Inference Providers use base URL
`https://router.huggingface.co/v1`; dedicated HF Inference Endpoints, vLLM and
TGI also expose OpenAI-compatible chat completions. Replace model IDs with
models actually supported by your provider. The gateway does not download
models, so it can route to large modern LLMs without expanding Space memory.

**Pricing:** Set model input/output prices explicitly in the environment;
prices are provider-specific and change. Set `RETRIEVAL_USD_PER_CALL`
explicitly (including `0` when the retriever is free) to track retrieval
costs alongside model charges. Monetary ceilings are **forecast**
ceilings, not hard spend caps; actual per-request charges can differ.

## Retrieval service contract

The Space sends `POST $RETRIEVAL_URL` with JSON:

```json
{"query":"What is the capital of Japan?","top_k":5}
```

Your retriever replies:

```json
{"documents":[
  {"id":"doc-101","title":"Tokyo","text":"Tokyo is the capital of Japan.","score":0.91},
  {"id":"doc-102","title":"Japan","text":"Japan is in East Asia.","score":0.42}
]}
```

Production implementations can adapt an existing Qdrant, Elasticsearch,
OpenSearch, Azure AI Search, Vespa, or other search service to this contract.
Use an **external index** for corpus sizes in the millions; do not load a
large vector index inside the CPU Space.

**Security:** The retriever URL and inference URLs are server-controlled
environment variables; clients cannot force arbitrary URLs. The Space API
requires bearer authentication. Provider secrets are not emitted to clients.
Use a separate API gateway with distributed rate limiting, audit logging,
and quotas for public multi-tenant production deployments.

## Fit the policy on real LLM outcomes

The included `fit_policy.py` expects one row **per question and action**, with
all actions tested in each calibration question, from a calibration dataset
separate from the evaluation set.

```csv
bucket,action,correct,cost_usd,latency_ms
c0_g0,retrieve_fast,1,0.0007,750
c0_g0,retrieve_strong,1,0.0051,1750
c0_g0,iterative_strong,1,0.0101,3200
```

The numbers in this CSV snippet are placeholders illustrating the schema,
**not experimental observations**. Do not use them as actual calibration.

Collect actual calibration outcomes from your running API using a
**training-only** JSONL dataset, one `question` and `answers` array per row:

```bash
python collect_calibration.py \
  --api https://YOUR-SPACE.hf.space \
  --questions calibration_train.jsonl \
  --out calibration_traces.csv \
  --raw-jsonl calibration_raw.jsonl --concurrency 4
```

The collector calls all three actions for every calibration question, using
actual model inference and returning the observed prediction, costs, tokens,
and latency. It explicitly forces each action and uses placeholder
`action_forecasts` *only to bypass missing calibration while collecting data*;
these placeholder forecasts are **not** used as empirical accuracy results.
The collector reports failed and unpriced model or retrieval calls. All
calibration actions must succeed and report priced usage before fitting a
dollar-aware policy. Set `RETRIEVAL_USD_PER_CALL` explicitly.

Then fit and upload:

```bash
python fit_policy.py --traces calibration_traces.csv --output config/policy.json
```

For benchmarking, keep calibration questions entirely separate from the
500-question evaluation set.

The empirical-Bayes estimator is

\[
\widehat p(z,a)=\frac{S_{z,a}+\kappa\widehat p_0(a)}{n_z+\kappa},
\qquad
S_a=\widehat p(z,a)-\lambda\widehat c_a-\mu\widehat t_a.
\]

The code uses per-action mean full-workflow cost and empirical p95
**post-preflight latency** from the actual models and retriever traces. This
avoids double-counting initial retrieval time when making the routing decision;
it reproduces the lightweight macro-policy family from the reported experiments. It is not a globally optimal constrained POMDP solver.

**Call budgets:** `max_llm_calls` and `max_retrieval_calls` are enforced before
downstream calls. **Deadlines:** both predicted p95 feasibility screening and
an actual wall-clock timeout are applied. Cancelled HTTP requests may still
incur provider charges. Model-token pricing is computed only if provider usage
metadata and configured prices are both present; unknown usage is disclosed.

## Scale and limitations

- API controller: **O(number of candidate actions)** and no generative LLM
  calls for routing. Numerical scoring happens on CPU.
- Async `httpx` calls with connection pooling; `MAX_INFLIGHT_REQUESTS` bounds
  simultaneous answers per process. Default admission capacity: 64.
- Large model families (8B, 32B, 70B, 120B+) are supported **as external
  OpenAI-compatible endpoints**, not hosted on the Space CPU.
- Throughput and end-to-end latency depend on retriever and model-serving
  provisioned capacity, network latency and rate limits. The supplied
  concurrency number is a **configuration limit, not a measured QPS claim**.
- Horizontal scale requires replicated paid Spaces or a conventional
  container deployment behind a load balancer; per-replica semaphores are not
  distributed quotas.
- Model-call pricing and latency forecasts need periodic recalibration; old
  Qwen-0.5B calibration cannot be assumed valid for a 70B model.
- No SSE streaming, persistent memory, multi-tenant identity, or guaranteed
  hard-dollar expenditure is claimed in this release.

## Run locally and test

```bash
python -m pip install -r requirements.txt pytest
export API_TOKEN=test-only-secret
python -m pytest -q
python bench_controller.py --requests 50000 --actions 20
uvicorn service.api:app --host 0.0.0.0 --port 7860
```

To run the local test retriever:

```bash
uvicorn examples.retriever_stub:app --host 127.0.0.1 --port 7861
```

The stub contains only four public example documents; it is not a
production-scale vector search engine.

## Docker sanity checks

```bash
docker build -t closedform-rag-api .
docker run --rm -p 7860:7860 \
  -e API_TOKEN=test-only-secret closedform-rag-api
curl http://127.0.0.1:7860/health
```

## Artifact and research integrity

The API is deployable infrastructure, not an ESWA benchmark in itself. No
commercial LLM accuracy, price, or latency is invented by this repository.
For a journal evaluation, run this exact API with real 8B/70B providers and
capture paired question-level traces with configured per-provider token prices.