forked from Zakaria/hermes-agent
Hermes-agent
This commit is contained in:
+266
@@ -0,0 +1,266 @@
|
||||
---
|
||||
sidebar_position: 11
|
||||
title: "用 Cron 自动化一切"
|
||||
description: "使用 Hermes cron 的真实自动化模式——监控、报告、数据管道与多技能工作流"
|
||||
---
|
||||
|
||||
# 用 Cron 自动化一切
|
||||
|
||||
[每日简报机器人教程](/guides/daily-briefing-bot)涵盖了基础内容。本指南更进一步——五种真实的自动化模式,可直接改造用于你自己的工作流。
|
||||
|
||||
完整功能参考请见 [定时任务(Cron)](/user-guide/features/cron)。
|
||||
|
||||
:::info 核心概念
|
||||
Cron 任务在全新的 agent 会话中运行,不保留当前对话的任何记忆。Prompt(提示词)必须**完全自包含**——把 agent 需要知道的一切都写进去。
|
||||
:::
|
||||
|
||||
:::tip 不需要 LLM?你有两种零 token 方案。
|
||||
- **循环看门狗**:脚本本身已能生成精确消息(内存告警、磁盘告警、心跳)时,使用 [纯脚本 cron 任务](/guides/cron-script-only)。相同的调度器,无需 LLM。你可以在对话中让 Hermes 帮你设置——`cronjob` 工具知道何时选择 `no_agent=True` 并为你编写脚本。
|
||||
- **已在运行的脚本发起的一次性通知**(CI 步骤、post-commit hook、部署脚本、外部调度的监控):使用 [`hermes send`](/guides/pipe-script-output) 将 stdout 或文件直接推送到 Telegram / Discord / Slack 等,无需设置 cron 条目。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 模式一:网站变更监控
|
||||
|
||||
监视某个 URL 的变化,仅在内容发生变化时发送通知。
|
||||
|
||||
`script` 参数是这里的秘密武器。每次执行前会先运行一个 Python 脚本,其 stdout 作为上下文传给 agent。脚本负责机械性工作(抓取、对比差异);agent 负责推理(这个变化是否值得关注?)。
|
||||
|
||||
创建监控脚本:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.hermes/scripts
|
||||
```
|
||||
|
||||
```python title="~/.hermes/scripts/watch-site.py"
|
||||
import hashlib, json, os, urllib.request
|
||||
|
||||
URL = "https://example.com/pricing"
|
||||
STATE_FILE = os.path.expanduser("~/.hermes/scripts/.watch-site-state.json")
|
||||
|
||||
# Fetch current content
|
||||
req = urllib.request.Request(URL, headers={"User-Agent": "Hermes-Monitor/1.0"})
|
||||
content = urllib.request.urlopen(req, timeout=30).read().decode()
|
||||
current_hash = hashlib.sha256(content.encode()).hexdigest()
|
||||
|
||||
# Load previous state
|
||||
prev_hash = None
|
||||
if os.path.exists(STATE_FILE):
|
||||
with open(STATE_FILE) as f:
|
||||
prev_hash = json.load(f).get("hash")
|
||||
|
||||
# Save current state
|
||||
with open(STATE_FILE, "w") as f:
|
||||
json.dump({"hash": current_hash, "url": URL}, f)
|
||||
|
||||
# Output for the agent
|
||||
if prev_hash and prev_hash != current_hash:
|
||||
print(f"CHANGE DETECTED on {URL}")
|
||||
print(f"Previous hash: {prev_hash}")
|
||||
print(f"Current hash: {current_hash}")
|
||||
print(f"\nCurrent content (first 2000 chars):\n{content[:2000]}")
|
||||
else:
|
||||
print("NO_CHANGE")
|
||||
```
|
||||
|
||||
设置 cron 任务:
|
||||
|
||||
```bash
|
||||
/cron add "every 1h" "If the script output says CHANGE DETECTED, summarize what changed on the page and why it might matter. If it says NO_CHANGE, respond with just [SILENT]." --script ~/.hermes/scripts/watch-site.py --name "Pricing monitor" --deliver telegram
|
||||
```
|
||||
|
||||
:::tip `[SILENT]` 技巧
|
||||
当 agent 的最终响应包含 `[SILENT]` 时,投递会被抑制。这意味着只有在真正发生变化时你才会收到通知——安静时段不会产生垃圾消息。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 模式二:每周报告
|
||||
|
||||
从多个来源汇总信息,生成格式化摘要。每周运行一次,投递到你的主频道。
|
||||
|
||||
```bash
|
||||
/cron add "0 9 * * 1" "Generate a weekly report covering:
|
||||
|
||||
1. Search the web for the top 5 AI news stories from the past week
|
||||
2. Search GitHub for trending repositories in the 'machine-learning' topic
|
||||
3. Check Hacker News for the most discussed AI/ML posts
|
||||
|
||||
Format as a clean summary with sections for each source. Include links.
|
||||
Keep it under 500 words — highlight only what matters." --name "Weekly AI digest" --deliver telegram
|
||||
```
|
||||
|
||||
通过 CLI:
|
||||
|
||||
```bash
|
||||
hermes cron create "0 9 * * 1" \
|
||||
"Generate a weekly report covering the top AI news, trending ML GitHub repos, and most-discussed HN posts. Format with sections, include links, keep under 500 words." \
|
||||
--name "Weekly AI digest" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
`0 9 * * 1` 是标准 cron 表达式:每周一上午 9:00。
|
||||
|
||||
---
|
||||
|
||||
## 模式三:GitHub 仓库监控
|
||||
|
||||
监控某个仓库的新 issue、PR 或 release。
|
||||
|
||||
```bash
|
||||
/cron add "every 6h" "Check the GitHub repository NousResearch/hermes-agent for:
|
||||
- New issues opened in the last 6 hours
|
||||
- New PRs opened or merged in the last 6 hours
|
||||
- Any new releases
|
||||
|
||||
Use the terminal to run gh commands:
|
||||
gh issue list --repo NousResearch/hermes-agent --state open --json number,title,author,createdAt --limit 10
|
||||
gh pr list --repo NousResearch/hermes-agent --state all --json number,title,author,createdAt,mergedAt --limit 10
|
||||
|
||||
Filter to only items from the last 6 hours. If nothing new, respond with [SILENT].
|
||||
Otherwise, provide a concise summary of the activity." --name "Repo watcher" --deliver discord
|
||||
```
|
||||
|
||||
:::warning 自包含的 Prompt
|
||||
注意 prompt 中包含了精确的 `gh` 命令。cron agent 不记得之前的运行记录或你的偏好——把所有内容都明确写出来。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 模式四:数据采集管道
|
||||
|
||||
定期抓取数据、保存到文件,并随时间检测趋势。此模式将脚本(用于采集)与 agent(用于分析)结合使用。
|
||||
|
||||
```python title="~/.hermes/scripts/collect-prices.py"
|
||||
import json, os, urllib.request
|
||||
from datetime import datetime
|
||||
|
||||
DATA_DIR = os.path.expanduser("~/.hermes/data/prices")
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
|
||||
# Fetch current data (example: crypto prices)
|
||||
url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd"
|
||||
data = json.loads(urllib.request.urlopen(url, timeout=30).read())
|
||||
|
||||
# Append to history file
|
||||
entry = {"timestamp": datetime.now().isoformat(), "prices": data}
|
||||
history_file = os.path.join(DATA_DIR, "history.jsonl")
|
||||
with open(history_file, "a") as f:
|
||||
f.write(json.dumps(entry) + "\n")
|
||||
|
||||
# Load recent history for analysis
|
||||
lines = open(history_file).readlines()
|
||||
recent = [json.loads(l) for l in lines[-24:]] # Last 24 data points
|
||||
|
||||
# Output for the agent
|
||||
print(f"Current: BTC=${data['bitcoin']['usd']}, ETH=${data['ethereum']['usd']}")
|
||||
print(f"Data points collected: {len(lines)} total, showing last {len(recent)}")
|
||||
print(f"\nRecent history:")
|
||||
for r in recent[-6:]:
|
||||
print(f" {r['timestamp']}: BTC=${r['prices']['bitcoin']['usd']}, ETH=${r['prices']['ethereum']['usd']}")
|
||||
```
|
||||
|
||||
```bash
|
||||
/cron add "every 1h" "Analyze the price data from the script output. Report:
|
||||
1. Current prices
|
||||
2. Trend direction over the last 6 data points (up/down/flat)
|
||||
3. Any notable movements (>5% change)
|
||||
|
||||
If prices are flat and nothing notable, respond with [SILENT].
|
||||
If there's a significant move, explain what happened." \
|
||||
--script ~/.hermes/scripts/collect-prices.py \
|
||||
--name "Price tracker" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
脚本负责机械性的数据采集;agent 在此之上添加推理层。
|
||||
|
||||
---
|
||||
|
||||
## 模式五:多技能工作流
|
||||
|
||||
将多个 skill(技能)串联起来,完成复杂的定时任务。Skill 按顺序加载,然后执行 prompt。
|
||||
|
||||
```bash
|
||||
# 使用 arxiv skill 查找论文,再用 obsidian skill 保存笔记
|
||||
/cron add "0 8 * * *" "Search arXiv for the 3 most interesting papers on 'language model reasoning' from the past day. For each paper, create an Obsidian note with the title, authors, abstract summary, and key contribution." \
|
||||
--skill arxiv \
|
||||
--skill obsidian \
|
||||
--name "Paper digest"
|
||||
```
|
||||
|
||||
直接通过工具调用:
|
||||
|
||||
```python
|
||||
cronjob(
|
||||
action="create",
|
||||
skills=["arxiv", "obsidian"],
|
||||
prompt="Search arXiv for papers on 'language model reasoning' from the past day. Save the top 3 as Obsidian notes.",
|
||||
schedule="0 8 * * *",
|
||||
name="Paper digest",
|
||||
deliver="local"
|
||||
)
|
||||
```
|
||||
|
||||
Skill 按顺序加载——先加载 `arxiv`(教 agent 如何搜索论文),再加载 `obsidian`(教 agent 如何写笔记)。Prompt 将二者串联起来。
|
||||
|
||||
---
|
||||
|
||||
## 管理你的任务
|
||||
|
||||
```bash
|
||||
# 列出所有活跃任务
|
||||
/cron list
|
||||
|
||||
# 立即触发某个任务(用于测试)
|
||||
/cron run <job_id>
|
||||
|
||||
# 暂停任务而不删除
|
||||
/cron pause <job_id>
|
||||
|
||||
# 编辑运行中任务的调度或 prompt
|
||||
/cron edit <job_id> --schedule "every 4h"
|
||||
/cron edit <job_id> --prompt "Updated task description"
|
||||
|
||||
# 为现有任务添加或移除 skill
|
||||
/cron edit <job_id> --skill arxiv --skill obsidian
|
||||
/cron edit <job_id> --clear-skills
|
||||
|
||||
# 永久删除任务
|
||||
/cron remove <job_id>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 投递目标
|
||||
|
||||
`--deliver` 标志控制结果发送到哪里:
|
||||
|
||||
| 目标 | 示例 | 使用场景 |
|
||||
|--------|---------|----------|
|
||||
| `origin` | `--deliver origin` | 创建该任务的对话(默认) |
|
||||
| `local` | `--deliver local` | 仅保存到本地文件 |
|
||||
| `telegram` | `--deliver telegram` | 你的 Telegram 主频道 |
|
||||
| `discord` | `--deliver discord` | 你的 Discord 主频道 |
|
||||
| `slack` | `--deliver slack` | 你的 Slack 主频道 |
|
||||
| 指定对话 | `--deliver telegram:-1001234567890` | 特定 Telegram 群组 |
|
||||
| 线程投递 | `--deliver telegram:-1001234567890:17585` | 特定 Telegram 话题线程 |
|
||||
|
||||
---
|
||||
|
||||
## 使用技巧
|
||||
|
||||
**让 prompt 完全自包含。** Cron 任务中的 agent 不记得你的任何对话。把 URL、仓库名、格式偏好和投递说明直接写进 prompt。
|
||||
|
||||
**大量使用 `[SILENT]`。** 对于监控类任务,始终加上类似"如果没有变化,回复 `[SILENT]`"的指令,防止通知噪音。
|
||||
|
||||
**用脚本做数据采集。** `script` 参数让 Python 脚本处理枯燥的部分(HTTP 请求、文件 I/O、状态追踪)。Agent 只看到脚本的 stdout,并对其进行推理。这比让 agent 自己抓取更省钱、更可靠。
|
||||
|
||||
**用 `/cron run` 测试。** 不要等调度触发,使用 `/cron run <job_id>` 立即执行,验证输出是否符合预期。
|
||||
|
||||
**调度表达式。** 支持的格式:相对延迟(`30m`)、间隔(`every 2h`)、标准 cron 表达式(`0 9 * * *`)、ISO 时间戳(`2025-06-15T09:00:00`)。不支持自然语言如 `daily at 9am`——请改用 `0 9 * * *`。
|
||||
|
||||
---
|
||||
|
||||
*完整的 cron 参考——所有参数、边界情况和内部机制——请见 [定时任务(Cron)](/user-guide/features/cron)。*
|
||||
+595
@@ -0,0 +1,595 @@
|
||||
---
|
||||
sidebar_position: 15
|
||||
title: "自动化蓝图"
|
||||
description: "开箱即用的自动化蓝图——定时任务、GitHub 事件触发、API webhook 及多技能工作流"
|
||||
---
|
||||
|
||||
# 自动化蓝图
|
||||
|
||||
常见自动化模式的复制粘贴蓝图。每个蓝图使用 Hermes 内置的 [cron 调度器](/user-guide/features/cron) 实现基于时间的触发,使用 [webhook 平台](/user-guide/messaging/webhooks) 实现事件驱动触发。
|
||||
|
||||
所有蓝图适用于**任意模型**——不绑定单一提供商。
|
||||
|
||||
如需带表单的参数化蓝图(无需手写 cron 语法),请参阅[自动化蓝图目录](/reference/automation-blueprints-catalog)。
|
||||
|
||||
:::tip 三种触发类型
|
||||
| 触发方式 | 方式 | 工具 |
|
||||
|---------|-----|------|
|
||||
| **定时** | 按周期运行(每小时、每晚、每周) | `cronjob` 工具或 `/cron` 斜杠命令 |
|
||||
| **GitHub 事件** | PR 开启、推送、issue、CI 结果时触发 | Webhook 平台(`hermes webhook subscribe`) |
|
||||
| **API 调用** | 外部服务向你的端点 POST JSON | Webhook 平台(config.yaml 路由或 `hermes webhook subscribe`) |
|
||||
|
||||
三种方式均支持投递到 Telegram、Discord、Slack、SMS、邮件、GitHub 评论或本地文件。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 开发工作流
|
||||
|
||||
### 每晚待办事项分类
|
||||
|
||||
每晚自动对新 issue 进行标签分类、优先级排序和摘要汇总,并将摘要投递到团队频道。
|
||||
|
||||
**触发方式:** 定时(每晚)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 2 * * *" \
|
||||
"You are a project manager triaging the NousResearch/hermes-agent GitHub repo.
|
||||
|
||||
1. Run: gh issue list --repo NousResearch/hermes-agent --state open --json number,title,labels,author,createdAt --limit 30
|
||||
2. Identify issues opened in the last 24 hours
|
||||
3. For each new issue:
|
||||
- Suggest a priority label (P0-critical, P1-high, P2-medium, P3-low)
|
||||
- Suggest a category label (bug, feature, docs, security)
|
||||
- Write a one-line triage note
|
||||
4. Summarize: total open issues, new today, breakdown by priority
|
||||
|
||||
Format as a clean digest. If no new issues, respond with [SILENT]." \
|
||||
--name "Nightly backlog triage" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### 自动 PR 代码审查
|
||||
|
||||
PR 开启时自动进行审查,并直接在 PR 上发布审查评论。
|
||||
|
||||
**触发方式:** GitHub webhook
|
||||
|
||||
**方式 A——动态订阅(CLI):**
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe github-pr-review \
|
||||
--events "pull_request" \
|
||||
--prompt "Review this pull request:
|
||||
Repository: {repository.full_name}
|
||||
PR #{pull_request.number}: {pull_request.title}
|
||||
Author: {pull_request.user.login}
|
||||
Action: {action}
|
||||
Diff URL: {pull_request.diff_url}
|
||||
|
||||
Fetch the diff with: curl -sL {pull_request.diff_url}
|
||||
|
||||
Review for:
|
||||
- Security issues (injection, auth bypass, secrets in code)
|
||||
- Performance concerns (N+1 queries, unbounded loops, memory leaks)
|
||||
- Code quality (naming, duplication, error handling)
|
||||
- Missing tests for new behavior
|
||||
|
||||
Post a concise review. If the PR is a trivial docs/typo change, say so briefly." \
|
||||
--skill github-code-review \
|
||||
--deliver github_comment
|
||||
```
|
||||
|
||||
**方式 B——静态路由(config.yaml):**
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
port: 8644
|
||||
secret: "your-global-secret"
|
||||
routes:
|
||||
github-pr-review:
|
||||
events: ["pull_request"]
|
||||
secret: "github-webhook-secret"
|
||||
prompt: |
|
||||
Review PR #{pull_request.number}: {pull_request.title}
|
||||
Repository: {repository.full_name}
|
||||
Author: {pull_request.user.login}
|
||||
Diff URL: {pull_request.diff_url}
|
||||
Review for security, performance, and code quality.
|
||||
skills: ["github-code-review"]
|
||||
deliver: "github_comment"
|
||||
deliver_extra:
|
||||
repo: "{repository.full_name}"
|
||||
pr_number: "{pull_request.number}"
|
||||
```
|
||||
|
||||
然后在 GitHub 中:**Settings → Webhooks → Add webhook** → Payload URL:`http://your-server:8644/webhooks/github-pr-review`,Content type:`application/json`,Secret:`github-webhook-secret`,Events:**Pull requests**。
|
||||
|
||||
### 文档偏差检测
|
||||
|
||||
每周扫描已合并的 PR,找出需要更新文档的 API 变更。
|
||||
|
||||
**触发方式:** 定时(每周)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 9 * * 1" \
|
||||
"Scan the NousResearch/hermes-agent repo for documentation drift.
|
||||
|
||||
1. Run: gh pr list --repo NousResearch/hermes-agent --state merged --json number,title,files,mergedAt --limit 30
|
||||
2. Filter to PRs merged in the last 7 days
|
||||
3. For each merged PR, check if it modified:
|
||||
- Tool schemas (tools/*.py) — may need docs/reference/tools-reference.md update
|
||||
- CLI commands (hermes_cli/commands.py, hermes_cli/main.py) — may need docs/reference/cli-commands.md update
|
||||
- Config options (hermes_cli/config.py) — may need docs/user-guide/configuration.md update
|
||||
- Environment variables — may need docs/reference/environment-variables.md update
|
||||
4. Cross-reference: for each code change, check if the corresponding docs page was also updated in the same PR
|
||||
|
||||
Report any gaps where code changed but docs didn't. If everything is in sync, respond with [SILENT]." \
|
||||
--name "Docs drift detection" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### 依赖安全审计
|
||||
|
||||
每日扫描项目依赖中的已知漏洞。
|
||||
|
||||
**触发方式:** 定时(每日)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 6 * * *" \
|
||||
"Run a dependency security audit on the hermes-agent project.
|
||||
|
||||
1. cd ~/.hermes/hermes-agent && source .venv/bin/activate
|
||||
2. Run: pip audit --format json 2>/dev/null || pip audit 2>&1
|
||||
3. Run: npm audit --json 2>/dev/null (in website/ directory if it exists)
|
||||
4. Check for any CVEs with CVSS score >= 7.0
|
||||
|
||||
If vulnerabilities found:
|
||||
- List each one with package name, version, CVE ID, severity
|
||||
- Check if an upgrade is available
|
||||
- Note if it's a direct dependency or transitive
|
||||
|
||||
If no vulnerabilities, respond with [SILENT]." \
|
||||
--name "Dependency audit" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DevOps 与监控
|
||||
|
||||
### 部署验证
|
||||
|
||||
每次部署后触发冒烟测试。CI/CD 流水线在部署完成时向 webhook POST 请求。
|
||||
|
||||
**触发方式:** API 调用(webhook)
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe deploy-verify \
|
||||
--events "deployment" \
|
||||
--prompt "A deployment just completed:
|
||||
Service: {service}
|
||||
Environment: {environment}
|
||||
Version: {version}
|
||||
Deployed by: {deployer}
|
||||
|
||||
Run these verification steps:
|
||||
1. Check if the service is responding: curl -s -o /dev/null -w '%{http_code}' {health_url}
|
||||
2. Search recent logs for errors: check the deployment payload for any error indicators
|
||||
3. Verify the version matches: curl -s {health_url}/version
|
||||
|
||||
Report: deployment status (healthy/degraded/failed), response time, any errors found.
|
||||
If healthy, keep it brief. If degraded or failed, provide detailed diagnostics." \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
你的 CI/CD 流水线触发方式:
|
||||
|
||||
```bash
|
||||
curl -X POST http://your-server:8644/webhooks/deploy-verify \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Hub-Signature-256: sha256=$(echo -n '{"service":"api","environment":"prod","version":"2.1.0","deployer":"ci","health_url":"https://api.example.com/health"}' | openssl dgst -sha256 -hmac 'your-secret' | cut -d' ' -f2)" \
|
||||
-d '{"service":"api","environment":"prod","version":"2.1.0","deployer":"ci","health_url":"https://api.example.com/health"}'
|
||||
```
|
||||
|
||||
### 告警分类
|
||||
|
||||
将监控告警与近期变更关联,起草响应方案。适用于 Datadog、PagerDuty、Grafana 或任何能 POST JSON 的告警系统。
|
||||
|
||||
**触发方式:** API 调用(webhook)
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe alert-triage \
|
||||
--prompt "Monitoring alert received:
|
||||
Alert: {alert.name}
|
||||
Severity: {alert.severity}
|
||||
Service: {alert.service}
|
||||
Message: {alert.message}
|
||||
Timestamp: {alert.timestamp}
|
||||
|
||||
Investigate:
|
||||
1. Search the web for known issues with this error pattern
|
||||
2. Check if this correlates with any recent deployments or config changes
|
||||
3. Draft a triage summary with:
|
||||
- Likely root cause
|
||||
- Suggested first response steps
|
||||
- Escalation recommendation (P1-P4)
|
||||
|
||||
Be concise. This goes to the on-call channel." \
|
||||
--deliver slack
|
||||
```
|
||||
|
||||
### 可用性监控
|
||||
|
||||
每 30 分钟检查一次端点,仅在服务宕机时发送通知。
|
||||
|
||||
**触发方式:** 定时(每 30 分钟)
|
||||
|
||||
```python title="~/.hermes/scripts/check-uptime.py"
|
||||
import urllib.request, json, time
|
||||
|
||||
ENDPOINTS = [
|
||||
{"name": "API", "url": "https://api.example.com/health"},
|
||||
{"name": "Web", "url": "https://www.example.com"},
|
||||
{"name": "Docs", "url": "https://docs.example.com"},
|
||||
]
|
||||
|
||||
results = []
|
||||
for ep in ENDPOINTS:
|
||||
try:
|
||||
start = time.time()
|
||||
req = urllib.request.Request(ep["url"], headers={"User-Agent": "Hermes-Monitor/1.0"})
|
||||
resp = urllib.request.urlopen(req, timeout=10)
|
||||
elapsed = round((time.time() - start) * 1000)
|
||||
results.append({"name": ep["name"], "status": resp.getcode(), "ms": elapsed})
|
||||
except Exception as e:
|
||||
results.append({"name": ep["name"], "status": "DOWN", "error": str(e)})
|
||||
|
||||
down = [r for r in results if r.get("status") == "DOWN" or (isinstance(r.get("status"), int) and r["status"] >= 500)]
|
||||
if down:
|
||||
print("OUTAGE DETECTED")
|
||||
for r in down:
|
||||
print(f" {r['name']}: {r.get('error', f'HTTP {r[\"status\"]}')} ")
|
||||
print(f"\nAll results: {json.dumps(results, indent=2)}")
|
||||
else:
|
||||
print("NO_ISSUES")
|
||||
```
|
||||
|
||||
```bash
|
||||
hermes cron create "every 30m" \
|
||||
"If the script reports OUTAGE DETECTED, summarize which services are down and suggest likely causes. If NO_ISSUES, respond with [SILENT]." \
|
||||
--script ~/.hermes/scripts/check-uptime.py \
|
||||
--name "Uptime monitor" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 研究与情报
|
||||
|
||||
### 竞品仓库侦察
|
||||
|
||||
监控竞品仓库中有价值的 PR、功能和架构决策。
|
||||
|
||||
**触发方式:** 定时(每日)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 8 * * *" \
|
||||
"Scout these AI agent repositories for notable activity in the last 24 hours:
|
||||
|
||||
Repos to check:
|
||||
- anthropics/claude-code
|
||||
- openai/codex
|
||||
- All-Hands-AI/OpenHands
|
||||
- Aider-AI/aider
|
||||
|
||||
For each repo:
|
||||
1. gh pr list --repo <repo> --state all --json number,title,author,createdAt,mergedAt --limit 15
|
||||
2. gh issue list --repo <repo> --state open --json number,title,labels,createdAt --limit 10
|
||||
|
||||
Focus on:
|
||||
- New features being developed
|
||||
- Architectural changes
|
||||
- Integration patterns we could learn from
|
||||
- Security fixes that might affect us too
|
||||
|
||||
Skip routine dependency bumps and CI fixes. If nothing notable, respond with [SILENT].
|
||||
If there are findings, organize by repo with brief analysis of each item." \
|
||||
--skill competitive-pr-scout \
|
||||
--name "Competitor scout" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### AI 新闻摘要
|
||||
|
||||
每周汇总 AI/ML 领域动态。
|
||||
|
||||
**触发方式:** 定时(每周)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 9 * * 1" \
|
||||
"Generate a weekly AI news digest covering the past 7 days:
|
||||
|
||||
1. Search the web for major AI announcements, model releases, and research breakthroughs
|
||||
2. Search for trending ML repositories on GitHub
|
||||
3. Check arXiv for highly-cited papers on language models and agents
|
||||
|
||||
Structure:
|
||||
## Headlines (3-5 major stories)
|
||||
## Notable Papers (2-3 papers with one-sentence summaries)
|
||||
## Open Source (interesting new repos or major releases)
|
||||
## Industry Moves (funding, acquisitions, launches)
|
||||
|
||||
Keep each item to 1-2 sentences. Include links. Total under 600 words." \
|
||||
--name "Weekly AI digest" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### 论文摘要与笔记
|
||||
|
||||
每日扫描 arXiv 并将摘要保存到笔记系统。
|
||||
|
||||
**触发方式:** 定时(每日)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 8 * * *" \
|
||||
"Search arXiv for the 3 most interesting papers on 'language model reasoning' OR 'tool-use agents' from the past day. For each paper, create an Obsidian note with the title, authors, abstract summary, key contribution, and potential relevance to Hermes Agent development." \
|
||||
--skill arxiv --skill obsidian \
|
||||
--name "Paper digest" \
|
||||
--deliver local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub 事件自动化
|
||||
|
||||
### Issue 自动打标签
|
||||
|
||||
自动对新 issue 打标签并回复。
|
||||
|
||||
**触发方式:** GitHub webhook
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe github-issues \
|
||||
--events "issues" \
|
||||
--prompt "New GitHub issue received:
|
||||
Repository: {repository.full_name}
|
||||
Issue #{issue.number}: {issue.title}
|
||||
Author: {issue.user.login}
|
||||
Action: {action}
|
||||
Body: {issue.body}
|
||||
Labels: {issue.labels}
|
||||
|
||||
If this is a new issue (action=opened):
|
||||
1. Read the issue title and body carefully
|
||||
2. Suggest appropriate labels (bug, feature, docs, security, question)
|
||||
3. If it's a bug report, check if you can identify the affected component from the description
|
||||
4. Post a helpful initial response acknowledging the issue
|
||||
|
||||
If this is a label or assignment change, respond with [SILENT]." \
|
||||
--deliver github_comment
|
||||
```
|
||||
|
||||
### CI 失败分析
|
||||
|
||||
分析 CI 失败原因并在 PR 上发布诊断信息。
|
||||
|
||||
**触发方式:** GitHub webhook
|
||||
|
||||
```yaml
|
||||
# config.yaml route
|
||||
platforms:
|
||||
webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
routes:
|
||||
ci-failure:
|
||||
events: ["check_run"]
|
||||
secret: "ci-secret"
|
||||
prompt: |
|
||||
CI check failed:
|
||||
Repository: {repository.full_name}
|
||||
Check: {check_run.name}
|
||||
Status: {check_run.conclusion}
|
||||
PR: #{check_run.pull_requests.0.number}
|
||||
Details URL: {check_run.details_url}
|
||||
|
||||
If conclusion is "failure":
|
||||
1. Fetch the log from the details URL if accessible
|
||||
2. Identify the likely cause of failure
|
||||
3. Suggest a fix
|
||||
If conclusion is "success", respond with [SILENT].
|
||||
deliver: "github_comment"
|
||||
deliver_extra:
|
||||
repo: "{repository.full_name}"
|
||||
pr_number: "{check_run.pull_requests.0.number}"
|
||||
```
|
||||
|
||||
### 跨仓库自动移植变更
|
||||
|
||||
某仓库 PR 合并后,自动将等效变更移植到另一个仓库。
|
||||
|
||||
**触发方式:** GitHub webhook
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe auto-port \
|
||||
--events "pull_request" \
|
||||
--prompt "PR merged in the source repository:
|
||||
Repository: {repository.full_name}
|
||||
PR #{pull_request.number}: {pull_request.title}
|
||||
Author: {pull_request.user.login}
|
||||
Action: {action}
|
||||
Merge commit: {pull_request.merge_commit_sha}
|
||||
|
||||
If action is 'closed' and pull_request.merged is true:
|
||||
1. Fetch the diff: curl -sL {pull_request.diff_url}
|
||||
2. Analyze what changed
|
||||
3. Determine if this change needs to be ported to the Go SDK equivalent
|
||||
4. If yes, create a branch, apply the equivalent changes, and open a PR on the target repo
|
||||
5. Reference the original PR in the new PR description
|
||||
|
||||
If action is not 'closed' or not merged, respond with [SILENT]." \
|
||||
--skill github-pr-workflow \
|
||||
--deliver log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 业务运营
|
||||
|
||||
### Stripe 支付监控
|
||||
|
||||
跟踪支付事件并汇总失败情况。
|
||||
|
||||
**触发方式:** API 调用(webhook)
|
||||
|
||||
```bash
|
||||
hermes webhook subscribe stripe-payments \
|
||||
--events "payment_intent.succeeded,payment_intent.payment_failed,charge.dispute.created" \
|
||||
--prompt "Stripe event received:
|
||||
Event type: {type}
|
||||
Amount: {data.object.amount} cents ({data.object.currency})
|
||||
Customer: {data.object.customer}
|
||||
Status: {data.object.status}
|
||||
|
||||
For payment_intent.payment_failed:
|
||||
- Identify the failure reason from {data.object.last_payment_error}
|
||||
- Suggest whether this is a transient issue (retry) or permanent (contact customer)
|
||||
|
||||
For charge.dispute.created:
|
||||
- Flag as urgent
|
||||
- Summarize the dispute details
|
||||
|
||||
For payment_intent.succeeded:
|
||||
- Brief confirmation only
|
||||
|
||||
Keep responses concise for the ops channel." \
|
||||
--deliver slack
|
||||
```
|
||||
|
||||
### 每日营收摘要
|
||||
|
||||
每天早晨汇总关键业务指标。
|
||||
|
||||
**触发方式:** 定时(每日)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 8 * * *" \
|
||||
"Generate a morning business metrics summary.
|
||||
|
||||
Search the web for:
|
||||
1. Current Bitcoin and Ethereum prices
|
||||
2. S&P 500 status (pre-market or previous close)
|
||||
3. Any major tech/AI industry news from the last 12 hours
|
||||
|
||||
Format as a brief morning briefing, 3-4 bullet points max.
|
||||
Deliver as a clean, scannable message." \
|
||||
--name "Morning briefing" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 多技能工作流
|
||||
|
||||
### 安全审计流水线
|
||||
|
||||
组合多个技能,每周进行全面安全审查。
|
||||
|
||||
**触发方式:** 定时(每周)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 3 * * 0" \
|
||||
"Run a comprehensive security audit of the hermes-agent codebase.
|
||||
|
||||
1. Check for dependency vulnerabilities (pip audit, npm audit)
|
||||
2. Search the codebase for common security anti-patterns:
|
||||
- Hardcoded secrets or API keys
|
||||
- SQL injection vectors (string formatting in queries)
|
||||
- Path traversal risks (user input in file paths without validation)
|
||||
- Unsafe deserialization (pickle.loads, yaml.load without SafeLoader)
|
||||
3. Review recent commits (last 7 days) for security-relevant changes
|
||||
4. Check if any new environment variables were added without being documented
|
||||
|
||||
Write a security report with findings categorized by severity (Critical, High, Medium, Low).
|
||||
If nothing found, report a clean bill of health." \
|
||||
--skill codebase-security-audit \
|
||||
--name "Weekly security audit" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### 内容流水线
|
||||
|
||||
按计划研究、起草并准备内容。
|
||||
|
||||
**触发方式:** 定时(每周)
|
||||
|
||||
```bash
|
||||
hermes cron create "0 10 * * 3" \
|
||||
"Research and draft a technical blog post outline about a trending topic in AI agents.
|
||||
|
||||
1. Search the web for the most discussed AI agent topics this week
|
||||
2. Pick the most interesting one that's relevant to open-source AI agents
|
||||
3. Create an outline with:
|
||||
- Hook/intro angle
|
||||
- 3-4 key sections
|
||||
- Technical depth appropriate for developers
|
||||
- Conclusion with actionable takeaway
|
||||
4. Save the outline to ~/drafts/blog-$(date +%Y%m%d).md
|
||||
|
||||
Keep the outline to ~300 words. This is a starting point, not a finished post." \
|
||||
--name "Blog outline" \
|
||||
--deliver local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速参考
|
||||
|
||||
### Cron 调度语法
|
||||
|
||||
| 表达式 | 含义 |
|
||||
|-----------|---------|
|
||||
| `every 30m` | 每 30 分钟 |
|
||||
| `every 2h` | 每 2 小时 |
|
||||
| `0 2 * * *` | 每天凌晨 2:00 |
|
||||
| `0 9 * * 1` | 每周一上午 9:00 |
|
||||
| `0 9 * * 1-5` | 工作日上午 9:00 |
|
||||
| `0 3 * * 0` | 每周日凌晨 3:00 |
|
||||
| `0 */6 * * *` | 每 6 小时 |
|
||||
|
||||
### 投递目标
|
||||
|
||||
| 目标 | 参数 | 说明 |
|
||||
|--------|------|-------|
|
||||
| 当前会话 | `--deliver origin` | 默认——投递到任务创建所在的位置 |
|
||||
| 本地文件 | `--deliver local` | 保存输出,不发送通知 |
|
||||
| Telegram | `--deliver telegram` | 主频道,或用 `telegram:CHAT_ID` 指定特定会话 |
|
||||
| Discord | `--deliver discord` | 主频道,或用 `discord:CHANNEL_ID` 指定 |
|
||||
| Slack | `--deliver slack` | 主频道 |
|
||||
| SMS | `--deliver sms:+15551234567` | 直接发送到手机号 |
|
||||
| 指定话题 | `--deliver telegram:-100123:456` | Telegram 论坛话题 |
|
||||
|
||||
### Webhook 模板变量
|
||||
|
||||
| 变量 | 说明 |
|
||||
|----------|-------------|
|
||||
| `{pull_request.title}` | PR 标题 |
|
||||
| `{issue.number}` | Issue 编号 |
|
||||
| `{repository.full_name}` | `owner/repo` |
|
||||
| `{action}` | 事件动作(opened、closed 等) |
|
||||
| `{__raw__}` | 完整 JSON payload(截断至 4000 字符) |
|
||||
| `{sender.login}` | 触发事件的 GitHub 用户 |
|
||||
|
||||
### [SILENT] 模式
|
||||
|
||||
当 cron 任务的响应包含 `[SILENT]` 时,投递将被抑制。使用此模式可避免在无事发生时产生通知噪音:
|
||||
|
||||
```
|
||||
If nothing noteworthy happened, respond with [SILENT].
|
||||
```
|
||||
|
||||
这样只有当 Agent 有内容需要汇报时,你才会收到通知。
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
sidebar_position: 14
|
||||
title: "AWS Bedrock"
|
||||
description: "将 Hermes Agent 与 Amazon Bedrock 配合使用——原生 Converse API、IAM 身份验证、Guardrails 及跨区域推理"
|
||||
---
|
||||
|
||||
# AWS Bedrock
|
||||
|
||||
Hermes Agent 通过 **Converse API** 原生支持 Amazon Bedrock——而非 OpenAI 兼容端点。这让你可以完整访问 Bedrock 生态系统:IAM 身份验证、Guardrails、跨区域推理配置文件以及所有基础模型。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- **AWS 凭证** — [boto3 凭证链](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html)支持的任意来源:
|
||||
- IAM 实例角色(EC2、ECS、Lambda — 零配置)
|
||||
- `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` 环境变量
|
||||
- `AWS_PROFILE`(用于 SSO 或命名配置文件)
|
||||
- `aws configure`(用于本地开发)
|
||||
- **boto3** — 通过 `pip install hermes-agent[bedrock]` 安装
|
||||
- **IAM 权限** — 至少需要:
|
||||
- `bedrock:InvokeModel` 和 `bedrock:InvokeModelWithResponseStream`(用于推理)
|
||||
- `bedrock:ListFoundationModels` 和 `bedrock:ListInferenceProfiles`(用于模型发现)
|
||||
|
||||
:::tip EC2 / ECS / Lambda
|
||||
在 AWS 计算环境中,为实例附加带有 `AmazonBedrockFullAccess` 的 IAM 角色即可。无需 API 密钥,无需 `.env` 配置——Hermes 会自动检测实例角色。
|
||||
:::
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 安装并启用 Bedrock 支持
|
||||
pip install hermes-agent[bedrock]
|
||||
|
||||
# 选择 Bedrock 作为提供商
|
||||
hermes model
|
||||
# → 选择 "More providers..." → "AWS Bedrock"
|
||||
# → 选择你的区域和模型
|
||||
|
||||
# 开始对话
|
||||
hermes chat
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
运行 `hermes model` 后,你的 `~/.hermes/config.yaml` 将包含以下内容:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: us.anthropic.claude-sonnet-4-6
|
||||
provider: bedrock
|
||||
base_url: https://bedrock-runtime.us-east-2.amazonaws.com
|
||||
|
||||
bedrock:
|
||||
region: us-east-2
|
||||
```
|
||||
|
||||
### 区域
|
||||
|
||||
通过以下任意方式设置 AWS 区域(优先级从高到低):
|
||||
|
||||
1. `config.yaml` 中的 `bedrock.region`
|
||||
2. `AWS_REGION` 环境变量
|
||||
3. `AWS_DEFAULT_REGION` 环境变量
|
||||
4. 默认值:`us-east-1`
|
||||
|
||||
### Guardrails
|
||||
|
||||
要对所有模型调用应用 [Amazon Bedrock Guardrails](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html):
|
||||
|
||||
```yaml
|
||||
bedrock:
|
||||
region: us-east-2
|
||||
guardrail:
|
||||
guardrail_identifier: "abc123def456" # 来自 Bedrock 控制台
|
||||
guardrail_version: "1" # 版本号或 "DRAFT"
|
||||
stream_processing_mode: "async" # "sync" 或 "async"
|
||||
trace: "disabled" # "enabled"、"disabled" 或 "enabled_full"
|
||||
```
|
||||
|
||||
### 模型发现
|
||||
|
||||
Hermes 通过 Bedrock 控制平面自动发现可用模型。你可以自定义发现行为:
|
||||
|
||||
```yaml
|
||||
bedrock:
|
||||
discovery:
|
||||
enabled: true
|
||||
provider_filter: ["anthropic", "amazon"] # 仅显示这些提供商
|
||||
refresh_interval: 3600 # 缓存 1 小时
|
||||
```
|
||||
|
||||
## 可用模型
|
||||
|
||||
Bedrock 模型使用**推理配置文件 ID** 进行按需调用。`hermes model` 选择器会自动显示这些 ID,并将推荐模型置于顶部:
|
||||
|
||||
| 模型 | ID | 备注 |
|
||||
|-------|-----|-------|
|
||||
| Claude Sonnet 4.6 | `us.anthropic.claude-sonnet-4-6` | 推荐——速度与能力的最佳平衡 |
|
||||
| Claude Opus 4.6 | `us.anthropic.claude-opus-4-6-v1` | 能力最强 |
|
||||
| Claude Haiku 4.5 | `us.anthropic.claude-haiku-4-5-20251001-v1:0` | 最快的 Claude |
|
||||
| Amazon Nova Pro | `us.amazon.nova-pro-v1:0` | Amazon 旗舰模型 |
|
||||
| Amazon Nova Micro | `us.amazon.nova-micro-v1:0` | 最快、最经济 |
|
||||
| DeepSeek V3.2 | `deepseek.v3.2` | 强大的开源模型 |
|
||||
| Llama 4 Scout 17B | `us.meta.llama4-scout-17b-instruct-v1:0` | Meta 最新模型 |
|
||||
|
||||
:::info 跨区域推理
|
||||
以 `us.` 为前缀的模型使用跨区域推理配置文件,可在多个 AWS 区域间提供更好的容量保障和自动故障转移。以 `global.` 为前缀的模型则在全球所有可用区域间路由。
|
||||
:::
|
||||
|
||||
## 会话中途切换模型
|
||||
|
||||
在对话过程中使用 `/model` 命令:
|
||||
|
||||
```
|
||||
/model us.amazon.nova-pro-v1:0
|
||||
/model deepseek.v3.2
|
||||
/model us.anthropic.claude-opus-4-6-v1
|
||||
```
|
||||
|
||||
## 诊断
|
||||
|
||||
```bash
|
||||
hermes doctor
|
||||
```
|
||||
|
||||
诊断工具会检查:
|
||||
- AWS 凭证是否可用(环境变量、IAM 角色、SSO)
|
||||
- `boto3` 是否已安装
|
||||
- Bedrock API 是否可达(ListFoundationModels)
|
||||
- 你所在区域的可用模型数量
|
||||
|
||||
## Gateway(消息平台)
|
||||
|
||||
Bedrock 可与所有 Hermes gateway 平台配合使用(Telegram、Discord、Slack、飞书等)。将 Bedrock 配置为提供商后,正常启动 gateway 即可:
|
||||
|
||||
```bash
|
||||
hermes gateway setup
|
||||
hermes gateway start
|
||||
```
|
||||
|
||||
Gateway 读取 `config.yaml` 并使用相同的 Bedrock 提供商配置。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### "No API key found" / "No AWS credentials"
|
||||
|
||||
Hermes 按以下顺序检查凭证:
|
||||
1. `AWS_BEARER_TOKEN_BEDROCK`
|
||||
2. `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`
|
||||
3. `AWS_PROFILE`
|
||||
4. EC2 实例元数据(IMDS)
|
||||
5. ECS 容器凭证
|
||||
6. Lambda 执行角色
|
||||
|
||||
若均未找到,请运行 `aws configure` 或为你的计算实例附加 IAM 角色。
|
||||
|
||||
### "Invocation of model ID ... with on-demand throughput isn't supported"
|
||||
|
||||
请使用**推理配置文件 ID**(以 `us.` 或 `global.` 为前缀),而非裸基础模型 ID。例如:
|
||||
- ❌ `anthropic.claude-sonnet-4-6`
|
||||
- ✅ `us.anthropic.claude-sonnet-4-6`
|
||||
|
||||
### "ThrottlingException"
|
||||
|
||||
你已触及 Bedrock 单模型速率限制。Hermes 会自动进行退避重试。如需提高限额,请在 [AWS Service Quotas 控制台](https://console.aws.amazon.com/servicequotas/)申请配额提升。
|
||||
|
||||
## 一键 AWS 部署
|
||||
|
||||
如需在 EC2 上通过 CloudFormation 进行全自动部署:
|
||||
|
||||
**[sample-hermes-agent-on-aws-with-bedrock](https://github.com/JiaDe-Wu/sample-hermes-agent-on-aws-with-bedrock)** — 自动创建 VPC、IAM 角色、EC2 实例并配置 Bedrock。一键即可在任意区域完成部署。
|
||||
@@ -0,0 +1,334 @@
|
||||
---
|
||||
sidebar_position: 15
|
||||
title: "Microsoft Foundry"
|
||||
description: "将 Hermes Agent 与 Microsoft Foundry 配合使用——OpenAI 风格与 Anthropic 风格端点、传输协议与已部署模型的自动检测"
|
||||
---
|
||||
|
||||
# Microsoft Foundry
|
||||
|
||||
Hermes Agent 的 `azure-foundry` provider 支持 Microsoft Foundry(原 Azure AI Foundry)和 Azure OpenAI。单个 Foundry 资源可以托管两种不同传输格式的模型:
|
||||
|
||||
- **OpenAI 风格** — 在 `https://<resource>.openai.azure.com/openai/v1` 等端点上执行 `POST /v1/chat/completions`。用于 GPT-4.x、GPT-5.x、Llama、Mistral 及大多数开放权重模型。
|
||||
- **Anthropic 风格** — 在 `https://<resource>.services.ai.azure.com/anthropic` 等端点上执行 `POST /v1/messages`。当 Microsoft Foundry 通过 Anthropic Messages API 格式提供 Claude 模型时使用。
|
||||
|
||||
设置向导会探测你的端点并自动检测所使用的传输协议、可用的部署以及每个模型的上下文长度。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- 一个至少包含一个部署的 Microsoft Foundry 或 Azure OpenAI 资源
|
||||
- 该部署的端点 URL
|
||||
- **以下之一**:API 密钥(从 Azure Portal 的"Keys and Endpoint"获取),**或者**在 Foundry 资源上拥有 **Azure AI User** RBAC 角色(如果你计划使用 Microsoft Entra ID——即 Microsoft 推荐的无密钥方式)。某些租户在 Microsoft 重命名推出期间可能将该角色显示为 **Foundry User**。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → 选择 "Azure Foundry"
|
||||
# → 输入你的端点 URL
|
||||
# → 选择认证方式:
|
||||
# 1. API key
|
||||
# 2. Microsoft Entra ID(托管标识 / 工作负载标识 / az login)
|
||||
# → (Entra)Hermes 探测 DefaultAzureCredential;成功后不再询问密钥
|
||||
# → (API key)输入你的 API 密钥
|
||||
# Hermes 探测端点并自动检测传输协议 + 模型
|
||||
# → 从列表中选择模型(或手动输入部署名称)
|
||||
```
|
||||
|
||||
向导将执行以下操作:
|
||||
|
||||
1. **嗅探 URL 路径** — 以 `/anthropic` 结尾的 URL 被识别为 Microsoft Foundry Claude 路由。
|
||||
2. **探测 `GET <base>/models`** — 如果端点返回 OpenAI 格式的模型列表,Hermes 切换到 `chat_completions` 并用返回的部署 ID 预填选择器。
|
||||
3. **探测 Anthropic Messages 格式** — 针对不暴露 `/models` 但接受 Anthropic Messages 格式的端点的回退方案。
|
||||
4. **回退到手动输入** — 拒绝所有探测的私有/受限端点仍然可用;你手动选择 API 模式并输入部署名称。
|
||||
|
||||
所选模型的上下文长度通过 Hermes 的标准元数据链(`models.dev`、provider 元数据及硬编码的系列回退)解析,并存储在 `config.yaml` 中,以便模型正确确定自身的上下文窗口大小。
|
||||
|
||||
## Microsoft Entra ID(无密钥,RBAC)——推荐
|
||||
|
||||
Microsoft 推荐在生产 Foundry 工作负载中使用 [Microsoft Entra ID 无密钥认证](https://learn.microsoft.com/azure/ai-foundry/foundry-models/how-to/configure-entra-id)。Hermes 对**两种** API 接口均支持 Entra ID:
|
||||
|
||||
- **OpenAI 风格**(`api_mode: chat_completions` / `codex_responses`)— GPT-4/5、Llama、Mistral、DeepSeek 等。
|
||||
- **Anthropic 风格**(`api_mode: anthropic_messages`)— Microsoft Foundry 上的 Claude 模型。
|
||||
|
||||
Foundry 的 RBAC 是按资源级别的(`Azure AI User` 授予两种接口的访问权限;某些租户可能显示为 `Foundry User`),Microsoft 文档对两者使用相同的推理 scope(`https://ai.azure.com/.default`)。底层实现:
|
||||
|
||||
- OpenAI 风格使用 OpenAI Python SDK 原生的可调用 `api_key=` 契约——SDK 每次请求自动生成新的 JWT。
|
||||
- Anthropic 风格使用带有请求事件 hook 的 `httpx.Client`,该 hook 由 `agent.azure_identity_adapter.build_bearer_http_client` 安装,因为 Anthropic SDK 原生不接受可调用的 `auth_token`。该 hook 在每次出站请求时重写 `Authorization: Bearer <fresh-jwt>`。RBAC 和 Foundry scope 相同——唯一的区别在于 SDK 契约。
|
||||
|
||||
### 为什么使用 Entra ID?
|
||||
|
||||
- 无需轮换或吊销长期有效的 API 密钥。
|
||||
- RBAC 驱动的访问控制——在 Foundry 资源上授予或移除 `Azure AI User`,无需重写配置。
|
||||
- 访问和审计日志按被分配者分段,而非所有调用者共享一个静态密钥。
|
||||
- 通过托管标识,为 Azure VM、AKS Pod、App Service、Functions、Container Apps 和 Foundry Agent Service 提供统一的认证接口。
|
||||
- 支持 CI/CD 流水线的工作负载标识和服务主体流程。
|
||||
|
||||
### 一次性设置(Azure 侧)
|
||||
|
||||
1. 在 Azure Portal 中,打开你的 Foundry 资源 → **访问控制 (IAM)** → **添加 → 添加角色分配**。
|
||||
2. 选择 **Azure AI User** 角色(如果你的租户已重命名,则选择 **Foundry User**)。
|
||||
3. 将其分配给:
|
||||
- **你的用户账户**,用于通过 `az login` 进行本地开发。
|
||||
- **托管标识或工作负载标识**,用于 Azure 托管计算(生产环境推荐)。
|
||||
- **Foundry Agent Service 托管 Agent 的 Agent 标识**,当 Hermes 在托管 Agent 内运行时。
|
||||
- **服务主体**,用于工作负载标识不可用时的 CI/CD 流水线。
|
||||
4. 等待约 5 分钟以使角色生效。
|
||||
|
||||
Azure CLI 等效命令:
|
||||
|
||||
```bash
|
||||
az role assignment create \
|
||||
--assignee <principal-or-agent-identity-client-id> \
|
||||
--role "Azure AI User" \
|
||||
--scope <foundry-resource-id>
|
||||
```
|
||||
|
||||
### 一次性设置(Hermes 侧)
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → 选择 "Azure Foundry"
|
||||
# → 输入你的端点 URL
|
||||
# → 认证方式:2(Microsoft Entra ID)
|
||||
# → (可选)用户分配的托管标识客户端 ID
|
||||
# → (可选)Azure 租户 ID
|
||||
# → Hermes 探测 DefaultAzureCredential() 并报告哪个内部凭据成功
|
||||
# (例如 AzureCliCredential、ManagedIdentityCredential)
|
||||
```
|
||||
|
||||
向导运行一个有时间限制的预检探测(10 秒超时)。失败时提供"仍然保存,稍后验证"选项——适用于在当前机器上尚无凭据但运行时会有凭据的场景(例如为托管标识部署准备配置)。
|
||||
|
||||
`azure-identity` 在首次使用时通过 Hermes 的懒加载安装路径自动安装。如需预先安装:
|
||||
|
||||
```bash
|
||||
pip install azure-identity
|
||||
```
|
||||
|
||||
### 写入 `config.yaml` 的配置
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: azure-foundry
|
||||
base_url: https://my-resource.openai.azure.com/openai/v1
|
||||
api_mode: chat_completions
|
||||
auth_mode: entra_id
|
||||
default: gpt-4o
|
||||
context_length: 128000
|
||||
entra:
|
||||
scope: https://ai.azure.com/.default # 仅在覆盖默认值时使用
|
||||
```
|
||||
|
||||
Hermes 在 `config.yaml` 中只管理一个 Entra 专属配置项:
|
||||
|
||||
- **`scope`** — OAuth 资源 scope。默认为 Microsoft 文档中的推理 scope(`https://ai.azure.com/.default`)。仅在你的资源针对非标准 audience 进行了预配时才需要覆盖。
|
||||
|
||||
其他所有内容(租户、服务主体密钥、联合令牌文件、主权云 authority、broker 偏好)均由 `azure-identity` 直接从标准 `AZURE_*` 环境变量读取——参见下方的[凭据解析顺序](#credential-resolution-order)。在 `~/.hermes/.env` 或你的部署环境中设置这些变量,与 Microsoft SDK 参考文档的描述完全一致。
|
||||
|
||||
Entra 模式下不会将任何密钥写入 `~/.hermes/.env`——`azure-identity` 在进程内缓存令牌(在可用时也会使用操作系统密钥链 / `~/.IdentityService`)。
|
||||
|
||||
### 凭据解析顺序
|
||||
|
||||
`azure-identity` 的 `DefaultAzureCredential` 在每次令牌请求时按以下链路逐一尝试,在第一个返回令牌的凭据处停止:
|
||||
|
||||
1. **环境凭据** — `AZURE_TENANT_ID` + `AZURE_CLIENT_ID` + `AZURE_CLIENT_SECRET`(或 `AZURE_CLIENT_CERTIFICATE_PATH` / `AZURE_FEDERATED_TOKEN_FILE`)。
|
||||
2. **工作负载标识** — `AZURE_FEDERATED_TOKEN_FILE`(AKS 联合令牌 / OIDC)。
|
||||
3. **托管标识** — 虚拟机使用 IMDS 端点(`169.254.169.254`);App Service / Functions / Container Apps 使用 `IDENTITY_ENDPOINT`。Foundry Agent Service 托管 Agent 使用托管 Agent 的 Agent 标识。
|
||||
4. **Visual Studio Code** — Azure 账户扩展。
|
||||
5. **Azure CLI** — `az login` 会话。
|
||||
6. **Azure Developer CLI** — `azd auth login`。
|
||||
7. **Azure PowerShell** — `Connect-AzAccount`。
|
||||
8. **Broker**(仅限 Windows / WSL)— Web Account Manager。
|
||||
|
||||
交互式浏览器凭据在无人值守的 Hermes 运行中默认被排除;请改用 Azure CLI、Azure Developer CLI、托管标识、工作负载标识或服务主体凭据。
|
||||
|
||||
### 部署模式
|
||||
|
||||
**本地开发:**
|
||||
```bash
|
||||
az login
|
||||
hermes model # 选择 Azure Foundry → Entra ID
|
||||
hermes # 使用你的 az login 令牌
|
||||
```
|
||||
|
||||
**Azure VM / Functions / App Service / Container Apps(系统分配的托管标识):**
|
||||
1. 在计算资源上启用系统分配的标识。
|
||||
2. 在 Foundry 资源上为该标识授予 `Azure AI User`(或 `Foundry User`)角色。
|
||||
3. 在 config.yaml 中设置 `model.auth_mode: entra_id`——无需环境变量。
|
||||
|
||||
**Azure VM / Functions / App Service / Container Apps(用户分配的托管标识):**
|
||||
- 将 `AZURE_CLIENT_ID` 设置为用户分配标识的客户端 ID,以便 `DefaultAzureCredential` 选择正确的标识。
|
||||
|
||||
**Foundry Agent Service 托管 Agent:**
|
||||
- 创建托管 Agent 并在 Foundry 资源上为该 Agent 的标识授予 `Azure AI User`(或 `Foundry User`)角色。Hermes 在托管 Agent 内部使用 `ManagedIdentityCredential`;角色分配应针对 Agent 标识,而非仅针对父项目或你的用户。
|
||||
|
||||
**AKS 工作负载标识(替代 AAD Pod Identity):**
|
||||
- 使用工作负载标识客户端 ID 注解 Pod 的服务账户。
|
||||
- Pod 的联合令牌文件通过 `AZURE_FEDERATED_TOKEN_FILE` 自动检测。
|
||||
- `model.auth_mode: entra_id` 无需进一步修改配置即可使用。
|
||||
|
||||
**CI 中的服务主体:**
|
||||
- 在 runner 环境中设置 `AZURE_TENANT_ID`、`AZURE_CLIENT_ID`、`AZURE_CLIENT_SECRET`。
|
||||
|
||||
#### 主权云(政府云、中国云)
|
||||
|
||||
导出 `AZURE_AUTHORITY_HOST`(例如 Azure Government 使用 `https://login.microsoftonline.us`,Azure China 使用 `https://login.partner.microsoftonline.cn`)。`azure-identity` 会直接读取该变量。
|
||||
|
||||
### 健康检查
|
||||
|
||||
当 `model.auth_mode: entra_id` 时,`hermes doctor` 会对 `DefaultAzureCredential` 运行 10 秒探测,报告哪个内部凭据成功(环境变量是否存在、托管标识端点是否可达等)。
|
||||
|
||||
`hermes auth` 显示结构化状态块:
|
||||
|
||||
```
|
||||
azure-foundry (Microsoft Entra ID):
|
||||
Endpoint: https://my-resource.openai.azure.com/openai/v1
|
||||
Scope: https://ai.azure.com/.default
|
||||
Status: configured; live token probe is skipped here
|
||||
```
|
||||
|
||||
### 限制
|
||||
|
||||
- **Anthropic 风格端点使用 httpx 事件 hook。** Anthropic Python SDK(≤ 0.86.0)原生不接受可调用的 `auth_token`。Hermes 在自定义 `httpx.Client` 上安装请求事件 hook,每次出站请求时生成新的 JWT 并重写 `Authorization: Bearer <jwt>`。这在功能上等同于 OpenAI SDK 原生的 `Callable[[], str]` 契约,但多了一层间接调用。如果 Anthropic SDK 在未来版本中添加对可调用认证的原生支持,Hermes 将透明地切换到该方式。
|
||||
- **批处理任务与 `multiprocessing.Pool`。** Entra 令牌 provider 是一个闭包,无法跨进程边界序列化。`batch_runner.py` 会自动从 worker 配置中移除该可调用对象,让每个 worker 进程从 `config.yaml` 重建自己的 provider——无需用户操作,但每个 worker 在启动时需要执行一次凭据链遍历。
|
||||
- **不在 `auth.json` 中持久化 Bearer JWT。** Hermes 不复制 `azure-identity` 的内部令牌缓存;冷启动时会在首次推理时遍历凭据链。
|
||||
|
||||
## 配置(写入 `config.yaml`)
|
||||
|
||||
运行向导后,你将看到类似如下的内容:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: azure-foundry
|
||||
base_url: https://my-resource.openai.azure.com/openai/v1
|
||||
api_mode: chat_completions # 或 "anthropic_messages"
|
||||
default: gpt-5.4-mini # 你的部署 / 模型名称
|
||||
context_length: 400000 # 自动检测
|
||||
```
|
||||
|
||||
以及在 `~/.hermes/.env` 中:
|
||||
|
||||
```
|
||||
AZURE_FOUNDRY_API_KEY=<your-azure-key>
|
||||
```
|
||||
|
||||
## OpenAI 风格端点(GPT、Llama 等)
|
||||
|
||||
Azure OpenAI 的 v1 GA 端点接受标准 `openai` Python 客户端,改动极少:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: azure-foundry
|
||||
base_url: https://my-resource.openai.azure.com/openai/v1
|
||||
api_mode: chat_completions
|
||||
default: gpt-5.4
|
||||
```
|
||||
|
||||
重要行为:
|
||||
|
||||
- **GPT-5.x、codex 和 o 系列自动路由到 Responses API。** Microsoft Foundry 将 GPT-5 / codex / o1 / o3 / o4 模型部署为仅支持 Responses API——对其调用 `/chat/completions` 会返回 `400 "The requested operation is unsupported."`。Hermes 通过名称检测这些模型系列,并透明地将 `api_mode` 升级为 `codex_responses`,即使 `config.yaml` 中仍写着 `api_mode: chat_completions`。GPT-4、GPT-4o、Llama、Mistral 及其他部署保持使用 `/chat/completions`。
|
||||
- **自动使用 `max_completion_tokens`。** Azure OpenAI(与直接使用 OpenAI 一样)对 gpt-4o、o 系列和 gpt-5.x 模型要求使用 `max_completion_tokens`。Hermes 根据端点发送正确的参数。
|
||||
- **需要 `api-version` 的旧版端点。** 如果你有类似 `https://<resource>.openai.azure.com/openai?api-version=2025-04-01-preview` 的旧版 base URL,Hermes 会提取查询字符串并通过每次请求的 `default_query` 转发(否则 OpenAI SDK 在拼接路径时会丢弃它)。
|
||||
|
||||
## Anthropic 风格端点(通过 Microsoft Foundry 使用 Claude)
|
||||
|
||||
对于 Claude 部署,使用 Anthropic 风格路由:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: azure-foundry
|
||||
base_url: https://my-resource.services.ai.azure.com/anthropic
|
||||
api_mode: anthropic_messages
|
||||
default: claude-sonnet-4-6
|
||||
```
|
||||
|
||||
重要行为:
|
||||
|
||||
- **从 base URL 中去除 `/v1`。** Anthropic SDK 在每次请求 URL 后追加 `/v1/messages`——Hermes 在将 URL 传递给 SDK 之前移除末尾的 `/v1`,以避免出现双重 `/v1` 路径。
|
||||
- **`api-version` 通过 `default_query` 传递,而非追加到 URL。** Azure Anthropic 要求 `api-version` 查询字符串。将其嵌入 base URL 会产生类似 `/anthropic?api-version=.../v1/messages` 的畸形路径并返回 404。Hermes 通过 Anthropic SDK 的 `default_query` 传递 `api-version=2025-04-15`。
|
||||
- **使用 Bearer 认证而非 `x-api-key`。** Azure 的 Anthropic 兼容路由要求 `Authorization: Bearer <key>`,而非 Anthropic 原生的 `x-api-key` 头。Hermes 检测到 base URL 中包含 `azure.com` 时,通过 SDK 的 `auth_token` 字段路由 API 密钥,确保正确的头部到达上游。
|
||||
- **保留 1M 上下文窗口 beta 头。** Azure 仍通过 `anthropic-beta: context-1m-2025-08-07` 头控制 1M token Claude 上下文(Opus 4.6/4.7、Sonnet 4.6)的访问。Hermes 在 Azure 路径上保留该 beta 头(在原生 Anthropic OAuth 请求中会被去除,因为某些订阅会拒绝它,但 Azure 要求它)。
|
||||
- **禁用 OAuth 令牌刷新。** Azure 部署使用静态 API 密钥。适用于 Anthropic Console 的 `~/.claude/.credentials.json` OAuth 令牌刷新循环对 Azure 端点明确跳过,以防止 Claude Code OAuth 令牌在会话中途覆盖你的 Azure 密钥。
|
||||
|
||||
## 替代方案:`provider: anthropic` + Azure base URL
|
||||
|
||||
如果你已配置 `provider: anthropic` 并只想将其指向 Microsoft Foundry 以使用 Claude,可以完全跳过 `azure-foundry` provider:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: anthropic
|
||||
base_url: https://my-resource.services.ai.azure.com/anthropic
|
||||
key_env: AZURE_ANTHROPIC_KEY
|
||||
default: claude-sonnet-4-6
|
||||
```
|
||||
|
||||
在 `~/.hermes/.env` 中设置 `AZURE_ANTHROPIC_KEY`。Hermes 检测到 base URL 中包含 `azure.com` 时,会绕过 Claude Code OAuth 令牌链,直接使用 Azure 密钥进行 `x-api-key` 认证。
|
||||
|
||||
`key_env` 是规范的 snake_case 字段名;`api_key_env`(以及驼峰式 `keyEnv` / `apiKeyEnv`)作为别名被接受。如果同时设置了 `key_env` 和 `AZURE_ANTHROPIC_KEY`/`ANTHROPIC_API_KEY`,`key_env` 指定的环境变量优先。
|
||||
|
||||
## 模型发现
|
||||
|
||||
Azure **不**暴露纯 API 密钥端点来列出你的*已部署*模型部署。部署枚举需要 Azure Resource Manager 认证(`az cognitiveservices account deployment list`)和 Azure AD 主体,而非推理 API 密钥。
|
||||
|
||||
Hermes 能做的:
|
||||
|
||||
- Azure OpenAI v1 端点(`<resource>.openai.azure.com/openai/v1`)通过 `GET /models` 暴露资源的**可用**模型目录。Hermes 使用此列表预填模型选择器。
|
||||
- Microsoft Foundry `/anthropic` 路由:通过 URL 路径检测,模型名称手动输入。
|
||||
- 私有 / 防火墙后的端点:手动输入,并显示友好的"无法探测"提示。
|
||||
|
||||
你始终可以直接输入部署名称——Hermes 不会对返回的列表进行验证。
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量 | 用途 |
|
||||
|----------|---------|
|
||||
| `AZURE_FOUNDRY_API_KEY` | Microsoft Foundry / Azure OpenAI 的主 API 密钥(api_key 模式) |
|
||||
| `AZURE_FOUNDRY_BASE_URL` | 端点 URL(通过 `hermes model` 设置;环境变量作为回退) |
|
||||
| `AZURE_ANTHROPIC_KEY` | 由 `provider: anthropic` + Azure base URL 使用(`ANTHROPIC_API_KEY` 的替代) |
|
||||
| `AZURE_TENANT_ID` | 服务主体流程的 Entra ID 租户 |
|
||||
| `AZURE_CLIENT_ID` | Entra ID 客户端 ID(服务主体、工作负载标识或用户分配的托管标识) |
|
||||
| `AZURE_CLIENT_SECRET` | 服务主体密钥 |
|
||||
| `AZURE_CLIENT_CERTIFICATE_PATH` | 服务主体证书(密钥的替代方案) |
|
||||
| `AZURE_FEDERATED_TOKEN_FILE` | 工作负载标识联合令牌路径(AKS) |
|
||||
| `AZURE_AUTHORITY_HOST` | 主权云 authority 主机覆盖 |
|
||||
| `IDENTITY_ENDPOINT` / `MSI_ENDPOINT` | App Service、Functions 和 Container Apps 的托管标识端点;VM 通常改用 IMDS |
|
||||
|
||||
Azure SDK 直接读取 `AZURE_*` 环境变量。Hermes 除在 `hermes doctor` 输出中报告哪些来源存在外,不会检查这些变量。
|
||||
|
||||
## 故障排查
|
||||
|
||||
**gpt-5.x 部署返回 401 Unauthorized。**
|
||||
Azure 在 `/chat/completions` 上提供 gpt-5.x,而非 `/responses`。当 URL 包含 `openai.azure.com` 时,Hermes 会自动处理此问题,但如果你看到带有 `Invalid API key` 正文的 401,请检查 `config.yaml` 中的 `api_mode` 是否为 `chat_completions`。
|
||||
|
||||
**`/v1/messages?api-version=.../v1/messages` 返回 404。**
|
||||
这是修复前 Azure Anthropic 设置中的畸形 URL 问题。升级 Hermes——`api-version` 参数现在通过 `default_query` 传递,而非嵌入 base URL,因此 SDK 在 URL 拼接时不会破坏它。
|
||||
|
||||
**向导提示"自动检测不完整"。**
|
||||
端点拒绝了 `/models` 探测和 Anthropic Messages 探测。这对于防火墙后或设有 IP 白名单的私有端点是正常现象。回退到手动选择 API 模式并输入部署名称——一切仍然正常工作,Hermes 只是无法预填选择器。
|
||||
|
||||
**选择了错误的传输协议。**
|
||||
再次运行 `hermes model`,向导将重新探测。如果探测仍然选择了错误的模式,可以直接编辑 `config.yaml`:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
provider: azure-foundry
|
||||
api_mode: anthropic_messages # 或 chat_completions
|
||||
```
|
||||
|
||||
**Entra ID:"credential chain exhausted" 或切换到 `auth_mode: entra_id` 后返回 401 Unauthorized。**
|
||||
- 运行 `az login` 刷新你的开发者会话(缓存的令牌可能已过期)。
|
||||
- 验证 `Azure AI User`(或 `Foundry User`)角色分配是否已生效:`az role assignment list --assignee <user-or-identity-id>` 应在你的 Foundry 资源上列出该角色。角色传播最多需要 5 分钟。
|
||||
- 对于用户分配的托管标识,请仔细检查 `AZURE_CLIENT_ID` 是否与附加到计算资源的标识匹配。
|
||||
- 运行 `hermes doctor`——Azure Entra 探测会报告令牌获取是否成功,并提供修复提示。
|
||||
|
||||
**Entra ID:向导预检挂起或超时。**
|
||||
10 秒预检是软性检查。选择"仍然保存,稍后验证",部署到目标环境后运行 `hermes doctor`。常见原因包括令牌服务不可达或本地登录状态过期——在 CI 中优先使用工作负载标识,使用服务主体时设置 `AZURE_TENANT_ID`+`AZURE_CLIENT_ID`+`AZURE_CLIENT_SECRET`,或在本地开发时运行 `az login`。
|
||||
|
||||
**Anthropic 风格端点使用 Entra ID 时返回 401。**
|
||||
验证同一 `Azure AI User`(或 `Foundry User`)角色是否已在 Foundry 资源上分配(它同时覆盖 `/openai/v1` 和 `/anthropic` 路径)。如果向导期间 OpenAI 风格探测成功,但运行时 `claude-*` 请求失败,最常见的原因是早期向导运行遗留的过时 `model.entra.scope`——从 `config.yaml` 中删除 `entra.scope` 行,使运行时回退到默认的 `https://ai.azure.com/.default` scope。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [环境变量](/reference/environment-variables)
|
||||
- [配置](/user-guide/configuration)
|
||||
- [AWS Bedrock](/guides/aws-bedrock) — 另一个主要的云 provider 集成
|
||||
- [Microsoft:为 Foundry 配置 Entra ID](https://learn.microsoft.com/azure/ai-foundry/foundry-models/how-to/configure-entra-id) — 无密钥路径的上游文档
|
||||
+1153
File diff suppressed because it is too large
Load Diff
+247
@@ -0,0 +1,247 @@
|
||||
---
|
||||
sidebar_position: 13
|
||||
title: "纯脚本 Cron 任务(无 LLM)"
|
||||
description: "完全跳过 LLM 的经典看门狗 cron 任务——脚本按计划运行,其 stdout 输出直接投递到你的消息平台。内存告警、磁盘告警、CI 通知、定期健康检查。"
|
||||
---
|
||||
|
||||
# 纯脚本 Cron 任务
|
||||
|
||||
有时你已经清楚地知道要发送什么消息。你不需要 agent 来推理——你只需要一个脚本按计时器运行,并将其输出(如有)发送到 Telegram / Discord / Slack / Signal。
|
||||
|
||||
Hermes 将此称为**无 agent 模式**。这是去掉 LLM 的 cron 系统。
|
||||
|
||||
<!-- ascii-guard-ignore -->
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ scheduler tick │ every │ run script │
|
||||
│ (every N minutes)│ ──────▶ │ (bash or python) │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
│
|
||||
│ stdout
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ delivery router │
|
||||
│ (telegram/disc…) │
|
||||
└──────────────────┘
|
||||
```
|
||||
<!-- ascii-guard-ignore-end -->
|
||||
|
||||
- **无 LLM 调用。** 零 token,零 agent 循环,零模型费用。
|
||||
- **脚本即任务。** 由脚本决定是否告警。有输出 → 发送消息;无输出 → 静默执行。
|
||||
- **Bash 或 Python。** `.sh` / `.bash` 文件在 `/bin/bash` 下运行;其他扩展名在当前 Python 解释器下运行。`~/.hermes/scripts/` 中的任何文件均可接受。
|
||||
- **同一调度器。** 与 LLM 任务共存于 `cronjob` 中——暂停、恢复、列出、日志和投递目标的操作方式完全相同。
|
||||
|
||||
## 适用场景
|
||||
|
||||
以下情况使用无 agent 模式:
|
||||
|
||||
- **内存 / 磁盘 / GPU 看门狗。** 每 5 分钟运行一次,仅在超过阈值时告警。
|
||||
- **CI hook(钩子)。** 部署完成 → 发送 commit SHA;构建失败 → 发送最后 100 行日志。
|
||||
- **定期指标。** "每天上午 9 点的 Stripe 收入"——一次简单的 API 调用加格式化输出。
|
||||
- **外部事件轮询。** 检查 API,在状态变化时告警。
|
||||
- **心跳。** 每 N 分钟 ping 一次仪表板,证明主机存活。
|
||||
|
||||
当你需要 agent **决定**说什么时——总结长文档、从 feed 中挑选有趣条目、起草友好提醒——请使用普通的(LLM 驱动的)cron 任务。无 agent 路径适用于脚本的 stdout 本身就是消息内容的场景。
|
||||
|
||||
## 通过聊天创建
|
||||
|
||||
无 agent 模式的真正优势在于:agent 本身可以为你设置看门狗——无需编辑器、无需 shell、无需记忆 CLI 参数。你描述需求,Hermes 编写脚本、安排计划,并告知你何时触发。
|
||||
|
||||
### 示例对话
|
||||
|
||||
> **你:** 每 5 分钟检查一次,如果内存超过 85% 就在 telegram 通知我
|
||||
>
|
||||
> **Hermes:** *(写入 `~/.hermes/scripts/memory-watchdog.sh`,然后以 `no_agent=true` 调用 `cronjob(...)`)*
|
||||
>
|
||||
> 已设置。每 5 分钟运行一次,仅在内存超过 85% 时告警 Telegram。脚本:`memory-watchdog.sh`。任务 ID:`abc123`。
|
||||
|
||||
在底层,agent 进行了两次工具调用:
|
||||
|
||||
```python
|
||||
# 1. 写入检查脚本
|
||||
write_file(
|
||||
path="~/.hermes/scripts/memory-watchdog.sh",
|
||||
content='''#!/usr/bin/env bash
|
||||
ram_pct=$(free | awk '/^Mem:/ {printf "%d", $3 * 100 / $2}')
|
||||
if [ "$ram_pct" -ge 85 ]; then
|
||||
echo "RAM ${ram_pct}% on $(hostname)"
|
||||
fi
|
||||
# Empty stdout = silent tick; no message sent.
|
||||
''',
|
||||
)
|
||||
|
||||
# 2. 调度任务 — no_agent=True 在每次触发时跳过 LLM
|
||||
cronjob(
|
||||
action="create",
|
||||
schedule="every 5m",
|
||||
script="memory-watchdog.sh",
|
||||
no_agent=True,
|
||||
deliver="telegram",
|
||||
name="memory-watchdog",
|
||||
)
|
||||
```
|
||||
|
||||
此后每次触发都是免费的:调度器运行脚本,若 stdout 非空则将其发送到 Telegram,且从不调用模型。
|
||||
|
||||
### agent 为你决定的内容
|
||||
|
||||
当你的请求类似"当 X 时告警我"或"每 N 分钟检查 Y,如果 Z 则通知我",Hermes 的 `cronjob` 工具描述会指示它在消息内容完全由脚本决定时使用 `no_agent=True`。当请求需要推理时(*"总结新 issue"*、*"挑选最有趣的头条"*、*"起草一条友好提醒"*),则回退到普通的 LLM 驱动路径。
|
||||
|
||||
你不必自己指定 `--no-agent`。只需描述你想要的行为即可。
|
||||
|
||||
### 通过聊天管理看门狗
|
||||
|
||||
agent 可以用与创建任务相同的方式暂停、恢复、编辑和删除任务:
|
||||
|
||||
> **你:** 今晚先停掉内存看门狗
|
||||
>
|
||||
> **Hermes:** *(调用 `cronjob(action='pause', job_id='abc123')`)*
|
||||
>
|
||||
> 已暂停。说"重新开启"或执行 `hermes cron resume abc123` 可恢复。
|
||||
|
||||
> **你:** 改成每 15 分钟一次
|
||||
>
|
||||
> **Hermes:** *(调用 `cronjob(action='update', job_id='abc123', schedule='every 15m')`)*
|
||||
|
||||
完整生命周期(创建 / 列出 / 更新 / 暂停 / 恢复 / 立即运行 / 删除)均可由 agent 操作,无需你学习任何 CLI 命令。
|
||||
|
||||
## 通过 CLI 创建
|
||||
|
||||
偏好 shell?CLI 路径用三条命令即可达到相同效果:
|
||||
|
||||
```bash
|
||||
# 1. 编写脚本
|
||||
cat > ~/.hermes/scripts/memory-watchdog.sh <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Alert when RAM usage is over 85%. Silent otherwise.
|
||||
RAM_PCT=$(free | awk '/^Mem:/ {printf "%d", $3 * 100 / $2}')
|
||||
if [ "$RAM_PCT" -ge 85 ]; then
|
||||
echo "⚠ RAM ${RAM_PCT}% on $(hostname)"
|
||||
fi
|
||||
# Empty stdout = silent run; no message sent.
|
||||
EOF
|
||||
chmod +x ~/.hermes/scripts/memory-watchdog.sh
|
||||
|
||||
# 2. 调度任务
|
||||
hermes cron create "every 5m" \
|
||||
--no-agent \
|
||||
--script memory-watchdog.sh \
|
||||
--deliver telegram \
|
||||
--name "memory-watchdog"
|
||||
|
||||
# 3. 验证
|
||||
hermes cron list
|
||||
hermes cron run <job_id> # 触发一次以测试
|
||||
```
|
||||
|
||||
就这些。无 prompt(提示词),无技能,无模型。
|
||||
|
||||
|
||||
## 脚本输出与投递的映射关系
|
||||
|
||||
| 脚本行为 | 结果 |
|
||||
|-----------------|--------|
|
||||
| 退出码 0,stdout 非空 | stdout 原样投递 |
|
||||
| 退出码 0,stdout 为空 | 静默执行——不投递 |
|
||||
| 退出码 0,stdout 最后一行包含 `{"wakeAgent": false}` | 静默执行(与 LLM 任务共用的门控) |
|
||||
| 非零退出码 | 投递错误告警(确保损坏的看门狗不会静默失败) |
|
||||
| 脚本超时 | 投递错误告警 |
|
||||
|
||||
"空则静默"的行为是经典看门狗模式的关键:脚本可以每分钟运行一次,但只有在真正需要关注时,频道才会收到消息。
|
||||
|
||||
## 脚本规则
|
||||
|
||||
脚本必须位于 `~/.hermes/scripts/`。这在任务创建时和运行时均会强制检查——绝对路径、`~/` 展开以及路径穿越模式(`../`)均会被拒绝。该目录与 LLM 任务使用的预检脚本门控共享。
|
||||
|
||||
解释器由文件扩展名决定:
|
||||
|
||||
| 扩展名 | 解释器 |
|
||||
|-----------|-------------|
|
||||
| `.sh`、`.bash` | `/bin/bash` |
|
||||
| 其他任意扩展名 | `sys.executable`(当前 Python) |
|
||||
|
||||
我们有意**不**遵循 `#!/...` shebang——保持解释器集合明确且精简,可减少调度器信任的攻击面。
|
||||
|
||||
## 计划语法
|
||||
|
||||
与所有其他 cron 任务相同:
|
||||
|
||||
```bash
|
||||
hermes cron create "every 5m" # 间隔
|
||||
hermes cron create "every 2h"
|
||||
hermes cron create "0 9 * * *" # 标准 cron:每天上午 9 点
|
||||
hermes cron create "30m" # 单次:30 分钟后运行一次
|
||||
```
|
||||
|
||||
完整语法请参阅 [cron 功能参考](/user-guide/features/cron)。
|
||||
|
||||
## 投递目标
|
||||
|
||||
`--deliver` 接受 gateway 已知的所有目标。常见形式:
|
||||
|
||||
```bash
|
||||
--deliver telegram # 平台默认频道
|
||||
--deliver telegram:-1001234567890 # 指定聊天
|
||||
--deliver telegram:-1001234567890:17585 # 指定 Telegram 论坛话题
|
||||
--deliver discord:#ops
|
||||
--deliver slack:#engineering
|
||||
--deliver signal:+15551234567
|
||||
--deliver local # 仅保存到 ~/.hermes/cron/output/
|
||||
```
|
||||
|
||||
对于使用 bot token 的平台(Telegram、Discord、Slack、Signal、SMS、WhatsApp),脚本运行时无需运行中的 gateway——工具直接使用 `~/.hermes/.env` / `~/.hermes/config.yaml` 中已有的凭据调用各平台的 REST 端点。
|
||||
|
||||
## 编辑与生命周期
|
||||
|
||||
```bash
|
||||
hermes cron list # 查看所有任务
|
||||
hermes cron pause <job_id> # 停止触发,保留定义
|
||||
hermes cron resume <job_id>
|
||||
hermes cron edit <job_id> --schedule "every 10m" # 调整频率
|
||||
hermes cron edit <job_id> --agent # 切换为 LLM 模式
|
||||
hermes cron edit <job_id> --no-agent --script … # 切换回无 agent 模式
|
||||
hermes cron remove <job_id> # 删除任务
|
||||
```
|
||||
|
||||
所有适用于 LLM 任务的操作(暂停、恢复、手动触发、投递目标变更)同样适用于无 agent 任务。
|
||||
|
||||
## 实战示例:磁盘空间告警
|
||||
|
||||
```bash
|
||||
cat > ~/.hermes/scripts/disk-alert.sh <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Alert when / or /home is over 90% full.
|
||||
THRESHOLD=90
|
||||
df -h / /home 2>/dev/null | awk -v t="$THRESHOLD" '
|
||||
NR > 1 && $5+0 >= t {
|
||||
printf "⚠ Disk %s full on %s\n", $5, $6
|
||||
}
|
||||
'
|
||||
EOF
|
||||
chmod +x ~/.hermes/scripts/disk-alert.sh
|
||||
|
||||
hermes cron create "*/15 * * * *" \
|
||||
--no-agent \
|
||||
--script disk-alert.sh \
|
||||
--deliver telegram \
|
||||
--name "disk-alert"
|
||||
```
|
||||
|
||||
当两个文件系统均低于 90% 时静默;当某个文件系统超出阈值时,每个超限文件系统触发一行告警。
|
||||
|
||||
## 与其他模式的对比
|
||||
|
||||
| 方式 | 运行内容 | 适用场景 |
|
||||
|----------|-----------|-------------|
|
||||
| `cronjob --no-agent`(本页) | 你的脚本,由 Hermes 调度 | 不需要推理的周期性看门狗 / 告警 / 指标 |
|
||||
| `cronjob`(默认,LLM) | 带可选预检脚本的 agent | 消息内容需要对数据进行推理时 |
|
||||
| OS cron + `curl` 到 [webhook 订阅](/user-guide/messaging/webhooks) | 你的脚本,由 OS 调度 | 当 Hermes 本身可能不健康时(即被监控对象) |
|
||||
|
||||
对于必须在 **gateway 宕机时也能触发**的关键系统健康看门狗,请使用 OS 级 cron 配合 `curl` 调用 Hermes webhook 订阅(或任何外部告警端点)——这些作为独立 OS 进程运行,不依赖 Hermes 是否在线。当被监控对象是外部系统时,in-gateway 调度器才是正确选择。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [用 Cron 自动化一切](/guides/automate-with-cron) — LLM 驱动的 cron 模式。
|
||||
- [定时任务(Cron)参考](/user-guide/features/cron) — 完整计划语法、生命周期、投递路由。
|
||||
- [Webhook 订阅](/user-guide/messaging/webhooks) — 供外部调度器使用的即发即忘 HTTP 入口。
|
||||
- [Gateway 内部机制](/developer-guide/gateway-internals) — 投递路由器内部实现。
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
---
|
||||
sidebar_position: 12
|
||||
title: "Cron 故障排查"
|
||||
description: "诊断并修复常见的 Hermes cron 问题——任务未触发、投递失败、skill 加载错误及性能问题"
|
||||
---
|
||||
|
||||
# Cron 故障排查
|
||||
|
||||
当 cron 任务行为异常时,请按顺序逐项检查。大多数问题属于以下四类之一:时序、投递、权限或 skill 加载。
|
||||
|
||||
---
|
||||
|
||||
## 任务未触发
|
||||
|
||||
### 检查 1:确认任务存在且处于活跃状态
|
||||
|
||||
```bash
|
||||
hermes cron list
|
||||
```
|
||||
|
||||
找到该任务并确认其状态为 `[active]`(而非 `[paused]` 或 `[completed]`)。若显示 `[completed]`,可能是重复次数已耗尽——编辑该任务以重置。
|
||||
|
||||
### 检查 2:确认调度表达式正确
|
||||
|
||||
格式错误的调度表达式会静默降级为单次执行,或被直接拒绝。测试你的表达式:
|
||||
|
||||
| 你的表达式 | 应解析为 |
|
||||
|----------------|-------------------|
|
||||
| `0 9 * * *` | 每天上午 9:00 |
|
||||
| `0 9 * * 1` | 每周一上午 9:00 |
|
||||
| `every 2h` | 从现在起每 2 小时 |
|
||||
| `30m` | 从现在起 30 分钟后 |
|
||||
| `2025-06-01T09:00:00` | 2025 年 6 月 1 日 09:00 UTC |
|
||||
|
||||
若任务触发一次后从列表中消失,说明这是单次调度(`30m`、`1d` 或 ISO 时间戳)——属于预期行为。
|
||||
|
||||
### 检查 3:gateway 是否正在运行?
|
||||
|
||||
Cron 任务由 gateway 的后台 ticker 线程触发,该线程每 60 秒 tick 一次。普通的 CLI 聊天会话**不会**自动触发 cron 任务。
|
||||
|
||||
如果你期望任务自动触发,需要运行一个 gateway(前台运行用 `hermes gateway`,安装为服务用 `hermes gateway start`)。如需单次调试,可手动触发一次 tick:`hermes cron tick`。
|
||||
|
||||
### 检查 4:检查系统时钟和时区
|
||||
|
||||
任务使用本地时区。若机器时钟有误或时区与预期不符,任务将在错误的时间触发。验证方法:
|
||||
|
||||
```bash
|
||||
date
|
||||
hermes cron list # 将 next_run 时间与本地时间对比
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 投递失败
|
||||
|
||||
### 检查 1:确认投递目标正确
|
||||
|
||||
投递目标区分大小写,且要求对应平台已正确配置。目标配置错误会静默丢弃响应。
|
||||
|
||||
| 目标 | 所需配置 |
|
||||
|--------|----------|
|
||||
| `telegram` | `~/.hermes/.env` 中的 `TELEGRAM_BOT_TOKEN` |
|
||||
| `discord` | `~/.hermes/.env` 中的 `DISCORD_BOT_TOKEN` |
|
||||
| `slack` | `~/.hermes/.env` 中的 `SLACK_BOT_TOKEN` |
|
||||
| `whatsapp` | 已配置 WhatsApp gateway |
|
||||
| `signal` | 已配置 Signal gateway |
|
||||
| `matrix` | 已配置 Matrix homeserver |
|
||||
| `email` | `config.yaml` 中已配置 SMTP |
|
||||
| `sms` | 已配置 SMS 提供商 |
|
||||
| `local` | 对 `~/.hermes/cron/output/` 有写权限 |
|
||||
| `origin` | 投递到创建该任务的聊天会话 |
|
||||
|
||||
其他支持的平台包括 `mattermost`、`homeassistant`、`dingtalk`、`feishu`、`wecom`、`weixin`、`bluebubbles`、`qqbot` 和 `webhook`。你也可以使用 `platform:chat_id` 语法指定特定聊天(例如 `telegram:-1001234567890`)。
|
||||
|
||||
若投递失败,任务仍会执行——只是不会发送到任何地方。检查 `hermes cron list` 中的 `last_error` 字段(如有)。
|
||||
|
||||
### 检查 2:检查 `[SILENT]` 的使用
|
||||
|
||||
若你的 cron 任务没有输出,或 agent 响应为 `[SILENT]`,投递会被抑制。这对监控类任务是预期行为——但请确认你的 prompt(提示词)没有意外地抑制所有输出。
|
||||
|
||||
若 prompt 中写有"如果没有变化则回复 [SILENT]",非空响应也可能被静默吞掉。请检查你的条件逻辑。
|
||||
|
||||
### 检查 3:平台 token 权限
|
||||
|
||||
每个消息平台的 bot 需要特定权限才能发送消息。若投递静默失败:
|
||||
|
||||
- **Telegram**:Bot 必须是目标群组/频道的管理员
|
||||
- **Discord**:Bot 必须有目标频道的发送权限
|
||||
- **Slack**:Bot 必须已加入工作区并拥有 `chat:write` scope
|
||||
|
||||
### 检查 4:响应包装
|
||||
|
||||
默认情况下,cron 响应会添加页眉和页脚(`config.yaml` 中的 `cron.wrap_response: true`)。某些平台或集成可能无法正常处理。如需禁用:
|
||||
|
||||
```yaml
|
||||
cron:
|
||||
wrap_response: false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Skill 加载失败
|
||||
|
||||
### 检查 1:确认 skill 已安装
|
||||
|
||||
```bash
|
||||
hermes skills list
|
||||
```
|
||||
|
||||
Skill 必须先安装才能附加到 cron 任务。若 skill 缺失,先用 `hermes skills install <skill-name>` 安装,或在 CLI 中通过 `/skills` 安装。
|
||||
|
||||
### 检查 2:检查 skill 名称与 skill 文件夹名称
|
||||
|
||||
Skill 名称区分大小写,必须与已安装 skill 的文件夹名称完全匹配。若任务指定的是 `ai-funding-daily-report`,但 skill 文件夹也是 `ai-funding-daily-report`,请从 `hermes skills list` 确认确切名称。
|
||||
|
||||
### 检查 3:依赖交互式工具的 skill
|
||||
|
||||
Cron 任务运行时,`cronjob`、`messaging` 和 `clarify` 工具集均被禁用。这可防止递归创建 cron、直接发送消息(投递由调度器处理)以及交互式提示。若某 skill 依赖这些工具集,它将无法在 cron 上下文中运行。
|
||||
|
||||
请查阅该 skill 的文档,确认其支持非交互式(headless)模式。
|
||||
|
||||
### 检查 4:多 skill 加载顺序
|
||||
|
||||
使用多个 skill 时,它们按顺序加载。若 Skill A 依赖 Skill B 的上下文,请确保 B 先加载:
|
||||
|
||||
```bash
|
||||
/cron add "0 9 * * *" "..." --skill context-skill --skill target-skill
|
||||
```
|
||||
|
||||
在此示例中,`context-skill` 先于 `target-skill` 加载。
|
||||
|
||||
---
|
||||
|
||||
## 任务错误与失败
|
||||
|
||||
### 检查 1:查看近期任务输出
|
||||
|
||||
若任务运行后失败,可在以下位置查看错误上下文:
|
||||
|
||||
1. 任务投递的聊天会话(若投递成功)
|
||||
2. `~/.hermes/logs/agent.log`(调度器消息)或 `errors.log`(警告信息)
|
||||
3. 通过 `hermes cron list` 查看任务的 `last_run` 元数据
|
||||
|
||||
### 检查 2:常见错误模式
|
||||
|
||||
**脚本报 "No such file or directory"**
|
||||
`script` 路径必须为绝对路径(或相对于 Hermes 配置目录的路径)。验证:
|
||||
```bash
|
||||
ls ~/.hermes/scripts/your-script.py # 必须存在
|
||||
hermes cron edit <job_id> --script ~/.hermes/scripts/your-script.py
|
||||
```
|
||||
|
||||
**任务执行时报 "Skill not found"**
|
||||
Skill 必须安装在运行调度器的机器上。若你在不同机器间切换,skill 不会自动同步——请用 `hermes skills install <skill-name>` 重新安装。
|
||||
|
||||
**任务运行但没有投递任何内容**
|
||||
可能是投递目标问题(见上方"投递失败"部分)或响应被静默抑制(`[SILENT]`)。
|
||||
|
||||
**任务挂起或超时**
|
||||
调度器使用基于不活跃时间的超时机制(默认 600 秒,可通过 `HERMES_CRON_TIMEOUT` 环境变量配置,`0` 表示无限制)。只要 agent 持续调用工具,就可以一直运行——计时器仅在持续不活跃后触发。长时间运行的任务应使用脚本处理数据采集,仅将结果投递出去。
|
||||
|
||||
### 检查 3:锁竞争
|
||||
|
||||
调度器使用基于文件的锁来防止 tick 重叠。若同时运行了两个 gateway 实例(或 CLI 会话与 gateway 冲突),任务可能被延迟或跳过。
|
||||
|
||||
终止重复的 gateway 进程:
|
||||
```bash
|
||||
ps aux | grep hermes
|
||||
# 终止重复进程,只保留一个
|
||||
```
|
||||
|
||||
### 检查 4:jobs.json 的权限
|
||||
|
||||
任务存储在 `~/.hermes/cron/jobs.json`。若该文件对当前用户不可读写,调度器将静默失败:
|
||||
|
||||
```bash
|
||||
ls -la ~/.hermes/cron/jobs.json
|
||||
chmod 600 ~/.hermes/cron/jobs.json # 应由你的用户拥有
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能问题
|
||||
|
||||
### 任务启动缓慢
|
||||
|
||||
每个 cron 任务都会创建一个全新的 AIAgent 会话,可能涉及提供商认证和模型加载。对于时间敏感的调度,请预留缓冲时间(例如用 `0 8 * * *` 代替 `0 9 * * *`)。
|
||||
|
||||
### 过多任务重叠
|
||||
|
||||
调度器在每次 tick 内顺序执行任务。若多个任务同时到期,它们将依次运行。考虑错开调度时间(例如用 `0 9 * * *` 和 `5 9 * * *` 代替两者都设为 `0 9 * * *`)以避免延迟。
|
||||
|
||||
### 脚本输出过大
|
||||
|
||||
输出数兆字节数据的脚本会拖慢 agent,并可能触及 token 限制。请在脚本层面进行过滤/摘要——只输出 agent 需要推理的内容。
|
||||
|
||||
---
|
||||
|
||||
## 诊断命令
|
||||
|
||||
```bash
|
||||
hermes cron list # 显示所有任务、状态、next_run 时间
|
||||
hermes cron run <job_id> # 安排在下次 tick 执行(用于测试)
|
||||
hermes cron edit <job_id> # 修复配置问题
|
||||
hermes logs # 查看近期 Hermes 日志
|
||||
hermes skills list # 确认已安装的 skill
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取更多帮助
|
||||
|
||||
若你已按本指南逐项排查,问题仍未解决:
|
||||
|
||||
1. 使用 `hermes cron run <job_id>` 运行任务(在下次 gateway tick 时触发),观察聊天输出中的错误
|
||||
2. 查看 `~/.hermes/logs/agent.log` 中的调度器消息和 `~/.hermes/logs/errors.log` 中的警告
|
||||
3. 在 [github.com/NousResearch/hermes-agent](https://github.com/NousResearch/hermes-agent) 提交 issue,并附上:
|
||||
- 任务 ID 和调度表达式
|
||||
- 投递目标
|
||||
- 预期行为与实际行为
|
||||
- 日志中的相关错误信息
|
||||
|
||||
---
|
||||
|
||||
*完整的 cron 参考文档,请参阅 [用 Cron 自动化一切](/guides/automate-with-cron) 和 [定时任务(Cron)](/user-guide/features/cron)。*
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
title: "教程:每日简报机器人"
|
||||
description: "构建一个自动化每日简报机器人,研究主题、汇总发现,并每天早晨推送至 Telegram 或 Discord"
|
||||
---
|
||||
|
||||
# 教程:构建每日简报机器人
|
||||
|
||||
在本教程中,你将构建一个个人简报机器人,它每天早晨自动启动,研究你关心的主题,汇总发现,并将简洁的简报直接推送到你的 Telegram 或 Discord。
|
||||
|
||||
完成后,你将拥有一个完全自动化的工作流,结合了 **网页搜索**、**cron 调度**、**委托(delegation)** 和 **消息推送** — 无需编写代码。
|
||||
|
||||
## 我们要构建什么
|
||||
|
||||
流程如下:
|
||||
|
||||
1. **上午 8:00** — cron 调度器触发任务
|
||||
2. **Hermes 启动**一个全新的 agent 会话,使用你的 prompt(提示词)
|
||||
3. **网页搜索**拉取你关注主题的最新新闻
|
||||
4. **汇总**将内容提炼为简洁的简报格式
|
||||
5. **推送**将简报发送到你的 Telegram 或 Discord
|
||||
|
||||
整个流程无需人工干预。你只需在早晨喝咖啡时阅读简报即可。
|
||||
|
||||
## 前提条件
|
||||
|
||||
开始之前,请确保:
|
||||
|
||||
- **已安装 Hermes Agent** — 参见[安装指南](/getting-started/installation)
|
||||
- **Gateway 正在运行** — gateway 守护进程负责处理 cron 执行:
|
||||
```bash
|
||||
hermes gateway install # Install as a user service
|
||||
sudo hermes gateway install --system # Linux servers: boot-time system service
|
||||
# or
|
||||
hermes gateway # Run in foreground
|
||||
```
|
||||
- **Firecrawl API 密钥** — 在环境变量中设置 `FIRECRAWL_API_KEY` 以启用网页搜索
|
||||
- **已配置消息推送**(可选但推荐)— 已设置 [Telegram](/user-guide/messaging/telegram) 或 Discord 并配置了 home channel
|
||||
|
||||
:::tip 没有消息推送?没关系
|
||||
你仍然可以使用 `deliver: "local"` 跟随本教程。简报将保存至 `~/.hermes/cron/output/`,你可以随时查阅。
|
||||
:::
|
||||
|
||||
## 第一步:手动测试工作流
|
||||
|
||||
在自动化之前,先确认简报功能正常。启动聊天会话:
|
||||
|
||||
```bash
|
||||
hermes
|
||||
```
|
||||
|
||||
然后输入以下 prompt:
|
||||
|
||||
```
|
||||
Search for the latest news about AI agents and open source LLMs.
|
||||
Summarize the top 3 stories in a concise briefing format with links.
|
||||
```
|
||||
|
||||
Hermes 将搜索网页、阅读结果,并生成类似以下内容:
|
||||
|
||||
```
|
||||
☀️ Your AI Briefing — March 8, 2026
|
||||
|
||||
1. Qwen 3 Released with 235B Parameters
|
||||
Alibaba's latest open-weight model matches GPT-4.5 on several
|
||||
benchmarks while remaining fully open source.
|
||||
→ https://qwenlm.github.io/blog/qwen3/
|
||||
|
||||
2. LangChain Launches Agent Protocol Standard
|
||||
A new open standard for agent-to-agent communication gains
|
||||
adoption from 15 major frameworks in its first week.
|
||||
→ https://blog.langchain.dev/agent-protocol/
|
||||
|
||||
3. EU AI Act Enforcement Begins for General-Purpose Models
|
||||
The first compliance deadlines hit, with open source models
|
||||
receiving exemptions under the 10M parameter threshold.
|
||||
→ https://artificialintelligenceact.eu/updates/
|
||||
|
||||
---
|
||||
3 stories • Sources searched: 8 • Generated by Hermes Agent
|
||||
```
|
||||
|
||||
如果运行正常,你就可以开始自动化了。
|
||||
|
||||
:::tip 反复调整格式
|
||||
尝试不同的 prompt,直到得到你满意的输出。可以添加诸如"使用 emoji 标题"或"每条摘要不超过 2 句话"之类的指令。最终确定的内容将写入 cron 任务。
|
||||
:::
|
||||
|
||||
## 第二步:创建 Cron 任务
|
||||
|
||||
现在让我们将其设置为每天早晨自动运行。有两种方式可以实现。
|
||||
|
||||
在创建 cron 任务之前,请确保 Hermes 已全局配置了默认模型和 provider。如果你希望某个任务使用不同的值,可在创建时设置该任务专属的 model/provider 覆盖项。
|
||||
|
||||
### 方式 A:自然语言(在聊天中)
|
||||
|
||||
直接告诉 Hermes 你想要什么:
|
||||
|
||||
```
|
||||
Every morning at 8am, search the web for the latest news about AI agents
|
||||
and open source LLMs. Summarize the top 3 stories in a concise briefing
|
||||
with links. Use a friendly, professional tone. Deliver to telegram.
|
||||
```
|
||||
|
||||
Hermes 将使用统一的 `cronjob` 工具为你创建 cron 任务。
|
||||
|
||||
### 方式 B:CLI 斜杠命令
|
||||
|
||||
使用 `/cron` 命令进行更精细的控制:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * *" "Search the web for the latest news about AI agents and open source LLMs. Find at least 5 recent articles from the past 24 hours. Summarize the top 3 most important stories in a concise daily briefing format. For each story include: a clear headline, a 2-sentence summary, and the source URL. Use a friendly, professional tone. Format with emoji bullet points and end with a total story count."
|
||||
```
|
||||
|
||||
### 黄金法则:自包含的 Prompt
|
||||
|
||||
:::warning 关键概念
|
||||
Cron 任务在**全新会话**中运行 — 不保留之前对话的任何记忆,也不了解你"之前设置"的任何内容。你的 prompt 必须包含 agent 完成任务所需的**一切信息**。
|
||||
:::
|
||||
|
||||
**糟糕的 prompt:**
|
||||
```
|
||||
Do my usual morning briefing.
|
||||
```
|
||||
|
||||
**好的 prompt:**
|
||||
```
|
||||
Search the web for the latest news about AI agents and open source LLMs.
|
||||
Find at least 5 recent articles from the past 24 hours. Summarize the
|
||||
top 3 most important stories in a concise daily briefing format. For each
|
||||
story include: a clear headline, a 2-sentence summary, and the source URL.
|
||||
Use a friendly, professional tone. Format with emoji bullet points.
|
||||
```
|
||||
|
||||
好的 prompt 明确说明了**搜索什么**、**多少篇文章**、**什么格式**以及**什么语气**。它在一次输入中包含了 agent 所需的全部信息。
|
||||
|
||||
## 第三步:自定义简报
|
||||
|
||||
基础简报运行正常后,你可以进一步发挥创意。
|
||||
|
||||
### 多主题简报
|
||||
|
||||
在一份简报中涵盖多个领域:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * *" "Create a morning briefing covering three topics. For each topic, search the web for recent news from the past 24 hours and summarize the top 2 stories with links.
|
||||
|
||||
Topics:
|
||||
1. AI and machine learning — focus on open source models and agent frameworks
|
||||
2. Cryptocurrency — focus on Bitcoin, Ethereum, and regulatory news
|
||||
3. Space exploration — focus on SpaceX, NASA, and commercial space
|
||||
|
||||
Format as a clean briefing with section headers and emoji. End with today's date and a motivational quote."
|
||||
```
|
||||
|
||||
### 使用委托进行并行研究
|
||||
|
||||
若要加快简报生成速度,可以告诉 Hermes 将每个主题委托给子 agent:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * *" "Create a morning briefing by delegating research to sub-agents. Delegate three parallel tasks:
|
||||
|
||||
1. Delegate: Search for the top 2 AI/ML news stories from the past 24 hours with links
|
||||
2. Delegate: Search for the top 2 cryptocurrency news stories from the past 24 hours with links
|
||||
3. Delegate: Search for the top 2 space exploration news stories from the past 24 hours with links
|
||||
|
||||
Collect all results and combine them into a single clean briefing with section headers, emoji formatting, and source links. Add today's date as a header."
|
||||
```
|
||||
|
||||
每个子 agent 独立并行搜索,然后主 agent 将所有内容合并为一份精美的简报。详见[委托文档](/user-guide/features/delegation)了解其工作原理。
|
||||
|
||||
### 仅工作日调度
|
||||
|
||||
不需要周末简报?使用针对周一至周五的 cron 表达式:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * 1-5" "Search for the latest AI and tech news..."
|
||||
```
|
||||
|
||||
### 每日两次简报
|
||||
|
||||
获取早晨概览和傍晚回顾:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * *" "Morning briefing: search for AI news from the past 12 hours..."
|
||||
/cron add "0 18 * * *" "Evening recap: search for AI news from the past 12 hours..."
|
||||
```
|
||||
|
||||
### 通过 Memory 添加个人上下文
|
||||
|
||||
如果你启用了 [memory(记忆)](/user-guide/features/memory),可以存储跨会话持久保留的偏好设置。但请记住 — cron 任务在全新会话中运行,不保留对话记忆。若要添加个人上下文,请直接将其写入 prompt:
|
||||
|
||||
```
|
||||
/cron add "0 8 * * *" "You are creating a briefing for a senior ML engineer who cares about: PyTorch ecosystem, transformer architectures, open-weight models, and AI regulation in the EU. Skip stories about product launches or funding rounds unless they involve open source.
|
||||
|
||||
Search for the latest news on these topics. Summarize the top 3 stories with links. Be concise and technical — this reader doesn't need basic explanations."
|
||||
```
|
||||
|
||||
:::tip 定制受众角色
|
||||
在 prompt 中加入简报受众的详细信息,能显著提升内容相关性。告诉 agent 你的角色、兴趣以及需要跳过的内容。
|
||||
:::
|
||||
|
||||
## 第四步:管理你的任务
|
||||
|
||||
### 列出所有已调度任务
|
||||
|
||||
在聊天中:
|
||||
```
|
||||
/cron list
|
||||
```
|
||||
|
||||
或在终端中:
|
||||
```bash
|
||||
hermes cron list
|
||||
```
|
||||
|
||||
你将看到类似以下的输出:
|
||||
|
||||
```
|
||||
ID | Name | Schedule | Next Run | Deliver
|
||||
------------|-------------------|-------------|--------------------|--------
|
||||
a1b2c3d4 | Morning Briefing | 0 8 * * * | 2026-03-09 08:00 | telegram
|
||||
e5f6g7h8 | Evening Recap | 0 18 * * * | 2026-03-08 18:00 | telegram
|
||||
```
|
||||
|
||||
### 删除任务
|
||||
|
||||
在聊天中:
|
||||
```
|
||||
/cron remove a1b2c3d4
|
||||
```
|
||||
|
||||
或通过对话方式:
|
||||
```
|
||||
Remove my morning briefing cron job.
|
||||
```
|
||||
|
||||
Hermes 将使用 `cronjob(action="list")` 查找任务,并使用 `cronjob(action="remove")` 将其删除。
|
||||
|
||||
### 检查 Gateway 状态
|
||||
|
||||
确认调度器正在运行:
|
||||
|
||||
```bash
|
||||
hermes cron status
|
||||
```
|
||||
|
||||
如果 gateway 未运行,你的任务将不会执行。将其安装为后台服务以确保可靠性:
|
||||
|
||||
```bash
|
||||
hermes gateway install
|
||||
# or on Linux servers
|
||||
sudo hermes gateway install --system
|
||||
```
|
||||
|
||||
## 进一步探索
|
||||
|
||||
你已经构建了一个可运行的每日简报机器人。以下是一些可以继续探索的方向:
|
||||
|
||||
- **[定时任务(Cron)](/user-guide/features/cron)** — 调度格式、重复限制和推送选项的完整参考
|
||||
- **[委托](/user-guide/features/delegation)** — 深入了解并行子 agent 工作流
|
||||
- **[消息推送平台](/user-guide/messaging)** — 设置 Telegram、Discord 或其他推送目标
|
||||
- **[Memory](/user-guide/features/memory)** — 跨会话的持久上下文
|
||||
- **[技巧与最佳实践](/guides/tips)** — 更多 prompt 工程建议
|
||||
|
||||
:::tip 还能调度什么?
|
||||
简报机器人的模式适用于任何场景:竞争对手监控、GitHub 仓库摘要、天气预报、投资组合追踪、服务器健康检查,甚至每日笑话。只要你能用 prompt 描述它,就能调度它。
|
||||
:::
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
---
|
||||
sidebar_position: 13
|
||||
title: "委托与并行工作"
|
||||
description: "何时以及如何使用子代理委托——并行研究、代码审查和多文件工作的模式"
|
||||
---
|
||||
|
||||
# 委托与并行工作
|
||||
|
||||
Hermes 可以生成隔离的子代理来并行处理任务。每个子代理拥有独立的对话、终端会话和工具集。只有最终摘要会返回——中间工具调用不会进入你的上下文窗口。
|
||||
|
||||
完整功能参考,请参阅[子代理委托](/user-guide/features/delegation)。
|
||||
|
||||
---
|
||||
|
||||
## 何时委托
|
||||
|
||||
**适合委托的场景:**
|
||||
- 推理密集型子任务(调试、代码审查、研究综合)
|
||||
- 会用中间数据淹没上下文的任务
|
||||
- 并行独立工作流(同时进行研究 A 和研究 B)
|
||||
- 需要代理以无偏见方式处理的全新上下文任务
|
||||
|
||||
**使用其他方式的场景:**
|
||||
- 单次工具调用 → 直接使用工具
|
||||
- 步骤间有逻辑的机械性多步骤工作 → `execute_code`
|
||||
- 需要用户交互的任务 → 子代理无法使用 `clarify`
|
||||
- 快速文件编辑 → 直接操作
|
||||
- 必须在当前轮次结束后继续运行的持久性长任务 → `cronjob` 或 `terminal(background=True, notify_on_complete=True)`。`delegate_task` 是**同步**的:若父轮次被中断,活跃的子代理将被取消,其工作将被丢弃。
|
||||
|
||||
---
|
||||
|
||||
## 模式:并行研究
|
||||
|
||||
同时研究三个主题并获取结构化摘要:
|
||||
|
||||
```
|
||||
并行研究以下三个主题:
|
||||
1. WebAssembly 在浏览器之外的现状
|
||||
2. 2025 年 RISC-V 服务器芯片的采用情况
|
||||
3. 量子计算的实际应用
|
||||
|
||||
重点关注近期进展和关键参与者。
|
||||
```
|
||||
|
||||
在后台,Hermes 使用:
|
||||
|
||||
```python
|
||||
delegate_task(tasks=[
|
||||
{
|
||||
"goal": "Research WebAssembly outside the browser in 2025",
|
||||
"context": "Focus on: runtimes (Wasmtime, Wasmer), cloud/edge use cases, WASI progress",
|
||||
"toolsets": ["web"]
|
||||
},
|
||||
{
|
||||
"goal": "Research RISC-V server chip adoption",
|
||||
"context": "Focus on: server chips shipping, cloud providers adopting, software ecosystem",
|
||||
"toolsets": ["web"]
|
||||
},
|
||||
{
|
||||
"goal": "Research practical quantum computing applications",
|
||||
"context": "Focus on: error correction breakthroughs, real-world use cases, key companies",
|
||||
"toolsets": ["web"]
|
||||
}
|
||||
])
|
||||
```
|
||||
|
||||
三个任务并发运行。每个子代理独立搜索网络并返回摘要。父代理随后将它们综合成一份连贯的简报。
|
||||
|
||||
---
|
||||
|
||||
## 模式:代码审查
|
||||
|
||||
将安全审查委托给一个全新上下文的子代理,让它以无先入之见的方式审查代码:
|
||||
|
||||
```
|
||||
审查 src/auth/ 中的认证模块,检查安全问题。
|
||||
检查 SQL 注入、JWT 验证问题、密码处理
|
||||
和会话管理。修复发现的问题并运行测试。
|
||||
```
|
||||
|
||||
关键在于 `context` 字段——它必须包含子代理所需的一切信息:
|
||||
|
||||
```python
|
||||
delegate_task(
|
||||
goal="Review src/auth/ for security issues and fix any found",
|
||||
context="""Project at /home/user/webapp. Python 3.11, Flask, PyJWT, bcrypt.
|
||||
Auth files: src/auth/login.py, src/auth/jwt.py, src/auth/middleware.py
|
||||
Test command: pytest tests/auth/ -v
|
||||
Focus on: SQL injection, JWT validation, password hashing, session management.
|
||||
Fix issues found and verify tests pass.""",
|
||||
toolsets=["terminal", "file"]
|
||||
)
|
||||
```
|
||||
|
||||
:::warning 上下文问题
|
||||
子代理对你的对话**一无所知**。它们从完全空白的状态开始。如果你委托"修复我们讨论的那个 bug",子代理根本不知道你指的是哪个 bug。务必明确传递文件路径、错误信息、项目结构和约束条件。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 模式:比较备选方案
|
||||
|
||||
并行评估同一问题的多种解决方案,然后选出最佳方案:
|
||||
|
||||
```
|
||||
我需要为 Django 应用添加全文搜索。并行评估三种方案:
|
||||
1. PostgreSQL tsvector(内置)
|
||||
2. 通过 django-elasticsearch-dsl 使用 Elasticsearch
|
||||
3. 通过 meilisearch-python 使用 Meilisearch
|
||||
|
||||
对每种方案评估:配置复杂度、查询能力、资源需求
|
||||
和维护开销。比较后推荐一种。
|
||||
```
|
||||
|
||||
每个子代理独立研究一个选项。由于它们相互隔离,不存在交叉干扰——每项评估都基于自身的优缺点。父代理获取全部三份摘要后进行比较。
|
||||
|
||||
---
|
||||
|
||||
## 模式:多文件重构
|
||||
|
||||
将大型重构任务拆分给并行子代理,每个子代理负责代码库的不同部分:
|
||||
|
||||
```python
|
||||
delegate_task(tasks=[
|
||||
{
|
||||
"goal": "Refactor all API endpoint handlers to use the new response format",
|
||||
"context": """Project at /home/user/api-server.
|
||||
Files: src/handlers/users.py, src/handlers/auth.py, src/handlers/billing.py
|
||||
Old format: return {"data": result, "status": "ok"}
|
||||
New format: return APIResponse(data=result, status=200).to_dict()
|
||||
Import: from src.responses import APIResponse
|
||||
Run tests after: pytest tests/handlers/ -v""",
|
||||
"toolsets": ["terminal", "file"]
|
||||
},
|
||||
{
|
||||
"goal": "Update all client SDK methods to handle the new response format",
|
||||
"context": """Project at /home/user/api-server.
|
||||
Files: sdk/python/client.py, sdk/python/models.py
|
||||
Old parsing: result = response.json()["data"]
|
||||
New parsing: result = response.json()["data"] (same key, but add status code checking)
|
||||
Also update sdk/python/tests/test_client.py""",
|
||||
"toolsets": ["terminal", "file"]
|
||||
},
|
||||
{
|
||||
"goal": "Update API documentation to reflect the new response format",
|
||||
"context": """Project at /home/user/api-server.
|
||||
Docs at: docs/api/. Format: Markdown with code examples.
|
||||
Update all response examples from old format to new format.
|
||||
Add a 'Response Format' section to docs/api/overview.md explaining the schema.""",
|
||||
"toolsets": ["terminal", "file"]
|
||||
}
|
||||
])
|
||||
```
|
||||
|
||||
:::tip
|
||||
每个子代理拥有独立的终端会话。只要它们编辑不同的文件,就可以在同一项目目录中工作而互不干扰。如果两个子代理可能修改同一文件,请在并行工作完成后自行处理该文件。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 模式:先收集后分析
|
||||
|
||||
使用 `execute_code` 进行机械性数据收集,然后委托推理密集型分析:
|
||||
|
||||
```python
|
||||
# 第一步:机械性收集(此处 execute_code 更合适——无需推理)
|
||||
execute_code("""
|
||||
from hermes_tools import web_search, web_extract
|
||||
|
||||
results = []
|
||||
for query in ["AI funding Q1 2026", "AI startup acquisitions 2026", "AI IPOs 2026"]:
|
||||
r = web_search(query, limit=5)
|
||||
for item in r["data"]["web"]:
|
||||
results.append({"title": item["title"], "url": item["url"], "desc": item["description"]})
|
||||
|
||||
# Extract full content from top 5 most relevant
|
||||
urls = [r["url"] for r in results[:5]]
|
||||
content = web_extract(urls)
|
||||
|
||||
# Save for the analysis step
|
||||
import json
|
||||
with open("/tmp/ai-funding-data.json", "w") as f:
|
||||
json.dump({"search_results": results, "extracted": content["results"]}, f)
|
||||
print(f"Collected {len(results)} results, extracted {len(content['results'])} pages")
|
||||
""")
|
||||
|
||||
# 第二步:推理密集型分析(此处委托更合适)
|
||||
delegate_task(
|
||||
goal="Analyze AI funding data and write a market report",
|
||||
context="""Raw data at /tmp/ai-funding-data.json contains search results and
|
||||
extracted web pages about AI funding, acquisitions, and IPOs in Q1 2026.
|
||||
Write a structured market report: key deals, trends, notable players,
|
||||
and outlook. Focus on deals over $100M.""",
|
||||
toolsets=["terminal", "file"]
|
||||
)
|
||||
```
|
||||
|
||||
这通常是最高效的模式:`execute_code` 以低成本处理 10 余次顺序工具调用,然后子代理在干净的上下文中完成单次高成本推理任务。
|
||||
|
||||
---
|
||||
|
||||
## 工具集选择
|
||||
|
||||
根据子代理的需求选择工具集:
|
||||
|
||||
| 任务类型 | 工具集 | 原因 |
|
||||
|-----------|----------|-----|
|
||||
| 网络研究 | `["web"]` | 仅 web_search + web_extract |
|
||||
| 代码工作 | `["terminal", "file"]` | Shell 访问 + 文件操作 |
|
||||
| 全栈 | `["terminal", "file", "web"]` | 除消息功能外的全部工具 |
|
||||
| 只读分析 | `["file"]` | 只能读取文件,无 Shell |
|
||||
|
||||
限制工具集可使子代理保持专注,并防止意外副作用(例如研究子代理执行 Shell 命令)。
|
||||
|
||||
---
|
||||
|
||||
## 约束条件
|
||||
|
||||
- **默认 3 个并行任务**:批次默认并发 3 个子代理(可通过 config.yaml 中的 `delegation.max_concurrent_children` 配置,无硬性上限,最低为 1)
|
||||
- **嵌套委托需显式启用**:叶子子代理(默认)无法调用 `delegate_task`、`clarify`、`memory`、`send_message` 或 `execute_code`。编排器子代理(`role="orchestrator"`)保留 `delegate_task` 以支持进一步委托,但仅在 `delegation.max_spawn_depth` 高于默认值 1 时生效(支持 1-3);其余四项仍被禁用。可通过 `delegation.orchestrator_enabled: false` 全局禁用。
|
||||
|
||||
### 调整并发数与深度
|
||||
|
||||
| 配置项 | 默认值 | 范围 | 效果 |
|
||||
|--------|---------|-------|--------|
|
||||
| `max_concurrent_children` | 3 | >=1 | 每次 `delegate_task` 调用的并行批次大小 |
|
||||
| `max_spawn_depth` | 1 | 1-3 | 可进一步生成子代理的委托层级数 |
|
||||
|
||||
示例:运行 30 个并行 worker 并启用嵌套子代理:
|
||||
|
||||
```yaml
|
||||
delegation:
|
||||
max_concurrent_children: 30
|
||||
max_spawn_depth: 2
|
||||
```
|
||||
|
||||
- **独立终端** — 每个子代理拥有独立的终端会话,具有独立的工作目录和状态
|
||||
- **无对话历史** — 子代理只能看到父代理调用 `delegate_task` 时传入的 `goal` 和 `context`
|
||||
- **默认 50 次迭代** — 对简单任务设置较低的 `max_iterations` 以节省成本
|
||||
- **非持久性** — `delegate_task` 是同步的,在父轮次内运行。若父轮次被中断(新用户消息、`/stop`、`/new`),所有活跃子代理将被取消(`status="interrupted"`),其工作将被丢弃。对于必须在当前轮次结束后继续运行的工作,请使用 `cronjob` 或 `terminal(background=True, notify_on_complete=True)`。
|
||||
|
||||
---
|
||||
|
||||
## 技巧
|
||||
|
||||
**目标要具体。** "修复 bug"过于模糊。"修复 api/handlers.py 第 47 行的 TypeError,该错误由 parse_body() 向 process_request() 返回 None 引起"才能给子代理足够的信息。
|
||||
|
||||
**包含文件路径。** 子代理不了解你的项目结构。务必提供相关文件的绝对路径、项目根目录和测试命令。
|
||||
|
||||
**利用委托实现上下文隔离。** 有时你需要全新的视角。委托迫使你清晰地阐述问题,而子代理会在没有对话中积累的假设前提下处理它。
|
||||
|
||||
**核验结果。** 子代理的摘要只是摘要。如果子代理说"修复了 bug 且测试通过",请自行运行测试或查看 diff 来验证。
|
||||
|
||||
---
|
||||
|
||||
*完整的委托参考——所有参数、ACP 集成和高级配置——请参阅[子代理委托](/user-guide/features/delegation)。*
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
title: "教程:GitHub PR 审查 Agent"
|
||||
description: "构建一个自动化 AI 代码审查器,监控你的仓库、审查 Pull Request 并自动发送反馈——全程无需人工干预"
|
||||
---
|
||||
|
||||
# 教程:构建 GitHub PR 审查 Agent
|
||||
|
||||
**问题所在:** 团队提交 PR 的速度比你审查的速度还快。PR 等待数天无人问津。初级开发者因为没人检查而合并了有 bug 的代码。你每天早上都在追赶 diff,而不是在写新功能。
|
||||
|
||||
**解决方案:** 一个全天候监控你的仓库的 AI agent,对每个新 PR 进行 bug、安全问题和代码质量审查,并向你发送摘要——这样你只需把时间花在真正需要人工判断的 PR 上。
|
||||
|
||||
**你将构建的内容:**
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ Cron Timer ──▶ Hermes Agent ──▶ GitHub API ──▶ Review │
|
||||
│ (every 2h) + gh CLI (PR diffs) delivery │
|
||||
│ + skill (Telegram, │
|
||||
│ + memory Discord, │
|
||||
│ local) │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
本指南使用 **cron 任务**按计划轮询 PR——无需服务器或公开端点,在 NAT 和防火墙后面同样可用。
|
||||
|
||||
:::tip 想要实时审查?
|
||||
如果你有可用的公开端点,请查看[使用 Webhook 自动化 GitHub PR 评论](./webhook-github-pr-review.md)——GitHub 会在 PR 被打开或更新时立即向 Hermes 推送事件。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 前提条件
|
||||
|
||||
- **已安装 Hermes Agent** — 参见[安装指南](/getting-started/installation)
|
||||
- **Gateway 已运行**(用于 cron 任务):
|
||||
```bash
|
||||
hermes gateway install # Install as a service
|
||||
# or
|
||||
hermes gateway # Run in foreground
|
||||
```
|
||||
- **已安装并认证 GitHub CLI(`gh`)**:
|
||||
```bash
|
||||
# Install
|
||||
brew install gh # macOS
|
||||
sudo apt install gh # Ubuntu/Debian
|
||||
|
||||
# Authenticate
|
||||
gh auth login
|
||||
```
|
||||
- **已配置消息通知**(可选)— [Telegram](/user-guide/messaging/telegram) 或 [Discord](/user-guide/messaging/discord)
|
||||
|
||||
:::tip 没有消息通知?没关系
|
||||
使用 `deliver: "local"` 将审查结果保存到 `~/.hermes/cron/output/`。在接入通知之前用于测试非常方便。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第一步:验证配置
|
||||
|
||||
确保 Hermes 可以访问 GitHub。启动对话:
|
||||
|
||||
```bash
|
||||
hermes
|
||||
```
|
||||
|
||||
用一个简单命令测试:
|
||||
|
||||
```
|
||||
Run: gh pr list --repo NousResearch/hermes-agent --state open --limit 3
|
||||
```
|
||||
|
||||
你应该能看到一个开放 PR 的列表。如果成功,就可以继续了。
|
||||
|
||||
---
|
||||
|
||||
## 第二步:手动试审一个 PR
|
||||
|
||||
仍在对话中,让 Hermes 审查一个真实的 PR:
|
||||
|
||||
```
|
||||
Review this pull request. Read the diff, check for bugs, security issues,
|
||||
and code quality. Be specific about line numbers and quote problematic code.
|
||||
|
||||
Run: gh pr diff 3888 --repo NousResearch/hermes-agent
|
||||
```
|
||||
|
||||
Hermes 将会:
|
||||
1. 执行 `gh pr diff` 获取代码变更
|
||||
2. 通读整个 diff
|
||||
3. 生成包含具体发现的结构化审查报告
|
||||
|
||||
如果你对审查质量满意,就可以开始自动化了。
|
||||
|
||||
---
|
||||
|
||||
## 第三步:创建审查 Skill
|
||||
|
||||
Skill 为 Hermes 提供一致的审查准则,在会话和 cron 运行之间持久保存。没有 skill,审查质量会参差不齐。
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.hermes/skills/code-review
|
||||
```
|
||||
|
||||
创建 `~/.hermes/skills/code-review/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: code-review
|
||||
description: Review pull requests for bugs, security issues, and code quality
|
||||
---
|
||||
|
||||
# Code Review Guidelines
|
||||
|
||||
When reviewing a pull request:
|
||||
|
||||
## What to Check
|
||||
1. **Bugs** — Logic errors, off-by-one, null/undefined handling
|
||||
2. **Security** — Injection, auth bypass, secrets in code, SSRF
|
||||
3. **Performance** — N+1 queries, unbounded loops, memory leaks
|
||||
4. **Style** — Naming conventions, dead code, missing error handling
|
||||
5. **Tests** — Are changes tested? Do tests cover edge cases?
|
||||
|
||||
## Output Format
|
||||
For each finding:
|
||||
- **File:Line** — exact location
|
||||
- **Severity** — Critical / Warning / Suggestion
|
||||
- **What's wrong** — one sentence
|
||||
- **Fix** — how to fix it
|
||||
|
||||
## Rules
|
||||
- Be specific. Quote the problematic code.
|
||||
- Don't flag style nitpicks unless they affect readability.
|
||||
- If the PR looks good, say so. Don't invent problems.
|
||||
- End with: APPROVE / REQUEST_CHANGES / COMMENT
|
||||
```
|
||||
|
||||
验证是否已加载——启动 `hermes`,你应该能在启动时的 skill 列表中看到 `code-review`。
|
||||
|
||||
---
|
||||
|
||||
## 第四步:教会它你的团队规范
|
||||
|
||||
这才是让审查器真正有用的关键。启动一个会话,向 Hermes 传授你的团队标准:
|
||||
|
||||
```
|
||||
Remember: In our backend repo, we use Python with FastAPI.
|
||||
All endpoints must have type annotations and Pydantic models.
|
||||
We don't allow raw SQL — only SQLAlchemy ORM.
|
||||
Test files go in tests/ and must use pytest fixtures.
|
||||
```
|
||||
|
||||
```
|
||||
Remember: In our frontend repo, we use TypeScript with React.
|
||||
No `any` types allowed. All components must have props interfaces.
|
||||
We use React Query for data fetching, never useEffect for API calls.
|
||||
```
|
||||
|
||||
这些记忆会永久保存——审查器无需每次提醒就会自动执行你的规范。
|
||||
|
||||
---
|
||||
|
||||
## 第五步:创建自动化 Cron 任务
|
||||
|
||||
现在把所有内容串联起来。创建一个每 2 小时运行一次的 cron 任务:
|
||||
|
||||
```bash
|
||||
hermes cron create "0 */2 * * *" \
|
||||
"Check for new open PRs and review them.
|
||||
|
||||
Repos to monitor:
|
||||
- myorg/backend-api
|
||||
- myorg/frontend-app
|
||||
|
||||
Steps:
|
||||
1. Run: gh pr list --repo REPO --state open --limit 5 --json number,title,author,createdAt
|
||||
2. For each PR created or updated in the last 4 hours:
|
||||
- Run: gh pr diff NUMBER --repo REPO
|
||||
- Review the diff using the code-review guidelines
|
||||
3. Format output as:
|
||||
|
||||
## PR Reviews — today
|
||||
|
||||
### [repo] #[number]: [title]
|
||||
**Author:** [name] | **Verdict:** APPROVE/REQUEST_CHANGES/COMMENT
|
||||
[findings]
|
||||
|
||||
If no new PRs found, say: No new PRs to review." \
|
||||
--name "pr-review" \
|
||||
--deliver telegram \
|
||||
--skill code-review
|
||||
```
|
||||
|
||||
验证任务已调度:
|
||||
|
||||
```bash
|
||||
hermes cron list
|
||||
```
|
||||
|
||||
### 其他常用调度计划
|
||||
|
||||
| 计划 | 触发时机 |
|
||||
|------|----------|
|
||||
| `0 */2 * * *` | 每 2 小时 |
|
||||
| `0 9,13,17 * * 1-5` | 工作日每天三次 |
|
||||
| `0 9 * * 1` | 每周一早上汇总 |
|
||||
| `30m` | 每 30 分钟(高流量仓库) |
|
||||
|
||||
---
|
||||
|
||||
## 第六步:按需手动触发
|
||||
|
||||
不想等待调度?手动触发:
|
||||
|
||||
```bash
|
||||
hermes cron run pr-review
|
||||
```
|
||||
|
||||
或在对话会话中:
|
||||
|
||||
```
|
||||
/cron run pr-review
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 进阶用法
|
||||
|
||||
### 直接在 GitHub 上发布审查评论
|
||||
|
||||
不将结果发送到 Telegram,而是让 agent 直接在 PR 上评论:
|
||||
|
||||
在你的 cron prompt(提示词)中添加:
|
||||
|
||||
```
|
||||
After reviewing, post your review:
|
||||
- For issues: gh pr review NUMBER --repo REPO --comment --body "YOUR_REVIEW"
|
||||
- For critical issues: gh pr review NUMBER --repo REPO --request-changes --body "YOUR_REVIEW"
|
||||
- For clean PRs: gh pr review NUMBER --repo REPO --approve --body "Looks good"
|
||||
```
|
||||
|
||||
:::caution
|
||||
确保 `gh` 使用的 token 具有 `repo` 权限范围。审查评论将以 `gh` 当前认证的用户身份发布。
|
||||
:::
|
||||
|
||||
### 每周 PR 看板
|
||||
|
||||
创建一个每周一早上的仓库概览:
|
||||
|
||||
```bash
|
||||
hermes cron create "0 9 * * 1" \
|
||||
"Generate a weekly PR dashboard:
|
||||
- myorg/backend-api
|
||||
- myorg/frontend-app
|
||||
- myorg/infra
|
||||
|
||||
For each repo show:
|
||||
1. Open PR count and oldest PR age
|
||||
2. PRs merged this week
|
||||
3. Stale PRs (older than 5 days)
|
||||
4. PRs with no reviewer assigned
|
||||
|
||||
Format as a clean summary." \
|
||||
--name "weekly-dashboard" \
|
||||
--deliver telegram
|
||||
```
|
||||
|
||||
### 多仓库监控
|
||||
|
||||
在 prompt 中添加更多仓库即可扩展规模。Agent 会按顺序处理它们——无需额外配置。
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### "gh: command not found"
|
||||
Gateway 在精简环境中运行。请确保 `gh` 在系统 PATH 中,然后重启 gateway。
|
||||
|
||||
### 审查结果过于泛泛
|
||||
1. 添加 `code-review` skill(第三步)
|
||||
2. 通过 memory(记忆)向 Hermes 传授你的团队规范(第四步)
|
||||
3. 它对你的技术栈了解越多,审查质量越好
|
||||
|
||||
### Cron 任务未运行
|
||||
```bash
|
||||
hermes gateway status # Is the gateway running?
|
||||
hermes cron list # Is the job enabled?
|
||||
```
|
||||
|
||||
### 速率限制
|
||||
GitHub 对已认证用户每小时允许 5,000 次 API 请求。每次 PR 审查约消耗 3-5 次请求(列表 + diff + 可选评论)。即使每天审查 100 个 PR,也远低于限制。
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
- **[基于 Webhook 的 PR 审查](./webhook-github-pr-review.md)** — 在 PR 被打开时立即获得审查(需要公开端点)
|
||||
- **[每日简报 Bot](/guides/daily-briefing-bot)** — 将 PR 审查与你的晨间资讯摘要结合
|
||||
- **[构建 Plugin](/guides/build-a-hermes-plugin)** — 将审查逻辑封装为可共享的 plugin
|
||||
- **[Profiles](/user-guide/profiles)** — 运行一个专属审查器 profile,拥有独立的 memory 和配置
|
||||
- **[Fallback Providers](/user-guide/features/fallback-providers)** — 确保在某个 provider 不可用时审查任务仍能正常运行
|
||||
@@ -0,0 +1,280 @@
|
||||
---
|
||||
sidebar_position: 16
|
||||
title: "Google Gemini"
|
||||
description: "将 Hermes Agent 与 Google Gemini 配合使用——原生 AI Studio API、API 密钥配置、OAuth 选项、工具调用、流式传输及配额说明"
|
||||
---
|
||||
|
||||
# Google Gemini
|
||||
|
||||
Hermes Agent 通过 **Google AI Studio / Gemini API** 原生支持 Google Gemini——而非 OpenAI 兼容端点。这使 Hermes 能够将其内部 OpenAI 格式的消息和工具循环转换为 Gemini 原生的 `generateContent` API,同时保留工具调用、流式传输、多模态输入以及 Gemini 特有的响应元数据。
|
||||
|
||||
Hermes 还支持独立的 **Google Gemini(OAuth)** provider,使用与 Google Gemini CLI 相同的 Cloud Code Assist 后端。如需最低风险的官方 API 路径,请使用 API 密钥 provider(`gemini`)。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- **Google AI Studio API 密钥** — 在 [aistudio.google.com/apikey](https://aistudio.google.com/apikey) 创建
|
||||
- **已启用计费的 Google Cloud 项目** — 推荐用于 Agent 场景。Gemini 免费层级对长时间运行的 Agent 会话而言配额过小,因为 Hermes 每次用户交互可能发起多次模型调用。
|
||||
- **已安装 Hermes** — 原生 Gemini provider 无需额外安装 Python 包。
|
||||
|
||||
:::tip API 密钥路径
|
||||
设置 `GOOGLE_API_KEY` 或 `GEMINI_API_KEY`。Hermes 对 `gemini` provider 会同时检查这两个名称。
|
||||
:::
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 添加 Gemini API 密钥
|
||||
echo "GOOGLE_API_KEY=..." >> ~/.hermes/.env
|
||||
|
||||
# 选择 Gemini 作为 provider
|
||||
hermes model
|
||||
# → 选择 "More providers..." → "Google AI Studio"
|
||||
# → Hermes 检查密钥层级并显示 Gemini 模型列表
|
||||
# → 选择一个模型
|
||||
|
||||
# 开始对话
|
||||
hermes chat
|
||||
```
|
||||
|
||||
如果你偏好直接编辑配置文件,请使用原生 Gemini API 基础 URL:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: gemini-3-flash-preview
|
||||
provider: gemini
|
||||
base_url: https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
运行 `hermes model` 后,`~/.hermes/config.yaml` 将包含:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: gemini-3-flash-preview
|
||||
provider: gemini
|
||||
base_url: https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
`~/.hermes/.env` 中:
|
||||
|
||||
```bash
|
||||
GOOGLE_API_KEY=...
|
||||
```
|
||||
|
||||
### 原生 Gemini API
|
||||
|
||||
推荐使用的端点为:
|
||||
|
||||
```text
|
||||
https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
Hermes 检测到该端点后会创建原生 Gemini 适配器。在内部,Hermes 仍以 OpenAI 格式维护 Agent 循环,然后将每个请求转换为 Gemini 原生 schema:
|
||||
|
||||
- `messages[]` → Gemini `contents[]`
|
||||
- 系统提示(system prompt)→ Gemini `systemInstruction`
|
||||
- 工具 schema → Gemini `functionDeclarations`
|
||||
- 工具结果 → Gemini `functionResponse` 部分
|
||||
- 流式响应 → 供 Hermes 循环使用的 OpenAI 格式流式数据块
|
||||
|
||||
:::note Gemini 3 思维签名
|
||||
对于 Gemini 3 的工具调用,Hermes 会保留附加在函数调用部分的 `thoughtSignature` 值,并在下一个工具轮次中重放。这覆盖了多步骤 Agent 工作流中验证关键路径的需求。
|
||||
|
||||
Gemini 3 也可能在其他响应部分附加思维签名。Hermes 的原生适配器目前针对 Agent 工具循环进行了优化,尚未以完整的部分级保真度重放所有非工具调用签名。
|
||||
:::
|
||||
|
||||
### 优先使用原生端点
|
||||
|
||||
Google 还提供了 OpenAI 兼容端点:
|
||||
|
||||
```text
|
||||
https://generativelanguage.googleapis.com/v1beta/openai/
|
||||
```
|
||||
|
||||
对于 Hermes Agent 会话,请优先使用上述原生 Gemini 端点。Hermes 内置原生 Gemini 适配器,可将多轮工具调用、工具调用结果、流式传输、多模态输入以及 Gemini 响应元数据直接映射到 Gemini 的 `generateContent` API。OpenAI 兼容端点在你明确需要 OpenAI API 兼容性时仍然有用。
|
||||
|
||||
如果你之前将 `GEMINI_BASE_URL` 设置为 `/openai` URL,请将其删除或修改:
|
||||
|
||||
```bash
|
||||
GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
### OAuth Provider
|
||||
|
||||
Hermes 还提供 `google-gemini-cli` provider:
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → 选择 "Google Gemini (OAuth)"
|
||||
```
|
||||
|
||||
该方式使用浏览器 PKCE 登录和 Cloud Code Assist 后端。对于希望使用 Gemini CLI 风格 OAuth 的用户可能有用,但 Hermes 会显示明确警告,因为 Google 可能将第三方软件使用 Gemini CLI OAuth 客户端的行为视为违反政策。对于生产环境或最低风险使用场景,请优先使用上述 API 密钥 provider。
|
||||
|
||||
## 可用模型
|
||||
|
||||
`hermes model` 选择器显示 Hermes provider 注册表中维护的 Gemini 模型。常见选项包括:
|
||||
|
||||
| 模型 | ID | 说明 |
|
||||
|------|----|------|
|
||||
| Gemini 3.1 Pro Preview | `gemini-3.1-pro-preview` | 可用时最强大的预览模型 |
|
||||
| Gemini 3 Pro Preview | `gemini-3-pro-preview` | 强大的推理和编码模型 |
|
||||
| Gemini 3 Flash Preview | `gemini-3-flash-preview` | 推荐的默认选项,速度与能力均衡 |
|
||||
| Gemini 3.1 Flash Lite Preview | `gemini-3.1-flash-lite-preview` | 可用时速度最快、成本最低的选项 |
|
||||
|
||||
模型可用性会随时间变化。如果某个模型消失或未对你的密钥启用,请重新运行 `hermes model` 并从当前列表中选择。
|
||||
|
||||
:::info 模型 ID
|
||||
当 `provider: gemini` 时,请使用 Gemini 原生模型 ID,如 `gemini-3-flash-preview`,而非 OpenRouter 风格的 ID(如 `google/gemini-3-flash-preview`)。
|
||||
:::
|
||||
|
||||
### 最新别名
|
||||
|
||||
Google 为 Pro 和 Flash Gemini 系列发布了滚动别名。当你希望 Google 自动升级模型而无需修改 Hermes 配置时,`gemini-pro-latest` 和 `gemini-flash-latest` 非常实用。
|
||||
|
||||
| 别名 | 当前指向 | 说明 |
|
||||
|------|----------|------|
|
||||
| `gemini-pro-latest` | 最新 Gemini Pro 模型 | 需要 Google 当前 Pro 默认值时的最佳选择 |
|
||||
| `gemini-flash-latest` | 最新 Gemini Flash 模型 | 需要 Google 当前 Flash 默认值时的最佳选择 |
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: gemini-pro-latest
|
||||
provider: gemini
|
||||
base_url: https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
如果需要严格的可复现性,请优先使用明确的模型 ID,如 `gemini-3.1-pro-preview` 或 `gemini-3-flash-preview`。
|
||||
|
||||
### 通过 Gemini API 使用 Gemma
|
||||
|
||||
Google 也通过 Gemini API 提供 Gemma 模型。Hermes 将这些模型识别为 Google 模型,但会在默认模型选择器中隐藏吞吐量极低的 Gemma 条目,以防新用户在长时间运行的 Agent 会话中意外选择评估层级的模型。
|
||||
|
||||
常用评估 ID 包括:
|
||||
|
||||
| 模型 | ID | 说明 |
|
||||
|------|----|------|
|
||||
| Gemma 4 31B IT | `gemma-4-31b-it` | 较大的 Gemma 模型;适用于兼容性和质量评估 |
|
||||
| Gemma 4 26B A4B IT | `gemma-4-26b-a4b-it` | 可用时的较小活跃参数变体 |
|
||||
|
||||
这些模型最适合作为 Gemini API 密钥的评估选项。Google 的 Gemma API 定价仅限免费层级,与生产级 Gemini 模型相比使用上限较低,因此持续的 Hermes Agent 使用通常应切换到付费 Gemini 模型、自托管部署或具有适当配额的其他 provider。
|
||||
|
||||
如需使用选择器中隐藏的 Gemma 模型,请直接在配置中指定:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: gemma-4-31b-it
|
||||
provider: gemini
|
||||
base_url: https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
## 会话中途切换模型
|
||||
|
||||
在对话中使用 `/model` 命令:
|
||||
|
||||
```text
|
||||
/model gemini-3-flash-preview
|
||||
/model gemini-flash-latest
|
||||
/model gemini-3-pro-preview
|
||||
/model gemini-pro-latest
|
||||
/model gemma-4-31b-it
|
||||
/model gemini-3.1-flash-lite-preview
|
||||
```
|
||||
|
||||
如果尚未配置 Gemini,请退出会话并先运行 `hermes model`。`/model` 用于在已配置的 provider 和模型之间切换,不会收集新的 API 密钥。
|
||||
|
||||
## 诊断
|
||||
|
||||
```bash
|
||||
hermes doctor
|
||||
```
|
||||
|
||||
doctor 命令检查:
|
||||
|
||||
- `GOOGLE_API_KEY` 或 `GEMINI_API_KEY` 是否可用
|
||||
- `google-gemini-cli` 的 Gemini OAuth 凭据是否存在
|
||||
- 已配置的 provider 凭据是否可以解析
|
||||
|
||||
如需查看 OAuth 配额使用情况,请在 Hermes 会话中运行:
|
||||
|
||||
```text
|
||||
/gquota
|
||||
```
|
||||
|
||||
`/gquota` 适用于 `google-gemini-cli` OAuth provider,不适用于 AI Studio API 密钥 provider。
|
||||
|
||||
## Gateway(消息平台)
|
||||
|
||||
Gemini 可与所有 Hermes gateway 平台配合使用(Telegram、Discord、Slack、WhatsApp、LINE、飞书等)。将 Gemini 配置为你的 provider,然后正常启动 gateway:
|
||||
|
||||
```bash
|
||||
hermes gateway setup
|
||||
hermes gateway start
|
||||
```
|
||||
|
||||
gateway 读取 `config.yaml` 并使用相同的 Gemini provider 配置。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### "Gemini native client requires an API key"
|
||||
|
||||
Hermes 找不到可用的 API 密钥。请将以下任一项添加到 `~/.hermes/.env`:
|
||||
|
||||
```bash
|
||||
GOOGLE_API_KEY=...
|
||||
# 或
|
||||
GEMINI_API_KEY=...
|
||||
```
|
||||
|
||||
然后重新运行 `hermes model`。
|
||||
|
||||
### "This Google API key is on the free tier"
|
||||
|
||||
Hermes 在设置期间会探测 Gemini API 密钥。由于工具调用、重试、压缩和辅助任务可能需要多次模型调用,免费层级配额在少数几轮 Agent 交互后即可耗尽。
|
||||
|
||||
请为与密钥关联的 Google Cloud 项目启用计费,必要时重新生成密钥,然后运行:
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
```
|
||||
|
||||
### "404 model not found"
|
||||
|
||||
所选模型对你的账号、地区或密钥不可用。重新运行 `hermes model` 并从当前列表中选择其他 Gemini 模型。
|
||||
|
||||
### Gemma 模型未显示在 `hermes model` 中
|
||||
|
||||
Hermes 默认可能会在选择器中隐藏低吞吐量的 Gemma 模型。如果你有意评估某个模型,请直接在 `~/.hermes/config.yaml` 中设置模型 ID。
|
||||
|
||||
### Gemma 出现 "429 quota exceeded"
|
||||
|
||||
通过 Gemini API 提供的 Gemma 模型适合评估使用,但其 Gemini API 免费层级上限较低。请将其用于兼容性测试,然后切换到付费 Gemini 模型或其他 provider 以进行持续的 Agent 会话。
|
||||
|
||||
### 已配置 OpenAI 兼容端点
|
||||
|
||||
检查 `~/.hermes/.env` 中是否存在:
|
||||
|
||||
```bash
|
||||
GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
|
||||
```
|
||||
|
||||
将其修改为原生端点或删除该覆盖项:
|
||||
|
||||
```bash
|
||||
GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
|
||||
```
|
||||
|
||||
### OAuth 登录警告
|
||||
|
||||
`google-gemini-cli` provider 使用 Gemini CLI / Cloud Code Assist OAuth 流程。Hermes 在启动前会发出警告,因为这与官方 AI Studio API 密钥路径不同。如需官方 API 密钥集成,请使用 `provider: gemini` 配合 `GOOGLE_API_KEY`。
|
||||
|
||||
### 工具调用因 schema 错误而失败
|
||||
|
||||
升级 Hermes 并重新运行 `hermes model`。原生 Gemini 适配器会针对 Gemini 更严格的函数声明格式对工具 schema 进行清理;旧版本或自定义端点可能不支持此功能。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [AI Providers](/integrations/providers)
|
||||
- [Configuration](/user-guide/configuration)
|
||||
- [Fallback Providers](/user-guide/features/fallback-providers)
|
||||
- [AWS Bedrock](/guides/aws-bedrock) — 使用 AWS 凭据的原生云 provider 集成
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
title: "在 Mac 上运行本地 LLM"
|
||||
description: "使用 llama.cpp 或 MLX 在 macOS 上搭建兼容 OpenAI 的本地 LLM 服务器,涵盖模型选择、内存优化以及 Apple Silicon 上的实测基准数据"
|
||||
---
|
||||
|
||||
# 在 Mac 上运行本地 LLM
|
||||
|
||||
本指南介绍如何在 macOS 上运行一个兼容 OpenAI API 的本地 LLM 服务器。你将获得完整的隐私保护、零 API 费用,以及 Apple Silicon 上出乎意料的出色性能。
|
||||
|
||||
我们涵盖两个后端:
|
||||
|
||||
| 后端 | 安装方式 | 优势 | 格式 |
|
||||
|---------|---------|---------|--------|
|
||||
| **llama.cpp** | `brew install llama.cpp` | 首 token 延迟最低,量化 KV 缓存节省内存 | GGUF |
|
||||
| **omlx** | [omlx.ai](https://omlx.ai) | token 生成速度最快,原生 Metal 优化 | MLX (safetensors) |
|
||||
|
||||
两者均暴露兼容 OpenAI 的 `/v1/chat/completions` 端点。Hermes 支持任意一个——只需将其指向 `http://localhost:8080` 或 `http://localhost:8000`。
|
||||
|
||||
:::info 仅限 Apple Silicon
|
||||
本指南面向搭载 Apple Silicon(M1 及更新)的 Mac。Intel Mac 可使用 llama.cpp,但无 GPU 加速——性能会明显更慢。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 选择模型
|
||||
|
||||
入门推荐 **Qwen3.5-9B**——这是一个强推理模型,量化后可在 8GB+ 统一内存上轻松运行。
|
||||
|
||||
| 变体 | 磁盘占用 | 所需内存(128K 上下文) | 后端 |
|
||||
|---------|-------------|---------------------------|---------|
|
||||
| Qwen3.5-9B-Q4_K_M (GGUF) | 5.3 GB | ~10 GB(含量化 KV 缓存) | llama.cpp |
|
||||
| Qwen3.5-9B-mlx-lm-mxfp4 (MLX) | ~5 GB | ~12 GB | omlx |
|
||||
|
||||
**内存估算规则:** 模型大小 + KV 缓存。9B Q4 模型约 5 GB。128K 上下文下 Q4 量化的 KV 缓存额外占用约 4–5 GB。若使用默认(f16)KV 缓存,则会膨胀至约 16 GB。llama.cpp 中的量化 KV 缓存参数是内存受限系统的关键技巧。
|
||||
|
||||
对于更大的模型(27B、35B),你需要 32 GB+ 的统一内存。9B 是 8–16 GB 机器的最佳选择。
|
||||
|
||||
---
|
||||
|
||||
## 方案 A:llama.cpp
|
||||
|
||||
llama.cpp 是移植性最强的本地 LLM 运行时。在 macOS 上,它开箱即用地通过 Metal 进行 GPU 加速。
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
brew install llama.cpp
|
||||
```
|
||||
|
||||
安装后即可全局使用 `llama-server` 命令。
|
||||
|
||||
### 下载模型
|
||||
|
||||
你需要 GGUF 格式的模型。最简便的来源是通过 `huggingface-cli` 从 Hugging Face 下载:
|
||||
|
||||
```bash
|
||||
brew install huggingface-cli
|
||||
```
|
||||
|
||||
然后下载:
|
||||
|
||||
```bash
|
||||
huggingface-cli download unsloth/Qwen3.5-9B-GGUF Qwen3.5-9B-Q4_K_M.gguf --local-dir ~/models
|
||||
```
|
||||
|
||||
:::tip 受限模型
|
||||
Hugging Face 上的部分模型需要身份验证。如果遇到 401 或 404 错误,请先运行 `huggingface-cli login`。
|
||||
:::
|
||||
|
||||
### 启动服务器
|
||||
|
||||
```bash
|
||||
llama-server -m ~/models/Qwen3.5-9B-Q4_K_M.gguf \
|
||||
-ngl 99 \
|
||||
-c 131072 \
|
||||
-np 1 \
|
||||
-fa on \
|
||||
--cache-type-k q4_0 \
|
||||
--cache-type-v q4_0 \
|
||||
--host 0.0.0.0
|
||||
```
|
||||
|
||||
各参数说明:
|
||||
|
||||
| 参数 | 用途 |
|
||||
|------|---------|
|
||||
| `-ngl 99` | 将所有层卸载到 GPU(Metal)。设置较大的数值以确保没有层留在 CPU 上。 |
|
||||
| `-c 131072` | 上下文窗口大小(128K token)。内存不足时可减小此值。 |
|
||||
| `-np 1` | 并行槽数量。单用户使用时保持为 1——更多槽会分摊内存预算。 |
|
||||
| `-fa on` | Flash attention。减少内存占用并加速长上下文推理。 |
|
||||
| `--cache-type-k q4_0` | 将 key 缓存量化为 4-bit。**这是最大的内存节省手段。** |
|
||||
| `--cache-type-v q4_0` | 将 value 缓存量化为 4-bit。与上一项合用,相比 f16 可将 KV 缓存内存减少约 75%。 |
|
||||
| `--host 0.0.0.0` | 监听所有网络接口。若不需要网络访问,可改为 `127.0.0.1`。 |
|
||||
|
||||
当你看到以下输出时,服务器已就绪:
|
||||
|
||||
```
|
||||
main: server is listening on http://0.0.0.0:8080
|
||||
srv update_slots: all slots are idle
|
||||
```
|
||||
|
||||
### 内存受限系统的优化
|
||||
|
||||
`--cache-type-k q4_0 --cache-type-v q4_0` 参数是内存有限系统最重要的优化手段。以下是 128K 上下文下的影响对比:
|
||||
|
||||
| KV 缓存类型 | KV 缓存内存(128K 上下文,9B 模型) |
|
||||
|---------------|--------------------------------------|
|
||||
| f16(默认) | ~16 GB |
|
||||
| q8_0 | ~8 GB |
|
||||
| **q4_0** | **~4 GB** |
|
||||
|
||||
在 8 GB Mac 上,使用 `q4_0` KV 缓存并将上下文缩减为 `-c 32768`(32K)。在 16 GB 上,可以轻松使用 128K 上下文。在 32 GB+ 上,可以运行更大的模型或多个并行槽。
|
||||
|
||||
如果仍然内存不足,优先减小上下文大小(`-c`),然后尝试更小的量化级别(Q3_K_M 代替 Q4_K_M)。
|
||||
|
||||
### 测试
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8080/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "Qwen3.5-9B-Q4_K_M.gguf",
|
||||
"messages": [{"role": "user", "content": "Hello!"}],
|
||||
"max_tokens": 50
|
||||
}' | jq .choices[0].message.content
|
||||
```
|
||||
|
||||
### 获取模型名称
|
||||
|
||||
如果忘记了模型名称,可查询 models 端点:
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8080/v1/models | jq '.data[].id'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方案 B:通过 omlx 使用 MLX
|
||||
|
||||
[omlx](https://omlx.ai) 是一款 macOS 原生应用,用于管理和提供 MLX 模型服务。MLX 是 Apple 自研的机器学习框架,专为 Apple Silicon 统一内存架构优化。
|
||||
|
||||
### 安装
|
||||
|
||||
从 [omlx.ai](https://omlx.ai) 下载并安装。它提供图形界面用于模型管理,并内置服务器。
|
||||
|
||||
### 下载模型
|
||||
|
||||
使用 omlx 应用浏览并下载模型。搜索 `Qwen3.5-9B-mlx-lm-mxfp4` 并下载。模型存储在本地(通常位于 `~/.omlx/models/`)。
|
||||
|
||||
### 启动服务器
|
||||
|
||||
omlx 默认在 `http://127.0.0.1:8000` 上提供服务。通过应用 UI 启动服务,或在可用时使用 CLI。
|
||||
|
||||
### 测试
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "Qwen3.5-9B-mlx-lm-mxfp4",
|
||||
"messages": [{"role": "user", "content": "Hello!"}],
|
||||
"max_tokens": 50
|
||||
}' | jq .choices[0].message.content
|
||||
```
|
||||
|
||||
### 列出可用模型
|
||||
|
||||
omlx 可同时提供多个模型的服务:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8000/v1/models | jq '.data[].id'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 基准测试:llama.cpp vs MLX
|
||||
|
||||
两个后端在同一台机器(Apple M5 Max,128 GB 统一内存)上测试,使用相同模型(Qwen3.5-9B),量化级别相当(GGUF 使用 Q4_K_M,MLX 使用 mxfp4)。五个不同 prompt,每个运行三次,后端顺序测试以避免资源竞争。
|
||||
|
||||
### 结果
|
||||
|
||||
| 指标 | llama.cpp (Q4_K_M) | MLX (mxfp4) | 胜者 |
|
||||
|--------|-------------------|-------------|--------|
|
||||
| **TTFT(首 token 延迟,均值)** | **67 ms** | 289 ms | llama.cpp(快 4.3 倍) |
|
||||
| **TTFT(p50)** | **66 ms** | 286 ms | llama.cpp(快 4.3 倍) |
|
||||
| **生成速度(均值)** | 70 tok/s | **96 tok/s** | MLX(快 37%) |
|
||||
| **生成速度(p50)** | 70 tok/s | **96 tok/s** | MLX(快 37%) |
|
||||
| **总耗时(512 token)** | 7.3s | **5.5s** | MLX(快 25%) |
|
||||
|
||||
### 含义解读
|
||||
|
||||
- **llama.cpp** 在 prompt 处理上表现突出——其 flash attention + 量化 KV 缓存流水线可在约 66ms 内返回第一个 token。如果你在构建对响应速度敏感的交互式应用(聊天机器人、自动补全),这是显著优势。
|
||||
|
||||
- **MLX** 一旦开始生成,token 速度快约 37%。对于批量任务、长文本生成,或任何更关注总完成时间而非初始延迟的场景,MLX 完成得更快。
|
||||
|
||||
- 两个后端都**极为稳定**——多次运行间的方差可忽略不计。这些数据可作为可靠参考。
|
||||
|
||||
### 如何选择?
|
||||
|
||||
| 使用场景 | 推荐 |
|
||||
|----------|---------------|
|
||||
| 交互式聊天、低延迟工具 | llama.cpp |
|
||||
| 长文本生成、批量处理 | MLX (omlx) |
|
||||
| 内存受限(8–16 GB) | llama.cpp(量化 KV 缓存无可匹敌) |
|
||||
| 同时提供多个模型服务 | omlx(内置多模型支持) |
|
||||
| 最大兼容性(含 Linux) | llama.cpp |
|
||||
|
||||
---
|
||||
|
||||
## 连接 Hermes
|
||||
|
||||
本地服务器启动后:
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
```
|
||||
|
||||
选择 **Custom endpoint**,按提示操作。系统会询问 base URL 和模型名称——使用你所配置的后端对应的值即可。
|
||||
|
||||
---
|
||||
|
||||
## 超时设置
|
||||
|
||||
Hermes 会自动检测本地端点(localhost、局域网 IP)并放宽其流式传输超时限制。大多数情况下无需额外配置。
|
||||
|
||||
如果仍然遇到超时错误(例如在慢速硬件上使用超大上下文),可以覆盖流式读取超时:
|
||||
|
||||
```bash
|
||||
# 在 .env 中——将默认的 120s 提高到 30 分钟
|
||||
HERMES_STREAM_READ_TIMEOUT=1800
|
||||
```
|
||||
|
||||
| 超时类型 | 默认值 | 本地自动调整 | 环境变量覆盖 |
|
||||
|---------|---------|----------------------|------------------|
|
||||
| 流式读取(socket 级别) | 120s | 提升至 1800s | `HERMES_STREAM_READ_TIMEOUT` |
|
||||
| 停滞流检测 | 180s | 完全禁用 | `HERMES_STREAM_STALE_TIMEOUT` |
|
||||
| API 调用(非流式) | 1800s | 无需调整 | `HERMES_API_TIMEOUT` |
|
||||
|
||||
流式读取超时最容易引发问题——它是接收下一个数据块的 socket 级别截止时间。在大上下文的预填充(prefill)阶段,本地模型可能在处理 prompt 时数分钟内没有任何输出。自动检测机制会透明地处理这一情况。
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
title: "使用 Ollama 在本地运行 Hermes — 零 API 费用"
|
||||
description: "使用 Ollama 和 Gemma 4 等开放权重模型在本机完整运行 Hermes Agent 的分步指南,无需云端 API 密钥或付费订阅"
|
||||
---
|
||||
|
||||
# 使用 Ollama 在本地运行 Hermes — 零 API 费用
|
||||
|
||||
## 问题所在
|
||||
|
||||
云端 LLM API 按 token(令牌)计费。一次高强度的编程会话可能花费 5–20 美元。对于个人项目、学习或隐私敏感的工作,费用会不断累积——而且你的每一段对话都会发送给第三方。
|
||||
|
||||
## 本指南解决什么
|
||||
|
||||
你将在自己的硬件上完整运行 Hermes Agent,使用 [Ollama](https://ollama.com) 作为模型后端。无需 API 密钥,无需订阅,数据不会离开你的机器。配置完成后,Hermes 的使用体验与 OpenRouter 或 Anthropic 完全一致——终端命令、文件编辑、网页浏览、任务委派——只是模型在本地运行。
|
||||
|
||||
完成后,你将拥有:
|
||||
|
||||
- Ollama 提供一个或多个开放权重模型的服务
|
||||
- Hermes 通过自定义端点连接到 Ollama
|
||||
- 一个可以编辑文件、执行命令、浏览网页的本地 agent
|
||||
- 可选:由你自己的硬件驱动的 Telegram/Discord 机器人
|
||||
|
||||
## 所需条件
|
||||
|
||||
| 组件 | 最低配置 | 推荐配置 |
|
||||
|-----------|---------|-------------|
|
||||
| **内存** | 8 GB(适用于 3B 模型) | 32+ GB(适用于 27B+ 模型) |
|
||||
| **存储** | 5 GB 可用空间 | 30+ GB(适用于多个模型) |
|
||||
| **CPU** | 4 核 | 8+ 核(AMD EPYC、Ryzen、Intel Xeon) |
|
||||
| **GPU** | 非必需 | 配备 8+ GB 显存的 NVIDIA GPU 可显著提速 |
|
||||
|
||||
:::tip 仅 CPU 可用,但响应速度较慢
|
||||
Ollama 可在纯 CPU 服务器上运行。现代 8 核 CPU 运行 9B 模型约可达 ~10 tokens/sec。31B 模型在 CPU 上更慢(~2–5 tokens/sec)——每次响应需要 30–120 秒,但可以正常工作。GPU 能大幅改善这一情况。对于纯 CPU 环境,通过环境变量(而非 `config.yaml` 键)放宽 API 超时时间:
|
||||
|
||||
```bash
|
||||
# ~/.hermes/.env
|
||||
HERMES_API_TIMEOUT=1800 # 30 分钟 — 为慢速本地模型留出充裕时间
|
||||
```
|
||||
:::
|
||||
|
||||
## 第一步:安装 Ollama
|
||||
|
||||
```bash
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
```
|
||||
|
||||
验证是否正在运行:
|
||||
|
||||
```bash
|
||||
ollama --version
|
||||
curl http://localhost:11434/api/tags # 应返回 {"models":[]}
|
||||
```
|
||||
|
||||
## 第二步:拉取模型
|
||||
|
||||
根据你的硬件选择:
|
||||
|
||||
| 模型 | 磁盘占用 | 所需内存 | 工具调用 | 适用场景 |
|
||||
|-------|-------------|------------|:------------:|----------|
|
||||
| `gemma4:31b` | ~20 GB | 24+ GB | 支持 | 最佳质量——工具使用和推理能力强 |
|
||||
| `gemma2:27b` | ~16 GB | 20+ GB | 不支持 | 对话任务,不支持工具使用 |
|
||||
| `gemma2:9b` | ~5 GB | 8+ GB | 不支持 | 快速问答——无法调用工具 |
|
||||
| `llama3.2:3b` | ~2 GB | 4+ GB | 不支持 | 仅适合轻量级快速回答 |
|
||||
|
||||
:::warning 工具调用至关重要
|
||||
Hermes 是一个**agentic(智能体)**助手——它通过工具调用来编辑文件、执行命令和浏览网页。不支持工具调用的模型只能进行对话,无法执行操作。要体验完整的 Hermes 功能,请使用支持工具的模型(如 `gemma4:31b`)。
|
||||
:::
|
||||
|
||||
拉取你选择的模型:
|
||||
|
||||
```bash
|
||||
ollama pull gemma4:31b
|
||||
```
|
||||
|
||||
:::info 多个模型
|
||||
你可以拉取多个模型,并在 Hermes 中使用 `/model` 切换。Ollama 按需将活跃模型加载到内存,并自动卸载空闲模型。
|
||||
:::
|
||||
|
||||
验证模型是否正常工作:
|
||||
|
||||
```bash
|
||||
curl http://localhost:11434/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "gemma4:31b",
|
||||
"messages": [{"role": "user", "content": "Say hello"}],
|
||||
"max_tokens": 50
|
||||
}'
|
||||
```
|
||||
|
||||
你应该看到包含模型回复的 JSON 响应。
|
||||
|
||||
## 第三步:配置 Hermes
|
||||
|
||||
运行 Hermes 设置向导:
|
||||
|
||||
```bash
|
||||
hermes setup
|
||||
```
|
||||
|
||||
当提示选择提供商时,选择 **Custom Endpoint**,并输入:
|
||||
|
||||
- **Base URL:** `http://localhost:11434/v1`
|
||||
- **API Key:** 留空或输入 `no-key`(Ollama 不需要密钥)
|
||||
- **Model:** `gemma4:31b`(或你拉取的模型)
|
||||
|
||||
也可以直接编辑 `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: "gemma4:31b"
|
||||
provider: "custom"
|
||||
base_url: "http://localhost:11434/v1"
|
||||
```
|
||||
|
||||
## 第四步:开始使用 Hermes
|
||||
|
||||
```bash
|
||||
hermes
|
||||
```
|
||||
|
||||
就这样。你现在运行的是一个完全本地化的 agent。试试看:
|
||||
|
||||
```
|
||||
You: List all Python files in this directory and count the lines of code in each
|
||||
|
||||
You: Read the README.md and summarize what this project does
|
||||
|
||||
You: Create a Python script that fetches the weather for Ho Chi Minh City
|
||||
```
|
||||
|
||||
Hermes 将使用终端工具、文件操作和你的本地模型——无需任何云端调用。
|
||||
|
||||
## 第五步:为任务选择合适的模型
|
||||
|
||||
并非每个任务都需要最大的模型。以下是实用指南:
|
||||
|
||||
| 任务 | 推荐模型 | 原因 |
|
||||
|------|-------------------|-----|
|
||||
| 文件编辑、代码、终端命令 | `gemma4:31b` | 唯一具备可靠工具调用能力的模型 |
|
||||
| 快速问答(无需工具调用) | `gemma2:9b` | 对话任务响应速度快 |
|
||||
| 轻量级聊天 | `llama3.2:3b` | 最快,但能力非常有限 |
|
||||
|
||||
:::note
|
||||
对于完整的 agentic 工作(编辑文件、执行命令、浏览网页),`gemma4:31b` 目前是支持工具调用的最佳本地选项。请关注 [Ollama 的模型库](https://ollama.com/library) 以获取更新模型——工具调用支持正在快速扩展。
|
||||
:::
|
||||
|
||||
在会话中即时切换模型:
|
||||
|
||||
```
|
||||
/model gemma2:9b
|
||||
```
|
||||
|
||||
## 第六步:优化速度
|
||||
|
||||
### 增大 Ollama 的上下文窗口
|
||||
|
||||
默认情况下,Ollama 使用 2048 token 的上下文。对于 agentic 工作(工具调用、长对话),需要更大的上下文:
|
||||
|
||||
```bash
|
||||
# 创建一个扩展上下文的 Modelfile
|
||||
cat > /tmp/Modelfile << 'EOF'
|
||||
FROM gemma4:31b
|
||||
PARAMETER num_ctx 16384
|
||||
EOF
|
||||
|
||||
ollama create gemma4-16k -f /tmp/Modelfile
|
||||
```
|
||||
|
||||
然后将 Hermes 配置中的模型名称更新为 `gemma4-16k`。
|
||||
|
||||
### 保持模型常驻内存
|
||||
|
||||
默认情况下,Ollama 在模型空闲 5 分钟后将其卸载。对于持久化的 gateway 机器人,保持模型常驻:
|
||||
|
||||
```bash
|
||||
# 将 keep-alive 设置为 24 小时
|
||||
curl http://localhost:11434/api/generate \
|
||||
-d '{"model": "gemma4:31b", "keep_alive": "24h"}'
|
||||
```
|
||||
|
||||
或在 Ollama 的环境变量中全局设置:
|
||||
|
||||
```bash
|
||||
# /etc/systemd/system/ollama.service.d/override.conf
|
||||
[Service]
|
||||
Environment="OLLAMA_KEEP_ALIVE=24h"
|
||||
```
|
||||
|
||||
### 使用 GPU 卸载(如有)
|
||||
|
||||
如果你有 NVIDIA GPU,Ollama 会自动将层卸载到 GPU。通过以下命令检查:
|
||||
|
||||
```bash
|
||||
ollama ps # 显示已加载的模型及 GPU 层数
|
||||
```
|
||||
|
||||
对于 12 GB 显存 GPU 上的 31B 模型,你将获得部分卸载(约 40 层在 GPU 上,其余在 CPU 上),仍能带来显著的速度提升。
|
||||
|
||||
## 第七步:作为 Gateway 机器人运行(可选)
|
||||
|
||||
一旦 Hermes 在 CLI 中本地运行正常,你可以将其作为 Telegram 或 Discord 机器人对外提供服务——仍完全运行在你的硬件上。
|
||||
|
||||
### Telegram
|
||||
|
||||
1. 通过 [@BotFather](https://t.me/BotFather) 创建机器人并获取 token
|
||||
2. 添加到 `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: "gemma4:31b"
|
||||
provider: "custom"
|
||||
base_url: "http://localhost:11434/v1"
|
||||
|
||||
platforms:
|
||||
telegram:
|
||||
enabled: true
|
||||
token: "YOUR_TELEGRAM_BOT_TOKEN"
|
||||
```
|
||||
|
||||
3. 启动 gateway:
|
||||
|
||||
```bash
|
||||
hermes gateway
|
||||
```
|
||||
|
||||
现在在 Telegram 上给你的机器人发消息——它将使用你的本地模型进行响应。
|
||||
|
||||
### Discord
|
||||
|
||||
1. 在 [discord.com/developers](https://discord.com/developers/applications) 创建 Discord 应用
|
||||
2. 添加到配置:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
discord:
|
||||
enabled: true
|
||||
token: "YOUR_DISCORD_BOT_TOKEN"
|
||||
```
|
||||
|
||||
3. 启动:`hermes gateway`
|
||||
|
||||
## 第八步:设置回退方案(可选)
|
||||
|
||||
本地模型在处理复杂任务时可能力不从心。设置一个仅在本地模型失败时激活的云端回退:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: "gemma4:31b"
|
||||
provider: "custom"
|
||||
base_url: "http://localhost:11434/v1"
|
||||
|
||||
fallback_providers:
|
||||
- provider: openrouter
|
||||
model: anthropic/claude-sonnet-4
|
||||
```
|
||||
|
||||
这样,90% 的使用是免费的(本地),只有困难任务才会调用付费 API。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 启动时出现"Connection refused"
|
||||
|
||||
Ollama 未在运行。启动它:
|
||||
|
||||
```bash
|
||||
sudo systemctl start ollama
|
||||
# 或
|
||||
ollama serve
|
||||
```
|
||||
|
||||
### 响应缓慢
|
||||
|
||||
- **检查模型大小与内存:** 如果模型所需内存超过可用内存,会发生磁盘交换。请使用更小的模型或增加内存。
|
||||
- **检查 `ollama ps`:** 如果没有 GPU 层被卸载,响应受 CPU 限制。这对于纯 CPU 服务器是正常现象。
|
||||
- **减少上下文:** 长对话会降低推理速度。定期使用 `/compress`,或在配置中设置更低的压缩阈值。
|
||||
|
||||
### 模型不遵循工具调用
|
||||
|
||||
较小的模型(3B、7B)有时会忽略工具调用指令,输出纯文本而非结构化的函数调用。解决方案:
|
||||
|
||||
- **使用更大的模型** —— `gemma4:31b` 或 `gemma2:27b` 处理工具调用的能力远优于 3B/7B 模型。
|
||||
- **Hermes 具备自动修复功能** —— 它能检测格式错误的工具调用并自动尝试修复。
|
||||
- **设置回退方案** —— 如果本地模型连续失败 3 次,Hermes 将回退到云端提供商。
|
||||
|
||||
### 上下文窗口错误
|
||||
|
||||
Ollama 默认上下文(2048 token)对于 agentic 工作来说太小。请参阅[第六步](#step-6-optimize-for-speed)了解如何增大上下文。
|
||||
|
||||
## 费用对比
|
||||
|
||||
以下是与云端 API 相比,本地运行的节省情况,基于典型编程会话(约 10 万 token 输入,约 2 万 token 输出):
|
||||
|
||||
| 提供商 | 每次会话费用 | 每月费用(每日使用) |
|
||||
|----------|-----------------|---------------------|
|
||||
| Anthropic Claude Sonnet | ~$0.80 | ~$24 |
|
||||
| OpenRouter(GPT-4o) | ~$0.60 | ~$18 |
|
||||
| **Ollama(本地)** | **$0.00** | **$0.00** |
|
||||
|
||||
你唯一的成本是电费——根据硬件不同,每次会话约 $0.01–0.05。
|
||||
|
||||
## 本地运行效果好的场景
|
||||
|
||||
- **文件编辑和代码生成** —— 9B+ 模型处理效果良好
|
||||
- **终端命令** —— Hermes 封装命令、执行并读取输出,与模型无关
|
||||
- **网页浏览** —— 浏览器工具负责抓取内容,模型只需解读结果
|
||||
- **定时任务(Cron job)和计划任务** —— 与云端设置完全一致
|
||||
- **多平台 gateway** —— Telegram、Discord、Slack 均可与本地模型配合使用
|
||||
|
||||
## 云端模型更具优势的场景
|
||||
|
||||
- **非常复杂的多步推理** —— 70B+ 或 Claude Opus 等云端模型明显更强
|
||||
- **长上下文窗口** —— 云端模型提供 10 万–100 万 token;本地模型通常为 8K–32K
|
||||
- **大篇幅响应的速度** —— 对于长文本生成,云端推理比纯 CPU 本地运行更快
|
||||
|
||||
最佳策略:日常任务使用本地模型,困难任务设置云端回退。
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
---
|
||||
title: "注册 Microsoft Graph 应用程序"
|
||||
description: "Azure 门户操作指南:创建为 Teams 会议流水线提供支持的应用注册"
|
||||
---
|
||||
|
||||
# 注册 Microsoft Graph 应用程序
|
||||
|
||||
Teams 会议流水线使用**仅限应用**(daemon)身份验证从 Microsoft Graph 读取会议转录、录制及相关产物——无需用户登录,无需每次会议单独交互式授权。这需要一个经过管理员同意、具备应用程序权限的 Azure AD 应用注册。
|
||||
|
||||
本指南涵盖以下步骤:
|
||||
|
||||
1. 创建应用注册
|
||||
2. 创建客户端密钥
|
||||
3. 授予流水线所需的 Graph API 权限
|
||||
4. 管理员同意这些权限
|
||||
5. (可选)通过应用程序访问策略将应用限定到特定用户
|
||||
|
||||
完成本指南需要**租户管理员权限**(或由管理员代为授予同意)。请记录收集到的值——最终需要填入 `~/.hermes/.env`。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- 一个具备 Teams Premium 或 Teams 许可证(可生成会议转录和录制)的 Microsoft 365 租户
|
||||
- 可访问 Azure 门户 [entra.microsoft.com](https://entra.microsoft.com) 的管理员权限
|
||||
- 一个可公开访问的 HTTPS 端点,用于接收 Graph 变更通知(在后续 webhook 监听器步骤中配置)
|
||||
|
||||
## 步骤 1:创建应用注册
|
||||
|
||||
1. 以租户管理员身份登录 [entra.microsoft.com](https://entra.microsoft.com)。
|
||||
2. 导航至 **Identity → Applications → App registrations**。
|
||||
3. 点击 **New registration**。
|
||||
4. 填写以下内容:
|
||||
- **Name:**`Hermes Teams Meeting Pipeline`(或任何你能识别的名称)。
|
||||
- **Supported account types:***Accounts in this organizational directory only (Single tenant)*。
|
||||
- **Redirect URI:**留空——仅限应用的身份验证不需要此项。
|
||||
5. 点击 **Register**。
|
||||
|
||||
页面将跳转至应用概览页。复制以下两个值:
|
||||
|
||||
- **Application (client) ID** → `MSGRAPH_CLIENT_ID`
|
||||
- **Directory (tenant) ID** → `MSGRAPH_TENANT_ID`
|
||||
|
||||
## 步骤 2:创建客户端密钥
|
||||
|
||||
1. 在左侧导航栏中,打开 **Certificates & secrets**。
|
||||
2. 点击 **New client secret**。
|
||||
3. **Description:**`hermes-graph-secret`。**Expires:**根据你的轮换策略选择合适的值(通常为 6-24 个月)。
|
||||
4. 点击 **Add**。
|
||||
5. 立即复制 **Value** 列的值——该值仅显示一次。此值即为 `MSGRAPH_CLIENT_SECRET`。
|
||||
|
||||
> **Secret ID** 列不是密钥本身。你需要的是 **Value** 列。
|
||||
|
||||
## 步骤 3:授予 Graph API 权限
|
||||
|
||||
流水线使用最小化的应用程序权限集。仅添加所需权限;每项权限都会扩大应用在租户范围内的读取能力。
|
||||
|
||||
1. 在左侧导航栏中,打开 **API permissions**。
|
||||
2. 点击 **Add a permission** → **Microsoft Graph** → **Application permissions**。
|
||||
3. 根据下表添加流水线所需的权限。
|
||||
4. 添加完成后,点击 **Grant admin consent for `<your tenant>`**。每项权限的 Status 列应变为绿色对勾。
|
||||
|
||||
### 转录优先摘要所需权限
|
||||
|
||||
| 权限 | 允许应用执行的操作 |
|
||||
|------------|--------------------------|
|
||||
| `OnlineMeetings.Read.All` | 读取 Teams 在线会议元数据(主题、参与者、加入 URL)。 |
|
||||
| `OnlineMeetingTranscript.Read.All` | 读取 Teams 生成的会议转录。 |
|
||||
|
||||
### 录制回退所需权限(当转录不可用时)
|
||||
|
||||
| 权限 | 允许应用执行的操作 |
|
||||
|------------|--------------------------|
|
||||
| `OnlineMeetingRecording.Read.All` | 下载 Teams 会议录制以进行离线语音转文字处理。 |
|
||||
| `CallRecords.Read.All` | 仅知道加入 URL 时,通过通话记录解析会议信息。 |
|
||||
|
||||
### 出站摘要投递所需权限(仅限 Graph 模式)
|
||||
|
||||
若 `platforms.teams.extra.delivery_mode` 设置为 `graph`,流水线将通过 Graph API 将摘要发布到 Teams 频道或聊天。如果使用 `incoming_webhook` 投递模式,可跳过这些权限。
|
||||
|
||||
| 权限 | 允许应用执行的操作 |
|
||||
|------------|--------------------------|
|
||||
| `ChannelMessage.Send` | 以应用身份向 Teams 频道发布消息。 |
|
||||
| `Chat.ReadWrite.All` | 向一对一及群组聊天发布消息(仅在将 `chat_id` 设为投递目标时需要)。 |
|
||||
|
||||
### 不推荐的权限
|
||||
|
||||
- `OnlineMeetings.ReadWrite.All` / `Chat.ReadWrite`(不带 `.All`)——权限范围超出流水线所需。
|
||||
- 委托权限——流水线使用仅限应用(客户端凭据)流程;委托权限在没有用户登录的情况下无法生效。
|
||||
|
||||
## 步骤 4:(推荐)通过应用程序访问策略限定应用范围
|
||||
|
||||
默认情况下,`OnlineMeetings.Read.All` 等应用程序权限会授予应用访问租户中**所有**会议的权限。对于合作伙伴演示和开发租户而言这没有问题;但在生产环境中,你几乎肯定需要限制应用可读取哪些用户的会议。
|
||||
|
||||
Microsoft 专门为 Teams 提供了**应用程序访问策略**(Application Access Policies)。该策略仅支持 PowerShell 操作,没有门户 UI。
|
||||
|
||||
在已安装并连接 MicrosoftTeams 模块的管理员 PowerShell 中(`Connect-MicrosoftTeams`)执行:
|
||||
|
||||
```powershell
|
||||
# Create a policy scoped to the Hermes app
|
||||
New-CsApplicationAccessPolicy `
|
||||
-Identity "Hermes-Meeting-Pipeline-Policy" `
|
||||
-AppIds "<MSGRAPH_CLIENT_ID>" `
|
||||
-Description "Restrict Hermes meeting pipeline to allow-listed users"
|
||||
|
||||
# Grant the policy to specific users whose meetings the pipeline may read
|
||||
Grant-CsApplicationAccessPolicy `
|
||||
-PolicyName "Hermes-Meeting-Pipeline-Policy" `
|
||||
-Identity "alice@example.com"
|
||||
|
||||
Grant-CsApplicationAccessPolicy `
|
||||
-PolicyName "Hermes-Meeting-Pipeline-Policy" `
|
||||
-Identity "bob@example.com"
|
||||
```
|
||||
|
||||
授权后策略生效最长需要 30 分钟。使用以下命令验证:
|
||||
|
||||
```powershell
|
||||
Test-CsApplicationAccessPolicy -Identity "alice@example.com" -AppId "<MSGRAPH_CLIENT_ID>"
|
||||
```
|
||||
|
||||
若不配置此策略,**任何**用户的会议均可被读取——这正是该权限在技术层面所授予的范围。生产租户请勿跳过此步骤。
|
||||
|
||||
## 步骤 5:将凭据写入环境文件
|
||||
|
||||
将收集到的三个值填入 `~/.hermes/.env`:
|
||||
|
||||
```bash
|
||||
MSGRAPH_TENANT_ID=<directory-tenant-id>
|
||||
MSGRAPH_CLIENT_ID=<application-client-id>
|
||||
MSGRAPH_CLIENT_SECRET=<client-secret-value>
|
||||
```
|
||||
|
||||
设置文件权限,确保只有你能读取密钥:
|
||||
|
||||
```bash
|
||||
chmod 600 ~/.hermes/.env
|
||||
```
|
||||
|
||||
## 步骤 6:验证令牌流程
|
||||
|
||||
Hermes 内置了 Graph 身份验证冒烟测试。在 Hermes 安装目录下执行:
|
||||
|
||||
```python
|
||||
python -c "
|
||||
import asyncio
|
||||
from tools.microsoft_graph_auth import MicrosoftGraphTokenProvider
|
||||
provider = MicrosoftGraphTokenProvider.from_env()
|
||||
token = asyncio.run(provider.get_access_token())
|
||||
print('Token acquired, length:', len(token))
|
||||
print(provider.inspect_token_health())
|
||||
"
|
||||
```
|
||||
|
||||
成功执行后将打印一个较长的 token(令牌)字符串,以及一个健康状态字典,其中 `cached: True`,`expires_in_seconds` 值接近 3600。失败时将抛出 `MicrosoftGraphTokenError`,并附带 Azure 错误码——最常见的错误如下:
|
||||
|
||||
| Azure 错误码 | 含义 | 修复方法 |
|
||||
|-------------|---------|-----|
|
||||
| `AADSTS7000215: Invalid client secret` | 密钥值不匹配或已过期。 | 在步骤 2 中生成新密钥,并更新 `.env`。 |
|
||||
| `AADSTS700016: Application not found` | `MSGRAPH_CLIENT_ID` 错误或租户不匹配。 | 确认步骤 1 中的值来自同一应用。 |
|
||||
| `AADSTS90002: Tenant not found` | `MSGRAPH_TENANT_ID` 存在拼写错误。 | 重新从应用概览页复制 Directory (tenant) ID。 |
|
||||
| `insufficient_claims`(调用时报错,非获取令牌时) | 令牌获取成功,但 Graph 返回 401/403。 | 跳过了步骤 3 的管理员同意,或添加权限后未重新同意。重新进入 API permissions 并点击 **Grant admin consent**。 |
|
||||
|
||||
## 轮换客户端密钥
|
||||
|
||||
Azure 客户端密钥有固定的过期时间。在密钥过期前:
|
||||
|
||||
1. 在步骤 2 中创建第二个客户端密钥,不要删除第一个。
|
||||
2. 用新值更新 `~/.hermes/.env` 中的 `MSGRAPH_CLIENT_SECRET`。
|
||||
3. 重启 gateway 以使新密钥生效:`hermes gateway restart`。
|
||||
4. 使用上述冒烟测试进行验证。
|
||||
5. 在 Azure 门户中删除旧密钥。
|
||||
|
||||
## 后续步骤
|
||||
|
||||
凭据验证通过后,继续完成以下配置:
|
||||
|
||||
- **Webhook 监听器配置**——部署接收 Graph 变更通知的 `msgraph_webhook` gateway 平台。
|
||||
- **流水线配置**——配置 Teams 会议流水线运行时及操作员 CLI。
|
||||
- **出站投递**——将摘要回传至 Teams 频道或聊天。
|
||||
|
||||
上述页面将随添加对应运行时的 PR 一并发布。本凭据配置是独立的前提步骤,可提前完成。
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
title: "从 OpenClaw 迁移"
|
||||
description: "将 OpenClaw / Clawdbot 配置迁移到 Hermes Agent 的完整指南——包括迁移内容、配置键映射及迁移后的检查事项。"
|
||||
---
|
||||
|
||||
# 从 OpenClaw 迁移
|
||||
|
||||
`hermes claw migrate` 将你的 OpenClaw(或旧版 Clawdbot/Moldbot)配置导入 Hermes。本指南详细说明迁移内容、配置键映射以及迁移后的验证步骤。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 预览后迁移(始终先显示预览,再要求确认)
|
||||
hermes claw migrate
|
||||
|
||||
# 仅预览,不做任何更改
|
||||
hermes claw migrate --dry-run
|
||||
|
||||
# 完整迁移,包含 API 密钥,跳过确认
|
||||
hermes claw migrate --preset full --migrate-secrets --yes
|
||||
```
|
||||
|
||||
迁移操作在执行任何更改前,始终会显示完整的导入预览。请检查列表后确认继续。
|
||||
|
||||
默认从 `~/.openclaw/` 读取。旧版 `~/.clawdbot/` 或 `~/.moltbot/` 目录会被自动检测,旧版配置文件名(`clawdbot.json`、`moltbot.json`)同理。
|
||||
|
||||
## 选项
|
||||
|
||||
| 选项 | 说明 |
|
||||
|--------|-------------|
|
||||
| `--dry-run` | 仅预览——显示将迁移的内容后停止。 |
|
||||
| `--preset <name>` | `full`(所有兼容设置)或 `user-data`(排除基础设施配置)。两种预设默认均不导入密钥——需显式传入 `--migrate-secrets`。 |
|
||||
| `--overwrite` | 冲突时覆盖已有 Hermes 文件(默认:计划存在冲突时拒绝执行)。 |
|
||||
| `--migrate-secrets` | 包含 API 密钥。即使使用 `--preset full` 也需要显式指定——没有任何预设会静默导入密钥。 |
|
||||
| `--no-backup` | 跳过迁移前对 `~/.hermes/` 的 zip 快照备份(默认在执行前写入单个还原点归档,位于 `~/.hermes/backups/pre-migration-*.zip`;可通过 `hermes import` 还原)。 |
|
||||
| `--source <path>` | 自定义 OpenClaw 目录。 |
|
||||
| `--workspace-target <path>` | `AGENTS.md` 的放置位置。 |
|
||||
| `--skill-conflict <mode>` | `skip`(默认)、`overwrite` 或 `rename`。 |
|
||||
| `--yes` | 跳过预览后的确认提示。 |
|
||||
|
||||
## 迁移内容
|
||||
|
||||
### Persona(角色设定)、记忆与指令
|
||||
|
||||
| 内容 | OpenClaw 来源 | Hermes 目标 | 备注 |
|
||||
|------|----------------|-------------------|-------|
|
||||
| Persona | `workspace/SOUL.md` | `~/.hermes/SOUL.md` | 直接复制 |
|
||||
| 工作区指令 | `workspace/AGENTS.md` | `--workspace-target` 中的 `AGENTS.md` | 需要 `--workspace-target` 标志 |
|
||||
| 长期记忆 | `workspace/MEMORY.md` | `~/.hermes/memories/MEMORY.md` | 解析为条目,与现有内容合并并去重,使用 `§` 分隔符 |
|
||||
| 用户档案 | `workspace/USER.md` | `~/.hermes/memories/USER.md` | 与记忆相同的条目合并逻辑 |
|
||||
| 每日记忆文件 | `workspace/memory/*.md` | `~/.hermes/memories/MEMORY.md` | 所有每日文件合并至主记忆 |
|
||||
|
||||
工作区文件还会在 `workspace.default/` 和 `workspace-main/` 作为备用路径进行检测(OpenClaw 在近期版本中将 `workspace/` 重命名为 `workspace-main/`,多 Agent 配置下使用 `workspace-{agentId}`)。
|
||||
|
||||
### Skills(技能,4 个来源)
|
||||
|
||||
| 来源 | OpenClaw 位置 | Hermes 目标 |
|
||||
|--------|------------------|-------------------|
|
||||
| 工作区 skills | `workspace/skills/` | `~/.hermes/skills/openclaw-imports/` |
|
||||
| 托管/共享 skills | `~/.openclaw/skills/` | `~/.hermes/skills/openclaw-imports/` |
|
||||
| 个人跨项目 skills | `~/.agents/skills/` | `~/.hermes/skills/openclaw-imports/` |
|
||||
| 项目级共享 skills | `workspace/.agents/skills/` | `~/.hermes/skills/openclaw-imports/` |
|
||||
|
||||
Skill 冲突由 `--skill-conflict` 处理:`skip` 保留现有 Hermes skill,`overwrite` 替换,`rename` 创建带 `-imported` 后缀的副本。
|
||||
|
||||
### 模型与 Provider 配置
|
||||
|
||||
| 内容 | OpenClaw 配置路径 | Hermes 目标 | 备注 |
|
||||
|------|---------------------|-------------------|-------|
|
||||
| 默认模型 | `agents.defaults.model` | `config.yaml` → `model` | 可为字符串或 `{primary, fallbacks}` 对象 |
|
||||
| 自定义 providers | `models.providers.*` | `config.yaml` → `custom_providers` | 映射 `baseUrl`、`apiType`/`api`——同时处理短格式("openai"、"anthropic")和带连字符格式("openai-completions"、"anthropic-messages"、"google-generative-ai") |
|
||||
| Provider API 密钥 | `models.providers.*.apiKey` | `~/.hermes/.env` | 需要 `--migrate-secrets`。参见下方 [API 密钥解析](#api-key-resolution) |
|
||||
|
||||
### Agent 行为
|
||||
|
||||
| 内容 | OpenClaw 配置路径 | Hermes 配置路径 | 映射规则 |
|
||||
|------|---------------------|-------------------|---------|
|
||||
| 最大轮次 | `agents.defaults.timeoutSeconds` | `agent.max_turns` | `timeoutSeconds / 10`,上限 200 |
|
||||
| 详细模式 | `agents.defaults.verboseDefault` | `agent.verbose` | "off" / "on" / "full" |
|
||||
| 推理强度 | `agents.defaults.thinkingDefault` | `agent.reasoning_effort` | "always"/"high"/"xhigh" → "high","auto"/"medium"/"adaptive" → "medium","off"/"low"/"none"/"minimal" → "low" |
|
||||
| 压缩 | `agents.defaults.compaction.mode` | `compression.enabled` | "off" → false,其他 → true |
|
||||
| 压缩模型 | `agents.defaults.compaction.model` | `compression.summary_model` | 直接字符串复制 |
|
||||
| 人工延迟 | `agents.defaults.humanDelay.mode` | `human_delay.mode` | "natural" / "custom" / "off" |
|
||||
| 人工延迟时间 | `agents.defaults.humanDelay.minMs` / `.maxMs` | `human_delay.min_ms` / `.max_ms` | 直接复制 |
|
||||
| 时区 | `agents.defaults.userTimezone` | `timezone` | 直接字符串复制 |
|
||||
| 执行超时 | `tools.exec.timeoutSec` | `terminal.timeout` | 直接复制(字段名为 `timeoutSec`,非 `timeout`) |
|
||||
| Docker 沙箱 | `agents.defaults.sandbox.backend` | `terminal.backend` | "docker" → "docker" |
|
||||
| Docker 镜像 | `agents.defaults.sandbox.docker.image` | `terminal.docker_image` | 直接复制 |
|
||||
|
||||
### 会话重置策略
|
||||
|
||||
| OpenClaw 配置路径 | Hermes 配置路径 | 备注 |
|
||||
|---------------------|-------------------|-------|
|
||||
| `session.reset.mode` | `session_reset.mode` | "daily"、"idle" 或两者 |
|
||||
| `session.reset.atHour` | `session_reset.at_hour` | 每日重置的小时(0–23) |
|
||||
| `session.reset.idleMinutes` | `session_reset.idle_minutes` | 不活跃分钟数 |
|
||||
|
||||
注意:OpenClaw 还有 `session.resetTriggers`(简单字符串数组,如 `["daily", "idle"]`)。若结构化的 `session.reset` 不存在,迁移将回退到从 `resetTriggers` 推断。
|
||||
|
||||
### MCP 服务器
|
||||
|
||||
| OpenClaw 字段 | Hermes 字段 | 备注 |
|
||||
|----------------|-------------|-------|
|
||||
| `mcp.servers.*.command` | `mcp_servers.*.command` | stdio 传输 |
|
||||
| `mcp.servers.*.args` | `mcp_servers.*.args` | |
|
||||
| `mcp.servers.*.env` | `mcp_servers.*.env` | |
|
||||
| `mcp.servers.*.cwd` | `mcp_servers.*.cwd` | |
|
||||
| `mcp.servers.*.url` | `mcp_servers.*.url` | HTTP/SSE 传输 |
|
||||
| `mcp.servers.*.tools.include` | `mcp_servers.*.tools.include` | 工具过滤 |
|
||||
| `mcp.servers.*.tools.exclude` | `mcp_servers.*.tools.exclude` | |
|
||||
|
||||
### TTS(文字转语音)
|
||||
|
||||
TTS 设置从 OpenClaw 配置的**两个**位置读取,优先级如下:
|
||||
|
||||
1. `messages.tts.providers.{provider}.*`(规范位置)
|
||||
2. 顶层 `talk.providers.{provider}.*`(备用)
|
||||
3. 旧版扁平键 `messages.tts.{provider}.*`(最旧格式)
|
||||
|
||||
| 内容 | Hermes 目标 |
|
||||
|------|-------------------|
|
||||
| Provider 名称 | `config.yaml` → `tts.provider` |
|
||||
| ElevenLabs voice ID | `config.yaml` → `tts.elevenlabs.voice_id` |
|
||||
| ElevenLabs model ID | `config.yaml` → `tts.elevenlabs.model_id` |
|
||||
| OpenAI 模型 | `config.yaml` → `tts.openai.model` |
|
||||
| OpenAI 语音 | `config.yaml` → `tts.openai.voice` |
|
||||
| Edge TTS 语音 | `config.yaml` → `tts.edge.voice`(OpenClaw 将 "edge" 重命名为 "microsoft"——两者均可识别) |
|
||||
| TTS 资源文件 | `~/.hermes/tts/`(文件复制) |
|
||||
|
||||
### 消息平台
|
||||
|
||||
| 平台 | OpenClaw 配置路径 | Hermes `.env` 变量 | 备注 |
|
||||
|----------|---------------------|----------------------|-------|
|
||||
| Telegram | `channels.telegram.botToken` 或 `.accounts.default.botToken` | `TELEGRAM_BOT_TOKEN` | Token 可为字符串或 [SecretRef](#secretref-handling),支持扁平和 accounts 两种布局 |
|
||||
| Telegram | `credentials/telegram-default-allowFrom.json` | `TELEGRAM_ALLOWED_USERS` | 从 `allowFrom[]` 数组逗号拼接 |
|
||||
| Discord | `channels.discord.token` 或 `.accounts.default.token` | `DISCORD_BOT_TOKEN` | |
|
||||
| Discord | `channels.discord.allowFrom` 或 `.accounts.default.allowFrom` | `DISCORD_ALLOWED_USERS` | |
|
||||
| Slack | `channels.slack.botToken` 或 `.accounts.default.botToken` | `SLACK_BOT_TOKEN` | |
|
||||
| Slack | `channels.slack.appToken` 或 `.accounts.default.appToken` | `SLACK_APP_TOKEN` | |
|
||||
| Slack | `channels.slack.allowFrom` 或 `.accounts.default.allowFrom` | `SLACK_ALLOWED_USERS` | |
|
||||
| WhatsApp | `channels.whatsapp.allowFrom` 或 `.accounts.default.allowFrom` | `WHATSAPP_ALLOWED_USERS` | 通过 Baileys 二维码配对认证——迁移后需重新配对 |
|
||||
| Signal | `channels.signal.account` 或 `.accounts.default.account` | `SIGNAL_ACCOUNT` | |
|
||||
| Signal | `channels.signal.httpUrl` 或 `.accounts.default.httpUrl` | `SIGNAL_HTTP_URL` | |
|
||||
| Signal | `channels.signal.allowFrom` 或 `.accounts.default.allowFrom` | `SIGNAL_ALLOWED_USERS` | |
|
||||
| Matrix | `channels.matrix.accessToken` 或 `.accounts.default.accessToken` | `MATRIX_ACCESS_TOKEN` | 使用 `accessToken`(非 `botToken`) |
|
||||
| Mattermost | `channels.mattermost.botToken` 或 `.accounts.default.botToken` | `MATTERMOST_BOT_TOKEN` | |
|
||||
|
||||
### 其他配置
|
||||
|
||||
| 内容 | OpenClaw 路径 | Hermes 路径 | 备注 |
|
||||
|------|-------------|-------------|-------|
|
||||
| 审批模式 | `approvals.exec.mode` | `config.yaml` → `approvals.mode` | "auto"→"off","always"→"manual","smart"→"smart" |
|
||||
| 命令白名单 | `exec-approvals.json` | `config.yaml` → `command_allowlist` | 模式合并并去重 |
|
||||
| 浏览器 CDP URL | `browser.cdpUrl` | `config.yaml` → `browser.cdp_url` | |
|
||||
| 浏览器无头模式 | `browser.headless` | `config.yaml` → `browser.headless` | |
|
||||
| Brave 搜索密钥 | `tools.web.search.brave.apiKey` | `.env` → `BRAVE_API_KEY` | 需要 `--migrate-secrets` |
|
||||
| Gateway 认证 token | `gateway.auth.token` | `.env` → `HERMES_GATEWAY_TOKEN` | 需要 `--migrate-secrets` |
|
||||
| 工作目录 | `agents.defaults.workspace` | `.env` → `MESSAGING_CWD` | |
|
||||
|
||||
### 已归档(无对应 Hermes 等效项)
|
||||
|
||||
以下内容保存至 `~/.hermes/migration/openclaw/<timestamp>/archive/` 供人工审查:
|
||||
|
||||
| 内容 | 归档文件 | 在 Hermes 中的重建方式 |
|
||||
|------|-------------|--------------------------|
|
||||
| `IDENTITY.md` | `archive/workspace/IDENTITY.md` | 合并至 `SOUL.md` |
|
||||
| `TOOLS.md` | `archive/workspace/TOOLS.md` | Hermes 内置工具说明 |
|
||||
| `HEARTBEAT.md` | `archive/workspace/HEARTBEAT.md` | 使用 cron 作业执行周期性任务 |
|
||||
| `BOOTSTRAP.md` | `archive/workspace/BOOTSTRAP.md` | 使用上下文文件或 skills |
|
||||
| Cron 作业 | `archive/cron-config.json` | 通过 `hermes cron create` 重建 |
|
||||
| 插件 | `archive/plugins-config.json` | 参见 [插件指南](/user-guide/features/hooks) |
|
||||
| Hooks/webhooks | `archive/hooks-config.json` | 使用 `hermes webhook` 或 gateway hooks |
|
||||
| 记忆后端 | `archive/memory-backend-config.json` | 通过 `hermes honcho` 配置 |
|
||||
| Skills 注册表 | `archive/skills-registry-config.json` | 使用 `hermes skills config` |
|
||||
| UI/身份 | `archive/ui-identity-config.json` | 使用 `/skin` 命令 |
|
||||
| 日志 | `archive/logging-diagnostics-config.json` | 在 `config.yaml` 日志部分设置 |
|
||||
| 多 Agent 列表 | `archive/agents-list.json` | 使用 Hermes profiles |
|
||||
| 频道绑定 | `archive/bindings.json` | 按平台手动配置 |
|
||||
| 复杂频道配置 | `archive/channels-deep-config.json` | 手动配置各平台 |
|
||||
|
||||
## API 密钥解析
|
||||
|
||||
启用 `--migrate-secrets` 时,API 密钥按以下优先级从**四个来源**收集:
|
||||
|
||||
1. **配置值** — `openclaw.json` 中的 `models.providers.*.apiKey` 及 TTS provider 密钥
|
||||
2. **环境文件** — `~/.openclaw/.env`(如 `OPENROUTER_API_KEY`、`ANTHROPIC_API_KEY` 等)
|
||||
3. **配置 env 子对象** — `openclaw.json` → `"env"` 或 `"env"."vars"`(部分配置将密钥存于此处而非单独的 `.env` 文件)
|
||||
4. **认证档案** — `~/.openclaw/agents/main/agent/auth-profiles.json`(每个 Agent 的凭据)
|
||||
|
||||
配置值优先级最高,后续来源依次填补剩余空缺。
|
||||
|
||||
### 支持的密钥目标
|
||||
|
||||
`OPENROUTER_API_KEY`、`OPENAI_API_KEY`、`ANTHROPIC_API_KEY`、`DEEPSEEK_API_KEY`、`GEMINI_API_KEY`、`ZAI_API_KEY`、`MINIMAX_API_KEY`、`ELEVENLABS_API_KEY`、`TELEGRAM_BOT_TOKEN`、`VOICE_TOOLS_OPENAI_KEY`
|
||||
|
||||
不在此白名单中的密钥一律不会被复制。
|
||||
|
||||
## SecretRef 处理
|
||||
|
||||
OpenClaw 配置中 token 和 API 密钥的值支持三种格式:
|
||||
|
||||
```json
|
||||
// 纯字符串
|
||||
"channels": { "telegram": { "botToken": "123456:ABC-DEF..." } }
|
||||
|
||||
// 环境变量模板
|
||||
"channels": { "telegram": { "botToken": "${TELEGRAM_BOT_TOKEN}" } }
|
||||
|
||||
// SecretRef 对象
|
||||
"channels": { "telegram": { "botToken": { "source": "env", "id": "TELEGRAM_BOT_TOKEN" } } }
|
||||
```
|
||||
|
||||
迁移会解析所有三种格式。对于环境变量模板和 `source: "env"` 的 SecretRef 对象,会从 `~/.openclaw/.env` 和 `openclaw.json` 的 env 子对象中查找值。`source: "file"` 或 `source: "exec"` 的 SecretRef 对象无法自动解析——迁移会对此发出警告,相关值需通过 `hermes config set` 手动添加至 Hermes。
|
||||
|
||||
## 迁移后
|
||||
|
||||
1. **检查迁移报告** — 完成后打印,包含已迁移、已跳过和冲突项的计数。
|
||||
|
||||
2. **审查归档文件** — `~/.hermes/migration/openclaw/<timestamp>/archive/` 中的所有内容需要人工处理。
|
||||
|
||||
3. **开启新会话** — 导入的 skills 和记忆条目在新会话中生效,当前会话不受影响。
|
||||
|
||||
4. **验证 API 密钥** — 运行 `hermes status` 检查 provider 认证状态。
|
||||
|
||||
5. **测试消息平台** — 若迁移了平台 token,重启 gateway:`systemctl --user restart hermes-gateway`
|
||||
|
||||
6. **检查会话策略** — 验证 `hermes config get session_reset` 是否符合预期。
|
||||
|
||||
7. **重新配对 WhatsApp** — WhatsApp 使用二维码配对(Baileys),不支持 token 迁移。运行 `hermes whatsapp` 进行配对。
|
||||
|
||||
8. **清理归档** — 确认一切正常后,运行 `hermes claw cleanup` 将残留的 OpenClaw 目录重命名为 `.pre-migration/`(防止状态混淆)。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### "OpenClaw directory not found"
|
||||
|
||||
迁移依次检查 `~/.openclaw/`、`~/.clawdbot/`、`~/.moltbot/`。若你的安装路径不同,请使用 `--source /path/to/your/openclaw`。
|
||||
|
||||
### "No provider API keys found"
|
||||
|
||||
根据 OpenClaw 版本不同,密钥可能存储在多个位置:`openclaw.json` 中 `models.providers.*.apiKey` 内联、`~/.openclaw/.env`、`openclaw.json` 的 `"env"` 子对象,或 `agents/main/agent/auth-profiles.json`。迁移会检查所有四个位置。若密钥使用 `source: "file"` 或 `source: "exec"` 的 SecretRef,则无法自动解析——请通过 `hermes config set` 手动添加。
|
||||
|
||||
### 迁移后 skills 未出现
|
||||
|
||||
导入的 skills 位于 `~/.hermes/skills/openclaw-imports/`。开启新会话后生效,或运行 `/skills` 验证是否已加载。
|
||||
|
||||
### TTS 语音未迁移
|
||||
|
||||
OpenClaw 在两处存储 TTS 设置:`messages.tts.providers.*` 和顶层 `talk` 配置。迁移会检查两处。若你的 voice ID 是通过 OpenClaw UI 设置的(存储路径不同),可能需要手动设置:`hermes config set tts.elevenlabs.voice_id YOUR_VOICE_ID`。
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
sidebar_position: 15
|
||||
title: "MiniMax OAuth"
|
||||
description: "通过浏览器 OAuth 登录 MiniMax,在 Hermes Agent 中使用 MiniMax-M2.7 模型——无需 API 密钥"
|
||||
---
|
||||
|
||||
# MiniMax OAuth
|
||||
|
||||
Hermes Agent 通过基于浏览器的 OAuth 登录流程支持 **MiniMax**,使用与 [MiniMax 门户](https://www.minimax.io) 相同的凭据。无需 API 密钥或信用卡——登录一次,Hermes 即可自动刷新您的会话。
|
||||
|
||||
该传输层复用了 `anthropic_messages` 适配器(MiniMax 在 `/anthropic` 路径暴露了一个兼容 Anthropic Messages 的端点),因此所有现有的工具调用、流式传输和上下文功能无需任何适配器改动即可正常使用。
|
||||
|
||||
## 概览
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-------|
|
||||
| Provider ID | `minimax-oauth` |
|
||||
| 显示名称 | MiniMax (OAuth) |
|
||||
| 认证类型 | 浏览器 OAuth(PKCE 设备码流程) |
|
||||
| 传输层 | 兼容 Anthropic Messages(`anthropic_messages`) |
|
||||
| 模型 | `MiniMax-M2.7`、`MiniMax-M2.7-highspeed` |
|
||||
| 全球端点 | `https://api.minimax.io/anthropic` |
|
||||
| 中国端点 | `https://api.minimaxi.com/anthropic` |
|
||||
| 需要环境变量 | 否(`MINIMAX_API_KEY` **不**用于此 provider) |
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Python 3.9+
|
||||
- 已安装 Hermes Agent
|
||||
- 在 [minimax.io](https://www.minimax.io)(全球)或 [minimaxi.com](https://www.minimaxi.com)(中国)注册的 MiniMax 账户
|
||||
- 本地机器上可用的浏览器(远程会话请使用 `--no-browser`)
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 启动 provider 和模型选择器
|
||||
hermes model
|
||||
# → 从 provider 列表中选择 "MiniMax (OAuth)"
|
||||
# → Hermes 在浏览器中打开 MiniMax 授权页面
|
||||
# → 在浏览器中批准访问
|
||||
# → 选择模型(MiniMax-M2.7 或 MiniMax-M2.7-highspeed)
|
||||
# → 开始对话
|
||||
|
||||
hermes
|
||||
```
|
||||
|
||||
首次登录后,凭据将存储在 `~/.hermes/auth.json` 下,并在每次会话前自动刷新。
|
||||
|
||||
## 手动登录
|
||||
|
||||
您可以在不经过模型选择器的情况下触发登录:
|
||||
|
||||
```bash
|
||||
hermes auth add minimax-oauth
|
||||
```
|
||||
|
||||
### 中国区域
|
||||
|
||||
如果您的账户在中国平台(`minimaxi.com`),请改用中国区域 OAuth provider id `minimax-cn`,或跳过 OAuth 直接配置 `MINIMAX_CN_API_KEY` / `MINIMAX_CN_BASE_URL`。旧版文档中描述的 `--region cn` 标志**未**接入 CLI 的参数解析器;请改用 `minimax-cn` provider:
|
||||
|
||||
```bash
|
||||
hermes auth add minimax-cn --type oauth # 如果您的中国账户支持 OAuth
|
||||
# 或更简单的方式:
|
||||
echo 'MINIMAX_CN_API_KEY=your-key' >> ~/.hermes/.env
|
||||
```
|
||||
|
||||
### 远程/无头会话
|
||||
|
||||
在没有浏览器的服务器或容器上:
|
||||
|
||||
```bash
|
||||
hermes auth add minimax-oauth --no-browser
|
||||
```
|
||||
|
||||
Hermes 将打印验证 URL 和用户码——在任意设备上打开该 URL,并在提示时输入用户码。
|
||||
|
||||
## OAuth 流程
|
||||
|
||||
Hermes 针对 MiniMax OAuth 端点实现了 PKCE 设备码流程:
|
||||
|
||||
1. Hermes 生成 PKCE verifier/challenge 对和一个随机 state 值。
|
||||
2. 携带 challenge 向 `{base_url}/oauth/code` 发送 POST 请求,获取 `user_code` 和 `verification_uri`。
|
||||
3. 浏览器打开 `verification_uri`。如有提示,输入 `user_code`。
|
||||
4. Hermes 轮询 `{base_url}/oauth/token`,直到令牌到达(或超过截止时间)。
|
||||
5. 令牌(`access_token`、`refresh_token`、过期时间)以 `minimax-oauth` 为键保存到 `~/.hermes/auth.json`。
|
||||
|
||||
令牌刷新(标准 OAuth `refresh_token` 授权)在每次会话启动时自动执行,当 access token 距过期不足 60 秒时触发。
|
||||
|
||||
## 检查登录状态
|
||||
|
||||
```bash
|
||||
hermes doctor
|
||||
```
|
||||
|
||||
`◆ Auth Providers` 部分将显示:
|
||||
|
||||
```
|
||||
✓ MiniMax OAuth (logged in, region=global)
|
||||
```
|
||||
|
||||
或者,如果未登录:
|
||||
|
||||
```
|
||||
⚠ MiniMax OAuth (not logged in)
|
||||
```
|
||||
|
||||
## 切换模型
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → 选择 "MiniMax (OAuth)"
|
||||
# → 从模型列表中选择
|
||||
```
|
||||
|
||||
或直接设置模型:
|
||||
|
||||
```bash
|
||||
hermes config set model MiniMax-M2.7
|
||||
hermes config set provider minimax-oauth
|
||||
```
|
||||
|
||||
## 配置参考
|
||||
|
||||
登录后,`~/.hermes/config.yaml` 将包含类似如下的条目:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: MiniMax-M2.7
|
||||
provider: minimax-oauth
|
||||
base_url: https://api.minimax.io/anthropic
|
||||
```
|
||||
|
||||
### 区域端点
|
||||
|
||||
| Provider id | 门户 | 推理端点 |
|
||||
|-------------|--------|-------------------|
|
||||
| `minimax-oauth`(全球) | `https://api.minimax.io` | `https://api.minimax.io/anthropic` |
|
||||
| `minimax-cn`(中国) | `https://api.minimaxi.com` | `https://api.minimaxi.com/anthropic` |
|
||||
|
||||
### Provider 别名
|
||||
|
||||
以下所有别名均解析为 `minimax-oauth`:
|
||||
|
||||
```bash
|
||||
hermes --provider minimax-oauth # 规范名称
|
||||
hermes --provider minimax-portal # 别名
|
||||
hermes --provider minimax-global # 别名
|
||||
hermes --provider minimax_oauth # 别名(下划线形式)
|
||||
```
|
||||
|
||||
## 环境变量
|
||||
|
||||
`minimax-oauth` provider **不**使用 `MINIMAX_API_KEY` 或 `MINIMAX_BASE_URL`。这些变量仅用于基于 API 密钥的 `minimax` 和 `minimax-cn` provider。
|
||||
|
||||
| 变量 | 作用 |
|
||||
|----------|--------|
|
||||
| `MINIMAX_API_KEY` | 仅用于 `minimax` provider——对 `minimax-oauth` 无效 |
|
||||
| `MINIMAX_CN_API_KEY` | 仅用于 `minimax-cn` provider——对 `minimax-oauth` 无效 |
|
||||
|
||||
要将 `minimax-oauth` 设为活跃 provider,请在 `config.yaml` 中设置 `model.provider: minimax-oauth`(使用 `hermes setup` 进行引导式配置),或在单次调用时传入 `--provider minimax-oauth`:
|
||||
|
||||
```bash
|
||||
hermes --provider minimax-oauth
|
||||
```
|
||||
|
||||
## 模型
|
||||
|
||||
| 模型 | 最适合 |
|
||||
|-------|----------|
|
||||
| `MiniMax-M2.7` | 长上下文推理、复杂工具调用 |
|
||||
| `MiniMax-M2.7-highspeed` | 低延迟、轻量任务、辅助调用 |
|
||||
|
||||
两个模型均支持最多 200,000 个 token 的上下文。
|
||||
|
||||
当 `minimax-oauth` 为主 provider 时,`MiniMax-M2.7-highspeed` 也会自动用作视觉和委托任务的辅助模型。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 令牌已过期——未自动重新登录
|
||||
|
||||
Hermes 在每次会话启动时,若 access token 距过期不足 60 秒则刷新令牌。如果 access token 已经过期(例如长时间离线后),刷新将在下一次请求时自动触发。如果刷新失败并返回 `refresh_token_reused` 或 `invalid_grant`,Hermes 会将会话标记为需要重新登录。
|
||||
|
||||
当刷新失败为终态(HTTP 4xx、`invalid_grant`、授权已撤销等)时,Hermes 将 refresh token 标记为失效并在本地隔离,避免持续重放注定失败的交换。Agent 会显示一条"需要重新认证"的消息,并在您再次登录之前保持等待。
|
||||
|
||||
**解决方法:** 再次运行 `hermes auth add minimax-oauth` 以开始全新登录。下一次成功交换后隔离状态将自动清除。
|
||||
|
||||
### 授权超时
|
||||
|
||||
设备码流程有有限的过期窗口。如果您未在规定时间内批准登录,Hermes 将抛出超时错误。
|
||||
|
||||
**解决方法:** 重新运行 `hermes auth add minimax-oauth`(或 `hermes model`)。流程将重新开始。
|
||||
|
||||
### State 不匹配(可能的 CSRF)
|
||||
|
||||
Hermes 检测到授权服务器返回的 `state` 值与其发送的值不匹配。
|
||||
|
||||
**解决方法:** 重新运行登录。如果问题持续,请检查是否有代理或重定向正在修改 OAuth 响应。
|
||||
|
||||
### 从远程服务器登录
|
||||
|
||||
如果 `hermes` 无法打开浏览器窗口,请使用 `--no-browser`:
|
||||
|
||||
```bash
|
||||
hermes auth add minimax-oauth --no-browser
|
||||
```
|
||||
|
||||
Hermes 将打印 URL 和用户码。在任意设备上打开该 URL 并在那里完成流程。
|
||||
|
||||
### 运行时出现"未登录 MiniMax OAuth"错误
|
||||
|
||||
auth 存储中没有 `minimax-oauth` 的凭据。您尚未登录,或凭据文件已被删除。
|
||||
|
||||
**解决方法:** 运行 `hermes model` 并选择 MiniMax (OAuth),或运行 `hermes auth add minimax-oauth`。
|
||||
|
||||
## 退出登录
|
||||
|
||||
要移除已存储的 MiniMax OAuth 凭据:
|
||||
|
||||
```bash
|
||||
hermes auth remove minimax-oauth
|
||||
```
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [AI Providers 参考](../integrations/providers.md)
|
||||
- [环境变量](../reference/environment-variables.md)
|
||||
- [配置](../user-guide/configuration.md)
|
||||
- [hermes doctor](../reference/cli-commands.md)
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
sidebar_position: 17
|
||||
title: "SSH / 远程主机上的 OAuth"
|
||||
description: "当 Hermes 运行在远程机器、容器或跳板机后面时,如何完成基于浏览器的 OAuth(xAI、Spotify)"
|
||||
---
|
||||
|
||||
# SSH / 远程主机上的 OAuth
|
||||
|
||||
部分 Hermes 提供商——目前是 **xAI Grok OAuth** 和 **Spotify**——使用*回环重定向(loopback redirect)* OAuth 流程。认证服务器(xAI、Spotify)将浏览器重定向到 `http://127.0.0.1:<port>/callback`,由 `hermes auth ...` 命令启动的一个小型 HTTP 监听器来获取授权码。
|
||||
|
||||
当 Hermes 和浏览器在同一台机器上时,这一切运行正常。一旦两者不在同一台机器上就会出问题:你笔记本上的浏览器试图访问**你笔记本**上的 `127.0.0.1`,但监听器绑定的是**远程服务器**上的 `127.0.0.1`。
|
||||
|
||||
解决方法是一行 SSH 本地端口转发——**或者**,当你没有真正的 SSH 客户端时(GCP Cloud Shell、GitHub Codespaces、EC2 Instance Connect、Gitpod、基于浏览器的 Web IDE),使用 [#26923](https://github.com/NousResearch/hermes-agent/issues/26923) 中引入的新 `--manual-paste` 标志。
|
||||
|
||||
## 快速概览
|
||||
|
||||
```bash
|
||||
# 在你的本地机器(笔记本)上,另开一个终端:
|
||||
ssh -N -L 56121:127.0.0.1:56121 user@remote-host
|
||||
|
||||
# 在远程机器的现有 SSH 会话中:
|
||||
hermes auth add xai-oauth --no-browser
|
||||
# → Hermes 打印一个授权 URL,在笔记本的浏览器中打开它。
|
||||
# → 浏览器重定向到 127.0.0.1:56121/callback,隧道将请求转发
|
||||
# 到远程监听器,登录完成。
|
||||
```
|
||||
|
||||
`56121` 是 xAI OAuth 使用的端口。Spotify 请将其替换为 `43827`。Hermes 会在 `Waiting for callback on ...` 这一行打印它实际绑定的端口——从那里复制。
|
||||
|
||||
## 仅限浏览器的远程环境(Cloud Shell / Codespaces / EC2 Instance Connect)
|
||||
|
||||
如果你没有常规的 SSH 客户端——例如你在 GCP Cloud Shell、GitHub Codespaces、AWS EC2 Instance Connect、Gitpod 或其他基于浏览器的控制台中运行 Hermes——上述 SSH 隧道不可用。请改用 `--manual-paste`:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --manual-paste
|
||||
# → Hermes 打印一个授权 URL,在笔记本的浏览器中打开它。
|
||||
# → 在浏览器中批准。重定向到 127.0.0.1:56121/callback 会加载失败
|
||||
# ——这是预期行为。
|
||||
# → 从失败页面的地址栏复制完整 URL。
|
||||
# → 在终端的 "Callback URL:" 提示处粘贴。
|
||||
```
|
||||
|
||||
同样的标志也适用于集成模型选择器的 `hermes model --manual-paste`。如果不想粘贴完整 URL,也可以只接受裸的 `?code=...&state=...` 查询片段。
|
||||
|
||||
Hermes 对两种路径使用**相同的 PKCE verifier、state 和 nonce**,因此上游 OAuth 流程在字节层面完全一致——`--manual-paste` 纯粹是回调跳转的传输方式变更,不会降低安全性。
|
||||
|
||||
## 哪些提供商需要此操作
|
||||
|
||||
| 提供商 | 回环端口 | 需要隧道? |
|
||||
|----------|---------------|----------------|
|
||||
| `xai-oauth`(Grok SuperGrok) | `56121` | 是,当 Hermes 在远程时 |
|
||||
| Spotify | `43827` | 是,当 Hermes 在远程时 |
|
||||
| `anthropic`(Claude Pro/Max) | 不适用 | 否——粘贴代码流程 |
|
||||
| `openai-codex`(ChatGPT Plus/Pro) | 不适用 | 否——设备码流程 |
|
||||
| `minimax`、`nous-portal` | 不适用 | 否——设备码流程 |
|
||||
|
||||
如果你的提供商不在表中,则不需要隧道。
|
||||
|
||||
## 为什么监听器不能直接绑定 0.0.0.0
|
||||
|
||||
xAI 和 Spotify 都会根据白名单验证 `redirect_uri` 参数。两者都要求回环形式(`http://127.0.0.1:<exact-port>/callback`)。将监听器绑定到 `0.0.0.0` 或不同端口会导致认证服务器以 redirect_uri 不匹配为由拒绝请求。SSH 隧道可以端到端保持回环 URI 不变。
|
||||
|
||||
## 分步说明:单跳 SSH
|
||||
|
||||
### 1. 从本地机器启动隧道
|
||||
|
||||
```bash
|
||||
# xAI Grok OAuth(端口 56121)
|
||||
ssh -N -L 56121:127.0.0.1:56121 user@remote-host
|
||||
|
||||
# 或 Spotify(端口 43827)
|
||||
ssh -N -L 43827:127.0.0.1:43827 user@remote-host
|
||||
```
|
||||
|
||||
`-N` 表示"不打开远程 shell,只保持隧道开启"。在登录期间保持此终端运行。
|
||||
|
||||
### 2. 在另一个 SSH 会话中运行认证命令
|
||||
|
||||
```bash
|
||||
ssh user@remote-host
|
||||
hermes auth add xai-oauth --no-browser
|
||||
# 或 Spotify:
|
||||
# hermes auth add spotify --no-browser
|
||||
```
|
||||
|
||||
Hermes 检测到 SSH 会话后,跳过自动打开浏览器,打印授权 URL 以及 `Waiting for callback on http://127.0.0.1:<port>/callback` 这一行。
|
||||
|
||||
### 3. 在本地浏览器中打开 URL
|
||||
|
||||
从远程终端复制授权 URL,粘贴到笔记本的浏览器中。批准同意页面。认证服务器重定向到 `http://127.0.0.1:<port>/callback`。浏览器访问隧道,请求被转发到远程监听器,Hermes 打印 `Login successful!`。
|
||||
|
||||
看到成功提示后,可以关闭隧道(在第一个终端按 Ctrl+C)。
|
||||
|
||||
## 分步说明:通过跳板机
|
||||
|
||||
如果你通过堡垒机 / 跳板机访问 Hermes,使用 SSH 内置的 `-J`(ProxyJump):
|
||||
|
||||
```bash
|
||||
ssh -N -L 56121:127.0.0.1:56121 -J jump-user@jump-host user@final-host
|
||||
```
|
||||
|
||||
这会通过跳板机链式建立 SSH 连接,而不会将回环端口暴露在跳板机上。你笔记本上的本地 `127.0.0.1:56121` 直接隧道到最终远程主机上的 `127.0.0.1:56121`。
|
||||
|
||||
对于不支持 `-J` 的旧版 OpenSSH,完整写法为:
|
||||
|
||||
```bash
|
||||
ssh -N \
|
||||
-o "ProxyCommand=ssh -W %h:%p jump-user@jump-host" \
|
||||
-L 56121:127.0.0.1:56121 \
|
||||
user@final-host
|
||||
```
|
||||
|
||||
## Mosh、tmux、ssh ControlMaster
|
||||
|
||||
隧道是底层 SSH 连接的属性。如果你在 mosh 会话中的 `tmux` 里运行 Hermes,mosh 的漫游不会携带 `-L` 转发。**单独**开一个普通 SSH 会话**仅用于** `-L` 隧道——这个连接必须在整个认证流程期间保持存活。你的交互式 mosh/tmux 会话可以继续正常运行 Hermes。
|
||||
|
||||
如果你使用 `ssh -o ControlMaster=auto`,多路复用连接上的端口转发共享主连接的生命周期。如果隧道未能建立,重启主连接:
|
||||
|
||||
```bash
|
||||
ssh -O exit user@remote-host
|
||||
ssh -N -L 56121:127.0.0.1:56121 user@remote-host
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### `bind [127.0.0.1]:56121: Address already in use`
|
||||
|
||||
你笔记本上已有某个程序占用了该端口。可能是上一个隧道没有正常关闭,或者本地也有一个 Hermes 在监听。找到并终止占用进程:
|
||||
|
||||
```bash
|
||||
# macOS / Linux
|
||||
lsof -iTCP:56121 -sTCP:LISTEN
|
||||
kill <PID>
|
||||
```
|
||||
|
||||
然后重试 `ssh -L` 命令。
|
||||
|
||||
### "Could not establish connection. We couldn't reach your app."(xAI)
|
||||
|
||||
当 xAI 重定向到 `127.0.0.1:<port>/callback` 未能到达监听器时,xAI 的授权页面会显示此错误。可能是隧道未运行、端口错误,或者你使用的是 Hermes 上一次运行时打印的端口(如果首选端口被占用,端口可能会自动递增——始终以最新的 `Waiting for callback on ...` 行为准)。
|
||||
|
||||
### `xAI authorization timed out waiting for the local callback`
|
||||
|
||||
与上述原因相同——重定向从未返回。检查隧道是否仍然存活(`ssh -N` 不显示输出,查看启动它的终端),必要时重启,然后重新运行 `hermes auth add xai-oauth --no-browser`。
|
||||
|
||||
### Token 写入了错误的 `~/.hermes`
|
||||
|
||||
Token 写入运行 `hermes auth add ...` 的 Linux 用户目录下。如果你的网关 / systemd 服务以不同用户(如 `root` 或专用的 `hermes` 用户)运行,请以**该**用户身份进行认证,使 token 写入其 `~/.hermes/auth.json`。使用 `sudo -u hermes -i` 或等效命令。
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [xAI Grok OAuth](./xai-grok-oauth.md)
|
||||
- [Spotify(`通过 SSH 运行`)](../user-guide/features/spotify.md#running-over-ssh--in-a-headless-environment)
|
||||
- [SSH `-J` / ProxyJump(man 手册)](https://man.openbsd.org/ssh#J)
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
---
|
||||
title: "操作 Teams 会议流水线"
|
||||
description: "Microsoft Teams 会议流水线的运行手册、上线检查清单及操作员工作表"
|
||||
---
|
||||
|
||||
# 操作 Teams 会议流水线
|
||||
|
||||
本指南适用于已通过 [Teams Meetings](/user-guide/messaging/teams-meetings) 启用该功能之后的操作阶段。
|
||||
|
||||
本页内容:
|
||||
- 操作员 CLI 流程
|
||||
- 日常订阅维护
|
||||
- 故障排查
|
||||
- 上线检查
|
||||
- 上线工作表
|
||||
|
||||
## 核心操作员命令
|
||||
|
||||
### 验证配置快照
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline validate
|
||||
```
|
||||
|
||||
每次配置变更后首先执行此命令。
|
||||
|
||||
### 检查 token 健康状态
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline token-health
|
||||
hermes teams-pipeline token-health --force-refresh
|
||||
```
|
||||
|
||||
当怀疑 auth(认证)状态过期时,使用 `--force-refresh`。
|
||||
|
||||
### 检查订阅
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline subscriptions
|
||||
```
|
||||
|
||||
### 续期即将到期的订阅
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline maintain-subscriptions
|
||||
hermes teams-pipeline maintain-subscriptions --dry-run
|
||||
```
|
||||
|
||||
### 自动化订阅续期(生产环境必须配置)
|
||||
|
||||
**Microsoft Graph 订阅最多 72 小时后过期。** 若无任何续期操作,会议通知将在 3 天后静默停止,流水线看起来像是"故障"。这是所有基于 Graph 的集成中最常见的运维故障模式。
|
||||
|
||||
你**必须**按计划运行 `maintain-subscriptions`。从以下三种方式中选择一种:
|
||||
|
||||
#### 方式一:Hermes cron(若已运行 Hermes gateway,推荐此方式)
|
||||
|
||||
Hermes 内置 cron 调度器。`--no-agent` 模式以脚本作为任务执行(而非使用 LLM),`--script` 必须指向 `~/.hermes/scripts/` 下的文件。首先创建脚本:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.hermes/scripts
|
||||
cat > ~/.hermes/scripts/maintain-teams-subscriptions.sh <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
exec hermes teams-pipeline maintain-subscriptions
|
||||
EOF
|
||||
chmod +x ~/.hermes/scripts/maintain-teams-subscriptions.sh
|
||||
```
|
||||
|
||||
然后注册一个每 12 小时运行一次的纯脚本 cron 任务(相对于 72 小时过期窗口有 6 倍余量):
|
||||
|
||||
```bash
|
||||
hermes cron create "0 */12 * * *" \
|
||||
--name "teams-pipeline-maintain-subscriptions" \
|
||||
--no-agent \
|
||||
--script maintain-teams-subscriptions.sh \
|
||||
--deliver local
|
||||
```
|
||||
|
||||
验证注册情况并查看下次运行时间:
|
||||
|
||||
```bash
|
||||
hermes cron list
|
||||
hermes cron status # 调度器状态
|
||||
```
|
||||
|
||||
#### 方式二:systemd timer(推荐用于 Linux 生产部署)
|
||||
|
||||
创建 `/etc/systemd/system/hermes-teams-pipeline-maintain.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Hermes Teams pipeline subscription maintenance
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=hermes
|
||||
EnvironmentFile=/etc/hermes/env
|
||||
ExecStart=/usr/local/bin/hermes teams-pipeline maintain-subscriptions
|
||||
```
|
||||
|
||||
以及 `/etc/systemd/system/hermes-teams-pipeline-maintain.timer`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Run Hermes Teams pipeline subscription maintenance every 12 hours
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=12h
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
```
|
||||
|
||||
启用:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now hermes-teams-pipeline-maintain.timer
|
||||
systemctl list-timers hermes-teams-pipeline-maintain.timer
|
||||
```
|
||||
|
||||
#### 方式三:普通 crontab
|
||||
|
||||
```cron
|
||||
0 */12 * * * /usr/local/bin/hermes teams-pipeline maintain-subscriptions >> /var/log/hermes/teams-pipeline-maintain.log 2>&1
|
||||
```
|
||||
|
||||
确保 cron 环境中包含 `MSGRAPH_*` 凭据。最简单的方法:在 crontab 调用的包装脚本顶部 source `~/.hermes/.env`。
|
||||
|
||||
#### 验证续期是否正常工作
|
||||
|
||||
设置好计划任务后,在首次计划运行后检查续期活动:
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline subscriptions # 应显示 expirationDateTime 已推进
|
||||
hermes teams-pipeline maintain-subscriptions --dry-run # 大多数时候应显示"0 expiring soon"
|
||||
```
|
||||
|
||||
如果你发现 Graph webhook 在恰好约 72 小时后神秘地"停止工作",这是首先要检查的地方:续期任务是否实际运行了?
|
||||
|
||||
### 查看最近的任务
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline list
|
||||
hermes teams-pipeline list --status failed
|
||||
hermes teams-pipeline show <job-id>
|
||||
```
|
||||
|
||||
### 重放已存储的任务
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline run <job-id>
|
||||
```
|
||||
|
||||
### 干运行会议产物拉取
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline fetch --meeting-id <meeting-id>
|
||||
hermes teams-pipeline fetch --join-web-url "<join-url>"
|
||||
```
|
||||
|
||||
## 日常运行手册
|
||||
|
||||
### 首次设置后
|
||||
|
||||
按顺序执行:
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline validate
|
||||
hermes teams-pipeline token-health --force-refresh
|
||||
hermes teams-pipeline subscriptions
|
||||
```
|
||||
|
||||
然后触发或等待一个真实的会议事件,并确认:
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline list
|
||||
hermes teams-pipeline show <job-id>
|
||||
```
|
||||
|
||||
### 每日或定期检查
|
||||
|
||||
- 运行 `hermes teams-pipeline maintain-subscriptions --dry-run`
|
||||
- 检查 `hermes teams-pipeline list --status failed`
|
||||
- 确认 Teams 投递目标仍为正确的聊天或频道
|
||||
|
||||
### 变更 webhook URL 或投递目标前
|
||||
|
||||
- 更新公共通知 URL 或 Teams 目标配置
|
||||
- 运行 `hermes teams-pipeline validate`
|
||||
- 续期或重新创建受影响的订阅
|
||||
- 确认新事件落入预期的接收端
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 未创建任何任务
|
||||
|
||||
检查:
|
||||
- `msgraph_webhook` 是否已启用
|
||||
- 公共通知 URL 是否指向 `/msgraph/webhook`
|
||||
- 订阅中的 client state 是否与 `MSGRAPH_WEBHOOK_CLIENT_STATE` 匹配
|
||||
- 订阅是否在远端仍然存在且未过期
|
||||
|
||||
### 任务停留在重试状态或在摘要生成前失败
|
||||
|
||||
检查:
|
||||
- 转录权限及可用性
|
||||
- 录制权限及产物可用性
|
||||
- 若启用了录制回退,检查 `ffmpeg` 是否可用
|
||||
- Graph token 健康状态
|
||||
|
||||
### 摘要已生成但未投递到 Teams
|
||||
|
||||
检查:
|
||||
- `platforms.teams.enabled: true`
|
||||
- `delivery_mode`
|
||||
- webhook 模式下的 `incoming_webhook_url`
|
||||
- Graph 模式下的 `chat_id` 或 `team_id` 加 `channel_id`
|
||||
- 若使用 Graph 发帖,检查 Teams auth 配置
|
||||
|
||||
### 重复或意外的重放
|
||||
|
||||
检查:
|
||||
- 是否手动通过 `hermes teams-pipeline run` 重放了任务
|
||||
- 该会议的 sink 记录是否已存在
|
||||
- 是否在本地配置中有意启用了重发路径
|
||||
|
||||
## 上线检查清单
|
||||
|
||||
- [ ] Graph 凭据已存在且正确
|
||||
- [ ] `msgraph_webhook` 已启用且可从公网访问
|
||||
- [ ] `MSGRAPH_WEBHOOK_CLIENT_STATE` 已设置且与订阅匹配
|
||||
- [ ] 转录订阅已创建
|
||||
- [ ] 若需要 STT 回退,录制订阅已创建
|
||||
- [ ] 若启用录制回退,`ffmpeg` 已安装
|
||||
- [ ] Teams 出站投递目标已配置并验证
|
||||
- [ ] Notion 和 Linear 接收端仅在实际需要时配置
|
||||
- [ ] `hermes teams-pipeline validate` 返回 OK 快照
|
||||
- [ ] `hermes teams-pipeline token-health --force-refresh` 执行成功
|
||||
- [ ] **`maintain-subscriptions` 已配置计划任务**(Hermes cron、systemd timer 或 crontab——参见[自动化订阅续期](#automating-subscription-renewal-required-for-production))。若未配置,Graph 订阅将在 72 小时内静默过期。
|
||||
- [ ] 一个真实的端到端会议事件已生成存储任务
|
||||
- [ ] 至少一条摘要已到达预期的投递接收端
|
||||
|
||||
## 投递模式决策指南
|
||||
|
||||
| 模式 | 适用场景 | 权衡 |
|
||||
|------|----------|----------|
|
||||
| `incoming_webhook` | 仅需简单地向 Teams 发帖 | 配置最简单,控制较少 |
|
||||
| `graph` | 需要通过 Graph 向频道或聊天发帖 | 控制更多,auth 和目标配置更复杂 |
|
||||
|
||||
## 操作员工作表
|
||||
|
||||
上线前填写:
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-------|
|
||||
| 公共通知 URL | |
|
||||
| Graph 租户 ID | |
|
||||
| Graph 客户端 ID | |
|
||||
| Webhook client state | |
|
||||
| 转录资源订阅 | |
|
||||
| 录制资源订阅 | |
|
||||
| Teams 投递模式 | |
|
||||
| Teams 聊天 ID 或团队/频道 | |
|
||||
| Notion 数据库 ID | |
|
||||
| Linear 团队 ID | |
|
||||
| Store 路径覆盖(如有) | |
|
||||
| 每日检查负责人 | |
|
||||
|
||||
## 变更审查工作表
|
||||
|
||||
变更部署前使用:
|
||||
|
||||
| 问题 | 答案 |
|
||||
|----------|--------|
|
||||
| 是否正在变更公共 webhook URL? | |
|
||||
| 是否正在轮换 Graph 凭据? | |
|
||||
| 是否正在变更 Teams 投递模式? | |
|
||||
| 是否正在迁移到新的 Teams 聊天或频道? | |
|
||||
| 订阅是否需要重新创建或续期? | |
|
||||
| 是否需要重新进行端到端验证? | |
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Teams Meetings 设置](/user-guide/messaging/teams-meetings)
|
||||
- [Microsoft Teams bot 设置](/user-guide/messaging/teams)
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
---
|
||||
sidebar_position: 12
|
||||
title: "将脚本输出推送到消息平台"
|
||||
description: "使用 `hermes send` 将任意 shell 脚本、cron 任务、CI hook 或监控守护进程的文本发送到 Telegram、Discord、Slack、Signal 等平台。"
|
||||
---
|
||||
|
||||
# 将脚本输出推送到消息平台
|
||||
|
||||
`hermes send` 是一个轻量、可脚本化的 CLI,能将消息推送到 Hermes 已配置的任意消息平台。可以把它理解为跨平台的通知专用 `curl`——无需运行中的 gateway,无需 LLM,也无需在每个脚本里重复粘贴 bot token。
|
||||
|
||||
适用场景:
|
||||
|
||||
- 系统监控(内存、磁盘、GPU 温度、长时任务完成通知)
|
||||
- CI/CD 通知(部署完成、测试失败)
|
||||
- 需要将结果推送给你的 cron 脚本
|
||||
- 从终端发送一次性消息
|
||||
- 将任意工具的输出管道到任意平台(`make | hermes send --to slack:#builds`)
|
||||
|
||||
该命令复用 `hermes gateway` 已有的凭据和平台适配器,无需维护第二套配置。
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 向某平台的默认频道发送纯文本
|
||||
hermes send --to telegram "deploy finished"
|
||||
|
||||
# 将任意命令的 stdout 通过管道传入
|
||||
echo "RAM 92%" | hermes send --to telegram:-1001234567890
|
||||
|
||||
# 发送文件
|
||||
hermes send --to discord:#ops --file /tmp/report.md
|
||||
|
||||
# 附加主题/标题行
|
||||
hermes send --to slack:#eng --subject "[CI] build.log" --file build.log
|
||||
|
||||
# 指定线程目标(Telegram 话题、Discord 线程)
|
||||
hermes send --to telegram:-1001234567890:17585 "threaded reply"
|
||||
|
||||
# 列出所有已配置的目标
|
||||
hermes send --list
|
||||
|
||||
# 按平台过滤
|
||||
hermes send --list telegram
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 参数参考
|
||||
|
||||
| 标志 | 说明 |
|
||||
|------|-------------|
|
||||
| `-t, --to TARGET` | 目标地址。参见[目标格式](#target-formats)。 |
|
||||
| `message`(位置参数) | 消息文本。省略时从 `--file` 或 stdin 读取。 |
|
||||
| `-f, --file PATH` | 从文件读取消息体。`--file -` 强制从 stdin 读取。 |
|
||||
| `-s, --subject LINE` | 在消息体前添加标题/主题行。 |
|
||||
| `-l, --list` | 列出可用目标。可选位置参数用于按平台过滤。 |
|
||||
| `-q, --quiet` | 成功时不输出到 stdout(仅返回退出码——适合脚本使用)。 |
|
||||
| `--json` | 输出发送结果的原始 JSON。 |
|
||||
| `-h, --help` | 显示内置帮助文本。 |
|
||||
|
||||
### 目标格式 {#target-formats}
|
||||
|
||||
| 格式 | 示例 | 含义 |
|
||||
|--------|---------|---------|
|
||||
| `platform` | `telegram` | 发送到该平台配置的默认频道 |
|
||||
| `platform:chat_id` | `telegram:-1001234567890` | 指定数字 chat / 群组 / 用户 |
|
||||
| `platform:chat_id:thread_id` | `telegram:-1001234567890:17585` | 指定线程或 Telegram 论坛话题 |
|
||||
| `platform:#channel` | `discord:#ops` | 易读的频道名称(通过频道目录解析) |
|
||||
| `platform:+E164` | `signal:+15551234567` | 以电话号码寻址的平台:Signal、SMS、WhatsApp |
|
||||
|
||||
Hermes 附带适配器的所有平台均可作为目标:
|
||||
`telegram`、`discord`、`slack`、`signal`、`sms`、`whatsapp`、`matrix`、
|
||||
`mattermost`、`feishu`、`dingtalk`、`wecom`、`weixin`、`email` 等。
|
||||
|
||||
### 退出码
|
||||
|
||||
| 码 | 含义 |
|
||||
|------|---------|
|
||||
| `0` | 发送(或列出)成功 |
|
||||
| `1` | 平台层面投递失败(认证、权限、网络) |
|
||||
| `2` | 用法 / 参数 / 配置错误 |
|
||||
|
||||
退出码遵循标准 Unix 惯例,脚本可以像处理 `curl` 或 `grep` 一样对其进行分支判断。
|
||||
|
||||
---
|
||||
|
||||
## 消息体解析顺序
|
||||
|
||||
`hermes send` 按以下顺序解析消息体:
|
||||
|
||||
1. **位置参数** — `hermes send --to telegram "hi"`
|
||||
2. **`--file PATH`** — `hermes send --to telegram --file msg.txt`
|
||||
3. **管道 stdin** — `echo hi | hermes send --to telegram`
|
||||
|
||||
当 stdin 是 TTY(无管道)时,Hermes **不会**等待输入——你会收到明确的用法错误提示。这可以防止脚本在意外省略消息体时挂起。
|
||||
|
||||
---
|
||||
|
||||
## 实际使用示例
|
||||
|
||||
### 监控:内存 / 磁盘告警
|
||||
|
||||
用一行简洁的代码替换 watchdog 脚本中的 `curl https://api.telegram.org/...` 调用:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
ram_pct=$(free | awk '/^Mem:/ {printf "%d", $3 * 100 / $2}')
|
||||
if [ "$ram_pct" -ge 85 ]; then
|
||||
hermes send --to telegram --subject "⚠ MEMORY WARNING" \
|
||||
"RAM ${ram_pct}% on $(hostname)"
|
||||
fi
|
||||
```
|
||||
|
||||
由于 `hermes send` 复用你的 Hermes 配置,同一脚本可在任何安装了 Hermes 的主机上运行——无需手动将 bot token 导出到每台机器的环境变量中。
|
||||
|
||||
:::tip 不要用 gateway 监控自身
|
||||
对于可能在 gateway 本身出现问题时触发的 watchdog(OOM 告警、磁盘满告警),请继续使用最简单的 `curl` 调用,而非 `hermes send`。如果 Python 解释器因机器抖动无法加载,你仍然希望告警能发出去。
|
||||
:::
|
||||
|
||||
### CI / CD:构建与测试结果
|
||||
|
||||
```bash
|
||||
# 在 .github/workflows/deploy.yml 或任意 CI 脚本中
|
||||
if ./scripts/deploy.sh; then
|
||||
hermes send --to slack:#deploys "✅ ${CI_COMMIT_SHA:0:7} deployed"
|
||||
else
|
||||
tail -n 100 deploy.log | hermes send \
|
||||
--to slack:#deploys --subject "❌ deploy failed"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Cron:每日报告
|
||||
|
||||
```bash
|
||||
# Crontab 条目
|
||||
0 9 * * * /usr/local/bin/generate-metrics.sh \
|
||||
| /home/me/.hermes/bin/hermes send \
|
||||
--to telegram --subject "Daily metrics $(date +%Y-%m-%d)"
|
||||
```
|
||||
|
||||
### 长时任务:完成后推送通知
|
||||
|
||||
```bash
|
||||
./train.py --epochs 200 && \
|
||||
hermes send --to telegram "training done" || \
|
||||
hermes send --to telegram "training failed (exit $?)"
|
||||
```
|
||||
|
||||
### 脚本中使用 `--json` 与 `--quiet`
|
||||
|
||||
```bash
|
||||
# 投递失败时让脚本硬失败;成功时不污染日志
|
||||
hermes send --to telegram --quiet "keepalive" || {
|
||||
echo "Telegram delivery failed" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 捕获消息 ID 以便后续编辑 / 回复线程
|
||||
msg_id=$(hermes send --to discord:#ops --json "build started" \
|
||||
| jq -r .message_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `hermes send` 需要 gateway 运行吗?
|
||||
|
||||
**通常不需要。** 对于所有基于 bot token 的平台——Telegram、Discord、Slack、Signal、SMS、WhatsApp Cloud API 等——`hermes send` 直接使用 `~/.hermes/.env` 和 `~/.hermes/config.yaml` 中的凭据调用平台的 REST 接口。它是一个独立的子进程,消息投递完成后即退出。
|
||||
|
||||
只有依赖持久适配器连接的**插件平台**才需要运行中的 gateway(例如,某个保持长连接 WebSocket 的自定义插件)。此时你会收到明确的错误提示,指引你启动 gateway;执行 `hermes gateway start` 后重试即可。
|
||||
|
||||
---
|
||||
|
||||
## 列出与发现目标
|
||||
|
||||
在向特定频道发送消息之前,可以查看可用目标:
|
||||
|
||||
```bash
|
||||
# 列出所有已配置平台的所有目标
|
||||
hermes send --list
|
||||
|
||||
# 仅列出 Telegram 目标
|
||||
hermes send --list telegram
|
||||
|
||||
# 机器可读格式
|
||||
hermes send --list --json
|
||||
```
|
||||
|
||||
列表数据来源于 `~/.hermes/channel_directory.json`,gateway 运行期间每隔几分钟刷新一次。如果看到"尚未发现频道",请先启动一次 gateway(`hermes gateway start`)以填充缓存。
|
||||
|
||||
易读名称(`discord:#ops`、`slack:#engineering`)在发送时通过该缓存解析,无需记忆数字 ID。
|
||||
|
||||
---
|
||||
|
||||
## 与其他方案的对比
|
||||
|
||||
| 方案 | 多平台 | 复用 Hermes 凭据 | 需要 gateway | 最适合 |
|
||||
|----------|----------------|---------------------|---------------|----------|
|
||||
| `hermes send` | ✅ | ✅ | 否(bot token) | 以下所有场景 |
|
||||
| 对各平台直接 `curl` | 各自单独编写 | 手动管理 | 否 | 关键 watchdog |
|
||||
| 带 `--deliver` 的 `cron` 任务 | ✅ | ✅ | 否 | 定时 agent 任务 |
|
||||
| `send_message` agent 工具 | ✅ | ✅ | 否 | agent 循环内部 |
|
||||
|
||||
`hermes send` 有意保持最简接口。如果需要 agent 决定说什么,请在对话或 cron 任务中使用 `send_message` 工具。如果需要定时运行并生成 LLM 内容,请使用带 `deliver='telegram:...'` 的 `cronjob(action='create', prompt=...)`。如果只需要管道传输原始字符串,直接用 `hermes send`。
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [用 Cron 自动化一切](/guides/automate-with-cron) —
|
||||
输出自动投递到任意平台的定时任务。
|
||||
- [Gateway 内部机制](/developer-guide/gateway-internals) —
|
||||
`hermes send` 与 cron 投递共享的投递路由器。
|
||||
- [消息平台配置](/user-guide/messaging/) —
|
||||
各平台的一次性配置说明。
|
||||
@@ -0,0 +1,341 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
title: "将 Hermes 作为 Python 库使用"
|
||||
description: "将 AIAgent 嵌入你自己的 Python 脚本、Web 应用或自动化流水线——无需 CLI"
|
||||
---
|
||||
|
||||
# 将 Hermes 作为 Python 库使用
|
||||
|
||||
Hermes 不仅仅是一个 CLI 工具。你可以直接导入 `AIAgent`,在自己的 Python 脚本、Web 应用或自动化流水线中以编程方式使用它。本指南将介绍具体方法。
|
||||
|
||||
---
|
||||
|
||||
## 安装
|
||||
|
||||
直接从仓库安装 Hermes:
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/NousResearch/hermes-agent.git
|
||||
```
|
||||
|
||||
或使用 [uv](https://docs.astral.sh/uv/):
|
||||
|
||||
```bash
|
||||
uv pip install git+https://github.com/NousResearch/hermes-agent.git
|
||||
```
|
||||
|
||||
也可以在 `requirements.txt` 中固定版本:
|
||||
|
||||
```text
|
||||
hermes-agent @ git+https://github.com/NousResearch/hermes-agent.git
|
||||
```
|
||||
|
||||
:::tip
|
||||
将 Hermes 作为库使用时,CLI 所需的环境变量同样必须设置。至少需要设置 `OPENROUTER_API_KEY`(若直接访问提供商,则设置 `OPENAI_API_KEY` 或 `ANTHROPIC_API_KEY`)。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 基本用法
|
||||
|
||||
使用 Hermes 最简单的方式是 `chat()` 方法——传入一条消息,返回一个字符串:
|
||||
|
||||
```python
|
||||
from run_agent import AIAgent
|
||||
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
)
|
||||
response = agent.chat("What is the capital of France?")
|
||||
print(response)
|
||||
```
|
||||
|
||||
`chat()` 在内部处理完整的对话循环——工具调用、重试等一切事务——并仅返回最终的文本响应。
|
||||
|
||||
:::warning
|
||||
将 Hermes 嵌入自己的代码时,务必设置 `quiet_mode=True`。否则,agent 会打印 CLI 的加载动画、进度指示器及其他终端输出,从而干扰你的应用输出。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 完整对话控制
|
||||
|
||||
如需对对话进行更精细的控制,可直接使用 `run_conversation()`。它返回一个包含完整响应、消息历史和元数据的字典:
|
||||
|
||||
```python
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
)
|
||||
|
||||
result = agent.run_conversation(
|
||||
user_message="Search for recent Python 3.13 features",
|
||||
task_id="my-task-1",
|
||||
)
|
||||
|
||||
print(result["final_response"])
|
||||
print(f"Messages exchanged: {len(result['messages'])}")
|
||||
```
|
||||
|
||||
返回的字典包含:
|
||||
- **`final_response`** — agent 的最终文本回复
|
||||
- **`messages`** — 完整的消息历史(系统消息、用户消息、助手消息、工具调用)
|
||||
|
||||
(传入的 `task_id` 存储在 agent 实例上用于 VM 隔离,不会在返回字典中回显。)
|
||||
|
||||
你也可以传入自定义系统消息,覆盖该次调用的临时系统 prompt(提示词):
|
||||
|
||||
```python
|
||||
result = agent.run_conversation(
|
||||
user_message="Explain quicksort",
|
||||
system_message="You are a computer science tutor. Use simple analogies.",
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置工具集
|
||||
|
||||
使用 `enabled_toolsets` 或 `disabled_toolsets` 控制 agent 可访问的工具集:
|
||||
|
||||
```python
|
||||
# 仅启用 Web 工具(浏览、搜索)
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
enabled_toolsets=["web"],
|
||||
quiet_mode=True,
|
||||
)
|
||||
|
||||
# 启用除终端访问外的所有功能
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
disabled_toolsets=["terminal"],
|
||||
quiet_mode=True,
|
||||
)
|
||||
```
|
||||
|
||||
:::tip
|
||||
当你需要一个功能最小化、受限的 agent 时(例如,仅用于研究机器人的 Web 搜索),使用 `enabled_toolsets`。当你需要大部分功能但需限制特定能力时(例如,在共享环境中禁用终端访问),使用 `disabled_toolsets`。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 多轮对话
|
||||
|
||||
通过将消息历史传回来维护多轮对话的状态:
|
||||
|
||||
```python
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
)
|
||||
|
||||
# 第一轮
|
||||
result1 = agent.run_conversation("My name is Alice")
|
||||
history = result1["messages"]
|
||||
|
||||
# 第二轮——agent 记住了上下文
|
||||
result2 = agent.run_conversation(
|
||||
"What's my name?",
|
||||
conversation_history=history,
|
||||
)
|
||||
print(result2["final_response"]) # "Your name is Alice."
|
||||
```
|
||||
|
||||
`conversation_history` 参数接受上一次结果的 `messages` 列表。agent 会在内部复制该列表,因此你的原始列表不会被修改。
|
||||
|
||||
---
|
||||
|
||||
## 保存轨迹数据
|
||||
|
||||
启用轨迹保存,以 ShareGPT 格式捕获对话——适用于生成训练数据或调试:
|
||||
|
||||
```python
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
save_trajectories=True,
|
||||
quiet_mode=True,
|
||||
)
|
||||
|
||||
agent.chat("Write a Python function to sort a list")
|
||||
# 以 ShareGPT 格式保存到 trajectory_samples.jsonl
|
||||
```
|
||||
|
||||
每次对话以单行 JSONL 的形式追加写入,便于从自动化运行中收集数据集。
|
||||
|
||||
---
|
||||
|
||||
## 自定义系统 Prompt
|
||||
|
||||
使用 `ephemeral_system_prompt` 设置自定义系统 prompt,用于引导 agent 的行为,但**不会**保存到轨迹文件中(保持训练数据的整洁):
|
||||
|
||||
```python
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
ephemeral_system_prompt="You are a SQL expert. Only answer database questions.",
|
||||
quiet_mode=True,
|
||||
)
|
||||
|
||||
response = agent.chat("How do I write a JOIN query?")
|
||||
print(response)
|
||||
```
|
||||
|
||||
这非常适合构建专用 agent——代码审查员、文档撰写员、SQL 助手——全部使用相同的底层工具。
|
||||
|
||||
---
|
||||
|
||||
## 批量处理
|
||||
|
||||
如需并行运行大量 prompt,Hermes 提供了 `batch_runner.py`,它可管理并发的 `AIAgent` 实例并进行适当的资源隔离:
|
||||
|
||||
```bash
|
||||
python batch_runner.py --input prompts.jsonl --output results.jsonl
|
||||
```
|
||||
|
||||
每个 prompt 都有自己的 `task_id` 和隔离环境。如果需要自定义批处理逻辑,可以直接使用 `AIAgent` 构建:
|
||||
|
||||
```python
|
||||
import concurrent.futures
|
||||
from run_agent import AIAgent
|
||||
|
||||
prompts = [
|
||||
"Explain recursion",
|
||||
"What is a hash table?",
|
||||
"How does garbage collection work?",
|
||||
]
|
||||
|
||||
def process_prompt(prompt):
|
||||
# 每个任务创建一个新的 agent 实例以保证线程安全
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
skip_memory=True,
|
||||
)
|
||||
return agent.chat(prompt)
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
|
||||
results = list(executor.map(process_prompt, prompts))
|
||||
|
||||
for prompt, result in zip(prompts, results):
|
||||
print(f"Q: {prompt}\nA: {result}\n")
|
||||
```
|
||||
|
||||
:::warning
|
||||
务必为**每个线程或任务创建一个新的 `AIAgent` 实例**。agent 维护着内部状态(对话历史、工具会话、迭代计数器),这些状态不是线程安全的,不能共享。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 集成示例
|
||||
|
||||
### FastAPI 端点
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from run_agent import AIAgent
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
message: str
|
||||
model: str = "anthropic/claude-sonnet-4"
|
||||
|
||||
@app.post("/chat")
|
||||
async def chat(request: ChatRequest):
|
||||
agent = AIAgent(
|
||||
model=request.model,
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=True,
|
||||
)
|
||||
response = agent.chat(request.message)
|
||||
return {"response": response}
|
||||
```
|
||||
|
||||
### Discord 机器人
|
||||
|
||||
```python
|
||||
import discord
|
||||
from run_agent import AIAgent
|
||||
|
||||
client = discord.Client(intents=discord.Intents.default())
|
||||
|
||||
@client.event
|
||||
async def on_message(message):
|
||||
if message.author == client.user:
|
||||
return
|
||||
if message.content.startswith("!hermes "):
|
||||
query = message.content[8:]
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=True,
|
||||
platform="discord",
|
||||
)
|
||||
response = agent.chat(query)
|
||||
await message.channel.send(response[:2000])
|
||||
|
||||
client.run("YOUR_DISCORD_TOKEN")
|
||||
```
|
||||
|
||||
### CI/CD 流水线步骤
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""CI step: auto-review a PR diff."""
|
||||
import subprocess
|
||||
from run_agent import AIAgent
|
||||
|
||||
diff = subprocess.check_output(["git", "diff", "main...HEAD"]).decode()
|
||||
|
||||
agent = AIAgent(
|
||||
model="anthropic/claude-sonnet-4",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=True,
|
||||
disabled_toolsets=["terminal", "browser"],
|
||||
)
|
||||
|
||||
review = agent.chat(
|
||||
f"Review this PR diff for bugs, security issues, and style problems:\n\n{diff}"
|
||||
)
|
||||
print(review)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键构造函数参数
|
||||
|
||||
| 参数 | 类型 | 默认值 | 描述 |
|
||||
|-----------|------|---------|-------------|
|
||||
| `model` | `str` | `"anthropic/claude-opus-4.6"` | OpenRouter 格式的模型名称 |
|
||||
| `quiet_mode` | `bool` | `False` | 抑制 CLI 输出 |
|
||||
| `enabled_toolsets` | `List[str]` | `None` | 白名单指定工具集 |
|
||||
| `disabled_toolsets` | `List[str]` | `None` | 黑名单指定工具集 |
|
||||
| `save_trajectories` | `bool` | `False` | 将对话保存为 JSONL |
|
||||
| `ephemeral_system_prompt` | `str` | `None` | 自定义系统 prompt(不保存到轨迹文件) |
|
||||
| `max_iterations` | `int` | `90` | 每次对话的最大工具调用迭代次数 |
|
||||
| `skip_context_files` | `bool` | `False` | 跳过加载 AGENTS.md 文件 |
|
||||
| `skip_memory` | `bool` | `False` | 禁用持久化内存的读写 |
|
||||
| `api_key` | `str` | `None` | API 密钥(回退到环境变量) |
|
||||
| `base_url` | `str` | `None` | 自定义 API 端点 URL |
|
||||
| `platform` | `str` | `None` | 平台提示(`"discord"`、`"telegram"` 等) |
|
||||
|
||||
---
|
||||
|
||||
## 重要说明
|
||||
|
||||
:::tip
|
||||
- 如果不希望将工作目录中的 `AGENTS.md` 文件加载到系统 prompt 中,请设置 **`skip_context_files=True`**。
|
||||
- 设置 **`skip_memory=True`** 可阻止 agent 读写持久化内存——推荐用于无状态 API 端点。
|
||||
- `platform` 参数(如 `"discord"`、`"telegram"`)会注入平台特定的格式化提示,使 agent 适配其输出风格。
|
||||
:::
|
||||
|
||||
:::warning
|
||||
- **线程安全**:每个线程或任务创建一个 `AIAgent` 实例。切勿在并发调用中共享同一实例。
|
||||
- **资源清理**:agent 在对话结束时会自动清理资源(终端会话、浏览器实例)。若在长期运行的进程中使用,请确保每次对话正常结束。
|
||||
- **迭代限制**:默认的 `max_iterations=90` 较为宽松。对于简单的问答场景,建议适当降低该值(如 `max_iterations=10`),以防止工具调用循环失控并控制成本。
|
||||
:::
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "通过 Nous Portal 运行 Hermes Agent"
|
||||
description: "完整操作指南:订阅、配置、切换模型、启用 gateway 工具并验证路由"
|
||||
---
|
||||
|
||||
# 通过 Nous Portal 运行 Hermes Agent
|
||||
|
||||
本指南带你从头到尾完成在 [Nous Portal](https://portal.nousresearch.com) 订阅下运行 Hermes Agent 的全过程——从注册账号到验证每个工具的路由是否正确。如果你只想了解 Portal 的概述及订阅内容,请参阅 [Nous Portal 集成页面](/integrations/nous-portal)。本页是操作步骤脚本。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- 已安装 Hermes Agent([快速入门](/getting-started/quickstart))
|
||||
- 在你正在配置的机器上有可用的浏览器(或 SSH 端口转发——参见 [OAuth over SSH](/guides/oauth-over-ssh))
|
||||
- 约 5 分钟时间
|
||||
|
||||
你**不需要**:OpenAI 密钥、Anthropic 密钥、Firecrawl 账号、FAL 账号、Browser Use 账号,或任何其他按供应商分配的凭证。这正是 Portal 的意义所在。
|
||||
|
||||
## 1. 获取订阅
|
||||
|
||||
打开 [portal.nousresearch.com/manage-subscription](https://portal.nousresearch.com/manage-subscription),注册并选择一个套餐。
|
||||
|
||||
已订阅?跳至第 2 步。
|
||||
|
||||
## 2. 运行一键配置
|
||||
|
||||
```bash
|
||||
hermes setup --portal
|
||||
```
|
||||
|
||||
这条命令会完成五件事:
|
||||
|
||||
1. 打开浏览器跳转至 portal.nousresearch.com 进行 OAuth 登录
|
||||
2. 将 refresh token 存储至 `~/.hermes/auth.json`
|
||||
3. 在 `~/.hermes/config.yaml` 中设置 `model.provider: nous`
|
||||
4. 选择一个默认的 agentic 模型(`anthropic/claude-sonnet-4.6` 或类似模型)
|
||||
5. 为网页搜索、图像生成、TTS 和浏览器自动化开启 Tool Gateway
|
||||
|
||||
命令执行完毕后,你将回到终端,可以直接开始对话。
|
||||
|
||||
### 如果我通过 SSH 连接到服务器怎么办?
|
||||
|
||||
OAuth 需要浏览器,但 loopback 回调运行在 Hermes 所在的机器上。有两种方案:
|
||||
|
||||
```bash
|
||||
# 方案 A:SSH 端口转发(推荐)
|
||||
ssh -N -L 8642:127.0.0.1:8642 user@remote-host # 在本地终端执行
|
||||
hermes setup --portal # 在远程机器上执行,在本地浏览器中打开打印出的 URL
|
||||
|
||||
# 方案 B:手动粘贴(适用于 Cloud Shell、Codespaces、EC2 Instance Connect)
|
||||
hermes auth add nous --type oauth --manual-paste
|
||||
# 然后重新运行 `hermes setup --portal` 以连接 provider + gateway
|
||||
```
|
||||
|
||||
完整操作说明(包括 ProxyJump 链、mosh/tmux 和 ControlMaster 注意事项)请参阅 [OAuth over SSH / 远程主机](/guides/oauth-over-ssh)。
|
||||
|
||||
## 3. 验证配置是否成功
|
||||
|
||||
```bash
|
||||
hermes portal info
|
||||
```
|
||||
|
||||
你应该看到:
|
||||
|
||||
```
|
||||
Nous Portal
|
||||
───────────
|
||||
Auth: ✓ logged in
|
||||
Portal: https://portal.nousresearch.com
|
||||
Model: ✓ using Nous as inference provider
|
||||
|
||||
Tool Gateway
|
||||
────────────
|
||||
Web search & extract via Nous Portal
|
||||
Image generation via Nous Portal
|
||||
Text-to-speech via Nous Portal
|
||||
Browser automation via Nous Portal
|
||||
```
|
||||
|
||||
如果任何一行显示的不是"via Nous Portal",或者 auth 行显示"not logged in",请跳至下方的[故障排查](#troubleshooting)。
|
||||
|
||||
## 4. 运行第一次对话
|
||||
|
||||
```bash
|
||||
hermes chat
|
||||
```
|
||||
|
||||
尝试一个同时调用模型和 Tool Gateway 的请求:
|
||||
|
||||
```
|
||||
Hey, search the web for "Hermes Agent release notes" and summarize the top 3 hits.
|
||||
```
|
||||
|
||||
你应该看到 Hermes 调用 `web_search`(通过 gateway 由 Firecrawl 提供支持)并返回摘要。如果搜索正常执行且响应内容合理,说明配置完成——Portal 已端到端连通。
|
||||
|
||||
## 5. 选择你实际需要的模型
|
||||
|
||||
`hermes setup --portal` 会在设置过程中让你选择模型,但订阅的意义在于可以访问完整的模型目录——随时可在会话中使用 `/model` 切换:
|
||||
|
||||
```bash
|
||||
/model anthropic/claude-sonnet-4.6 # 最佳通用 agentic 模型
|
||||
/model openai/gpt-5.4 # 强推理 + 工具调用
|
||||
/model google/gemini-2.5-pro # 超大上下文窗口
|
||||
/model deepseek/deepseek-v3.2 # 高性价比编程模型
|
||||
/model anthropic/claude-opus-4.6 # 处理复杂问题的重量级模型
|
||||
```
|
||||
|
||||
或者打开选择器浏览:
|
||||
|
||||
```bash
|
||||
/model
|
||||
```
|
||||
|
||||
永久设置不同的默认模型:
|
||||
|
||||
```bash
|
||||
# 在终端中,在任何会话之外执行
|
||||
hermes config set model.default anthropic/claude-sonnet-4.6
|
||||
```
|
||||
|
||||
### 不要在 agent 任务中使用 Hermes-4
|
||||
|
||||
Hermes-4-70B 和 Hermes-4-405B 在 Portal 上以大幅折扣提供,但它们是**对话/推理模型**,并非针对工具调用优化的模型。它们在多步骤 agent 循环中表现不佳。请通过 [Nous Chat](https://chat.nousresearch.com) 将它们用于对话/研究工作,或通过[订阅代理](/user-guide/features/subscription-proxy)从非 agent 工具中使用。对于 Hermes Agent 本身,请坚持使用上述前沿 agentic 模型。
|
||||
|
||||
Portal 的[信息页面](https://portal.nousresearch.com/info)也有此说明——这是 Nous 官方指导,并非仅代表 Hermes 一方的意见。
|
||||
|
||||
## 6. (可选)自定义 Tool Gateway 路由
|
||||
|
||||
gateway 是按工具选择启用的,而非全部开启或全部关闭。如果你已有 Browserbase 账号并希望继续使用,同时将网页搜索和图像生成路由至 Nous,这是支持的:
|
||||
|
||||
```bash
|
||||
hermes tools
|
||||
# → Web search → "Nous Subscription" (推荐)
|
||||
# → Image generation → "Nous Subscription" (推荐)
|
||||
# → Browser → "Browserbase" (你自己的密钥)
|
||||
# → TTS → "Nous Subscription" (推荐)
|
||||
```
|
||||
|
||||
使用以下命令验证你的混合配置:
|
||||
|
||||
```bash
|
||||
hermes portal tools
|
||||
```
|
||||
|
||||
你将看到每个工具的路由情况——通过订阅路由的工具显示 `via Nous Portal`,使用你自己密钥的工具显示合作方名称(`browserbase`、`firecrawl` 等)。
|
||||
|
||||
## 7. (可选)启用语音模式
|
||||
|
||||
由于 Tool Gateway 包含 OpenAI TTS,无需单独的 OpenAI 密钥即可使用[语音模式](/user-guide/features/voice-mode):
|
||||
|
||||
```bash
|
||||
hermes setup voice
|
||||
# → 为 TTS 选择 "Nous Subscription"
|
||||
# → 选择语音转文字后端(本地 faster-whisper 免费,无需配置)
|
||||
```
|
||||
|
||||
之后在任何消息平台会话中(Telegram、Discord、Signal 等),发送语音消息,Hermes 将转录内容、生成回复并以合成语音回复——全部通过你的 Portal 订阅完成。
|
||||
|
||||
## 8. (可选)Cron 定时任务与常驻工作流
|
||||
|
||||
Portal 订阅对 [cron 定时任务](/user-guide/features/cron)和[批处理](/user-guide/features/batch-processing)的支持方式与交互式对话相同——OAuth refresh token 会自动复用。无需额外配置,直接安排 cron 任务,费用将计入你的订阅。
|
||||
|
||||
```bash
|
||||
hermes cron add "Daily AI news summary" "every day at 9am" \
|
||||
"Search the web for top AI news and summarize the 5 most important stories"
|
||||
```
|
||||
|
||||
该 cron 任务无人值守运行,调用模型、网页搜索和摘要生成,全部通过你的 Portal 订阅完成。
|
||||
|
||||
## Profiles 与多用户配置
|
||||
|
||||
如果你使用 [Hermes profiles](/user-guide/profiles)(例如每个项目单独一套配置),Portal refresh token 会通过共享 token 存储自动在所有 profiles 之间共享。在任意 profile 上登录一次,其余 profiles 会自动获取。
|
||||
|
||||
对于多人共用一台机器的团队场景,每个人有自己的 Portal 账号 → 每个 home 目录保存各自的 `~/.hermes/auth.json` → 用户之间不共享 token。这是正确的边界划分。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 运行 `hermes setup --portal` 后,`hermes portal info` 显示"not logged in"
|
||||
|
||||
OAuth 流程未完成。重新运行:
|
||||
|
||||
```bash
|
||||
hermes portal
|
||||
```
|
||||
|
||||
如果浏览器未打开或回调失败,你可能在远程/无头主机上——参见 [OAuth over SSH](/guides/oauth-over-ssh) 了解端口转发和手动粘贴的解决方案。
|
||||
|
||||
### "Model: currently openrouter"(或其他 provider)而非"using Nous as inference provider"
|
||||
|
||||
本地配置发生了偏移。OAuth 成功,但 `model.provider` 仍指向其他 provider。修复方法:
|
||||
|
||||
```bash
|
||||
hermes config set model.provider nous
|
||||
```
|
||||
|
||||
或以交互方式:
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# 选择 Nous Portal
|
||||
```
|
||||
|
||||
使用 `hermes portal info` 重新验证。
|
||||
|
||||
### Tool Gateway 工具显示合作方名称而非"via Nous Portal"
|
||||
|
||||
按工具的配置覆盖了 gateway 设置。运行:
|
||||
|
||||
```bash
|
||||
hermes tools
|
||||
# 对需要通过 gateway 路由的工具选择 "Nous Subscription"
|
||||
```
|
||||
|
||||
部分用户会有意混合使用——例如网页搜索通过 Nous 路由,但浏览器使用自己的 Browserbase 密钥。如果这是有意为之,保持不变即可。如果不是,此命令可修复。
|
||||
|
||||
### 会话中途出现"Re-authentication required"
|
||||
|
||||
你的 Portal refresh token 已失效(密码更改、手动撤销、会话过期)。该 token 现已在本地被隔离,以防 Hermes 无限重试。重新登录即可:
|
||||
|
||||
```bash
|
||||
hermes auth add nous
|
||||
```
|
||||
|
||||
成功重新登录后,隔离状态会自动解除。
|
||||
|
||||
### 我想要的模型不在 `/model` 选择器中
|
||||
|
||||
Portal 目录镜像了 OpenRouter 的模型列表(300+ 个)。如果某个模型缺失,尝试直接输入 OpenRouter 风格的 slug:
|
||||
|
||||
```bash
|
||||
/model anthropic/claude-opus-4.6
|
||||
/model openai/o1-2025-12-17
|
||||
```
|
||||
|
||||
如果某个模型确实不可用,请[提交 issue](https://github.com/NousResearch/hermes-agent/issues)——大多数缺失是我们可以更新的路由配置问题。
|
||||
|
||||
### 账单未出现在我的 Portal 账号中
|
||||
|
||||
`hermes portal info` 会告诉你是否真的在通过 Portal 路由,还是使用了其他 provider。常见原因:
|
||||
|
||||
- `model.provider` 设置为 `openrouter`/`anthropic`/等,而非 `nous`
|
||||
- OAuth refresh 失败后回退到了其他已配置的 provider
|
||||
- 存在多个 Hermes profiles,你使用的是错误的那个(检查 `hermes profile current`)
|
||||
|
||||
### 想要撤销并重新开始
|
||||
|
||||
```bash
|
||||
hermes auth remove nous # 清除本地 refresh token
|
||||
# 然后重新运行 setup,或在 Portal 网页界面取消订阅
|
||||
```
|
||||
|
||||
## 用具体数字说明 Portal 的价值
|
||||
|
||||
| 不使用 Portal | 使用 Portal |
|
||||
|----------------|-------------|
|
||||
| 1 个 OpenRouter / Anthropic / OpenAI 密钥写入 `.env` | 1 个 OAuth refresh token,无需 `.env` 密钥 |
|
||||
| 1 个 Firecrawl 密钥用于网页搜索 | 网页搜索通过 gateway 路由 |
|
||||
| 1 个 FAL 密钥用于图像生成 | 图像生成通过 gateway 路由 |
|
||||
| 1 个 Browser Use / Browserbase 密钥用于浏览器 | 浏览器通过 gateway 路由 |
|
||||
| 1 个 OpenAI 密钥用于 TTS / 语音模式 | TTS 通过 gateway 路由 |
|
||||
| 5 个独立的控制台、充值、发票 | 1 个订阅,1 张发票 |
|
||||
| 跨机器:复制全部 5 个密钥 | 跨机器:重新 OAuth 一次 |
|
||||
|
||||
这就是 Portal 的价值。如果你本来就在使用其中两个以上的后端,订阅费用自然就回来了。
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- **[Nous Portal 集成页面](/integrations/nous-portal)** — 订阅内容概述
|
||||
- **[Tool Gateway](/user-guide/features/tool-gateway)** — 每个 gateway 路由工具的完整说明
|
||||
- **[订阅代理](/user-guide/features/subscription-proxy)** — 在非 Hermes 工具中使用你的 Portal 订阅
|
||||
- **[语音模式](/user-guide/features/voice-mode)** — 在 Portal 订阅上配置语音对话
|
||||
- **[OAuth over SSH](/guides/oauth-over-ssh)** — 远程/无头主机登录方案
|
||||
- **[Profiles](/user-guide/profiles)** — 在多个 Hermes 配置之间共享一个 Portal 登录
|
||||
+441
@@ -0,0 +1,441 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
title: "教程:团队 Telegram 助手"
|
||||
description: "逐步指南:为整个团队搭建一个 Telegram 机器人,用于代码帮助、研究、系统管理等"
|
||||
---
|
||||
|
||||
# 搭建团队 Telegram 助手
|
||||
|
||||
本教程将引导你搭建一个由 Hermes Agent 驱动的 Telegram 机器人,供多名团队成员使用。完成后,你的团队将拥有一个共享 AI 助手,可以向它发消息寻求代码、研究、系统管理等方面的帮助——并通过按用户授权保障安全。
|
||||
|
||||
## 我们要构建什么
|
||||
|
||||
一个 Telegram 机器人,具备以下能力:
|
||||
|
||||
- **任何已授权的团队成员**都可以私信寻求帮助——代码审查、研究、Shell 命令、调试
|
||||
- **运行在你的服务器上**,拥有完整工具访问权限——终端、文件编辑、网络搜索、代码执行
|
||||
- **按用户会话隔离**——每个人拥有独立的对话上下文
|
||||
- **默认安全**——只有经过审批的用户才能交互,支持两种授权方式
|
||||
- **定时任务**——每日站会、健康检查和提醒推送到团队频道
|
||||
|
||||
---
|
||||
|
||||
## 前提条件
|
||||
|
||||
开始前,请确保你已具备:
|
||||
|
||||
- **已在服务器或 VPS 上安装 Hermes Agent**(不是你的笔记本——机器人需要持续运行)。如尚未安装,请参阅[安装指南](/getting-started/installation)。
|
||||
- **一个 Telegram 账号**(机器人所有者)
|
||||
- **已配置 LLM 提供商**——至少在 `~/.hermes/.env` 中配置了 OpenAI、Anthropic 或其他受支持提供商的 API 密钥
|
||||
|
||||
:::tip
|
||||
一台 $5/月的 VPS 足以运行 gateway(网关)。Hermes 本身很轻量——花钱的是 LLM API 调用,而那些调用发生在远端。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第一步:创建 Telegram 机器人
|
||||
|
||||
每个 Telegram 机器人都从 **@BotFather** 开始——这是 Telegram 官方用于创建机器人的机器人。
|
||||
|
||||
1. **打开 Telegram**,搜索 `@BotFather`,或访问 [t.me/BotFather](https://t.me/BotFather)
|
||||
|
||||
2. **发送 `/newbot`**——BotFather 会询问两件事:
|
||||
- **显示名称**——用户看到的名字(例如 `Team Hermes Assistant`)
|
||||
- **用户名**——必须以 `bot` 结尾(例如 `myteam_hermes_bot`)
|
||||
|
||||
3. **复制机器人 token**——BotFather 会回复类似内容:
|
||||
```
|
||||
Use this token to access the HTTP API:
|
||||
7123456789:AAH1bGciOiJSUzI1NiIsInR5cCI6Ikp...
|
||||
```
|
||||
保存此 token——下一步会用到。
|
||||
|
||||
4. **设置描述**(可选,但推荐):
|
||||
```
|
||||
/setdescription
|
||||
```
|
||||
选择你的机器人,然后输入类似内容:
|
||||
```
|
||||
Team AI assistant powered by Hermes Agent. DM me for help with code, research, debugging, and more.
|
||||
```
|
||||
|
||||
5. **设置机器人命令**(可选——为用户提供命令菜单):
|
||||
```
|
||||
/setcommands
|
||||
```
|
||||
选择你的机器人,然后粘贴:
|
||||
```
|
||||
new - Start a fresh conversation
|
||||
model - Show or change the AI model
|
||||
status - Show session info
|
||||
help - Show available commands
|
||||
stop - Stop the current task
|
||||
```
|
||||
|
||||
:::warning
|
||||
请妥善保管你的机器人 token。任何持有该 token 的人都可以控制机器人。如果泄露,请在 BotFather 中使用 `/revoke` 生成新 token。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第二步:配置 Gateway
|
||||
|
||||
你有两种选择:交互式设置向导(推荐)或手动配置。
|
||||
|
||||
### 方式 A:交互式设置(推荐)
|
||||
|
||||
```bash
|
||||
hermes gateway setup
|
||||
```
|
||||
|
||||
通过方向键选择完成所有配置。选择 **Telegram**,粘贴你的机器人 token,并在提示时输入你的用户 ID。
|
||||
|
||||
### 方式 B:手动配置
|
||||
|
||||
在 `~/.hermes/.env` 中添加以下内容:
|
||||
|
||||
```bash
|
||||
# Telegram bot token from BotFather
|
||||
TELEGRAM_BOT_TOKEN=7123456789:AAH1bGciOiJSUzI1NiIsInR5cCI6Ikp...
|
||||
|
||||
# Your Telegram user ID (numeric)
|
||||
TELEGRAM_ALLOWED_USERS=123456789
|
||||
```
|
||||
|
||||
### 查找你的用户 ID
|
||||
|
||||
你的 Telegram 用户 ID 是一个数字值(不是你的用户名)。查找方式:
|
||||
|
||||
1. 在 Telegram 上给 [@userinfobot](https://t.me/userinfobot) 发消息
|
||||
2. 它会立即回复你的数字用户 ID
|
||||
3. 将该数字填入 `TELEGRAM_ALLOWED_USERS`
|
||||
|
||||
:::info
|
||||
Telegram 用户 ID 是永久性数字,例如 `123456789`。它与可以更改的 `@username` 不同。白名单中请始终使用数字 ID。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第三步:启动 Gateway
|
||||
|
||||
### 快速测试
|
||||
|
||||
先在前台运行 gateway,确认一切正常:
|
||||
|
||||
```bash
|
||||
hermes gateway
|
||||
```
|
||||
|
||||
你应该看到类似输出:
|
||||
|
||||
```
|
||||
[Gateway] Starting Hermes Gateway...
|
||||
[Gateway] Telegram adapter connected
|
||||
[Gateway] Cron scheduler started (tick every 60s)
|
||||
```
|
||||
|
||||
打开 Telegram,找到你的机器人,发送一条消息。如果它回复了,说明一切正常。按 `Ctrl+C` 停止。
|
||||
|
||||
### 生产环境:安装为服务
|
||||
|
||||
若要持久部署并在重启后自动恢复:
|
||||
|
||||
```bash
|
||||
hermes gateway install
|
||||
sudo hermes gateway install --system # 仅 Linux:开机启动的系统服务
|
||||
```
|
||||
|
||||
这会创建一个后台服务:Linux 上默认为用户级 **systemd** 服务,macOS 上为 **launchd** 服务,传入 `--system` 则创建开机启动的 Linux 系统服务。
|
||||
|
||||
```bash
|
||||
# Linux——管理默认用户服务
|
||||
hermes gateway start
|
||||
hermes gateway stop
|
||||
hermes gateway status
|
||||
|
||||
# 查看实时日志
|
||||
journalctl --user -u hermes-gateway -f
|
||||
|
||||
# SSH 退出后保持运行
|
||||
sudo loginctl enable-linger $USER
|
||||
|
||||
# Linux 服务器——显式系统服务命令
|
||||
sudo hermes gateway start --system
|
||||
sudo hermes gateway status --system
|
||||
journalctl -u hermes-gateway -f
|
||||
```
|
||||
|
||||
```bash
|
||||
# macOS——管理服务
|
||||
hermes gateway start
|
||||
hermes gateway stop
|
||||
tail -f ~/.hermes/logs/gateway.log
|
||||
```
|
||||
|
||||
:::tip macOS PATH
|
||||
launchd plist 在安装时捕获你的 Shell PATH,以便 gateway 子进程能找到 Node.js 和 ffmpeg 等工具。如果之后安装了新工具,请重新运行 `hermes gateway install` 以更新 plist。
|
||||
:::
|
||||
|
||||
### 验证运行状态
|
||||
|
||||
```bash
|
||||
hermes gateway status
|
||||
```
|
||||
|
||||
然后在 Telegram 上向你的机器人发送测试消息。几秒内应收到回复。
|
||||
|
||||
---
|
||||
|
||||
## 第四步:设置团队访问权限
|
||||
|
||||
现在让你的队友获得访问权限。有两种方式。
|
||||
|
||||
### 方式 A:静态白名单
|
||||
|
||||
收集每位团队成员的 Telegram 用户 ID(让他们给 [@userinfobot](https://t.me/userinfobot) 发消息),然后以逗号分隔的列表形式添加:
|
||||
|
||||
```bash
|
||||
# 在 ~/.hermes/.env 中
|
||||
TELEGRAM_ALLOWED_USERS=123456789,987654321,555555555
|
||||
```
|
||||
|
||||
修改后重启 gateway:
|
||||
|
||||
```bash
|
||||
hermes gateway stop && hermes gateway start
|
||||
```
|
||||
|
||||
### 方式 B:私信配对(推荐用于团队)
|
||||
|
||||
私信配对更灵活——无需提前收集用户 ID。工作流程如下:
|
||||
|
||||
1. **队友私信机器人**——由于不在白名单中,机器人会回复一次性配对码:
|
||||
```
|
||||
🔐 Pairing code: XKGH5N7P
|
||||
Send this code to the bot owner for approval.
|
||||
```
|
||||
|
||||
2. **队友将配对码发给你**(通过任何渠道——Slack、邮件或当面)
|
||||
|
||||
3. **你在服务器上审批**:
|
||||
```bash
|
||||
hermes pairing approve telegram XKGH5N7P
|
||||
```
|
||||
|
||||
4. **他们即可使用**——机器人立即开始响应他们的消息
|
||||
|
||||
**管理已配对用户:**
|
||||
|
||||
```bash
|
||||
# 查看所有待审批和已审批用户
|
||||
hermes pairing list
|
||||
|
||||
# 撤销某人的访问权限
|
||||
hermes pairing revoke telegram 987654321
|
||||
|
||||
# 清除已过期的待审批码
|
||||
hermes pairing clear-pending
|
||||
```
|
||||
|
||||
:::tip
|
||||
私信配对非常适合团队使用,因为添加新用户时无需重启 gateway。审批立即生效。
|
||||
:::
|
||||
|
||||
### 安全注意事项
|
||||
|
||||
- **切勿在拥有终端访问权限的机器人上设置 `GATEWAY_ALLOW_ALL_USERS=true`**——任何找到你机器人的人都可能在你的服务器上执行命令
|
||||
- 配对码在 **1 小时**后过期,并使用密码学随机数生成
|
||||
- 速率限制防止暴力破解:每用户每 10 分钟 1 次请求,每平台最多 3 个待审批码
|
||||
- 5 次审批失败后,该平台进入 1 小时锁定状态
|
||||
- 所有配对数据以 `chmod 0600` 权限存储
|
||||
|
||||
---
|
||||
|
||||
## 第五步:配置机器人
|
||||
|
||||
### 设置主频道
|
||||
|
||||
**主频道**是机器人投递 cron 任务结果和主动消息的地方。没有主频道,定时任务将无处发送输出。
|
||||
|
||||
**方式 1:** 在机器人所在的任意 Telegram 群组或聊天中使用 `/sethome` 命令。
|
||||
|
||||
**方式 2:** 在 `~/.hermes/.env` 中手动设置:
|
||||
|
||||
```bash
|
||||
TELEGRAM_HOME_CHANNEL=-1001234567890
|
||||
TELEGRAM_HOME_CHANNEL_NAME="Team Updates"
|
||||
```
|
||||
|
||||
要查找频道 ID,可将 [@userinfobot](https://t.me/userinfobot) 添加到群组——它会报告该群组的聊天 ID。
|
||||
|
||||
### 配置工具进度显示
|
||||
|
||||
控制机器人在使用工具时显示的详细程度。在 `~/.hermes/config.yaml` 中:
|
||||
|
||||
```yaml
|
||||
display:
|
||||
tool_progress: new # off | new | all | verbose
|
||||
```
|
||||
|
||||
| 模式 | 显示内容 |
|
||||
|------|-------------|
|
||||
| `off` | 仅显示干净的回复——无工具活动 |
|
||||
| `new` | 每次新工具调用的简短状态(推荐用于消息场景) |
|
||||
| `all` | 每次工具调用及其详情 |
|
||||
| `verbose` | 完整工具输出,包括命令结果 |
|
||||
|
||||
用户也可以在聊天中使用 `/verbose` 命令按会话更改此设置。
|
||||
|
||||
### 使用 SOUL.md 设置个性
|
||||
|
||||
通过编辑 `~/.hermes/SOUL.md` 自定义机器人的沟通方式:
|
||||
|
||||
完整指南请参阅[在 Hermes 中使用 SOUL.md](/guides/use-soul-with-hermes)。
|
||||
|
||||
```markdown
|
||||
# Soul
|
||||
You are a helpful team assistant. Be concise and technical.
|
||||
Use code blocks for any code. Skip pleasantries — the team
|
||||
values directness. When debugging, always ask for error logs
|
||||
before guessing at solutions.
|
||||
```
|
||||
|
||||
### 添加项目上下文
|
||||
|
||||
如果你的团队在特定项目上工作,可以创建上下文文件,让机器人了解你们的技术栈:
|
||||
|
||||
```markdown
|
||||
<!-- ~/.hermes/AGENTS.md -->
|
||||
# Team Context
|
||||
- We use Python 3.12 with FastAPI and SQLAlchemy
|
||||
- Frontend is React with TypeScript
|
||||
- CI/CD runs on GitHub Actions
|
||||
- Production deploys to AWS ECS
|
||||
- Always suggest writing tests for new code
|
||||
```
|
||||
|
||||
:::info
|
||||
上下文文件会注入到每个会话的系统 prompt(提示词)中。请保持简洁——每个字符都会占用你的 token 预算。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第六步:设置定时任务
|
||||
|
||||
gateway 运行后,你可以安排定期任务,将结果投递到团队频道。
|
||||
|
||||
### 每日站会摘要
|
||||
|
||||
在 Telegram 上给机器人发消息:
|
||||
|
||||
```
|
||||
Every weekday at 9am, check the GitHub repository at
|
||||
github.com/myorg/myproject for:
|
||||
1. Pull requests opened/merged in the last 24 hours
|
||||
2. Issues created or closed
|
||||
3. Any CI/CD failures on the main branch
|
||||
Format as a brief standup-style summary.
|
||||
```
|
||||
|
||||
Agent 会自动创建一个 cron 任务,并将结果投递到你提问的聊天(或主频道)。
|
||||
|
||||
### 服务器健康检查
|
||||
|
||||
```
|
||||
Every 6 hours, check disk usage with 'df -h', memory with 'free -h',
|
||||
and Docker container status with 'docker ps'. Report anything unusual —
|
||||
partitions above 80%, containers that have restarted, or high memory usage.
|
||||
```
|
||||
|
||||
### 管理定时任务
|
||||
|
||||
```bash
|
||||
# 通过 CLI
|
||||
hermes cron list # 查看所有定时任务
|
||||
hermes cron status # 检查调度器是否运行
|
||||
|
||||
# 通过 Telegram 聊天
|
||||
/cron list # 查看任务
|
||||
/cron remove <job_id> # 删除任务
|
||||
```
|
||||
|
||||
:::warning
|
||||
Cron 任务的 prompt 在完全全新的会话中运行,不保留任何先前对话的记忆。请确保每个 prompt 包含 agent 所需的**全部**上下文——文件路径、URL、服务器地址以及清晰的指令。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 生产环境建议
|
||||
|
||||
### 使用 Docker 保障安全
|
||||
|
||||
在共享团队机器人上,使用 Docker 作为终端后端,让 agent 命令在容器中运行,而非直接在宿主机上运行:
|
||||
|
||||
```bash
|
||||
# 在 ~/.hermes/.env 中
|
||||
TERMINAL_BACKEND=docker
|
||||
TERMINAL_DOCKER_IMAGE=nikolaik/python-nodejs:python3.11-nodejs20
|
||||
```
|
||||
|
||||
或在 `~/.hermes/config.yaml` 中:
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: docker
|
||||
container_cpu: 1
|
||||
container_memory: 5120
|
||||
container_persistent: true
|
||||
```
|
||||
|
||||
这样即使有人要求机器人执行破坏性操作,你的宿主系统也受到保护。
|
||||
|
||||
### 监控 Gateway
|
||||
|
||||
```bash
|
||||
# 检查 gateway 是否运行
|
||||
hermes gateway status
|
||||
|
||||
# 查看实时日志(Linux)
|
||||
journalctl --user -u hermes-gateway -f
|
||||
|
||||
# 查看实时日志(macOS)
|
||||
tail -f ~/.hermes/logs/gateway.log
|
||||
```
|
||||
|
||||
### 保持 Hermes 更新
|
||||
|
||||
在 Telegram 中向机器人发送 `/update`——它会拉取最新版本并重启。或在服务器上执行:
|
||||
|
||||
```bash
|
||||
hermes update
|
||||
hermes gateway stop && hermes gateway start
|
||||
```
|
||||
|
||||
### 日志位置
|
||||
|
||||
| 内容 | 位置 |
|
||||
|------|----------|
|
||||
| Gateway 日志 | `journalctl --user -u hermes-gateway`(Linux)或 `~/.hermes/logs/gateway.log`(macOS) |
|
||||
| Cron 任务输出 | `~/.hermes/cron/output/{job_id}/{timestamp}.md` |
|
||||
| Cron 任务定义 | `~/.hermes/cron/jobs.json` |
|
||||
| 配对数据 | `~/.hermes/pairing/` |
|
||||
| 会话历史 | `~/.hermes/sessions/` |
|
||||
|
||||
---
|
||||
|
||||
## 进一步探索
|
||||
|
||||
你已经拥有一个可用的团队 Telegram 助手。以下是一些后续步骤:
|
||||
|
||||
- **[安全指南](/user-guide/security)**——深入了解授权、容器隔离和命令审批
|
||||
- **[消息 Gateway](/user-guide/messaging)**——gateway 架构、会话管理和聊天命令的完整参考
|
||||
- **[Telegram 设置](/user-guide/messaging/telegram)**——平台专属详情,包括语音消息和 TTS
|
||||
- **[定时任务](/user-guide/features/cron)**——高级 cron 调度,含投递选项和 cron 表达式
|
||||
- **[上下文文件](/user-guide/features/context-files)**——用于项目知识的 AGENTS.md、SOUL.md 和 .cursorrules
|
||||
- **[个性设置](/user-guide/features/personality)**——内置个性预设和自定义角色定义
|
||||
- **添加更多平台**——同一 gateway 可同时运行 [Discord](/user-guide/messaging/discord)、[Slack](/user-guide/messaging/slack) 和 [WhatsApp](/user-guide/messaging/whatsapp)
|
||||
|
||||
---
|
||||
|
||||
*有问题或遇到问题?请在 GitHub 上提 issue——欢迎贡献。*
|
||||
@@ -0,0 +1,234 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "技巧与最佳实践"
|
||||
description: "充分发挥 Hermes Agent 潜力的实用建议——prompt 技巧、CLI 快捷键、上下文文件、记忆、成本优化与安全"
|
||||
---
|
||||
|
||||
# 技巧与最佳实践
|
||||
|
||||
一份实用技巧速查集,帮助你立即提升使用 Hermes Agent 的效率。每个章节针对不同方面——扫描标题,直接跳到相关内容。
|
||||
|
||||
---
|
||||
|
||||
## 获得最佳结果
|
||||
|
||||
### 明确说明你的需求
|
||||
|
||||
模糊的 prompt(提示词)只会产生模糊的结果。不要说"修复代码",而要说"修复 `api/handlers.py` 第 47 行的 TypeError——`process_request()` 函数从 `parse_body()` 收到了 `None`。"给出的上下文越多,所需的迭代次数就越少。
|
||||
|
||||
### 预先提供上下文
|
||||
|
||||
在请求开头就给出相关细节:文件路径、错误信息、预期行为。一条精心构造的消息胜过三轮来回确认。直接粘贴错误堆栈——agent 能够解析它们。
|
||||
|
||||
### 使用上下文文件处理重复指令
|
||||
|
||||
如果你发现自己在反复输入相同的指令("用 tab 而非空格"、"我们用 pytest"、"API 地址是 `/api/v2`"),把它们放进 `AGENTS.md` 文件。agent 每次会话都会自动读取它——设置一次,永久生效。
|
||||
|
||||
### 让 Agent 使用它的工具
|
||||
|
||||
不要试图手把手指导每一步。说"找到并修复失败的测试",而不是"打开 `tests/test_foo.py`,看第 42 行,然后……"。agent 拥有文件搜索、终端访问和代码执行能力——让它自行探索和迭代。
|
||||
|
||||
### 对复杂工作流使用 Skill
|
||||
|
||||
在写一大段 prompt 解释如何做某件事之前,先检查是否已有对应的 skill。输入 `/skills` 浏览可用的 skill,或直接调用,例如 `/axolotl` 或 `/github-pr-workflow`。
|
||||
|
||||
## CLI 高级用户技巧
|
||||
|
||||
### 多行输入
|
||||
|
||||
按 **Alt+Enter**、**Ctrl+J** 或 **Shift+Enter** 可插入换行而不发送消息。`Shift+Enter` 仅在终端将其作为独立按键发送时有效(Kitty / foot / WezTerm / Ghostty 默认支持;iTerm2 / Alacritty / VS Code 终端需启用 Kitty 键盘协议)。另外两种方式在所有终端中均可使用。
|
||||
|
||||
### 粘贴检测
|
||||
|
||||
CLI 会自动检测多行粘贴。直接粘贴代码块或错误堆栈——不会将每行作为单独消息发送。粘贴内容会被缓冲后作为一条消息发送。
|
||||
|
||||
### 中断与重定向
|
||||
|
||||
按一次 **Ctrl+C** 可中断 agent 的响应过程,然后输入新消息重新引导它。在 2 秒内双击 Ctrl+C 可强制退出。当 agent 开始走错方向时,这个功能非常有用。
|
||||
|
||||
### 使用 `-c` 恢复会话
|
||||
|
||||
上次会话有遗漏?运行 `hermes -c` 可精确恢复到上次离开的位置,完整对话历史全部还原。也可以按标题恢复:`hermes -r "my research project"`。
|
||||
|
||||
### 剪贴板图片粘贴
|
||||
|
||||
按 **Ctrl+V** 可将剪贴板中的图片直接粘贴到对话中。agent 会使用视觉能力分析截图、图表、错误弹窗或 UI 原型——无需先保存为文件。
|
||||
|
||||
### Slash 命令自动补全
|
||||
|
||||
输入 `/` 后按 **Tab** 可查看所有可用命令,包括内置命令(`/compress`、`/model`、`/title`)和所有已安装的 skill。无需记忆任何内容——Tab 补全全部搞定。
|
||||
|
||||
:::tip
|
||||
使用 `/verbose` 循环切换工具输出显示模式:**off → new → all → verbose**。"all" 模式非常适合观察 agent 的操作过程;"off" 模式在简单问答时最为简洁。
|
||||
:::
|
||||
|
||||
## 上下文文件
|
||||
|
||||
### AGENTS.md:你的项目大脑
|
||||
|
||||
在项目根目录创建 `AGENTS.md`,写入架构决策、编码规范和项目专属指令。该文件会自动注入每次会话,让 agent 始终了解你的项目规则。
|
||||
|
||||
```markdown
|
||||
# Project Context
|
||||
- This is a FastAPI backend with SQLAlchemy ORM
|
||||
- Always use async/await for database operations
|
||||
- Tests go in tests/ and use pytest-asyncio
|
||||
- Never commit .env files
|
||||
```
|
||||
|
||||
### SOUL.md:自定义个性
|
||||
|
||||
想让 Hermes 拥有稳定的默认风格?编辑 `~/.hermes/SOUL.md`(如果使用自定义 Hermes home,则为 `$HERMES_HOME/SOUL.md`)。Hermes 现在会自动生成一个初始 SOUL 文件,并将该全局文件作为实例级个性来源。
|
||||
|
||||
完整说明请参阅 [在 Hermes 中使用 SOUL.md](/guides/use-soul-with-hermes)。
|
||||
|
||||
```markdown
|
||||
# Soul
|
||||
You are a senior backend engineer. Be terse and direct.
|
||||
Skip explanations unless asked. Prefer one-liners over verbose solutions.
|
||||
Always consider error handling and edge cases.
|
||||
```
|
||||
|
||||
使用 `SOUL.md` 设置持久个性,使用 `AGENTS.md` 设置项目专属指令。
|
||||
|
||||
### .cursorrules 兼容性
|
||||
|
||||
已有 `.cursorrules` 或 `.cursor/rules/*.mdc` 文件?Hermes 同样会读取它们。无需重复编写编码规范——这些文件会从工作目录自动加载。
|
||||
|
||||
### 发现机制
|
||||
|
||||
Hermes 在会话启动时从当前工作目录加载顶层 `AGENTS.md`。子目录中的 `AGENTS.md` 文件在工具调用期间通过 `subdirectory_hints.py` 延迟发现,并注入工具结果——不会在启动时预先加载到系统 prompt 中。
|
||||
|
||||
:::tip
|
||||
保持上下文文件简洁聚焦。每个字符都会消耗 token 配额,因为它们会注入到每一条消息中。
|
||||
:::
|
||||
|
||||
## 记忆与 Skill
|
||||
|
||||
### 记忆 vs. Skill:各司其职
|
||||
|
||||
**记忆(Memory)** 用于存储事实:你的环境、偏好、项目位置,以及 agent 了解到的关于你的信息。**Skill** 用于存储流程:多步骤工作流、特定工具的操作指南和可复用的操作方案。记忆存"是什么",skill 存"怎么做"。
|
||||
|
||||
### 何时创建 Skill
|
||||
|
||||
如果某个任务需要 5 步以上且你会重复执行,就让 agent 为它创建一个 skill。说"把你刚才做的保存为名为 `deploy-staging` 的 skill"。下次只需输入 `/deploy-staging`,agent 就会加载完整流程。
|
||||
|
||||
### 管理记忆容量
|
||||
|
||||
记忆容量是有意限制的(`MEMORY.md` 约 2,200 字符,`USER.md` 约 1,375 字符)。当记忆填满时,agent 会自动整合条目。你也可以主动说"清理你的记忆"或"替换旧的 Python 3.9 备注——我们现在用 3.12 了"。
|
||||
|
||||
### 让 Agent 记住内容
|
||||
|
||||
在一次高效的会话结束后,说"记住这些以备下次使用",agent 会保存关键要点。也可以具体指定:"保存到记忆中,我们的 CI 使用 GitHub Actions 的 `deploy.yml` 工作流。"
|
||||
|
||||
:::warning
|
||||
记忆是一个冻结的快照——会话期间的修改不会出现在系统 prompt 中,直到下一次会话开始。agent 会立即写入磁盘,但 prompt 缓存在会话中途不会失效。
|
||||
:::
|
||||
|
||||
## 性能与成本
|
||||
|
||||
### 不要破坏 Prompt 缓存
|
||||
|
||||
大多数 LLM 提供商会缓存系统 prompt 前缀。如果你保持系统 prompt 稳定(相同的上下文文件、相同的记忆),同一会话中的后续消息会命中**缓存**,成本显著降低。避免在会话中途切换模型或修改系统 prompt。
|
||||
|
||||
### 在达到限制前使用 /compress
|
||||
|
||||
长会话会积累大量 token。当你发现响应变慢或被截断时,运行 `/compress`。这会对对话历史进行摘要,在大幅减少 token 数量的同时保留关键上下文。使用 `/usage` 查看当前用量。
|
||||
|
||||
### 使用委托实现并行工作
|
||||
|
||||
需要同时研究三个主题?让 agent 使用 `delegate_task` 并行分配子任务。每个子 agent 独立运行,拥有各自的上下文,最终只有摘要结果返回——大幅减少主对话的 token 消耗。
|
||||
|
||||
### 使用 execute_code 进行批量操作
|
||||
|
||||
不要逐条运行终端命令,而是让 agent 编写一个脚本一次性完成所有操作。"写一个 Python 脚本把所有 `.jpeg` 文件重命名为 `.jpg` 并运行它"比逐个重命名文件更省钱、更快速。
|
||||
|
||||
### 选择合适的模型
|
||||
|
||||
使用 `/model` 在会话中途切换模型。对于复杂推理和架构决策,使用前沿模型(Claude Sonnet/Opus、GPT-4o);对于格式化、重命名或样板代码生成等简单任务,切换到更快的模型。
|
||||
|
||||
:::tip
|
||||
定期运行 `/usage` 查看 token 消耗情况。运行 `/insights` 可查看过去 30 天的用量模式概览。
|
||||
:::
|
||||
|
||||
## 消息技巧
|
||||
|
||||
### 设置主频道
|
||||
|
||||
在你偏好的 Telegram 或 Discord 聊天中使用 `/sethome`,将其指定为主频道。定时任务结果和计划任务输出会发送到这里。没有主频道,agent 就没有地方发送主动消息。
|
||||
|
||||
### 使用 /title 整理会话
|
||||
|
||||
用 `/title auth-refactor` 或 `/title research-llm-quantization` 为会话命名。命名后的会话可通过 `hermes sessions list` 轻松找到,并用 `hermes -r "auth-refactor"` 恢复。未命名的会话会堆积起来,难以区分。
|
||||
|
||||
### DM 配对实现团队访问
|
||||
|
||||
不要手动收集用户 ID 来维护白名单,而是启用 DM 配对。当团队成员向 bot 发送私信时,他们会收到一次性配对码。你用 `hermes pairing approve telegram XKGH5N7P` 批准即可——简单且安全。
|
||||
|
||||
### 工具进度显示模式
|
||||
|
||||
使用 `/verbose` 控制工具活动的显示详细程度。在消息平台上,通常越简洁越好——保持"new"模式只查看新的工具调用。在 CLI 中,"all" 模式可以实时查看 agent 的所有操作。
|
||||
|
||||
:::tip
|
||||
在消息平台上,会话会在空闲一段时间后自动重置(默认 24 小时),或每天凌晨 4 点重置。如需更长的会话时间,可在 `~/.hermes/config.yaml` 中按平台调整。
|
||||
:::
|
||||
|
||||
## 安全
|
||||
|
||||
### 对不可信代码使用 Docker
|
||||
|
||||
在处理不可信仓库或运行陌生代码时,使用 Docker 或 Daytona 作为终端后端。在 `.env` 中设置 `TERMINAL_BACKEND=docker`。容器内的破坏性命令不会影响宿主系统。
|
||||
|
||||
```bash
|
||||
# In your .env:
|
||||
TERMINAL_BACKEND=docker
|
||||
TERMINAL_DOCKER_IMAGE=hermes-sandbox:latest
|
||||
```
|
||||
|
||||
### 避免 Windows 编码陷阱
|
||||
|
||||
在 Windows 上,某些默认编码(如 `cp125x`)无法表示所有 Unicode 字符,在测试或脚本中写入文件时可能导致 `UnicodeEncodeError`。
|
||||
|
||||
- 建议在打开文件时显式指定 UTF-8 编码:
|
||||
|
||||
```python
|
||||
with open("results.txt", "w", encoding="utf-8") as f:
|
||||
f.write("✓ All good\n")
|
||||
```
|
||||
|
||||
- 在 PowerShell 中,也可以将当前会话的控制台和原生命令输出切换为 UTF-8:
|
||||
|
||||
```powershell
|
||||
$OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::new($false)
|
||||
```
|
||||
|
||||
这样可以让 PowerShell 和子进程统一使用 UTF-8,避免仅在 Windows 上出现的失败。
|
||||
|
||||
### 谨慎选择"始终允许"
|
||||
|
||||
当 agent 触发危险命令审批(`rm -rf`、`DROP TABLE` 等)时,你有四个选项:**once(仅此一次)**、**session(本次会话)**、**always(始终允许)**、**deny(拒绝)**。选择"always"前请仔细考虑——它会永久将该模式加入白名单。在熟悉之前,先用"session"。
|
||||
|
||||
### 命令审批是你的安全防线
|
||||
|
||||
Hermes 在执行每条命令前都会与一份精心维护的危险模式列表进行比对,包括递归删除、SQL DROP、curl 管道到 shell 等。不要在生产环境中禁用此功能——它的存在有充分的理由。
|
||||
|
||||
:::warning
|
||||
在容器后端(Docker、Singularity、Modal、Daytona)中运行时,危险命令检查会被**跳过**,因为容器本身就是安全边界。请确保你的容器镜像已妥善加固。
|
||||
:::
|
||||
|
||||
### 为消息 Bot 使用白名单
|
||||
|
||||
永远不要在拥有终端访问权限的 bot 上设置 `GATEWAY_ALLOW_ALL_USERS=true`。始终使用平台专属白名单(`TELEGRAM_ALLOWED_USERS`、`DISCORD_ALLOWED_USERS`)或 DM 配对来控制谁可以与你的 agent 交互。
|
||||
|
||||
```bash
|
||||
# Recommended: explicit allowlists per platform
|
||||
TELEGRAM_ALLOWED_USERS=123456789,987654321
|
||||
DISCORD_ALLOWED_USERS=123456789012345678
|
||||
|
||||
# Or use cross-platform allowlist
|
||||
GATEWAY_ALLOWED_USERS=123456789,987654321
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*有值得收录的技巧?欢迎提交 issue 或 PR——社区贡献随时欢迎。*
|
||||
+490
@@ -0,0 +1,490 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
title: "在 Hermes 中使用 MCP"
|
||||
description: "将 MCP 服务器连接到 Hermes Agent、过滤其工具并在实际工作流中安全使用的实践指南"
|
||||
---
|
||||
|
||||
# 在 Hermes 中使用 MCP
|
||||
|
||||
本指南介绍如何在日常工作流中实际使用 Hermes Agent 的 MCP 功能。
|
||||
|
||||
如果功能页面解释的是 MCP 是什么,本指南则关注如何快速、安全地从中获取价值。
|
||||
|
||||
## 何时应该使用 MCP?
|
||||
|
||||
在以下情况下使用 MCP:
|
||||
- 工具已以 MCP 形式存在,且你不想构建原生 Hermes 工具
|
||||
- 你希望 Hermes 通过干净的 RPC 层操作本地或远程系统
|
||||
- 你需要细粒度的按服务器暴露控制
|
||||
- 你希望将 Hermes 连接到内部 API、数据库或公司系统,而无需修改 Hermes 核心
|
||||
|
||||
在以下情况下不要使用 MCP:
|
||||
- 内置 Hermes 工具已能很好地完成该工作
|
||||
- 服务器暴露了大量危险工具,而你没有准备好对其进行过滤
|
||||
- 你只需要一个非常窄的集成,原生工具会更简单、更安全
|
||||
|
||||
## 心智模型
|
||||
|
||||
将 MCP 视为一个适配器层:
|
||||
|
||||
- Hermes 仍然是 agent
|
||||
- MCP 服务器提供工具
|
||||
- Hermes 在启动或重新加载时发现这些工具
|
||||
- 模型可以像使用普通工具一样使用它们
|
||||
- 你控制每个服务器有多少内容可见
|
||||
|
||||
最后一点很重要。良好的 MCP 使用不是"连接一切",而是"以最小的有效范围连接正确的东西"。
|
||||
|
||||
## 第一步:安装 MCP 支持
|
||||
|
||||
如果你使用标准安装脚本安装了 Hermes,MCP 支持已包含在内(安装程序会运行 `uv pip install -e ".[all]"`)。
|
||||
|
||||
如果你在没有附加组件的情况下安装,需要单独添加 MCP:
|
||||
|
||||
```bash
|
||||
cd ~/.hermes/hermes-agent
|
||||
uv pip install -e ".[mcp]"
|
||||
```
|
||||
|
||||
对于基于 npm 的服务器,请确保 Node.js 和 `npx` 可用。
|
||||
|
||||
对于许多 Python MCP 服务器,`uvx` 是一个不错的默认选择。
|
||||
|
||||
## 第二步:先添加一个服务器
|
||||
|
||||
从单个、安全的服务器开始。
|
||||
|
||||
示例:仅访问一个项目目录的文件系统。
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
project_fs:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/my-project"]
|
||||
```
|
||||
|
||||
然后启动 Hermes:
|
||||
|
||||
```bash
|
||||
hermes chat
|
||||
```
|
||||
|
||||
现在提出一个具体问题:
|
||||
|
||||
```text
|
||||
Inspect this project and summarize the repo layout.
|
||||
```
|
||||
|
||||
## 第三步:验证 MCP 已加载
|
||||
|
||||
你可以通过以下几种方式验证 MCP:
|
||||
|
||||
- 配置后 Hermes 横幅/状态应显示 MCP 集成
|
||||
- 询问 Hermes 当前有哪些可用工具
|
||||
- 配置更改后使用 `/reload-mcp`
|
||||
- 如果服务器连接失败,检查日志
|
||||
|
||||
一个实用的测试 prompt(提示词):
|
||||
|
||||
```text
|
||||
Tell me which MCP-backed tools are available right now.
|
||||
```
|
||||
|
||||
## 第四步:立即开始过滤
|
||||
|
||||
如果服务器暴露了大量工具,不要等到以后再过滤。
|
||||
|
||||
### 示例:仅白名单你需要的内容
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
github:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-github"]
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
|
||||
tools:
|
||||
include: [list_issues, create_issue, search_code]
|
||||
```
|
||||
|
||||
对于敏感系统,这通常是最佳默认设置。
|
||||
|
||||
## WSL2:将 WSL 中的 Hermes 桥接到 Windows Chrome
|
||||
|
||||
以下是适用场景的实际配置:
|
||||
|
||||
- Hermes 在 WSL2 内运行
|
||||
- 你想控制的浏览器是 Windows 上已登录的普通 Chrome
|
||||
- 从 WSL 使用 `/browser connect` 不稳定或不可靠
|
||||
|
||||
在此配置中,Hermes **不**直接连接到 Chrome,而是:
|
||||
|
||||
- Hermes 在 WSL 中运行
|
||||
- Hermes 启动一个本地 stdio MCP 服务器
|
||||
- 该 MCP 服务器通过 Windows 互操作(`cmd.exe` 或 `powershell.exe`)启动
|
||||
- MCP 服务器附加到你的实时 Windows Chrome 会话
|
||||
|
||||
心智模型:
|
||||
|
||||
```text
|
||||
Hermes (WSL) -> MCP stdio bridge -> Windows Chrome
|
||||
```
|
||||
|
||||
### 为什么此模式有用
|
||||
|
||||
- 你保留真实的 Windows 浏览器配置文件、Cookie 和登录状态
|
||||
- Hermes 保持在其支持的 Unix 环境(WSL2)中
|
||||
- 浏览器控制以 MCP 工具的形式暴露,而不依赖 Hermes 核心浏览器传输
|
||||
|
||||
### 推荐服务器
|
||||
|
||||
使用 `chrome-devtools-mcp`。
|
||||
|
||||
如果你的 Windows Chrome 已通过 `chrome://inspect/#remote-debugging` 启用了实时远程调试,在 WSL 中按如下方式添加:
|
||||
|
||||
```bash
|
||||
hermes mcp add chrome-devtools-win --command cmd.exe --args /c npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics
|
||||
```
|
||||
|
||||
保存服务器后:
|
||||
|
||||
```bash
|
||||
hermes mcp test chrome-devtools-win
|
||||
```
|
||||
|
||||
然后启动一个新的 Hermes 会话或运行:
|
||||
|
||||
```text
|
||||
/reload-mcp
|
||||
```
|
||||
|
||||
### 典型 prompt
|
||||
|
||||
加载后,Hermes 可以直接使用带 MCP 前缀的浏览器工具。例如:
|
||||
|
||||
```text
|
||||
调用 MCP 工具 mcp_chrome_devtools_win_list_pages,列出当前浏览器标签页。
|
||||
```
|
||||
|
||||
### 何时 `/browser connect` 不适用
|
||||
|
||||
如果 Hermes 在 WSL 中运行而 Chrome 在 Windows 上运行,即使 Chrome 已打开且可调试,`/browser connect` 也可能失败。
|
||||
|
||||
常见原因:
|
||||
|
||||
- WSL 无法访问 Chrome 向 Windows 工具暴露的同一主机本地端点
|
||||
- 较新的 Chrome 实时调试流程与经典的 `ws://localhost:9222` 不同
|
||||
- 从 Windows 端辅助工具(如 `chrome-devtools-mcp`)附加浏览器更容易
|
||||
|
||||
在这些情况下,将 `/browser connect` 用于同环境配置,使用 MCP 进行 WSL 到 Windows 的浏览器桥接。
|
||||
|
||||
### 已知问题
|
||||
|
||||
- 通过 MCP 使用 Windows stdio 可执行文件时,从 `/mnt/c/Users/<you>` 或 `/mnt/c/workspace/...` 等 Windows 挂载路径启动 Hermes。
|
||||
- 如果从 `/root` 或 `/home/...` 启动 Hermes,Windows 可能在 MCP 服务器启动前发出 `UNC` 当前目录警告。
|
||||
- 如果 `chrome-devtools-mcp --autoConnect` 在枚举页面时超时,请减少 Chrome 中的后台/冻结标签页并重试。
|
||||
|
||||
### 示例:黑名单危险操作
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
stripe:
|
||||
url: "https://mcp.stripe.com"
|
||||
headers:
|
||||
Authorization: "Bearer ***"
|
||||
tools:
|
||||
exclude: [delete_customer, refund_payment]
|
||||
```
|
||||
|
||||
### 示例:同时禁用实用工具包装器
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
docs:
|
||||
url: "https://mcp.docs.example.com"
|
||||
tools:
|
||||
prompts: false
|
||||
resources: false
|
||||
```
|
||||
|
||||
## 过滤实际影响什么?
|
||||
|
||||
Hermes 中 MCP 暴露的功能分为两类:
|
||||
|
||||
1. 服务器原生 MCP 工具
|
||||
- 通过以下方式过滤:
|
||||
- `tools.include`
|
||||
- `tools.exclude`
|
||||
|
||||
2. Hermes 添加的实用工具包装器
|
||||
- 通过以下方式过滤:
|
||||
- `tools.resources`
|
||||
- `tools.prompts`
|
||||
|
||||
### 你可能看到的实用工具包装器
|
||||
|
||||
Resources(资源):
|
||||
- `list_resources`
|
||||
- `read_resource`
|
||||
|
||||
Prompts(提示词):
|
||||
- `list_prompts`
|
||||
- `get_prompt`
|
||||
|
||||
这些包装器仅在以下情况下出现:
|
||||
- 你的配置允许它们,且
|
||||
- MCP 服务器会话实际支持这些能力
|
||||
|
||||
因此,如果服务器不支持 resources/prompts,Hermes 不会假装它支持。
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 模式 1:本地项目助手
|
||||
|
||||
当你希望 Hermes 在有界工作区内推理时,使用 MCP 连接仓库本地的文件系统或 git 服务器。
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
fs:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/project"]
|
||||
|
||||
git:
|
||||
command: "uvx"
|
||||
args: ["mcp-server-git", "--repository", "/home/user/project"]
|
||||
```
|
||||
|
||||
好的 prompt:
|
||||
|
||||
```text
|
||||
Review the project structure and identify where configuration lives.
|
||||
```
|
||||
|
||||
```text
|
||||
Check the local git state and summarize what changed recently.
|
||||
```
|
||||
|
||||
### 模式 2:GitHub 分类助手
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
github:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-github"]
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
|
||||
tools:
|
||||
include: [list_issues, create_issue, update_issue, search_code]
|
||||
prompts: false
|
||||
resources: false
|
||||
```
|
||||
|
||||
好的 prompt:
|
||||
|
||||
```text
|
||||
List open issues about MCP, cluster them by theme, and draft a high-quality issue for the most common bug.
|
||||
```
|
||||
|
||||
```text
|
||||
Search the repo for uses of _discover_and_register_server and explain how MCP tools are registered.
|
||||
```
|
||||
|
||||
### 模式 3:内部 API 助手
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
internal_api:
|
||||
url: "https://mcp.internal.example.com"
|
||||
headers:
|
||||
Authorization: "Bearer ***"
|
||||
tools:
|
||||
include: [list_customers, get_customer, list_invoices]
|
||||
resources: false
|
||||
prompts: false
|
||||
```
|
||||
|
||||
好的 prompt:
|
||||
|
||||
```text
|
||||
Look up customer ACME Corp and summarize recent invoice activity.
|
||||
```
|
||||
|
||||
在这类场景中,严格的白名单远优于排除列表。
|
||||
|
||||
### 模式 4:文档/知识服务器
|
||||
|
||||
某些 MCP 服务器暴露的 prompts 或 resources 更像是共享知识资产,而非直接操作。
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
docs:
|
||||
url: "https://mcp.docs.example.com"
|
||||
tools:
|
||||
prompts: true
|
||||
resources: true
|
||||
```
|
||||
|
||||
好的 prompt:
|
||||
|
||||
```text
|
||||
List available MCP resources from the docs server, then read the onboarding guide and summarize it.
|
||||
```
|
||||
|
||||
```text
|
||||
List prompts exposed by the docs server and tell me which ones would help with incident response.
|
||||
```
|
||||
|
||||
## 教程:带过滤的端到端配置
|
||||
|
||||
以下是一个实际的渐进式流程。
|
||||
|
||||
### 阶段 1:使用严格白名单添加 GitHub MCP
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
github:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-github"]
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
|
||||
tools:
|
||||
include: [list_issues, create_issue, search_code]
|
||||
prompts: false
|
||||
resources: false
|
||||
```
|
||||
|
||||
启动 Hermes 并询问:
|
||||
|
||||
```text
|
||||
Search the codebase for references to MCP and summarize the main integration points.
|
||||
```
|
||||
|
||||
### 阶段 2:仅在需要时扩展
|
||||
|
||||
如果之后还需要更新 issue:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
include: [list_issues, create_issue, update_issue, search_code]
|
||||
```
|
||||
|
||||
然后重新加载:
|
||||
|
||||
```text
|
||||
/reload-mcp
|
||||
```
|
||||
|
||||
### 阶段 3:添加具有不同策略的第二个服务器
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
github:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-github"]
|
||||
env:
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: "***"
|
||||
tools:
|
||||
include: [list_issues, create_issue, update_issue, search_code]
|
||||
prompts: false
|
||||
resources: false
|
||||
|
||||
filesystem:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/project"]
|
||||
```
|
||||
|
||||
现在 Hermes 可以组合使用它们:
|
||||
|
||||
```text
|
||||
Inspect the local project files, then create a GitHub issue summarizing the bug you find.
|
||||
```
|
||||
|
||||
这就是 MCP 的强大之处:无需修改 Hermes 核心即可实现多系统工作流。
|
||||
|
||||
## 安全使用建议
|
||||
|
||||
### 对危险系统优先使用白名单
|
||||
|
||||
对于任何涉及财务、面向客户或具有破坏性的系统:
|
||||
- 使用 `tools.include`
|
||||
- 从尽可能小的集合开始
|
||||
|
||||
### 禁用未使用的实用工具
|
||||
|
||||
如果你不希望模型浏览服务器提供的 resources/prompts,请将其关闭:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
resources: false
|
||||
prompts: false
|
||||
```
|
||||
|
||||
### 保持服务器范围狭窄
|
||||
|
||||
示例:
|
||||
- 文件系统服务器根目录指向一个项目目录,而非整个主目录
|
||||
- git 服务器指向一个仓库
|
||||
- 内部 API 服务器默认以读取为主的工具暴露
|
||||
|
||||
### 配置更改后重新加载
|
||||
|
||||
```text
|
||||
/reload-mcp
|
||||
```
|
||||
|
||||
在更改以下内容后执行此操作:
|
||||
- include/exclude 列表
|
||||
- enabled 标志
|
||||
- resources/prompts 开关
|
||||
- 认证 header / env
|
||||
|
||||
## 按症状排查问题
|
||||
|
||||
### "服务器已连接,但我期望的工具不见了"
|
||||
|
||||
可能原因:
|
||||
- 被 `tools.include` 过滤
|
||||
- 被 `tools.exclude` 排除
|
||||
- 实用工具包装器通过 `resources: false` 或 `prompts: false` 禁用
|
||||
- 服务器实际上不支持 resources/prompts
|
||||
|
||||
### "服务器已配置,但什么都没加载"
|
||||
|
||||
检查:
|
||||
- 配置中是否遗留了 `enabled: false`
|
||||
- 命令/运行时是否存在(`npx`、`uvx` 等)
|
||||
- HTTP 端点是否可达
|
||||
- 认证 env 或 header 是否正确
|
||||
|
||||
### "为什么我看到的工具比 MCP 服务器公告的少?"
|
||||
|
||||
因为 Hermes 现在遵守你的按服务器策略和能力感知注册。这是预期行为,通常也是期望的结果。
|
||||
|
||||
### "如何在不删除配置的情况下移除 MCP 服务器?"
|
||||
|
||||
使用:
|
||||
|
||||
```yaml
|
||||
enabled: false
|
||||
```
|
||||
|
||||
这会保留配置,但阻止连接和注册。
|
||||
|
||||
## 推荐的首批 MCP 配置
|
||||
|
||||
适合大多数用户的首选服务器:
|
||||
- filesystem
|
||||
- git
|
||||
- GitHub
|
||||
- fetch / 文档 MCP 服务器
|
||||
- 一个范围窄的内部 API
|
||||
|
||||
不适合作为首选的服务器:
|
||||
- 具有大量破坏性操作且未经过滤的大型业务系统
|
||||
- 任何你不够了解、无法加以约束的系统
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [MCP(模型上下文协议)](/user-guide/features/mcp)
|
||||
- [FAQ](/reference/faq)
|
||||
- [斜杠命令](/reference/slash-commands)
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
title: "在 Hermes 中使用 SOUL.md"
|
||||
description: "如何使用 SOUL.md 塑造 Hermes Agent 的默认风格,哪些内容应放在其中,以及它与 AGENTS.md 和 /personality 的区别"
|
||||
---
|
||||
|
||||
# 在 Hermes 中使用 SOUL.md
|
||||
|
||||
`SOUL.md` 是你的 Hermes 实例的**主要身份标识**。它是系统提示词(system prompt)中的第一项内容——定义了 Agent 是谁、如何表达,以及应避免什么。
|
||||
|
||||
如果你希望每次与 Hermes 交谈时都感受到一致的助手风格,或者想用自己的角色完全替换 Hermes 的默认人设,这就是你需要编辑的文件。
|
||||
|
||||
## SOUL.md 的用途
|
||||
|
||||
`SOUL.md` 适用于:
|
||||
- 语气
|
||||
- 个性
|
||||
- 沟通风格
|
||||
- Hermes 应有多直接或多温和
|
||||
- Hermes 在风格上应避免什么
|
||||
- Hermes 如何应对不确定性、分歧和模糊情况
|
||||
|
||||
简而言之:
|
||||
- `SOUL.md` 关注的是 Hermes 是谁,以及 Hermes 如何表达
|
||||
|
||||
## SOUL.md 不适用的内容
|
||||
|
||||
不要在其中放置:
|
||||
- 特定代码仓库的编码规范
|
||||
- 文件路径
|
||||
- 命令
|
||||
- 服务端口
|
||||
- 架构说明
|
||||
- 项目工作流指令
|
||||
|
||||
这些内容属于 `AGENTS.md`。
|
||||
|
||||
一个简单的判断原则:
|
||||
- 如果某项内容应在所有地方生效,放入 `SOUL.md`
|
||||
- 如果某项内容只属于某个项目,放入 `AGENTS.md`
|
||||
|
||||
## 文件位置
|
||||
|
||||
Hermes 目前仅使用当前实例的全局 SOUL 文件:
|
||||
|
||||
```text
|
||||
~/.hermes/SOUL.md
|
||||
```
|
||||
|
||||
如果你使用自定义主目录运行 Hermes,路径变为:
|
||||
|
||||
```text
|
||||
$HERMES_HOME/SOUL.md
|
||||
```
|
||||
|
||||
## 首次运行行为
|
||||
|
||||
如果 `SOUL.md` 尚不存在,Hermes 会自动为你生成一个初始文件。
|
||||
|
||||
这意味着大多数用户一开始就有一个可以立即阅读和编辑的真实文件。
|
||||
|
||||
注意:
|
||||
- 如果你已有 `SOUL.md`,Hermes 不会覆盖它
|
||||
- 如果文件存在但为空,Hermes 不会从中向提示词添加任何内容
|
||||
|
||||
## Hermes 如何使用它
|
||||
|
||||
Hermes 启动会话时,会从 `HERMES_HOME` 读取 `SOUL.md`,扫描其中的提示词注入(prompt-injection)模式,必要时进行截断,并将其作为 **Agent 身份标识**——系统提示词中的第 1 个槽位。这意味着 `SOUL.md` 会完全替换内置的默认身份文本。
|
||||
|
||||
如果 `SOUL.md` 缺失、为空或无法加载,Hermes 将回退到内置的默认身份。
|
||||
|
||||
文件内容不会被任何包装语言包裹。内容本身才是关键——按照你希望 Agent 思考和表达的方式来写。
|
||||
|
||||
## 第一次编辑建议
|
||||
|
||||
如果你只做一件事,打开文件并修改几行,让它感觉像你自己的风格。
|
||||
|
||||
例如:
|
||||
|
||||
```markdown
|
||||
You are direct, calm, and technically precise.
|
||||
Prefer substance over politeness theater.
|
||||
Push back clearly when an idea is weak.
|
||||
Keep answers compact unless deeper detail is useful.
|
||||
```
|
||||
|
||||
仅此一项就能明显改变 Hermes 的感觉。
|
||||
|
||||
## 示例风格
|
||||
|
||||
### 1. 务实工程师
|
||||
|
||||
```markdown
|
||||
You are a pragmatic senior engineer.
|
||||
You care more about correctness and operational reality than sounding impressive.
|
||||
|
||||
## Style
|
||||
- Be direct
|
||||
- Be concise unless complexity requires depth
|
||||
- Say when something is a bad idea
|
||||
- Prefer practical tradeoffs over idealized abstractions
|
||||
|
||||
## Avoid
|
||||
- Sycophancy
|
||||
- Hype language
|
||||
- Overexplaining obvious things
|
||||
```
|
||||
|
||||
### 2. 研究伙伴
|
||||
|
||||
```markdown
|
||||
You are a thoughtful research collaborator.
|
||||
You are curious, honest about uncertainty, and excited by unusual ideas.
|
||||
|
||||
## Style
|
||||
- Explore possibilities without pretending certainty
|
||||
- Distinguish speculation from evidence
|
||||
- Ask clarifying questions when the idea space is underspecified
|
||||
- Prefer conceptual depth over shallow completeness
|
||||
```
|
||||
|
||||
### 3. 教师/讲解者
|
||||
|
||||
```markdown
|
||||
You are a patient technical teacher.
|
||||
You care about understanding, not performance.
|
||||
|
||||
## Style
|
||||
- Explain clearly
|
||||
- Use examples when they help
|
||||
- Do not assume prior knowledge unless the user signals it
|
||||
- Build from intuition to details
|
||||
```
|
||||
|
||||
### 4. 严格审阅者
|
||||
|
||||
```markdown
|
||||
You are a rigorous reviewer.
|
||||
You are fair, but you do not soften important criticism.
|
||||
|
||||
## Style
|
||||
- Point out weak assumptions directly
|
||||
- Prioritize correctness over harmony
|
||||
- Be explicit about risks and tradeoffs
|
||||
- Prefer blunt clarity to vague diplomacy
|
||||
```
|
||||
|
||||
## 什么是优质的 SOUL.md?
|
||||
|
||||
优质的 `SOUL.md` 具备以下特点:
|
||||
- 稳定
|
||||
- 广泛适用
|
||||
- 风格具体
|
||||
- 不堆砌临时指令
|
||||
|
||||
劣质的 `SOUL.md` 则是:
|
||||
- 充斥项目细节
|
||||
- 自相矛盾
|
||||
- 试图微观管理每一个回复的形式
|
||||
- 大量泛泛之词,如"要有帮助"和"要清晰"
|
||||
|
||||
Hermes 本身已经尽力做到有帮助且清晰。`SOUL.md` 应当赋予真实的个性和风格,而不是重申显而易见的默认行为。
|
||||
|
||||
## 建议结构
|
||||
|
||||
不需要标题,但标题有助于组织内容。
|
||||
|
||||
一个实用的简单结构:
|
||||
|
||||
```markdown
|
||||
# Identity
|
||||
Who Hermes is.
|
||||
|
||||
# Style
|
||||
How Hermes should sound.
|
||||
|
||||
# Avoid
|
||||
What Hermes should not do.
|
||||
|
||||
# Defaults
|
||||
How Hermes should behave when ambiguity appears.
|
||||
```
|
||||
|
||||
## SOUL.md 与 /personality 的区别
|
||||
|
||||
两者互为补充。
|
||||
|
||||
使用 `SOUL.md` 作为持久的基础设定。
|
||||
使用 `/personality` 进行临时的模式切换。
|
||||
|
||||
示例:
|
||||
- 你的默认 SOUL 是务实且直接的
|
||||
- 某次会话中你使用 `/personality teacher`
|
||||
- 之后切换回来,无需修改基础风格文件
|
||||
|
||||
## SOUL.md 与 AGENTS.md 的区别
|
||||
|
||||
这是最常见的误用。
|
||||
|
||||
### 放入 SOUL.md 的内容
|
||||
- "Be direct."
|
||||
- "Avoid hype language."
|
||||
- "Prefer short answers unless depth helps."
|
||||
- "Push back when the user is wrong."
|
||||
|
||||
### 放入 AGENTS.md 的内容
|
||||
- "Use pytest, not unittest."
|
||||
- "Frontend lives in `frontend/`."
|
||||
- "Never edit migrations directly."
|
||||
- "The API runs on port 8000."
|
||||
|
||||
## 如何编辑
|
||||
|
||||
```bash
|
||||
nano ~/.hermes/SOUL.md
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```bash
|
||||
vim ~/.hermes/SOUL.md
|
||||
```
|
||||
|
||||
然后重启 Hermes 或开启新会话。
|
||||
|
||||
## 实用工作流
|
||||
|
||||
1. 从自动生成的默认文件开始
|
||||
2. 删除不符合你期望风格的内容
|
||||
3. 添加 4–8 行清晰定义语气和默认行为的文字
|
||||
4. 与 Hermes 交谈一段时间
|
||||
5. 根据仍感觉不对的地方进行调整
|
||||
|
||||
这种迭代方式比一次性设计完美人设更有效。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 我编辑了 SOUL.md,但 Hermes 听起来还是一样
|
||||
|
||||
检查:
|
||||
- 你编辑的是 `~/.hermes/SOUL.md` 或 `$HERMES_HOME/SOUL.md`
|
||||
- 而不是某个仓库本地的 `SOUL.md`
|
||||
- 文件不为空
|
||||
- 编辑后已重启会话
|
||||
- 没有 `/personality` 覆盖层主导了结果
|
||||
|
||||
### Hermes 忽略了我 SOUL.md 中的部分内容
|
||||
|
||||
可能原因:
|
||||
- 更高优先级的指令覆盖了它
|
||||
- 文件中包含相互冲突的指导内容
|
||||
- 文件过长被截断
|
||||
- 部分文本类似提示词注入内容,可能被扫描器拦截或修改
|
||||
|
||||
### 我的 SOUL.md 变得过于项目化
|
||||
|
||||
将项目指令移入 `AGENTS.md`,保持 `SOUL.md` 专注于身份标识和风格。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [个性与 SOUL.md](/user-guide/features/personality)
|
||||
- [上下文文件](/user-guide/features/context-files)
|
||||
- [配置](/user-guide/configuration)
|
||||
- [技巧与最佳实践](/guides/tips)
|
||||
+456
@@ -0,0 +1,456 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
title: "在 Hermes 中使用语音模式"
|
||||
description: "在 CLI、Telegram、Discord 及 Discord 语音频道中设置和使用 Hermes 语音模式的实用指南"
|
||||
---
|
||||
|
||||
# 在 Hermes 中使用语音模式
|
||||
|
||||
本指南是[语音模式功能参考](/user-guide/features/voice-mode)的实用配套文档。
|
||||
|
||||
功能页面介绍语音模式能做什么,本指南则说明如何真正用好它。
|
||||
|
||||
## 语音模式适合哪些场景
|
||||
|
||||
语音模式在以下情况特别有用:
|
||||
- 需要免手持的 CLI 工作流
|
||||
- 希望在 Telegram 或 Discord 中获得语音回复
|
||||
- 希望 Hermes 加入 Discord 语音频道进行实时对话
|
||||
- 边走动边快速记录想法、调试问题或来回交流,而不是打字
|
||||
|
||||
## 选择你的语音模式方案
|
||||
|
||||
Hermes 中实际上有三种不同的语音体验。
|
||||
|
||||
| 模式 | 最适合 | 平台 |
|
||||
|---|---|---|
|
||||
| 交互式麦克风循环 | 编码或研究时的个人免手持使用 | CLI |
|
||||
| 聊天中的语音回复 | 在正常消息旁附带语音回复 | Telegram、Discord |
|
||||
| 实时语音频道机器人 | 在语音频道中进行群组或个人实时对话 | Discord 语音频道 |
|
||||
|
||||
推荐路径:
|
||||
1. 先让文本模式正常工作
|
||||
2. 再启用语音回复
|
||||
3. 最后如需完整体验,再切换到 Discord 语音频道
|
||||
|
||||
## 第一步:确保普通 Hermes 先正常运行
|
||||
|
||||
在接触语音模式之前,请确认:
|
||||
- Hermes 能正常启动
|
||||
- 已配置好 provider(提供商)
|
||||
- Agent 能正常回答文本 prompt(提示词)
|
||||
|
||||
```bash
|
||||
hermes
|
||||
```
|
||||
|
||||
问一个简单的问题:
|
||||
|
||||
```text
|
||||
What tools do you have available?
|
||||
```
|
||||
|
||||
如果文本模式还不稳定,请先修复它。
|
||||
|
||||
## 第二步:安装所需的额外依赖
|
||||
|
||||
### CLI 麦克风 + 播放
|
||||
|
||||
```bash
|
||||
pip install "hermes-agent[voice]"
|
||||
```
|
||||
|
||||
### 消息平台
|
||||
|
||||
```bash
|
||||
pip install "hermes-agent[messaging]"
|
||||
```
|
||||
|
||||
### 高级 ElevenLabs TTS
|
||||
|
||||
```bash
|
||||
pip install "hermes-agent[tts-premium]"
|
||||
```
|
||||
|
||||
### 本地 NeuTTS(可选)
|
||||
|
||||
```bash
|
||||
python -m pip install -U neutts[all]
|
||||
```
|
||||
|
||||
### 全部安装
|
||||
|
||||
```bash
|
||||
pip install "hermes-agent[all]"
|
||||
```
|
||||
|
||||
## 第三步:安装系统依赖
|
||||
|
||||
### macOS
|
||||
|
||||
```bash
|
||||
brew install portaudio ffmpeg opus
|
||||
brew install espeak-ng
|
||||
```
|
||||
|
||||
### Ubuntu / Debian
|
||||
|
||||
```bash
|
||||
sudo apt install portaudio19-dev ffmpeg libopus0
|
||||
sudo apt install espeak-ng
|
||||
```
|
||||
|
||||
各依赖的作用:
|
||||
- `portaudio` → CLI 语音模式的麦克风输入与播放
|
||||
- `ffmpeg` → TTS 和消息传递的音频转换
|
||||
- `opus` → Discord 语音编解码器支持
|
||||
- `espeak-ng` → NeuTTS 的 phonemizer 后端
|
||||
|
||||
## 第四步:选择 STT 和 TTS 提供商
|
||||
|
||||
Hermes 同时支持本地和云端语音处理方案。
|
||||
|
||||
### 最简单 / 最低成本的方案
|
||||
|
||||
使用本地 STT 和免费的 Edge TTS:
|
||||
- STT provider:`local`
|
||||
- TTS provider:`edge`
|
||||
|
||||
这通常是最好的起点。
|
||||
|
||||
### 环境变量文件示例
|
||||
|
||||
添加到 `~/.hermes/.env`:
|
||||
|
||||
```bash
|
||||
# 云端 STT 选项(本地无需密钥)
|
||||
GROQ_API_KEY=***
|
||||
VOICE_TOOLS_OPENAI_KEY=***
|
||||
|
||||
# 高级 TTS(可选)
|
||||
ELEVENLABS_API_KEY=***
|
||||
```
|
||||
|
||||
### Provider 推荐
|
||||
|
||||
#### 语音转文字(STT)
|
||||
|
||||
- `local` → 隐私保护和零成本使用的最佳默认选项
|
||||
- `groq` → 极快的云端转录
|
||||
- `openai` → 良好的付费备选
|
||||
|
||||
#### 文字转语音(TTS)
|
||||
|
||||
- `edge` → 免费,对大多数用户已足够
|
||||
- `neutts` → 免费的本地/设备端 TTS
|
||||
- `elevenlabs` → 最佳质量
|
||||
- `openai` → 良好的中间选项
|
||||
- `mistral` → 多语言,原生 Opus
|
||||
|
||||
### 如果使用 `hermes setup`
|
||||
|
||||
如果你在设置向导中选择了 NeuTTS,Hermes 会检查 `neutts` 是否已安装。如果缺失,向导会告知你 NeuTTS 需要 Python 包 `neutts` 和系统包 `espeak-ng`,并提供自动安装,使用平台包管理器安装 `espeak-ng`,然后运行:
|
||||
|
||||
```bash
|
||||
python -m pip install -U neutts[all]
|
||||
```
|
||||
|
||||
如果跳过安装或安装失败,向导会回退到 Edge TTS。
|
||||
|
||||
## 第五步:推荐配置
|
||||
|
||||
```yaml
|
||||
voice:
|
||||
record_key: "ctrl+b"
|
||||
max_recording_seconds: 120
|
||||
auto_tts: false
|
||||
beep_enabled: true
|
||||
silence_threshold: 200
|
||||
silence_duration: 3.0
|
||||
|
||||
stt:
|
||||
provider: "local"
|
||||
local:
|
||||
model: "base"
|
||||
|
||||
tts:
|
||||
provider: "edge"
|
||||
edge:
|
||||
voice: "en-US-AriaNeural"
|
||||
```
|
||||
|
||||
这是适合大多数人的保守默认配置。
|
||||
|
||||
如果想改用本地 TTS,将 `tts` 块替换为:
|
||||
|
||||
```yaml
|
||||
tts:
|
||||
provider: "neutts"
|
||||
neutts:
|
||||
ref_audio: ''
|
||||
ref_text: ''
|
||||
model: neuphonic/neutts-air-q4-gguf
|
||||
device: cpu
|
||||
```
|
||||
|
||||
## 使用场景一:CLI 语音模式
|
||||
|
||||
## 开启方式
|
||||
|
||||
启动 Hermes:
|
||||
|
||||
```bash
|
||||
hermes
|
||||
```
|
||||
|
||||
在 CLI 内执行:
|
||||
|
||||
```text
|
||||
/voice on
|
||||
```
|
||||
|
||||
### 录音流程
|
||||
|
||||
默认按键:
|
||||
- `Ctrl+B`
|
||||
|
||||
工作流程:
|
||||
1. 按下 `Ctrl+B`
|
||||
2. 说话
|
||||
3. 等待静音检测自动停止录音
|
||||
4. Hermes 转录并回复
|
||||
5. 如果开启了 TTS,它会朗读答案
|
||||
6. 循环可自动重启以持续使用
|
||||
|
||||
### 常用命令
|
||||
|
||||
```text
|
||||
/voice
|
||||
/voice on
|
||||
/voice off
|
||||
/voice tts
|
||||
/voice status
|
||||
```
|
||||
|
||||
### 推荐的 CLI 工作流
|
||||
|
||||
#### 随走随调试
|
||||
|
||||
说:
|
||||
|
||||
```text
|
||||
I keep getting a docker permission error. Help me debug it.
|
||||
```
|
||||
|
||||
然后继续免手持操作:
|
||||
- "再读一遍最后的错误"
|
||||
- "用更简单的语言解释根本原因"
|
||||
- "现在给我精确的修复方案"
|
||||
|
||||
#### 研究 / 头脑风暴
|
||||
|
||||
非常适合:
|
||||
- 边走动边思考
|
||||
- 口述半成形的想法
|
||||
- 让 Hermes 实时整理你的思路
|
||||
|
||||
#### 无障碍 / 少打字场景
|
||||
|
||||
如果打字不方便,语音模式是保持完整 Hermes 工作流的最快方式之一。
|
||||
|
||||
## 调整 CLI 行为
|
||||
|
||||
### 静音阈值
|
||||
|
||||
如果 Hermes 开始/停止过于激进,调整:
|
||||
|
||||
```yaml
|
||||
voice:
|
||||
silence_threshold: 250
|
||||
```
|
||||
|
||||
阈值越高 = 灵敏度越低。
|
||||
|
||||
### 静音时长
|
||||
|
||||
如果你在句子之间经常停顿,增大该值:
|
||||
|
||||
```yaml
|
||||
voice:
|
||||
silence_duration: 4.0
|
||||
```
|
||||
|
||||
### 录音按键
|
||||
|
||||
如果 `Ctrl+B` 与你的终端或 tmux 习惯冲突:
|
||||
|
||||
```yaml
|
||||
voice:
|
||||
record_key: "ctrl+space"
|
||||
```
|
||||
|
||||
## 使用场景二:Telegram 或 Discord 中的语音回复
|
||||
|
||||
此模式比完整语音频道更简单。
|
||||
|
||||
Hermes 仍作为普通聊天机器人运行,但可以朗读回复。
|
||||
|
||||
### 启动 gateway
|
||||
|
||||
```bash
|
||||
hermes gateway
|
||||
```
|
||||
|
||||
### 开启语音回复
|
||||
|
||||
在 Telegram 或 Discord 中:
|
||||
|
||||
```text
|
||||
/voice on
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```text
|
||||
/voice tts
|
||||
```
|
||||
|
||||
### 模式说明
|
||||
|
||||
| 模式 | 含义 |
|
||||
|---|---|
|
||||
| `off` | 仅文本 |
|
||||
| `voice_only` | 仅当用户发送语音时才朗读 |
|
||||
| `all` | 朗读每条回复 |
|
||||
|
||||
### 何时使用哪种模式
|
||||
|
||||
- `/voice on`:仅对语音来源的消息给出语音回复
|
||||
- `/voice tts`:始终作为完整语音助手运行
|
||||
|
||||
### 推荐的消息平台工作流
|
||||
|
||||
#### 手机上的 Telegram 助手
|
||||
|
||||
适用于:
|
||||
- 离开电脑时
|
||||
- 发送语音备忘并获取快速语音回复
|
||||
- 希望 Hermes 充当便携式研究或运维助手
|
||||
|
||||
#### Discord 私信中的语音输出
|
||||
|
||||
适用于希望私密交互、避免服务器频道 @mention 行为的场景。
|
||||
|
||||
## 使用场景三:Discord 语音频道
|
||||
|
||||
这是最高级的模式。
|
||||
|
||||
Hermes 加入 Discord 语音频道(VC),监听用户语音,转录后运行正常的 agent 流水线,并将回复朗读回频道。
|
||||
|
||||
## 所需的 Discord 权限
|
||||
|
||||
除了普通文本机器人设置外,请确保机器人拥有:
|
||||
- Connect(连接)
|
||||
- Speak(发言)
|
||||
- 最好还有 Use Voice Activity(使用语音活动)
|
||||
|
||||
同时在开发者门户中启用特权 intent(意图):
|
||||
- Presence Intent
|
||||
- Server Members Intent
|
||||
- Message Content Intent
|
||||
|
||||
## 加入与离开
|
||||
|
||||
在机器人所在的 Discord 文本频道中:
|
||||
|
||||
```text
|
||||
/voice join
|
||||
/voice leave
|
||||
/voice status
|
||||
```
|
||||
|
||||
### 加入后的行为
|
||||
|
||||
- 用户在语音频道中说话
|
||||
- Hermes 检测语音边界
|
||||
- 转录内容发布到关联的文本频道
|
||||
- Hermes 以文字和音频形式回复
|
||||
- 文本频道为执行 `/voice join` 的那个频道
|
||||
|
||||
### Discord 语音频道使用最佳实践
|
||||
|
||||
- 严格限制 `DISCORD_ALLOWED_USERS`
|
||||
- 先使用专用的机器人/测试频道
|
||||
- 在尝试语音频道模式之前,先确认 STT 和 TTS 在普通文本聊天语音模式下正常工作
|
||||
|
||||
## 语音质量建议
|
||||
|
||||
### 最佳质量方案
|
||||
|
||||
- STT:本地 `large-v3` 或 Groq `whisper-large-v3`
|
||||
- TTS:ElevenLabs
|
||||
|
||||
### 最佳速度 / 便利性方案
|
||||
|
||||
- STT:本地 `base` 或 Groq
|
||||
- TTS:Edge
|
||||
|
||||
### 最佳零成本方案
|
||||
|
||||
- STT:本地
|
||||
- TTS:Edge
|
||||
|
||||
## 常见故障模式
|
||||
|
||||
### "No audio device found"
|
||||
|
||||
安装 `portaudio`。
|
||||
|
||||
### "机器人加入但听不到声音"
|
||||
|
||||
检查:
|
||||
- 你的 Discord 用户 ID 是否在 `DISCORD_ALLOWED_USERS` 中
|
||||
- 你是否处于静音状态
|
||||
- 特权 intent 是否已启用
|
||||
- 机器人是否拥有 Connect/Speak 权限
|
||||
|
||||
### "能转录但不说话"
|
||||
|
||||
检查:
|
||||
- TTS provider 配置
|
||||
- ElevenLabs 或 OpenAI 的 API 密钥 / 配额
|
||||
- Edge 转换路径的 `ffmpeg` 安装情况
|
||||
|
||||
### "Whisper 输出乱码"
|
||||
|
||||
尝试:
|
||||
- 更安静的环境
|
||||
- 提高 `silence_threshold`
|
||||
- 更换 STT provider/模型
|
||||
- 更短、更清晰的表达
|
||||
|
||||
### "在私信中正常但在服务器频道中不工作"
|
||||
|
||||
这通常是 mention(提及)策略问题。
|
||||
|
||||
默认情况下,除非另行配置,机器人在 Discord 服务器文本频道中需要被 `@mention` 才会响应。
|
||||
|
||||
## 建议的第一周方案
|
||||
|
||||
如果你想走最短的成功路径:
|
||||
|
||||
1. 让文本 Hermes 正常工作
|
||||
2. 安装 `hermes-agent[voice]`
|
||||
3. 使用本地 STT + Edge TTS 的 CLI 语音模式
|
||||
4. 然后在 Telegram 或 Discord 中启用 `/voice on`
|
||||
5. 只有在此之后,再尝试 Discord 语音频道模式
|
||||
|
||||
这种递进方式可以将调试范围控制到最小。
|
||||
|
||||
## 下一步阅读
|
||||
|
||||
- [语音模式功能参考](/user-guide/features/voice-mode)
|
||||
- [消息 Gateway](/user-guide/messaging)
|
||||
- [Discord 设置](/user-guide/messaging/discord)
|
||||
- [Telegram 设置](/user-guide/messaging/telegram)
|
||||
- [配置](/user-guide/configuration)
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
---
|
||||
sidebar_position: 11
|
||||
sidebar_label: "通过 Webhook 进行 GitHub PR 审查"
|
||||
title: "使用 Webhook 自动发布 GitHub PR 评论"
|
||||
description: "将 Hermes 连接到 GitHub,使其自动获取 PR diff、审查代码变更并发布评论——由 webhook 触发,无需手动提示"
|
||||
---
|
||||
|
||||
# 使用 Webhook 自动发布 GitHub PR 评论
|
||||
|
||||
本指南介绍如何将 Hermes Agent 连接到 GitHub,使其自动获取 pull request 的 diff、分析代码变更并发布评论——由 webhook 事件触发,无需手动 prompt(提示词)。
|
||||
|
||||
当 PR 被打开或更新时,GitHub 会向你的 Hermes 实例发送一个 webhook POST 请求。Hermes 使用一个 prompt 运行 agent,该 prompt 指示其通过 `gh` CLI 获取 diff,并将响应发布回 PR 线程。
|
||||
|
||||
:::tip 想要无需公网端点的更简单配置?
|
||||
如果你没有公网 URL,或只是想快速上手,请查看 [构建 GitHub PR 审查 Agent](./github-pr-review-agent.md) —— 使用 cron 作业按计划轮询 PR,可在 NAT 和防火墙后运行。
|
||||
:::
|
||||
|
||||
:::info 参考文档
|
||||
完整的 webhook 平台参考(所有配置选项、投递类型、动态订阅、安全模型),请参阅 [Webhooks](/user-guide/messaging/webhooks)。
|
||||
:::
|
||||
|
||||
:::warning Prompt 注入风险
|
||||
Webhook payload 包含攻击者可控的数据——PR 标题、commit 消息和描述中可能包含恶意指令。当你的 webhook 端点暴露在公网时,请在沙箱环境(Docker、SSH 后端)中运行 gateway。请参阅下方的[安全说明](#security-notes)。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Hermes Agent 已安装并运行(`hermes gateway`)
|
||||
- [`gh` CLI](https://cli.github.com/) 已安装并在 gateway 主机上完成认证(`gh auth login`)
|
||||
- 你的 Hermes 实例有一个可公网访问的 URL(如果在本地运行,请参阅[使用 ngrok 进行本地测试](#local-testing-with-ngrok))
|
||||
- 对 GitHub 仓库的管理员权限(管理 webhook 所需)
|
||||
|
||||
---
|
||||
|
||||
## 第一步——启用 webhook 平台
|
||||
|
||||
在你的 `~/.hermes/config.yaml` 中添加以下内容:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
port: 8644 # 默认值;如果该端口被其他服务占用,请修改
|
||||
rate_limit: 30 # 每条路由每分钟最大请求数(非全局上限)
|
||||
|
||||
routes:
|
||||
github-pr-review:
|
||||
secret: "your-webhook-secret-here" # 必须与 GitHub webhook secret 完全一致
|
||||
events:
|
||||
- pull_request
|
||||
|
||||
# agent 被指示在审查前先获取实际的 diff。
|
||||
# {number} 和 {repository.full_name} 从 GitHub payload 中解析。
|
||||
prompt: |
|
||||
A pull request event was received (action: {action}).
|
||||
|
||||
PR #{number}: {pull_request.title}
|
||||
Author: {pull_request.user.login}
|
||||
Branch: {pull_request.head.ref} → {pull_request.base.ref}
|
||||
Description: {pull_request.body}
|
||||
URL: {pull_request.html_url}
|
||||
|
||||
If the action is "closed" or "labeled", stop here and do not post a comment.
|
||||
|
||||
Otherwise:
|
||||
1. Run: gh pr diff {number} --repo {repository.full_name}
|
||||
2. Review the code changes for correctness, security issues, and clarity.
|
||||
3. Write a concise, actionable review comment and post it.
|
||||
|
||||
deliver: github_comment
|
||||
deliver_extra:
|
||||
repo: "{repository.full_name}"
|
||||
pr_number: "{number}"
|
||||
```
|
||||
|
||||
**关键字段:**
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `secret`(路由级别) | 该路由的 HMAC secret。如果省略,则回退到 `extra.secret` 全局配置。 |
|
||||
| `events` | 要接受的 `X-GitHub-Event` 请求头值列表。空列表 = 接受所有。 |
|
||||
| `prompt` | 模板;`{field}` 和 `{nested.field}` 从 GitHub payload 中解析。 |
|
||||
| `deliver` | `github_comment` 通过 `gh pr comment` 发布。`log` 仅写入 gateway 日志。 |
|
||||
| `deliver_extra.repo` | 从 payload 中解析为例如 `org/repo`。 |
|
||||
| `deliver_extra.pr_number` | 从 payload 中解析为 PR 编号。 |
|
||||
|
||||
:::note Payload 中不包含代码
|
||||
GitHub webhook payload 包含 PR 元数据(标题、描述、分支名、URL),但**不包含 diff**。上方的 prompt 指示 agent 运行 `gh pr diff` 来获取实际变更。`terminal` 工具已包含在默认的 `hermes-webhook` 工具集中,无需额外配置。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 第二步——启动 gateway
|
||||
|
||||
```bash
|
||||
hermes gateway
|
||||
```
|
||||
|
||||
你应该看到:
|
||||
|
||||
```
|
||||
[webhook] Listening on 0.0.0.0:8644 — routes: github-pr-review
|
||||
```
|
||||
|
||||
验证其是否正在运行:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8644/health
|
||||
# {"status": "ok", "platform": "webhook"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第三步——在 GitHub 上注册 webhook
|
||||
|
||||
1. 进入你的仓库 → **Settings** → **Webhooks** → **Add webhook**
|
||||
2. 填写:
|
||||
- **Payload URL:** `https://your-public-url.example.com/webhooks/github-pr-review`
|
||||
- **Content type:** `application/json`
|
||||
- **Secret:** 与路由配置中 `secret` 设置的值相同
|
||||
- **Which events?** → 选择单个事件 → 勾选 **Pull requests**
|
||||
3. 点击 **Add webhook**
|
||||
|
||||
GitHub 会立即发送一个 `ping` 事件以确认连接。该事件会被安全忽略——`ping` 不在你的 `events` 列表中——并返回 `{"status": "ignored", "event": "ping"}`。它仅在 DEBUG 级别记录日志,因此不会在默认日志级别的控制台中显示。
|
||||
|
||||
---
|
||||
|
||||
## 第四步——打开一个测试 PR
|
||||
|
||||
创建一个分支,推送一个变更,并打开一个 PR。在 30–90 秒内(取决于 PR 大小和模型),Hermes 应该会发布一条审查评论。
|
||||
|
||||
要实时跟踪 agent 的进度:
|
||||
|
||||
```bash
|
||||
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用 ngrok 进行本地测试
|
||||
|
||||
如果 Hermes 在你的笔记本上运行,使用 [ngrok](https://ngrok.com/) 将其暴露到公网:
|
||||
|
||||
```bash
|
||||
ngrok http 8644
|
||||
```
|
||||
|
||||
复制 `https://...ngrok-free.app` URL 并将其用作你的 GitHub Payload URL。在 ngrok 免费版中,每次 ngrok 重启后 URL 都会变化——每次会话都需要更新你的 GitHub webhook。付费 ngrok 账户可获得静态域名。
|
||||
|
||||
你可以直接用 `curl` 对静态路由进行冒烟测试——无需 GitHub 账户或真实 PR。
|
||||
|
||||
:::tip 本地测试时使用 `deliver: log`
|
||||
在测试时,将配置中的 `deliver: github_comment` 改为 `deliver: log`。否则 agent 将尝试向测试 payload 中的假 `org/repo#99` 仓库发布评论,这将会失败。对 prompt 输出满意后,再切换回 `deliver: github_comment`。
|
||||
:::
|
||||
|
||||
```bash
|
||||
SECRET="your-webhook-secret-here"
|
||||
BODY='{"action":"opened","number":99,"pull_request":{"title":"Test PR","body":"Adds a feature.","user":{"login":"testuser"},"head":{"ref":"feat/x"},"base":{"ref":"main"},"html_url":"https://github.com/org/repo/pull/99"},"repository":{"full_name":"org/repo"}}'
|
||||
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print "sha256="$2}')
|
||||
|
||||
curl -s -X POST http://localhost:8644/webhooks/github-pr-review \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-GitHub-Event: pull_request" \
|
||||
-H "X-Hub-Signature-256: $SIG" \
|
||||
-d "$BODY"
|
||||
# Expected: {"status":"accepted","route":"github-pr-review","event":"pull_request","delivery_id":"..."}
|
||||
```
|
||||
|
||||
然后观察 agent 运行:
|
||||
```bash
|
||||
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"
|
||||
```
|
||||
|
||||
:::note
|
||||
`hermes webhook test <name>` 仅适用于通过 `hermes webhook subscribe` 创建的**动态订阅**。它不读取 `config.yaml` 中的路由。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 过滤特定 action
|
||||
|
||||
GitHub 会针对多种 action 发送 `pull_request` 事件:`opened`、`synchronize`、`reopened`、`closed`、`labeled` 等。`events` 列表仅按 `X-GitHub-Event` 请求头值过滤——无法在路由级别按 action 子类型过滤。
|
||||
|
||||
第一步中的 prompt 已通过指示 agent 对 `closed` 和 `labeled` 事件提前停止来处理这一问题。
|
||||
|
||||
:::warning Agent 仍会运行并消耗 token(令牌)
|
||||
"stop here" 指令会阻止有意义的审查,但无论 action 如何,agent 仍会对每个 `pull_request` 事件运行至完成。GitHub webhook 只能按事件类型(`pull_request`、`push`、`issues` 等)过滤——无法按 action 子类型(`opened`、`closed`、`labeled`)过滤。路由级别没有针对子 action 的过滤器。对于高流量仓库,请接受这一成本,或通过 GitHub Actions workflow 在上游进行过滤,有条件地调用你的 webhook URL。
|
||||
:::
|
||||
|
||||
> 不支持 Jinja2 或条件模板语法。`{field}` 和 `{nested.field}` 是唯一支持的替换方式。其他内容会原样传递给 agent。
|
||||
|
||||
---
|
||||
|
||||
## 使用 skill 保持一致的审查风格
|
||||
|
||||
加载一个 [Hermes skill](/user-guide/features/skills) 以赋予 agent 一致的审查风格。在 `config.yaml` 的 `platforms.webhook.extra.routes` 中,向你的路由添加 `skills`:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
routes:
|
||||
github-pr-review:
|
||||
secret: "your-webhook-secret-here"
|
||||
events: [pull_request]
|
||||
prompt: |
|
||||
A pull request event was received (action: {action}).
|
||||
PR #{number}: {pull_request.title} by {pull_request.user.login}
|
||||
URL: {pull_request.html_url}
|
||||
|
||||
If the action is "closed" or "labeled", stop here and do not post a comment.
|
||||
|
||||
Otherwise:
|
||||
1. Run: gh pr diff {number} --repo {repository.full_name}
|
||||
2. Review the diff using your review guidelines.
|
||||
3. Write a concise, actionable review comment and post it.
|
||||
skills:
|
||||
- review
|
||||
deliver: github_comment
|
||||
deliver_extra:
|
||||
repo: "{repository.full_name}"
|
||||
pr_number: "{number}"
|
||||
```
|
||||
|
||||
> **注意:** 列表中只有第一个找到的 skill 会被加载。Hermes 不会叠加多个 skill——后续条目会被忽略。
|
||||
|
||||
---
|
||||
|
||||
## 将响应发送到 Slack 或 Discord
|
||||
|
||||
将路由中的 `deliver` 和 `deliver_extra` 字段替换为你的目标平台:
|
||||
|
||||
```yaml
|
||||
# 在 platforms.webhook.extra.routes.<route-name> 内部:
|
||||
|
||||
# Slack
|
||||
deliver: slack
|
||||
deliver_extra:
|
||||
chat_id: "C0123456789" # Slack 频道 ID(省略则使用配置的默认频道)
|
||||
|
||||
# Discord
|
||||
deliver: discord
|
||||
deliver_extra:
|
||||
chat_id: "987654321012345678" # Discord 频道 ID(省略则使用默认频道)
|
||||
```
|
||||
|
||||
目标平台也必须在 gateway 中启用并连接。如果省略 `chat_id`,响应将发送到该平台配置的默认频道。
|
||||
|
||||
有效的 `deliver` 值:`log` · `github_comment` · `telegram` · `discord` · `slack` · `signal` · `sms`
|
||||
|
||||
---
|
||||
|
||||
## GitLab 支持
|
||||
|
||||
同一适配器也适用于 GitLab。GitLab 使用 `X-Gitlab-Token` 进行认证(纯字符串匹配,非 HMAC)——Hermes 会自动处理两者。
|
||||
|
||||
对于事件过滤,GitLab 将 `X-GitLab-Event` 设置为 `Merge Request Hook`、`Push Hook`、`Pipeline Hook` 等值。在 `events` 中使用精确的请求头值:
|
||||
|
||||
```yaml
|
||||
events:
|
||||
- Merge Request Hook
|
||||
```
|
||||
|
||||
GitLab 的 payload 字段与 GitHub 不同——例如,MR 标题使用 `{object_attributes.title}`,MR 编号使用 `{object_attributes.iid}`。发现完整 payload 结构最简单的方式是使用 GitLab webhook 设置中的 **Test** 按钮,结合 **Recent Deliveries** 日志。或者,在路由配置中省略 `prompt`——Hermes 将把完整 payload 作为格式化 JSON 直接传递给 agent,agent 的响应(在 gateway 日志中通过 `deliver: log` 可见)将描述其结构。
|
||||
|
||||
---
|
||||
|
||||
## 安全说明
|
||||
|
||||
- **永远不要在生产环境中使用 `INSECURE_NO_AUTH`**——它会完全禁用签名验证。仅用于本地开发。
|
||||
- **定期轮换你的 webhook secret**,并在 GitHub(webhook 设置)和你的 `config.yaml` 中同步更新。
|
||||
- **速率限制**默认为每条路由每分钟 30 次请求(可通过 `extra.rate_limit` 配置)。超出限制返回 `429`。
|
||||
- **重复投递**(webhook 重试)通过 1 小时的幂等性缓存进行去重。缓存键依次为 `X-GitHub-Delivery`(如果存在)、`X-Request-ID`、毫秒级时间戳。当两个投递 ID 请求头都未设置时,重试**不会**去重。
|
||||
- **Prompt 注入:** PR 标题、描述和 commit 消息均为攻击者可控内容。恶意 PR 可能尝试操纵 agent 的行为。当暴露在公网时,请在沙箱环境(Docker、VM)中运行 gateway。
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 现象 | 检查项 |
|
||||
|---|---|
|
||||
| `401 Invalid signature` | config.yaml 中的 secret 与 GitHub webhook secret 不匹配 |
|
||||
| `404 Unknown route` | URL 中的路由名称与 `routes:` 中的键不匹配 |
|
||||
| `429 Rate limit exceeded` | 每条路由每分钟 30 次请求已超出——在 GitHub UI 中重新投递测试事件时常见;等待一分钟或提高 `extra.rate_limit` |
|
||||
| 未发布评论 | `gh` 未安装、不在 PATH 中,或未完成认证(`gh auth login`) |
|
||||
| Agent 运行但无评论 | 检查 gateway 日志——如果 agent 输出为空或仅为"SKIP",投递仍会被尝试 |
|
||||
| 端口已被占用 | 在 config.yaml 中修改 `extra.port` |
|
||||
| Agent 运行但仅审查了 PR 描述 | prompt 中未包含 `gh pr diff` 指令——diff 不在 webhook payload 中 |
|
||||
| 看不到 ping 事件 | 被忽略的事件仅在 DEBUG 日志级别返回 `{"status":"ignored","event":"ping"}`——检查 GitHub 的投递日志(仓库 → Settings → Webhooks → 你的 webhook → Recent Deliveries) |
|
||||
|
||||
**GitHub 的 Recent Deliveries 标签页**(仓库 → Settings → Webhooks → 你的 webhook)显示每次投递的精确请求头、payload、HTTP 状态和响应体。这是无需查看服务器日志即可诊断故障的最快方式。
|
||||
|
||||
---
|
||||
|
||||
## 完整配置参考
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
host: "0.0.0.0" # 绑定地址(默认:0.0.0.0)
|
||||
port: 8644 # 监听端口(默认:8644)
|
||||
secret: "" # 可选的全局回退 secret
|
||||
rate_limit: 30 # 每条路由每分钟请求数
|
||||
max_body_bytes: 1048576 # payload 大小限制,单位字节(默认:1 MB)
|
||||
|
||||
routes:
|
||||
<route-name>:
|
||||
secret: "required-per-route"
|
||||
events: [] # [] = 接受所有;否则列出 X-GitHub-Event 值
|
||||
prompt: "" # {field} / {nested.field} 从 payload 中解析
|
||||
skills: [] # 加载第一个匹配的 skill(仅一个)
|
||||
deliver: "log" # log | github_comment | telegram | discord | slack | signal | sms
|
||||
deliver_extra: {} # github_comment 需要 repo + pr_number;其他平台需要 chat_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
- **[基于 Cron 的 PR 审查](./github-pr-review-agent.md)** —— 按计划轮询 PR,无需公网端点
|
||||
- **[Webhook 参考](/user-guide/messaging/webhooks)** —— webhook 平台的完整配置参考
|
||||
- **[构建 Plugin](/guides/build-a-hermes-plugin)** —— 将审查逻辑打包为可共享的 plugin
|
||||
- **[Profiles](/user-guide/profiles)** —— 运行一个拥有独立内存和配置的专属审查者 profile
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
---
|
||||
sidebar_position: 12
|
||||
title: "使用 Skills"
|
||||
description: "查找、安装、使用和创建 skills——按需加载的知识文档,用于教会 Hermes 新的工作流程"
|
||||
---
|
||||
|
||||
# 使用 Skills
|
||||
|
||||
Skills(技能)是按需加载的知识文档,用于教会 Hermes 如何处理特定任务——从生成 ASCII 艺术到管理 GitHub PR。本指南介绍日常使用方法。
|
||||
|
||||
完整技术参考请见 [Skills 系统](/user-guide/features/skills)。
|
||||
|
||||
---
|
||||
|
||||
## 查找 Skills
|
||||
|
||||
每个 Hermes 安装都内置了捆绑的 skills。查看可用列表:
|
||||
|
||||
```bash
|
||||
# 在任意聊天会话中:
|
||||
/skills
|
||||
|
||||
# 或通过 CLI:
|
||||
hermes skills list
|
||||
```
|
||||
|
||||
输出包含名称和描述的紧凑列表:
|
||||
|
||||
```
|
||||
ascii-art Generate ASCII art using pyfiglet, cowsay, boxes...
|
||||
arxiv Search and retrieve academic papers from arXiv...
|
||||
github-pr-workflow Full PR lifecycle — create branches, commit...
|
||||
plan Plan mode — inspect context, write a markdown...
|
||||
excalidraw Create hand-drawn style diagrams using Excalidraw...
|
||||
```
|
||||
|
||||
### 搜索 Skill
|
||||
|
||||
```bash
|
||||
# 按关键词搜索
|
||||
/skills search docker
|
||||
/skills search music
|
||||
```
|
||||
|
||||
### Skills Hub
|
||||
|
||||
官方可选 skills(较重或小众、默认未激活的 skills)可通过 Hub 获取:
|
||||
|
||||
```bash
|
||||
# 浏览官方可选 skills
|
||||
/skills browse
|
||||
|
||||
# 搜索 Hub
|
||||
/skills search blockchain
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用 Skill
|
||||
|
||||
每个已安装的 skill 自动成为一个斜杠命令。直接输入其名称即可:
|
||||
|
||||
```bash
|
||||
# 加载 skill 并指定任务
|
||||
/ascii-art Make a banner that says "HELLO WORLD"
|
||||
/plan Design a REST API for a todo app
|
||||
/github-pr-workflow Create a PR for the auth refactor
|
||||
|
||||
# 只输入 skill 名称(不带任务)会加载它并让你描述需求
|
||||
/excalidraw
|
||||
```
|
||||
|
||||
你也可以通过自然对话触发 skills——告诉 Hermes 使用某个特定 skill,它会通过 `skill_view` 工具加载。
|
||||
|
||||
### 渐进式加载
|
||||
|
||||
Skills 采用 token 高效的加载模式,agent 不会一次性加载所有内容:
|
||||
|
||||
1. **`skills_list()`** — 所有 skills 的紧凑列表(约 3k tokens),在会话开始时加载。
|
||||
2. **`skill_view(name)`** — 单个 skill 的完整 SKILL.md 内容,在 agent 判断需要该 skill 时加载。
|
||||
3. **`skill_view(name, file_path)`** — skill 内的特定参考文件,仅在需要时加载。
|
||||
|
||||
这意味着 skills 在真正被使用之前不消耗任何 tokens。
|
||||
|
||||
---
|
||||
|
||||
## 从 Hub 安装
|
||||
|
||||
官方可选 skills 随 Hermes 一起发布,但默认未激活,需显式安装:
|
||||
|
||||
```bash
|
||||
# 安装官方可选 skill
|
||||
hermes skills install official/research/arxiv
|
||||
|
||||
# 在聊天会话中从 Hub 安装
|
||||
/skills install official/creative/songwriting-and-ai-music
|
||||
|
||||
# 直接从任意 HTTP(S) URL 安装单文件 SKILL.md
|
||||
hermes skills install https://sharethis.chat/SKILL.md
|
||||
/skills install https://example.com/SKILL.md --name my-skill
|
||||
```
|
||||
|
||||
安装过程:
|
||||
1. skill 目录被复制到 `~/.hermes/skills/`
|
||||
2. 出现在 `skills_list` 输出中
|
||||
3. 成为可用的斜杠命令
|
||||
|
||||
:::tip
|
||||
已安装的 skills 在新会话中生效。如需在当前会话中立即使用,可用 `/reset` 开启新会话,或添加 `--now` 参数立即使 prompt 缓存失效(下一轮会消耗更多 tokens)。
|
||||
:::
|
||||
|
||||
### 验证安装
|
||||
|
||||
```bash
|
||||
# 确认已安装
|
||||
hermes skills list | grep arxiv
|
||||
|
||||
# 或在聊天中
|
||||
/skills search arxiv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 插件提供的 Skills
|
||||
|
||||
插件可以使用命名空间名称(`plugin:skill`)捆绑自己的 skills,以避免与内置 skills 发生名称冲突。
|
||||
|
||||
```bash
|
||||
# 通过限定名称加载插件 skill
|
||||
skill_view("superpowers:writing-plans")
|
||||
|
||||
# 同名的内置 skill 不受影响
|
||||
skill_view("writing-plans")
|
||||
```
|
||||
|
||||
插件 skills **不会**列在系统 prompt 中,也不出现在 `skills_list` 中。它们是按需加载的——当你知道某个插件提供了某个 skill 时,显式加载它。加载后,agent 会看到一个横幅,列出同一插件的其他 skills。
|
||||
|
||||
关于如何在自己的插件中捆绑 skills,请参见 [构建 Hermes 插件 → 捆绑 skills](/guides/build-a-hermes-plugin#bundle-skills)。
|
||||
|
||||
---
|
||||
|
||||
## 配置 Skill 设置
|
||||
|
||||
部分 skills 在 frontmatter 中声明了所需的配置:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
hermes:
|
||||
config:
|
||||
- key: tenor.api_key
|
||||
description: "Tenor API key for GIF search"
|
||||
prompt: "Enter your Tenor API key"
|
||||
url: "https://developers.google.com/tenor/guides/quickstart"
|
||||
```
|
||||
|
||||
当带有配置的 skill 首次加载时,Hermes 会提示你输入相应值,并将其存储在 `config.yaml` 的 `skills.config.*` 下。
|
||||
|
||||
通过 CLI 管理 skill 配置:
|
||||
|
||||
```bash
|
||||
# 对特定 skill 进行交互式配置
|
||||
hermes skills config gif-search
|
||||
|
||||
# 查看所有 skill 配置
|
||||
hermes config get skills.config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 创建自己的 Skill
|
||||
|
||||
Skills 只是带有 YAML frontmatter 的 Markdown 文件,创建一个不超过五分钟。
|
||||
|
||||
### 1. 创建目录
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.hermes/skills/my-category/my-skill
|
||||
```
|
||||
|
||||
### 2. 编写 SKILL.md
|
||||
|
||||
```markdown title="~/.hermes/skills/my-category/my-skill/SKILL.md"
|
||||
---
|
||||
name: my-skill
|
||||
description: Brief description of what this skill does
|
||||
version: 1.0.0
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [my-tag, automation]
|
||||
category: my-category
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
## When to Use
|
||||
Use this skill when the user asks about [specific topic] or needs to [specific task].
|
||||
|
||||
## Procedure
|
||||
1. First, check if [prerequisite] is available
|
||||
2. Run `command --with-flags`
|
||||
3. Parse the output and present results
|
||||
|
||||
## Pitfalls
|
||||
- Common failure: [description]. Fix: [solution]
|
||||
- Watch out for [edge case]
|
||||
|
||||
## Verification
|
||||
Run `check-command` to confirm the result is correct.
|
||||
```
|
||||
|
||||
### 3. 添加参考文件(可选)
|
||||
|
||||
Skills 可以包含 agent 按需加载的辅助文件:
|
||||
|
||||
```
|
||||
my-skill/
|
||||
├── SKILL.md # 主 skill 文档
|
||||
├── references/
|
||||
│ ├── api-docs.md # agent 可查阅的 API 参考
|
||||
│ └── examples.md # 示例输入/输出
|
||||
├── templates/
|
||||
│ └── config.yaml # agent 可使用的模板文件
|
||||
└── scripts/
|
||||
└── setup.sh # agent 可执行的脚本
|
||||
```
|
||||
|
||||
在 SKILL.md 中引用这些文件:
|
||||
|
||||
```markdown
|
||||
For API details, load the reference: `skill_view("my-skill", "references/api-docs.md")`
|
||||
```
|
||||
|
||||
### 4. 测试
|
||||
|
||||
开启新会话并测试你的 skill:
|
||||
|
||||
```bash
|
||||
hermes chat -q "/my-skill help me with the thing"
|
||||
```
|
||||
|
||||
Skill 会自动出现——无需注册。放入 `~/.hermes/skills/` 即可立即生效。
|
||||
|
||||
:::info
|
||||
Agent 也可以使用 `skill_manage` 自行创建和更新 skills。解决复杂问题后,Hermes 可能会主动提议将该方法保存为 skill,以便下次使用。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 按平台管理 Skills
|
||||
|
||||
控制哪些 skills 在哪些平台上可用:
|
||||
|
||||
```bash
|
||||
hermes skills
|
||||
```
|
||||
|
||||
这会打开一个交互式 TUI,你可以按平台(CLI、Telegram、Discord 等)启用或禁用 skills。当你希望某些 skills 仅在特定场景下可用时非常有用——例如,在 Telegram 上禁用开发类 skills。
|
||||
|
||||
---
|
||||
|
||||
## Skills 与 Memory 的区别
|
||||
|
||||
两者都跨会话持久化,但用途不同:
|
||||
|
||||
| | Skills | Memory |
|
||||
|---|---|---|
|
||||
| **内容** | 程序性知识——如何做事 | 事实性知识——事物是什么 |
|
||||
| **时机** | 按需加载,仅在相关时加载 | 自动注入每个会话 |
|
||||
| **大小** | 可以较大(数百行) | 应保持紧凑(仅关键事实) |
|
||||
| **开销** | 加载前零 tokens | 少量但持续的 token 开销 |
|
||||
| **示例** | "如何部署到 Kubernetes" | "用户偏好深色模式,位于 PST 时区" |
|
||||
| **创建者** | 你、agent 或从 Hub 安装 | Agent,基于对话内容 |
|
||||
|
||||
**经验法则:** 如果你会把它写进参考文档,它就是 skill;如果你会把它写在便利贴上,它就是 memory。
|
||||
|
||||
---
|
||||
|
||||
## 使用技巧
|
||||
|
||||
**保持 skills 聚焦。** 试图涵盖"所有 DevOps"的 skill 会过于冗长且模糊。专注于"将 Python 应用部署到 Fly.io"的 skill 才足够具体,真正有用。
|
||||
|
||||
**让 agent 创建 skills。** 完成复杂的多步骤任务后,Hermes 通常会主动提议将该方法保存为 skill。接受它——这些由 agent 编写的 skills 会捕捉到完整的工作流程,包括过程中发现的各种坑。
|
||||
|
||||
**使用分类目录。** 将 skills 整理到子目录中(`~/.hermes/skills/devops/`、`~/.hermes/skills/research/` 等),保持列表整洁,并帮助 agent 更快找到相关 skills。
|
||||
|
||||
**及时更新过时的 skills。** 如果使用某个 skill 时遇到它未覆盖的问题,告诉 Hermes 用你学到的内容更新该 skill。不维护的 skills 会成为负担。
|
||||
|
||||
---
|
||||
|
||||
*完整的 skills 参考——frontmatter 字段、条件激活、外部目录等——请见 [Skills 系统](/user-guide/features/skills)。*
|
||||
@@ -0,0 +1,270 @@
|
||||
---
|
||||
sidebar_position: 16
|
||||
title: "xAI Grok OAuth(SuperGrok / X Premium+)"
|
||||
description: "使用 SuperGrok 或 X Premium+ 订阅登录,在 Hermes Agent 中使用 Grok 模型——无需 API 密钥"
|
||||
---
|
||||
|
||||
# xAI Grok OAuth(SuperGrok / X Premium+)
|
||||
|
||||
Hermes Agent 通过基于浏览器的 OAuth 登录流程支持 xAI Grok,认证服务器为 [accounts.x.ai](https://accounts.x.ai),支持 **SuperGrok 订阅**([grok.com](https://x.ai/grok))或 **X Premium+ 订阅**(已关联的 X 账号)。无需 `XAI_API_KEY`——登录一次后,Hermes 会在后台自动刷新会话。
|
||||
|
||||
当你使用拥有 Premium+ 的 X 账号登录时,xAI 会自动将订阅状态关联到你的 xAI 会话,因此 OAuth 流程与直接 SuperGrok 订阅者的体验完全相同。
|
||||
|
||||
该传输层复用 `codex_responses` 适配器(xAI 暴露了 Responses 风格的端点),因此推理、工具调用、流式传输和 prompt(提示词)缓存无需任何适配器改动即可正常工作。
|
||||
|
||||
同一 OAuth bearer token 也会被 Hermes 中所有直连 xAI 的功能复用——TTS、图像生成、视频生成和转录——因此单次登录即可覆盖全部四项功能。
|
||||
|
||||
## 概览
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-------|
|
||||
| Provider ID | `xai-oauth` |
|
||||
| 显示名称 | xAI Grok OAuth (SuperGrok / X Premium+) |
|
||||
| 认证类型 | 浏览器 OAuth 2.0 PKCE(回环回调) |
|
||||
| 传输层 | xAI Responses API(`codex_responses`) |
|
||||
| 默认模型 | `grok-4.3` |
|
||||
| 端点 | `https://api.x.ai/v1` |
|
||||
| 认证服务器 | `https://accounts.x.ai` |
|
||||
| 需要环境变量 | 否(此 provider 不使用 `XAI_API_KEY`) |
|
||||
| 订阅要求 | [SuperGrok](https://x.ai/grok) 或 [X Premium+](https://x.com/i/premium_sign_up)——见下方说明 |
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Python 3.9+
|
||||
- 已安装 Hermes Agent
|
||||
- 你的 xAI 账号拥有有效的 **SuperGrok** 订阅,**或**你登录所用的 X 账号拥有 **X Premium+** 订阅(xAI 会自动关联订阅)
|
||||
- 本地机器上有可用的浏览器(远程会话可使用 `--no-browser`)
|
||||
|
||||
:::warning xAI 可能按套餐限制 OAuth API 访问
|
||||
xAI 的后端对 OAuth API 接口维护自己的白名单,已有记录显示即使应用内订阅处于激活状态,标准 SuperGrok 订阅者也会收到 `HTTP 403`(见 issue [#26847](https://github.com/NousResearch/hermes-agent/issues/26847))。如果浏览器中 OAuth 登录成功但推理返回 403,请设置 `XAI_API_KEY` 并切换到 API 密钥路径(`provider: xai`)——该接口目前不受相同限制。
|
||||
:::
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 启动 provider 和模型选择器
|
||||
hermes model
|
||||
# → 从 provider 列表中选择 "xAI Grok OAuth (SuperGrok / X Premium+)"
|
||||
# → Hermes 在浏览器中打开 accounts.x.ai
|
||||
# → 在浏览器中批准访问
|
||||
# → 选择模型(grok-4.3 在列表顶部)
|
||||
# → 开始对话
|
||||
|
||||
hermes
|
||||
```
|
||||
|
||||
首次登录后,凭据存储在 `~/.hermes/auth.json` 中,并在过期前自动刷新。
|
||||
|
||||
## 手动登录
|
||||
|
||||
你可以不经过模型选择器直接触发登录:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth
|
||||
```
|
||||
|
||||
### 远程 / 无头会话
|
||||
|
||||
在没有浏览器的服务器、容器或 SSH 会话中,Hermes 会检测到远程环境并打印授权 URL,而不是打开浏览器。
|
||||
|
||||
**重要:** 回环监听器仍在远程机器的 `127.0.0.1:56121` 上运行。xAI 的重定向需要到达*该*监听器,因此在你的笔记本上打开 URL 会失败(`Could not establish connection. We couldn't reach your app.`),除非你转发端口:
|
||||
|
||||
```bash
|
||||
# 在本地机器的另一个终端中:
|
||||
ssh -N -L 56121:127.0.0.1:56121 user@remote-host
|
||||
|
||||
# 然后在远程机器的 SSH 会话中:
|
||||
hermes auth add xai-oauth --no-browser
|
||||
# 在本地浏览器中打开打印出的授权 URL。
|
||||
```
|
||||
|
||||
通过跳板机 / 堡垒机:添加 `-J jump-user@jump-host`。
|
||||
|
||||
完整步骤(包括 ProxyJump 链、mosh/tmux 和 ControlMaster 注意事项)请参阅 [OAuth over SSH / Remote Hosts](./oauth-over-ssh.md)。
|
||||
|
||||
### 仅限浏览器的远程环境(Cloud Shell、Codespaces、EC2 Instance Connect)
|
||||
|
||||
如果你没有常规 SSH 客户端(例如在 GCP Cloud Shell、GitHub Codespaces、AWS EC2 Instance Connect、Gitpod 或其他基于浏览器的控制台中运行 Hermes),上述 `ssh -L` 方案不可用。请改用 `--manual-paste`——Hermes 跳过回环监听器,让你直接从浏览器粘贴失败的回调 URL:
|
||||
|
||||
```bash
|
||||
hermes auth add xai-oauth --manual-paste
|
||||
# 或通过模型选择器:
|
||||
hermes model --manual-paste
|
||||
```
|
||||
|
||||
完整操作说明请参阅 [OAuth over SSH / Remote Hosts](./oauth-over-ssh.md#browser-only-remote-cloud-shell--codespaces--ec2-instance-connect)。此为 [#26923](https://github.com/NousResearch/hermes-agent/issues/26923) 的回归修复。
|
||||
|
||||
## 登录流程说明
|
||||
|
||||
1. Hermes 在浏览器中打开 `accounts.x.ai`。
|
||||
2. 你登录(或确认现有会话)并批准访问。
|
||||
3. xAI 重定向回 Hermes,token 保存到 `~/.hermes/auth.json`。
|
||||
4. 此后,Hermes 在后台刷新 access token——你将保持登录状态,直到执行 `hermes auth remove xai-oauth` 或在 xAI 账号设置中撤销访问。
|
||||
|
||||
## 检查登录状态
|
||||
|
||||
```bash
|
||||
hermes doctor
|
||||
```
|
||||
|
||||
`◆ Auth Providers` 部分将显示每个 provider 的当前状态,包括 `xai-oauth`。
|
||||
|
||||
## 切换模型
|
||||
|
||||
```bash
|
||||
hermes model
|
||||
# → 选择 "xAI Grok OAuth (SuperGrok / X Premium+)"
|
||||
# → 从模型列表中选择(grok-4.3 固定在顶部)
|
||||
```
|
||||
|
||||
或直接设置模型:
|
||||
|
||||
```bash
|
||||
hermes config set model.default grok-4.3
|
||||
hermes config set model.provider xai-oauth
|
||||
```
|
||||
|
||||
## 配置参考
|
||||
|
||||
登录后,`~/.hermes/config.yaml` 将包含:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
default: grok-4.3
|
||||
provider: xai-oauth
|
||||
base_url: https://api.x.ai/v1
|
||||
```
|
||||
|
||||
### Provider 别名
|
||||
|
||||
以下所有别名均解析为 `xai-oauth`:
|
||||
|
||||
```bash
|
||||
hermes --provider xai-oauth # 规范名称
|
||||
hermes --provider grok-oauth # 别名
|
||||
hermes --provider x-ai-oauth # 别名
|
||||
hermes --provider xai-grok-oauth # 别名
|
||||
```
|
||||
|
||||
## 直连 xAI 工具(TTS / 图像 / 视频 / 转录 / X 搜索)
|
||||
|
||||
通过 OAuth 登录后,每个直连 xAI 的工具都会自动复用同一 bearer token——**无需单独配置**,除非你更倾向于使用 API 密钥。
|
||||
|
||||
为每个工具选择后端:
|
||||
|
||||
```bash
|
||||
hermes tools
|
||||
# → Text-to-Speech → "xAI TTS"
|
||||
# → Image Generation → "xAI Grok Imagine (image)"
|
||||
# → Video Generation → "xAI Grok Imagine"
|
||||
# → X (Twitter) Search → "xAI Grok OAuth (SuperGrok / X Premium+)"
|
||||
```
|
||||
|
||||
如果 OAuth token 已存储,选择器会确认并跳过凭据提示。如果既没有 OAuth 也没有设置 `XAI_API_KEY`,选择器会提供三选一菜单:OAuth 登录、粘贴 API 密钥或跳过。
|
||||
|
||||
:::note 视频生成默认关闭
|
||||
`video_gen` 工具集默认禁用。在 `hermes tools` → `🎬 Video Generation`(按空格键)中启用后,agent 才能调用 `video_generate`。否则 agent 可能回退到内置的 ComfyUI 技能,该技能同样标记为视频生成。
|
||||
:::
|
||||
|
||||
:::note 配置 xAI 凭据后 X 搜索自动启用
|
||||
只要配置了 xAI 凭据(SuperGrok / X Premium+ OAuth token 或 `XAI_API_KEY`),`x_search` 工具集就会自动启用。如不需要,请通过 `hermes tools` → `🐦 X (Twitter) Search`(按空格键)显式禁用。该工具通过 xAI 内置的 `x_search` Responses API 路由——支持 **SuperGrok / X Premium+ OAuth 登录**或付费 `XAI_API_KEY`,两者同时配置时优先使用 OAuth(消耗订阅配额而非 API 费用)。未配置任何 xAI 凭据时,无论工具集是否启用,工具 schema 都对模型隐藏。
|
||||
:::
|
||||
|
||||
### 模型
|
||||
|
||||
| 工具 | 模型 | 说明 |
|
||||
|------|-------|-------|
|
||||
| 对话 | `grok-4.3` | 默认;通过 OAuth 登录时自动选择 |
|
||||
| 对话 | `grok-4.20-0309-reasoning` | 推理变体 |
|
||||
| 对话 | `grok-4.20-0309-non-reasoning` | 非推理变体 |
|
||||
| 对话 | `grok-4.20-multi-agent-0309` | 多 agent 变体 |
|
||||
| 图像 | `grok-imagine-image` | 默认;约 5–10 秒 |
|
||||
| 图像 | `grok-imagine-image-quality` | 更高保真度;约 10–20 秒 |
|
||||
| 视频 | `grok-imagine-video` | 文本转视频 |
|
||||
| 视频 | `grok-imagine-video-1.5-preview` | 图像转视频;日期别名 `grok-imagine-video-1.5-2026-05-30` |
|
||||
| TTS | (默认音色) | xAI `/v1/tts` 端点 |
|
||||
|
||||
对话模型目录从磁盘上的 `models.dev` 缓存实时获取;缓存刷新后,新的 xAI 模型会自动出现。`grok-4.3` 始终固定在列表顶部。
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量 | 作用 |
|
||||
|----------|--------|
|
||||
| `XAI_BASE_URL` | 覆盖默认的 `https://api.x.ai/v1` 端点(极少需要)。 |
|
||||
|
||||
要将 xAI 设为活跃 provider,请在 `config.yaml` 中设置 `model.provider: xai-oauth`(使用 `hermes setup` 进行引导配置),或在单次调用时传入 `--provider xai-oauth`。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### Token 过期——未自动重新登录
|
||||
|
||||
Hermes 在每次会话前刷新 token,并在收到 401 时响应式地再次刷新。如果刷新因 `invalid_grant` 失败(刷新 token 被撤销或账号已轮换),Hermes 会显示类型化的重新认证消息,而不是崩溃。
|
||||
|
||||
当刷新失败是终态时(HTTP 4xx、`invalid_grant`、授权被撤销等),Hermes 将刷新 token 标记为失效并在本地隔离——后续调用跳过注定失败的刷新尝试,而不是反复重放同一个 401。agent 显示一条"需要重新认证"消息,并在你再次登录前保持等待。
|
||||
|
||||
**修复方法:** 再次运行 `hermes auth add xai-oauth` 开始全新登录。下次成功交换后隔离状态自动清除。
|
||||
|
||||
### 授权超时
|
||||
|
||||
回环监听器有有限的过期窗口(默认 180 秒)。如果你未在时限内批准登录,Hermes 会抛出超时错误。
|
||||
|
||||
**修复方法:** 重新运行 `hermes auth add xai-oauth`(或 `hermes model`)。流程重新开始。
|
||||
|
||||
### State 不匹配(可能的 CSRF)
|
||||
|
||||
Hermes 检测到授权服务器返回的 `state` 值与发送的不匹配。
|
||||
|
||||
**修复方法:** 重新运行登录。如果问题持续,检查是否有代理或重定向在修改 OAuth 响应。
|
||||
|
||||
### 从远程服务器登录
|
||||
|
||||
在 SSH 或容器会话中,Hermes 打印授权 URL 而不是打开浏览器。回环回调监听器仍绑定在远程主机的 `127.0.0.1:56121`——你笔记本上的浏览器无法访问它,除非进行 SSH 本地端口转发:
|
||||
|
||||
```bash
|
||||
# 本地机器,另一个终端:
|
||||
ssh -N -L 56121:127.0.0.1:56121 user@remote-host
|
||||
|
||||
# 远程机器:
|
||||
hermes auth add xai-oauth --no-browser
|
||||
```
|
||||
|
||||
完整操作说明(跳板机、mosh/tmux、端口冲突):[OAuth over SSH / Remote Hosts](./oauth-over-ssh.md)。
|
||||
|
||||
### 登录成功后 HTTP 403(套餐 / 权限问题)
|
||||
|
||||
浏览器中 OAuth 完成,token 已保存,但推理或 token 刷新返回 `HTTP 403`,消息类似于 *"The caller does not have permission to execute the specified operation"*。
|
||||
|
||||
这**不是** token 过期问题——重新运行 `hermes model` 不会改变结果。xAI 的后端已被观察到将 OAuth API 访问限制在特定 SuperGrok 套餐,即使应用内订阅处于激活状态(issue [#26847](https://github.com/NousResearch/hermes-agent/issues/26847))。
|
||||
|
||||
**修复方法:** 设置 `XAI_API_KEY` 并切换到 API 密钥路径:
|
||||
|
||||
```bash
|
||||
export XAI_API_KEY=xai-...
|
||||
hermes config set model.provider xai
|
||||
```
|
||||
|
||||
或在 [x.ai/grok](https://x.ai/grok) 升级订阅(如果必须使用 OAuth 路径)。
|
||||
|
||||
### 运行时出现"No xAI credentials found"错误
|
||||
|
||||
auth 存储中没有 `xai-oauth` 条目,也未设置 `XAI_API_KEY`。你尚未登录,或凭据文件已被删除。
|
||||
|
||||
**修复方法:** 运行 `hermes model` 并选择 xAI Grok OAuth provider,或运行 `hermes auth add xai-oauth`。
|
||||
|
||||
## 退出登录
|
||||
|
||||
删除所有已存储的 xAI Grok OAuth 凭据:
|
||||
|
||||
```bash
|
||||
hermes auth logout xai-oauth
|
||||
```
|
||||
|
||||
这会清除 `auth.json` 中的单例 OAuth 条目以及 `xai-oauth` 的所有凭据池行。如果只想删除单个池条目,请使用 `hermes auth remove xai-oauth <index|id|label>`(运行 `hermes auth list xai-oauth` 查看列表)。
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [OAuth over SSH / Remote Hosts](./oauth-over-ssh.md) — 如果 Hermes 与浏览器不在同一台机器上,必读
|
||||
- [AI Providers 参考](../integrations/providers.md)
|
||||
- [环境变量](../reference/environment-variables.md)
|
||||
- [配置](../user-guide/configuration.md)
|
||||
- [语音与 TTS](../user-guide/features/tts.md)
|
||||
Reference in New Issue
Block a user