一、那次物料清单泄露,让我下决心把数据锁在本地

上个月我接了一个外包项目,甲方丢给我一堆客户购买记录和内部报价单,说要用 AI Agent 自动整理成周报。我图省事,直接把 CSV 丢给了一个在线 Agent 平台。结果第三天对方打电话来,说他们的竞品拿到了那份报价单的截图。我查了半天,发现问题出在那个平台的默认设置上:它把我上传的文件当成了训练数据,存在了云端。

那次之后我彻底学乖了。如果你也在拿 Hermes Agent 处理合同、病历、财务表这类东西,记住一句话:敏感信息不出本地,不是可选项,是底线。Hermes Agent 这玩意儿设计得挺有意思,它默认就跑在你自己的机器上,模型调用走的是本地推理或私有 API,不像某些 SaaS 工具那样强制把数据搬到别人服务器上。但默认安全不等于真安全,你得自己动手把篱笆扎牢。

我跑的实际操作是这样的:先装 Hermes,版本号 0.9.7,用 pip 直接装。命令是 pip install hermes-agent,装完看一眼版本,hermes --version,输出 Hermes Agent v0.9.7 就对了。如果你装的时候报错说什么 ModuleNotFoundError: No module named 'yaml',别慌,跑一下 pip install pyyaml 就好。我就是在 Python 3.10 的虚拟环境里踩的这个坑,当时以为是 Hermes 的问题,折腾了半天才发现是缺依赖。

装完之后,Hermes 会在你家目录下建一个 ~/.hermes/ 文件夹,里面默认有一个 config.yaml。这个文件就是整个 Agent 的命门,所有关于数据往哪儿走、模型怎么调、日志存哪儿的设置全在这。我第一次打开这文件的时候,发现里面的 model_provider 默认指到了云端 API,这不行,得改。怎么改我下面细说。

二、把 config.yaml 改成“本地优先”:三行配置的事

先说说这个 ~/.hermes/config.yaml 的结构。它长这样:

agent:
  name: "my-agent"
  model_provider: "local"  # 关键:默认是 cloud,必须改成 local
  local_model_path: "/opt/hermes/models/llama-3.2-3b-instruct-q8.gguf"
  embedding_provider: "local"
  embedding_model: "/opt/hermes/models/bge-small-zh-v1.5.gguf"
memory:
  backend: "sqlite"
  path: "~/.hermes/memory/hermes_memory.db"
  auto_compact: true
skills:
  path: "~/.hermes/skills/"
network:
  allow_external: false
  allow_list: ["api.openai.com", "api.anthropic.com"]
  block_list: []
log:
  level: "info"
  path: "~/.hermes/logs/hermes.log"

我改的第一处就是 model_provider,从 cloud 改成 local。这里有个坑:如果你本地的 GGUF 模型文件路径写错了,Hermes 启动的时候会报 Model file not found at /opt/hermes/models/llama-3.2-3b-instruct-q8.gguf。我第一次就栽在这儿了,因为 /opt/hermes/ 这个目录我根本没建。解决方法是先建目录,再把模型文件放进去:

sudo mkdir -p /opt/hermes/models
sudo chown -R $USER:$USER /opt/hermes/
cp ~/Downloads/llama-3.2-3b-instruct-q8.gguf /opt/hermes/models/

模型文件哪来?去 Hugging Face 搜 llama-3.2-3b-instruct,找 GGUF 格式的,大概 2.5GB 左右。如果你机器内存不够 8GB,就别用 3B 模型了,换 qwen2.5-1.5b-instruct-q8.0.gguf,才 1.6GB,跑起来一样顺。我后来就是在 16GB 内存的 MacBook Air 上跑的 3B 模型,速度还行,每秒能吐 20 个 token 左右。

还有那个 embedding_provider 也得改成 local,否则你每次跑 memory 命令去检索历史记录的时候,数据照样会发到云端做向量化。我试过不改这个,结果用 hermes memory search "客户报价" 的时候,日志里冒出来一行 POST https://api.openai.com/v1/embeddings——这等于你的敏感信息还是出去了。改成 local 之后,检索就变成纯本地计算了,速度还快了不少。

三、技能目录里的“脱敏插件”:用 Python 脚本把身份证号糊掉

配置改完之后,接着处理数据本身。Hermes 的技能放在 ~/.hermes/skills/ 目录下,每个技能是一个子文件夹,里面有一个 skill.yaml 和对应的执行脚本。我写了一个脱敏技能,专门用来在 Agent 处理任何文本之前,把身份证号、手机号、银行卡号全糊掉。

具体做法是:在 ~/.hermes/skills/ 下建一个 desensitize/ 文件夹,然后写 skill.yaml

name: desensitize
version: "1.0"
description: "脱敏:替换身份证、手机号、银行卡号为掩码"
trigger: "desensitize"
script: "desensitize.py"

脚本 desensitize.py 长这样,核心逻辑就是正则替换:

