#!/usr/bin/env python3 # -*- coding: utf-8 -*- """作业 1 · 步骤 3:创建「运维巡检 Agent」并把 HTTP 工具挂进快照+草稿。""" from __future__ import annotations import json import sys import _bootstrap # noqa: F401 import _agent_cfg as AC import _config as C from dify_api import Dify, pp SYSTEM_PROMPT = """你是企业运维巡检助手。 当用户询问某台服务器的状态时: 1. 必须调用「查询服务器状态 / getServerStatus」工具获取数据; 2. 用清晰的中文列表或表格返回 CPU、内存、GPU 利用率、显存; 3. 不要编造工具未返回的指标。 若用户未提供服务器名,请主动追问。""" def find_app(d: Dify) -> dict | None: name = C.HOMEWORK1_APP_NAME.replace("'", "''") sql = ( "SELECT ap.id AS app_id, a.id AS agent_id, " "a.active_config_snapshot_id AS snapshot_id, d.id AS draft_id " "FROM apps ap " "JOIN agents a ON a.app_id = ap.id " "JOIN agent_config_drafts d ON d.agent_id = a.id " "WHERE ap.name = '%s' LIMIT 1;" % name ) out, err = d.sh( 'docker exec %s psql -U postgres -d dify -t -A -F"|" -c "%s"' % (C.PG_CONTAINER, sql.replace("\n", " ")) ) line = (out or "").strip() if not line or "|" not in line: return None app_id, agent_id, snap_id, draft_id = line.split("|", 3) return { "app_id": app_id.strip(), "agent_id": agent_id.strip(), "snapshot_id": snap_id.strip(), "draft_id": draft_id.strip(), } def create_app(d: Dify) -> dict: body = { "name": C.HOMEWORK1_APP_NAME, "description": "作业 1 · 带 HTTP 工具调用的运维巡检 Agent", "mode": "agent", "icon_type": "emoji", "icon": "🛠", "icon_background": "#DBEAFE", } r = d.post("/apps", body) pp("create app", r) app_id = (r.get("json") or {}).get("id") if not app_id: raise RuntimeError("创建应用失败") info = find_app(d) if not info: raise RuntimeError("创建后未查到 agent_id") return info def configure_agent(cfg: dict) -> dict: cfg.setdefault("prompt", {})["system_prompt"] = SYSTEM_PROMPT cfg.setdefault("knowledge", {}).setdefault("sets", []) tool = { "enabled": True, "provider_type": "api", "provider_id": C.SERVER_STATUS_PROVIDER, "provider": C.SERVER_STATUS_PROVIDER, "tool_name": "getServerStatus", "credential_type": "unauthorized", "credential_ref": None, "runtime_parameters": {}, } tools = cfg.setdefault("tools", {}) dify_tools = tools.setdefault("dify_tools", []) if not any( t.get("provider_id") == C.SERVER_STATUS_PROVIDER and t.get("tool_name") == "getServerStatus" for t in dify_tools ): dify_tools.append(tool) model = cfg.setdefault("model", {}) model.setdefault("model", C.QWEN_MODEL) model.setdefault("model_provider", C.OPENAI_PROVIDER) model.setdefault("plugin_id", "langgenius/openai") ms = model.setdefault("model_settings", {}) if not ms.get("max_tokens"): ms["max_tokens"] = 8192 return cfg def main() -> int: d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD) try: d.login() info = find_app(d) if not info: info = create_app(d) print("app:", json.dumps(info, ensure_ascii=False)) snap = AC.load_cfg(d, "agent_config_snapshots", info["snapshot_id"]) draft = AC.load_cfg(d, "agent_config_drafts", info["draft_id"]) snap2 = configure_agent(snap) draft2 = configure_agent(draft) AC.save_cfg(d, "agent_config_snapshots", info["snapshot_id"], snap2, "hw1_snap") AC.save_cfg(d, "agent_config_drafts", info["draft_id"], draft2, "hw1_draft") out, _ = d.sh( "docker exec %s psql -U postgres -d dify -t -A -c " "\"SELECT config_snapshot::json -> 'tools' FROM agent_config_snapshots WHERE id='%s';\"" % (C.PG_CONTAINER, info["snapshot_id"]) ) print("tools:", out.strip()) print("\n[WARN] 改完不要点「构建/发布」;控制台强刷后新开对话验收。") print("agent_id:", info["agent_id"]) return 0 finally: d.close() if __name__ == "__main__": sys.exit(main())