fix(api): enforce global ollama endpoint order
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 5m13s
CD Pipeline / build-and-deploy (push) Successful in 3m31s
CD Pipeline / post-deploy-checks (push) Successful in 1m18s

This commit is contained in:
Your Name
2026-05-19 12:31:56 +08:00
parent 5fa0e1452c
commit 45cd55b2da
7 changed files with 359 additions and 228 deletions

View File

@@ -8,7 +8,7 @@ AWOOOI — Knowledge RAG Service (Phase 33, ADR-067)
- 超過 100 筆: 執行 CREATE INDEX ivfflat (手動觸發)
向量模型: bge-m3 (GCP-A/GCP-B/111 Ollama lane, 1024維)
生成模型: qwen2.5:7b-instruct (Ollama 111)
生成模型: qwen2.5:7b-instruct (Ollama GCP-A/GCP-B/111)
leWOOOgo: Service 層只處理業務邏輯DB 存取委派 rag_chunk_repository
架構審查 C1 修正: 2026-04-10 Claude Sonnet 4.6 Asia/Taipei
@@ -22,7 +22,7 @@ import structlog
import src.repositories.rag_chunk_repository as rag_repo
from src.core.config import settings
from src.services.ollama_endpoint_resolver import resolve_ollama_endpoint
from src.services.ollama_endpoint_resolver import resolve_ollama_order
logger = structlog.get_logger(__name__)
@@ -128,19 +128,35 @@ class KnowledgeRAGService:
# ------------------------------------------------------------------
async def _embed(self, text: str) -> list[float] | None:
try:
http = await self._get_http()
resp = await http.post(
f"{resolve_ollama_endpoint('embedding')}/api/embeddings",
json={
"model": getattr(settings, "OLLAMA_EMBEDDING_MODEL", _EMBED_MODEL),
"prompt": text,
},
)
if resp.status_code == 200:
return resp.json().get("embedding")
except Exception as e:
logger.warning("rag_embed_failed", error=str(e))
http = await self._get_http()
for endpoint in resolve_ollama_order("embedding"):
if not endpoint.url:
continue
try:
resp = await http.post(
f"{endpoint.url}/api/embeddings",
json={
"model": getattr(settings, "OLLAMA_EMBEDDING_MODEL", _EMBED_MODEL),
"prompt": text,
},
)
if resp.status_code == 200:
logger.debug(
"rag_embed_success",
provider=endpoint.provider_name,
)
return resp.json().get("embedding")
logger.warning(
"rag_embed_http_error",
provider=endpoint.provider_name,
status=resp.status_code,
)
except Exception as e:
logger.warning(
"rag_embed_failed",
provider=endpoint.provider_name,
error=str(e),
)
return None
async def _generate_answer(self, question: str, context: str) -> str:
@@ -150,22 +166,38 @@ class KnowledgeRAGService:
f"=== 相關資料 ===\n{context[:6000]}\n\n"
f"=== 問題 ===\n{question}"
)
try:
http = await self._get_http()
resp = await http.post(
f"{resolve_ollama_endpoint('rag')}/api/generate",
json={
"model": _GEN_MODEL,
"prompt": prompt,
"stream": False,
"options": {"num_predict": 512, "temperature": 0.2},
},
timeout=httpx.Timeout(90.0, connect=10.0),
)
if resp.status_code == 200:
return resp.json().get("response", "").strip()
except Exception as e:
logger.error("rag_generate_failed", error=str(e))
http = await self._get_http()
for endpoint in resolve_ollama_order("rag"):
if not endpoint.url:
continue
try:
resp = await http.post(
f"{endpoint.url}/api/generate",
json={
"model": _GEN_MODEL,
"prompt": prompt,
"stream": False,
"options": {"num_predict": 512, "temperature": 0.2},
},
timeout=httpx.Timeout(90.0, connect=10.0),
)
if resp.status_code == 200:
logger.debug(
"rag_generate_success",
provider=endpoint.provider_name,
)
return resp.json().get("response", "").strip()
logger.warning(
"rag_generate_http_error",
provider=endpoint.provider_name,
status=resp.status_code,
)
except Exception as e:
logger.error(
"rag_generate_failed",
provider=endpoint.provider_name,
error=str(e),
)
return "⚠️ RAG 生成失敗,請稍後再試"
# ------------------------------------------------------------------