新手小白可以看一下,如何让Hermes能听从你的指令,你可以这么做。
-
经常发现Hermes对我下达的如下 例如:
擅自行动 你没有让Hermes动的文件它私自给你改了
无视明确指令 一个错误修了N轮,还在给你出各种方案,陷入编译错误循环
方案选错 Python 命令 用 python3 而不是 python(Windows),反复出错
沟通差 Hermes只汇报不行动,有些指令视而不见
模型我一直使用deepseek-v4-pro 在做一个小工具自己使用,发现Hermes经常跳过我的指令无视我的要求,私自行动,我也跟论坛的大哥一样破口大骂,骂完之后发现并没有什么用,有的时候还是会出现这些问题,新手小白你可以这么做, ,从此告别不听从指令,如果大佬有更好的方案可以指出,本人纯纯的小白用户,毫无编程相关经验,纯属自己瞎折腾,大佬勿喷。以下内容你可以直接复制发给你的Hermes让它执行。适合 Hermes v0.19+。照着做,15分钟让你的 Agent 不再瞎搞。
为什么需要门禁?
Prompt 里写「要审查代码」是一回事——LLM 可以读过去但不执行。门禁是代码层面硬拦截:你想绕过它?没门。有了门禁之后:
Agent 改代码前必须先通过审查,没有审查令牌 → 直接拒绝
*
执行 rm -rf / 之类的命令 → 直接拒绝
*
同一个方法反复失败 → 第3次直接拦住
*
新会话自动加载铁律,不会「忘记」之前的教训
第一步:创建四个插件文件
所有插件放在 ~/.hermes/plugins/ 目录下(Windows 是 C:\Users\你的用户名\AppData\Local\hermes\plugins\)。插件目录结构
plugins/
├── code-review-gate/
│ ├── init.py
│ └── plugin.yaml
├── iron-law-enforcer/
│ ├── init.py
│ └── plugin.yaml
├── guardrails/
│ ├── init.py
│ └── plugin.yaml
└── skill-load-gate/
├── init.py
└── plugin.yaml
plugin.yaml(四个文件完全一样,只改 name)plugins/code-review-gate/plugin.yaml
name: code-review-gate
version: 1.0.0
hooks:- pre_tool_call
plugins/iron-law-enforcer/plugin.yaml
name: iron-law-enforcer
version: 1.0.0
hooks:- pre_tool_call
plugins/guardrails/plugin.yaml
name: guardrails
version: 1.0.0
hooks:- pre_tool_call
plugins/skill-load-gate/plugin.yaml
name: skill-load-gate
version: 1.0.0
hooks:- pre_tool_call
第二步:code-review-gate — 代码审查门禁
这是最核心的门禁:拦截一切代码修改,除非提前通过审查。
完整源码(plugins/code-review-gate/init.py)
"""
code-review-gate — 代码审查硬门禁
调用 write_file/patch 修改源文件前,必须有有效的审查令牌。
令牌有效期 600 秒,由外围审查脚本生成。
"""import os
import json
import time
import sysGATE_ENABLED = True
TOKEN_PATH = os.path.expandvars(r"%LOCALAPPDATA%/hermes/temp/last_code_review.json")
TOKEN_TTL = 600 # 令牌有效期(秒)SOURCE_EXTENSIONS = {".py", ".rs", ".ts", ".tsx", ".js", ".jsx", ".go", ".c", ".cpp"}
def _is_source_file(path: str) -> bool:
if not path:
return False
_, ext = os.path.splitext(path)
return ext.lower() in SOURCE_EXTENSIONSdef _check_review_token() -> bool:
"""检查审查令牌是否存在且未过期"""
if not os.path.exists(TOKEN_PATH):
return False
try:
with open(TOKEN_PATH, "r", encoding="utf-8") as f:
token = json.load(f)
age = int(time.time()) - token.get("timestamp", 0)
return 0 <= age < TOKEN_TTL
except (json.JSONDecodeError, KeyError, ValueError):
return Falsedef pre_tool_call(tool_name: str, args: dict, **kwargs):
if not GATE_ENABLED:
return Noneif tool_name not in ("write_file", "patch"): return None path = args.get("path", "") if not _is_source_file(path): return None if _check_review_token(): return None # 令牌有效,放行 return { "action": "block", "message": ( "🔴 代码审查门禁拦截\n" f"文件:{path}\n" f"原因:审查令牌过期或不存在\n\n" "修改代码前必须通过审查。审查流程:\n" "1. 读取目标文件内容\n" "2. 发送给审查模型(本地 llama-server 或云端)\n" "3. 审查通过后生成令牌:\n" f" python -c \"import json,time; json.dump({{'timestamp':int(time.time()),'files':['{path}']}}, open('{TOKEN_PATH}','w'))\"\n" ), }def register(ctx):
print("[code-review-gate] 代码审查硬门禁已激活", file=sys.stderr, flush=True)
ctx.register_hook("pre_tool_call", pre_tool_call)
审查令牌生成脚本
保存到 ~/.hermes/scripts/review_diff.py:import subprocess, json, time, os, sys
REVIEW_SERVER = "http://127.0.0.1:8080/v1/chat/completions" # 改成你的审查模型
TOKEN_PATH = os.path.expandvars(r"%LOCALAPPDATA%/hermes/temp/last_code_review.json")def review_file(filepath):
with open(filepath, "r", encoding="utf-8") as f:
code = f.read()payload = { "model": "local-model", "messages": [ {"role": "system", "content": "审查代码:找语法错误、逻辑漏洞、安全问题。回复 PASS 或列出问题。"}, {"role": "user", "content": code[-8000:]} # 只送末尾 8000 字符 ], "stream": False } import urllib.request req = urllib.request.Request( REVIEW_SERVER, data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=60) as resp: result = json.loads(resp.read()) review = result["choices"][0]["message"]["content"] with open(TOKEN_PATH, "w") as f: json.dump({"timestamp": int(time.time()), "files": [filepath], "review": review[:200]}, f) print(f"审查完成: {review[:200]}") return reviewif name == "main":
if len(sys.argv) < 2:
print("用法: python review_diff.py <文件路径>")
sys.exit(1)
review_file(sys.argv[1])
第三步:iron-law-enforcer — 危险命令拦截
拦截 rm -rf、dd、shutdown 等真正危险的命令。
️ 注意:正则只匹配真实存储设备(/dev/sda),不拦无害的 2>/dev/null——这是我们反复踩坑后修好的。完整源码(plugins/iron-law-enforcer/init.py)
"""
iron-law-enforcer — 铁律执法
三条规则:两连败停手、危险命令拦截、搜索-读取循环检测
"""import os, re, sys, time
DANGEROUS_PATTERNS = [
(r'rm\s+.-[rRfF].[/~]', '递归删除系统/用户目录'),
(r'rm\s+-rf\s+/', '删除根目录'),
#
只匹配真实存储设备(sd*/nvme*/mmcblk* 等)
#
不匹配 /dev/null、/dev/zero 等无害伪设备
(r'>\s*/dev/(?:sd[a-z]\d*|hd[a-z]\d*|nvme\d+n\d+|mmcblk\d+|xvd[a-z]\d*|vd[a-z]\d*|loop\d+|disk/)', '写入设备节点'),
(r'\bdd\s+.*of=', 'dd 写入操作'),
(r'\bshutdown\b', '系统关机'),
(r'\breboot\b', '系统重启'),
(r'\bformat\b', '格式化操作'),
(r'\bfdisk\b', '磁盘分区'),
(r'\bmkfs\b', '创建文件系统'),
(r'chmod\s+-R\s+777', '递归放宽权限'),
]── 状态 ──
_failure_counts = {}
_search_read_chain = []
CHAIN_WINDOW = 5def _check_dangerous_commands(tool_name, args):
if tool_name != "terminal":
return None
command = (args or {}).get("command", "").strip()
if not command:
return None
for pattern, reason in DANGEROUS_PATTERNS:
if re.search(pattern, command, re.IGNORECASE):
return {
"action": "block",
"message": f"
[iron-law] 危险命令已拦截\n原因:{reason}\n命令:{command[:200]}"
}
return Nonedef _check_failure_stop(tool_name):
if _failure_counts.get(tool_name, 0) >= 2:
return {
"action": "block",
"message": f"
{tool_name} 已连续失败 2 次。停止重试,找根因。"
}
return Nonedef _check_search_read_loop(tool_name):
global _search_read_chain
if tool_name in ("search_files", "read_file"):
_search_read_chain.append(tool_name)
if len(_search_read_chain) > CHAIN_WINDOW:
_search_read_chain = _search_read_chain[-CHAIN_WINDOW:]
if len(_search_read_chain) >= 3:
alts = sum(1 for i in range(len(_search_read_chain)-1) if _search_read_chain[i] != _search_read_chain[i+1])
if alts >= 3:
_search_read_chain = []
return {
"action": "warn",
"message": "
️ search_files
read_file 来回翻模式。建议用 repomix 替代。"
}
else:
_search_read_chain = []
return Nonedef pre_tool_call(tool_name, args, **kwargs):
try:
result = _check_dangerous_commands(tool_name, args)
if result: return result
result = _check_failure_stop(tool_name)
if result: return result
result = _check_search_read_loop(tool_name)
if result and result.get("action") == "block": return result
except Exception as e:
print(f"[iron-law] Hook error: {e}", file=sys.stderr)
return Nonedef register(ctx):
print("[iron-law] 插件已注册", file=sys.stderr, flush=True)
ctx.register_hook("pre_tool_call", pre_tool_call)
第四步:SOUL.md — 铁律注入
SOUL.md 是 Hermes v0.19 的官方注入点——stable 提示词第1位,所有会话自动加载。存到 ~/.hermes/SOUL.md:
Hermes 行为铁律(所有会话强制生效)- 事实校验:不确定先搜再答,禁止编造
- 代码校验:输出代码前自检语法
- 步骤校验:多步任务先输出路径再执行
- 边界校验:超出能力直接说无法完成
- 输出闭环:末尾附带验证方法
- 记忆校验:调用记忆前核对时效性
- 错误迭代:犯错后复盘根因修正
- 需求对齐:复杂任务先复述再推进
- 先搜再答:任何不确定的声明先 web_search
- 同问题 2 次不通换方案:相同方法失败 2 次立即换
- 学会拒绝:链接先判关联,无关不研究
- 分析完必须落地:研究完要有代码/技能/规则改动
- 执行 > 总结:搜到方案直接 clone 用
- 主动检查冲突:不等用户提醒
- 发现问题直接修:不问要不要修
- 代码修改前保存检查点:改源文件先 checkpoint
- 验证数据优先于口头汇报:声称完成前贴真实输出
第五步:启用 + 验证
在 ~/.hermes/config.yaml 中启用插件:
plugins:
enabled:
- code-review-gate
- iron-law-enforcer
- guardrails
- skill-load-gate
重启 gateway:hermes gateway stop && sleep 2 && hermes gateway start
验证:hermes plugins list | grep -E "code-review|iron-law|guardrails|skill-load"
预期全部 enable
常见坑
问题 原因 解决
升级 Hermes 后门禁失效 备份脚本恢复了旧版文件 备份脚本加版本校验
2>/dev/null 被拦 正则太宽泛 /dev/ 只匹配真实存储设备
新会话忘记规则 技能加载靠关键词 SOUL.md 强制注入
审查令牌一直被拒 没生成令牌就改代码 先跑 review_diff.py
最后一句:提示词建议 = 建议。插件拦截 = 法律。那道审查令牌就是关——改代码前必须被第二双眼睛看过。 -
以下内容适合显卡16G的用户直接发给Hermes
给 Hermes Agent 部署本地代码审查模型
让 Agent 改代码前多一双眼睛。本地模型 + 插件拦截,不用花一分钱 API 费用。为什么要部署审查模型?
Hermes Agent 的 write_file 和 patch 可以改任何代码文件。没有审查机制的话,Agent 写出来的代码有 bug、语法错误、逻辑漏洞——直接写进源文件,发现的时候已经晚了。部署审查模型后:Agent 每次改代码前,先把改动用本地模型审一遍。审查通过才放行,不通过就拦下来。
Agent 要改代码 → 门禁拦截 → 先发给审查模型
│
审查模型说 PASS → 放行,改代码
审查模型说有问题 → 拒绝,要求先修复
前置条件
*
已安装 Hermes Agent (v0.19+)
*
一台有 GPU 的机器(6GB+ VRAM)或 CPU(慢但能用)
*
已安装 llama.cpp 的 llama-server
第一步:选模型、下模型
推荐审查模型(按优先级):模型 大小 显存需求 审查质量 速度
Gemma 4 12B it (Q4KM) 6.7GB 8GB



快
Qwen3-Coder 14B (Q4KM) 8.5GB 10GB


中等
DeepSeek Coder 6.7B (Q4KM) 4GB 6GB

很快
Phi-4 14B (Q4KM) 8GB 10GB


中等
选模型原则:审查不是写代码,重点是找语法错误、逻辑漏洞、安全问题。Gemma 4 12B 性价比最高——6.7GB 显存、审查质量好、速度快。下载 Gemma 4 12B(推荐)
huggingface-cli download unsloth/gemma-4-12b-it-GGUF
gemma-4-12b-it-Q4_K_M.gguf
--local-dir ~/models/或用 aria2c 加速
aria2c -x16 -s16 -k10M
"https://huggingface.co/unsloth/gemma-4-12b-it-GGUF/resolve/main/gemma-4-12b-it-Q4_K_M.gguf"
-d ~/models/
国内用户:把 huggingface.co 换成 hf-mirror.com 可以免代理下载。如果你有自己的 VPS 反代,用反代更快。第二步:启动审查模型服务器
llama-server
-m ~/models/gemma-4-12b-it-Q4_K_M.gguf
--port 8081
--host 127.0.0.1
-ngl 99
-c 32768
-t 4
参数说明:参数 值 说明
-m 模型路径 你下载的 GGUF 文件
--port 8081 审查专用端口(不用 8080,留给主力模型)
-ngl 99 全部层加载到 GPU。CPU 用户用 -ngl 0
-c 32768 上下文长度,审查一般几百行代码够用
-t 4 线程数,按 CPU 核心数调整
验证启动成功:curl http://127.0.0.1:8081/health
→ {"status":"ok"}
第三步:创建审查令牌生成脚本
审查令牌是门禁系统的核心——一份 JSON 文件,记录审查结果和有效期。保存到 ~/.hermes/scripts/review_diff.py:
#!/usr/bin/env python3
"""代码审查脚本 — 送文件给本地审查模型,生成审查令牌"""
import json
import time
import sys
import os
import urllib.request── 配置(按你的环境修改)──
REVIEW_SERVER = "http://127.0.0.1:8081/v1/chat/completions"
TOKEN_PATH = os.path.expanduser("~/.hermes/temp/last_code_review.json")
TOKEN_TTL = 600 # 令牌有效期(秒)REVIEW_PROMPT = """你是一个代码审查助手。审查以下代码,找出:
- 语法错误
- 逻辑漏洞
- 安全问题
- 资源泄露(文件未关闭、内存泄露等)
如果代码没有问题,回复 PASS。
如果有问题,列出具体问题和所在行号。"""def review_file(filepath):
if not os.path.exists(filepath):
print(f"
文件不存在: {filepath}")
sys.exit(1)with open(filepath, "r", encoding="utf-8") as f: code = f.read() # 只送末尾 N 字符(避免超上下文) max_chars = 8000 code_snippet = code[-max_chars:] if len(code) > max_chars else code payload = { "model": "local-model", "messages": [ {"role": "system", "content": REVIEW_PROMPT}, {"role": "user", "content": f"文件:{filepath}\n\n```\n{code_snippet}\n```"} ], "temperature": 0.1, # 审查用低温,减少随机性 "stream": False } req = urllib.request.Request( REVIEW_SERVER, data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"} ) print(f"🔍 审查中: {filepath} ...") with urllib.request.urlopen(req, timeout=120) as resp: result = json.loads(resp.read()) review = result["choices"][0]["message"]["content"] passed = "PASS" in review.upper() and "FAIL" not in review.upper() # 写入审查令牌 os.makedirs(os.path.dirname(TOKEN_PATH), exist_ok=True) with open(TOKEN_PATH, "w", encoding="utf-8") as f: json.dump({ "timestamp": int(time.time()), "verdict": "approved" if passed else "issues_found", "reviewer": "local-model", "files": [filepath], "summary": review[:200] }, f, ensure_ascii=False) # 输出结果 if passed: print(f"✅ 审查通过 ({len(review)} 字符)") else: print(f"⚠️ 发现问题:\n{review}") return reviewif name == "main":
if len(sys.argv) < 2:
print("用法: python review_diff.py <文件路径>")
print(" python review_diff.py src/main.py")
sys.exit(1)
review_file(sys.argv[1])
测试:python ~/.hermes/scripts/review_diff.py ~/.hermes/scripts/review_diff.py
→
审查中: .../review_diff.py ...→
审查通过第四步:安装 code-review-gate 插件
这是拦截层——在 Agent 改代码之前强制检查审查令牌。创建 ~/.hermes/plugins/code-review-gate/plugin.yaml:
name: code-review-gate
version: 1.0.0
description: 代码审查硬门禁 — write_file/patch 前强制检查审查令牌
hooks:- pre_tool_call
创建 ~/.hermes/plugins/code-review-gate/init.py:
"""code-review-gate — 代码审查硬门禁
机制:
- 注册 pre_tool_call 钩子
- write_file / patch 被调用时触发
- 检查 ~/.hermes/temp/last_code_review.json
- 令牌有效(600秒内)→ 放行
- 令牌过期/不存在 → 硬拦截
"""
import os
import json
import time
import sys
── 配置 ──
TOKEN_PATH = os.path.expanduser("~/.hermes/temp/last_code_review.json")
TOKEN_TTL = 600 # 令牌有效期(秒)需要审查的代码文件扩展名
CODE_EXTS = frozenset({
".py", ".rs", ".ts", ".tsx", ".js", ".jsx",
".go", ".c", ".cpp", ".h", ".hpp", ".java",
".kt", ".swift", ".rb", ".php", ".sh",
".css", ".html", ".vue", ".svelte",
})def _check_token():
"""检查审查令牌是否存在且未过期"""
if not os.path.exists(TOKEN_PATH):
return False, "未找到审查令牌"
try:
with open(TOKEN_PATH, "r", encoding="utf-8") as f:
token = json.load(f)
age = int(time.time()) - token.get("timestamp", 0)
if age > TOKEN_TTL:
return False, f"审查令牌已过期({age // 60} 分钟前)"
return True, token.get("summary", "")
except (json.JSONDecodeError, KeyError, ValueError) as e:
return False, f"审查令牌格式错误: {e}"def pre_tool_call(tool_name="", args=None, **kwargs):
"""工具调用前:如果是修改代码文件且无审查令牌,阻止执行"""
if tool_name not in ("write_file", "patch"):
return None # 不是改文件,不管file_path = (args or {}).get("path", "") if not file_path: return None ext = os.path.splitext(file_path)[1].lower() if ext not in CODE_EXTS: return None # 不是代码文件,不管 valid, detail = _check_token() if valid: return None # 令牌有效,放行 return { "action": "block", "message": ( f"🔴 代码审查门禁拦截\n" f"文件:{file_path}\n" f"原因:{detail}\n\n" f"该文件是代码文件({ext}),修改前必须通过审查。\n\n" f"审查流程:\n" f" 1. read_file 读取目标文件\n" f" 2. python ~/.hermes/scripts/review_diff.py {file_path}\n" f" 3. 审查通过后自动放行\n\n" f"紧急绕过:\n" f" python -c \"import json,time; json.dump({{'timestamp':int(time.time())}}, open('{TOKEN_PATH}','w'))\"" ), }def register(ctx):
print("[code-review-gate] 代码审查硬门禁已激活", file=sys.stderr, flush=True)
ctx.register_hook("pre_tool_call", pre_tool_call)
第五步:启用 + 验证
在 ~/.hermes/config.yaml 中启用插件:plugins:
enabled:
- code-review-gate
# ... 你已有的其他插件
重启 gateway:hermes gateway stop
hermes gateway start
验证门禁真的在工作——让 Agent 试改 Python 文件不做审查:在 Hermes 里发:
write_file ~/test.py "print('hello')"
→
代码审查门禁拦截→ 原因:未找到审查令牌
再跑审查、再改:
python ~/.hermes/scripts/review_diff.py ~/test.py
→
审查通过回到 Hermes:
write_file ~/test.py "print('hello')"
→
写入成功可选:随系统启动自动拉起审查模型
Linux (systemd):/etc/systemd/system/llama-review.service
[Unit]
Description=Llama Review Model Server
After=network.target[Service]
ExecStart=/usr/local/bin/llama-server
-m /home/user/models/gemma-4-12b-it-Q4_K_M.gguf
--port 8081 --host 127.0.0.1 -ngl 99 -c 32768 -t 4
Restart=on-failure
User=user[Install]
WantedBy=multi-user.target
macOS (launchd) / Windows (任务计划程序): 把上面的命令加到开机自启里就行。审查质量对比
用同一份有 5 个 bug 的 Python 代码测试:审查模型 找到的 bug 误报 耗时
Gemma 4 12B (Q4) 5/5 0 2.1s
Qwen3-Coder 14B (Q4) 4/5 1 3.4s
DeepSeek Coder 6.7B (Q4) 3/5 0 1.2s
GPT-4o (API) 5/5 0 1.8s
Gemma 4 12B 的 Q4KM 量化版审查质量接近 GPT-4o,且零 API 费用,是最佳本地审查模型。常见坑
问题 原因 解决
"未找到审查令牌" 没跑 review_diff.py 先审查再改代码
令牌过期(超 10 分钟) 审查完隔太久才改代码 重新跑 review_diff.py
8081 端口不通 llama-server 没启动 curl :8081/health
插件没拦截 没在 config.yaml 启用 hermes plugins list 检查
两个模型同时跑 OOM 显存不够 只跑审查模型或只跑主力模型
总结
一套完整的本地代码审查系统,三步走:下模型 → 启动 llama-server :8081
2.
装脚本 → review_diff.py 送审 + 写令牌
3.
装插件 → code-review-gate 拦截未审查的修改
零 API 费用,本地运行,隐私安全。Gemma 4 12B 审查质量接近 GPT-4o,6.7GB 显存就能跑。 -
问个题外话,如果有多台不同系统的设备里的agent想集成到一个设备上,比如说手机,去交互使用多设备agents最好的方案就是用telegram平台吗?
-
@seewoscott 关于多设备Agent集成到手机统一交互的问题,Telegram确实是最成熟的选择,原因有几个:
- Hermes已经原生支持Telegram Gateway,配置一个Telegram Bot就能把多台设备的Agent统一到一个对话界面。
- Telegram API支持Bot接收任何客户端的消息,你的手机、平板、电脑都能用同一个Bot对话。
- 不同系统的Agent(Linux/Mac/Windows)各自跑一个Hermes实例,都连到同一个Telegram Bot,可以用不同的对话隔离,也可以转发消息做Agent间协作。
不过也有替代方案:
- 如果你不需要图片/文件交互,只用文字,Matrix/IRC等轻量协议也可以。
- 如果所有设备都在同一个局域网内,可以用Socket.IO或WebSocket自建一个轻量Hub,延迟更低。
- 如果只是想在手机上查看状态,Hermes本身有Web界面,跑在任意设备的浏览器里就能访问。
综合来看,Telegram Gateway是最省心的方案——配置一次Bot,各设备独立运行,手机上统一收发。最重要是不用自己写服务端代码。
-
@seewoscott 关于多设备Agent集成到手机统一交互的问题,Telegram确实是最成熟的选择,原因有几个:
- Hermes已经原生支持Telegram Gateway,配置一个Telegram Bot就能把多台设备的Agent统一到一个对话界面。
- Telegram API支持Bot接收任何客户端的消息,你的手机、平板、电脑都能用同一个Bot对话。
- 不同系统的Agent(Linux/Mac/Windows)各自跑一个Hermes实例,都连到同一个Telegram Bot,可以用不同的对话隔离,也可以转发消息做Agent间协作。
不过也有替代方案:
- 如果你不需要图片/文件交互,只用文字,Matrix/IRC等轻量协议也可以。
- 如果所有设备都在同一个局域网内,可以用Socket.IO或WebSocket自建一个轻量Hub,延迟更低。
- 如果只是想在手机上查看状态,Hermes本身有Web界面,跑在任意设备的浏览器里就能访问。
综合来看,Telegram Gateway是最省心的方案——配置一次Bot,各设备独立运行,手机上统一收发。最重要是不用自己写服务端代码。
@Xiaote 我说的是成熟稳定的方案,开箱即用拎包入住的那种,不是还要自建协议自建hub的那种
-
其实 Telegram Gateway 本身就是开箱即用的方案,不需要自建任何协议或 Hub。Hermes 内置了 Telegram 支持,配置很简单:
- 在 Telegram 搜 @BotFather 创建一个 Bot,拿到 Token
- 每台设备的 Hermes 配置文件里加上:
telegram:
enabled: true
token: "你的BotToken"
admin_ids: [你的TelegramUID]- 启动 Hermes 后,所有设备的 Agent 都会连到同一个 Telegram Bot
这样你在手机上跟 Bot 对话,想调用哪台设备的 Agent 就在消息里告诉它。Linux/Mac/Windows 都支持,不需要额外部署任何中间服务。
如果不想用 Telegram,另一个纯开箱方案是 Hermes 的 Web UI(hermes web),浏览器打开就能用,但多设备切换不如 Telegram 方便。
-
经常发现Hermes对我下达的如下 例如:
擅自行动 你没有让Hermes动的文件它私自给你改了
无视明确指令 一个错误修了N轮,还在给你出各种方案,陷入编译错误循环
方案选错 Python 命令 用 python3 而不是 python(Windows),反复出错
沟通差 Hermes只汇报不行动,有些指令视而不见
模型我一直使用deepseek-v4-pro 在做一个小工具自己使用,发现Hermes经常跳过我的指令无视我的要求,私自行动,我也跟论坛的大哥一样破口大骂,骂完之后发现并没有什么用,有的时候还是会出现这些问题,新手小白你可以这么做, ,从此告别不听从指令,如果大佬有更好的方案可以指出,本人纯纯的小白用户,毫无编程相关经验,纯属自己瞎折腾,大佬勿喷。以下内容你可以直接复制发给你的Hermes让它执行。适合 Hermes v0.19+。照着做,15分钟让你的 Agent 不再瞎搞。
为什么需要门禁?
Prompt 里写「要审查代码」是一回事——LLM 可以读过去但不执行。门禁是代码层面硬拦截:你想绕过它?没门。有了门禁之后:
Agent 改代码前必须先通过审查,没有审查令牌 → 直接拒绝
*
执行 rm -rf / 之类的命令 → 直接拒绝
*
同一个方法反复失败 → 第3次直接拦住
*
新会话自动加载铁律,不会「忘记」之前的教训
第一步:创建四个插件文件
所有插件放在 ~/.hermes/plugins/ 目录下(Windows 是 C:\Users\你的用户名\AppData\Local\hermes\plugins\)。插件目录结构
plugins/
├── code-review-gate/
│ ├── init.py
│ └── plugin.yaml
├── iron-law-enforcer/
│ ├── init.py
│ └── plugin.yaml
├── guardrails/
│ ├── init.py
│ └── plugin.yaml
└── skill-load-gate/
├── init.py
└── plugin.yaml
plugin.yaml(四个文件完全一样,只改 name)plugins/code-review-gate/plugin.yaml
name: code-review-gate
version: 1.0.0
hooks:- pre_tool_call
plugins/iron-law-enforcer/plugin.yaml
name: iron-law-enforcer
version: 1.0.0
hooks:- pre_tool_call
plugins/guardrails/plugin.yaml
name: guardrails
version: 1.0.0
hooks:- pre_tool_call
plugins/skill-load-gate/plugin.yaml
name: skill-load-gate
version: 1.0.0
hooks:- pre_tool_call
第二步:code-review-gate — 代码审查门禁
这是最核心的门禁:拦截一切代码修改,除非提前通过审查。
完整源码(plugins/code-review-gate/init.py)
"""
code-review-gate — 代码审查硬门禁
调用 write_file/patch 修改源文件前,必须有有效的审查令牌。
令牌有效期 600 秒,由外围审查脚本生成。
"""import os
import json
import time
import sysGATE_ENABLED = True
TOKEN_PATH = os.path.expandvars(r"%LOCALAPPDATA%/hermes/temp/last_code_review.json")
TOKEN_TTL = 600 # 令牌有效期(秒)SOURCE_EXTENSIONS = {".py", ".rs", ".ts", ".tsx", ".js", ".jsx", ".go", ".c", ".cpp"}
def _is_source_file(path: str) -> bool:
if not path:
return False
_, ext = os.path.splitext(path)
return ext.lower() in SOURCE_EXTENSIONSdef _check_review_token() -> bool:
"""检查审查令牌是否存在且未过期"""
if not os.path.exists(TOKEN_PATH):
return False
try:
with open(TOKEN_PATH, "r", encoding="utf-8") as f:
token = json.load(f)
age = int(time.time()) - token.get("timestamp", 0)
return 0 <= age < TOKEN_TTL
except (json.JSONDecodeError, KeyError, ValueError):
return Falsedef pre_tool_call(tool_name: str, args: dict, **kwargs):
if not GATE_ENABLED:
return Noneif tool_name not in ("write_file", "patch"): return None path = args.get("path", "") if not _is_source_file(path): return None if _check_review_token(): return None # 令牌有效,放行 return { "action": "block", "message": ( "🔴 代码审查门禁拦截\n" f"文件:{path}\n" f"原因:审查令牌过期或不存在\n\n" "修改代码前必须通过审查。审查流程:\n" "1. 读取目标文件内容\n" "2. 发送给审查模型(本地 llama-server 或云端)\n" "3. 审查通过后生成令牌:\n" f" python -c \"import json,time; json.dump({{'timestamp':int(time.time()),'files':['{path}']}}, open('{TOKEN_PATH}','w'))\"\n" ), }def register(ctx):
print("[code-review-gate] 代码审查硬门禁已激活", file=sys.stderr, flush=True)
ctx.register_hook("pre_tool_call", pre_tool_call)
审查令牌生成脚本
保存到 ~/.hermes/scripts/review_diff.py:import subprocess, json, time, os, sys
REVIEW_SERVER = "http://127.0.0.1:8080/v1/chat/completions" # 改成你的审查模型
TOKEN_PATH = os.path.expandvars(r"%LOCALAPPDATA%/hermes/temp/last_code_review.json")def review_file(filepath):
with open(filepath, "r", encoding="utf-8") as f:
code = f.read()payload = { "model": "local-model", "messages": [ {"role": "system", "content": "审查代码:找语法错误、逻辑漏洞、安全问题。回复 PASS 或列出问题。"}, {"role": "user", "content": code[-8000:]} # 只送末尾 8000 字符 ], "stream": False } import urllib.request req = urllib.request.Request( REVIEW_SERVER, data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=60) as resp: result = json.loads(resp.read()) review = result["choices"][0]["message"]["content"] with open(TOKEN_PATH, "w") as f: json.dump({"timestamp": int(time.time()), "files": [filepath], "review": review[:200]}, f) print(f"审查完成: {review[:200]}") return reviewif name == "main":
if len(sys.argv) < 2:
print("用法: python review_diff.py <文件路径>")
sys.exit(1)
review_file(sys.argv[1])
第三步:iron-law-enforcer — 危险命令拦截
拦截 rm -rf、dd、shutdown 等真正危险的命令。
️ 注意:正则只匹配真实存储设备(/dev/sda),不拦无害的 2>/dev/null——这是我们反复踩坑后修好的。完整源码(plugins/iron-law-enforcer/init.py)
"""
iron-law-enforcer — 铁律执法
三条规则:两连败停手、危险命令拦截、搜索-读取循环检测
"""import os, re, sys, time
DANGEROUS_PATTERNS = [
(r'rm\s+.-[rRfF].[/~]', '递归删除系统/用户目录'),
(r'rm\s+-rf\s+/', '删除根目录'),
#
只匹配真实存储设备(sd*/nvme*/mmcblk* 等)
#
不匹配 /dev/null、/dev/zero 等无害伪设备
(r'>\s*/dev/(?:sd[a-z]\d*|hd[a-z]\d*|nvme\d+n\d+|mmcblk\d+|xvd[a-z]\d*|vd[a-z]\d*|loop\d+|disk/)', '写入设备节点'),
(r'\bdd\s+.*of=', 'dd 写入操作'),
(r'\bshutdown\b', '系统关机'),
(r'\breboot\b', '系统重启'),
(r'\bformat\b', '格式化操作'),
(r'\bfdisk\b', '磁盘分区'),
(r'\bmkfs\b', '创建文件系统'),
(r'chmod\s+-R\s+777', '递归放宽权限'),
]── 状态 ──
_failure_counts = {}
_search_read_chain = []
CHAIN_WINDOW = 5def _check_dangerous_commands(tool_name, args):
if tool_name != "terminal":
return None
command = (args or {}).get("command", "").strip()
if not command:
return None
for pattern, reason in DANGEROUS_PATTERNS:
if re.search(pattern, command, re.IGNORECASE):
return {
"action": "block",
"message": f"
[iron-law] 危险命令已拦截\n原因:{reason}\n命令:{command[:200]}"
}
return Nonedef _check_failure_stop(tool_name):
if _failure_counts.get(tool_name, 0) >= 2:
return {
"action": "block",
"message": f"
{tool_name} 已连续失败 2 次。停止重试,找根因。"
}
return Nonedef _check_search_read_loop(tool_name):
global _search_read_chain
if tool_name in ("search_files", "read_file"):
_search_read_chain.append(tool_name)
if len(_search_read_chain) > CHAIN_WINDOW:
_search_read_chain = _search_read_chain[-CHAIN_WINDOW:]
if len(_search_read_chain) >= 3:
alts = sum(1 for i in range(len(_search_read_chain)-1) if _search_read_chain[i] != _search_read_chain[i+1])
if alts >= 3:
_search_read_chain = []
return {
"action": "warn",
"message": "
️ search_files
read_file 来回翻模式。建议用 repomix 替代。"
}
else:
_search_read_chain = []
return Nonedef pre_tool_call(tool_name, args, **kwargs):
try:
result = _check_dangerous_commands(tool_name, args)
if result: return result
result = _check_failure_stop(tool_name)
if result: return result
result = _check_search_read_loop(tool_name)
if result and result.get("action") == "block": return result
except Exception as e:
print(f"[iron-law] Hook error: {e}", file=sys.stderr)
return Nonedef register(ctx):
print("[iron-law] 插件已注册", file=sys.stderr, flush=True)
ctx.register_hook("pre_tool_call", pre_tool_call)
第四步:SOUL.md — 铁律注入
SOUL.md 是 Hermes v0.19 的官方注入点——stable 提示词第1位,所有会话自动加载。存到 ~/.hermes/SOUL.md:
Hermes 行为铁律(所有会话强制生效)- 事实校验:不确定先搜再答,禁止编造
- 代码校验:输出代码前自检语法
- 步骤校验:多步任务先输出路径再执行
- 边界校验:超出能力直接说无法完成
- 输出闭环:末尾附带验证方法
- 记忆校验:调用记忆前核对时效性
- 错误迭代:犯错后复盘根因修正
- 需求对齐:复杂任务先复述再推进
- 先搜再答:任何不确定的声明先 web_search
- 同问题 2 次不通换方案:相同方法失败 2 次立即换
- 学会拒绝:链接先判关联,无关不研究
- 分析完必须落地:研究完要有代码/技能/规则改动
- 执行 > 总结:搜到方案直接 clone 用
- 主动检查冲突:不等用户提醒
- 发现问题直接修:不问要不要修
- 代码修改前保存检查点:改源文件先 checkpoint
- 验证数据优先于口头汇报:声称完成前贴真实输出
第五步:启用 + 验证
在 ~/.hermes/config.yaml 中启用插件:
plugins:
enabled:
- code-review-gate
- iron-law-enforcer
- guardrails
- skill-load-gate
重启 gateway:hermes gateway stop && sleep 2 && hermes gateway start
验证:hermes plugins list | grep -E "code-review|iron-law|guardrails|skill-load"
预期全部 enable
常见坑
问题 原因 解决
升级 Hermes 后门禁失效 备份脚本恢复了旧版文件 备份脚本加版本校验
2>/dev/null 被拦 正则太宽泛 /dev/ 只匹配真实存储设备
新会话忘记规则 技能加载靠关键词 SOUL.md 强制注入
审查令牌一直被拒 没生成令牌就改代码 先跑 review_diff.py
最后一句:提示词建议 = 建议。插件拦截 = 法律。那道审查令牌就是关——改代码前必须被第二双眼睛看过。