add-llm-provider-or-model
GitHub指导如何安全添加LLM模型或提供商,强制预飞行验证ID、价格及上下文窗口。涵盖后端模型目录更新、客户端集成、前端配置及凭证加密,确保数据准确性与系统兼容性。
Trigger Scenarios
Install
npx skills add bagofwords1/bagofwords --skill add-llm-provider-or-model -g -y
SKILL.md
Frontmatter
{
"name": "add-llm-provider-or-model",
"description": "Add a new LLM model to the preset catalog, or a whole new LLM provider — with the mandatory pre-flight verification of model id, pricing, and context window against the provider's official docs. Use when asked to add\/update LLM models, providers, or pricing."
}
Add an LLM provider or model
Pre-flight: verify BEFORE adding (mandatory)
Never add a model from memory — model ids and prices change and training data goes stale. For each model, confirm from the provider's official docs/pricing page (web search / fetch, cite the URL in the PR):
- Exact
model_idas the API expects it (e.g.claude-sonnet-5,gpt-5.4-mini— not the marketing name). - Input and output cost per million tokens (USD) — these feed real cost
dashboards (
llm_usage_record, console cost metrics); a wrong number corrupts every org's reported spend. - Context window (tokens) and vision support.
- The model actually works on the provider's current API version used by
our client (
backend/app/ai/llm/clients/<provider>_client.py).
If any of these can't be verified from an official source, stop and say so — don't guess.
Adding a model (existing provider)
- Append to
LLM_MODEL_DETAILSinbackend/app/models/llm_model.py:name(display),model_id,provider_type,is_preset: True,is_enabled,supports_vision,context_window_tokens,input_cost_per_million_tokens_usd,output_cost_per_million_tokens_usd. Flags to handle deliberately:is_default: True— at most one per provider_type (that provider's flagship). Changing a default is a product decision — ask first.is_small_default: True— the provider's cheap/fast model for background tasks; at most one per provider_type.
- Preset providers auto-sync with this catalog
(
llm_service.py— "Only auto-sync preset providers with our curated catalog"), so existing orgs pick the model up; no migration needed. Custom providers keep the user's explicit selections. - If the model needs different request handling (new reasoning params,
streaming quirks), extend the provider client — don't special-case in
agent_v2/planner code.
Adding a provider
- Client —
backend/app/ai/llm/clients/<provider>_client.py, implementing the same streaming interface as the existing clients (openai_client.pyis the reference;anthropic_client.pyfor a non-OpenAI-shaped API). First check whether the provider is OpenAI-compatible — then it may just work through the existing custom provider (base_url override) and you only need presets. - Dispatch — wire the
provider_typebranch inbackend/app/ai/llm/llm.py(self.provider == "<type>"→ client). - Catalog — add to
LLM_PROVIDER_DETAILSinbackend/app/models/llm_provider.py(type,name,description,config,credentialsschema) and define the<Provider>Config/<Provider>Credentialsclasses next to the existing ones. The credentials schema drives the settings-page form; credentials are Fernet-encrypted at rest (encrypt_credentials) — never log or return them. - Models — add its models to
LLM_MODEL_DETAILS(pre-flight above). - Frontend — icon in
frontend/components/LLMProviderIcon.vue; the provider form itself is schema-driven viaGET /llm/available_providers. - Prompt language: conversational-vs-code agent split in
backend/app/ai/prompt_language.pyis provider-agnostic — no change needed unless the provider mishandles system prompts.
Verification
cd backend
# Catalog sanity: unique ids; ≤1 default and ≤1 small default per provider
uv run python - <<'EOF'
from collections import Counter
from app.models.llm_model import LLM_MODEL_DETAILS as M
ids = [m["model_id"] for m in M]
assert len(ids) == len(set(ids)), "duplicate model_id"
for flag in ("is_default", "is_small_default"):
per = Counter(m["provider_type"] for m in M if m.get(flag))
dupes = {p: n for p, n in per.items() if n > 1}
assert not dupes, f"multiple {flag} for provider(s): {dupes}"
assert all(m["input_cost_per_million_tokens_usd"] > 0 and m["output_cost_per_million_tokens_usd"] > 0 for m in M)
print(f"OK: {len(M)} models")
EOF
# Unit: connection-test schema still valid
uv run pytest tests/unit/test_llm_test_connection_schema.py -q
# Live round-trip (real key, env/integrations.json only — never committed)
uv run pytest tests/integrations/llm_clients.py -k "<provider>" -v
Then a live UI check: boot the stack, Settings → AI/LLMs → the provider and model appear, "Test connection" passes with a real key, and one prompt round-trips through the new model. Confirm a cost row lands in the console usage metrics with the expected per-token math.
Pitfalls
- Wrong price or a price in per-1K units instead of per-million — the catalog is per million tokens.
- Two
is_default/is_small_defaultmodels — org defaults become nondeterministic. - Adding an OpenAI-compatible provider as a full new client instead of a
preset on the
customprovider — double maintenance for nothing. - CI note:
integration-llmsin.github/workflows/e2e-tests.ymlcurrently skipsgoogle/bedrock/openai-reasoningcases — don't "fix" a red run by extending those skips; flag it instead.
Version History
- 1529fca Current 2026-08-20 15:41


