[V10.282] 補齊 Code Review Hermes 本地模型矩陣 | code_review_pipeline_service.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s
This commit is contained in:
@@ -65,6 +65,24 @@ CODE_REVIEW_OLLAMA_FALLBACK_TIMEOUT = int(
|
||||
CODE_REVIEW_OLLAMA_NUM_PREDICT = int(os.getenv("CODE_REVIEW_OLLAMA_NUM_PREDICT", "384"))
|
||||
CODE_REVIEW_OLLAMA_KEEP_ALIVE = os.getenv("CODE_REVIEW_OLLAMA_KEEP_ALIVE", "24h")
|
||||
CODE_REVIEW_HERMES_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_TIMEOUT", "35"))
|
||||
CODE_REVIEW_HERMES_PRIMARY_MODEL = os.getenv(
|
||||
"CODE_REVIEW_HERMES_PRIMARY_MODEL",
|
||||
CODE_REVIEW_OLLAMA_MODEL,
|
||||
)
|
||||
CODE_REVIEW_HERMES_SECONDARY_MODEL = os.getenv(
|
||||
"CODE_REVIEW_HERMES_SECONDARY_MODEL",
|
||||
CODE_REVIEW_OLLAMA_SECONDARY_MODEL,
|
||||
)
|
||||
CODE_REVIEW_HERMES_FALLBACK_MODEL = os.getenv(
|
||||
"CODE_REVIEW_HERMES_FALLBACK_MODEL",
|
||||
CODE_REVIEW_OLLAMA_FALLBACK_MODEL,
|
||||
)
|
||||
CODE_REVIEW_HERMES_PRIMARY_TIMEOUT = int(
|
||||
os.getenv("CODE_REVIEW_HERMES_PRIMARY_TIMEOUT", os.getenv("CODE_REVIEW_HERMES_TIMEOUT", "35"))
|
||||
)
|
||||
CODE_REVIEW_HERMES_SECONDARY_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_SECONDARY_TIMEOUT", "25"))
|
||||
CODE_REVIEW_HERMES_FALLBACK_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_FALLBACK_TIMEOUT", "20"))
|
||||
CODE_REVIEW_HERMES_NUM_PREDICT = int(os.getenv("CODE_REVIEW_HERMES_NUM_PREDICT", "768"))
|
||||
CODE_REVIEW_HERMES_MAX_FILES = int(os.getenv("CODE_REVIEW_HERMES_MAX_FILES", "3"))
|
||||
CODE_REVIEW_HERMES_MAX_CHARS = int(os.getenv("CODE_REVIEW_HERMES_MAX_CHARS", "2500"))
|
||||
INTERNAL_TOKEN = os.getenv("INTERNAL_WEBHOOK_TOKEN", "")
|
||||
@@ -248,44 +266,94 @@ class CodeReviewPipeline:
|
||||
|
||||
只輸出 JSON 陣列,不含其他文字。無問題時輸出 []"""
|
||||
|
||||
from services.ollama_service import OllamaService, get_host_label, get_provider_tag
|
||||
from services.ollama_service import (
|
||||
OLLAMA_HOST_FALLBACK,
|
||||
OLLAMA_HOST_PRIMARY,
|
||||
OLLAMA_HOST_SECONDARY,
|
||||
OllamaService,
|
||||
get_host_label,
|
||||
get_provider_tag,
|
||||
)
|
||||
|
||||
with log_ai_call(
|
||||
caller='code_review_hermes',
|
||||
provider='gcp_ollama',
|
||||
model=_HERMES_MODEL,
|
||||
request_id=f"cr-{self.commit_sha[:8]}",
|
||||
meta={'commit': self.commit_sha[:8], 'branch': self.branch,
|
||||
'files': len(files), 'route': 'ollama_first',
|
||||
'max_files': CODE_REVIEW_HERMES_MAX_FILES,
|
||||
'max_chars': CODE_REVIEW_HERMES_MAX_CHARS},
|
||||
) as _ctx:
|
||||
ollama = OllamaService(model=_HERMES_MODEL)
|
||||
resp = ollama.generate(
|
||||
prompt=prompt,
|
||||
model=_HERMES_MODEL,
|
||||
temperature=0.1,
|
||||
timeout=CODE_REVIEW_HERMES_TIMEOUT,
|
||||
)
|
||||
actual_provider = get_provider_tag(resp.host or '')
|
||||
_ctx.set_provider(actual_provider)
|
||||
_ctx.set_tokens(
|
||||
input=resp.input_tokens,
|
||||
output=resp.output_tokens,
|
||||
)
|
||||
_ctx.add_meta('host', resp.host)
|
||||
_ctx.add_meta('host_label', get_host_label(resp.host or ''))
|
||||
if not resp.success:
|
||||
_ctx.set_error(resp.error or 'ollama generate failed')
|
||||
logger.warning("[CodeReview] Hermes Ollama 掃描失敗: %s", resp.error)
|
||||
return []
|
||||
raw = (resp.content or "").strip()
|
||||
hermes_attempts = [
|
||||
(
|
||||
"primary_code_scan",
|
||||
OLLAMA_HOST_PRIMARY,
|
||||
CODE_REVIEW_HERMES_PRIMARY_MODEL,
|
||||
CODE_REVIEW_HERMES_PRIMARY_TIMEOUT,
|
||||
),
|
||||
(
|
||||
"secondary_fast_scan",
|
||||
OLLAMA_HOST_SECONDARY,
|
||||
CODE_REVIEW_HERMES_SECONDARY_MODEL,
|
||||
CODE_REVIEW_HERMES_SECONDARY_TIMEOUT,
|
||||
),
|
||||
(
|
||||
"lan_111_hermes_scan",
|
||||
OLLAMA_HOST_FALLBACK,
|
||||
CODE_REVIEW_HERMES_FALLBACK_MODEL,
|
||||
CODE_REVIEW_HERMES_FALLBACK_TIMEOUT,
|
||||
),
|
||||
]
|
||||
findings = None
|
||||
last_error = None
|
||||
|
||||
match = re.search(r"\[.*\]", raw, re.DOTALL)
|
||||
if not match:
|
||||
logger.warning("[CodeReview] Hermes 回應無 JSON: %s", raw[:200])
|
||||
for attempt_index, (attempt_key, host, model_name, timeout_s) in enumerate(
|
||||
hermes_attempts,
|
||||
start=1,
|
||||
):
|
||||
with log_ai_call(
|
||||
caller='code_review_hermes',
|
||||
provider=get_provider_tag(host),
|
||||
model=model_name,
|
||||
request_id=f"cr-{self.commit_sha[:8]}",
|
||||
meta={'commit': self.commit_sha[:8], 'branch': self.branch,
|
||||
'files': len(files), 'route': 'ollama_first',
|
||||
'attempt': attempt_index,
|
||||
'attempt_key': attempt_key,
|
||||
'max_files': CODE_REVIEW_HERMES_MAX_FILES,
|
||||
'max_chars': CODE_REVIEW_HERMES_MAX_CHARS,
|
||||
'timeout_s': timeout_s},
|
||||
) as _ctx:
|
||||
ollama = OllamaService(host=host, model=model_name)
|
||||
resp = ollama.generate(
|
||||
prompt=prompt,
|
||||
model=model_name,
|
||||
temperature=0.1,
|
||||
timeout=timeout_s,
|
||||
keep_alive=CODE_REVIEW_OLLAMA_KEEP_ALIVE,
|
||||
options={"num_predict": CODE_REVIEW_HERMES_NUM_PREDICT},
|
||||
)
|
||||
actual_host = resp.host or host
|
||||
_ctx.set_provider(get_provider_tag(actual_host))
|
||||
_ctx.set_tokens(
|
||||
input=resp.input_tokens,
|
||||
output=resp.output_tokens,
|
||||
)
|
||||
_ctx.add_meta('host', actual_host)
|
||||
_ctx.add_meta('host_label', get_host_label(actual_host))
|
||||
if not resp.success:
|
||||
last_error = resp.error or 'ollama generate failed'
|
||||
_ctx.set_error(last_error)
|
||||
continue
|
||||
raw = (resp.content or "").strip()
|
||||
match = re.search(r"\[.*\]", raw, re.DOTALL)
|
||||
if not match:
|
||||
last_error = f"missing JSON array: {raw[:120]}"
|
||||
_ctx.set_error(last_error)
|
||||
logger.warning("[CodeReview] Hermes 回應無 JSON: %s", raw[:200])
|
||||
continue
|
||||
try:
|
||||
findings = json.loads(match.group())
|
||||
except Exception as exc:
|
||||
last_error = f"json parse failed: {type(exc).__name__}: {exc}"
|
||||
_ctx.set_error(last_error)
|
||||
continue
|
||||
break
|
||||
|
||||
if findings is None:
|
||||
logger.warning("[CodeReview] Hermes 本地掃描全部失敗: %s", last_error)
|
||||
return []
|
||||
findings = json.loads(match.group())
|
||||
|
||||
for f in findings:
|
||||
sev = f.get("severity", "LOW").lower()
|
||||
|
||||
Reference in New Issue
Block a user