feat: add durable success-first modelhub agent

This commit is contained in:
CoolBoy
2026-08-15 19:24:26 +08:00
parent 91d1d3d87d
commit 4260793c03
22 changed files with 2420 additions and 86 deletions

View File

@@ -6,7 +6,7 @@ This repository is packaged for the ModelHub XC agent platform.
- Root-level `Dockerfile`
- Listens on port `8080`
- Exposes `GET /health`
- Exposes `GET /health` for liveness and `GET /ready` for submission readiness
- Handles `SIGTERM`
- Reads platform-provided `STRATEGY_ID` and attaches it to task submissions as `strategyId`
@@ -44,6 +44,8 @@ Optional tuning:
- `MODELHUB_AGENT_GPUS`
- `MODELHUB_AGENT_EXTRA_ARGS`
- `MODELHUB_GPU_STRATEGY_STATE_PATH` default `.modelhub_state/gpu_strategy.json`
- `MODELHUB_ROUTING_STATE_PATH` default `.modelhub_state/routing_intelligence.json`
- `MODELHUB_OFFICIAL_CAPABILITIES_PATH` default `.modelhub_state/official_capabilities.json`
- `MODELHUB_MARKET_INTELLIGENCE_PATH` default `.modelhub_state/market_intelligence.json`
- `MODELHUB_MARKET_QUEUE_REFRESH_SECONDS` default `600`
- `MODELHUB_MARKET_FRAMEWORK_REFRESH_SECONDS` default `21600`
@@ -64,19 +66,31 @@ Optional tuning:
- `MODELHUB_ARCHITECTURE_BOOTSTRAP_MAX_LOGS` default `0` (unlimited)
- `MODELHUB_RECENT_MODEL_RESERVE_SLOTS` default `5` per account
- `MODELHUB_RECENT_MODEL_DAYS` default `7`
- `MODELHUB_STATE_SYNC_REMOTE` default `https://dev.modelhub.org.cn/CoolBoy/submmit.git`
- `MODELHUB_STATE_SYNC_BRANCH` default `agent-state`
- `MODELHUB_STATE_SYNC_BATCH_SIZE` default `20`
Git state synchronization reads `modelhub_user_name`, `modelhub_user_email`, and
`modelhub_user_password` from the tracked private-deployment `.env`. Uppercase
`MODELHUB_GIT_USERNAME`, `MODELHUB_GIT_EMAIL`, and `MODELHUB_GIT_PASSWORD`
override them when supplied by the container.
## Adaptive GPU Strategy
When no explicit GPU override is supplied, the worker uses a success-first 70/30
strategy generation with no self-funded exploration:
When no explicit GPU override is supplied, the worker uses one deterministic
success-first scorer. The former 70/30 long-term/recent quota no longer controls
traffic and there is no self-funded random exploration. Evidence falls back from
the most specific qualifying cohort to broader community evidence:
- 70%: the three long-term GPUs with the best Wilson lower confidence score and at least 100 terminal samples
- 30%: the top recent GPUs among the latest 1,000 terminal tasks
- 0%: unvetted/all-GPU exploration; community-wide results provide the exploration signal
- local task+GPU+framework+architecture+quantization+load-size bucket (20 samples)
- local task+GPU+framework+architecture+quantization (40 samples)
- local task+GPU+framework (100 samples)
- official community task+GPU+framework aggregate
- a conservative global prior when the platform has no observations
The 70/30 category ratio remains exact across accepted tasks. Inside each
category, weighted fair scheduling combines the category's historical rank with
live public market data:
Each rate is ranked by its Wilson lower confidence bound. Routes within five
percentage points of the best success estimate use expected successful
completions per hour as the tie-breaker:
- recent public success quality, scored with a strongly weighted Wilson lower confidence bound
- estimated backlog hours (`waiting / recent completions per hour`) as a bounded tie-breaker
@@ -86,7 +100,9 @@ live public market data:
This optimizes expected successful completions rather than blindly selecting the
smallest queue. Queue/throughput data is refreshed every 10 minutes and persisted
in `.modelhub_state/market_intelligence.json`. A failed refresh keeps the last good
snapshot, uses a retry backoff, and never blocks normal submissions.
snapshot and uses retry backoff. Critical official capability data is different:
without a usable GPU catalog, task route, framework catalog, build config, or
model/GPU uniqueness response, the entire submission cycle pauses fail-closed.
For each compatible model/GPU pair, the worker also ranks the GPU's supported
frameworks using ModelHub's public aggregate `modelCount` and `successCount` data,
@@ -100,12 +116,12 @@ at least 10%. A new framework
is eligible only after the authenticated official build-config endpoint returns
a complete config that passes local structure, placeholder, framework-name, and
GPU-parallelism validation. Valid official configs are cached and refreshed with
the framework snapshot; local templates remain the fail-safe fallback.
the framework snapshot; production routing never substitutes a hand template
when both the live config and its bounded last-good cache are unavailable.
Only platform-accepted tasks count. After exactly 200 accepted tasks, the next
poll cycle reloads all account history, generates a new immutable strategy snapshot,
and resets the generation counters to 140/60 targets. The active snapshot and
progress are stored in `.modelhub_state/gpu_strategy.json`.
Only platform-accepted tasks count. Routing is recalculated from the current
evidence on every scan; accepted route counters and lifetime sufficient statistics
are stored in `.modelhub_state/routing_intelligence.json`.
Five consecutive local failures open a 12-hour GPU/framework circuit breaker.
A sub-20% success rate over the latest 20 terminal tasks opens a 6-hour breaker.
@@ -116,6 +132,28 @@ idle card does not permanently poison otherwise successful evidence.
Candidate shortages expand the model search window; they never unlock an
unvetted GPU or framework.
## Durable State Branch
The hosted worker synchronizes an allowlisted runtime snapshot to the orphan
`agent-state` branch of this repository. Before each batch of at most 20 API
submissions it pushes write-ahead intents containing model, GPU, task, framework,
safe parameter vector, and a config fingerprint. It pushes task IDs and results
after the batch. If either push fails, no further submission begins until the
same snapshot can be synchronized.
At startup the worker verifies the manifest and file checksums, restores local
capacity, outcomes, routing evidence, architecture rules, exclusions, intents,
and active-task context, then reconciles every account against the platform.
Pending intents are held for two hours before being released as unconfirmed.
The branch keeps 30 days of structured events plus lifetime aggregate counters;
raw stdout, credentials, request headers, downloaded archives, and full configs
are never copied. Git authentication uses a temporary `GIT_ASKPASS` helper, so
the password is absent from command arguments, remotes, commits, and logs.
`GET /health` reports process liveness. `GET /ready` returns HTTP 200 only after
state recovery, state synchronization, and critical official capability checks
are usable; otherwise it returns HTTP 503 without forcing a liveness restart.
Failed-task archives are also classified conservatively. When ModelHub explicitly
says that the selected framework does not support the model or architecture, the
runner learns an exact GPU + framework + task type + architecture block from the
@@ -324,12 +362,18 @@ counts fail closed for older candidates, and no startup or periodic cleanup can
cancel a task by date. It also keeps unclassified/ambiguous historical failures
neutral in GPU/framework success feedback while preserving deterministic OOM
and architecture cleanup.
Version `2026.08.15.1` replaces the 70/30 quota with hierarchical success-first
routing, dynamically gates models through the official GPU/task/framework/config
APIs, enriches ModelScope metadata and model lineage, learns only proven safe
config vectors, and adds crash-safe write-ahead state synchronization to the
`agent-state` branch. It also exposes `/ready` and extends deterministic cleanup
to officially removed waiting GPU/framework routes.
## Deploy
Create a tag and submit the repository URL plus tag in "我的适配智能体".
```bash
git tag agent-v24
git push origin agent-v24
git tag -a agent-v25 -m "ModelHub agent 2026.08.15.1"
git push origin main agent-v25
```