亚马逊AWS官方博客
用 Hermes Agent 在 AWS 上搭建投研助手
摘要:本文完整记录了在 AWS EC2(Amazon Linux)上安装 Hermes Agent,通过 LiteLLM 代理 Amazon Bedrock 模型、连接飞书,并配置多市场金融数据源(A 股、美股、港股、外汇)和投研 Skill 的全过程。Hermes Agent 在本文写作时的版本(v0.8.0)尚未原生支持 Bedrock,本文通过 LiteLLM 代理提供了一个实际验证过的接入方案。所有数据源均基于开源免费接口,可直接复现。
目录
一、第一部分:AWS 部署与消息平台集成
1. Hermes Agent 简介
Hermes Agent 是 Nous Research 开发的开源自托管 AI Agent 平台,运行在用户自有服务器上,支持飞书、Telegram、Slack 等多种消息平台交互,具备跨会话记忆、定时任务和丰富的内置工具等能力。本文重点解决的问题是:Hermes Agent v0.8.0 尚未原生支持 Bedrock,需要通过 LiteLLM 代理接入。
2. 环境准备
2.1 运行环境
- EC2 实例:Amazon Linux 2023(ARM / x86 均可)
- IAM Role:需要 Bedrock 调用权限
- 前置条件:Git 已安装(安装器会自动处理 Python、Node.js 等其他依赖)
EC2 的 IAM Role 需要有 Bedrock 模型调用权限。基础权限策略示例:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BedrockInvoke",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:*::foundation-model/*"
}
]
}
生产环境建议将 Resource 收窄到实际使用的模型 ARN,例如 arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-sonnet-4-6。
3. 安装 LiteLLM 代理 Bedrock
Hermes Agent v0.8.0 尚未支持原生 Bedrock 调用。如需使用 Claude 等 Bedrock 上的模型,需要通过 LiteLLM 搭建一层 OpenAI 兼容的代理。AWS 已经提供了生产级的 LiteLLM 部署方案——Guidance for Multi-Provider Generative AI Gateway on AWS,基于 ECS/EKS,包含 WAF、监控和多租户支持。本文以快速验证为目的,采用最简单的本地部署方式,不建议直接用于生产环境。
3.1 安装并配置pip3 install 'litellm[proxy,bedrock]'
创建 litellm_config.yaml:
model_list:
- model_name: claude-sonnet-4-6
litellm_params:
model: bedrock/global.anthropic.claude-sonnet-4-6
aws_region_name: us-west-2
3.2 启动并验证
nohup litellm --config litellm_config.yaml --port 4000 > litellm.log 2>&1 &
验证:
curl http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [{"role": "user", "content": "你好"}],
"max_tokens": 100
}'
收到正常的 JSON 响应即表示代理运行正常。
生产环境建议直接使用上述Guidance for Multi-Provider Generative AI Gateway on AWS 官方方案。
4. 安装与配置 Hermes Agent
4.1 一键安装
# 确保 git 已安装
sudo dnf install -y git
# 一键安装
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
安装过程大约需要 10 分钟,安装器会自动处理 Python、Node.js、ripgrep、ffmpeg 等所有依赖。
[图1:安装过程] |
安装完成后,重新加载 shell:
source ~/.bashrc
4.2 配置模型(关键步骤)
安装完成后运行 hermes setup,会进入初始化向导,主要需要配置模型和消息平台。消息平台(飞书、Telegram 等)的接入配置请参考 Hermes Agent 官方文档,本文不再赘述。
由于 Hermes Agent v0.8.0 尚未原生支持 Bedrock,在模型配置环节选择 Custom Endpoint,填入 LiteLLM 的地址:
[图2:模型配置——选择 Custom Endpoint] |
- Base URL:
http://localhost:4000/v1 - Model:
claude-sonnet-4-6 - API Key:如未在 LiteLLM 中设置 API Key,可留空
也可以通过命令行直接配置:
hermes model
4.3 验证安装
hermes doctor # 诊断检查
hermes status # 查看配置状态
Hermes Agent 和 OpenClaw 可以共存部署在同一台 EC2 上。若已部署 OpenClaw,hermes claw migrate 可一键导入已有的记忆、Skill 和配置(建议先用 --dry-run 预览)。
二、第二部分:FSI 数据源接入与投研 Skill 配置
5. 整体架构
hermes doctor 检查通过,消息平台收发正常。
6. 开源金融数据源总览
本文所有数据源均基于开源库或免费接口,无需 API Key 即可用于技术验证(部分有频率限制)。商业使用前请确认各数据源的许可协议和服务条款。
| 数据源 | 覆盖市场 | Python 包 | 特点 |
| AKShare | A 股、港股、期货、外汇、宏观 | akshare | 国内全面的开源金融数据接口 |
| yfinance | 美股、全球主要市场 | yfinance | Yahoo Finance 非官方接口,全球覆盖,商业使用需评估 ToS |
| exchangerate-api | 全球外汇 | requests | 免费汇率 API,每日更新 |
| pandas-datareader | 美股、宏观经济 | pandas-datareader | FRED、World Bank 等宏观数据 |
pip3 install akshare yfinance pandas-datareader PyMuPDF requests
7. 数据源接入与 API 速查
7.1 A 股(AKShare)
pip3 install akshare
import akshare as ak
# 验证:获取 A 股实时行情
df = ak.stock_zh_a_spot_em()
print(df[['代码', '名称', '最新价', '涨跌幅', '成交额']].head(5))
# 个股历史 K 线
df_hist = ak.stock_zh_a_hist(symbol="000001", period="daily", start_date="20260101", end_date="20260414", adjust="qfq")
# 财务报表
df_balance = ak.stock_financial_abstract_ths(symbol="000001", indicator="按年度")
# 北向资金(沪股通+深股通)
df_north = ak.stock_hsgt_north_net_flow_in_em(symbol="北上")
# 板块行情(行业/概念)
df_sector = ak.stock_board_industry_name_em()
# 指数行情
df_index = ak.stock_zh_index_daily_em(symbol="sh000001") # 上证指数
7.2 其他市场
| 市场 | Python 包 | 关键调用示例 |
| 美股 | yfinance | yf.Ticker(“AAPL”).info — 实时报价、市值、PE、EPS |
| 美股 | yfinance | yf.Ticker(“AAPL”).history(period=”3mo”) — K 线 |
| 美股 | yfinance | yf.Ticker(“AAPL”).income_stmt — 财务报表 |
| 美股 | yfinance | yf.Ticker(“^VIX”).history(period=”2d”) — VIX 恐慌指数 |
| 港股 | akshare | ak.stock_hk_spot_em() — 港股实时行情 |
| 港股 | akshare | ak.stock_hk_hist(symbol=”00700″, period=”daily”, …) — K 线 |
| 港股 | yfinance | yf.Ticker(“0700.HK”).info — 港股代码格式:数字.HK |
| 外汇 | akshare | ak.currency_boc_sina(symbol=”美元”, …) — 中国银行牌价 |
| 外汇 | requests | requests.get(“https://open.er-api.com/v6/latest/USD”) — 免费全球汇率 |
| 外汇 | yfinance | yf.Ticker(“USDCNY=X”).history(period=”1d”) — 实时汇率 |
8. 投研 Skill 配置
Hermes Agent 的 Skill 采用 agentskills.io 定义的 SKILL.md 格式。所有技能位于 ~/.hermes/skills/ 目录下,每个 Skill 是一个包含 SKILL.md(主文件)和可选 scripts/(辅助脚本)的目录。
技能采用渐进披露模式加载:Agent 先看到技能列表(Level 0),需要时才加载完整内容(Level 1),有效节省 token。
前置条件:Python 虚拟环境已创建并安装依赖:
python3 -m venv ~/myenv
source ~/myenv/bin/activate
pip3 install akshare yfinance pandas-datareader PyMuPDF requests
后续所有 Skill 脚本通过 ~/myenv/bin/python3 调用,无需 activate。
这是核心 Skill,聚合 A 股、美股、港股、外汇,一条命令查询全球市场。
目录结构:
8.1.1 SKILL.md
---
name: global-market
description: 全球金融市场速查,支持 A 股、美股、港股、外汇,自动识别市场并路由到对应数据源
version: 1.0.0
platforms: [linux]
metadata:
hermes:
tags: [finance, market-data, fsi]
category: fsi
requires_toolsets: [terminal]
---
# 全球市场速查## When to Use- 用户查询任何股票、货币的行情
- 用户说"查一下 XXX"、"XXX 行情"、"XXX 最新价"
- 用户说"全球市场"查看概览
## Procedure1. 接收用户查询关键词
2. 执行脚本自动识别市场类型(A 股/美股/港股/外汇)并返回行情:
```bash
~/myenv/bin/python3 ~/.hermes/skills/fsi/global-market/scripts/run.py "用户查询内容"
```3. 将结果格式化后返回给用户
## Pitfalls- AKShare 接口在非交易时间可能返回上一交易日数据
- yfinance 偶尔被 Yahoo 限流,重试即可
- 港股代码需 5 位数字(如 00700),美股代码为 1-5 位英文字母
## Verification
脚本返回包含价格、涨跌幅等信息的格式化文本,无报错即成功。
8.1.2 scripts/run.py
#!/usr/bin/env python3"""全球市场速查 Skill — 自动识别市场并路由到对应数据源"""import sys
import re
def detect_market(query):
"""根据输入自动判断市场类型"""
q = query.upper().strip()
# 外汇
fx_keywords = ['汇率', '美元', '欧元', '日元', '英镑', '比索', '印尼盾', '新加坡元', '澳元', '加元', '港币']
for kw in fx_keywords:
if kw in query:
return 'fx', query
if re.match(r'^[A-Z]{6}$', q): # USDCNY 格式return 'fx', q
# 港股if q.endswith('.HK') or q.startswith('0') and len(q) == 5:
return 'hk', q.replace('.HK', '')
# 美股(纯英文字母,2-5 位)if re.match(r'^[A-Z]{1,5}$', q) and q not in ['SH', 'SZ', 'HK']:
return 'us', q
# A 股(默认)return 'a', query
def query_a_stock(query):
import akshare as ak
df = ak.stock_zh_a_spot_em()
match = df[df['名称'].str.contains(query) | df['代码'].str.contains(query)]
if match.empty:
return f"A 股未找到「{query}」"
row = match.iloc[0]
lines = [
f" {row['名称']}({row['代码']})",
f"最新价: ¥{row['最新价']} 涨跌幅: {row['涨跌幅']}%",
f"成交额: {float(row['成交额'])/1e8:.2f}亿 换手率: {row['换手率']}%",
f"PE: {row.get('市盈率-动态', 'N/A')} PB: {row.get('市净率', 'N/A')}",
]
return "\n".join(lines)
def query_us_stock(symbol):
import yfinance as yf
ticker = yf.Ticker(symbol)
info = ticker.info
if 'currentPrice' not in info:
return f"美股未找到「{symbol}」"
lines = [
f" {info.get('shortName', symbol)}({symbol})",
f"最新价: ${info['currentPrice']} 市值: ${info.get('marketCap', 0)/1e9:.1f}B",
f"PE: {info.get('trailingPE', 'N/A')} EPS: ${info.get('trailingEps', 'N/A')}",
f"52周范围: ${info.get('fiftyTwoWeekLow', 'N/A')} - ${info.get('fiftyTwoWeekHigh', 'N/A')}",
]
return "\n".join(lines)
def query_hk_stock(code):
import akshare as ak
df = ak.stock_hk_spot_em()
match = df[df['代码'] == code]
if match.empty:
match = df[df['名称'].str.contains(code)]
if match.empty:
return f"港股未找到「{code}」"
row = match.iloc[0]
lines = [
f" {row['名称']}({row['代码']}.HK)",
f"最新价: HK${row['最新价']} 涨跌幅: {row['涨跌幅']}%",
]
return "\n".join(lines)
def query_fx(query):
import requests
resp = requests.get("https://open.er-api.com/v6/latest/USD", timeout=10)
data = resp.json()
currency_map = {
"美元": "CNY", "人民币": "CNY", "欧元": "EUR", "日元": "JPY",
"英镑": "GBP", "比索": "MXN", "墨西哥": "MXN",
"印尼盾": "IDR", "印尼": "IDR", "菲律宾": "PHP",
"新加坡": "SGD", "澳元": "AUD", "加元": "CAD",
"港币": "HKD", "新台币": "TWD",
}
target = Nonefor kw, code in currency_map.items():
if kw in query:
target = code
breakif target:
rate = data['rates'].get(target, 'N/A')
cny_rate = data['rates'].get('CNY', 1)
lines = [f" 1 USD = {rate} {target}", f" 1 USD = {cny_rate} CNY"]
return "\n".join(lines)
# 显示所有出海相关汇率
pairs = {"CNY": "人民币", "MXN": "墨西哥比索", "IDR": "印尼盾",
"PHP": "菲律宾比索", "SGD": "新加坡元", "HKD": "港币"}
lines = [" 出海汇率速查(基准: 1 USD)"]
for code, name in pairs.items():
lines.append(f" {name}({code}): {data['rates'].get(code, 'N/A')}")
return "\n".join(lines)
def main(query):
market, parsed = detect_market(query)
handlers = {
'a': query_a_stock,
'us': query_us_stock,
'hk': query_hk_stock,
'fx': query_fx,
}
return handlers[market](parsed)
if __name__ == "__main__":
query = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "全球市场"print(main(query))
[图3:全球市场速查] |
目录结构:
8.2.1 SKILL.md
---
name: quant-monitor
description: 量化市场因子监控——A 股涨跌统计、北向资金、VIX、美股指数,一键获取市场情绪快照
version: 1.0.0
platforms: [linux]
metadata:
hermes:
tags: [finance, quant, monitoring, fsi]
category: fsi
requires_toolsets: [terminal]
---
# 量化因子监控## When to Use- 用户说"市场因子"、"北向资金"、"量化日报"、"市场情绪"
- 每日开盘前/收盘后获取市场全景快照
- 配合定时任务(cron)自动推送到飞书
## Procedure1. 执行量化因子快照脚本:
```bash
~/myenv/bin/python3 ~/.hermes/skills/fsi/quant-monitor/scripts/run.py
```2. 脚本自动采集以下因子并汇总:
- A 股涨跌家数、涨停/跌停数
- 北向资金净流入
- VIX 恐慌指数(<20 / <30 / ≥30)
- S&P 500、NASDAQ 指数涨跌
3. 将快照结果返回给用户
## Pitfalls- A 股数据仅交易时间实时,非交易时间为上一交易日收盘数据
- 北向资金接口偶尔延迟,可能返回前一日数据
- 各数据源独立 try/except,单个失败不影响整体输出
## Verification
脚本输出包含时间戳和至少 3 个市场板块的因子数据
8.2.2 scripts/run.py
#!/usr/bin/env python3"""量化因子监控 Skill — A 股 + 美股联动"""import akshare as ak
import yfinance as yf
from datetime import datetime
def get_quant_snapshot():
result = [f" 量化因子快照 — {datetime.now().strftime('%Y-%m-%d %H:%M')}"]
result.append("=" * 40)
# A 股指数try:
df = ak.stock_zh_a_spot_em()
up = len(df[df['涨跌幅'] > 0])
down = len(df[df['涨跌幅'] < 0])
limit_up = len(df[df['涨跌幅'] >= 9.9])
limit_down = len(df[df['涨跌幅'] <= -9.9])
result.append(f"\n A 股")
result.append(f" 涨跌家数: {up}↑ / {down}↓ 涨停/跌停: {limit_up}/{limit_down}")
except Exception:
pass# 北向资金try:
df_n = ak.stock_hsgt_north_net_flow_in_em(symbol="北上")
if not df_n.empty:
latest = df_n.iloc[-1]
result.append(f" 北向净流入: {latest['当日净流入']:.2f}亿")
except Exception:
pass# 美股 VIXtry:
vix = yf.Ticker("^VIX")
hist = vix.history(period="2d")
if not hist.empty:
current = hist['Close'].iloc[-1]
prev = hist['Close'].iloc[-2] if len(hist) > 1 else current
change = (current - prev) / prev * 100
emoji = "LOW" if current < 20 else "MID" if current < 30 else "HIGH"
result.append(f"\n 美股")
result.append(f" {emoji} VIX: {current:.2f} ({change:+.1f}%)")
except Exception:
pass# 美股主要指数try:
for name, sym in [("S&P 500", "^GSPC"), ("NASDAQ", "^IXIC")]:
t = yf.Ticker(sym)
h = t.history(period="2d")
if len(h) >= 2:
chg = (h['Close'].iloc[-1] - h['Close'].iloc[-2]) / h['Close'].iloc[-2] * 100
result.append(f" {name}: {h['Close'].iloc[-1]:,.0f} ({chg:+.2f}%)")
except Exception:
passreturn "\n".join(result)
if __name__ == "__main__":
print(get_quant_snapshot())
8.3 从 Skills Hub 安装第三方技能
除了自己编写 Skill,Hermes 还支持直接安装社区或官方发布的技能。例如,安装一个新闻资讯类 Skill,配合前面的行情数据,就能让 Agent 自动分析股票涨跌背后的原因。
8.3.1 搜索与安装
# 搜索资讯/新闻相关技能
hermes skills search news
hermes skills search finance --source skills-sh
# 浏览官方可选技能
hermes skills browse --source official
# 安装(以某个资讯技能为例)
hermes skills install <source>/<skill-name>
# 查看已安装的技能
hermes skills list --source hub
8.3.2 组合使用示例
安装资讯类 Skill 后,就可以在对话中将多个 Skill 串联使用。
自建 Skill 负责拉行情数据,第三方 Skill 负责补资讯,Agent 把两边结果综合起来给出分析——不需要用户手动调度,Skill 之间的编排由 Agent 根据上下文自动判断。
[图4:交易建议] |
9. 安全与合规
建议在部署时参考以下安全措施:
| 安全措施 | 说明 |
| 飞书 WebSocket | 出站连接,无需开放入站端口 |
| Bedrock VPC Endpoint | 配置后模型调用走内网(需额外配置) |
| SSM Session Manager | 服务器管理走内网,无需 SSH |
| 用户白名单 | FEISHU_ALLOWED_USERS 限制授权用户 |
| IAM 最小权限 | 仅 bedrock:InvokeModel,生产环境建议收窄 Resource 到实际使用的模型 ARN |
| 非 root 运行 | 专用用户运行 Hermes Agent |
⚠️ 风险提示:本文仅为技术演示,不构成任何投资建议,据此操作风险自担。金融数据的商业使用需确认数据源许可协议。
三、结语
➡️ 下一步行动:
相关产品:
- Amazon Bedrock — 用于构建生成式人工智能应用程序和代理的端到端平台
- Amazon EC2 — 安全且可调整大小的计算容量
- Amazon IAM — 身份管理和访问权限
- Amazon VPC — 隔离云网络
- Amazon ECS — 完全托管的容器编排服务
相关文章:
- Guidance for Multi-Provider Generative AI Gateway on AWS
- OpenClaw 安全和功能增强实践
- 以Kiro快速部署云上Agent:只需几个小时,从业务需求到部署于Amazon Bedrock Agentcore落地
- 当 AI Agent 学会”忘记”:Amazon Bedrock AgentCore Memory 的记忆哲学”
- 使用Amazon Bedrock + 自建ECS Docker Sandbox实现Agent 程序化工具调用Programmatic Tool Calling
*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。
本篇作者
AWS 架构师中心:云端创新的引领者探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用 |
![]() |





