feat: 持久化诊断历史并修复 Agent 命令执行
This commit is contained in:
+41
-5
@@ -1,5 +1,6 @@
|
||||
"""AI Agent 分析模块 - 调用 OpenAI 兼容接口分析诊断结果 (支持流式输出)"""
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
import httpx
|
||||
from backend.config import AI_API_BASE, AI_API_KEY, AI_MODEL
|
||||
@@ -22,7 +23,12 @@ _HEADERS = {
|
||||
}
|
||||
|
||||
|
||||
AGENT_SYSTEM_PROMPT = """你是 Kubernetes 自主诊断 Agent。你可以根据诊断报告决定执行 kubectl 命令获取更多证据,并在证据充分后给出结论。
|
||||
AGENT_SYSTEM_PROMPT = """你是 Kubernetes 自主诊断 Agent。你的首要职责是主动调用 kubectl 获取现场证据,而不是只给用户一段脚本或操作建议。
|
||||
|
||||
行为要求:
|
||||
1. 如果证据不足,必须返回 command 动作并逐条调查;至少检查与故障资源直接相关的状态、describe、events 或 logs。
|
||||
2. 禁止在 final 中仅提供“请执行以下命令”的脚本。只有在已经依据真实命令输出形成结论时才能返回 final。
|
||||
3. 每次只提出一条 kubectl 命令,服务端会执行并把真实输出返回给你,然后你继续下一轮判断。
|
||||
|
||||
安全规则:
|
||||
1. 只允许提出单条 kubectl 命令,不得使用 shell、管道、重定向或命令连接符。
|
||||
@@ -40,10 +46,25 @@ _PENDING_APPROVALS: dict[str, dict] = {}
|
||||
|
||||
|
||||
def _parse_agent_action(content: str) -> dict:
|
||||
try:
|
||||
action = json.loads(content.strip())
|
||||
except json.JSONDecodeError as exc:
|
||||
raise ValueError("AI 未返回合法 JSON 动作") from exc
|
||||
text = content.strip()
|
||||
candidates = [text]
|
||||
fenced = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL | re.IGNORECASE)
|
||||
if fenced:
|
||||
candidates.insert(0, fenced.group(1))
|
||||
first_brace = text.find("{")
|
||||
last_brace = text.rfind("}")
|
||||
if first_brace >= 0 and last_brace > first_brace:
|
||||
candidates.append(text[first_brace:last_brace + 1])
|
||||
|
||||
action = None
|
||||
for candidate in candidates:
|
||||
try:
|
||||
action = json.loads(candidate)
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
if action is None:
|
||||
raise ValueError("AI 未返回合法 JSON 动作")
|
||||
if not isinstance(action, dict) or action.get("action") not in {"command", "final"}:
|
||||
raise ValueError("AI 返回了不支持的动作")
|
||||
if action["action"] == "command" and not action.get("command"):
|
||||
@@ -91,6 +112,20 @@ async def run_diagnostic_agent(
|
||||
{"role": "user", "content": user_content},
|
||||
]
|
||||
|
||||
if execution_mode == "ai":
|
||||
initial_command = "kubectl get nodes -o wide"
|
||||
yield {
|
||||
"type": "command", "step": 0, "command": initial_command,
|
||||
"reason": "建立集群节点状态基线,确保 AI 执行模式实际采集现场证据",
|
||||
"mode": "read",
|
||||
}
|
||||
initial_result = await execute_kubectl(initial_command)
|
||||
yield {"type": "result", **initial_result}
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": "AI 执行模式已自动采集第一份现场证据:\n" + json.dumps(initial_result, ensure_ascii=False),
|
||||
})
|
||||
|
||||
for step in range(1, max_steps + 1):
|
||||
yield {"type": "thinking", "step": step, "message": f"AI 正在规划第 {step} 轮诊断"}
|
||||
try:
|
||||
@@ -134,6 +169,7 @@ async def run_diagnostic_agent(
|
||||
"command": command,
|
||||
"reason": reason,
|
||||
"created_by": AI_MODEL,
|
||||
"run_id": "",
|
||||
}
|
||||
yield {
|
||||
"type": "approval_required", "approval_id": approval_id,
|
||||
|
||||
Reference in New Issue
Block a user