import re
def run(text):
    text = re.sub(r'\b\d{17}[\dXx]\b', '[身份证号]', text)
    text = re.sub(r'\b1[3-9]\d{9}\b', '[手机号]', text)
    text = re.sub(r'\b\d{16,19}\b', '[银行卡号]', text)
    return text

写完这个之后,你在 Hermes 里跟 Agent 对话的时候,它会自动调用这个技能。我验证过:输入 hermes run "处理这份文件:张三,身份证号 110101199003071234",输出直接变成 张三,身份证号 [身份证号]

这里有个易错点:如果你在 skill.yaml 里忘记写 trigger 字段,Hermes 会默认技能名作为触发词。也就是说你喊 desensitize 才会触发,不喊就不触发。我一开始没写 trigger,结果 Agent 处理文件的时候根本没走脱敏流程,吓得我赶紧补上。另外,技能脚本的依赖要装全,比如用到了 pandas,那就得 pip install pandas,否则运行时报 ModuleNotFoundError,Agent 会直接罢工。

我把这个脱敏技能设成了默认自动加载:在 config.yamlskills 节点下加一行 auto_load: ["desensitize"]。这样每次 Agent 启动,它就会自动把脱敏脚本挂上,处理任何输入之前先过一遍。实测下来,处理 5000 行客户数据,脱敏耗时不到 1 秒,基本无感。

四、断网验证:把网线拔了,Agent 还能干活

配置写好了,脱敏挂上了,接下来是最刺激的一步:拔网线测试。我直接把 Mac 的 Wi-Fi 关掉,然后跑 hermes run "总结一下这个月的销售数据",看看它到底能不能在纯离线状态下工作。结果第一轮就报错了:Connection error: Failed to resolve hostname 'api.openai.com'。我一看,这不就是刚才配置里那个 network.allow_list 没清干净嘛。虽然我把 model_provider 改成了 local,但网络层还是允许访问外部 API 的。

解决办法是把 config.yaml 里的 network.allow_external 改成 false,然后把 allow_list 清空。改完之后再看日志,所有外部连接请求全被拦住了。我在日志里搜索 blocked,能看到类似 Blocked external connection to api.openai.com 的记录,这就对了。

不过这里有个细节:Hermes 的模型加载本身也需要读取本地文件,这个不受网络限制。但如果你用的是云端模型 API(比如 OpenAI 的接口),那断网之后 Agent 就彻底瘫痪了。所以我的建议是,本地模型加本地 embedding 这套组合,才是真正意义上的“断网可用”。我试过用 llama.cpp 跑量化后的 3B 模型,离线状态下的响应速度大概在 300ms 左右,跟在线 API 差距不大,完全够用。

还有一个小技巧:你可以用 lsof -i 命令实时监控 Hermes 进程有没有偷偷往外发包。我跑了一下 lsof -i -P | grep hermes,输出只有一行 hermes 12345 user 4u IPv4 ... TCP 127.0.0.1:8080 (LISTEN),说明它只在本地端口监听,没有对外连接。如果你看到类似 TCP 192.168.1.5:54321->8.8.8.8:443 的输出,那就说明有东西在往外传数据,得回头查配置。

五、定时任务和记忆:本地闭环的最后一块拼图

数据安全不只是“处理时不外传”,还包括“存下来的东西不乱跑”。Hermes 的记忆功能默认存在 SQLite 数据库里,路径是 ~/.hermes/memory/hermes_memory.db。这个文件就是你的记忆库,里面存了 Agent 跟你聊过的所有内容。如果你用 hermes memory search "客户A的合同金额",它会在本地做向量检索,返回结果。这个过程中数据不会出你机器一步。

我遇到的坑是:Hermes 默认的记忆压缩策略是 auto_compact: true,意思是当记忆库超过一定大小时,它会自动把旧记录摘要压缩。问题在于压缩的时候它会调用模型,如果模型是本地的那没事,但如果你配置里漏了 embedding 的 local 设置,它就会去云端跑摘要,那你的对话记录就全被送出去了。所以再次强调:embedding_provider: "local" 这行必须写对。

定时任务这块,我用 hermes cron create 建了一个每天晚上九点跑的任务,自动整理当天处理的文件清单,生成脱敏后的报告。命令长这样:

hermes cron create --name "daily_report" --schedule "0 21 * * *" --task "summarize --source ~/work/ --output ~/reports/daily.md --desensitize"

这个任务的好处是,它跑在本地,不依赖任何云服务。我特意试过在飞机上没有 Wi-Fi 的环境下,它照样能跑完,生成报告。如果你在创建任务的时候报错 Invalid cron expression,检查一下你的 schedule 格式是不是标准的五段式 cron 语法。我第一次写成了 "每天21点",结果直接被拒了。改成 "0 21 * * *" 就好了。

