使用 A3S Code + Kimi 的 LLM 驱动 AHP 服务器
| 93 | |
| 94 | |
| 95 | class AHPServerAgent: |
| 96 | """使用 A3S Code + Kimi 的 LLM 驱动 AHP 服务器""" |
| 97 | |
| 98 | def __init__(self): |
| 99 | self.session = None |
| 100 | self.stats = {"requests": 0, "allowed": 0, "blocked": 0} |
| 101 | |
| 102 | def _ensure_session(self): |
| 103 | """懒初始化:第一次请求时才创建 session(避免启动超时)""" |
| 104 | if self.session is not None: |
| 105 | return |
| 106 | config = find_config() |
| 107 | agent = Agent.create(config) |
| 108 | import tempfile |
| 109 | workspace = tempfile.mkdtemp(prefix="ahp_srv_") |
| 110 | |
| 111 | # 挂载 ahp_skills 目录,让 AHP Server 智能体使用 skill 分析工具调用 |
| 112 | skill_dir = str(Path(__file__).parent / "ahp_skills") |
| 113 | opts = SessionOptions() |
| 114 | opts.builtin_skills = False |
| 115 | opts.skill_dirs = [skill_dir] |
| 116 | opts.permission_policy = PermissionPolicy(default_decision="allow") |
| 117 | self.session = agent.session(workspace, opts) |
| 118 | log(f"AHP Server Agent 已就绪 (config={config}, skills={skill_dir})") |
| 119 | |
| 120 | def _llm_decide(self, prompt: str) -> Dict[str, Any]: |
| 121 | """查询 LLM 并解析 JSON 响应""" |
| 122 | self._ensure_session() |
| 123 | try: |
| 124 | result = self.session.send(prompt) |
| 125 | text = result.text.strip() |
| 126 | start = text.find("{") |
| 127 | end = text.rfind("}") + 1 |
| 128 | if start >= 0 and end > start: |
| 129 | return json.loads(text[start:end]) |
| 130 | log(f"响应中未找到 JSON: {text[:100]}") |
| 131 | except Exception as e: |
| 132 | log(f"LLM 错误: {e}") |
| 133 | # 解析失败时的保守回退 |
| 134 | return {"action": "continue", "reason": "分析失败,默认允许"} |
| 135 | |
| 136 | def _handle_pre_tool_use(self, payload: Dict[str, Any], depth: int) -> Dict[str, Any]: |
| 137 | tool = payload.get("tool", "unknown") |
| 138 | args = payload.get("arguments", {}) |
| 139 | self.stats["requests"] += 1 |
| 140 | log(f"pre_tool_use: tool={tool} args={json.dumps(args)[:80]} depth={depth}") |
| 141 | |
| 142 | prompt = PRE_TOOL_PROMPT.format( |
| 143 | tool=tool, |
| 144 | args=json.dumps(args, ensure_ascii=False), |
| 145 | depth=depth, |
| 146 | ) |
| 147 | decision = self._llm_decide(prompt) |
| 148 | action = decision.get("action", "continue") |
| 149 | reason = decision.get("reason", "") |
| 150 | |
| 151 | if action == "block": |
| 152 | self.stats["blocked"] += 1 |
no outgoing calls
no test coverage detected