--- name: zhipu-coding-subagent description: 智谱 GLM Coding Plan 作为 Hermes delegate_task 的 subagent provider,用于 coding 任务。API key 存于 ~/.hermes/.env (GLM_CODING_API_KEY),delegation 配置在 config.yaml 中。 category: autonomous-ai-agents tags: [zhipu, glm, coding-plan, delegation, subagent] --- # 智谱 Coding Plan Subagent 将智谱 GLM Coding Plan 配置为 Hermes `delegate_task` 的 subagent provider, 让 Hermes 可以通过 `delegate_task` 调用智谱模型处理 coding 任务。 ## 配置概要 | 配置项 | 值 | |--------|-----| | Provider | `custom:zhipu-coding` | | Base URL | `https://api.z.ai/api/coding/paas/v4` | | 默认模型 | `glm-5.1` | | API Key 位置 | `~/.hermes/.env` → `GLM_CODING_API_KEY` | | 协议 | OpenAI Chat Completions 兼容 | ## 可用模型 通过 Coding Plan API key 可用的模型(OpenAI 协议端点): - `glm-5.2` (最新推理模型 ⭐,reasoning 模型类似 o1/R1,max_tokens 需 2-3x) - `glm-5.1` (旗舰,推荐) - `glm-5` - `glm-5-turbo` - `glm-4.7` - `glm-4.6` - `glm-4.5` - `glm-4.5-air` ### GLM-5.2 CLI 快速调用模板 ```bash python3 << 'PYEOF' import urllib.request, json with open('/tmp/glm_key.txt') as f: key = f.read().strip() req = urllib.request.Request('https://api.z.ai/api/coding/paas/v4/chat/completions', data=json.dumps({ 'model': 'glm-5.2', 'messages': [{'role':'user','content':'你的prompt'}], 'max_tokens': 4000 # reasoning模型:必须2-3x }).encode(), method='POST') req.add_header('Authorization', f'Bearer {key}') req.add_header('Content-Type', 'application/json') resp = json.loads(urllib.request.urlopen(req, timeout=120).read()) choice = resp['choices'][0]['message'] print('CONTENT:', choice.get('content', '')) print('REASONING:', choice.get('reasoning_content', '')[:200]) PYEOF ``` GLM-5.2 是 reasoning 模型(chain-of-thought),响应包含两个字段: - `content` — 最终回答 - `reasoning_content` — 思维链(消耗 reasoning_tokens) ⚠️ **关键限制**:`max_tokens` 同时覆盖 reasoning + content!如果设太小, 所有 tokens 被推理吃掉,content 为空。**建议至少 2000-4000 tokens**, 复杂任务需 6000+。 典型数据:简单代码 1000 tokens → 290R+94C,中文分析 2000 → 812R+588C。 延时:简单 ~6s,复杂 ~25-40s。 ✅ **代码审查已实战验证**(2026-07-04): - Config Health 实现审查:34KB prompt → 6000 tokens,85s,发现 5🔴+7🟡 - Bridge Server 安全审查:61KB prompt → 8000 tokens,131s,发现 6🔴+5🟡 - 二次审查也发现了真实遗漏问题(dependsOn 死路、锁竞态、S2 吊销绕过等) - 完整工作流见 `references/glm52-code-review.md` ## Config 片段 ```yaml delegation: model: glm-5.1 provider: custom:zhipu-coding base_url: https://api.z.ai/api/coding/paas/v4 api_key: ${GLM_CODING_API_KEY} api_mode: '' max_iterations: 50 child_timeout_seconds: 600 ``` ## API Key 管理 API Key 格式:`face68ad5cd546dab842ebb9332d0160.ALUElE8NPNjbNKGV` **变更 Key 时**: ```bash # 更新 .env 文件中的 GLM_CODING_API_KEY python3 -c " import os env = os.path.expanduser('~/.hermes/.env') lines = [l for l in open(env).readlines() if not l.startswith('GLM_CODING_API_KEY=')] lines.append('GLM_CODING_API_KEY=新KEY\n') open(env,'w').writelines(lines) " ``` **测试 API 连通性**: ```python import urllib.request, json, os from dotenv import load_dotenv load_dotenv(os.path.expanduser('~/.hermes/.env')) KEY = os.getenv('GLM_CODING_API_KEY') BASE = 'https://api.z.ai/api/coding/paas/v4' # 模型列表 req = urllib.request.Request(BASE + '/models') req.add_header('Authorization', f'Bearer {KEY}') print(json.loads(urllib.request.urlopen(req, timeout=15).read())) # 简单对话 req = urllib.request.Request(BASE + '/chat/completions', data=json.dumps({'model': 'glm-4.7', 'messages': [{'role':'user','content':'hi'}], 'max_tokens': 20}).encode(), method='POST') req.add_header('Authorization', f'Bearer {KEY}') req.add_header('Content-Type', 'application/json') print(json.loads(urllib.request.urlopen(req, timeout=30).read())) ``` ## 典型工作流 ### Spec / 代码 Review > ⚠️ **2026-06-19 更新:** GLM-5.1 通过 `delegate_task` 做 spec review 已不可靠——连续两次只返回一句话(`api_calls: 1, output_tokens: ~50`)就 completed,web fetch 成功但模型不产出审查内容。长输出 spec/code review 任务**优先用 `claude -p`**,短 coding 任务仍可用 `delegate_task`。 **备选方案 — Python 脚本直调 API**(已验证可靠,优于 `delegate_task` 的长输出场景): 详见 `references/glm-direct-api-review.md` — 写 Python 脚本直调 Coding Plan API,spec 全文喂入,返回完整审查结果(已验证:17KB spec → 3k tokens review,无截断)。 **推荐方案 — Claude Code 直调:** ```bash curl -sL $DOC_URL | claude -p --max-turns 8 --dangerously-skip-permissions \ "你是代码审查专家。请从架构、安全、错误处理、边界条件等维度审查此文档..." 2>&1 ``` 配合 `terminal(background=true, notify_on_complete=true)` 异步执行,`process(action='wait')` 等待结果。 **备选方案 — delegate_task(仅短任务):** ``` delegate_task( goal="审查单文件代码逻辑问题...", context="短任务场景...", toolsets=["terminal","file"] ) ``` GLM-5.1 通过 delegate_task 处理短 coding 任务(如单文件 bug fix、简单逻辑检查)仍正常,长输出场景切 Claude Code。 ### 当 delegate_task 暂时不可用时 如果配置刚更新但 delegate_task 仍走旧 provider(gateway 缓存未刷新), 用 `terminal()` + Python 直接调智谱 API 作为应急方案(见下方"直接调 API"), 同时执行 `hermes gateway restart` 修复。重启后验证:`delegate_task(goal="ls /tmp/")`。 ## 替代方案:Claude Code + 智谱 智谱 Coding Plan 也提供 Anthropic Messages 协议端点: - `https://api.z.ai/api/anthropic` 可以直接配置 Claude Code 使用智谱: ```json // ~/.claude/settings.json { "env": { "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic", "ANTHROPIC_AUTH_TOKEN": "你的API Key", "ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.1", "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.1" } } ``` 然后通过 `terminal(background=true)` 调用 `claude -p "prompt"`。 ### Claude Code 模型版本管理 **推荐用 `opus` alias 代替 pin 版本号**(2026-07-04 更新): ```json // ~/.claude/settings.json {"model": "opus"} // 自动跟随最新版(当前 → Opus 4.8) ``` 旧配置 `"model": "claude-opus-4-20250514"` 锁定了 2025.5 的最早版本, 错过了 4.1→4.5→4.6→4.7→4.8 多轮升级。改为 `opus` 后自动获取最新。 验证:`claude --version` 显示 CLI 版本,实际模型通过 API 确定。 ### Claude Opus 4.8 审计 **2026-07-04 已验证**:Opus 4.8 比 Opus 4 **慢 3-4 倍但质量显著更高**, 能发现之前审查遗漏的"防护错觉"问题(安全控制在代码中存在但实际被绕过)。 核心数据(详见 `references/opus48-code-review.md`): | repo | 耗时 | max_turns | 结果 | |------|------|:---:|------| | Atomlisting_Server | 458s | 12 | ✅ 4🟡+5🟢,无新🔴 | | AtomK-Desktop | 458s | 12 | ❌ 超时,重试 16 turns→✅ 4🟡+4🟢 | | Bridge | 143s | 12 | ❌ 超时,重试 16 turns→❌ 仍超时 | **关键坑**: - `--max-turns 12` **不够用**,大仓库建议 `16`,超大用 `20` - `process(action='wait', timeout=...)` 有 ~60s 钳制,改用**循环 poll** - 并行三件套需 `timeout=900` 以上 - 在 prompt 中加 `"高效审查——用 git diff + grep,不要逐文件阅读"` 可节省 ~30% **Claude Code 超时后的 fallback — Python 脚本直调 Anthropic API**: 当 Claude Code 多次超时(如 Bridge 12→16 turns 仍不够),改用 `write_file` 写 Python 脚本 → `terminal()` 调 Anthropic Messages API: ```python # 用 write_file 写 /tmp/audit_bridge.py # 注意:必须用绝对路径!heredoc 的 workdir 不继承 terminal(workdir=) import urllib.request, json key_line = [l for l in open(os.path.expanduser('~/.hermes/.env')).readlines() if l.startswith('GLM_CODING_API_KEY=')] key = key_line[0].split('=', 1)[1].strip() req = urllib.request.Request('https://api.z.ai/api/anthropic/v1/messages', ...) ``` 脚本模板见 `references/opus48-code-review.md`。 **适用场景**:深度安全审计用 4.8(值得等),日常快速审查用 GLM-5.2。 ## 完整审查→修复流水线 GLM-5.1 审查 + Claude Code 实现 = 已验证的大仓库安全审计流水线: ``` GLM-5.1 全量审查 → Spec → Claude Code Phase 1 (🔴) → Phase 2 (🟡) → Phase 3 (🟢) ``` 详见 `atomk-desktop-development` skill 的 `references/glm-claude-review-pipeline.md`。 ### Claude Code 实现注意事项 - `cat prompt.txt | claude -p "..." --permission-mode acceptEdits` — 喂 spec + 指令 - 大文件(200+行变更)可能触发 terminal 600s 超时,但 Claude Code 通常已完成编辑 - 超时后先 `git diff --stat` 检查变更,`py_compile` 验证,不要当失败重跑 - 每阶段独立分支 + 独立 PR + 回归测试 ## 注意事项 - **不用于分解任务**:这个 subagent 配置是直接作为 coding agent 用的,不是用于 kanban 式的任务分解 - Coding Plan 按订阅配额计费,不是按 token - API key 绝不出现在 shell 命令中,必须通过 Python chr() 或 env 文件读取 - 删除旧 key:需要同时在 `.env` 和智谱后台删除 - **配置变更后需 `hermes gateway restart`**:`delegate_task` 的 config.yaml 修改不会自动生效 - **审查工作流**:详见 `references/review-workflow.md`(spec review + delegate_task 流程) - **批量代码审查**:详见 `references/code-review-batch.md`(多文件大规模审查,Python 脚本 + 直接 API 调用,已验证:60k chars prompt → 23k chars review) - **Spec 审查(长文档)**:详见 `references/direct-api-spec-review.md`(GLM-5.1 直接 API 审查 17KB spec,输出 94 行完整 review,6🔴+10🟡+17遗漏) - **直接 API 调用**:详见 `references/direct-api-review.md`(delegate_task 不可用时的应急方案,Python 脚本 + terminal() 模式) - **GLM-5.2 代码审查**:详见 `references/glm52-code-review.md`(GLM-5.2 CLI 直调审查,2026-07-04 已验证:34KB 输入 → 5🔴+7🟡,85s) - **Claude Opus 4.8 审计**:详见 `references/opus48-code-review.md`(Opus 4.8 审计实战数据,2026-07-04 已验证:三件套并行审查,458s/server,发现防护错觉问题) ## ⚠️ 常见陷阱 ### GLM-5.1 返回极短/截断响应 — delegate_task 场景 **症状:** `delegate_task` 走 GLM-5.1 时,subagent 只输出一句话(如"我来获取文档并进行全面审查。")就 `exit_reason: "completed"`,实际任务根本没完成。API calls 显示只有 1 次(如 web fetch 成功),output_tokens 极少(50-100)。 **触发条件:** 给 GLM-5.1 的 prompt 包含需要长输出的任务(如 code/spec review),且通过 `delegate_task` → Hermes subagent 链路时偶发(非必现,但连续重试也会复现)。 **根本原因推测:** GLM-5.1 的 Coding Plan 端点可能对某些长输出场景提前截断(与 Hermes subagent 的 max_tokens/stop 序列交互有关)。 **应急方案:** 改为 `terminal(background=true)` → `claude -p` 直调: ```bash # 将 prompt 写入文件,通过 stdin 喂给 claude cat /tmp/review-prompt.txt | claude -p --max-turns 8 --dangerously-skip-permissions "你的指令" 2>&1 ``` 配合 `notify_on_complete=true` 后台执行,用 `process(action='wait')` 等待结果。 **决策逻辑:** - Spec review / 长分析 → 优先 `claude -p`(已验证输出完整) - 短任务 / coding fix → `delegate_task`(GLM-5.1 短输出场景正常) - 如果 `delegate_task` 第一次就只返回一句话 → 不要再重试,直接切到 `claude -p` ### API Key 含 `***` → inline Python `-c` 语法错误 API key 结尾的 `***` 在 `python3 -c "..."` 的引号匹配中会被解析为字符串终结符失败。 **任何基于 inline `-c` 的调用都会报 `SyntaxError: unterminated string literal`。** **唯一可靠方案:heredoc** ```bash python3 << 'PYEOF' import urllib.request, json # 用 write_file 写入临时的 .py 文件也行,但 heredoc 更简洁 K = open('/tmp/glm_key.txt').read().strip() # 先用 write_file 存 key # ... 其余代码 PYEOF ``` **预存 key 到文件**(一次,用 `grep | cut` 避免 heredoc `***` 问题): ```bash grep 'GLM_CODING_API_KEY=' ~/.hermes/.env | cut -d= -f2 > /tmp/glm_key.txt ``` 验证: `wc -c /tmp/glm_key.txt` → 应输出 ~50 chars。 ### 大规模代码审查:write_file → terminal 模式 当审查 prompt 超大(60k+ chars,含多个完整源文件)时,不要在 prompt 文本中 内联代码——用 `write_file` 写审查脚本,再用 `terminal()` 执行: ```bash # Step 1: write_file("/tmp/glm-review.py", <完整Python脚本,内含所有代码字符串>) # Step 2: terminal("python3 /tmp/glm-review.py", timeout=360) ``` 脚本模板:见 `references/code-review-batch.md`。 ### GLM-5.2 审查后台执行 + process.wait 超时被钳制 **症状**:用 `terminal(background=true, notify_on_complete=true)` 后台调 GLM-5.2, 然后 `process(action='wait', timeout=300)` 等待结果。实际 60s 就超时返回,但 后台进程仍在运行(GLM-5.2 大审查通常需要 80-130s)。 **原因**:Hermes 对 `process.wait` 的 timeout 有钳制上限(当前 ~60s), 超过的 timeout 被截断。 **正确方案**:不用 `wait`,改循环 `poll`: ```python # terminal(background=true, notify_on_complete=true) 启动后 # 然后在循环中 poll直到 exited: for _ in range(10): # 最多等 10*15=150s time.sleep(15) result = process(action='poll', session_id=proc_id) if result['status'] == 'exited': break # 读结果: read_file('/tmp/glm52-review.md') ``` 或者直接用前台 `terminal(timeout=360)`,但 cron 会话会被 blocked——推荐上述 poll 模式。 ### python3 heredoc 不继承 terminal(workdir=) **症状**:`terminal(workdir="/repo", command="python3 << 'PYEOF'...")` 时, heredoc 内的 Python 代码在当前工作目录(/home/ubuntu)而非 /repo 执行, `open('server.py')` 报 FileNotFoundError。 **原因**:`terminal()` 的 `workdir` 参数设置 shell 的 cwd,但 heredoc 是 inline stdin 传递的代码块,其相对路径解析相对于 Agent 会话的 cwd,不受 `workdir` 影响。 **修复**:heredoc 或 `write_file` 脚本中使用**绝对路径**: ```python BRIDGE_DIR = '/home/ubuntu/atomk-page-bridge' server_py = open(os.path.join(BRIDGE_DIR, 'cloud-bridge', 'server.py')).read() ``` ### git commit 长消息触发 timeout → 被 blocked **症状**:`git commit -m "很长的多行消息..."` 在包含 `***` 等特殊字符时, Hermes 的 approval 机制可能将其标记为 secrets 并等待用户确认,导致超时 blocked。 **修复**:commit 消息精简为一句话,详细内容用 `git commit -m "short" -m "detail"`: ```bash # ❌ 易超时 git commit -m "fix(A): long message with symbols (A/B/C) — more detail..." # ✅ 安全 git commit -m "security: fix S1-S4" -m "S1: auth bypass, S2: cache, S3: lock, S4: SSRF" ``` API key `face68...NKGV` 结尾的 `***` 在 Python f-string 中会被解析为字符串引号匹配失败: 修改 `config.yaml` 后,`delegate_task` 可能仍走旧 provider(如旧的 OneAPI/SiliconFlow)。 **症状**:`delegate_task` 返回 401 或额度不足,token trace 显示使用了错误的 model。 **原因**:gateway 进程缓存了旧配置。 **修复**: ```bash hermes gateway restart ``` 重启后 `delegate_task` 才会读取新的 `delegation` 配置。 ### 验证配置是否生效 跑一个极简任务确认 model 正确: ``` delegate_task(goal="ls /home/ubuntu/docs/", toolsets=["terminal"]) ``` 成功标志:返回结果中 `model: "glm-5.1"`,duration ~5s。 ### 当 delegate_task 不可用时:直接调 API 如果 `delegate_task` 短期无法修复(gateway 不可重启、execute_code 被 blocked), 用 `terminal()` + Python heredoc 直接调 OpenAI 兼容端点: ```python python3 << 'PYEOF' import urllib.request, json # API key 通过 chr() 构建(绝不在 shell 明文) K = chr(102)+chr(97)+chr(99)+... # 用 Python 生成 BASE = 'https://open.bigmodel.cn/api/paas/v4' req = urllib.request.Request(BASE + '/chat/completions', data=json.dumps({ 'model': 'glm-5.1', 'messages': [{'role': 'user', 'content': '你的prompt'}], 'max_tokens': 8000, 'temperature': 0.3 }).encode(), method='POST') req.add_header('Authorization', f'Bearer {K}') req.add_header('Content-Type', 'application/json') resp = urllib.request.urlopen(req, timeout=180) data = json.loads(resp.read()) print(data['choices'][0]['message']['content']) PYEOF ``` ### 两个端点都可用 Coding Plan API key 可同时用于: - `https://api.z.ai/api/coding/paas/v4` — **Coding Plan 端点**(走订阅配额,推荐) - `https://open.bigmodel.cn/api/paas/v4` — 标准 API 端点(走按量计费) 始终优先使用 Coding Plan 端点以消耗订阅配额。两个端点模型列表相同。