Skip to content

Fix/default model backfill select best - #4045

Merged
jeffwu-1999 merged 4 commits into
developfrom
fix/default-model-backfill-select-best
Sep 30, 2026
Merged

jeffwu-1999 merged 4 commits into
developfrom
fix/default-model-backfill-select-best

Conversation

@lijiayang619

@lijiayang619 lijiayang619 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

修改了默认模型配置逻辑,
1.没有默认模型的时候,批量添加直接选上下文最大的
2.如果已有默认模型,就添加模型的时候不会再去变动
3.如果默认模型是空的,那就从新添加的里面选
没有默认模型就选上下文最大
20260930-112409

有模型但是没有默认模型,从新添加的模型里面选

20260930-112531 20260930-112539

ljy added 3 commits September 30, 2026 09:51
… models

The default-model backfill runs after EVERY model creation, and a slot it
fills is treated as final. Batch adds create models one by one, so the
first-created model permanently occupied the slot before better candidates
landed -- the "available first, then larger context window" ranking never
got to compare across the batch. Observed live: a 5-model batch import
left a 256K-context model as the default LLM while two 1M-context models
arrived right after it.

Distinguish user choices from backfill placeholders via the config row's
user_id: the UI save path (set_single_config) stamps the acting user on
rows it writes, backfill-inserted rows leave it empty. Backfill now:

- never touches a slot whose row carries a user_id (user's explicit choice)
- re-evaluates a previously auto-configured slot on every create and swaps
  in the best candidate (available first, then larger context); the first
  user save flips the row to user-owned and locks it
- repairs dangling rows and fills never-configured slots as before

get_single_config_info now also returns the row's user_id for this
classification.
The backfill used to pick the best candidate from ALL live models of a slot's
type. When a user deliberately cleared a default slot and then added one new
model, the backfill resurrected an older, larger-context model they had
passed over -- silently overriding the clear.

Pass the ids of the models created by the current call into the backfill:
- an empty slot (never configured, or cleared by the user) is now filled
  only from those newly created models; if the call added none of the
  slot's type, the slot stays empty
- dangling rows still repair from the full pool (the previous choice is
  gone, so the best remaining replacement is appropriate)
- auto-configured slots keep re-evaluating among all candidates (the
  larger-context swap from the previous commit)
- user-configured slots remain locked

create_model_record returns only a bool, so the new ids are recovered via
display-name lookup (_ids_for_created_models); multi_embedding creates
include their embedding twin automatically.
…session

The auto-slot swap from the earlier commit never expired: an auto-configured
default could be replaced by a better model at any later create, so adding
models months after an import could still move the default. Users expect a
default that has been sitting in the slot to stay put -- only the batch
import that is still in progress should converge on the best model.

Gate the swap on occupant freshness:

- swap candidates are the current occupant plus the models created in the
  current call; older models the user passed over are never resurrected
  through the swap path (previously the swap re-ranked ALL models of the
  type, so a cleared-then-refilled slot could drift back to an old giant)
- the swap only runs while the occupant was created within
  _AUTO_SLOT_SWAP_WINDOW (5 minutes) of the newest model in the current
  call -- batch imports create their rows seconds apart, so mid-batch
  convergence still works; an occupant from an earlier session is frozen
- timestamps come from the DB on both sides, so no clock/timezone skew;
  missing create_time disables the gate (permissive, legacy behaviour)
- empty-slot fill (new-only), dangling repair and user-choice locking are
  unchanged
Copilot AI balanced review requested due to automatic review settings September 30, 2026 02:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Batch detection, ownership inference, and display-name ID recovery can select or overwrite incorrect defaults.

Review effort: Balanced
Findings: 3 Medium severity · 2 Low severity

Open (5)
What changed in this PR

Updates default-model backfilling after model creation.

Changes:

  • Restricts empty-slot candidates to newly created models.
  • Adds automatic-default replacement logic.
  • Expands regression tests.
File Description
backend/​services/​model_management_service.py Implements candidate selection and backfill behavior.
backend/​database/​tenant_config_db.py Exposes config-row user ownership.
test/​backend/​services/​test_model_management_service.py Adds backfill regression tests.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread backend/services/model_management_service.py Outdated
Comment thread backend/services/model_management_service.py Outdated
Comment thread backend/services/model_management_service.py
Comment thread backend/services/model_management_service.py
Comment thread test/backend/services/test_model_management_service.py
@codecov

codecov Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.00000% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
backend/apps/model_managment_app.py 26.66% 11 Missing ⚠️
backend/services/model_management_service.py 81.25% 3 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

The auto-slot swap was removed: a default slot occupied by ANY live model --
user-picked or system-backfilled -- is now never touched by later creates.
Users expect "the slot already has a model" to mean exactly that; swapping
in a better model months after an import silently moved defaults and
compounded with the empty-slot rules into hard-to-predict behaviour. The
previous commit's freshness window tried to reconcile this with mid-batch
convergence via heuristics; explicit batch context replaces it.

Batch imports now carry their own flow control:

- ModelRequest gains an optional skip_default_backfill flag (popped by the
  app layer before the dict reaches the service/DB layer, same contract as
  the accept-signal fields). The batch dialog marks every per-row create
  with it, so no row claims empty slots as it lands.
- A new POST /model/backfill_defaults endpoint finalizes the batch: it
  resolves the created display names to ids and runs the backfill ONCE with
  the whole batch as candidates, so an empty slot gets the best model of
  the batch (available first, then larger context) in a single decision.
- The user-facing batch dialog calls the finalize after its loop; the
  manage-tenant path keeps its existing per-row behaviour (its request
  model ignores the flag and its frontend service does not forward it).

Final slot semantics: occupied -> never touched; empty -> best of the
current call's new models (or all models for legacy callers); dangling ->
repaired from the full pool; user choice -> locked.
@jeffwu-1999
jeffwu-1999 merged commit 1c92895 into develop Sep 30, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants