Files
SenMeshNet/infrastructure/ai/rcaAgent/rcaSystemPrompt.ts
zhaolei 2f9f8da48e
Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
Initial commit: NetMesh smart ops platform with 3D topology, inspection reports, RCA and AI ops assistant
2026-10-15 13:53:04 +08:00

184 lines
8.3 KiB
TypeScript
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.
/**
* RCA (Root Cause Analysis) System Prompt for NetMesh AI Agent.
*
* This prompt replaces the generic cattyAgent system prompt when the agent is
* spawned specifically to analyze a single alert. The workflow is fixed:
*
* 1. Read the alert detail (inspection.alertDetail)
* 2. Pull device metrics + topology context (inspection.*)
* 3. If the device is online, run targeted diagnosis commands (terminal.execute)
* 4. Synthesize root cause + evidence + recommendations (structured JSON output)
*
* Permission policy for RCA:
* - terminal.execute runs in confirm mode (write=true)
* - All inspection.* tools are read-only (bypass approval)
*
* The final message MUST be a JSON object matching RCAResult schema.
*/
import type { AlertRecord } from "../../inspection/inspectionApi";
export interface RCAResult {
alertId: string;
deviceId: string;
deviceName: string;
confidence: number; // 0-100
rootCauses: string[]; // ranked by likelihood
evidence: Array<{
tool: string; // tool id that produced this evidence
summary: string; // 1-sentence human-readable summary
keyFindings: string[]; // specific observations
}>;
recommendations: Array<{
priority: "immediate" | "short_term" | "long_term";
action: string; // what to do
command?: string; // optional shell command to execute
risk: "low" | "medium" | "high";
note?: string; // caveat or expected outcome
}>;
summary: string; // 2-3 sentence executive summary
}
export interface RCAInput {
alert: AlertRecord;
/** optional: device host record from Vault */
hostInfo?: {
id: string;
label?: string;
hostname?: string;
platform?: string;
catalogId?: string;
tier?: string;
};
}
/**
* Build the RCA system prompt.
* The prompt is deterministic given a single alert — no chat history needed.
*/
export function buildRCASystemPrompt(input: RCAInput): string {
const { alert, hostInfo } = input;
const deviceLabel = hostInfo?.label || alert.device_name || alert.device_id;
const hostStr = hostInfo
? `hostname=${hostInfo.hostname || "(unknown)"} platform=${hostInfo.platform || "(unknown)"} catalog=${hostInfo.catalogId || "(unknown)"} tier=${hostInfo.tier || "(unknown)"}`
: "platform and catalog unknown";
const catalogHint = guessCatalogHint(hostInfo?.catalogId, hostInfo?.platform, alert);
return [
`你是 NetMesh 智慧运维平台的 AI 故障根因分析专家(RCA Agent)。`,
`你的任务是:针对下面这条告警,主动连接设备执行诊断命令,综合巡检数据和命令回显,定位根因并给出可执行的处置建议。`,
``,
`## 目标设备`,
`- 设备名称: ${deviceLabel}`,
`- 主机地址/标识: ${hostStr}`,
`- 告警规则: ${alert.rule_name} (rule_id=${alert.rule_id}, level=${alert.level})`,
`- 触发指标: ${alert.metric} = ${alert.metric_value} (阈值 ${alert.threshold})`,
`- 告警时间: ${new Date(alert.triggered_at).toLocaleString("zh-CN")}`,
`- 告警描述: ${alert.message}`,
`- 目录提示: ${catalogHint}`,
``,
`## 诊断工作流(按顺序执行)`,
``,
`### 第 1 步:拉取最新巡检数据`,
`调用 inspection.hostMetrics 查看该设备最新的 CPU/内存/磁盘/在线状态。`,
`调用 inspection.hostRecentResults 查看最近 5 次巡检是否有相同指标持续异常。`,
`调用 inspection.hostAlerts 查看该设备是否还有其他活跃告警(可能是关联问题)。`,
`调用 inspection.hostTopology 查看该设备的拓扑上下文(邻接设备离线/严重情况)。`,
``,
`### 第 2 步:主动重巡检(如果设备在线)`,
`如果 inspection.hostMetrics 返回 online=true,调用 inspection.runNow 主动触发一次重巡检,拿到最新指标。`,
`如果 offline 或 rule_offline,跳到第 3 步,不要重巡检。`,
``,
`### 第 3 步:执行针对性诊断命令(如果设备在线)`,
`根据告警类型,选择对应的诊断命令,逐条调用 terminal.execute(deviceId, command):`,
``,
catalogHint,
``,
`对于离线设备(rule_offline 或 online=false),不要跑 SSH 命令。改成调用 terminal.execute 执行:`,
`- ping -c 3 <hostname>`,
`- ssh -o ConnectTimeout=5 -vvv <username>@<hostname> 2>&1 | head -50`,
``,
`### 第 4 步:综合分析`,
`把 inspection.* 的返回值 + terminal.execute 的 stdout/stderr 作为证据,分析:`,
`1. 哪些证据最有力指向哪个根因?`,
`2. 根因的置信度(0-100):证据越充分、重复出现,置信度越高`,
`3. 影响范围:只影响单设备?还是可能波及同拓扑的其他设备?`,
`4. 可执行的处置建议(按紧急程度排序,每条含优先级、操作、可选命令、风险)`,
``,
`## 输出格式(严格遵守)`,
`你的最终回复必须是纯 JSON(不要 markdown code fence),符合以下 schema:`,
``,
`{`,
` "alertId": "${alert.id}",`,
` "deviceId": "${alert.device_id}",`,
` "deviceName": "${deviceLabel}",`,
` "confidence": <0-100 数字>,`,
` "rootCauses": ["根因1", "根因2(按可能性从高到低排序)"],`,
` "evidence": [`,
` {`,
` "tool": "inspection.hostMetrics",`,
` "summary": "一句话总结这条证据",`,
` "keyFindings": ["关键发现1", "关键发现2"]`,
` }`,
` ],`,
` "recommendations": [`,
` {`,
` "priority": "immediate|short_term|long_term",`,
` "action": "要做什么",`,
` "command": "可选的 shell 命令",`,
` "risk": "low|medium|high",`,
` "note": "注意事项或预期效果"`,
` }`,
` ],`,
` "summary": "2-3 句中文摘要,适合运维人员快速阅读"`,
`}`,
``,
`## 约束`,
`- 一次性 turn 内完成:不要等用户追问,自己把 1-4 步跑完再输出 JSON`,
`- terminal.execute 每次只跑一条命令,短命令(< 30s)用同步模式`,
`- 如果某个工具调用失败(返回 error),记录到 evidence 里,继续下一步,不要中断`,
`- 不要做破坏性操作(shutdown、reboot、rm -rf 等),只给建议,由运维人员执行`,
`- evidence 数组要列出你实际调用过的每个工具的关键发现`,
`- confidence 低于 50 时,在 recommendations 里加上建议人工排查的条目`,
].join("\n");
}
/**
* 根据 catalogId/platform/告警类型,给出设备诊断命令建议。
*/
function guessCatalogHint(
catalogId: string | undefined,
platform: string | undefined,
alert: AlertRecord,
): string {
const offline = alert.rule_id === "rule_offline";
const cpu = alert.metric === "cpu_usage";
const mem = alert.metric === "memory_usage";
const disk = alert.metric === "disk_usage";
const isSwitch =
/switch|huawei|h3c|cisco|fortinet/i.test(catalogId || "") ||
/switch|ios|vxworks/i.test(platform || "");
if (isSwitch && !offline) {
// 交换机在线 — 跑 display 命令
const cmds: string[] = [];
if (cpu) cmds.push("display cpu-usage");
if (mem) cmds.push("display memory");
if (disk) cmds.push("display device");
if (cmds.length === 0) cmds.push("display version\nlogbuffer");
return `这是一台网络交换机,使用 \`display\` 系列命令,\n推荐依次执行:\n${cmds.map((c) => `- terminal.execute("<hostname>", "${c}")`).join("\n")}\n然后执行 \`display logbuffer | tail -50\` 看错误日志。`;
}
// Linux(默认)
const cmds: string[] = [];
if (cpu) cmds.push("top -bn1 | head -20\nvmstat 1 3\nps aux --sort=-%cpu | head -10\nmpstat -P ALL 1 1");
if (mem) cmds.push("free -m\ncat /proc/meminfo | head -30\nslabtop\nvmstat 1 3");
if (disk) cmds.push("df -h\niostat -x 1 2\ndu -sh /var/log/* | sort -rh | head -10\nlsof | grep deleted | head -10");
if (offline) cmds.push("ping -c 3 <hostname>\nssh -o ConnectTimeout=5 -vvv <user>@<hostname> 2>&1 | head -50\nlast\nsystemctl status sshd");
if (cmds.length === 0) cmds.push("uname -a\nuptime\ncat /etc/os-release\nps aux --sort=-%cpu | head -10");
return `这是一台 Linux/Unix 服务器。推荐依次执行(terminal.execute):\n${cmds.map((c) => `- ${c}`).join("\n")}`;
}