Skip to main content

LiteLLM journey: DB mode — 3 tables, config.yaml overlay, 60s auto-reload

· 5 min read

"ผม assume ว่า config.yaml เป็น source of truth — จนกว่าจะไปอ่าน docs เจอบรรทัดนี้: 'DB rows overlay config.yaml on every refresh'"

Part 1 ผมเล่าเรื่อง drop_params ต้อง recreate Part 2 ผมเล่าเรื่อง 3 flags ที่ใช้บ่อย Part 3 คือภาพของ DB mode — เก็บอะไรไว้ที่ไหน, config.yaml กับ DB ตัวไหนมีลำดับสูงกว่า, auto-reload ทำอะไรได้บ้าง

TL;DR​

ตอนผมตั้ง LiteLLM ครั้งแรก — assume ว่า "แก้ config.yaml = แก้ทุกอย่าง" มันไม่ใช่ — DB rows overlay config.yaml ทุกครั้งที่ refresh

3 tables หลักที่ LiteLLM ใช้:

  1. LiteLLM_Config — settings ทั้งหมด (litellm / router / general / environment)
  2. LiteLLM_ProxyModelTable — model + deployment configs
  3. LiteLLM_SpendLogs — per-request tracking

Insight ใหม่ที่หลายคนไม่รู้: ลำดับความสำคัญเมื่อ config.yaml กับ DB ขัดแย้งกัน

config.yaml (base) → DB rows (overlay)
DB มีลำดับสูงกว่าเมื่อค่าขัดแย้ง

1. 3 tables หลัก — เก็บอะไรที่ไหน​

LiteLLM_Config — settings ทั้งหมด​

เก็บเป็น JSONB แยกตาม section:

SELECT param_name, param_value
FROM "LiteLLM_Config";
param_nameเนื้อหา
litellm_settingsdrop_params, cache, callbacks, success_callback, failure_callback
router_settingsrouting_strategy, num_retries, allowed_fails, cooldown_time
general_settingsmaster_key, disable_env_credential_login, alerting
environment_variablesAPI keys ของพวก model providers

→ ทุก flag ที่เขียนใน config.yaml มี row อยู่ใน LiteLLM_Config

LiteLLM_ProxyModelTable — models​

เก็บ model_name + litellm_params เป็น JSON:

Columnเนื้อหา
model_namevirtual name เช่น M3-CHATx-256k
litellm_paramsmodel, api_base, api_key, rpm, tpm, max_input_tokens
model_infometadata

ทุก model ที่ลูกค้าเรียกผ่าน proxy = row ในตารางนี้ (16 models ตอนนี้)

LiteLLM_SpendLogs — tracking​

ทุก request = 1 row:

SELECT
count(*) FILTER (WHERE cache_hit = true) AS hits,
count(*) FILTER (WHERE cache_hit = false) AS misses,
count(*) FILTER (WHERE cache_hit IS NULL) AS untracked
FROM "LiteLLM_SpendLogs";
Fieldเนื้อหา
cache_hittrue / false / NULL (record เก่า)
modeldeployment model
spendcost ที่คิด
startTime, endTimeduration
prompt, completiontoken + content (เก็บ debug)

ผมเก็บ ~17,000 rows ใน 2 สัปดาห์ = data ที่น่าเชื่อถือพอทำ analysis

Tables อื่นๆ (ไม่ใช้บ่อย)​

จาก docs.db_info:

CategoryTableใช้เมื่อ
AuthLiteLLM_VerificationTokenvirtual keys + RBAC
BudgetLiteLLM_BudgetTablerate limits per user/team
RBACLiteLLM_OrganizationTableorg-level configs
LiteLLM_TeamTableteam-level settings
LiteLLM_UserTableindividual user
LiteLLM_EndUserTableend-user tracking

ตอนนี้ผมไม่ได้ใช้ RBAC + virtual keys — ใช้แค่ master_key ตรงๆ — แต่ถ้าจะ scale ต้องใช้

2. config.yaml vs DB — overlay order (Insight ใหม่)​

จาก docs official:

"On startup and on every config refresh, the proxy loads your config.yaml first and then overlays the database rows for general_settings, router_settings, litellm_settings, and environment_variables"

ดังนั้น:

1. config.yaml → base
2. DB rows → overlay (DB มีลำดับสูงกว่า)

ในทางปฏิบัติ​