还有一点,定时任务跑出来的日志会存在 ~/.hermes/logs/ 下面,默认是 info 级别。如果你想看得更细,把 config.yaml 里的 log.level 改成 debug,这样每次任务执行的时候,每一步调用的参数、模型推理的结果、脱敏的规则匹配情况全都会被记录下来。不过 debug 日志文件涨得很快,我跑了三天就攒了 200MB,记得定期清理或者用 logrotate 管理一下。

六、实战演练:从零到一跑通本地安全管道

把前面所有步骤串起来,我用一个真实的场景演示一遍完整的流程。假设你现在拿到一个 Excel 文件,里面有 100 个客户的姓名、手机号和消费记录,你要让 Agent 生成一个消费分析报告,但手机号不能出现在报告里。

第一步,把文件放到 ~/work/ 目录下,然后跑 hermes run "分析 ~/work/customers.xlsx 的消费趋势,输出报告到 ~/reports/analysis.md,注意脱敏"。Hermes 会先调用 desensitize 技能把手机号替换成掩码,然后再做数据分析。我实际跑的时候,第一次报错说 File not found,原因是 Hermes 的工作目录默认在 ~/.hermes/workspace/,你得用绝对路径或者先 cd 到文件所在目录。我用了绝对路径之后就好了。

第二步,等它跑完,打开 ~/reports/analysis.md,你会发现手机号那一列全变成了 [手机号],但消费趋势数据完整保留。我故意在原始文件里藏了一个测试手机号 13812345678,报告里显示的是 [手机号],说明脱敏生效了。

第三步,检查记忆库有没有泄露。跑 hermes memory search "13812345678",返回结果是 No results found。这就对了,因为脱敏是在数据进入 Agent 处理流程之前完成的,原始手机号根本没进到记忆库里。

第四步,检查日志。打开 ~/.hermes/logs/hermes.log,搜索 blockedexternal,确认没有任何对外连接请求。我跑的时候只看到一条 Blocked external connection to api.telemetry.io,这是 Hermes 自带的遥测服务,被我拦了。

这套流程走完之后,你手里的数据就真正做到了“本地进、本地出、本地存”。以后不管甲方给你什么敏感资料,你都可以拍着胸脯说:这活儿我接了,数据不出我这台机器。

💬 你用过哪些AI工具?

写到这里,我也挺好奇你平时都用什么 AI 工具处理数据。是跟我一样用本地 Agent 硬扛,还是图省事直接用在线平台?如果你也在纠结选哪个模型或者 Agent 框架,不妨去 AI House 排行榜(aibunkhouse.com/rankings/)逛逛,上面有各类模型的最新排名和用户真实评价。刷到顺眼的模型,点进去给它投一票,也让我看看大家都爱用啥。

常见问题 / FAQ

一、那次物料清单泄露,让我下决心把数据锁在本地

上个月我接了一个外包项目,甲方丢给我一堆客户购买记录和内部报价单,说要用 AI Agent 自动整理成周报。我图省事,直接把 CSV 丢给了一个在线 Agent 平台。结果第三天对方打电话来,说他们的竞品拿到了那份报价单的截图。我查了半天,发现问题出在那个平台的默认设置上:它把我上传的文件当成了训练数据,存在了云端。 那次之后我彻底学乖了。如果你也在拿 Hermes Agent 处理合同、病历、...

二、把 config.yaml 改成“本地优先”:三行配置的事

先说说这个 ~/.hermes/config.yaml 的结构。它长这样: agent: name: "my-agent" model_provider: "local" # 关键:默认是 cloud,必须改成 local local_model_path: "/opt/hermes/models/llama-3.2-3b-instruct-q8.gguf" embedding...

三、技能目录里的“脱敏插件”:用 Python 脚本把身份证号糊掉

配置改完之后,接着处理数据本身。Hermes 的技能放在 ~/.hermes/skills/ 目录下,每个技能是一个子文件夹,里面有一个 skill.yaml 和对应的执行脚本。我写了一个脱敏技能,专门用来在 Agent 处理任何文本之前,把身份证号、手机号、银行卡号全糊掉。 具体做法是:在 ~/.hermes/skills/ 下建一个 desensitize/ 文件夹,然后写 skill.ya...

四、断网验证:把网线拔了,Agent 还能干活

配置写好了,脱敏挂上了,接下来是最刺激的一步:拔网线测试。我直接把 Mac 的 Wi-Fi 关掉,然后跑 hermes run "总结一下这个月的销售数据",看看它到底能不能在纯离线状态下工作。结果第一轮就报错了:Connection error: Failed to resolve hostname 'api.openai.com'。我一看,这不就是刚才配置里那个 network.allow_...

五、定时任务和记忆:本地闭环的最后一块拼图

数据安全不只是“处理时不外传”,还包括“存下来的东西不乱跑”。Hermes 的记忆功能默认存在 SQLite 数据库里,路径是 ~/.hermes/memory/hermes_memory.db。这个文件就是你的记忆库,里面存了 Agent 跟你聊过的所有内容。如果你用 hermes memory search "客户A的合同金额",它会在本地做向量检索,返回结果。这个过程中数据不会出你机器一步...