LLM 호출 규격 전환: 고객사 사내 LLM(FabriX/Gauss) 헤더 지원 (LLM_PROVIDER=fabrix)
- settings: LLM_PROVIDER/LLM_CHAT_PATH/LLM_BODY_MODEL/LLM_JSON_MODE/LLM_MAX_TOKENS, FABRIX_* 3종, llm_enabled() - llm_client: headers()/body() 를 규격별로 구성. fabrix 는 x-openapi-token(Bearer)/x-generative-ai-client/ x-llm-model-id/x-generative-ai-user-email, body model 은 LLM_BODY_MODEL - summarize/ping: 접속 점검 명령 (--show 로 요청만 확인) - docs/llm-provider-plan.md: 계획·.env 값·오류별 조치. 기본값은 openai 라 기존 동작 불변 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
89deb108b0
commit
0f70c0d245
@@ -201,3 +201,65 @@ def test_ingest_backend_file_queues_without_key(api_client, monkeypatch):
|
||||
q = c.get("/summaries/jobs").json()
|
||||
assert q["pending"] >= 1, q
|
||||
assert any(n["task"] == "program_summary" for n in q["next"]), q
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ 호출 규격 (LLM_PROVIDER)
|
||||
|
||||
def _configure(monkeypatch, **kw):
|
||||
from config.settings import settings
|
||||
base = {"llm_base_url": "http://x", "llm_api_key": "", "llm_provider": "openai",
|
||||
"llm_chat_path": "/chat/completions", "llm_body_model": "", "llm_json_mode": True,
|
||||
"llm_max_tokens": 0, "llm_model": "m", "fabrix_client_key": "", "fabrix_openapi_token": "",
|
||||
"fabrix_user_email": ""}
|
||||
base.update(kw)
|
||||
for k, v in base.items():
|
||||
monkeypatch.setattr(settings, k, v)
|
||||
|
||||
|
||||
def test_openai_provider_headers_and_body(monkeypatch):
|
||||
from summarize import llm_client
|
||||
_configure(monkeypatch, llm_api_key="k", llm_max_tokens=800)
|
||||
c = llm_client.OpenAICompatClient()
|
||||
assert c.url == "http://x/chat/completions"
|
||||
assert c.headers() == {"Content-Type": "application/json", "Authorization": "Bearer k"}
|
||||
b = c.body("s", "u")
|
||||
assert b["model"] == "m" and b["response_format"] == {"type": "json_object"} and b["max_tokens"] == 800
|
||||
|
||||
|
||||
def test_fabrix_provider_headers_and_body(monkeypatch):
|
||||
from summarize import llm_client
|
||||
_configure(monkeypatch, llm_provider="fabrix", llm_base_url="https://h/dxhq/prod/api-llm",
|
||||
llm_chat_path="", llm_model="581", llm_body_model="/mnt/models", llm_json_mode=False,
|
||||
fabrix_client_key="CK", fabrix_openapi_token="TOK", fabrix_user_email="me@x.com")
|
||||
c = llm_client.OpenAICompatClient()
|
||||
assert c.url == "https://h/dxhq/prod/api-llm" # 완성 주소면 경로를 안 붙인다
|
||||
h = c.headers()
|
||||
assert h["x-openapi-token"] == "Bearer TOK" # Bearer 접두를 코드가 붙인다
|
||||
assert h["x-generative-ai-client"] == "CK"
|
||||
assert h["x-llm-model-id"] == "581"
|
||||
assert h["x-generative-ai-user-email"] == "me@x.com"
|
||||
assert "Authorization" not in h
|
||||
b = c.body("s", "u")
|
||||
assert b["model"] == "/mnt/models" and "response_format" not in b and "max_tokens" not in b
|
||||
|
||||
|
||||
def test_fabrix_keeps_existing_bearer_prefix(monkeypatch):
|
||||
from summarize import llm_client
|
||||
_configure(monkeypatch, llm_provider="fabrix", fabrix_client_key="CK", fabrix_openapi_token="Bearer TOK")
|
||||
assert llm_client.OpenAICompatClient().headers()["x-openapi-token"] == "Bearer TOK"
|
||||
|
||||
|
||||
def test_provider_requires_its_credentials(monkeypatch):
|
||||
from config.settings import settings
|
||||
from summarize import llm_client
|
||||
_configure(monkeypatch, llm_provider="fabrix") # 키 없음
|
||||
with pytest.raises(RuntimeError):
|
||||
llm_client.OpenAICompatClient()
|
||||
assert settings.llm_enabled() is False
|
||||
_configure(monkeypatch, llm_provider="fabrix", fabrix_client_key="a", fabrix_openapi_token="b")
|
||||
assert settings.llm_enabled() is True
|
||||
_configure(monkeypatch, llm_provider="openai") # api key 없음
|
||||
assert settings.llm_enabled() is False
|
||||
_configure(monkeypatch, llm_provider="bogus", llm_api_key="k")
|
||||
with pytest.raises(RuntimeError):
|
||||
llm_client.OpenAICompatClient()
|
||||
|
||||
Reference in New Issue
Block a user