# PAM 智能部署 LangGraph 重构设计文档 ## 1. 背景 当前 PAM 智能部署能力由三部分组成: - `PAM_AUTO_DEPLY_SKILL.md`:定义 Agent/Skill 的流程约束、参数确认、执行顺序、回滚规则、检查点和输出规范。 - PAM_NODE MCP 工具:面向 Node 在线执行场景,提供可由 Agent 调用的节点侧部署工具能力。 - `deploy.sh` / `deploy.ps1`:提供实际 API 调用能力,已经暴露 action 入口,可按步骤执行建版、上传、发布、节点发现、云下载、升级、启停、校验、日志下载和回滚。 当前接口能力边界: - PAM_HOME 接口不具备 MCP 能力,只能通过现有脚本 action 调用。 - PAM_NODE 接口支持 MCP,可以由 Agent 通过 MCP 工具调用。 现有模式的主要问题是:核心编排规则写在 Skill 文档中,依赖 Agent 按文本约束执行;HOME 脚本 action 与 NODE MCP 工具之间缺少统一动作路由;用户意图理解、参数抽取、缺参追问、异常解释等智能能力没有被显式建模;断点续跑、人工确认、回滚确认、进度事件和最终报告缺少一个可测试、可复用、可持久化的 Agent Runtime。 本设计将这套 Skill + PAM_NODE MCP + Shell/PowerShell 脚本组合重构为 LangGraph Agent。LangGraph 不只是顺序执行器,而是承载“大模型推理 + Skill 规则约束 + 混合工具路由 + 人工确认 + 状态持久化”的智能部署 Agent。 ## 2. 设计目标 1. 将 LangGraph 实现为 PAM 智能部署 Agent,而不是单纯脚本编排器。 2. 支持 `Skill + MCP`:Skill 提供规则、约束和流程策略,PAM_NODE MCP 提供节点侧在线工具能力。 3. 保留现有 `deploy.sh` / `deploy.ps1` action 能力,作为 PAM_HOME 固定执行后端,并作为全脚本离线模式后端。 4. 引入大模型参与意图理解、参数抽取、缺参追问、执行计划生成、失败解释和报告摘要。 5. 对高风险动作使用确定性图节点和人工确认兜底,禁止大模型绕过确认直接部署或回滚。 6. 支持 checkpoint 持久化和断点续跑。 7. 支持部署过程进度流式输出,避免长时间静默执行。 8. 将 PAM_NODE MCP 和 PAM_HOME 脚本 action 输出解析、错误分类、最终报告生成标准化。 9. 为后续服务化、可视化和 Python 原生 API client 迁移预留接口。 ## 3. 非目标 第一阶段不做以下事情: - 不自动生成、覆盖或修改 `deploy.sh`、`deploy.ps1`、`deploy.bat`、测试脚本。 - 不调用脚本主流程做真实部署,只调用 action 入口。 - 不把 `CLIENT_SECRET` 等敏感字段拼接到命令行。 - 不自动执行回滚。 - 不在正式主流程里使用 `download-cloud-to-node`。 - 不一次性重写所有 PAM HTTP API 调用。 - 不让大模型直接执行高风险工具调用;大模型只能生成建议、解释和结构化计划,真实动作由图节点在确认后执行。 ## 4. 总体架构 ```text 用户输入 / CLI / API / Chat | v LangGraph PAM Deploy Agent | |-- Skill Loader | |-- 加载 PAM_AUTO_DEPLY_SKILL.md | |-- 提取硬约束、参数规范、流程策略 | |-- LLM Reasoning Layer | |-- 意图理解 | |-- 参数抽取与缺参追问 | |-- 部署计划生成 | |-- 失败原因解释 | |-- 报告摘要生成 | |-- Deterministic Graph Layer | |-- 人工确认 interrupt | |-- 流程路由 | |-- checkpoint 更新 | |-- 回滚确认 interrupt | |-- 安全策略校验 | |-- Tool Runtime Layer |-- ActionRouter |-- MCPActionRunner |-- ScriptActionRunner |-- OutputParser |-- EventBus | v 工具后端 | |-- PAM_NODE MCP tools |-- deploy.sh --action ... |-- deploy.ps1 -Action ... | v PAM HOME / PAM NODE API ``` 核心原则是:大模型负责理解、规划、解释和生成候选动作;Skill 负责约束大模型和 Agent 的行为边界;LangGraph 确定性节点负责确认、状态和动作路由;PAM_HOME 动作固定走脚本 action;PAM_NODE 动作优先走 MCP,必要时可按用户确认降级到脚本 action。 ### 4.1 Agent 分层 PAM LangGraph Agent 分为四层: 1. `Skill Policy Layer` - 读取并解析 `PAM_AUTO_DEPLY_SKILL.md`。 - 形成系统提示词、工具白名单、确认点、禁止事项和流程约束。 - 对 LLM 输出做规则校验。 2. `LLM Reasoning Layer` - 从自然语言中识别部署意图。 - 抽取业务参数和控制参数。 - 判断是否缺参或存在歧义。 - 生成用户可读的部署计划、风险提示、失败解释和最终摘要。 3. `Deterministic Orchestration Layer` - 用 LangGraph StateGraph 固化主流程。 - 执行人工确认、条件路由、checkpoint、重试和断点续跑。 - 决定何时允许调用工具。 4. `Tool Runtime Layer` - 按 action 粒度路由 HOME/NODE 动作。 - PAM_HOME 脚本 action 后端。 - PAM_NODE MCP 在线工具后端。 - 全脚本离线后端。 - Fake runner 测试后端。 - 统一 action 结果、错误和事件格式。 ### 4.2 大模型介入点 大模型介入但不越权执行: | 阶段 | LLM 作用 | 确定性约束 | | --- | --- | --- | | 意图识别 | 判断是部署、预演、查询、回滚还是用法说明 | 输出必须符合枚举 `intent` | | 执行策略选择 | 结合用户表达判断使用混合执行还是全脚本执行 | HOME 固定脚本,NODE 可选 MCP 或脚本 | | 参数抽取 | 从自然语言、文件片段或对话上下文抽取参数 | 必填参数缺失时不能进入真实 action | | 缺参追问 | 生成简短追问 | 只问缺失或歧义字段 | | 部署计划 | 生成用户可读执行计划和风险提示 | action 顺序由图固定,不由 LLM 任意改 | | 失败解释 | 将 action 错误、HTTP 响应和日志摘要解释给用户 | 原始错误必须保留 | | 回滚建议 | 根据失败阶段建议 `stopFirst` | 回滚必须 interrupt 等用户确认 | | 最终报告 | 生成摘要和后续建议 | 统计数据来自 State,不由 LLM 编造 | 禁止大模型做的事情: - 直接调用真实部署工具。 - 跳过参数确认。 - 跳过 IP 范围确认。 - 自动执行回滚。 - 修改现有脚本文件。 - 编造 action 执行结果。 ### 4.3 Skill + MCP 混合执行方式 `Skill + MCP` 在本项目中的实际含义是“HOME 脚本 action + NODE MCP 工具”的混合执行,而不是全链路 MCP。 ```text PAM_AUTO_DEPLY_SKILL.md | v SkillPolicy | v LangGraph Agent | v ActionRouter | |-- PAM_HOME action -> ScriptActionRunner -> deploy.sh/deploy.ps1 | |-- PAM_NODE action -> MCPActionRunner -> PAM_NODE MCP tools | v PAM HOME / PAM NODE ``` 当用户明确要求“用 MCP”“直接在线执行”“不要生成脚本”,Agent 仍需要说明:PAM_HOME 当前没有 MCP 能力,HOME 阶段会通过现有脚本 action 执行;PAM_NODE 阶段使用 MCP 工具执行。 当 PAM_NODE MCP 不可用、用户明确要求脚本模式、或需要离线执行时,整轮部署可切换为全脚本执行,但必须在真实部署前向用户确认。 执行策略选择规则: 1. 默认策略:`hybrid_node_mcp`,即 HOME 走脚本 action,NODE 走 MCP。 2. 用户明确指定 MCP:使用 `hybrid_node_mcp`;如果 NODE MCP 不可用则停止并说明,不自动改为全脚本。 3. 用户明确指定脚本或离线:使用 `script_only`,所有 action 都走 `deploy.sh` / `deploy.ps1`。 4. 用户只说“帮我部署”:默认 `hybrid_node_mcp`;如果 NODE MCP 不可用,询问是否切换 `script_only`。 5. 用户只要用法或预演:不调用 MCP,也不调用脚本。 6. 高风险动作无论 MCP 还是脚本,都必须先通过参数确认。 标准 action 归属: | action | 接口归属 | 默认执行后端 | | --- | --- | --- | | `get-token` | PAM_HOME | 脚本 action | | `create-version` | PAM_HOME | 脚本 action | | `upload-package` | PAM_HOME | 脚本 action | | `publish-version` | PAM_HOME | 脚本 action | | `get-node-url` | PAM_HOME | 脚本 action | | `get-online-ips` | PAM_NODE | MCP | | `create-download-task` | PAM_NODE | MCP | | `poll-download-progress` | PAM_NODE | MCP | | `upgrade-ip` | PAM_NODE | MCP | | `poll-upgrade-progress` | PAM_NODE | MCP | | `start-ip` | PAM_NODE | MCP | | `stop-ip` | PAM_NODE | MCP | | `verify-ip` | PAM_NODE | MCP | | `download-log` | PAM_NODE | MCP | | `rollback-ip` | PAM_NODE | MCP,且必须人工确认 | ## 5. 推荐目录结构 ```text pam_deploy_graph/ __init__.py agent.py cli.py graph.py state.py constants.py skill_policy.py nodes/ __init__.py skill.py intent.py params.py planning.py confirmation.py backend.py tools.py scripts.py config_writer.py global_actions.py ip_actions.py rollback.py report.py llm/ __init__.py client.py prompts.py structured_outputs.py validators.py runtime/ __init__.py action_router.py tool_registry.py mcp_runner.py script_runner.py fake_runner.py output_parser.py checkpoint_store.py event_bus.py file_lock.py schemas/ __init__.py skill.py params.py plan.py action_result.py checkpoint.py report.py tests/ test_output_parser.py test_skill_policy.py test_llm_structured_outputs.py test_mcp_runner.py test_script_runner.py test_graph_routes.py test_checkpoint_resume.py fixtures/ action_outputs/ ``` 后续服务化时可新增: ```text pam_deploy_api/ app.py routes.py sse.py ``` ## 6. 关键状态模型 LangGraph 的 State 是整个 Agent 的事实来源。建议使用 `TypedDict` 或 Pydantic model。第一版如果需要开发速度,可用 `TypedDict`;如果需要更强校验,使用 Pydantic。 ```python class DeployState(TypedDict, total=False): run_id: str thread_id: str user_input: str messages: list[dict] skill: SkillPolicy skill_version: str skill_source_path: str llm_intent_result: LlmIntentResult llm_param_result: LlmParamResult llm_plan: LlmDeployPlan mode: Literal["MCP", "API脚本"] execution_strategy: Literal["hybrid_node_mcp", "script_only", "fake"] action_backends: dict[str, Literal["mcp", "script", "fake"]] intent: Literal[ "deploy", "show_usage", "preview", "query_node_ips", "rollback" ] show_usage_only: bool params: DeployParams control: ControlParams node_mcp_server_name: str node_mcp_tool_names: dict[str, str] script_entry: Literal["deploy.sh", "deploy.ps1"] script_base_dir: str config_path: str checkpoint_path: str trace_file_path: str confirmation: ConfirmationState completed_global_steps: list[str] token_acquired: bool hash_code: str node_url: str online_ips: list[str] target_ips: list[str] ip_states: dict[str, IpDeployState] last_success_step: str last_failed_step: str pending_confirmation: str errors: list[DeployError] events: list[DeployEvent] final_report: str ``` ### 6.1 SkillPolicy `SkillPolicy` 是从 `PAM_AUTO_DEPLY_SKILL.md` 加载出的规则对象,供 LLM prompt、图路由和工具执行共同使用。 ```python class SkillPolicy(TypedDict): name: str source_path: str allowed_modes: list[str] allowed_actions: list[str] forbidden_actions: list[str] required_confirmations: list[str] required_params: list[str] optional_params: dict[str, object] action_sequence: list[str] ip_action_sequence: list[str] rollback_rules: dict[str, object] output_requirements: dict[str, object] ``` 用途: - 作为 LLM system prompt 的事实来源。 - 作为确定性节点的规则输入。 - 作为工具白名单和执行顺序约束。 - 当 Skill 文档更新时,Agent 不需要散落修改多个节点。 ### 6.2 ActionRoute `ActionRoute` 描述每个标准 action 的接口归属和实际执行后端。 ```python class ActionRoute(TypedDict): action: str api_domain: Literal["PAM_HOME", "PAM_NODE"] backend: Literal["script", "mcp", "fake"] required_inputs: list[str] produces: list[str] ``` 默认路由: - `PAM_HOME` action 固定 `backend=script`。 - `PAM_NODE` action 在 `hybrid_node_mcp` 策略下 `backend=mcp`。 - `PAM_NODE` action 在 `script_only` 策略下 `backend=script`。 ### 6.3 DeployParams ```python class DeployParams(TypedDict): HOME_BASE_URL: str CLIENT_ID: str CLIENT_SECRET: str AIRPORT_CODE: str APP_NAME: str MODULE_NAME: str VERSION_NUMBER: str ZIP_FILE_PATH: str ACTION_TYPE: str TIMEOUT: int LOG_NAME: str ``` 默认值: - `ACTION_TYPE = "FULL"` - `TIMEOUT = 120` - `LOG_NAME = "app.log"` ### 6.4 ControlParams ```python class ControlParams(TypedDict): user_specified_ips: list[str] all_or_nothing: bool rollback_approved: bool os_target: Literal["windows", "linux", "macos", "git-bash"] resume_from_checkpoint: bool step_interval_sec: int first_poll_delay_sec: int per_ip_step_interval_sec: int per_ip_interval_sec: int failure_pause_sec: int ``` 默认值: - `step_interval_sec = 2` - `first_poll_delay_sec = 2` - `per_ip_step_interval_sec = 1` - `per_ip_interval_sec = 3` - `failure_pause_sec = 0` ### 6.5 LLM 结构化输出 LLM 节点必须输出结构化对象,不直接输出可执行命令。 ```python class LlmIntentResult(TypedDict): intent: str mode_preference: Literal["MCP", "API脚本", "未指定"] confidence: float reasons: list[str] needs_clarification: bool clarification_questions: list[str] class LlmParamResult(TypedDict): extracted_params: dict[str, object] extracted_control: dict[str, object] missing_required_params: list[str] ambiguous_fields: list[str] sensitive_fields_present: list[str] class LlmDeployPlan(TypedDict): summary: str risk_notes: list[str] planned_actions: list[str] requires_confirmation: bool ``` 结构化输出必须经过 `validators.py` 校验: - `intent` 必须在枚举内。 - `planned_actions` 必须是 Skill 允许的 action 子集。 - 不允许出现 shell 命令或 PowerShell 命令文本。 - 不允许包含 `CLIENT_SECRET` 明文。 ### 6.6 IpDeployState ```python class IpDeployState(TypedDict, total=False): ip: str status: Literal["PENDING", "RUNNING", "SUCCESS", "FAILED", "SKIPPED"] current_stage: str completed_steps: list[str] failed_stage: str failure_reason: str rollback_status: Literal[ "ROLLBACK_NOT_RUN", "PENDING_AGENT_CONFIRMATION", "ROLLBACK_SUCCESS", "ROLLBACK_FAILED", "ROLLBACK_REQUEST_FAILED", "ROLLBACK_VERIFY_FAILED", "ROLLBACK_SKIPPED" ] rollback_stop_first: bool log_file: str raw_outputs: dict[str, str] ``` ## 7. 工作流主图 ### 7.1 主流程 ```text START -> load_skill_policy -> llm_understand_request -> validate_llm_intent -> llm_extract_params -> validate_and_normalize_params -> llm_generate_plan -> apply_skill_guardrails -> route_by_intent route_by_intent: show_usage -> show_script_usage -> END preview -> render_preview -> END query_node_ips -> confirm_params -> select_execution_strategy -> build_action_routes -> prepare_tool_runtimes -> query_node_ips_flow -> END deploy -> confirm_params -> select_execution_strategy -> build_action_routes -> prepare_tool_runtimes -> deploy_flow rollback -> rollback_entry_flow deploy_flow: init_runtime_files -> maybe_resume_from_checkpoint -> get_token -> create_version -> upload_package -> publish_version -> get_node_url -> get_online_ips -> filter_target_ips -> confirm_target_scope_if_needed -> create_download_task -> wait_first_poll_delay -> poll_download_progress -> deploy_ip_loop -> aggregate_result -> final_report -> END ``` 说明: - `llm_understand_request`、`llm_extract_params`、`llm_generate_plan` 是智能层节点。 - `validate_llm_intent`、`validate_and_normalize_params`、`apply_skill_guardrails` 是确定性安全节点。 - `select_execution_strategy` 根据用户意图、Skill 规则和 PAM_NODE MCP 可用性选择 `hybrid_node_mcp`、`script_only` 或 `fake`。 - `build_action_routes` 生成每个 action 的实际后端;HOME action 固定脚本,NODE action 按策略走 MCP 或脚本。 - `prepare_tool_runtimes` 检查 PAM_NODE MCP 工具、脚本文件和运行时配置。 ### 7.2 单 IP 子流程 ```text deploy_ip: mark_ip_running -> upgrade_ip -> wait_per_ip_step_interval -> poll_upgrade_progress -> wait_per_ip_step_interval -> start_ip -> wait_per_ip_step_interval -> verify_ip -> wait_per_ip_step_interval -> download_log -> mark_ip_success on failure: record_ip_failure -> download_log_best_effort -> mark_pending_rollback -> rollback_confirm_interrupt -> route_rollback_decision ``` 第一版建议逐台顺序执行 IP,不做并发。原因是部署动作本身风险较高,当前 Skill 文档也要求逐台播报。后续如果需要并发,可以在单 IP 子图稳定后引入受控 fan-out,并保留最大并发数和失败策略。 ### 7.3 Agent ReAct 子图边界 本设计不采用开放式 ReAct 循环执行真实部署工具。原因是 PAM 部署包含建版、发布、升级和回滚等高风险动作,不能让模型自由选择下一步真实工具。 允许使用受限 ReAct 子图的场景: - 缺参追问。 - 用户意图澄清。 - 失败原因解释。 - 日志摘要。 - 最终报告文字润色。 不允许使用开放式 ReAct 的场景: - `create-version` - `upload-package` - `publish-version` - `create-download-task` - `upgrade-ip` - `rollback-ip` 这些动作必须由确定性图节点按照 Skill 固定顺序调用。 ## 8. 节点设计 ### 8.1 load_skill_policy 职责: - 读取 `PAM_AUTO_DEPLY_SKILL.md`。 - 解析 Skill frontmatter 和正文中的关键规则。 - 生成 `SkillPolicy`。 - 将 Skill 规则注入 LLM system prompt 和后续图节点。 失败策略: - Skill 文件缺失或解析失败时,Agent 不进入真实部署。 ### 8.2 llm_understand_request 职责: - 调用大模型理解用户自然语言。 - 输出结构化 `LlmIntentResult`。 - 判断用户是否要求 MCP、脚本、预演、查询或回滚。 约束: - LLM 只输出结构化意图,不输出命令。 - 置信度低或存在歧义时,进入澄清分支。 ### 8.3 validate_llm_intent 职责: - 校验 LLM 输出是否符合枚举。 - 按 Skill 规则修正或拒绝不合法意图。 - 例如用户要求“生成脚本”时,转入 `show_usage` 或限制说明分支。 ### 8.4 llm_extract_params 职责: - 从用户输入、对话上下文、上传的参数文件或历史 checkpoint 中抽取业务参数。 - 识别缺失字段和歧义字段。 - 标记 `CLIENT_ID`、`CLIENT_SECRET` 等敏感字段是否已提供。 约束: - 不把 `CLIENT_SECRET` 明文写入普通消息。 - 不猜测必填参数。 ### 8.5 validate_and_normalize_params 职责: - 将 LLM 抽取结果映射为 `DeployParams` 和 `ControlParams`。 - 补齐默认值。 - 校验必填参数。 - 对机场码、版本号、IP 列表、路径格式做基础校验。 硬约束: - 必填参数缺失时,不进入真实 action。 - 参数有歧义时,应中断并要求补充。 ### 8.6 llm_generate_plan 职责: - 基于 Skill 和已归一化参数生成用户可读部署计划。 - 说明执行策略:默认是 HOME 脚本 action + NODE MCP 的混合执行。 - 如果用户要求 MCP,明确提示 HOME 阶段仍会通过脚本 action 执行,因为 PAM_HOME 不具备 MCP 能力。 - 说明高风险动作和确认点。 约束: - 计划中的 action 顺序必须与 Skill 固定流程一致。 - 计划只用于展示和确认,不作为真实执行序列的唯一来源。 ### 8.7 apply_skill_guardrails 职责: - 校验 LLM 输出是否违反 Skill 禁止事项。 - 校验是否试图调用脚本主流程。 - 校验是否试图自动回滚。 - 校验是否试图修改脚本。 失败策略: - 发现违规时终止真实执行并输出限制说明。 ### 8.8 parse_intent 职责: - 判断用户要真实部署、查看用法、预演计划、查询 Node/IP,还是手动回滚。 - 判断用户是否明确要求 `MCP` 或 `API脚本`。 - 如果用户要求生成或修改脚本,直接进入受限说明分支。 输出: - `intent` - `mode` - `show_usage_only` 说明: - 该节点保留为确定性兜底逻辑,用于 LLM 不可用或 structured output 失败时的基础规则识别。 ### 8.9 normalize_params 职责: - 从用户输入、环境变量、配置文件或外部调用参数中收集业务参数。 - 补齐默认值。 - 标记缺失参数。 - 敏感字段不进入普通播报内容。 硬约束: - 必填参数缺失时,不进入真实 action。 - 参数有歧义时,应中断并要求补充。 说明: - 该节点保留为确定性兜底逻辑。 ### 8.10 confirm_params 职责: - 渲染归一化参数确认单。 - 使用 LangGraph interrupt 等待用户确认。 - 未确认前不得调用任何真实 action。 确认单不展示 `CLIENT_SECRET` 明文,只展示“已提供/未提供”。 ### 8.11 select_execution_strategy 职责: - 根据用户偏好、PAM_NODE MCP 可用性、Skill 规则和运行环境选择执行策略。 - 输出 `execution_strategy = hybrid_node_mcp | script_only | fake`。 选择规则: 1. 用户明确指定 MCP:选择 `hybrid_node_mcp`;PAM_NODE MCP 不可用则停止。 2. 用户明确指定脚本或离线:选择 `script_only`。 3. 用户未指定且 PAM_NODE MCP 可用:选择 `hybrid_node_mcp`。 4. 用户未指定且 PAM_NODE MCP 不可用:询问是否切换 `script_only`。 5. 测试环境可显式选择 fake runner。 ### 8.12 build_action_routes 职责: - 根据 `execution_strategy` 生成 `action_backends`。 - HOME action 固定为 `script`。 - NODE action 在 `hybrid_node_mcp` 下为 `mcp`。 - NODE action 在 `script_only` 下为 `script`。 - fake 策略下所有 action 为 `fake`。 输出示例: ```json { "get-token": "script", "create-version": "script", "upload-package": "script", "publish-version": "script", "get-node-url": "script", "get-online-ips": "mcp", "create-download-task": "mcp", "poll-download-progress": "mcp", "upgrade-ip": "mcp", "poll-upgrade-progress": "mcp", "start-ip": "mcp", "verify-ip": "mcp", "download-log": "mcp", "rollback-ip": "mcp" } ``` ### 8.13 prepare_tool_runtimes 职责: - 混合执行下:检查脚本文件、选择脚本入口、写入 HOME 脚本配置,同时检查 PAM_NODE MCP server 和工具映射。 - 全脚本执行下:检查脚本文件、选择脚本入口、写入完整脚本配置。 - fake 模式下:加载 fixture 输出。 ### 8.14 check_scripts 职责: - 检查当前目录下是否存在 `deploy.sh` / `deploy.ps1`。 - 检查目标脚本是否可读。 - 不自动补写脚本。 失败策略: - 缺少脚本时终止流程并输出原因。 ### 8.15 select_script_entry 职责: - Windows 默认选择 `deploy.ps1`。 - Linux / macOS / Git Bash 默认选择 `deploy.sh`。 - `deploy.bat` 只作为兼容包装入口,不作为 LangGraph action runner 默认入口。 ### 8.16 write_config 职责: - 将确认后的业务参数写入 `config.txt` 或本次运行专属配置文件。 - 命令行只传 action 级参数,不传 `CLIENT_SECRET`。 建议: - 默认写入 `./runtime/config_.txt`,避免覆盖人工维护的 `config.txt`。 - 如果必须兼容脚本默认路径,可由 CLI 参数指定 `--config-path ./config.txt`。 说明: - 混合执行下仍需要写配置文件,因为 PAM_HOME action 固定通过脚本执行。 - 全脚本执行下写完整配置文件。 - PAM_NODE MCP 工具不从 `config.txt` 读参数,由 Agent 通过 MCP tool input 传入必要字段。 - `CLIENT_SECRET` 只允许写入受控配置文件或安全凭证通道,不进入命令行和普通日志。 ### 8.17 init_runtime_files 职责: - 创建 `logs/` 或 `runtime/` 目录。 - 生成本次运行的 `checkpoint_path`。 - 生成本次运行的 `trace_file_path`。 - 写入初始业务 checkpoint。 命名建议: ```text logs/deploy_checkpoint____.json logs/api_trace_____.log ``` ### 8.18 action 节点 每个 action 节点只做四件事: 1. 播报即将执行的阶段。 2. 通过 `ActionRouter` 按 action 归属调用 MCP 或脚本 action。 3. 解析 key=value 输出并更新 State。 4. 更新 checkpoint 和进度事件。 全局 action 节点: - `get_token` - `create_version` - `upload_package` - `publish_version` - `get_node_url` - `get_online_ips` - `create_download_task` - `poll_download_progress` 单 IP action 节点: - `upgrade_ip` - `poll_upgrade_progress` - `start_ip` - `verify_ip` - `download_log` - `rollback_ip` ### 8.19 llm_explain_failure 职责: - 在全局失败或单 IP 失败后,基于 `ActionResult`、原始输出、阶段名和 Skill 规则生成用户可读解释。 - 给出下一步建议,例如检查凭证、包路径、Node 连通性、在线 IP 或是否回滚。 约束: - 不能替换原始错误。 - 不能承诺未发生的恢复动作。 - 回滚建议必须进入确认节点。 ### 8.20 final_report 职责: - 汇总模式、脚本入口、机场、应用、模块、版本。 - 汇总在线 IP 数、目标 IP 数、成功数、失败数。 - 汇总每台 IP 的状态、失败阶段、失败原因、回滚状态、日志路径。 - 输出 checkpoint 和 trace 路径。 - 输出是否断点续跑和当前间隔控制参数。 - 调用 LLM 生成简短摘要,但所有统计值必须来自 State。 ## 9. Tool Runtime 设计 ### 9.1 统一 ToolRunner 接口 ```python class ToolRunner: def run( self, action: str, *, params: DeployParams, config_path: str | None = None, script_entry: str | None = None, ip: str | None = None, hash_code: str | None = None, stop_first: bool = False, trace_file_path: str | None = None, timeout_sec: int | None = None, ) -> ActionResult: ... ``` `ActionRouter` 根据 `state.action_backends[action]` 按 action 粒度分发到具体 runner: ```python class ActionRouter: def run_action(self, state: DeployState, action: str, **kwargs) -> ActionResult: backend = state["action_backends"][action] if backend == "mcp": return self.node_mcp_runner.run(action, params=state["params"], **kwargs) if backend == "script": return self.script_runner.run( action, params=state["params"], config_path=state["config_path"], script_entry=state["script_entry"], **kwargs, ) return self.fake_runner.run(action, params=state["params"], **kwargs) ``` ### 9.2 MCPActionRunner MCPActionRunner 只负责 PAM_NODE action。PAM_HOME 当前没有 MCP 能力,HOME action 不进入 MCPActionRunner。 PAM_NODE MCP 工具映射: | 标准 action | MCP tool 建议名 | 说明 | | --- | --- | --- | | `get-online-ips` | `pam_get_online_ips` | 获取在线工作站 | | `create-download-task` | `pam_create_download_task` | 创建云下载任务 | | `poll-download-progress` | `pam_poll_download_progress` | 轮询云下载进度 | | `upgrade-ip` | `pam_upgrade_ip` | 创建单 IP 升级任务 | | `poll-upgrade-progress` | `pam_poll_upgrade_progress` | 轮询单 IP 升级进度 | | `start-ip` | `pam_start_ip` | 启动应用 | | `stop-ip` | `pam_stop_ip` | 停止应用 | | `verify-ip` | `pam_verify_ip` | 校验应用 | | `download-log` | `pam_download_log` | 下载日志 | | `rollback-ip` | `pam_rollback_ip` | 手动回滚 | MCP runner 职责: - 发现 PAM_NODE MCP server 和工具列表。 - 将标准 action 映射为 MCP tool。 - 将 `DeployParams` 转为 tool input。 - 读取 `node_url`、`airportCode`、`applicationName`、`moduleName`、`versionNumber`、目标 IP 等运行时状态。 - 调用工具并统一转为 `ActionResult`。 - 保存工具原始返回。 - 对敏感字段做脱敏。 MCP runner 约束: - 只能调用 Skill 白名单中的 PAM_NODE 工具。 - 不能调用 PAM_HOME action。 - `rollback-ip` 必须在回滚确认后调用。 - 工具返回结果不得由 LLM 改写后写入 State。 - PAM_NODE MCP 不可用时,不能静默切换脚本后端,除非用户确认 `script_only`。 ### 9.3 ScriptActionRunner ScriptActionRunner 有两类职责: 1. 在 `hybrid_node_mcp` 策略下,固定执行 PAM_HOME action: - `get-token` - `create-version` - `upload-package` - `publish-version` - `get-node-url` 2. 在 `script_only` 策略下,执行全部 action,包括 PAM_NODE action。 脚本后端仍然只允许调用 action 入口,不允许调用脚本主流程。 ### 9.4 Shell 命令 ```bash bash ./deploy.sh \ --config ./config.txt \ --action upload-package \ --trace-file ./logs/api_trace_xxx.log ``` 带 IP: ```bash bash ./deploy.sh \ --config ./config.txt \ --action upgrade-ip \ --ip 192.168.1.10 \ --trace-file ./logs/api_trace_xxx.log ``` 发布版本: ```bash bash ./deploy.sh \ --config ./config.txt \ --action publish-version \ --hash-code 43858bcf \ --trace-file ./logs/api_trace_xxx.log ``` 回滚: ```bash bash ./deploy.sh \ --config ./config.txt \ --action rollback-ip \ --ip 192.168.1.10 \ --stop-first \ --trace-file ./logs/api_trace_xxx.log ``` ### 9.5 PowerShell 命令 ```powershell powershell -File .\deploy.ps1 -ConfigPath .\config.txt -Action upload-package ``` 带 IP: ```powershell powershell -File .\deploy.ps1 -ConfigPath .\config.txt -Action upgrade-ip -Ip 192.168.1.10 ``` 发布版本: ```powershell powershell -File .\deploy.ps1 -ConfigPath .\config.txt -Action publish-version -HashCode 43858bcf ``` 回滚: ```powershell powershell -File .\deploy.ps1 -ConfigPath .\config.txt -Action rollback-ip -Ip 192.168.1.10 -RollbackStopFirst ``` ### 9.6 当前能力差异 Shell 侧当前支持 `--trace-file`,可以由 LangGraph 在一轮部署中传入同一个 trace 文件。 PowerShell 侧当前 `deploy.ps1` action 参数未暴露 `-TraceFile`。第一阶段处理策略: - LangGraph 统一保存每个 PowerShell action 的 stdout/stderr 到工作流 trace。 - 业务 checkpoint 中仍记录同一个 `trace_file_path`。 - 如果必须做到 PowerShell 脚本内部 HTTP trace 也复用同一个文件,需要后续单独评估是否修改 `deploy.ps1`,不纳入第一阶段。 ### 9.7 FakeRunner Fake runner 用于图路由、LLM 结构化输出、checkpoint 和报告生成测试。 职责: - 根据 action 返回 fixture。 - 模拟全局失败、单 IP 失败、回滚确认和日志下载失败。 - 不访问真实 PAM 环境。 ## 10. Action 输出解析 `OutputParser` 负责把脚本 stdout 和 MCP tool result 都归一化为 `ActionResult`。 脚本后端优先解析 `key=value` 行。 输入示例: ```text ACTION=upload-package HASH_CODE=43858bcf TRACE_FILE=./logs/api_trace_xxx.log ``` 解析结果: ```python { "ACTION": "upload-package", "HASH_CODE": "43858bcf", "TRACE_FILE": "./logs/api_trace_xxx.log" } ``` 解析规则: 1. 只将形如 `KEY=VALUE` 的行作为结构化结果。 2. `[INFO]`、`[WARN]`、`[FLOW]` 作为日志,不参与主结果判断。 3. 同名 key 多次出现时: - `IP` 保留为列表。 - 其他字段默认以后出现的值覆盖先出现的值。 4. 非零退出码视为 action 失败。 5. stderr、非结构化 stdout 和原始输出必须保存在 `ActionResult.raw_output`。 6. 出现 `PENDING_AGENT_CONFIRMATION(...)` 时,必须转入人工确认分支。 MCP 后端解析规则: 1. MCP tool 如果返回 JSON object,直接映射到 `values`。 2. MCP tool 如果返回文本,先尝试按 JSON 解析,再尝试按 `key=value` 解析。 3. MCP 原始返回必须保存在 `raw_output`。 4. MCP tool error 统一转换为 `ok=false` 和 `error_summary`。 5. 结果字段名归一化为脚本 action 同款字段,例如 `hashCode` 归一为 `HASH_CODE`,`nodeUrl` 归一为 `NODE_URL`。 ### 10.1 ActionResult ```python class ActionResult(TypedDict): action: str backend: Literal["mcp", "script", "fake"] tool_name: str exit_code: int ok: bool values: dict[str, str | list[str]] stdout: str stderr: str raw_output: str error_summary: str ``` ## 11. Checkpoint 设计 需要两层 checkpoint: 1. LangGraph checkpointer:保存图执行位置和完整 State,用于 `interrupt` 恢复和工作流续跑。 2. 业务 checkpoint JSON:兼容现有 Skill 文档,方便人工排查,也方便脱离 LangGraph 查看部署状态。 ### 11.1 业务 checkpoint 文件 路径: ```text ./logs/deploy_checkpoint____.json ``` 内容: ```json { "runId": "20260529_103000_abcd", "mode": "MCP", "executionStrategy": "hybrid_node_mcp", "actionBackends": { "get-token": "script", "create-version": "script", "upload-package": "script", "publish-version": "script", "get-node-url": "script", "get-online-ips": "mcp", "create-download-task": "mcp", "poll-download-progress": "mcp", "upgrade-ip": "mcp", "poll-upgrade-progress": "mcp", "start-ip": "mcp", "verify-ip": "mcp", "download-log": "mcp", "rollback-ip": "mcp" }, "skillVersion": "pam-auto-deply", "scriptEntry": "deploy.ps1", "nodeMcpServerName": "pam-node", "checkpointPath": "./logs/deploy_checkpoint_HET_PAM_Node_2.0.5.json", "resumeFromCheckpoint": true, "params": { "HOME_BASE_URL": "https://pam.home.example.com", "AIRPORT_CODE": "HET", "APP_NAME": "PAM", "MODULE_NAME": "Node", "VERSION_NUMBER": "2.0.5", "ZIP_FILE_PATH": "C:\\path\\to\\pam-2.0.5.zip", "ACTION_TYPE": "FULL", "LOG_NAME": "app.log" }, "artifacts": { "configPath": "./runtime/config_20260529_103000_abcd.txt", "traceFilePath": "./logs/api_trace_HET_PAM_Node_2.0.5_20260529_103000_abcd.log", "hashCode": "43858bcf", "nodeUrl": "https://pam-node.example.com" }, "onlineIps": [ "192.168.1.10", "192.168.1.11" ], "targetIps": [ "192.168.1.10" ], "completedGlobalSteps": [ "get-token", "create-version", "upload-package", "publish-version" ], "ipStates": { "192.168.1.10": { "status": "FAILED", "completedSteps": [ "upgrade-ip", "poll-upgrade-progress", "start-ip" ], "failedStage": "verify-ip", "failureReason": "Health check failed", "rollbackStatus": "PENDING_AGENT_CONFIRMATION", "rollbackStopFirst": true, "logFile": "./logs/deploy_192.168.1.10.zip" } }, "lastSuccessStep": "start-ip", "lastFailedStep": "verify-ip", "pendingConfirmation": "rollback-ip:192.168.1.10", "updatedAt": "2026-05-29 10:30:00" } ``` 敏感字段不写入业务 checkpoint: - `CLIENT_SECRET` - token - Authorization header ### 11.2 断点续跑策略 1. 启动时如果指定 `resume_from_checkpoint=true`,先读取业务 checkpoint。 2. 校验当前核心参数与 checkpoint 参数是否一致。 3. 核心参数不一致时,不直接续跑,必须要求用户确认重新开始或使用旧参数。 4. 已完成的全局步骤默认跳过。 5. `create-download-task` 已成功但 `poll-download-progress` 未完成时,从 `poll-download-progress` 继续。 6. 单 IP 已成功的默认跳过。 7. 单 IP 失败且处于回滚确认状态时,恢复后先进入回滚确认,不继续后续动作。 ## 12. 人工确认设计 使用 LangGraph interrupt 表示需要外部输入的确认点。 ### 12.1 参数确认 触发点: - 真实部署前。 - 查询 Node/IP 前。 - 手动回滚前。 确认内容: - 模式 - 脚本入口 - HOME_BASE_URL - AIRPORT_CODE - APP_NAME - MODULE_NAME - VERSION_NUMBER - ZIP_FILE_PATH - ACTION_TYPE - TIMEOUT - LOG_NAME - 指定 IP - CLIENT_ID 是否已提供 - CLIENT_SECRET 是否已提供 ### 12.2 IP 范围确认 触发点: - 用户指定 IP 和在线 IP 取交集后,部署范围发生变化。 - 过滤结果为空。 - 用户启用 `all_or_nothing=true` 且部分 IP 不在线。 ### 12.3 回滚确认 触发点: - `upgrade-ip` 失败。 - `poll-upgrade-progress` 失败。 - `start-ip` 失败。 - `verify-ip` 失败。 - action 输出 `PENDING_AGENT_CONFIRMATION(...)`。 确认内容: - 目标 IP - 失败阶段 - 失败原因 - 建议是否回滚 - `stopFirst` 建议值 默认建议: - 升级失败:建议回滚,`stopFirst=false` - 启动失败:建议回滚,`stopFirst=true` - 校验失败:建议回滚,`stopFirst=true` ## 13. 进度事件设计 工作流运行中输出结构化事件,供 CLI、日志、SSE 或 WebSocket 使用。 ```python class DeployEvent(TypedDict): run_id: str level: Literal["INFO", "WARN", "ERROR"] type: Literal[ "FLOW_START", "FLOW_DONE", "FLOW_FAIL", "ACTION_START", "ACTION_DONE", "ACTION_FAIL", "WAIT", "IP_START", "IP_DONE", "IP_FAIL", "CONFIRMATION_REQUIRED", "REPORT" ] stage: str ip: str | None message: str next_stage: str | None wait_sec: int | None data: dict created_at: str ``` 事件示例: ```json { "type": "ACTION_DONE", "stage": "upload-package", "message": "软件包上传完成", "data": { "HASH_CODE": "43858bcf" } } ``` 等待事件示例: ```json { "type": "WAIT", "stage": "create-download-task", "message": "等待 2 秒后开始首次下载进度轮询", "next_stage": "poll-download-progress", "wait_sec": 2 } ``` ## 14. 分支流程 ### 14.1 混合智能执行 适用场景: - 用户明确要求“用 MCP”“直接在线执行”“不要生成脚本”。 - 用户只说“帮我部署”,且当前环境存在可用 PAM_NODE MCP 工具。 流程: ```text load_skill_policy -> llm_understand_request -> llm_extract_params -> validate_and_normalize_params -> llm_generate_plan -> confirm_params -> select_execution_strategy(hybrid_node_mcp) -> build_action_routes -> prepare_tool_runtimes -> deploy_flow ``` 行为: - PAM_HOME action 通过 `ScriptActionRunner` 调用 `deploy.sh` / `deploy.ps1` action。 - PAM_NODE action 通过 `MCPActionRunner` 调用 PAM_NODE MCP 工具。 - 需要写配置文件供 HOME 脚本 action 使用,但敏感字段不进入命令行和普通日志。 - 仍然按 Skill 固定 action 顺序执行。 - 仍然写业务 checkpoint 和 trace。 - 仍然要求参数确认、IP 范围确认和回滚确认。 ### 14.2 脚本离线执行 适用场景: - 用户明确要求“用脚本”“离线执行”。 - PAM_NODE MCP 不可用且用户确认切换全脚本后端。 流程: ```text load_skill_policy -> llm_understand_request -> llm_extract_params -> validate_and_normalize_params -> llm_generate_plan -> confirm_params -> select_execution_strategy(script_only) -> build_action_routes -> prepare_tool_runtimes -> deploy_flow ``` 行为: - 只调用 `deploy.sh` / `deploy.ps1` action 入口。 - 不调用脚本主流程。 - `CLIENT_SECRET` 只写入配置文件,不进入命令行。 ### 14.3 只说明脚本用法 适用场景: - 用户要求“给我脚本用法”。 - 用户要求“生成脚本”,但 Skill 禁止生成或修改脚本。 - 用户明确“不直接动环境”。 行为: - 说明现有 `deploy.sh` / `deploy.ps1` action 用法。 - 不写 `config.txt`。 - 不调用 MCP。 - 不调用真实脚本 action。 ### 14.4 预演部署计划 适用场景: - 用户只想确认参数和计划,不执行真实部署。 行为: - LLM 抽取和归一化参数。 - LLM 生成用户可读部署计划。 - 输出确认单。 - 输出预计 action 顺序。 - 输出执行策略:混合执行或全脚本执行。 - 明确 HOME action 和 NODE action 的执行后端。 - 如存在 checkpoint,说明可从哪个步骤恢复。 - 不调用真实 action。 ### 14.5 只查询 Node 和在线 IP 流程: ```text confirm_params -> select_execution_strategy -> build_action_routes -> prepare_tool_runtimes -> get_token -> get_node_url -> get_online_ips -> report_node_ips ``` 禁止执行: - `create-version` - `upload-package` - `publish-version` - `create-download-task` - `upgrade-ip` ### 14.6 手动回滚 流程: ```text rollback_entry -> llm_extract_rollback_target -> confirm_rollback_target -> select_execution_strategy -> build_action_routes -> prepare_tool_runtimes -> rollback_ip -> verify_ip optional -> download_log -> update_checkpoint -> final_report ``` 回滚必须由用户明确确认,不能根据失败状态自动执行。 ## 15. 错误处理策略 ### 15.1 全局失败 以下阶段失败时终止整轮部署: - `get-token` - `create-version` - `upload-package` - `publish-version` - `get-node-url` - `get-online-ips` - `create-download-task` - `poll-download-progress` 处理: - 记录 `last_failed_step`。 - 写 checkpoint。 - 输出失败报告。 - 保留原始 action 输出。 ### 15.2 单 IP 失败 以下阶段失败时只标记当前 IP 失败: - `upgrade-ip` - `poll-upgrade-progress` - `start-ip` - `verify-ip` 处理: - 记录失败阶段和原因。 - 尽力执行 `download-log`。 - 写 checkpoint。 - 转入回滚确认。 - 未确认回滚前,不执行 `rollback-ip`。 ### 15.3 日志下载失败 `download-log` 失败不覆盖原始失败原因。 处理: - 记录日志下载失败。 - 保留主失败阶段。 - 报告中明确日志缺失或下载失败。 ## 16. 安全设计 1. `CLIENT_SECRET` 不进入命令行。 2. `CLIENT_SECRET` 不进入普通日志、进度事件、最终报告。 3. token 不进入最终报告。 4. action 原始输出保存前需要做敏感字段脱敏。 5. `config.txt` 或运行时配置文件权限应尽量限制为当前用户可读写。 6. 回滚必须显式确认。 7. 若用户要求“不落地配置文件”,真实部署流程直接终止并说明原因。 8. 对脚本路径使用白名单,只允许当前工作目录下既有脚本。 9. MCP 工具调用使用白名单,只允许 Skill 中定义的 PAM_NODE 工具。 10. LLM 输出必须经过结构化校验和 Skill guardrails。 11. LLM 不能生成可执行 shell/PowerShell 命令作为真实执行依据。 12. PAM_HOME action 不允许被路由到 MCP。 ## 17. CLI 设计 第一阶段建议先落地 Agent CLI,便于本地验证 Skill、LLM、MCP 和脚本后端。 ### 17.1 部署 ```bash python -m pam_deploy_graph.cli deploy \ --strategy hybrid-node-mcp \ --home-base-url https://pam.home.example.com \ --client-id xxx \ --client-secret "***" \ --airport-code HET \ --app-name PAM \ --module-name Node \ --version-number 2.0.5 \ --zip-file-path C:\path\to\pam-2.0.5.zip \ --target-ip 192.168.1.10 \ --target-ip 192.168.1.11 ``` 脚本后端: ```bash python -m pam_deploy_graph.cli deploy \ --strategy script-only \ --config ./deploy_params.json ``` ### 17.2 预演 ```bash python -m pam_deploy_graph.cli preview --config ./deploy_params.json ``` ### 17.3 对话式 Agent ```bash python -m pam_deploy_graph.cli chat ``` 对话式 Agent 行为: - 使用 LLM 理解用户自然语言。 - 使用 Skill 规则控制工具调用。 - 在真实部署前输出确认单并等待用户确认。 - 支持继续追问缺失参数。 ### 17.4 断点续跑 ```bash python -m pam_deploy_graph.cli resume \ --checkpoint ./logs/deploy_checkpoint_HET_PAM_Node_2.0.5.json ``` ### 17.5 回滚确认恢复 ```bash python -m pam_deploy_graph.cli resume \ --thread-id \ --approve-rollback \ --ip 192.168.1.10 \ --stop-first ``` ## 18. 服务化设计 后续可将 Agent CLI 包装为 FastAPI 服务。 接口建议: ```text POST /agent/chat POST /deploy/preview POST /deploy/start POST /deploy/{run_id}/confirm POST /deploy/{run_id}/rollback/confirm POST /deploy/{run_id}/resume GET /deploy/{run_id} GET /deploy/{run_id}/events GET /deploy/{run_id}/report ``` 事件输出: - CLI:直接打印结构化进度。 - API:通过 SSE 或 WebSocket 输出 `DeployEvent`。 ## 19. 测试策略 ### 19.1 单元测试 覆盖: - `SkillPolicy` 从 Skill 文档提取规则。 - LLM structured output schema 校验。 - LLM 输出违反 Skill guardrails 时会被拒绝。 - `OutputParser` 解析 `key=value`。 - 多个 `IP=` 行解析为列表。 - `PENDING_AGENT_CONFIRMATION(...)` 检测。 - 敏感字段脱敏。 - MCP tool input 构造。 - 脚本 action 命令构造。 - checkpoint JSON 写入和读取。 ### 19.2 图路由测试 覆盖: - `show_usage` 不调用 action。 - `preview` 不调用 action。 - 参数未确认不调用 action。 - PAM_NODE MCP 可用且用户未指定策略时使用 `hybrid_node_mcp`。 - PAM_NODE MCP 不可用时需要用户确认才切 `script_only`。 - HOME action 始终路由到脚本。 - NODE action 在混合策略下路由到 MCP。 - IP 范围变化进入确认。 - 单 IP 失败进入回滚确认。 - 用户拒绝回滚后继续或结束。 ### 19.3 LLM 节点测试 覆盖: - 自然语言中抽取机场、应用、模块、版本和包路径。 - 缺少 `CLIENT_SECRET` 时生成追问。 - 用户说“不要动环境”时进入预演或用法说明。 - 用户说“用 MCP”时 strategy preference 为 `hybrid_node_mcp`,并提示 HOME 仍走脚本 action。 - 用户说“离线脚本执行”时 mode preference 为 API脚本。 - LLM 计划中出现非法 action 时被 guardrails 拒绝。 ### 19.4 MCP runner 测试 覆盖: - PAM_NODE 标准 action 到 MCP tool 的映射。 - PAM_NODE MCP 工具缺失时停止。 - PAM_HOME action 不会进入 MCP runner。 - MCP 返回结构化结果转为 `ActionResult`。 - MCP 原始错误进入 `raw_output`。 - 回滚未确认时不调用 `pam_rollback_ip`。 ### 19.5 Runner 假实现测试 使用 fake runner 模拟脚本输出: - 全部成功。 - 全局失败。 - 上传返回 `HASH_CODE`。 - Node 返回 `NODE_URL`。 - 在线 IP 返回多个 `IP=`。 - 单 IP 校验失败。 - 日志下载失败。 ### 19.6 集成测试 MCP 或脚本真实后端接入后,只做可控环境下的 smoke: - `get-token` - `get-node-url` - `get-online-ips` 完整部署集成测试需要人工指定测试环境和测试包,不默认纳入自动 CI。 ## 20. 实施计划 ### 阶段一:Agent MVP 交付: - `DeployState` - `SkillPolicy` 加载器 - LLM structured output schema - `llm_understand_request` - `llm_extract_params` - `llm_generate_plan` - Skill guardrails - 主图和单 IP 顺序流程 - fake runner - output parser - 参数确认 interrupt - 业务 checkpoint JSON - 最终报告 验收: - 对话式输入能抽取参数并生成部署计划。 - 能跑通 `preview`。 - 能跑通 `query_node_ips`。 - fake runner 能跑通完整部署成功链路。 - fake runner 能验证单 IP 失败和回滚确认。 - LLM 不能绕过参数确认调用 fake runner。 ### 阶段二:混合工具路由接入 交付: - `ActionRouter`。 - PAM_HOME action 到 `ScriptActionRunner` 的固定路由。 - PAM_NODE MCP server/tool discovery。 - `MCPActionRunner`。 - PAM_NODE 标准 action 到 MCP tool 的映射。 - MCP 工具结果统一转 `ActionResult`。 - 混合执行 `query_node_ips` smoke:`get-token/get-node-url` 走脚本,`get-online-ips` 走 MCP。 验收: - 用户指定 MCP 时进入 `hybrid_node_mcp`,HOME 阶段仍走脚本。 - 用户未指定策略且 PAM_NODE MCP 可用时默认混合执行。 - PAM_NODE MCP 不可用时不会静默切全脚本。 - 回滚未确认时不会调用 MCP 回滚工具。 ### 阶段三:全脚本后端完善 交付: - Shell runner 接入全部 `deploy.sh --action`。 - PowerShell runner 接入全部 `deploy.ps1 -Action`。 - 真实 stdout/stderr 收集。 - action 超时控制。 - 统一工作流 trace 文件。 验收: - 在 Windows 上可调用 `deploy.ps1` action。 - 在 Git Bash/Linux 上可调用 `deploy.sh` action。 - 不调用脚本主流程。 ### 阶段四:断点续跑完善 交付: - 从业务 checkpoint 恢复。 - 参数一致性校验。 - 已完成全局步骤跳过。 - 已成功 IP 跳过。 - pending rollback 恢复后继续等待确认。 验收: - 模拟中断后可从指定阶段恢复。 - 参数变化时会要求用户确认。 ### 阶段五:服务化和可视化 交付: - Chat Agent API。 - FastAPI 包装。 - SSE/WebSocket 进度事件。 - 运行记录查询。 - 最终报告接口。 验收: - 前端或调用方可实时看到进度。 - 可通过接口完成确认和恢复。 ### 阶段六:Python 原生 API client 迁移 交付: - 将脚本内部 HTTP 能力逐步迁移为 Python client。 - 保留脚本作为兼容入口。 验收: - Python client 与脚本 action 行为一致。 - 关键接口都有单元测试和契约测试。 ## 21. 风险与待决事项 1. PowerShell 脚本当前未暴露 `-TraceFile`,接口级 trace 复用存在能力差异。 2. HOME action 只能通过脚本 action 执行,脚本内部会重复获取 token。第一阶段接受该开销,后续若 PAM_HOME 支持 MCP 或 Python client 后再优化。 3. `config.txt` 落地包含敏感字段,需要明确文件权限和清理策略。 4. 单 IP 是否允许并发需要谨慎评估,第一版不并发。 5. 真实回滚策略需要业务方确认“失败后是否继续处理后续 IP”的默认行为。 6. PAM_NODE MCP 工具名称、参数 schema 和返回 schema 需要与 MCP server 对齐。 7. LLM 结构化输出需要稳定模型和严格 schema 校验,否则只能作为建议,不能驱动真实工具。 8. Skill 文档如果继续演进,需要建立 SkillPolicy 的解析测试,避免规则变更后 Agent 行为漂移。 9. 混合执行会同时依赖脚本环境和 MCP 环境,需要在启动前做两类运行时检查。 ## 22. 推荐第一版取舍 第一版只做三件事: 1. 用 LangGraph 实现 Agent 骨架:Skill 加载、LLM 结构化理解、确认点、固定流程和 fake runner。 2. 优先接混合工具路由:HOME 脚本 action + NODE MCP,形成符合当前接口能力的智能部署闭环。 3. 再完善全脚本策略作为离线和兜底路径,不重写现有脚本。 这样能先体现智能部署:用户用自然语言发起部署,LLM 负责理解和计划,Skill 负责约束,LangGraph 负责状态和确认,ActionRouter 按 HOME/NODE 归属分发到脚本或 MCP。流程稳定后,再决定是否把脚本能力迁移到 Python 原生实现。