ลำดับ practical ของผม:

  1. ตั้งค่า config.yaml ครั้งแรก (initial setup)
  2. แก้ค่าผ่าน UI admin / psql UPDATE — DB rows จะเก็บ
  3. config.yaml จะถูก overwritten เมื่อมีการ save ผ่าน UI

ดังนั้น ถ้าแก้ config.yaml ด้วยมือ หลังจากเคยแก้ผ่าน UI ค่าใน config.yaml จะถูก UI แทนที่

Example (จริงที่ผมเจอ)​

ผมเขียน failure_callback: ["database"] ใน config.yaml แต่ UI ก็มี failure_callback: ["database"] แล้ว → LiteLLM merge แล้วเกิดซ้ำ log 2 ครั้ง

Rule: ถ้าจะแก้ — เลือกที่เดียว (UI หรือ config.yaml) ไม่ใช่ทั้งสองที่

3. Hierarchy — router_settings > litellm_settings​

จาก docs:

"If you see overlapping values, settings on router_settings will override those on litellm_settings"

ยกตัวอย่าง:

litellm_settings:
num_retries: 5 # จะถูก override

router_settings:
num_retries: 2 # priority สูงกว่า litellm_settings

→ ลำดับชั้น: router_settings > litellm_settings > general_settings

ในตอนนี้ผมตั้ง num_retries: 2 ใน router_settings (DB) — เลยไม่ต้องไปยุ่งใน litellm_settings

4. 60s auto-reload — scope จาก Part 1 + 2 สรุป​

proxy_config_reload_interval_seconds (default 60s) job 3 อย่าง:

JobScopeAuto-reload
check_periodic_reloadsmodel cost map, anthropic beta headers✅
get_credentialsDB credentials + virtual keys✅
add_deploymentmodels จาก LiteLLM_ProxyModelTable✅

ที่ไม่ apply (ต้อง recreate):

  • drop_params
  • routing_strategy
  • Image upgrade
  • Critical callbacks

ผมเคยทำเรื่องนี้เต็มใน Part 1 + 2 แล้ว — link อยู่ข้างบน

5. Auto-register — เพิ่ม model ผ่าน UI ก็ได้​

# ผ่าน UI admin panel: Settings > Models
# ใส่ model_name + litellm_params
# Save
# → LiteLLM apply ทันที (60s)

ไม่ต้องแก้ config.yaml ไม่ต้อง recreate

ครั้งหนึ่งที่ผมทำ: เพิ่ม model ใหม่ qwen3.8-27b-kongvut (self-host vLLM)

  • ไป UI → Models → Add model
  • ใส่ model_name: qwen3.8-27b-kongvut
  • ใส่ litellm_params: { api_base: http://..., rpm: ... }
  • Save → auto-register ทันที
  • ทดสอบ: curl /v1/chat/completions -d '{"model":"qwen3.8-27b-kongvut"...}' → 200

แต่ ถ้าจะ set default/general_settings (เช่น master_key, alerting) → แก้ config.yaml ดีกว่า (DB UI ไม่ให้แก้)

6. Production tip — disable spend_logs เมื่อไม่ใช้​

ถ้าไม่ใช้ SpendLogs (เช่น dev environment) — disable:

general_settings:
disable_spend_logs: true

หรือ

general_settings:
disable_error_logs: true

ประหยัด disk + เร็วขึ้น — แต่ผม เปิดไว้ เพราะต้อง debug

สรุป​

Tableเก็บอะไร
LiteLLM_Configsettings JSONB (litellm/router/general/env)
LiteLLM_ProxyModelTablemodel + litellm_params
LiteLLM_SpendLogsper-request tracking

3 lessons จาก web research ที่ผมเพิ่งเรียนรู้:

  1. config.yaml เป็น base, DB rows overlay — DB มีลำดับสูงกว่าเมื่อค่าขัดแย้ง
  2. router_settings > litellm_settings (hierarchy ที่ชัดเจน)
  3. UI สามารถ auto-register model ใหม่ได้ — ไม่ต้องแก้ config.yaml

ทำไมต้องรู้เรื่องนี้? เพราะถ้าแก้ config.yaml + DB ขัดแย้งกัน โดยไม่รู้ว่า DB มีลำดับสูงกว่า → งง สองชั่วโมง ได้ — เหมือน Part 1

Part 4 → vLLM integration + streaming + reasoning_effort edge case

อ้างอิง​

แชร์บทความ
☕

เนื้อหานี้มีประโยชน์ไหม? ช่วยสนับสนุนค่ากาแฟให้ผู้เขียนสักแก้ว

Buy Me a Coffee
Loading...