关于 route-researcher
route-researcher 是用于研究北美山峰并生成路线攻略报告的技能,面向登山计划制定者。它汇集登山网站、行程报告和天气等状况数据,整理路线与风险信息。
主要功能
- 01识别山峰并检索详情
- 02获取天气与雪崩状况
- 03汇总登山信息来源
- 04整理行程报告与风险
- 05生成路线攻略报告
适用场景
- 01攀登前研究指定山峰
- 02查看路线、风险和近期状况
- 03规划登山行程时间与安排
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dreamiurg/ claude-mountaineering-skills --skill route-researcher安装后在 Claude Code 中输入/route-researcher确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/report-template.mdtrip-report-template.mddocs/architecture.mdexamples/2025-10-23-mount-si.md2025-11-06-mount-adams.md2025-11-06-wolf-peak.md2026-01-29-mount-shuksan.md2026-01-29-tinkham-peak.mdtools/.python-versioncloudscrape.pyfetch_conditions.pypyproject.tomlREADME.mdtest_cloudscrape.pytest_fetch_conditions_unit.pytest_fetch_conditions.pytest_geodata_fetchers.pytest_phase4.pytest_phase5.pyuv.lock详细介绍
路线研究员
研究北美各地的山峰,并生成全面的路线攻略报告,整合来自多个来源的数据,包括 PeakBagger、SummitPost、WTA、AllTrails、天气预报、雪崩状况和行程报告。
数据来源: 此技能汇总了专业登山网站的信息(PeakBagger、SummitPost、Washington Trails Association、AllTrails、The Mountaineers 和区域雪崩中心)。生成报告的质量取决于这些来源所提供信息的完整程度。如果目标山峰在这些网站上的资料较少,报告可能只包含有限的详细信息。此技能最适用于北美资料丰富的山峰。
何时使用此技能
用户提出以下请求时,请使用此技能:
- 研究某座特定山峰
- 获取路线攻略或攀登信息
- 获取山峰行程规划信息
- 查询登山目标的当前状况
示例:
- “研究 Mt Baker”
- “我计划下个月攀登 Sahale Peak,你能研究一下路线吗?”
- “生成 Forbidden Peak 的路线攻略”
进度检查清单
研究进度:
- 阶段 1:山峰识别(已验证山峰,已获取 ID)
- 阶段 2:山峰信息检索(已获取坐标和详细信息)
- 阶段 3:数据收集(并行执行)
- 阶段 3a:通过 Python 获取状况(天气、空气质量、日照时长、雪崩、PeakBagger 统计数据/攀登记录)
- 阶段 3b:研究 Agent(3 个并行执行——网络来源和行程报告)
- 阶段 3c:汇总结果
- 阶段 3d:通行/许可证(内联 WebSearch)
- 阶段 4:路线分析(综合路线、关键难点和危险因素)
- 阶段 5:报告生成(报告撰写 Agent)
- 阶段 6:报告审查与验证(报告审查 Agent)
- 阶段 7:完成(通知用户并提供后续步骤)
编排工作流
第 1 阶段:山峰识别
目标: 确定并验证要研究的具体山峰。
-
从用户消息中提取山峰名称
- 查找山峰名称或攀登目标
- 常见示例:“Mt Baker”“Mount Rainier”“Sahale Peak”等
-
使用 peakbagger-cli 搜索 PeakBagger:
uvx --with patchright --from "git+https://github.com/dreamiurg/[email protected]" peakbagger peak search "{peak_name}" --format json- 解析 JSON 输出,提取匹配的山峰
- 每条结果包含:peak_id、名称、海拔(英尺/米)、位置、URL
-
处理多个匹配结果:
-
如果找到多个山峰:使用 AskUserQuestion 列出选项
- 对每个选项,显示:山峰名称、海拔、位置以及 PeakBagger URL
- 将每个选项的描述格式设为:“[山峰名称]([海拔],[位置])- [PeakBagger URL]”
- 这样用户可以点击链接并确认正确的山峰
- 让用户选择正确的山峰
- 如果都不匹配,提供“其他”选项
-
如果找到单个匹配结果:向用户确认
- 显示包含山峰详情和 PeakBagger 链接的确认消息
- 显示:“已找到:[山峰名称]([海拔],[位置])”
- 在消息中包含 PeakBagger URL,供用户核实:“[PeakBagger URL]”
- 使用 AskUserQuestion 提问:“这是正确的山峰吗?你可以在 [PeakBagger URL] 查看确认”
-
如果没有找到匹配结果:
- 系统地尝试山峰名称的不同变体(参见“山峰名称变体”部分):
- 颠倒词序:“Mountain Pratt” → “Pratt Mountain”
- **称谓变体:**Mt/Mount、St/Saint
- **添加位置:**包含州名或山脉名称
- **移除称谓:**仅尝试核心名称
- 使用不同变体并行运行多次搜索
- 合并结果,并向用户展示最合适的匹配结果
- 如果仍无结果,使用 AskUserQuestion 询问用户提供:
- 其他山峰名称变体
- 直接提供 PeakBagger 山峰 ID 或 URL
- 通用 PeakBagger 搜索
- 系统地尝试山峰名称的不同变体(参见“山峰名称变体”部分):
-
-
提取山峰 ID:
- 从搜索结果 JSON 中提取
peak_id字段 - 保存该值,供后续 peakbagger-cli 命令使用
- 同时保存 PeakBagger URL,供参考链接使用
- 从搜索结果 JSON 中提取
第 2 阶段:获取山峰信息
目标: 获取详细的山峰信息和坐标,以便收集基于位置的数据。
此阶段必须在第 3 阶段之前完成,因为天气、日照和雪崩数据都需要坐标。
使用第 1 阶段获取的山峰 ID 检索详细的山峰信息:
uvx --with patchright --from "git+https://github.com/dreamiurg/[email protected]" peakbagger peak show {peak_id} --format json
这将返回结构化的 JSON,其中包含:
- 山峰名称和别名
- 海拔(英尺和米)
- 地形突起度(英尺和米)
- 隔离距离(英里和公里)
- 坐标(十进制度表示的纬度和经度)
- 位置(县、州、国家)
- 路线(如有):步道起点、距离、爬升高度
- 所属山峰列表及排名
- 标准路线描述(如路线数据中提供)
错误处理:
- 如果 peakbagger-cli 失败:改用 WebSearch/WebFetch,并在“信息缺口”中注明
- 如果 JSON 中缺少特定字段:在缺口部分标记为“不可用”
- 速率限制:peakbagger-cli 内置速率限制(默认延迟 2 秒)
从此步骤获取坐标后,立即进入第 3 阶段。
第 3 阶段:收集数据
目标: 从所有可用来源收集全面的路线信息。
执行策略: 运行 Python 脚本获取确定性的 API 数据,同时并行调度专用 Agent 进行网络研究。这种混合方式既能最大限度地减少令牌用量,又能提高并行处理能力。
步骤 3A:获取状况数据(Python 脚本)
运行状况数据获取脚本,收集所有基于 API 的数据:
cd "{repo_root}/skills/route-researcher/tools"
uv run python fetch_conditions.py \
--coordinates "{latitude},{longitude}" \
--elevation {elevation_m} \
--peak-name "{peak_name}" \
--peak-id {peak_id} \
--trailhead "{trailhead_lat},{trailhead_lon}" \
--distance-mi {round_trip_distance_mi} \
--gain-ft {total_gain_ft} \
--start-time "{HH:MM}" \
--waypoint "{lat1},{lon1}" --waypoint "{lat2},{lon2}"
可选参数:--trailhead 启用多县路径采样(登山口→山顶);医院/护林站查询始终从山顶开始;--distance-mi/--gain-ft 启用 time_estimates;--start-time(需同时提供距离和爬升高度)启用 itinerary;--waypoint(2 个或以上)启用 bearings。
此脚本会返回 JSON,包含:
- weather:7 天预报,含温度、降水、冰冻高度;每天均包含
snow_line_note(以易读的方式说明冰冻高度与雪线的关系)和near_summit(布尔值:冰冻高度距山顶 2000 ft 以内时为 true) - air_quality:AQI 评级及任何相关风险
- daylight:完整的曙暮光时刻表 —
astronomical_dawn、nautical_dawn、civil_twilight(黎明)、sunrise、sunset、civil_dusk、nautical_dusk、astronomical_dusk;在高纬度地区,当太阳未达到阈值(白夜)时,这些值为null;daylight_hours、timezone - time_estimates:使用绳索/不使用绳索的时间估算,以及 3 档速度估算(
roped_hr、unroped_hr、fast_hr、moderate_hr、leisurely_hr)— 仅当提供--distance-mi和--gain-ftCLI 参数时才会包含 - itinerary:行程安排及安全提示(
start_time、summit_eta、turnaround_by、return_eta、total_hr、after_dark布尔值、dusk_cutoff、note)— 仅当同时提供--start-time、--distance-mi和--gain-ft时才会包含;after_dark: true是一项必须醒目呈现的安全警告;total_hr是往返总时长(小时) - bearings:航点间的导航方位(
segments[]包含bearing_deg、distance_mi、cumulative_distance_mi;total_distance_mi)— 仅当提供 2 个或以上--waypoint "lat,lon"参数时才会包含 - avalanche:NWAC 区域及供手动查询的 URL
- peakbagger:攀登统计数据及近期攀登记录(如果提供了 peak_id)
- counties:从登山口到山顶经过的县(
counties[]包含county_name、county_fips、state_name、state_code);sampled布尔值和sample_points整数表示是否运行了路径采样(需要--trailhead);如果未提供--trailhead,则仅返回山顶所在县 - nearest_hospital:最近的医院/急诊室(
hospitals[]包含name、lat、lon、distance_miles、emergency,以及 OSM 中提供的phone/website/address);优先排列急诊室,然后按距离排序;最多 3 家 - ranger_station:最近的护林站(
stations[]包含name、lat、lon、distance_miles,以及有提供时的phone/website/address)+ 可选的admin_district(如果山顶坐标与 USFS 护林区重叠,则包含district_name、forest_name、region) - campgrounds:约 12 mi(20 km)范围内已建成的露营地(
campgrounds[]包含name、lat、lon、distance_miles、camp_type、backcountry、operator,以及有提供时的website);不包括野外/高海拔营地 — 请从行程报告中提取此类信息 - gaps:报告中注明的任何 API 失败
请与步骤 3B 并行运行 — 在同一轮回复中同时包含 fetch_conditions.py 的 Bash 命令和全部 3 个 Task 调用,以最大限度提高并行度。
步骤 3B:分派研究 Agent(并行)
在一条消息中分派 3 个研究 Agent(同时发出全部 Task 调用)。每个 Agent 负责研究指定来源,并直接获取行程报告内容。
Agent 1:PeakBagger + SummitPost
Task(
subagent_type="general-purpose",
model="sonnet",
prompt="""You are a route researcher gathering mountaineering data for {peak_name}.
## Your Assignment
Research from these sources: PeakBagger, SummitPost
**Discover first (web sources):** for SummitPost, run a `site:summitpost.org` WebSearch to get exact URLs, then fetch those (don't WebFetch guessed paths).
## PeakBagger Research
1. Search: "{peak_name} site:peakbagger.com"
2. Extract route descriptions from peak page
3. List recent ascents with trip reports:
```bash
uvx --with patchright --from "git+https://github.com/dreamiurg/[email protected]" peakbagger peak ascents {peak_id} --format json --with-tr --limit 20
-
找出包含内容的行程报告(word_count > 0)
-
使用以下方式获取最多 5 篇近期行程报告的内容:
uvx --with patchright --from "git+https://github.com/dreamiurg/[email protected]" peakbagger ascent show {ascent_id} --format json
SummitPost 研究
-
搜索:"{peak_name} site:summitpost.org"
-
使用 WebFetch 提取:路线名称、难度、接近路线、描述、危险
-
如果 WebFetch 失败,请使用以下获取流程:
# Fast path (httpx with browser-like headers, no browser) uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py "{url}" # If the above returns {"error": ...} or content is blocked/JS-rendered: uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render "{url}" # If --render still returns a Cloudflare challenge page, escalate (needs a display): uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render --headed "{url}"
行程报告提取
对于获取的每份报告,提取:
- 日期、作者、路线状况、提及的装备
- 危险因素(明确并分别提取):
- 落石区域:路线上的位置、状况、提及的时间建议
- 冰瀑/冰塔危险:位置、稳定性、黎明前/时间方面的建议
- 冰檐危险:位置、堆积方向、避让说明
- 地形详情(如有提及则提取):
- 下攀路段:位置、难度、是否有下降锚点
- 河流/溪流渡口:位置、水流状况、涉水难度
- 水源:有名称的地点、季节性可用情况
- 有名称的营地或露营点:名称/位置、暴露情况说明
输出格式(严格按以下 JSON 返回)
{
"sources": ["PeakBagger", "SummitPost"],
"route_info": [
{"source": "...", "name": "...", "difficulty": "...", "description": "...", "hazards": [...]}
],
"trip_reports": [
{"source": "...", "date": "...", "author": "...", "url": "...", "summary": "...", "conditions": "...", "has_gpx": false,
"rockfall": "...", "icefall": "...", "cornices": "...",
"downclimbs": "...", "crossings": "...", "water_sources": "...", "camps": "..."}
],
"gaps": ["what couldn't be fetched and why"]
}
```"""
)
Agent 2:WTA + Mountaineers + 区域来源
Task(
subagent_type="general-purpose",
model="sonnet",
prompt="""You are a route researcher gathering mountaineering data for {peak_name}.
## Your Assignment
Research from these sources: WTA, Mountaineers.org, northwesthikers.net, hikeoftheweek.com, Oregon Hikers Field Guide (oregonhikers.org), Cascade Climbers (cascadeclimbers.com), Mountain Project
**Retrieval strategy — discover URLs, then fetch.** For each web source below (except mountaineers.org — use the Mountaineers MCP, see below), FIRST run a `site:` WebSearch (e.g. `"{peak_name} site:wta.org"`, `site:nwhikers.net`, `site:cascadeclimbers.com`) to collect the exact hike-page and individual trip-report URLs. THEN fetch each discovered URL through the fetching ladder. Do not WebFetch a guessed URL — enumerate real URLs first. This recovers reports that one-pass fetching loses to 403/JS blocks.
## WTA Research
1. Search: "{peak_name} site:wta.org"
2. Find the hike page and extract: trail name, difficulty, distance, elevation gain, hazards
3. Get trip reports from AJAX endpoint: {wta_url}/@@related_tripreport_listing
4. Fetch content for up to 5 recent trip reports using the fetching ladder:
```bash
# Fast path first
uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py "{trip_report_url}"
# If output contains {"error": ...} or content is blocked/JS-rendered:
uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render "{trip_report_url}"
# If --render still returns a Cloudflare challenge page, escalate (needs a display):
uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render --headed "{trip_report_url}"
Mountaineers 研究(优先使用 Mountaineers MCP——不要抓取网页)
mountaineers.org 通常会对 WebFetch/cloudscrape 返回 HTTP 403。请改用 Mountaineers MCP 工具——它们会返回结构化数据:
- 使用
mcp__mountaineers__search_routes(查询 “{peak_name}”)和mcp__mountaineers__get_route获取路线/地点页面(难度、方向、装备)。 - 使用
mcp__mountaineers__search_trip_reports(查询 “{peak_name}”);如果已有路线 URL,则使用mcp__mountaineers__get_route_trip_reports列出会员行程报告。 - 使用
mcp__mountaineers__get_trip_report获取每份相关报告的正文及结构化字段(日期、作者、结果、道路/状况说明)。 - 只有在 MCP 不可用时才记录此缺口——mountaineers.org 通常会对 WebFetch/cloudscrape 返回 HTTP 403,因此抓取网页并非此域名的可行后备方案。
注意:Task 派发的 general-purpose Agent(即本 Agent)可以使用 Mountaineers MCP。请从 MCP 结果中提取路线信息、技术要求和危险因素。
NWHikers 研究(northwesthikers.net / nwhikers.net)
- 搜索:“{peak_name} site:nwhikers.net OR site:northwesthikers.net”
- 使用 WebFetch 提取第一人称行程报告、GPS 轨迹说明和状况
- 如果 WebFetch 失败,使用
cloudscrape.py "{url}"(快速路径通常足够)
Hike of the Week(hikeoftheweek.com——必须使用 --render)
-
搜索:“{peak_name} site:hikeoftheweek.com”
-
必须使用
--render标志——该网站受 Cloudflare 保护,会拦截 WebFetch:uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render "{url}" # If --render still returns a Cloudflare challenge page, escalate (needs a display): uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py --render --headed "{url}" -
提取:行程安排、路线叙述、进入路线的说明、登山口方向
Oregon Hikers Field Guide(oregonhikers.org——仅限俄勒冈州目标)
- 搜索:“{peak_name} site:oregonhikers.org”
- 使用 WebFetch——该网站是静态 MediaWiki HTML,适用于 WebFetch
- 提取:路线描述、进入路线的说明、许可证、状况说明
Cascade Climbers(cascadeclimbers.com)
- 搜索:“{peak_name} site:cascadeclimbers.com”
- 使用 WebFetch;如果被拦截,则使用
cloudscrape.py "{url}" - 提取:技术路线信息、装备清单、行程报告、状况
Mountain Project(适用于技术性/岩石路段)
- 搜索:“{peak_name} site:mountainproject.com”
- 使用 WebFetch 提取:路线名称、等级、装备、描述、岩石质量
- 如果 WebFetch 失败,使用
cloudscrape.py "{url}"
后备方案
如果 WebFetch 无法获取任何页面,请按以下抓取顺序操作:cloudscrape.py "{url}"(快速)→ 对于由 JS 渲染或受 Cloudflare 保护的页面,使用 cloudscrape.py --render "{url}"。
行程报告提取
对于获取的每份报告,提取:
- 日期、作者、路线状况、提及的装备
- 危险因素(明确并分别提取):
- 落石区域:路线上的位置、状况、提及的时间建议
- 冰瀑/冰塔危险:位置、稳定性、黎明前/时间方面的建议
- 冰檐危险:位置、堆积方向、避让说明
- 地形详情(如有提及则提取):
- 下攀路段:位置、难度、是否有下降锚点
- 河流/溪流渡口:位置、水流状况、涉水难度
- 水源:有名称的地点、季节性可用情况
- 有名称的营地或露营点:名称/位置、暴露情况说明
输出格式(返回 EXACTLY 此 JSON)
{
"sources": ["WTA", "Mountaineers", "NWHikers", "HikeOfTheWeek", "OregonHikers", "CascadeClimbers", "MountainProject"],
"route_info": [
{"source": "...", "name": "...", "difficulty": "...", "description": "...", "hazards": [...]}
],
"trip_reports": [
{"source": "...", "date": "...", "author": "...", "url": "...", "summary": "...", "conditions": "...", "has_gpx": false,
"rockfall": "...", "icefall": "...", "cornices": "...",
"downclimbs": "...", "crossings": "...", "water_sources": "...", "camps": "..."}
],
"gaps": ["what couldn't be fetched and why"]
}
```"""
)
Agent 3:AllTrails
Task(
subagent_type="general-purpose",
model="sonnet",
prompt="""You are a route researcher gathering mountaineering data for {peak_name}.
## Your Assignment
Research from AllTrails
## AllTrails Research
1. Search: "{peak_name} site:alltrails.com"
2. Use WebFetch to extract: trail name, difficulty, distance, elevation gain, route type, best season, hazards
3. If WebFetch fails, use:
```bash
uv run python {repo_root}/skills/route-researcher/tools/cloudscrape.py "{url}"
- 从路线描述以及任何可见的评价/评论中提取以下信息(如有):
- 落石区域、冰瀑/冰塔林风险、雪檐风险
- 下攀路段、河流/溪流渡口、水源、已命名的营地
输出格式(返回 EXACTLY 此 JSON)
{
"sources": ["AllTrails"],
"route_info": [
{"source": "...", "name": "...", "difficulty": "...", "distance_miles": N, "elevation_gain_ft": N, "description": "...", "hazards": [...],
"rockfall": "...", "icefall": "...", "cornices": "...",
"downclimbs": "...", "crossings": "...", "water_sources": "...", "camps": "..."}
],
"trip_reports": [],
"gaps": ["what couldn't be fetched and why"]
}
```"""
)
在同一条回复中包含所有 Task 调用,并行执行全部 3 个 Agent。
步骤 3C:汇总结果
Python 脚本和所有 Agent 返回后,汇总为统一的数据结构:
{
"conditions": { /* from fetch_conditions.py */ },
"route_data": {
"sources": [ /* merged from all 3 agents */ ],
"trip_reports": [ /* merged from all agents */ ]
},
"gaps": [ /* merged gaps from all sources */ ]
}
部分失败处理:
- 如果任何 Agent 完全失败,则使用成功 Agent 返回的数据继续处理
- 在 gaps 数组中注明失败的来源
- 最低可用要求:路况数据 + 至少一个路线来源
步骤 3D:通行、许可和道路/闸门状态(内联处理)
确定许可证以及通往登山口的当前道路/闸门状态——不要只告诉用户自行查询。主动调查并报告实际状态,同时注明来源和日期。
许可证:
WebSearch: "{peak_name} trailhead access" ; "{peak_name} permit requirements"
道路/闸门状态工作流(先确定通行公路 + 林道 + 管理机构,然后按顺序检查来源;记录每个来源的 URL,以便写入报告):
- 州 DOT 垭口报告(WA → WSDOT):获取相关垭口页面,例如
https://wsdot.com/travel/real-time/mountainpasses/mt.-baker(SR-542)或.../north-cascades(SR-20)。读取RoadCondition/TravelAdvisoryActive/ 限制信息。其他州:WebSearch "{state} DOT mountain pass report {highway}"。 - USFS 森林警报/路况:获取
https://www.fs.usda.gov/{region}/{forest-shortname}/alerts(例如r06/mbs/alerts)和/conditions;在页面中搜索道路编号/登山口名称 → 封闭里程桩、原因、季节性闸门。还要使用WebSearch "{forest name} {road or trailhead} road open {year}"搜索季节性开放公告。 - NPS 道路状况(如果路线位于或经过国家公园):获取
https://www.nps.gov/{park-code}/planyourvisit/road-conditions.htm(例如noca、mora、olym)→ 各道路的开放/关闭状态和里程桩。 - WTA 实地信息(PNW):使用
WebSearch "site:wta.org {trail} gate road open closed {year}"或获取徒步页面;查看最近 3-5 篇行程报告,搜索“gate”/“road open/closed”/“drove to”(如果 WTA 返回 403,使用cloudscrape.py --render)。 - InciWeb 火灾封闭信息(7 月至 10 月):使用
WebSearch "inciweb {area} closure {trailhead} {year}";如果登山口附近有正在发生的事故,阅读其封闭页面。
综合为报告“道路状况”部分撰写注明日期的状态说明:
“闸门/道路状态(截至 {date}):根据 来源,{road} 为 {OPEN/CLOSED/SEASONAL GATE/UNKNOWN}。{如果关闭:闸门位于 {milepost},每程需额外行驶约 {N} 英里。}”
如果没有来源能够确认状态,请明确说明,并提供负责管理的护林站电话号码作为备用联系方式。将登山口名称、许可证、状态说明和所有来源 URL 添加到 route_data。
第 4 阶段:路线分析
目标: 分析收集到的数据,确定路线特征并综合相关信息。
步骤 4A:确定路线类型
根据路线描述、海拔和装备提及内容,将路线分类为:
- 冰川: 提及冰裂缝、冰川行进,通常海拔 >8000ft
- 攀岩: 技术攀登、YDS 等级(5.x)、提及保护装备
- 攀爬: 2-4 级,需要经过暴露地形,但非技术路线
- 徒步: 1-2 级,以步道为主,暴露地形很少
步骤 4B:综合多个来源的路线信息
目标: 将步骤 3B 调研 Agent 收集的行程报告和路线描述,以及步骤 3A 收集的路况数据,整合为全面的路线攻略。
来源优先级:
- 行程报告(步骤 3B Agent)——第一手体验
- 路线描述(步骤 3B Agent)——已发布的基础路线攻略
- PeakBagger/登顶数据(步骤 3A Python 脚本)——基本信息、规律
路线、关键难点和风险的综合模式:
- 从基准信息开始:依据路线描述(标准路线名称、公布的难度)
- 结合登山报告细节(地标、具体状况、实际经历)
- 标注冲突:登山报告与公布信息不一致时予以说明
- 突出共识(“多份报告提到……”)
- 纳入具体细节(海拔、地点、引述)
- **将每项具体报告的出处链接到其来源。**凡是某个细节来自特定的登山或攀登报告(日期、引述、“某支队伍发现……”、“近期一份报告指出……”),出处必须是指向该报告 URL 的 Markdown 超链接,绝不能使用纯文本。综合时保留每份登山报告的
url(以及日期/作者),以便添加链接;链接文本使用日期/作者。对于共识表述(“多份报告提到……”),在句中链接 2–3 份相关报告。只有不带特定来源的一般性/已发布的路线信息才不需要链接。
示例(路线描述):
“标准路线沿东侧山脊延伸(3 级)。2025 年 9 月的一支队伍发现,在 4,800 英尺处有一条路标堆砌清晰的徒步小径向右分岔——这才是正确的转向点;小径穿过碎石坡,他们称这段路‘乏味’且‘容易扭伤脚踝’。2025 年 10 月的一份报告指出,该路段被积雪覆盖,因此需要穿戴微型冰爪。”
将此模式应用于:
- **路线:**采用基准结构,补充登山报告中的地标/导航信息,并注明实际用时
- **关键路段:**描述位置/难度,补充登山报告中的评估,并说明因状况而异的情况
- **危险:**提取登山报告中的所有危险。按类型整理,并设置明确、独立的小节——不要将落石或冰崩归入笼统的“暴露路段”:
- **落石:**标注位置、触发因素(其他队伍/冻融/阳光照射山壁)、规避时机(黎明前通过、迅速穿过危险区)
- **冰崩/冰塔:**标注位置、稳定性评估、规避时机(避开下午、黎明前通过)
- **雪檐:**标注位置、安全绕行路线、形成状况(堆积方向、季节)
- 其他危险(冰裂缝、暴露路段、路线辨识、季节性危险)分别列为独立条目
- 内容务必全面,关系到安全;需包含具体位置和规避策略
- **地形细节:**如果登山报告/路线信息中提及,请在报告中列出以下内容:
- 下攀:位置、难度、是否有下降锚点
- 河流/溪流渡口:位置、季节性水流、涉水难度
- 水源:具名地点及各季节每天的可用情况
- 有名称的营地/露营点:名称、位置、暴露情况;注明这些信息来自登山报告,而非露营地数据库
提取关键信息:
从所有综合数据中,识别:
- 难度评级: YDS 等级、攀爬等级或总体难度(经行程报告验证)
- 关键难点: 路线中最困难或技术性最强的路段(综合整理自上文)
- 危险因素: 已识别的所有危险因素(综合整理自上文)
- 显著装备: 行程报告或路线信息中提及的任何特殊或重要装备(应纳入相关章节,而非单独成节)
- 起点: 名称及大致位置
- 距离/爬升: 往返距离和海拔爬升(比较已发布数据与实际行程报告数据)
- 时间估算: 使用 fetch_conditions.py 输出中的
conditions.time_estimates(键:fast_hr、moderate_hr、leisurely_hr、roped_hr、unroped_hr)——仅当调用时提供了--distance-mi和--gain-ft才呈现。如果 conditions 数据中没有time_estimates,请在信息缺口中注明。填充方式: 根据第 3B 步研究得知路线距离/爬升后,使用--distance-mi {distance}和--gain-ft {gain}重新调用 fetch_conditions.py。同时添加--start-time HH:MM参数以获取itinerary,并添加--waypoint参数以获取bearings——这些可选输出仅在提供相应参数时启用。 - 冰点高度分析: 比较山峰海拔与预报冰点高度:
- 包含冰点高度警报的情况: 预报中任意一天的冰点高度距山峰海拔不到 2000 ft
- 省略警报的情况: 整个预报期间冰点高度始终高于山峰 2000 ft 以上(典型夏季条件)
- 示例:海拔 5,469 ft 的山峰,冰点高度为 5,000-8,000 ft → 包含警报(条件临界)
- 示例:海拔 4,000 ft 的山峰,冰点高度为 10,000+ ft → 省略警报(远高于山顶)
第 4C 步:报告中的地理空间数据
在可用时纳入以下地理空间数据字段。报告中提及的每个地点都必须附上链接——请参见下方的链接格式。
地点/地图链接格式(根据地点的 lat/lon 和 name 构建):
- Google Maps 地点(命名实体):
https://www.google.com/maps/search/?api=1&query={URL-encoded name + address}——医院、护林站、露营地以及任何命名地点都使用此格式(而非裸坐标),确保链接指向实际地点。仅在坐标有意义时,使用query={lat},{lon}。 - Gaia GPS:
https://www.gaiagps.com/map/?loc=14/{lon}/{lat}(缩放级别/经度/纬度)。 - CalTopo:
https://caltopo.com/map.html#ll={lat},{lon}&z=14&b=mbt。
展示规则:
- 县: 在概览中列出
conditions.counties.counties[]中的county_name + state_name。为空或为error→ 列入信息缺口。 - 紧急联系人: 根据
conditions.nearest_hospital.hospitals[]和conditions.ranger_station(站点 + 行政区)创建表格。为每个名称添加链接:如果有website,链接到该网站;否则链接到以name + address搜索 Google Maps 的结果。始终包含电话和地址列——如果 OSM 有数据,每个条目现在都带有phone/website/address/lat/lon;如果缺少phone或address,请先尽力从该实体的官方网站或 Google Maps 列表中查找真实电话/地址,然后再填写“—”。缺失或为error→ 在信息缺口中注明。 - 露营地: 根据
conditions.campgrounds.campgrounds[]创建露营表格;为名称添加链接(网站或 Google Maps 地点),并根据每个条目的lat/lon添加 Google Maps 和 Gaia 地图链接。 - 报告中提及的任何命名地点(营地、露营点、高营地、命名地貌、起点):至少附上 Google Maps 和 Gaia 链接,遵循上述格式。对于行程报告中提及但没有坐标的营地,请使用名称搜索 Google Maps,并尽力定位;如果无法定位,请明确说明。偏远地区营地/高营地的信息来自行程报告,而非露营地数据库。
第 4D 步:识别信息缺口
明确记录未找到或不可靠的数据:
- 缺少登山报告
- 没有可用的 GPS 轨迹
- 脚本失败(天气、雪崩、日照时间)
- 不同来源的信息相互冲突
- 季节性数据有限
阶段 5:生成报告
目标: 调度报告撰写 Agent,创建全面的 Markdown 文档。
第 5A 步:准备数据包
将收集和分析的所有数据整理成结构化 JSON:
{
"peak": {
"name": "{peak_name}",
"id": {peak_id},
"elevation_ft": {elevation},
"coordinates": [{latitude}, {longitude}],
"location": "{location}",
"peakbagger_url": "{url}"
},
"conditions": {
// From fetch_conditions.py output
"weather": {"forecast": [{"date": "...", "snow_line_note": "...", "near_summit": bool, "freezing_level_ft": N, ...}], ...},
"air_quality": {...},
"daylight": {"astronomical_dawn": "...", "nautical_dawn": "...", "civil_twilight": "...", "sunrise": "...", "sunset": "...", "civil_dusk": "...", "nautical_dusk": "...", "astronomical_dusk": "...", "daylight_hours": N},
"avalanche": {...},
"peakbagger": {...},
"counties": {"counties": [{"county_name": "...", "county_fips": "...", "state_name": "...", "state_code": "..."}], "sampled": bool, "sample_points": N}, // sampled + sample_points only present when --trailhead was given
"nearest_hospital": {"hospitals": [{"name": "...", "lat": N, "lon": N, "distance_miles": N, "emergency": "yes|null", "phone": "...", "website": "...", "address": "..." /* phone/website/address optional */}]},
"ranger_station": {"stations": [{"name": "...", "lat": N, "lon": N, "distance_miles": N, "phone": "...", "website": "...", "address": "..." /* optional */}], "admin_district": {"district_name": "...", "forest_name": "...", "region": "..."}},
"campgrounds": {"campgrounds": [{"name": "...", "lat": N, "lon": N, "distance_miles": N, "camp_type": "...", "operator": "...", "website": "..." /* optional */}], "note": "..."},
"time_estimates": {"roped_hr": N, "unroped_hr": N, "fast_hr": N, "moderate_hr": N, "leisurely_hr": N, "note": "..."},
"itinerary": {"start_time": "HH:MM", "summit_eta": "HH:MM", "turnaround_by": "HH:MM", "return_eta": "HH:MM", "total_hr": N, "after_dark": false, "dusk_cutoff": "9:15 PM" /* 12-hr AM/PM format, unlike other time fields */, "note": "..."},
"bearings": {"segments": [{"from": 0, "to": 1, "bearing_deg": N, "distance_mi": N, "cumulative_distance_mi": N}], "total_distance_mi": N}
},
"route_data": {
// Merged from all Researcher agents
"sources": [...],
"trip_reports": [...]
},
"analysis": {
// From Phase 4
"route_type": "{hike|scramble|technical|glacier}",
"difficulty": "{rating}",
"crux": "{description}",
"hazards": [...],
"access": {...}
},
"gaps": [...]
}
第 5B 步:调度报告撰写 Agent
Task(
subagent_type="general-purpose",
model="sonnet",
prompt="""You are a Report Writer generating a mountaineering route report.
## Instructions
1. **Read the report template:**
Use the Read tool to read: {repo_root}/skills/route-researcher/assets/report-template.md
2. **Generate report following template structure exactly:**
- Header with peak name, elevation, location, date
- AI disclaimer (prominent safety warning)
- Overview: route type, difficulty, distance/gain, time estimates
- Route Description: synthesized from sources, include landmarks
- Crux: describe hardest section with specifics
- Known Hazards: comprehensive list
- Current Conditions: weather forecast, freezing levels, air quality, daylight
- Trip Reports: links organized by source with dates
- Information Gaps: explicitly list missing data
- Data Sources: links to all sources used
3. **Markdown Formatting Rules:**
- ALWAYS add blank line before lists
- ALWAYS add blank line after section headers
- Use `-` for bullets (not `*` or `+`)
- Use `**text**` for bold emphasis
- Break paragraphs >4 sentences
- **Link specific-report attributions.** Any statement attributed to a particular trip/climb report (a date, a quote, "one party…", "a recent report…") MUST be a Markdown link `[date/author](report_url)` to that report's source URL — never plain-text attribution. Pull the URL from the matching `trip_reports[].url` in the data package. Leave only generic/published beta (no specific source) unlinked.
4. **Save the report:**
Use the Write tool to save to the user's current working directory: {date}-{peak-name-slug}.md
## Data Package
{data_package_json}
## Output Format (return EXACTLY this JSON)
```json
{
"status": "SUCCESS",
"file_path": "/absolute/path/to/report.md",
"filename": "YYYY-MM-DD-peak-name.md",
"sections_generated": N
}
```"""
)
第 5C 步:记录报告文件路径
从 Agent 的 JSON 响应中提取 file_path,供阶段 6 使用。
阶段 6:报告审查与验证
目标: 调度报告审查 Agent,验证报告质量。
第 6A 步:调度报告审查 Agent
Task(
subagent_type="general-purpose",
model="opus",
prompt="""You are a Report Reviewer validating a mountaineering route report.
## Instructions
1. **Read the report:**
Use the Read tool to read: {report_file_path}
2. **Perform systematic quality checks:**
**Factual Consistency:**
- Dates match their stated day-of-week (e.g., "Thu Nov 6, 2025" is actually Thursday)
- Coordinates, elevations, distances consistent across all mentions
- Weather forecasts align logically (freezing levels match precipitation types)
**Mathematical Accuracy:**
- Elevation gains add up correctly
- Time estimates reasonable given distance and elevation gain
- Unit conversions correct (feet to meters, etc.)
**Internal Logic:**
- Hazard warnings align with route descriptions
- Recommendations match current conditions
- Crux descriptions match overall difficulty rating
**Completeness:**
- No placeholder texts like {{peak_name}} or {{YYYY-MM-DD}}
- All referenced links actually provided
- Mandatory sections present: Overview, Route, Current Conditions, Trip Reports, Information Gaps, Data Sources
**Formatting:**
- Markdown headers properly structured
- Lists have blank lines before them
- Tables properly formatted
**Safety & Responsibility:**
- AI disclaimer present and prominent
- Critical hazards properly emphasized
- Users directed to verify information from primary sources
**Emergency contacts & location links (verify INDEPENDENTLY):**
- Each emergency contact (hospital, ranger station) has a working name link (website or a Google Maps place link to the actual entity — NOT bare coordinates), a phone, and an address. Independently confirm the phone/address look right for that named entity (e.g. via its official site / Google Maps); fix or flag mismatches and fill blanks you can confirm.
- Road/gate status is a dated statement with a cited source, not a "go check it yourself" punt.
- Every named place in the report (campsite, bivy, high camp, trailhead, named feature) carries map links (Google Maps + Gaia GPS). Flag any named location missing links.
- Specific trip-report attributions are hyperlinks to their source, not plain text.
3. **Fix issues:**
- **Critical** (safety errors, factual errors, missing disclaimers): MUST fix using Edit tool
- **Important** (completeness, consistency): SHOULD fix
- **Minor** (formatting, polish): FIX if quick
## Output Format (return EXACTLY this JSON)
```json
{
"status": "PASS" | "PASS_WITH_FIXES" | "FAIL",
"issues_found": N,
"fixes_applied": ["description of fix 1", "description of fix 2"],
"remaining_issues": ["issues that couldn't be fixed"],
"report_path": "/absolute/path/to/report.md"
}
```"""
)
第 6B 步:处理验证结果
处理审查 Agent 的响应:
- PASS 或 PASS_WITH_FIXES: 使用
report_path继续阶段 7 - FAIL: 向用户展示
remaining_issues并询问如何处理
报告审查器会自动修复问题并返回修正后的文件路径。
阶段 7:完成
目标: 告知用户任务已完成及后续步骤。
向用户报告:
- 成功消息:“{Peak Name} 的路线研究已完成”
- **文件位置:**生成的报告的完整绝对路径
- **摘要:**简要概述,2–3 句话:
- 路线类型和难度
- 主要危险或注意事项
- 任何重要的信息缺口
- **后续步骤:**建议用户:
- 查看报告
- 从一手来源核实关键信息
- 尝试路线前查看当前状况
- **行程安排与导航:**如果用户需要出发时间安排和/或罗盘方位,请使用
--start-time HH:MM(添加itinerary键)和/或--waypoint lat,lon标志(2 个或更多航点会添加bearings键)重新运行fetch_conditions.py。将after_dark: true作为醒目的安全警告指出。 - **登顶后登山报告:**登山后,可提供
skills/route-researcher/assets/trip-report-template.md中的登山报告模板,作为撰写登山报告的起点。
完成消息示例:
Route research complete for Mount Baker!
Report saved to: 2025-10-20-mount-baker.md
Summary: Mount Baker via Coleman-Deming route is a moderate glacier climb (Class 3) with significant crevasse hazards. The route involves 5,000+ ft elevation gain and typically requires an alpine start. Weather and avalanche forecasts are included.
Next steps: Review the report and verify current conditions before your climb. Remember that mountain conditions change rapidly - check recent trip reports and weather forecasts immediately before your trip.
错误处理原则
执行过程中,请遵循以下错误处理指南:
脚本失败
- **不要因此中断:**如果 Python 脚本失败,请在“信息缺口”中记录并继续
- **提供替代方案:**附上手动检查链接(Mountain-Forecast.com、NWAC.us)
- **最多重试一次:**网络超时时重试一次,然后继续
缺失数据
- **明确说明:**始终记录未找到的内容
- **提供帮助:**提供手动检查链接
- **不要猜测:**切勿编造数据来填补缺口
搜索失败
- **尝试不同写法:**如果未找到山峰,尝试其他名称(Mt 与 Mount)
- **询问用户:**如果仍未找到,请用户澄清或提供直接 URL
- **提供指导:**建议用户如何手动搜索 PeakBagger
WebFetch/WebSearch 问题
- **获取顺序:**先用 WebFetch →
cloudscrape.py "{url}"(快速 httpx,不使用浏览器)→cloudscrape.py --render "{url}"(通过 Patchright 使用真正的 Chrome;等待 Cloudflare 验证挑战结束;对于难以处理的页面,如果有显示器可用,则添加--headed) - **何时使用
--render:**用于 hikeoftheweek.com,以及默认方式在标准输出中返回{"error": ...}或内容被屏蔽/由 JavaScript 渲染的任何网站 - **优雅降级:**缺少一个来源不应导致整个研究停止;cloudscrape.py 失败时会以 0 退出
- **记录缺口:**注明哪些来源不可用(WebFetch 和所有 cloudscrape.py 路径均失败:快速路径、--render、--render --headed)
- **安全优先:**如果无法获取关键安全信息(雪崩、危险),请在缺口部分重点说明
执行超时
- 单个 Python 脚本: API 调用限时 30 秒;提供 --peak-id 时最长 120 秒(peakbagger-cli)
- WebFetch 操作: 使用默认超时
- WebSearch 操作: 使用默认超时
- 技能总执行时间: 目标为 3–5 分钟;综合研究时最长可接受 10 分钟
质量原则
每份生成的报告都必须:
- ✅ 在顶部醒目地包含安全免责声明
- ✅ 明确记录所有信息缺口
- ✅ 附上带链接的来源
- ✅ 在文件名和元数据中使用当前日期
- ✅ 严格遵循模板结构
- ✅ 提供可执行的信息(距离、时间、装备)
- ✅ 强调核实信息——这是研究结果,不是绝对准则
实现说明
详细的执行流程、组件概览、数据契约和设计决策,请参阅 skills/route-researcher/docs/architecture.md。
peakbagger-cli 命令参考(v1.10.0,git 源码)
需要
patchright+ Google Chrome。 peakbagger-cli 在自身的uvx环境中运行,并使用 Patchright 浏览器绕过 Cloudflare,因此每次调用都必须包含--with patchright。若不包含此参数,命令会因Error: patchright is required to bypass Cloudflare而中止。
所有命令都使用 --format json 获取结构化输出。运行方式:
uvx --with patchright --from "git+https://github.com/dreamiurg/[email protected]" peakbagger <command> --format json
可用命令:
peak search <query>- 按名称搜索山峰peak show <peak_id>- 获取山峰详细信息(坐标、海拔、路线)peak stats <peak_id>- 获取登顶统计数据和时间模式--within <period>- 按时间段筛选(例如,'1y'、'5y')--after <YYYY-MM-DD>/--before <YYYY-MM-DD>- 日期筛选
peak ascents <peak_id>- 列出个人登顶记录及行程报告链接--within <period>- 按时间段筛选(例如,'1y'、'5y')--with-gpx- 仅显示带 GPS 轨迹的登顶记录--with-tr- 仅显示带行程报告的登顶记录--limit <n>- 返回的登顶记录上限(默认值:100)
ascent show <ascent_id>- 获取登顶记录详细信息
注意: 要查看完整命令选项,请运行 peakbagger --help 或 peakbagger <command> --help
山峰名称变体
初次搜索失败时,可尝试以下常见变体:
- 颠倒词序: "Mountain Pratt" → "Pratt Mountain","Peak Sahale" → "Sahale Peak"
- 扩展名称: "Mt" → "Mount","St" → "Saint"
- 添加地点: "Baker, WA" 或 "Baker, North Cascades"
- 移除名称前缀: 使用 "Baker" 代替 "Mt Baker"
- 组合变体: 尝试颠倒词序并扩展名称(例如,"Mountain Pratt" → "Pratt Mount" + "Pratt Mountain")
导航地图链接
山顶坐标链接
以山顶为中心,使用十进制度数,为报告的概览行构建以下链接。
Google Maps:
https://www.google.com/maps/search/?api=1&query={latitude},{longitude}
CalTopo(MapBuilder Topo 底图,缩放级别 14):
https://caltopo.com/map.html#ll={latitude},{longitude}&z=14&b=mbt
Gaia GPS(顺序为缩放级别/经度/纬度):
https://www.gaiagps.com/map/?loc=14/{longitude}/{latitude}
PeakVisor 徒步地图(缩放级别/纬度/经度;查询参数中的斜杠需 URL 编码为 %2F):
https://peakvisor.com/hiking-map?custom=14%2F{latitude}%2F{longitude}#14/{latitude}/{longitude}
示例(Mt Baker,48.7768,-121.8144):
- Google Maps:
https://www.google.com/maps/search/?api=1&query=48.7768,-121.8144 - CalTopo:
https://caltopo.com/map.html#ll=48.7768,-121.8144&z=14&b=mbt - Gaia GPS:
https://www.gaiagps.com/map/?loc=14/-121.8144/48.7768 - PeakVisor:
https://peakvisor.com/hiking-map?custom=14%2F48.7768%2F-121.8144#14/48.7768/-121.8144
注意: 使用十进制度数。Gaia GPS 的顺序为缩放级别/经度/纬度;CalTopo 和 PeakVisor 的顺序为纬度/经度。
登山口 Google Maps 链接
如果有坐标(例如,来自 Mountaineers.org 的地点信息):
https://www.google.com/maps/search/?api=1&query={latitude},{longitude}
示例:https://www.google.com/maps/search/?api=1&query=48.5123,-121.0456
如果只有登山口名称:
https://www.google.com/maps/search/?api=1&query={trailhead_name}+{state}
示例:https://www.google.com/maps/search/?api=1&query=Cascade+Pass+Trailhead+WA
注意: 有坐标时优先使用坐标,以获得更精确的位置。
技能版本: 5.1.0 | 最后更新: 2026-05-22