Files
AI-Check-Test/.gitea/checker/llm_reviewer.py
dongzi 1b19e8366e
All checks were successful
API接口参数变更检测 / api-param-check (push) Successful in 16s
py修改
2026-06-04 09:53:36 +08:00

148 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
豆包 LLM 接口参数变更审核模块。
LLM 仅输出简短的兼容性提示,详细变更由 AST + Markdown 通知展示。
"""
import json
from typing import Any, Dict, List, Optional
import requests
from comparator import EndpointChangeReport
# 写入 prompt不在通知中展示
FRAMEWORK_IGNORE_HINT = """
以下参数类型/名称属于 Spring MVC 框架自动注入,不是 API 调用方入参,审核时必须忽略,不要在结果中提及:
HttpServletRequest、HttpServletResponse、HttpSession、ServletRequest、ServletResponse、
WebRequest、NativeWebRequest、Model、ModelMap、RedirectAttributes、BindingResult、
Authentication、Principal 等。
"""
def is_llm_enabled(config: Dict[str, Any]) -> bool:
"""判断大模型总开关是否开启。"""
return config.get("llm", {}).get("enabled", True)
def call_doubao_api(
api_key: str,
prompt: str,
config: Dict[str, Any],
) -> Optional[str]:
"""调用豆包 API。"""
if not api_key or api_key == "YOUR_DOUBAO_API_KEY":
print("[警告] 未配置豆包 API Key跳过 LLM 审核。")
return None
llm_cfg = config.get("llm", {})
model = llm_cfg.get("model") or llm_cfg.get("endpoint_id", "")
if not model:
print("[警告] 未配置 llm.model跳过 LLM 审核。")
return None
api_url = llm_cfg.get(
"api_url", "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
)
timeout = llm_cfg.get("timeout")
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
payload = {
"model": model,
"messages": [
{
"role": "system",
"content": (
"你是 Java Spring Boot API 变更分析专家。"
"你只负责输出简短的兼容性风险提示,不重复罗列接口参数明细。"
+ FRAMEWORK_IGNORE_HINT
),
},
{"role": "user", "content": prompt},
],
"temperature": 0.1,
}
try:
kwargs = {"headers": headers, "json": payload}
if timeout is not None:
kwargs["timeout"] = timeout
resp = requests.post(api_url, **kwargs)
resp.raise_for_status()
data = resp.json()
if "choices" in data and data["choices"]:
return data["choices"][0]["message"]["content"]
return None
except requests.RequestException as exc:
print(f"[错误] 豆包 API 调用失败: {exc}")
return None
def build_parameter_change_prompt(
reports: List[EndpointChangeReport],
changed_files: List[str],
git_diff: str = "",
) -> str:
"""
构造 LLM 提示词:只要求输出兼容性摘要,不要求重复参数列表。
"""
ast_report = []
for r in reports:
ast_report.append(
{
"uri": f"{r.http_method} {r.uri}",
"is_new": r.is_new_endpoint,
"is_removed": r.is_removed_endpoint,
"changes": [
{
"type": c.change_type.value,
"name": c.param_name,
"java_type": c.param_type,
"required": c.required,
}
for c in r.parameter_changes
],
}
)
diff_block = git_diff.strip()[:6000] if git_diff.strip() else "(无)"
return f"""请根据以下 Controller 接口参数变更,**仅输出「兼容性提示」**,要求:
{FRAMEWORK_IGNORE_HINT}
## 输出格式(严格遵守)
- 只输出 36 行 Markdown不要输出「整体说明」「接口变更详情」等标题
- 不要逐条重复 URI 和参数列表(通知里已有)
- 不要提及「排除框架注入」相关字样
- 重点说明:是否有破坏性变更、哪些必填参数调用方必须传入
- 全新 Controller 说明「均为新接口,对现有调用方无破坏」即可
- 语气简洁,可用 <font color="warning">...</font> 标注风险项
## 变更文件
{json.dumps(changed_files, ensure_ascii=False)}
## AST 变更摘要
{json.dumps(ast_report, ensure_ascii=False, indent=2)}
## Git Diff
{diff_block}
"""
def review_parameter_changes(
reports: List[EndpointChangeReport],
config: Dict[str, Any],
changed_files: List[str],
git_diff: str = "",
) -> Optional[str]:
"""LLM 审核,返回简短兼容性提示。"""
if not is_llm_enabled(config) or not reports:
return None
llm_cfg = config.get("llm", {})
prompt = build_parameter_change_prompt(reports, changed_files, git_diff)
return call_doubao_api(llm_cfg.get("api_key", ""), prompt, config)