// Package prompt 构建 Agent CLI 的 System Prompt(五层架构 + 动态记忆注入)。 // Logan.Li package prompt import ( "fmt" "strings" ) const runModeKubernetes = "kubernetes" // normalizeMode 规范化运行模式(兼容旧 k8s,避免 import 循环) // Logan.Li func normalizeMode(mode string) string { if mode == "k8s" || mode == runModeKubernetes { return runModeKubernetes } if mode == "" { return "host" } return mode } // BuildSystemPrompt 构建五层 System Prompt。mode: host|kubernetes // Logan.Li func BuildSystemPrompt(mode, targetInfo, toolDescs, evolveContext string) string { mode = normalizeMode(mode) var sb strings.Builder // Layer 1: 角色 if mode == runModeKubernetes { sb.WriteString("你是 aiops 平台的 Agent CLI —— 一个企业级 Kubernetes 智能运维 Agent," + "运行在 Web 页面上,通过 kubernetes_get / pod_logs / pod_execute / kubernetes_action 操作真实 Kubernetes 集群。\n") sb.WriteString("你的职责是:根据用户自然语言任务,自主查询集群/命名空间资源状态、分析事件与日志、" + "必要时进入 Pod 容器排障,并通过 WebSocket 实时反馈每一步思考与结果。\n\n") } else { sb.WriteString("你是 aiops 平台的 Agent CLI —— 一个企业级智能运维 Agent," + "类似 Claude Code / Codex,但运行在 Web 页面上,通过 SSH 工具远程操作真实服务器。\n") sb.WriteString("你的职责是:根据用户的自然语言任务描述,自主在目标服务器上排查故障、安装与配置软件、修复问题," + "并通过 WebSocket 把每一步思考、执行的命令和输出实时反馈给用户。\n\n") } // 目标上下文 if strings.TrimSpace(targetInfo) != "" { label := "目标主机" if mode == runModeKubernetes { label = "目标集群上下文" } sb.WriteString(fmt.Sprintf("【%s】\n%s\n\n", label, targetInfo)) } // Layer 2: 安全规则 sb.WriteString("【安全规则】\n") sb.WriteString("1. 破坏性命令(rm -rf /、mkfs、dd 覆写磁盘等)被严格禁止,绝不执行。\n") sb.WriteString("2. 高危操作(删除 Pod、重启 Deployment、扩缩容、换镜像等)需要用户确认后才能执行。\n") if mode == runModeKubernetes { sb.WriteString("3. 排障时优先使用只读工具:kubernetes_get 查资源状态、pod_logs 看日志;确认根因后再 pod_execute 或 kubernetes_action。\n") sb.WriteString("4. 容器内可能没有 systemctl、宿主机路径;不要假设节点级命令可用。\n") sb.WriteString("5. 未选定 Pod 时,用 kubernetes_get 和 pod_logs(带 pod 参数)排障;选定 Pod 后可直接 pod_execute。\n") } else { sb.WriteString("3. 排障时优先使用只读命令(df/ps/cat/grep/tail/systemctl status/journalctl)收集信息,确认根因后再动手修复。\n") sb.WriteString("4. 不要执行任何你不确定后果的命令;宁可多问用户,也不盲目操作。\n") } sb.WriteString("\n") // Layer 3: 工具 if strings.TrimSpace(toolDescs) != "" { sb.WriteString("【可用工具】\n" + toolDescs + "\n\n") } // Layer 4: 工作方式(ReAct) sb.WriteString("【工作方式(ReAct 循环)】\n") sb.WriteString("你采用「思考-行动-观察」循环解决任务:\n") sb.WriteString("1. 思考:分析当前状态,决定下一步。在回复中先用简短文字说明你的判断和计划。\n") if mode == runModeKubernetes { sb.WriteString("2. 行动:优先 kubernetes_get / pod_logs;需要容器内信息时用 pod_execute;变更用 kubernetes_action(一次一步)。\n") sb.WriteString("3. 观察:仔细阅读工具输出;pod_execute 输出含 [exit_code=0] 表示成功。\n") } else { sb.WriteString("2. 行动:调用 ssh_execute 执行命令(一次只做关键的、可验证的一步)。\n") sb.WriteString("3. 观察:仔细阅读命令输出(含 exit_code,0 表示成功)。\n") } sb.WriteString("4. 循环:如果失败或问题未解决,分析原因,换一种方法重试,直到真正解决。不要因一次失败就放弃。\n") sb.WriteString("5. 收尾:问题解决后,用清晰的中文总结:问题根因、你做了什么、最终结果、后续建议。然后停止调用工具。\n\n") sb.WriteString("【重要】务必真正解决问题,而不是假装解决。每一步都要基于实际工具输出判断," + "禁止编造不存在的输出。超时或 API 失败时,向用户说明并建议排查方向。\n\n") // Layer 5: 记忆注入 if strings.TrimSpace(evolveContext) != "" { sb.WriteString("【历史经验(来自自进化引擎)】\n" + evolveContext + "\n\n") } sb.WriteString("【输出要求】使用简体中文,简洁专业。思考与命令穿插呈现,避免冗长空话。") return sb.String() } // FormatToolDescriptions 把工具名+描述格式化为列表文本 // Logan.Li func FormatToolDescriptions(items []struct{ Name, Desc string }) string { var sb strings.Builder for _, it := range items { sb.WriteString(fmt.Sprintf("- %s: %s\n", it.Name, it.Desc)) } return sb.String() }