第 3 篇:CLI 界面详解------命令行交互全攻略
引言
Hermes 的 CLI 不仅是一个简单的提示符,它是一个完整的终端用户界面,支持多行编辑、斜杠命令自动补全、对话历史、中断重定向和流式工具输出。
启动方式
bash
# 交互式会话(默认)
hermes
# 单次查询模式(非交互)
hermes chat -q "Hello"
# 指定模型
hermes chat --model "anthropic/claude-sonnet-4"
# 指定提供商
hermes chat --provider nous
# 指定工具集
hermes chat --toolsets "web,terminal,skills"
# 预加载技能
hermes -s hermes-agent-dev,github-auth
hermes chat -s github-pr-workflow -q "open a draft PR"
# 恢复会话
hermes --continue # 恢复最近会话
hermes --resume <session_id> # 恢复指定会话
# 隔离 git worktree(并行运行多个代理)
hermes -w -z "Fix issue #123"
状态栏
CLI 在输入区上方有一个实时状态栏:
bash
⚕ claude-sonnet-4-20250514 │ 12.4K/200K │ [██████░░░░] 6% │ $0.06 │ 15m
| 元素 | 说明 |
|---|---|
| 模型名称 | 当前模型(超过 26 字符截断) |
| Token 计数 | 已用上下文 / 最大上下文窗口 |
| 上下文条 | 颜色编码的填充指示器 |
| 费用 | 预估会话费用 |
| 持续时间 | 经过的会话时间 |
上下文颜色编码:
| 颜色 | 阈值 | 含义 |
|---|---|---|
| 绿色 | < 50% | 空间充足 |
| 黄色 | 50--80% | 开始变满 |
| 橙色 | 80--95% | 接近限制 |
| 红色 | ≥ 95% | 接近溢出------考虑 /compress |
关键绑定
| 按键 | 动作 |
|---|---|
Enter |
发送消息 |
Alt+Enter / Ctrl+J / Shift+Enter |
换行(多行输入) |
Ctrl+G |
在 $EDITOR 中编辑当前输入 |
Ctrl+S |
暂存当前草稿 |
Ctrl+C |
中断代理(双击强退) |
Ctrl+Z |
挂起到后台(仅 Unix) |
Tab |
自动补全或接受建议 |
!<command> |
Shell 模式------直接运行 shell 命令 |
Shell 模式(! 前缀)
以 ! 开头的行会直接作为 shell 命令运行,不经过模型:
shell
> !git status
> !ls -la
> !pytest -x tests/cli
特点:零成本 (不调用模型 API)、不进入对话历史(上下文保持干净)、在代理的终端工具同一目录下运行。
斜杠命令
输入 / 查看自动补全下拉菜单:
| 命令 | 描述 |
|---|---|
/help |
显示命令帮助 |
/model |
显示或更改当前模型 |
/tools |
列出当前可用工具 |
/background <prompt> |
在后台会话中运行提示 |
/reasoning high |
提高推理强度 |
/title My Session |
命名当前会话 |
/status |
显示会话信息(模型/profile/token/时长) |
/context |
上下文使用可视化分解 |
/sessions |
会话选择器 |
/compress |
手动压缩会话 |
/new |
开始新会话 |
快速命令(Quick Commands)
你可以在 config.yaml 中定义自定义命令,在 CLI 和消息平台上都可用:
yaml
# ~/.hermes/config.yaml
quick_commands:
status:
type: exec
command: systemctl status hermes-agent
gpu:
type: exec
command: nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv,noheader
restart:
type: alias
target: /gateway restart
然后在任何聊天中输入 /status、/gpu 或 /restart 即可。
中断与重定向
当代理正在工作时,你可以发送修正消息:
- 输入新消息 + Enter --- 重定向当前回合
- Ctrl+C --- 中断当前操作(双击 2 秒内强制退出)
- 已完成的工具工作和推理保留在上下文中
忙时输入模式(display.busy_input_mode):
yaml
display:
busy_input_mode: "steer" # steer | queue | interrupt(默认)
| 模式 | 行为 |
|---|---|
interrupt(默认) |
你的消息重定向活动回合 |
queue |
消息排队,代理完成后发送 |
steer |
消息注入当前运行,不中断、不开新回合 |
后台会话
在一个独立的后台会话中运行提示,同时继续使用 CLI:
css
/background Analyze the logs in /var/log and summarize any errors from today
Hermes 会确认任务并立即把输入权交还给你:
yaml
🔄 Background task #1 started: "Analyze the logs in /var/log and summarize..."
Task ID: bg_143022_a1b2c3
后台会话是隔离的------它不知道你当前会话的历史,只收到你提供的提示。
Q&A
Q1: Shell 模式的 ! 前缀和让代理运行命令有什么区别? A1: Shell 模式直接在终端运行命令,不调用模型(零 API 成本),不进入对话历史。让代理运行命令则是通过模型的 terminal 工具,会计费、会进入上下文,但代理可以理解输出并做出决策。
Q2: 如何在长会话中管理上下文消耗? A2: 使用 /compress 手动压缩,或让自动压缩在阈值触发时运行(默认 50%)。你也可以用 /context 查看各部分(系统提示/工具/技能/记忆/对话)的 token 占比,用 /usage 查看详细的费用分解。
Q3: Ctrl+S 暂存草稿后怎么找回? A3: 在空输入区按 Ctrl+S 即可恢复最近暂存的草稿。如果暂存了多个,Ctrl+S 会打开浏览面板,用上下方向键导航、Enter 恢复、D 丢弃。
双层邮件管道状态机:50ms 哑层 + LLM 一次性会话的零空闲成本架构
Hermes Agent 深度拆解 · 第 03 篇
双层邮件管道状态机:50ms 哑层 + LLM 一次性会话的零空闲成本架构
当所有人都在用 hermes cron 每分钟唤醒 LLM 检查邮件时,mayuronx 用一个 50ms 的纯 Python 哑脚本 + .trigger/.lock 文件协议,把 LLM 调用次数压到"仅有新邮件时才触发"。本文从 Discord 归档到 himalaya CLI,1:1 逆向双层状态机。
作者:mayuronx (Discord) 分类:Dev Workflow · Email Automation 来源:Discord 归档 发布:2026-04-11
PART 01
案例背景 + 溯源 + 整体架构
开篇:你的 Agent 邮件自动化在烧钱
给 Hermes Agent 加邮件自动回复,大多数人想到的第一条路是------hermes cron create "*/1 * * * *" "检查我的收件箱并回复新邮件"。看起来合理:每分钟检查一次,新邮件立即处理。但算一笔账:一天 1,440 分钟,即使收件箱 99% 的时间是空的,LLM 也会被唤醒 1,440 次。按 Claude Sonnet 4.6 单次最低 200 tokens 算,一天光"空转"就烧掉 28 万 tokens------这还不算每次 IMAP 连接、邮件读取、上下文组装的开销。
社区用户 mayuronx 撞上了同一堵墙。他的洞察很简单:收件箱大部分时间是空闲的,LLM 不应该为"没有事可做"而付费 。于是他设计了一个双层状态机------一个 50ms 的纯 Python 哑脚本负责"有没有新邮件"的判断,只有判断为"是"时,才通过 hermes chat -q 拉起一次 LLM 会话。LLM 处理完立即退出,不常驻、不轮询、不空转。
核心痛点
用 LLM 做邮件轮询是"用大炮打蚊子"------收件箱状态检查是 O(1) 的差集运算,根本不需要 LLM 参与。把状态检测和内容处理混在一个 LLM 会话里,导致 99% 的 LLM 调用都在做无用功。
溯源信息
溯源渠道与原始链接
Discord 归档Nous Discord #community-projects-showcase, thread 1492347479805530182
归档标题Email Checker State Machine
发布日期2026-04-11
作者mayuronx (Discord)
公开仓库未找到(归档仅含设计文档,check-email.py 源码未公开)
作者在 Discord 原帖中的原话:
作者原话
"Two-tier email processing system for my agent (I gave it Spacemail IMAP via himalaya). Tier 1 (Dumb): Pure Python script, no LLM. Detects new email, manages state. Tier 2 (Smart): LLM session via hermes chat -q. Only invoked when new email detected. Key goal: Zero LLM calls when inbox is idle."
需求梳理:双层状态机要解决什么?
mayuronx 的核心诉求可以拆成五条:
| 痛点 | 常见方案 | mayuronx 方案 |
|---|---|---|
| LLM 空转烧钱 | hermes cron 每分钟调用 LLM 检查邮件 | Tier 1 哑脚本 50ms 判断,仅新邮件时拉起 LLM |
| LLM 会话并发冲突 | 多个 cron 重叠 → 同一收件箱被多个会话同时操作 | .lock 文件互斥锁,LLM busy 时哑脚本 deferred 退出 |
| 多封邮件到达需多次 LLM | 每封邮件一次 LLM 会话,成本线性增长 | .trigger 批处理追加,LLM 一次会话处理所有积压邮件 |
| LLM 崩溃后系统卡死 | 锁不释放 → 后续所有检查都被阻塞 | 陈旧锁检测:.lock 超过 10 分钟 → 哑脚本强制删除 |
| 邮件安全验证缺失 | LLM 直接回复,不验证发件人身份 | Tier 2 检查 SPF/DKIM/DMARC 头,受信+已认证才回复 |
五层完整架构图
mayuronx 的双层邮件管道不是一个独立系统,而是嵌入 Hermes 部署运维层的事件驱动管道。以下是完整五层视图:
顶层 · 调度
cron 守护进程 --- */1 * * * * 每分钟触发 check-email.py(无 LLM 参与)
↓ exec
Tier 1 · 哑层
★ check-email.py(纯 Python,~50ms,无 LLM): himalaya envelope list → 差集 → .lock/.trigger 检查 → 写 .trigger → 拉起 LLM
↓ 后台分离式 spawn(nohup &)
Tier 2 · 智能层
★ hermes chat -q 一次性会话(LLM,完成后退出): 读 .trigger → 写 .lock → himalaya message read → SPF/DKIM/DMARC → 回复/转发 → 清理
↓ 读写
状态文件层
~/.hermes/email/: seen_ids.json · .trigger · .lock · events.log · rules.md
↓ 调用
工具层
himalaya CLI(IMAP 信封列表 / 邮件读取 / SMTP 发送)· hermes chat -q(LLM 一次性查询)
↓ 连接
部署运维层
VPS 主机 · cron 调度器 · Spacemail IMAP 服务器 · events.log 日志轮转 · cron.log 错误捕获
层级权责说明
| 层级 | 组件 | 权责 | 关键约束 |
|---|---|---|---|
| 顶层 · 调度 | cron 守护进程 | 每分钟触发 Tier 1 哑脚本,无 LLM 参与 | 单一 cron 任务,无 LLM cron |
| Tier 1 · 哑层 | check-email.py | 列出信封 → 差集 → 状态检查 → 写 .trigger → 后台拉起 LLM | 纯 Python,无 LLM 调用,执行时间 ~50ms |
| Tier 2 · 智能层 | hermes chat -q | 读 .trigger → 写 .lock → 逐封读取 → 认证检查 → 回复/转发 → 清理 | 一次性会话,完成后退出;不常驻 |
| 状态文件层 | ~/.hermes/email/ | 跨层级状态传递:seen_ids / .trigger / .lock / events.log / rules.md | .trigger 由哑脚本创建、LLM 删除;.lock 由 LLM 创建删除 |
| 工具层 | himalaya + hermes CLI | himalaya 负责 IMAP/SMTP 操作;hermes chat -q 负责 LLM 推理 | himalaya 支持 --json 标志用于脚本化解析 |
| 部署运维层 | VPS + cron + IMAP | 进程调度、邮件服务器连接、日志管理 | cron.log 捕获 stderr,events.log 仅追加 |
设计精髓:哑层与智能层的物理隔离
Tier 1 和 Tier 2 是两个完全独立的进程 ,通过文件系统状态传递------不是函数调用,不是 IPC,不是消息队列。哑脚本通过 nohup ... & 后台分离式拉起 LLM 后立即退出,不等待 LLM 完成。这意味着 cron 的 1 分钟周期永远不会被 LLM 的处理时间阻塞。
状态文件全景
双层状态机的核心是五个状态文件,全部位于 ~/.hermes/email/ 目录下。它们是 Tier 1 和 Tier 2 之间唯一的通信渠道:
| 文件 | 用途 | 格式 | 生命周期 |
|---|---|---|---|
| seen_ids.json | 已处理邮件 ID 数组 | JSON 数组: 44, 45, 46 | 持久化,每次处理后更新 |
| .trigger | 触发器:通知 LLM 有新邮件待处理 | JSON: {"timestamp": "...", "ids": 45, 46, "summary": "..."} | 哑脚本创建,LLM 删除 |
| .lock | 互斥锁:防止多个 LLM 会话并发 | JSON: {"email_id": 45, "timestamp": "...", "pid": 12345} | LLM 创建,LLM 完成时删除 |
| events.log | 带时间戳的操作日志 | 纯文本,每行一条 | 仅追加,手动轮转 |
| rules.md | 回复/转发规则 | Markdown | 静态,人工编辑 |
锁协议:四条铁律
双层状态机最容易出错的地方是 Tier 1 和 Tier 2 的并发控制。mayuronx 用四条锁协议规则解决了这个问题:
锁协议四条铁律
规则 1 :哑脚本优先检查 .lock --- 若存在 → 记录 "deferred, LLM busy",立即退出(不写 .trigger)
规则 2 :LLM 启动时立即写 .lock(在任何邮件读取之前)------先占锁,后干活
规则 3 :LLM 完成时(无论成功或失败)删除 .lock + .trigger------必须用 try/finally 确保异常时也释放锁
规则 4 :陈旧锁检测 --- 若 .lock 超过 10 分钟,哑脚本删除它并继续------防止 LLM 崩溃后系统永久卡死
触发器批处理:多封邮件一次处理
mayuronx 的另一个精妙设计是触发器批处理。当多封邮件在两次 cron 检查之间到达时,它们不会被拆成多次 LLM 会话:
yaml
# 触发器批处理时序(基于设计文档还原)
# 第一次检查(03:45:01):邮件 A 到达
03:45:01 CHECK: Found 1 new email (ID: 45)
03:45:01 TRIGGER: Written for IDs [45] # .trigger = {ids: [45]}
03:45:02 SPAWN: LLM session started # 后台拉起 hermes chat -q
# 第二次检查(03:46:01):邮件 B 到达,但 LLM 还在处理 A
03:46:01 CHECK: Found 1 new email (ID: 46)
03:46:01 .lock exists → DEFERRED # 规则 1:LLM busy,退出
# --- 但 .trigger 已存在,不会覆盖,邮件 B 等待下一轮
# LLM 处理完 A 后删除 .lock + .trigger(规则 3)
03:46:30 CLEANUP: .trigger + .lock deleted
# 第三次检查(03:47:01):邮件 B 仍在,.trigger 不存在
03:47:01 CHECK: Found 1 new email (ID: 46) # B 仍未处理(seen_ids 未更新)
03:47:01 TRIGGER: Written for IDs [46] # 新 .trigger = {ids: [46]}
03:47:02 SPAWN: LLM session started
批处理的成本优势
如果两封邮件在 30 秒内先后到达,传统方案需要两次 LLM 会话。mayuronx 的方案中,如果 LLM 还在处理第一封,第二封会等待 .lock 释放后被下一轮检查重新触发------但更常见的情况是:多封邮件在两次检查间到达,.trigger 追加所有 ID,LLM 一次会话批量处理。这意味着LLM 调用次数 ≤ 新邮件批次数量,而非 ≤ 新邮件数量。
PART 02
分步落地教程 + 全 Hermes 命令清单
从零搭建:5 阶段完整流程
① 前期环境准备
硬件与依赖准备清单
VPS 推荐:1 vCPU / 1GB RAM / 20GB SSD(双层管道极轻量,哑脚本 50ms,LLM 按需调用)
操作系统:Ubuntu 22.04 LTS 或 Debian 12(cron + Python 3 一等支持)
邮件服务:任何支持 IMAP/SMTP 的邮箱(mayuronx 使用 Spacemail IMAP;Gmail/Fastmail/Outlook 均可)
API 密钥:OpenRouter API Key(推荐,300+ 模型可选);或 Anthropic / OpenAI 直连 Key
辅助工具:himalaya CLI(Rust 编写的邮件命令行工具,MIT OR Apache-2.0)
Step 1:安装 Hermes Agent
bash
# 一键安装脚本(Linux / macOS / WSL2)
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# 重载 shell 让 hermes 命令生效
source ~/.bashrc
# 交互式配置:选择 Provider → 粘贴 API Key → 选择模型
hermes setup
# 验证安装
hermes doctor
Step 2:安装 himalaya CLI
bash
# 方式 1:官方安装脚本(推荐)
curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | PREFIX=~/.local sh
# 方式 2:Homebrew(macOS)
brew install himalaya
# 方式 3:Cargo 编译(可定制 backend feature)
cargo install --locked --git https://github.com/pimalaya/himalaya.git \
--no-default-features --features imap,smtp,rustls-ring
# 方式 4:Arch Linux
pacman -S himalaya
# 验证安装
himalaya --version
himalaya account list
himalaya 是什么
himalaya 是一个用 Rust 编写的 CLI 邮件客户端,支持 IMAP/SMTP/JMAP/Gmail REST API/Microsoft Graph/Maildir 多种后端。关键特性:支持 --json 标志 输出结构化 JSON,非常适合脚本化使用------这正是 mayuronx 选择它而非 Python imaplib 的原因。配置文件位于 ~/.config/himalaya/config.toml 或 ~/.himalayarc。
Step 3:配置 himalaya 连接 IMAP
ini
# ~/.config/himalaya/config.toml(基于 himalaya 官方 config.sample.toml 适配)
[accounts.spacemail]
default = true
# IMAP 配置(接收邮件)
imap.server = "imaps://imap.spacemail.example.com"
imap.sasl.plain.username = "you@example.com"
imap.sasl.plain.password.command = "pass show spacemail"
# SMTP 配置(发送邮件)
smtp.server = "smtps://smtp.spacemail.example.com"
smtp.sasl.plain.username = "you@example.com"
smtp.sasl.plain.password.command = "pass show spacemail"
# 邮箱别名(让 -m 参数可选)
mailbox.alias.inbox = "INBOX"
mailbox.alias.sent = "Sent"
mailbox.alias.drafts = "Drafts"
mailbox.alias.trash = "Trash"
# 适配点:将 imap.spacemail.example.com 替换为你的 IMAP 服务器地址
# 适配点:密码建议用 pass/gopass 管理,不要明文写入配置
bash
# 验证 himalaya 连接
himalaya envelope list # 列出收件箱信封
himalaya envelope list --json # JSON 格式输出(脚本用)
himalaya message read 1 # 读取第 1 封邮件
② Tier 1 哑脚本部署
Step 4:创建目录结构与状态文件
bash
# 创建邮件管道目录结构
mkdir -p ~/.hermes/email
mkdir -p ~/.hermes/scripts/email
# 初始化 seen_ids.json(空数组)
echo '[]' > ~/.hermes/email/seen_ids.json
# 创建空的 events.log
touch ~/.hermes/email/events.log
# 创建 rules.md(回复/转发规则,人工编辑)
cat > ~/.hermes/email/rules.md <<'EOF'
# Email Processing Rules
## Trusted Senders (Reply directly)
- hello@mayur.ca
- *@trusted-domain.com
## Action: Reply
- If sender is trusted AND SPF/DKIM/DMARC all pass → reply directly
## Action: Forward
- If sender is unknown OR authentication fails → forward to admin@example.com
## Action: Ignore
- If DMARC fails → do not reply, log only
EOF
# .trigger 和 .lock 不需要手动创建------由脚本运行时自动管理
Step 5:部署 check-email.py 哑脚本
bash
# 将 check-email.py 放到 ~/.hermes/scripts/email/ 目录
# 完整源码见 PART 03 核心代码 ①(基于设计文档重建)
chmod +x ~/.hermes/scripts/email/check-email.py
# 手动测试运行(不通过 cron)
python3 ~/.hermes/scripts/email/check-email.py
# 查看 events.log 确认执行
tail -f ~/.hermes/email/events.log
③ Tier 2 智能层配置
Step 6:编写 LLM 提示词与 SOUL.md
sql
# ~/.hermes/SOUL.md(邮件处理 Agent 人格)
cat > ~/.hermes/SOUL.md <<'EOF'
# Personality
You are an email processing assistant for mayuronx.
You are invoked only when new emails arrive. Process them efficiently and exit.
## Style
- Be concise in replies
- Always verify sender authentication before replying
- When uncertain, forward rather than reply
## Technical posture
- Read ~/.hermes/email/rules.md for processing rules
- Check SPF/DKIM/DMARC headers before any action
- Trusted + authenticated → reply; everything else → forward
- Always clean up .trigger and .lock when done
EOF
Step 7:验证 hermes chat -q 一次性调用
bash
# 测试 hermes chat -q 一次性查询模式
# -q = quiet 模式,非交互式,传入 prompt 后执行并退出
hermes chat -q "读取 ~/.hermes/email/rules.md 并告诉我回复规则是什么"
# 确认输出后进程自动退出(不常驻)
echo "Exit code: $?"
hermes chat -q 验证状态
hermes chat -q 的一次性调用模式(quiet,非交互式,传入 prompt 后执行并退出)在 Discord 归档中被明确声明为 Tier 2 的调用方式。这是双层架构能成立的前提条件------如果 hermes chat 不支持非交互式一次性退出,整个方案就无法工作。归档声明 + Hermes 仓库的 one-shot 提交记录提供了部分验证。
④ Cron 配置
Step 8:配置 cron 定时任务
perl
# 编辑 crontab
crontab -e
# 添加以下行(每分钟执行一次哑脚本)
*/1 * * * * /usr/bin/python3 ~/.hermes/scripts/email/check-email.py >> ~/.hermes/email/cron.log 2>&1
# 保存退出后验证
crontab -l | grep check-email
# 等待 1 分钟后检查 cron.log
tail -f ~/.hermes/email/cron.log
Cron 配置要点
单一 cron 任务 :只有一个 cron 条目调用哑脚本,没有 LLM cron ------LLM 由哑脚本通过 hermes chat -q 按需拉起。
stderr 重定向 :2>&1 将 stderr 合并到 cron.log,确保 Python 异常不会丢失。cron.log 是 cron 级别的日志(捕获脚本启动失败等),events.log 是业务级别的日志(记录邮件处理动作)。
⑤ 测试与验证
Step 9:端到端测试
bash
# 测试 1:收件箱为空时------验证零 LLM 调用
# 等待 2 分钟,检查 events.log
tail ~/.hermes/email/events.log
# 预期输出:CHECK: No new emails(无 SPAWN 行)
# 测试 2:发一封测试邮件给自己
echo "Test email" | mail -s "Pipeline Test" you@example.com
# 等待 1-2 分钟,检查完整流程
tail -20 ~/.hermes/email/events.log
# 预期输出序列:
# CHECK: Found 1 new email (ID: N)
# TRIGGER: Written for IDs [N]
# SPAWN: LLM session started (PID xxxx)
# LOCK: Set for ID N
# ACTION: Replied to ID N (...) 或 Forwarded ID N
# CLEANUP: .trigger + .lock deleted
# 测试 3:验证 seen_ids.json 已更新
cat ~/.hermes/email/seen_ids.json
# 预期:["N"](已处理的邮件 ID)
# 测试 4:模拟 LLM busy 场景------手动创建 .lock
echo '{"email_id": 999, "timestamp": "2099-01-01 00:00:00", "pid": 99999}' > ~/.hermes/email/.lock
python3 ~/.hermes/scripts/email/check-email.py
# 预期:DEFERRED: .lock exists, skipping (LLM busy)
# 测试 5:模拟陈旧锁------创建 11 分钟前的 .lock
echo '{"email_id": 999, "timestamp": "2020-01-01 00:00:00", "pid": 99999}' > ~/.hermes/email/.lock
python3 ~/.hermes/scripts/email/check-email.py
# 预期:STALE LOCK detected, removing → 正常继续处理
全 Hermes + himalaya 命令清单
以下是本案例中用到的全部 CLI 指令,按工具分组:
| 指令完整写法 | 功能作用 | 适用场景 | 关键入参 | 工具 |
|---|---|---|---|---|
| himalaya envelope list | 列出收件箱邮件信封(ID、发件人、主题、日期) | Tier 1 哑脚本获取当前邮件列表 | -m(邮箱)、--page(分页)、--json | himalaya |
| himalaya envelope list --json | JSON 格式输出信封列表 | 脚本化解析邮件 ID | --json | himalaya |
| himalaya message read | 读取指定 ID 的邮件完整内容(含头) | Tier 2 LLM 逐封读取邮件 | id(邮件 ID)、--json | himalaya |
| himalaya smtp send | 通过 SMTP 发送邮件 | Tier 2 LLM 回复/转发邮件 | stdin 传入邮件内容 | himalaya |
| himalaya message read --json | JSON 格式读取邮件(含所有头字段) | Tier 2 解析 SPF/DKIM/DMARC 头 | --json | himalaya |
| himalaya account list | 列出已配置的邮件账户 | 验证 himalaya 配置 | 无 | himalaya |
| himalaya mailbox list | 列出所有邮箱文件夹 | 验证 IMAP 连接 | 无 | himalaya |
| hermes chat -q "prompt" | 一次性查询(quiet,非交互式,执行后退出) | Tier 2 LLM 会话------哑脚本后台拉起 | -q(quiet)、--provider、--model | hermes |
| hermes setup | 交互式配置向导 | 首次安装后配置 Provider/API Key/模型 | --portal(OAuth 一键配置) | hermes |
| hermes doctor | 诊断配置和依赖问题 | 安装后验证、故障排查 | 无 | hermes |
| hermes model | 交互式选择 LLM Provider 和模型 | 切换模型、添加新 Provider | 无(交互式) | hermes |
| hermes config set KEY VAL | 设置配置值 | 修改模型、API Key、各种参数 | KEY(如 model)、VAL | hermes |
| hermes config edit | 在编辑器中打开 config.yaml | 批量修改配置 | 无 | hermes |
| hermes profile create NAME | 创建新 Profile | 邮件 Agent 专用 Profile 隔离 | --no-skills | hermes |
| hermes cron create "schedule" "prompt" | 创建定时任务 | 日志轮转、定期维护(非邮件检查) | --name、--deliver | hermes |
| hermes cron list | 列出所有 cron 任务 | 任务管理 | 无 | hermes |
| hermes fallback | 管理后备 Provider | 主模型宕机切换 | 交互式 | hermes |
| hermes backup | 备份 Hermes 主目录到 zip | 定期备份状态文件 | 无 | hermes |
| hermes gateway install | 安装为后台服务 | VPS 部署、24/7 运行 | --system | hermes |
| crontab -e | 编辑 cron 定时任务表 | 配置哑脚本每分钟执行 | 无 | 系统 |
| crontab -l | 列出当前 cron 任务 | 验证 cron 配置 | 无 | 系统 |
完整配置模板(可直接复制)
himalaya config.toml 模板
ini
# ~/.config/himalaya/config.toml
# 基于 himalaya 官方 config.sample.toml 适配
[accounts.default]
default = true
# IMAP(接收)--- 适配点:替换为你的 IMAP 服务器
imap.server = "imaps://imap.example.com"
imap.sasl.plain.username = "you@example.com"
imap.sasl.plain.password.command = "pass show email-password"
# SMTP(发送)--- 适配点:替换为你的 SMTP 服务器
smtp.server = "smtps://smtp.example.com"
smtp.sasl.plain.username = "you@example.com"
smtp.sasl.plain.password.command = "pass show email-password"
# 邮箱别名
mailbox.alias.inbox = "INBOX"
mailbox.alias.sent = "Sent"
mailbox.alias.drafts = "Drafts"
mailbox.alias.trash = "Trash"
cron 配置模板
bash
# crontab -e 添加以下内容
# ═══ 邮件管道:每分钟执行哑脚本 ═══
# 单一 cron 任务,无 LLM cron
# stderr 合并到 cron.log 以捕获 Python 异常
*/1 * * * * /usr/bin/python3 ~/.hermes/scripts/email/check-email.py >> ~/.hermes/email/cron.log 2>&1
# ═══ 日志轮转:每天凌晨压缩 events.log ═══
# 保留最近 7 天日志
0 0 * * * cd ~/.hermes/email && mv events.log events.$(date +\%Y\%m\%d).log && touch events.log && find . -name "events.*.log" -mtime +7 -delete
rules.md 回复/转发规则模板
diff
# ~/.hermes/email/rules.md
# 人工编辑,LLM 在 Tier 2 会话中读取此文件决定动作
# Email Processing Rules
## Trusted Senders (Reply directly)
- hello@mayur.ca
- *@your-company.com
- specific-friend@gmail.com
## Authentication Requirements
- SPF: must pass (sender IP authorized)
- DKIM: must pass (signature valid)
- DMARC: must pass (alignment confirmed)
- All three pass + sender trusted → REPLY
- Any failure + sender unknown → FORWARD to admin
- DMARC fail → IGNORE (do not reply, log only)
## Reply Tone
- Professional but warm
- Acknowledge receipt of their email
- Keep under 150 words
- Sign as "mayuronx's AI assistant"
## Forward Rules
- Forward to: admin@example.com
- Include original email as attachment
- Add prefix "[FORWARDED by AI]" to subject
## Special Handling
- Mailing list emails → ignore (check List-Id header)
- Automated notifications → ignore (check Auto-Submitted header)
- Emails with attachments → forward to admin for manual review
config.yaml 邮件 Agent 专用模板
yaml
# ~/.hermes/config.yaml(邮件处理 Agent 专用配置)
# 主模型配置------建议用便宜模型处理邮件
model:
provider: "openrouter"
default: "anthropic/claude-sonnet-4.6"
# 记忆配置(邮件 Agent 不需要太多记忆)
memory:
memory_enabled: true
user_profile_enabled: false
memory_char_limit: 1000
# 会话重置策略------邮件处理是一次性的,快速重置
session_reset:
mode: idle
idle_minutes: 5
# 子 Agent 委派(邮件处理不需要)
delegation:
max_concurrent_children: 0
# 终端后端(LLM 需要执行 himalaya 命令)
terminal:
backend: local
cwd: "~/.hermes/email"
timeout: 120
PART 03
源码深度解读 + 部署加固 + 复刻避坑总结
核心代码 ①:Tier 1 哑脚本 check-email.py
代码来源声明
mayuronx 的 check-email.py 实际源代码未公开 (Discord 归档仅含设计文档,未找到公开 GitHub 仓库)。以下实现基于归档中的设计文档完整重建,覆盖所有已验证的状态机行为:信封差集、.lock 检查、.trigger 追加、后台拉起 LLM、陈旧锁检测、事件日志。标注了所有适配修改点。
python
# check-email.py --- Tier 1 哑层脚本(基于设计文档重建)
# 路径:~/.hermes/scripts/email/check-email.py
# 特性:纯 Python,无 LLM 调用,执行时间 ~50ms
import json, os, sys, time, subprocess, logging
from datetime import datetime
from pathlib import Path
# ═══════════════════════════════════════════════════════════════
# 配置(适配点:根据你的环境修改路径)
# ═══════════════════════════════════════════════════════════════
EMAIL_DIR = Path.home() / ".hermes" / "email"
SEEN_IDS_FILE = EMAIL_DIR / "seen_ids.json"
TRIGGER_FILE = EMAIL_DIR / ".trigger"
LOCK_FILE = EMAIL_DIR / ".lock"
EVENTS_LOG = EMAIL_DIR / "events.log"
LLM_SCRIPT = Path.home() / ".hermes" / "scripts" / "email" / "process-emails.py"
STALE_LOCK_MINUTES = 10 # 陈旧锁阈值:10 分钟
# ═══════════════════════════════════════════════════════════════
# 日志工具
# ═══════════════════════════════════════════════════════════════
def log_event(message):
"""写入 events.log,格式:[YYYY-MM-DD HH:MM:SS] MESSAGE"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(EVENTS_LOG, "a") as f:
f.write(f"[{timestamp}] {message}\n")
# ═══════════════════════════════════════════════════════════════
# Step 1:获取当前收件箱邮件 ID 列表
# ═══════════════════════════════════════════════════════════════
def get_envelope_ids():
"""调用 himalaya envelope list --json 获取邮件 ID 列表"""
try:
result = subprocess.run(
["himalaya", "envelope", "list", "--json"],
capture_output=True, text=True, timeout=15
)
if result.returncode != 0:
log_event(f"ERROR: himalaya failed: {result.stderr}")
return []
envelopes = json.loads(result.stdout)
# 适配点:himalaya --json 输出格式可能因版本不同
# v1.x 输出为列表,v2.x 可能嵌套在对象中
if isinstance(envelopes, dict):
envelopes = envelopes.get("envelopes", [])
return [e["id"] for e in envelopes]
except Exception as e:
log_event(f"ERROR: get_envelope_ids exception: {e}")
return []
# ═══════════════════════════════════════════════════════════════
# Step 2:与 seen_ids.json 做差集,找出新邮件
# ═══════════════════════════════════════════════════════════════
def find_new_emails(current_ids):
"""返回 current_ids 中不在 seen_ids.json 里的新 ID"""
try:
with open(SEEN_IDS_FILE, "r") as f:
seen_ids = set(json.load(f))
except (FileNotFoundError, json.JSONDecodeError):
seen_ids = set() # 首次运行或文件损坏,视为全部已见
new_ids = [int(id) for id in current_ids if int(id) not in seen_ids]
return new_ids
# ═══════════════════════════════════════════════════════════════
# Step 3:陈旧锁检测(规则 4)
# ═══════════════════════════════════════════════════════════════
def check_stale_lock():
"""若 .lock 超过 10 分钟,删除它并返回 True(已清理)"""
if not LOCK_FILE.exists():
return False
try:
with open(LOCK_FILE, "r") as f:
lock_data = json.load(f)
lock_time = datetime.strptime(lock_data["timestamp"], "%Y-%m-%d %H:%M:%S")
age_minutes = (datetime.now() - lock_time).total_seconds() / 60
if age_minutes > STALE_LOCK_MINUTES:
log_event(f"STALE LOCK: .lock age {age_minutes:.1f}min > {STALE_LOCK_MINUTES}min, removing")
LOCK_FILE.unlink()
return True # 已清理,可继续
except Exception as e:
# .lock 格式损坏 → 视为陈旧锁,删除
log_event(f"STALE LOCK: .lock corrupted ({e}), removing")
LOCK_FILE.unlink(missing_ok=True)
return True
return False # 锁仍有效
# ═══════════════════════════════════════════════════════════════
# Step 4:写 .trigger(支持批处理追加)
# ═══════════════════════════════════════════════════════════════
def write_trigger(new_ids):
"""写 .trigger,若已存在则追加 ID(批处理)"""
if TRIGGER_FILE.exists():
# .trigger 已存在 → 追加新 ID(去重)
with open(TRIGGER_FILE, "r") as f:
trigger = json.load(f)
existing_ids = set(trigger.get("ids", []))
merged_ids = list(existing_ids | set(new_ids))
trigger["ids"] = merged_ids
log_event(f"TRIGGER: Appended to existing, IDs now {merged_ids}")
else:
# .trigger 不存在 → 新建
trigger = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ids": new_ids,
"summary": f"{len(new_ids)} new email(s) detected"
}
log_event(f"TRIGGER: Written for IDs {new_ids}")
with open(TRIGGER_FILE, "w") as f:
json.dump(trigger, f, indent=2)
# ═══════════════════════════════════════════════════════════════
# Step 5:后台分离式拉起 LLM(hermes chat -q)
# ═══════════════════════════════════════════════════════════════
def spawn_llm_session():
"""通过 hermes chat -q 后台拉起 LLM 一次性会话,不等待完成"""
prompt = (
"New emails detected. Read ~/.hermes/email/.trigger for email IDs. "
"Process each email: read via 'himalaya message read <id>', "
"check SPF/DKIM/DMARC headers, apply rules from ~/.hermes/email/rules.md, "
"reply or forward accordingly, then clean up .trigger and .lock."
)
# nohup + & 后台分离:哑脚本不等待 LLM 完成
# 适配点:LLM_SCRIPT 是包装脚本,内部调用 hermes chat -q
subprocess.Popen(
["nohup", "python3", str(LLM_SCRIPT), prompt],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
stdin=subprocess.DEVNULL,
start_new_session=True # 完全脱离父进程
)
log_event(f"SPAWN: LLM session started")
# ═══════════════════════════════════════════════════════════════
# 主流程:状态机核心逻辑
# ═══════════════════════════════════════════════════════════════
def main():
# 1. 获取当前邮件 ID 列表
current_ids = get_envelope_ids()
if not current_ids:
log_event("CHECK: No emails or himalaya connection failed")
return
# 2. 差集:找出新邮件
new_ids = find_new_emails(current_ids)
if not new_ids:
log_event("CHECK: No new emails")
return # ★ 零 LLM 调用!核心目标达成
log_event(f"CHECK: Found {len(new_ids)} new email(s) (IDs: {', '.join(map(str, new_ids))})")
# 3. 检查 .lock(规则 1)
if LOCK_FILE.exists():
# 3a. 先检查是否为陈旧锁(规则 4)
if not check_stale_lock():
# .lock 仍有效 → deferred 退出(规则 1)
log_event("DEFERRED: .lock exists, skipping (LLM busy)")
return
# 4. 检查 .trigger(若已存在 → 追加 ID,不拉起新 LLM)
if TRIGGER_FILE.exists():
# .trigger 已存在 → LLM 已被拉起或在等待中,仅追加 ID
write_trigger(new_ids)
log_event("TRIGGER: Appended to existing, LLM will batch process")
return
# 5. 写 .trigger
write_trigger(new_ids)
# 6. 后台拉起 LLM 一次性会话
spawn_llm_session()
if __name__ == "__main__":
main()
核心代码 ②:Tier 2 LLM 处理流程
代码来源声明
Tier 2 的 LLM 处理逻辑在归档中以设计文档形式描述,实际提示词和包装脚本未公开 。以下 process-emails.py 基于"读 .trigger → 写 .lock → 逐封读取 → 认证检查 → 回复/转发 → 清理"的设计文档完整重建。
python
# process-emails.py --- Tier 2 智能层包装脚本(基于设计文档重建)
# 路径:~/.hermes/scripts/email/process-emails.py
# 职责:包装 hermes chat -q,处理锁协议和清理逻辑
import json, os, sys, subprocess
from datetime import datetime
from pathlib import Path
EMAIL_DIR = Path.home() / ".hermes" / "email"
TRIGGER_FILE = EMAIL_DIR / ".trigger"
LOCK_FILE = EMAIL_DIR / ".lock"
SEEN_IDS_FILE = EMAIL_DIR / "seen_ids.json"
EVENTS_LOG = EMAIL_DIR / "events.log"
def log_event(message):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(EVENTS_LOG, "a") as f:
f.write(f"[{timestamp}] {message}\n")
def update_seen_ids(processed_ids):
"""将已处理的 ID 追加到 seen_ids.json"""
try:
with open(SEEN_IDS_FILE, "r") as f:
seen = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
seen = []
seen.extend(processed_ids)
with open(SEEN_IDS_FILE, "w") as f:
json.dump(seen, f)
def main():
# ═══ Step 1:读取 .trigger 获取邮件 ID ═══
if not TRIGGER_FILE.exists():
log_event("LLM: No .trigger file, exiting")
return
with open(TRIGGER_FILE, "r") as f:
trigger = json.load(f)
email_ids = trigger.get("ids", [])
if not email_ids:
log_event("LLM: .trigger has no IDs, exiting")
TRIGGER_FILE.unlink(missing_ok=True)
return
# ═══ Step 2:立即写 .lock(规则 2:在任何邮件读取之前)═══
lock_data = {
"email_id": email_ids[0],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"pid": os.getpid()
}
with open(LOCK_FILE, "w") as f:
json.dump(lock_data, f)
log_event(f"LOCK: Set for ID {email_ids[0]} (PID {os.getpid()})")
# ═══ Step 3-6:调用 hermes chat -q 处理邮件 ═══
# 构造 LLM 提示词------包含所有待处理 ID 和操作指令
email_ids_str = ", ".join(str(id) for id in email_ids)
prompt = f"""You are processing {len(email_ids)} new email(s) with IDs: [{email_ids_str}].
For EACH email, follow this sequence:
1. Run: himalaya message read {email_ids[0]} --json (repeat for each ID)
2. Check SPF, DKIM, and DMARC authentication headers
3. Read ~/.hermes/email/rules.md for processing rules
4. If sender is trusted AND all auth checks pass → reply via 'himalaya smtp send'
5. If sender is unknown OR auth fails → forward to admin
6. Log each action
After processing ALL emails:
- Update ~/.hermes/email/seen_ids.json with the processed IDs
- The .trigger and .lock files will be cleaned up by the wrapper script
Process rules from ~/.hermes/email/rules.md determine reply vs forward."""
try:
# hermes chat -q:quiet 模式,非交互式,执行后退出
result = subprocess.run(
["hermes", "chat", "-q", prompt],
capture_output=True, text=True, timeout=300
)
log_event(f"LLM: Processing completed (exit {result.returncode})")
if result.returncode == 0:
update_seen_ids(email_ids)
except subprocess.TimeoutExpired:
log_event("LLM: TIMEOUT after 300s")
except Exception as e:
log_event(f"LLM: ERROR {e}")
# ═══ Step 7:清理 .trigger + .lock(规则 3:无论成功或失败)═══
finally:
TRIGGER_FILE.unlink(missing_ok=True)
LOCK_FILE.unlink(missing_ok=True)
log_event("CLEANUP: .trigger + .lock deleted")
if __name__ == "__main__":
main()
核心代码 ③:锁协议与陈旧锁检测详解
锁协议是双层状态机的安全网。以下是四种场景的完整时序分析:
yaml
# 锁协议四种场景时序分析(基于设计文档还原)
# ═══════════════════════════════════════════════════════════════
# 场景 A:正常流程(无并发)
# ═══════════════════════════════════════════════════════════════
03:45:01 Tier1: CHECK: Found 1 new email (ID: 45)
03:45:01 Tier1: .lock 不存在 → 继续
03:45:01 Tier1: .trigger 不存在 → 写 .trigger {ids: [45]}
03:45:02 Tier1: SPAWN: LLM session started → Tier1 退出
03:45:02 Tier2: 读 .trigger → 获取 [45]
03:45:02 Tier2: 写 .lock {email_id: 45, timestamp: "...", pid: 12345}
03:45:15 Tier2: himalaya message read 45 → 检查 SPF/DKIM/DMARC
03:45:30 Tier2: ACTION: Replied to ID 45
03:45:31 Tier2: CLEANUP: .trigger + .lock deleted → Tier2 退出
# ═══════════════════════════════════════════════════════════════
# 场景 B:LLM busy 时新邮件到达(规则 1:deferred)
# ═══════════════════════════════════════════════════════════════
03:46:01 Tier1: CHECK: Found 1 new email (ID: 46)
03:46:01 Tier1: .lock 存在(LLM 还在处理 45)
03:46:01 Tier1: DEFERRED: .lock exists, skipping (LLM busy) → 退出
# 邮件 46 等待下一轮检查
03:47:01 Tier1: CHECK: .lock 已删除(LLM 已完成)→ 处理 46
# ═══════════════════════════════════════════════════════════════
# 场景 C:.trigger 已存在时新邮件到达(批处理追加)
# ═══════════════════════════════════════════════════════════════
03:45:01 Tier1: 写 .trigger {ids: [45]}
03:45:02 Tier1: SPAWN LLM(但 LLM 还没来得及写 .lock)
03:45:03 Tier1(下一轮): CHECK: Found email 46
03:45:03 Tier1: .lock 不存在(LLM 还没写锁)
03:45:03 Tier1: .trigger 存在 → 追加 46 → .trigger {ids: [45, 46]}
03:45:03 Tier1: 不再 SPAWN(已有 LLM 在处理)→ 退出
# LLM 在一次会话中同时处理 45 和 46
# ═══════════════════════════════════════════════════════════════
# 场景 D:LLM 崩溃后 .lock 未释放(规则 4:陈旧锁检测)
# ═══════════════════════════════════════════════════════════════
03:45:02 Tier2: 写 .lock {timestamp: "03:45:02"}
03:45:10 Tier2: CRASH!(OOM / 网络断 / hermes 进程被杀)
# .lock 未删除,.trigger 未删除
03:46:01 Tier1: .lock 存在 → 检查陈旧 → age=58s < 10min → DEFERRED
03:47:01 Tier1: .lock 存在 → 检查陈旧 → age=118s < 10min → DEFERRED
...(每分钟检查一次,都 DEFERRED)...
03:55:02 Tier1: .lock 存在 → 检查陈旧 → age=600s = 10min → 删除 .lock
03:55:02 Tier1: STALE LOCK removed → 继续处理 → 写新 .trigger → SPAWN 新 LLM
陈旧锁阈值的选择
10 分钟是一个平衡点:太短(如 1 分钟)→ LLM 处理慢的正常邮件会被误判为崩溃;太长(如 1 小时)→ LLM 真的崩溃后系统卡死太久。10 分钟覆盖了绝大多数邮件处理场景(单封邮件 LLM 推理 + himalaya 读取 + SMTP 发送通常在 30 秒内完成),同时确保崩溃后恢复延迟可接受。
核心代码 ④:事件日志格式与真实示例
events.log 是双层状态机的可观测性核心。以下是归档中记录的真实事件日志格式:
less
# events.log 真实示例(来自 Discord 归档)
# 格式:[YYYY-MM-DD HH:MM:SS] EVENT_TYPE: Description
[2026-04-11 03:45:01] CHECK: Found 2 new emails (IDs: 45, 46)
[2026-04-11 03:45:01] TRIGGER: Written for IDs [45, 46]
[2026-04-11 03:45:02] SPAWN: LLM session started (PID 12345)
[2026-04-11 03:45:15] LOCK: Set for ID 45
[2026-04-11 03:45:30] ACTION: Replied to ID 45 (hello@mayur.ca)
[2026-04-11 03:45:45] ACTION: Forwarded ID 46 to (unknown sender)
[2026-04-11 03:45:46] CLEANUP: .trigger + .lock deleted
[2026-04-11 03:46:01] CHECK: No new emails
[2026-04-11 03:47:01] DEFERRED: .lock exists, skipping (LLM busy)
| 事件类型 | 触发层 | 含义 | 后续动作 |
|---|---|---|---|
| CHECK | Tier 1 | 邮件检查结果(发现新邮件 / 无新邮件) | 有新邮件 → 继续;无 → 退出 |
| TRIGGER | Tier 1 | 写入或追加 .trigger | → SPAWN |
| SPAWN | Tier 1 | 后台拉起 LLM 会话 | Tier 1 退出 |
| LOCK | Tier 2 | 写入 .lock 互斥锁 | → 开始处理邮件 |
| ACTION | Tier 2 | 对邮件执行的动作(回复 / 转发) | → 处理下一封或 CLEANUP |
| CLEANUP | Tier 2 | 删除 .trigger + .lock | Tier 2 退出 |
| DEFERRED | Tier 1 | .lock 存在,跳过本轮(LLM busy) | 等待下一轮 cron |
| STALE LOCK | Tier 1 | .lock 超过 10 分钟,强制删除 | → 继续正常流程 |
| ERROR | 任意 | 异常(himalaya 失败 / 文件损坏等) | 记录并退出 |
VPS 安全加固方案
bash
# ═══ 1. 状态文件权限加固 ═══
# seen_ids.json 和 events.log 可读,但仅限 owner
chmod 600 ~/.hermes/email/seen_ids.json
chmod 600 ~/.hermes/email/events.log
chmod 600 ~/.hermes/email/rules.md
# .trigger 和 .lock 包含邮件 ID 和 PID,也应限制权限
chmod 600 ~/.hermes/email/.trigger 2>/dev/null
chmod 600 ~/.hermes/email/.lock 2>/dev/null
# 脚本目录仅 owner 可执行
chmod 700 ~/.hermes/scripts/email/
# ═══ 2. himalaya 配置安全 ═══
# 配置文件包含 IMAP 凭据(通过 password.command 间接引用)
chmod 600 ~/.config/himalaya/config.toml
# 密码用 pass 管理(GPG 加密存储),不明文写入配置
pass insert spacemail # 交互式输入密码
# config.toml 中:password.command = "pass show spacemail"
# ═══ 3. 邮件认证验证(SPF/DKIM/DMARC)═══
# Tier 2 LLM 在回复前必须检查认证头
# 在 rules.md 中强制要求:
# - SPF: pass(发件人 IP 被授权)
# - DKIM: pass(签名有效)
# - DMARC: pass(对齐确认)
# - 三项全 pass + 发件人受信 → 回复
# - 任意失败 + 发件人未知 → 转发给管理员
# - DMARC 失败 → 不回复,仅记录(防止钓鱼回复)
# ═══ 4. 日志轮转(防止 events.log 无限增长)═══
# 已在 cron 配置中设置:每天凌晨轮转,保留 7 天
# 0 0 * * * cd ~/.hermes/email && mv events.log events.$(date +%Y%m%d).log ...
# ═══ 5. Hermes Gateway 安全 ═══
# 如果通过 Telegram/Discord 远程控制 Agent
# ~/.hermes/.env:
# TELEGRAM_ALLOWED_USERS=123456789
# DISCORD_ALLOWED_USERS=123456789012345678
# ═══ 6. 防止 LLM 执行危险命令 ═══
# config.yaml 中限制终端权限
# terminal.timeout: 120(单命令超时)
# 建议在 SOUL.md 中明确禁止 LLM 执行非邮件相关命令
备份容灾方案
perl
# ═══ 邮件管道状态备份脚本 ═══
# 保存为 ~/.hermes/scripts/backup_email_pipeline.sh
# crontab: 0 2 * * * ~/.hermes/scripts/backup_email_pipeline.sh
#!/bin/bash
BACKUP_DIR="$HOME/backups/email-pipeline"
DATE=$(date +%Y%m%d_%H%M%S)
EMAIL_DIR="$HOME/.hermes/email"
mkdir -p "$BACKUP_DIR"
# 1. 备份状态文件(seen_ids + rules + events)
tar czf "$BACKUP_DIR/email_state_$DATE.tar.gz" \
-C "$EMAIL_DIR" \
seen_ids.json events.log rules.md 2>/dev/null
# 2. 备份 himalaya 配置
cp ~/.config/himalaya/config.toml "$BACKUP_DIR/himalaya_config_$DATE.toml"
# 3. Hermes 全量备份(含 config、SOUL.md、scripts)
hermes backup
cp ~/.hermes/backups/hermes_backup.zip "$BACKUP_DIR/hermes_$DATE.zip"
# 4. 保留最近 14 天备份
find "$BACKUP_DIR" -name "email_state_*" -mtime +14 -delete
find "$BACKUP_DIR" -name "himalaya_*" -mtime +14 -delete
find "$BACKUP_DIR" -name "hermes_*" -mtime +14 -delete
echo "[$DATE] Email pipeline backup completed"
复刻检查清单
- VPS 已安装 Ubuntu 22.04+ 并完成 SSH 密钥加固
- Hermes Agent 已通过
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash安装 hermes doctor无报错- himalaya CLI 已安装(
himalaya --version验证) - himalaya config.toml 已配置 IMAP/SMTP 连接(
himalaya envelope list验证) ~/.hermes/email/目录已创建,seen_ids.json 初始化为[]- rules.md 已编写回复/转发规则(含 SPF/DKIM/DMARC 验证要求)
- check-email.py 已部署到
~/.hermes/scripts/email/并chmod +x - process-emails.py(Tier 2 包装脚本)已部署
- SOUL.md 已配置邮件处理 Agent 人格
hermes chat -q "test"一次性调用模式验证通过- 手动运行 check-email.py 测试:收件箱空时输出 "No new emails",无 SPAWN
- 手动运行 check-email.py 测试:有新邮件时输出 CHECK → TRIGGER → SPAWN 序列
- 手动创建 .lock 测试 deferred 行为(规则 1)
- 手动创建陈旧 .lock 测试强制删除行为(规则 4)
- cron 任务已配置:
*/1 * * * * /usr/bin/python3 ~/.hermes/scripts/email/check-email.py - cron.log 验证无 Python 异常(stderr 已重定向)
- events.log 日志轮转 cron 已配置(每天凌晨,保留 7 天)
- 状态文件权限已加固(
chmod 600) - himalaya 密码通过 pass/gopass 管理,非明文
- 备份脚本已配置并测试恢复流程
避坑汇总
坑 1:himalaya --json 输出格式版本差异
himalaya v1.x 和 v2(开发中)的 --json 输出结构不同。v1.x 直接输出列表,v2 可能嵌套在对象中(如 {"envelopes": [...]})。解决方案 :在 check-email.py 的 get_envelope_ids() 中做类型检查------如果是 dict 则取 envelopes 键,如果是 list 则直接用。部署前用 himalaya envelope list --json | python3 -m json.tool | head 确认实际格式。
坑 2:hermes chat -q 不退出导致 cron 堆积
如果 hermes chat -q 在某些情况下没有正确退出(如等待用户输入),会导致多个 LLM 进程堆积。解决方案 :(1) process-emails.py 中设置 timeout=300 防止无限挂起;(2) 用 start_new_session=True 确保子进程脱离父进程;(3) 在 cron.log 中监控 SPAWN 频率,如果每分钟都有 SPAWN 说明 LLM 没退出。
坑 3:.trigger 和 .lock 的竞态条件
Tier 1 检查 .trigger 存在后追加 ID,但此时 Tier 2 可能正好在读 .trigger。两个进程同时读写同一文件可能导致 JSON 损坏。解决方案 :(1) 写入时用临时文件 + 原子重命名(os.replace);(2) 或者用 flock 文件锁保护读写操作;(3) mayuronx 的原始设计文档未提及此问题,可能在低并发场景下不常见,但生产环境应加固。
坑 4:seen_ids.json 与 IMAP UID 不同步
himalaya 的邮件 ID 是 IMAP UID,如果邮箱做了 UID 重置(如 IMAP 服务器迁移、文件夹重建),seen_ids.json 中的旧 ID 会与新邮件 ID 冲突。解决方案:(1) 定期检查 events.log 中是否有 ID 回绕迹象;(2) 在 check-email.py 中加入 UID 有效性检查(如新 ID 小于 seen_ids 中的最大值时发出警告);(3) 必要时清空 seen_ids.json 重新开始。
坑 5:LLM 处理超时与陈旧锁的矛盾
如果 LLM 处理一批邮件超过 10 分钟(如邮件内容很长、需要多次工具调用),陈旧锁检测会误删 .lock,导致下一轮 cron 拉起新的 LLM 会话------两个 LLM 同时处理同一批邮件。解决方案 :(1) 调大 STALE_LOCK_MINUTES(如 20 或 30 分钟);(2) 在 process-emails.py 中处理前先检查 .trigger 的 ID 是否已在 seen_ids.json 中(幂等性检查);(3) 限制单次处理的邮件数量。
坑 6:Spacemail IMAP 兼容性未知
mayuronx 提到使用 "Spacemail IMAP",但 Spacemail 具体是什么邮件服务未经验证 (归档中未说明)。解决方案:Spacemail 可能是小众邮件服务或私有部署。复刻时建议先用主流服务(Gmail App Password / Fastmail / Proton Bridge)验证管道,再迁移到目标邮件服务。关键是确认目标服务支持 IMAP IDLE 或至少标准 IMAP LIST/FETCH 命令。
结尾:双层状态机的拓展方向
mayuronx 的双层管道设计是一个可泛化的模式------"哑层检测 + 智能层处理"不限于邮件:
RSS 订阅监控 Git 仓库变更通知 系统日志告警 社交媒体提及监控 API 健康检查 日历事件预处理 文件系统监控 数据库变更触发
想象一个场景:你把 .trigger/.lock 协议抽象成一个通用的"事件管道框架"------任何需要"检测变化 → 智能处理"的场景都能复用。哑层变成一个可插拔的检测器(邮件检测器、RSS 检测器、文件变更检测器),智能层变成一个统一的 hermes chat -q 调度器。检测器只负责"有没有变化",调度器负责"怎么处理"。这就是事件驱动的 Agent 操作系统的雏形。
或者,把双层管道和 BRAINSTACK 记忆内核(第 01 篇)结合------LLM 处理邮件时,自动把重要邮件内容写入 Graph-truth shelf 作为时序事实。下次有人问"上周那封关于项目截止日期的邮件说了什么",Agent 能从记忆图中直接召回,而不需要重新扫描收件箱。
下一篇预告
第 04 篇我们将拆解 Reverie 认知层------Hermes Agent 的"思考中间层"。它不是记忆,不是工具,而是一个让 Agent 在回复前"先想清楚"的认知框架。从 Reverie 的设计哲学到源码实现,完整逆向 Agent 如何在对话流中插入隐式推理步骤。
溯源引用
- mayuronx, Email Checker State Machine --- Discord 归档。Nous Discord #community-projects-showcase, thread 1492347479805530182, 2026-04-11. 双层邮件处理系统设计文档(Tier 1 哑层 + Tier 2 智能层 + .trigger/.lock 状态文件协议)。 github.com/teknium1/no...
- pimalaya, himalaya --- CLI 邮件客户端。Rust 编写, MIT OR Apache-2.0 许可证。支持 IMAP/SMTP/JMAP/Gmail REST API/Microsoft Graph/Maildir, --json 标志, TOML 配置。 github.com/pimalaya/hi...
- himalaya 官方配置模板 config.sample.toml。展示 IMAP/SMTP 账户配置、mailbox alias、password.command 等结构。 github.com/pimalaya/hi...
- Nous Research, Hermes Agent 官方文档。CLI 命令参考、hermes chat -q 一次性查询模式、Profile 隔离、Cron 调度、SOUL.md 系统提示词。 hermes-agent.nousresearch.com/docs/
- Nous Research, Hermes Agent 安装脚本。curl -fsSL hermes-agent.nousresearch.com/install.sh | bash。 hermes-agent.nousresearch.com/install.sh
- 本系列第 01 篇:BRAINSTACK 三层记忆内核拆解。五层架构图样式参考、Hermes Agent 关键架构事实(MEMORY.md/USER.md/SOUL.md/技能/Profile/Gateway/Cron/子Agent)。 Hermes Agent 深度拆解 #01 · BRAINSTACK
Hermes Agent 深度拆解连载 · 第 03 篇 · 双层邮件管道状态机
溯源驱动 · 源码佐证 · 1:1 可复刻 · 禁止虚构
延伸阅读与交流
本文涉及的Hermes Agent自进化智能体技术体系,目前已有系统化的深度学习资源可供参考。中国通信工业协会通信和信息技术创新人才培养工程项目办公室将于近期组织相关技术专题分享,围绕本文讨论的AI原生架构、智能体工作流、自进化数据层等方向展开系统讲解。
专题信息
- 主题:AI原生Hermes自进化智能体系统
- 时间:2026年8月22-23日
- 形式:线上直播
- 内容方向:AI原生架构 · Hermes智能体拆解 · 全栈扩展 · 智能自动化 · 产品级实战 · Context Engine · 自进化数据层
分享嘉宾
王老师(Gavin),Agentic AI企业联合创始人兼CTO,十余年硅谷AI系统工程经验。长期深耕NLP、强化学习、可控AI与智能体系统架构,提出"语言即控制(Language as Control)"原创范式,在RLHF、PPO、DPO、GRPO等方向有系统化工程实践,推动智能体技术在社交媒体、医疗、金融、法律、教育等专业场景落地。联系邮箱:hiheartfirst@gmail.com
技术交流
- 联系人:Sam
- Hermes Agent技术文档:hermes-agent.nousresearch.com/docs/

016 | 连接的代价
前几篇我们看清了进程树、共享内存、缓冲区缓存和每后端工作内存。本篇把镜头对准"连接"本身------一条 Postgres 连接在操作系统层面到底由什么构成、为什么把
max_connections调大永远不是修连接问题的答案、连接池器为什么不是可选项。最后用一节"常见错误"把整章六个反复出现的坑集中在一张清单里收束全文。
连接的代价
在 Postgres 里,一条连接不是一个 TCP socket。一条连接是一个后端进程,带着操作系统层面一切随之而来的重量。
这一句话值得反复咀嚼。很多人把"数据库连接"理解成"一条网络管道"------和 HTTP 连接差不多,便宜、可复用、随建随拆。在 Postgres 的世界里这是危险的误解。 网络管道只是表象,真正在跑你查询的是一个完整的、由 fork() 衍生出来的操作系统进程,有自己的地址空间、页表、文件描述符表、栈和信号掩码。5.2 节我们走过了 fork 的过程。到了一千个后端的规模,这份重量会复利式叠加------没人会在生产 Postgres 和应用之间什么都不放,这不是风格偏好,是被进程模型逼迫出来的工程必然。
一条连接由什么构成
当一个客户端连上来,postmaster 会按顺序做这几步:
- 接受 TCP 连接------三次握手完成,内核为这条 socket 分配缓冲区;
- 读启动包------里面装着数据库名、用户名、应用名等连接参数;
- 做认证 ------走
pg_hba.conf规则、密码挑战、SCRAM 交换; fork()一个子进程------这是真正"贵"的那一步,内核复制 postmaster 的进程描述符、页表等结构(写时复制);- 子进程挂接到共享内存,打开它的 catalog cache,向客户端发送
ReadyForQuery------告诉客户端"我准备好了,请发查询"。
这套序列在一台健康服务器上只需要个位数毫秒,快得几乎察觉不到。真正伤人的,不是建立连接的时间,而是这条连接存活期间一直持有、无法归还的那一切。
一条活着的后端,在它还没接到任何查询之前,就已经预留了下面这一摞资源:
- 一个操作系统进程及其内核数据结构------文件描述符表、信号掩码、页表,全套;
- 大约 5 到 10 MB 的常驻内存 ------这是在它一行 SQL 都没跑之前。其中相当一部分通过写时复制与 postmaster 共享(比如 Postgres 的可执行代码段、共享目录的只读页),所以每后端的独占私有 RSS (去重 private RSS)更接近几 MB 。注意,
ps这种工具会把共享页每个进程都算一次,所以你看到的标题数字会比"真实独占"偏大; - procarray 里的一个 proc 槽 ------这是
max_connections个槽之一,外加几个为超级用户和复制专门预留的。多版本并发控制 的快照计算每次都要扫这个数组; - catalog cache 条目 ------随着后端看过越来越多的表(系统目录也算),这些缓存条目会惰性累积,跑几小时后可能堆到几十 MB;
- 它最近碰过的每个 relation 的文件描述符------每张表、每个索引都可能占一个 fd,数量随会话活跃度增长;
- 上一节讲过的
work_mem等工作内存,再叠在这一摞之上。
把这一摞乘以连接数,你就明白为什么"再加几百个空闲连接"不是免费的午餐。
"贵"长什么样
我们把前面的数字放大到一千条空闲连接的规模,看看账单长什么样。一千条 Postgres 空闲连接,大约对应:
- 1,000 个进程表条目------内核进程表要为它们各留一行;
- 5 到 10 GB 什么活都没干的常驻内存------这是纯闲置、纯持有;
- 1,000 个在内核运行队列里的条目------即便大多数在睡觉;
- 内核在调度器决定扫一眼空闲后端时,就要付出的上下文切换开销------每次调度器轮到这些进程,哪怕只是"确认它们还在睡",都是一次切换成本。
我亲眼看过一台有 4,000 个空闲连接的 Postgres 服务器,在还没跑任何查询之前,40% 的 CPU 都花在上下文切换上 。应用以为自己"还有很多余量",因为它预热了连接池,每个线程都握着一条活连接。那个池子,是一份数据库默默付了几周的内存账单------直到某个深夜内存终于耗尽,OOM killer 选了一个目标,一切才浮出水面。
什么是上下文切换?简单说:CPU 在不同进程之间转手去做活儿时,要把当前进程的寄存器、页表基址等状态存起来,再把下一个进程的状态加载回来。每次切换都有固定成本(保存/恢复寄存器、TLB 可能被刷掉、CPU 缓存局部性被破坏)。一台机器上几千个进程,光调度器在这些"睡觉的进程"之间来回确认状态,CPU 时间就被啃掉一大块------这就是那 40% 的由来。
问题不在于一条连接的绝对成本 。一条连接的 5-10 MB 在 64 GB 服务器上确实不算什么。问题在于客户端连接数(常常上千)与 Postgres 后端应该并发干的活(大多数工作负载下只有几十)之间的鸿沟。你想让 1000 个客户端连进来,但数据库真正能高效服务的活跃后端就那么几十个;剩下 900 多个空闲后端,是纯成本没有产出。
CPU 数量经验法则
关于活跃 后端数量,有一条很有用的一阶法则:大约等于你的 CPU 数,乘以 2 到 3 这种为 I/O 等待留出的因子。 一台 16 核服务器能舒服地跑 30 到 50 个真正在干活的后端。超过这个数,后端就开始为 CPU 排队,而不是在做有用的数据库活------再加更多只会让吞吐更差,不会更好,因为它们相互抢 CPU 的时间,比串行跑还慢。
为什么是 2 到 3 这个因子而不是 1?因为数据库查询大部分时间不在 CPU 上烧,而在等 I/O (等磁盘、等网络、等锁)。在一个后端等 I/O 的时候,CPU 可以切去服务另一个后端。所以活跃后端数可以略多于 CPU 核数,但不能无限多------因子太大,上下文切换的开销就会吃掉这部分红利。
注意这条法则针对的是活跃后端 ------空闲后端不占 CPU。但空闲后端仍然 吃 RAM、文件描述符和上下文切换预算。最便宜的空闲后端,是那个根本不存在的空闲后端。 这一条比任何调优技巧都重要:不在场的资源,零成本;在场但闲置的资源,正成本。
错配与解药
这里终于要说出本篇的核心诊断:应用的并发模型和 Postgres 的并发模型对不上。
应用按"客户端"来思考并发。 一台 200 个工作线程的 Web 服务器,每个线程握一条数据库连接,就想要 200 条连接。三台 Web 服务器要 600 条。五台要 1,000 条。微服务架构、容器化部署、自动伸缩------每多一个实例就多几十上百条连接。算术很快就难看了,而这正是应用思考并发的自然方式:一个请求一个线程,一个线程一条连接。
Postgres 按"后端"来思考并发。 它想要的是几十个真正在干数据库活的活跃后端,没法在"大多数时间空闲的后端"数量上线性扩展------因为每个后端都是个完整 OS 进程,有固定的内存和调度成本。这两种世界观对不上。
标准答案是:在应用和 Postgres 之间放一个连接池器(连接 pooler)。
池器做两件事:第一,它廉价地接受成千上万的客户端连接------它每条连接的数据结构很小(几 KB 而非几 MB),而且没有 fork 要做;第二,它在背后维护一个小池子的真实 Postgres 连接(比如 50 条),把客户端流量路由上去。
举个具体场景:客户端发一条查询,池器从它的小池里抓一个空闲的 Postgres 后端,把这条查询送过去,拿到结果返回给客户端,跑完立刻把后端还回池子 。下一个客户端查询过来时,复用同一个后端。这样,1000 个客户端、50 条数据库连接,就能被伺候得很好------因为在任意一刻,真正同时在跑数据库活的客户端就那么多。Postgres 世界里事实上的池器是 pgbouncer :小、快、用 C 写,所有严肃 Postgres 部署的运维形态里都有它。PgCat 是个更新的、用 Rust 写的替代品,支持更现代的多 shard 路由特性。一些应用栈有客户端侧 的池,能帮上忙------它避免了一个应用实例开太多连接,但解决不了跨多个 app 实例的乘法问题 :5 台 app 实例各开 50 条连接,到 Postgres 那端还是 250 条。真正能解决"几千客户端 vs 几十后端"错配的,只有部署在 Postgres 前面的服务端池器。
答案就藏在进程模型里。Postgres 付出的是真实的 per-backend 成本。 一个为了"大量余量"而调大的池,把这份成本变成了一次服务器宕机。这不是配置不慎,是模型错配的必然后果。
运维法则的样子
把这一节压成三个要内化的数字:
- 一个工作中的后端,基线是 5 到 10 MB 常驻内存 (其中相当一部分通过写时复制与 postmaster 共享,独占私有 RSS 更接近几 MB),之上再叠查询内存(
work_mem等); - 活跃后端应该舒舒服服地落在你的 CPU 数乘一个小因子之下;
- 客户端连接 可以上千;服务器后端应该在几十到低百级。
这三条数字之间的差异,就是错配存在的空间。这段错配,就是池器要修的东西。 假装这段错配不存在,正是"半夜被 page 的 P3 事故"的配方------你的应用以为余量充足,你的数据库在内存和上下文切换的边缘摇摇欲坠。
警告 :"Idle in 事务"是 Postgres 里最危险的后端状态 。它意味着一条连接开启了一个事务、停下了活儿、却仍然持有一个快照。那些快照能看见的每一个旧版本行,都被锁住、不让 VACUUM 碰 ------表会因此持续膨胀;与此同时这个后端还占着一个 proc 槽和若干锁。在生产里务必给
idle_in_transaction_session_timeout设一个合理值(比如几分钟)。默认 0 意味着"永远"------而永远是很长的一段时间,长到足够让一个被遗忘的 psql 窗口把一张表撑大好几个 GB。
给max_connections定尺寸的正确方式是"能多低就多低 "。处理客户端负载的正确方式是在前面放一个池器。把max_connections当成修连接问题的旋钮,是这篇里最常见也最致命的误判。
常见错误
本篇结束前,把生产里反复出现的六个坑集中列出来。每一个都对应前面某一节的真实机制,认得它们能省下大量深夜时间。这些错误之所以反复出现,是因为它们看起来都"像是合理优化"------直到你理解了背后的进程模型和内存账单。
1. 把 shared_buffers 设到 RAM 的 50% 以为有帮助。
OS 页缓存会把同样的页再缓存一遍。超过 RAM 的 25% 到 40%,就是在两个缓存同一份数据的场地之间劈开内存,还让一部分页在两边都存一份。正确法则是"按你的热点工作集定尺寸"------在大多数服务器上,这个值落在 25% 附近。如果你的查询大量是顺序扫大表,可以更低让 OS 多缓存;如果是大量点查热点行,可以更高减少对 OS 缓存的依赖。
2. 全局调大 work_mem 然后 OOM 掉服务器。
work_mem 是 per-operation、per-backend 的------这个"乘法性"是它最坑人的特性。乘以 max_connections、再乘每查询的典型操作数 ,你就能看到最坏上限:400 连接 × 5 操作 × 64 MB = 128 GB,装在 32 GB 服务器上。在 postgresql.conf 里保守地设(大多数服务器 8 到 16 MB),然后在真正需要的会话和角色里 SET work_mem 调高 。用 pg_stat_statements.temp_blks_written 找出真正在溢写的查询,按查询调。
3. 用一个很小的 effective_cache_size 对规划器撒谎。
它不是分配,是提示 ------但这条提示直接决定规划器敢不敢用索引扫描。在 64 GB 服务器上设成 4 GB (服务器默认值),规划器会因为"假设随机读会打磁盘"而避开索引扫描,改走全表顺序扫 ------这在数据量大的表上可能慢上几个数量级。在专用数据库服务器上设成系统 RAM 的 50 到 75%,让规划器对着现实给查询定价。一个简单的设置,常常是"为什么这个查询在测试环境快、生产慢"的答案。
4. 把 max_connections 当成"修连接问题"的那个旋钮。
调大它,只是让症状暂时消失、让根上的问题更严重。更多后端 = 更多内存、更多上下文切换、更多 work_mem 乘法、对 procarray 更多压力。 当客户端因为"连不上"而抱怨,正确反应不是抬 max_connections,而是问"为什么这么多连接"------通常答案是缺一个池器。修复办法是在 Postgres 前面放一个 pgbouncer。
5. 在一个有多 GB shared_buffers 的服务器上忽略 huge_pages。
64 GB 缓冲池配 4 KB 页,是每个后端一千六百万条页表项。200 个后端下,光内核页表就是好几个 GB ------这些内存不算在 shared_buffers 里,是纯系统开销,而且每次内存访问都要走长长一串页表链。把 huge_pages 设成 on、把 vm.nr_hugepages 设到 Postgres 日志告诉你的那个值------这是系统里最便宜的性能红利之一:开销骤降到 1/512,TLB 命中率大幅提升。开启它几乎没有任何 downside,只有忘记开的人会慢性失血。
6. 把 idle_in_transaction_session_timeout 留在默认的 0。
一条开了事务却走开的连接,持有一个快照 ,从而阻止 VACUUM 推进------表里的死元组无法被回收,磁盘占用持续涨;它还占着一个后端槽和 procarray 里的一行,影响快照计算性能。在繁忙数据库上,一个被遗忘的 psql 窗口能让表膨胀好几个 GB ,逼出一次紧急 VACUUM 大作战。生产里把超时设成几分钟(5-10 分钟是常见值)------需要更长事务的应用可以局部覆盖它(SET LOCAL 或角色级配置)。这个设置是"零成本买平安"的典型,没有任何理由把它留成 0。
小结
让我们把整章压成几条可以带走的结论。这篇的每一个结论,都是后面所有章节的地基------索引、查询规划、VACUUM 调优、复制、高可用,每一章都会回头引用这里的某个机制。
-
Postgres 是一棵进程树。 一个 postmaster、一组固定的后台工作者(Autovacuum launcher、walwriter、bgwriter、checkpointer、逻辑复制 launcher),外加每个连接一个后端。本篇每一个概念,都坐落在这些进程中的某一个里。这是 1996 年以来的设计,没变过,也不会变------它的简单正是其可靠性的来源。
-
共享内存只在启动时分配一次。 缓冲区缓存、WAL 缓冲区、锁表、procarray、复制槽、共享统计------全都住在这里。你可以给它定尺寸,但不重启就没法让它增长。这一约束塑造了本节里每一个可调参数:都是固定预算里的固定切片。
-
缓冲区缓存用时钟扫描,不是 LRU。 页有使用计数,访问时往上走(上限 5)。缓存指针走遍缓存,削减计数,直到找到一个计数归零且未被 pin 的牺牲者。bgwriter 在后台把脏缓冲清干净,让前台后端几乎不必亲自写。这套机制没有"每次访问更新链表"的开销,因此能在高并发下扩展。
-
OS 页缓存会双重缓冲你的数据。 同一份 8 KB 同时住在
shared_buffers和内核缓存里,因为 Postgres 用普通read()不用 direct I/O。这就是"把shared_buffers设到 RAM 的 25%"这条民间智慧为什么对大多数服务器其实是对的根本原因------给 OS 缓存留出它那半边位置。 -
effective_cache_size是给规划器的提示,不是分配。 设太低,规划器在缓存充裕的服务器上也会避开索引扫描------这是最常见也最容易被忽略的误配置之一。 -
work_mem是 per-operation、per-backend 的。 它本质是个乘数,不是单值。乘以max_connections和每查询操作数,才能得到最坏上限。按 per-session 或 per-role 调,不要全局调。 把它当单值调,是 OOM 的标准配方。 -
连接很贵。 每一条都是个 OS 进程,5 到 10 MB 的内存底(其中相当一部分通过写时复制共享,独占私有 RSS 更接近几 MB),外加惰性累积的 catalog cache 和工作内存。客户端连接(上千)与 Postgres 后端(几十)之间的错配,正是 pgbouncer 存在的意义。 在任何真实工作负载上,连接池器都不是可选项------它是进程模型的必然产物。
第 5 章到这里结束了。从进程树、共享内存、缓冲区缓存,到每后端内存和连接的代价------这些机制共同决定了 Postgres 在生产环境里的内存形状与性能边界。读懂它,你才看得懂后面索引、查询规划、VACUUM 调优、高可用等所有话题"为什么要这么做"。内存住在哪里,决定了性能死在哪里。
下一篇 → 017 - 索引本质与 B 树内部结构(017-索引本质与 B 树内部结构.md)
常见问题答疑(学员答疑)
Q1:为什么 Postgres 的连接比 MySQL 的连接贵那么多?
因为两者的并发模型根本不同。Postgres 每条连接 fork 一个完整的 OS 进程------有自己的地址空间、页表、文件描述符、5-10 MB 常驻内存。MySQL (InnoDB)用线程,一条连接就是一个线程,开销小得多。Postgres 这个设计从1996年沿用至今,换来的是崩溃隔离:一个后端段错误自己死掉,数据库还能活;线程架构里一个线程崩溃可能拖垮整个进程。代价就是连接很贵------1000条空闲连接要吃5-10GB 内存,加上内核调度器在这些"睡觉的进程"之间来回确认状态的上下文切换开销。一台有4000个空闲连接的服务器,还没跑任何查询就可能把40%的 CPU 花在上下文切换上。这就是为什么"在 Postgres 前面放 pgbouncer"不是风格偏好,是进程模型逼迫出来的工程必然。
Q2:pgbouncer 是怎么解决连接问题的?它自己不会成为瓶颈吗?
pgbouncer 做两件事:第一,廉价地接受成千上万的客户端连接------它每条连接的数据结构只有几 KB,没有 fork 要做;第二,在背后维护一个小池子的真实 Postgres 连接(比如50条),把客户端流量路由上去。客户端发查询时,pgbouncer 从池里抓一个空闲后端,送查询过去,拿结果返回,跑完立刻把后端还回池子。1000个客户端、50条数据库连接就能伺候得很好------因为任意一刻真正同时在跑数据库活的客户端就那么多。pgbouncer 本身用 C 写、极轻量,单实例能轻松处理数万连接。需要注意的是它的事务模式(transaction pooling)不支持会话级特性(如临时表、SET 参数跨事务保留),应用需要做相应适配。
Q3:"Idle in transaction"为什么那么危险?一条连着不干活也有问题?
一条开了事务却走开的连接,持有一个 多版本并发控制 快照。这个快照能看到的每一个旧版本行都被锁住,不让 VACUUM 碰------表会持续膨胀。同时它还占着一个后端槽和 procarray 里的一行,影响所有其他事务的快照计算性能。更阴险的是:它把全库的可见性映射钉死在旧状态------在这条事务关闭之前,VACUUM 没法把新页标成 all-visible,全库的 Index-Only Scan 都会退化成多读堆页。一个被遗忘的 psql 窗口能让表膨胀好几个 GB,逼出一次紧急 VACUUM 大作战。生产里务必给idle_in_transaction_session_timeout设一个合理值(5-10分钟),默认0意味着"永远"------而永远长到足够出事。
第二篇:从RAG到Reasoning------Honcho如何重新定义Agent记忆
"我的RAG系统为什么总是不够聪明?"
这个问题困扰着几乎所有构建过AI Agent的开发者。你以为问题在嵌入模型不够好、分块策略不够精、检索算法不够优。但真正的问题在于:记忆不等于存储。
记忆是一种推理
这是Honcho最核心的设计哲学。传统记忆方案分两类:
类型一:静态检索(RAG)
- 检索语义相似的已存储内容
- 检索"说了什么",但遗漏"意味着什么"
- 矛盾信息处理笨拙,无法推断
类型二:预定义结构化存储
- 用数据库或知识图谱存"事实"
- 由系统替你决定什么重要
- 灵活性差,遗漏可能性大
Honcho采取了第三条路:通过穷尽推理提取所有隐含信息,让它在你需要时就在那里。
形式逻辑:Honcho的推理引擎
Honcho的记忆系统由专门训练的自定义模型驱动,执行形式逻辑推理。系统的工作流是:
提取显式陈述 → 从中得出确定性结论 → 识别多消息间模式 → 推断最简解释
来看一个推理输出的实际数据结构:
json
{
"explicit": [
{"content": "用户正在为买房攒钱"},
{"content": "用户讨厌订阅制消费"}
],
"deductive": [
{
"premises": ["用户正在为买房攒钱", "用户讨厌订阅制消费"],
"conclusion": "用户是预算敏感型消费者,关注长期财务目标"
}
]
}
注意deductive部分------用户从来没说过"我是预算敏感型消费者",这是Honcho从两个显式前提中逻辑推导出了这个结论。这就是推理的威力。
三个推理层次
Honcho的推理并非单一维度,而是分层的:
- 显式推理(Explicit):直接从消息中提取用户明确陈述的内容
- 演绎推理(Deductive):从显式前提出发,得出必然成立的结论
- 归纳推理(Inductive):跨多条消息识别模式(需要至少两个数据点)
- 溯因推理(Abductive):推断观察到的行为的最简解释
例如,如果用户频繁提到工作截止日期但很少提到爱好,Honcho可能归纳出"该用户时间紧张或以事业为重"。没有一条消息直接说了这话,但模式是清晰的。
为什么用自定义模型而不是GPT-4?
现成的大模型可以执行形式逻辑推理,但不是为此优化的。Honcho使用自定义模型,因为:
- 逻辑严谨性:遵循形式推理规则而非生成"听起来合理"的文本
- 结构化输出:一致JSON Schema(前提+结论),可编程组合
- 效率:更小更快的模型,专门为这个任务调优
这意味着Honcho推理比通用大模型更可靠、成本更低。
Q&A
Q1:形式逻辑听起来很学术,我需要理解逻辑学才能用Honcho吗?
A:完全不需要。形式逻辑是Honcho内部的推理引擎,作为开发者你只需要三件事:写入消息、查询洞察、获取上下文。所有推理在后台自动完成,你通过简单的SDK调用获取结果。就像你不需要理解数据库的B+树索引也能用SQL一样。
Q2:Honcho的推理是实时同步的还是异步的?
A:异步的,这是关键设计决策。消息写入时立即存储并加入后台队列,写入操作永不阻塞。后台Worker提取结论、生成摘要、更新表示。这意味着写入极快,但推理结果可能需要几秒到几分钟才出现。Honcho提供queue_status()让你追踪推理进度。
Q3:如果两条消息互相矛盾怎么办?比如用户先说喜欢某个东西后来说讨厌?
A:这正是推理优于存储的核心场景。传统RAG会把两条都检索出来让LLM困惑。Honcho的Dreaming机制会识别矛盾,在新信息出现时删除过时结论、创建新结论反映当前状态。这就像人类记忆------你会更新你对一个人的认知,而不是同时记住两个矛盾版本。
大模型日报 - 2026年8月7日
-
字节跳动拟训练超5万亿参数大模型,参数规模超越Kimi K3 据《晚点 LatePost》报道,字节跳动正在讨论训练一个参数规模超5万亿的模型,超过阿里Qwen 3.8-Max(2.4万亿参数)和月之暗面K3(2.8万亿参数),成为目前国内已知参数规模最大的模型。新模型将由Seed Foundation负责人项亮主导,与大语言模型预训练数据负责人沈科合作,Seed正在重新梳理组织、划分职责、分配资源。该计划仍处早期阶段,模型最终不一定会发布。
-
谷歌DeepMind重大人事变动:哈萨比斯卸任CEO,市值一日蒸发1800亿美元 谷歌一日内抛出两则重磅人事变动:2024年诺贝尔化学奖得主、DeepMind创始人兼CEO德米斯·哈萨比斯正式卸任日常管理职务,转任DeepMind董事长兼Alphabet首席科学家,将更多精力投入长期AI研究。CTO科拉伊·卡武库奥卢升任高级副总裁,直接向CEO皮查伊汇报。在谷歌干了近27年的核心科学家杰夫·迪恩也涉及调整。受此影响,谷歌市值一日蒸发约1800亿美元。
-
马斯克Grok 4.6今日发布,参数规模1.5万亿 马斯克此前在社交平台X上宣布,Grok 4.6将于8月7日发布,参数规模1.5万亿。几周后还将推出Grok 4.7,参数规模2.1万亿。此前Grok 4在LM Arena的ELO排行榜上以1495分排名全球前列,与Claude、Gemini等顶尖模型同台竞技。与此同时,马斯克表示特斯拉Optimus人形机器人的算力需求将占Terafab AI计算产出的约25%,剩余约75%供给航天器AI项目。
-
远景科技集团建成全球最强AI算力超级单体,乌兰察布星河基地投产 8月6日,远景科技集团宣布在乌兰察布建成AI算力超级单体,标志着"远景乌兰察布星河基地"正式投产。该超级单体采用超高比例绿电直连,以12万平方米的建筑体量(约20个标准足球场)、百万卡并行能力、百万P算力规模,成为全球Token产出能力最强的单体AI数据中心,刷新了AI基础设施的密度纪录。
-
AI战火烧到办公室:字节飞书并入豆包,阿里推出千问办公 字节和阿里两大互联网大厂先后宣布企业架构调整:字节将做了十余年的飞书产品团队整体并入豆包,飞书负责人谢欣改为向豆包负责人赵祺汇报,飞书的GTM(市场销售)体系直接并入火山引擎。阿里则将原本各自为战的QoderWork(编程)、MuleRun(任务调度)和悟空(桌面交互)三条Agent线整合为一款新产品"千问办公",管理权交给了6月刚接棒钉钉的92年"少帅"陈宇森。AI办公赛道进入巨头正面对决阶段。
大模型论文日报 - 2026-08-07
1. VisualPatchWorld (VPW):教AI"读懂"物理世界的程序归纳框架
论文编号: arXiv:2607.25236 研究机构: 香港浸会大学 研究方向: 具身智能 / 世界模型 / 机器人学习
摘要
研究团队提出VisualPatchWorld(VPW)框架,解决"如何让机器自动学会世界运转方式并做出行动决策"这一核心问题。VPW走出第三条路:让机器自动从观察数据中归纳出可执行的Python程序代码,将这段代码作为世界模型。它既像物理引擎一样清晰可读、可编辑,又像神经网络一样从数据中自动生成。核心采用"两级程序归纳":第一级通过主动探测选择物理动力学结构(如判断有无惯性、接触是否触发运动),第二级在选定结构上拟合具体参数,针对多步连续预测的累积误差进行优化。
结论
在LeWM基准测试的四个任务上,VPW平均成功率达69%,比此前最好的代码型基线(POMDP-Coder 45.5%)高出23.5个百分点。推箱子任务中混合评分成功率达88%-96%,接近使用真实物理引擎的96%天花板。VPW在机械臂任务上的预测误差从其他方法的0.86降至0.04,成功率从6%-30%提升至72%。
对旧假设的挑战
- 挑战"世界模型必须在神经网络黑盒和手工物理引擎之间二选一"的假设:VPW证明自动归纳的代码世界模型可以兼具数据驱动能力和可读可编辑性,在两者之间架起桥梁。
- 挑战"选对参数就能学好世界模型"的假设:研究证明,先确定物理结构类型再拟合参数至关重要。把有关节约束的机械臂当成自由质点建模,再怎么优化参数效果也很差。
- 挑战"VLM可以替代专用视觉管线"的假设:VLM的坐标误差高达236像素,是图像工具路径的130倍以上,语义理解与精确空间定量描述是两码事。
2. PerceptionBench:为什么顶尖AI还看不懂图片?
论文编号: arXiv:2607.24957 研究机构: 月之暗面(Moonshot AI) 研究方向: 多模态大模型 / 视觉感知能力评测
摘要
月之暗面研究团队设计了PerceptionBench------一套专门测试AI视觉感知能力的基准测试,不考知识和推理,只考"你看到了什么"。研究团队从42个已有视觉测试中收集超9000个失败案例,归纳出22种错误类型,其中10种为视觉感知能力。最终构建3000道题,每道只考一种能力,覆盖视觉定位、属性识别、计数、关系理解、深度感知、OCR、视觉比较、细粒度识别、上下文整合和感知幻觉。测试了GPT-5.6-Sol、Kimi K3、Claude-Fable-5、Gemini-3.1-Pro等16款顶尖模型。
结论
没有一款AI得分超过60分(满分100)。 表现最好的GPT-5.6-Sol仅得59.7分,Kimi K3得58.5分。感知性幻觉是所有能力中平均得分最低的(36.7%正确率)。更关键的是,Kimi K3"至少答对一次"得分73.9%,但"四次全对"仅42.7%,说明AI的视觉感知很多是"碰运气"而非真正掌握。
对旧假设的挑战
- 挑战"AI已在视觉任务上远超人类"的假设:在只考"看图"的测试中,最顶尖的AI仍有超40%的题答错。AI在复杂推理上的强能力掩盖了基础感知的系统性弱点。
- 挑战"总分高=各项能力全面"的假设:GPT-5.6-Sol总分第一,但感知幻觉得分仅26.9%;总分相近的模型能力画像截然不同。
- 挑战"模型答题稳定=能力可靠"的假设:宏观统计上成绩稳定,但每道题的表现飘忽不定,"蒙对"和"掌握"之间存在巨大鸿沟。这直接质疑依赖AI进行图像分析的应用场景(医疗影像、自动驾驶)的安全边界。
3. RARG:当AI搜索学会"先看哪里再翻书"
论文编号: arXiv:2607.24223 研究机构: 腾讯 / 中国科学院信息工程研究所 研究方向: 检索增强生成(RAG)/ AI搜索 / 智能体搜索
摘要
研究团队提出"相关性感知RipGrep搜索智能体"(RARG),核心思路是把"哪些文件更值得看"的判断直接融入到关键词搜索的执行过程中。RARG分三个层次:文档级相关性注入(按相关性排序文件路径传给rg搜索)、入口点初始化(额外提供10个最相关段落作为"开门砖")、匹配级相关性注入(对500条匹配行做重排序,保留最优质的30-60条)。研究还通过自动插入-j1参数强制rg单线程顺序扫描,使相关性真正控制搜索顺序。
结论
在10万文档的BrowseComp-Plus问答数据集上,RARG++使用GPT-5.4达到91%准确率,比RISE高9个百分点,同时工具调用次数仅为DCI的四分之一(23.9次 vs 99.1次),成本从0.5美元/题降至0.1美元/题。扩展至100万文档时,RARG++仍保持约10个百分点的优势。在BRIGHT检索任务上,RARG+的nDCG@10达53.36,超过NeMo智能体。
对旧假设的挑战
- 挑战"稠密检索和关键词搜索是竞争对立的两种范式"的假设:RARG证明两者恰好可以互补------用嵌入式检索提供方向感,用关键词搜索保持精准度。
- 挑战"相关性只需要在检索前做一次筛选即可"的假设:研究证明相关性应贯穿搜索执行全过程,不仅决定"看哪些文件",还要决定"按什么顺序看"和"哪些行优先展示"。
- 挑战"聚焦越精确效果越好"的通用假设:匹配级重排序在"快速找答案"的问答任务上有效,但在"找全所有相关文档"的检索任务上反而限制了覆盖广度,不同任务需要不同层次的RARG。
4. OpenAI Astra:AI以200美元攻克一道数学世纪难题
发布时间: 2026年8月1日 研究机构: OpenAI 研究方向: AI数学推理 / 形式化定理证明 / 多智能体协同
摘要
OpenAI下一代模型Astra的内部版本在数学和理论计算机科学领域取得十项重大突破,攻克了高维球堆积、编码理论、群论、量子复杂性、格密码学和极值组合学等领域长期悬而未决的难题(每道题学术积压均超十年)。总Token成本仅约2000美元,平均每题200美元。全部成果通过Lean形式化验证,GitHub仓库中"sorry"计数为零。Astra采用多智能体协同架构,由协调者拆解问题、分配子目标给不同专长的子智能体并行执行,再由验证智能体筛选合并。
结论
AI完成了从"解已知答案"到"产出人类也未知的原创证明"的跨越。从GPT-5的"文献检索"到GPT-5.2的"原创三题",再到5月"推翻80年猜想",最后到Astra"2000美元横扫十题",八个月完成从"图书馆管理员"到"独立研究者"的跃迁。Google DeepMind AlphaProof Nexus单题成本最低仅7.5美元,成本下降趋势持续。国际数学联盟已背书《莱顿人工智能与数学宣言》,超3000人签署。
对旧假设的挑战
- 挑战"前沿数学研究只有天才数学家才能做"的假设:当边际解决成本降到200美元/题,"做前沿数学"不再是人类智力专属领地,科研的成本结构正在被重写。
- 挑战"AI在数学中只是算得快的计算器"的假设:AI展现出跨域联想能力------将代数数论的Golod-Shafarevich理论应用于离散几何,被数学家评价为"具备原创、精妙的独立思想"。AI从"助手"变为"参与者"。
- 挑战"同行评议足以验证AI数学成果"的假设:当AI能以每天几十个问题的速度产生候选解,人类评议体系根本消化不了。Lean形式化验证从增值功能变为基础设施,但引发"谁来验证验证AI的AI"的递归困境。
- 挑战"密码学安全的传统假设":Anthropic的Claude以10万美元成本发现NIST后量子签名算法HAWK-256的缺陷,导致该方案撤回。纯AI推理驱动的密码分析不需要量子计算机,低成本密码分析平民化的威胁正在逼近。
5. POLIA:让多模态模型从"答对"走向"看对"
论文来源: ICML 2026 研究机构: 云蝶科技 / 华南理工大学 研究方向: 多模态推理 / 强化学习 / 视觉证据建模
摘要
云蝶科技科研团队提出POLIA(基于视觉对象级内在优势的多模态推理策略优化),在传统答案级评价之外增加针对视觉对象的细粒度评价机制。分两个阶段:第一阶段评价答案(计算答案级外在奖励),第二阶段评价证据(识别候选答案引用的视觉对象,根据预测位置与真实位置的匹配质量判断可靠程度)。POLIA实现了从"奖励正确答案"到"奖励模型正确使用视觉证据"的转变。在VSR、TallyQA、GQA、MathVista等7项基准上测试,覆盖空间关系、计数、视觉数学推理等任务。
结论
7B模型实验中,相比GRPO方法,POLIA在VSR、TallyQA、GQA和MathVista上准确率分别提升22.3、8.7、11.3和9.3个百分点。在高度依赖视觉证据的任务中,POLIA-7B的分数高于GPT-4o和Gemini 2.5 Pro。消融实验表明答案级外在优势维持训练稳定性,视觉对象级内在优势帮助模型更准确选择视觉证据。新增计算开销较低,性能提升并非依赖增加算力。
对旧假设的挑战
- 挑战"答案级奖励足以训练多模态模型"的假设:模型可能忽略关键视觉信息仅靠语言模式猜对答案,或引用错误视觉对象碰巧得到正确结论。表面正确≠真正理解。
- 挑战"需要更大模型才能更强"的假设:7B模型通过更细致的训练反馈即可超越GPT-4o和Gemini 2.5 Pro等更大模型,说明优化信用分配比堆参数更有效。
- 挑战"能回答=真理解"的多模态评估假设:POLIA证明,传统只看最终答案对错的评估方式无法区分"真理解"和"碰运气",必须深入到视觉证据使用层面才能评价模型的真实能力。
本期论文来源:arXiv预印本、ICML 2026、OpenAI官方报告 由 TeleAgent 自动整理发送 













2026年重磅喜讯! 喜报!热烈祝贺Gavin大咖人工智能领域经典著作《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》中国水利水电出版社发行上市!
内容提要
本书内容基于作者在硅谷 ChatGPT 项目及企业培训中的实战经验凝练而成,重点介绍企业级 ChatGPT 开发的核心技术、案例研究及最佳实践。全书共 16 章,分为基础篇和实战篇两大部分。
基础篇:
介绍 ChatGPT 底层架构 Transformer 技术及源码实现、GPT 的内部机制及源码实现、GPT 系列模型原理与应用:从 GPT-2 到 GPT-4 等内容。
实战篇:
介绍基于 ChatGPT 的端到端语音聊天机器人项目实战,企业级 ChatGPT 开发的三大核心内部机制及案例实战,ChatGPT 插件的内部机制、源码及案例实战,ChatGPT 提示词开发实战,思维链及 ReAct 解析与实战,提示词本质解析及评估实战与源码解析,LangChain 大模型框架的七大核心组件及案例解析(上、下),LangChain 代理深入解析及源码解析,AutoGPT 源码解析及综合案例实战,使用 LangChain 构建问答聊天机器人案例实战,构建基于大模型的自治代理案例,Llama 2 模型与 LangChain 项目详解。书中每个知识点均配有相应的实现代码和实例。
本书适合有一定 Python 基础的 ChatGPT 爱好者阅读,主要面向从事大模型应用开发、机器学习、数据挖掘或深度学习的专业人员,高等院校相关专业的师生,以及相关领域的科研人员。
本书附赠丰富的学习资源,具体如下:①同步学习资源,即 16 集同步教学视频,视频时长共计约 1000 分钟;②教师授课的辅助资源,即 187 个案例知识点、15 个项目实战的全部源代码。
前言
在当今快速发展的科技时代,人工智能(artificial intelligence,AI)技术正以惊人的速度改变着人们的生活和工作方式。在这个新时代的浪潮中,大模型技术成为AI领域的一颗耀眼新星。ChatGPT作为大模型技术的重要应用之一,正在引领着人机交互领域的革新浪潮。本书将带领读者深入探索大模型新时代,通过ChatGPT实战项目和内部解析,深入掌握基于ChatGPT的大模型应用开发领域的关键技术,并解密ChatGPT的底层架构和实现原理。
本书主要内容
本书通过ChatGPT实战项目的方式,为读者呈现一个全面、系统的学习路径,从基础知识的介绍开始,带领读者深入了解ChatGPT的工作原理和实际应用。本书非常适合具备Python基础的读者学习。
全书共16章,分为基础篇和实战篇两大部分。 基础篇包括第1~3章;实战篇包括第4~16章。
第1章 ChatGPT底层架构Transformer技术及源码实现,详解最大似然估计、最大后验概率、贝叶斯Transformer及自编码与自回归语言模型的内部机制。
第2章 GPT的内部机制及源码实现,剖析GPT运行机制、掩码机制、Decoder-Only模式,详解数据流动生命周期及GPT-2源码。
第3章 GPT系列模型原理与应用:从GPT-2到GPT-4,解析ChatGPT提示词流程、GPT-2运行机制,可视化解读GPT-3/4的内部机制。
第4章 基于ChatGPT的端到端语音聊天机器人项目实战,涵盖ChatGPT API开发、前后端构建(ReAct+FastAPI)及项目优化。
第5章 企业级ChatGPT开发的三大核心内部机制及案例实战,解析企业级开发核心,演示Notion问答对话AI案例。
第6章 ChatGPT插件的内部机制、源码及案例实战,详解插件工作原理、检索插件源码及全流程开发实战。
第7章 ChatGPT提示词开发实战,基于LangChain框架的提示词、思维链、链式提示词及模型评估开发。
第8章 思维链及ReAct解析与实战,剖析思维链推理、ReAct技术原理、框架源码及案例实战。
第9章 提示词本质解析及评估实战与源码解析,包含问答评估、代理评估源码解析及提示词本质探讨。
第10~11章 LangChain大模型框架的七大核心组件及案例解析(上、下),涵盖模型、词嵌入、提示词、内存、回调、数据连接、代理等核心组件及聊天机器人综合案例。
第12章 LangChain代理深入解析及源码解析,详解代理工作原理及AutoGPT源码解析。
第13章 AutoGPT源码解析及综合案例实战,剖析AutoGPT内部机制及其在LangChain代理、内存、PromptGenerator中的应用。
第14章 使用LangChain构建问答聊天机器人案例实战,涵盖GPT-4代码生成全流程及LangChain开发实战。
第15章 构建基于大模型的自治代理案例,详解自治代理原理、工具、示例及开源实现源码。
第16章 Llama 2模型与LangChain项目详解,包括模型部署(Replicate)、Hugging Face/LangChain实践、检索增强生成及自定义提示词RetrievalQA开发。
本书特色
●深入探索,全面剖析。 本书涵盖ChatGPT案例实战、LangChain项目实战及框架源码解析等多个层面的内容。每章都深入探讨相关技术与案例,并提供源码解析,使读者能够全面了解ChatGPT和LangChain等技术的内部机制与开发原理,为实际项目的应用提供有力指导。
●实战剖析,项目揭秘。 本书每章都提供具体的案例实战与项目解析,引导读者通过实际操作和代码理解技术细节和底层逻辑。通过理论结合实践的方式,使读者能够更好地运用所学知识,深入了解项目和框架的实现细节。
●前沿突破,技术驱动。 本书介绍了一系列突破性的技术,如ChatGPT、LangChain、Transformer、Prompt、Llama 2、AutoGPT、BabyAGI、CoT、ToT、ReAct、MRKL等。通过对这些技术的深入剖析,读者可以了解相关技术的发展和应用,并了解它们在实际项目中的具体应用场景和效果。
●源码解析,细致讲解。 本书对LangChain框架的关键技术进行了逐行源码剖析。读者可以深入理解源码实现和机制原理,从而更好地理解技术细节和底层逻辑,并将其应用于实际开发工作中。
本书还为读者提供了丰富的知识和实用的技能,帮助读者在ChatGPT和LangChain领域取得突破性的进展。无论是初学者还是有一定经验的开发者,都可以从本书中获得有价值的学习资源。
配套资源
为便于教与学,本书配有同步教学视频(约1000分钟)、源代码、数据集、教学课件、教学大纲、安装程序。
作者简介
王家林
美国斯坦福大学计算机专业毕业。曾在美国担任硅谷顶级机器学习和人工智能实验室主任、杰出AI工程师及首席机器学习工程师,专精于对话式人工智能(conversational AI)。现担任硅谷某知名对话机器人公司CTO,自2019年起专注于基于红队测试(red teaming)的责任型AI(responsible AI),并热衷于构建生成式AI/大语言模型教练系统(GenAI/LLM coaching systems)。在硅谷任职期间,曾领导多个GenAI/LLM解决方案项目,成功平衡企业业务需求下的大模型推理(reasoning)系统与幻觉(hallucinations)及偏见(biases)风险的最小化。
作为数据科学、机器学习、NLP、ChatGPT及大模型等领域25本书的主要作者,王家林对利用人工智能提供解决方案,以及通过机器学习驱动的NLP与LLM流程帮助组织实现数据驱动决策充满热情。他曾领导Apple、PayPal、Chase Bank、Faethm、LinkedIn等公司的11个重大NLP项目。
在NLP、对话式AI、大数据及基于AWS的无服务器(serverless)技术方面,拥有丰富的机器学习咨询经验。
段智华
中国电信股份有限公司上海分公司高级工程师。长期从事大模型与智能体技术领域,专注Agentic AI、Harness Agent等前沿方向研究。
新书购买链接
《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》 购买链接:item.jd.com/15389212.ht...