Install
openclaw skills install @mfang0126/research-pro系统化研究 skill — 螺旋收敛模型。把任何问题(模糊或清晰)分解成子问题,迭代搜索,越搜越清晰,直到每个子问题都有答案。 Triggers: "帮我研究", "研究一下", "调研", "分析对比", "research", "investigate", "look up" 也触发: 竞品分析、市场调研、技术选型对比、趋势了解 Setup triggers: "安装 research-pro", "配置 research-pro", "research-pro doctor", "setup research-pro", "research-pro 未就绪" **Gates:** 开始外部搜索前必须通过 READY doctor 与 Search Target Confirmation Gate;所有交互式多源/外部研究必须先展示 Search Contract 并收到用户明确确认。唯一例外是一个用户明确提供的 URL/文件、且只要求读取/提取/摘要、不作跨源比较或推断的 NARROW_SELFCHECK(见 SKILL Phase 1)。 Does NOT trigger normal multi-source research: - 已经知道答案的简单事实问题 - 用户直接给了 URL/文件、且只要读取/提取/摘要的,按 Step 1.2 的 NARROW_SELFCHECK 处理(不进入跨源 research) - 代码调试、写代码任务 Output: 结构化研究报告(结论 + 子问题答案 + 来源 + 争议点 + 未解决缺口)
openclaw skills install @mfang0126/research-pro核心原则: 不是"问清楚再搜",是"边搜边搞清楚"。先看本地,再看网络。
安装: SETUP.md 或 bash scripts/install.sh。
凭据: scripts/lib/credentials.mjs(never-override + allowlist)。通用 ~/.config/research-pro/.env(env.example)。安全:references/security.md。
⚠️ 裸第三方 CLI 必经 shim: tvly/firecrawl/youtube_transcript_api 等只读 process.env,不会自动加载 .env 源 → 冷启动报 "No API key"。必须用 node {baseDir}/scripts/run-with-creds.mjs <cmd> ... 运行(进程内注水 env 再 exec,secret 不进 stdout)。Node 脚本(grok_search.mjs/research.mjs)已自注水,直接调。
搜索 trace(debug/对比,默认开 light): 见下方「旁路搜索 Trace」。
定义:
doctor 的 ready/runnable == true(至少一个 Tavily / XAI / OpenRouter 或已知搜索 CLI)web_search / x_search / 等价工具none | min | good | full每次研究请求(含 setup 触发)必须先执行:
node {baseDir}/scripts/doctor.mjs --require-ready --json
| 结果 | 动作 |
|---|---|
exit 0 / ready: true | 记录 tier + capabilities → 继续 Phase 1 |
exit 1 / ready: false 且 无 host web 工具 | 停止所有外部搜索;把 doctor 的 setup 卡原样给用户;等配置后再来 |
| exit 1 但 有 host web 工具 | 可 READY=true,仅用 host 工具;在状态行注明 script=degraded |
禁止: 跳过 doctor 直接 tvly / curl / Grok / Firecrawl。
禁止: 未 READY 时编造搜索结果。
禁止: 为检查配置而 cat / 打印 .env 内容。
READY 后先输出一行(再拆子问题):
就绪:tier=min|good|full · script=yes|no · host_web=yes|no · caps: quick_search,realtime_web,...
用户未就绪时只给可复制步骤,不展开长方法论:
## research-pro 未就绪
需要至少一个搜索后端。
### 最快修复
mkdir -p ~/.config/research-pro && chmod 700 ~/.config/research-pro
cp {baseDir}/env.example ~/.config/research-pro/.env
# 编辑填入任意一个: TAVILY_API_KEY / XAI_API_KEY / OPENROUTER_API_KEY
chmod 600 ~/.config/research-pro/.env
node {baseDir}/scripts/doctor.mjs --require-ready
或: bash {baseDir}/scripts/install.sh
详见 SETUP.md
在整个研究过程中,在工作记忆中维护研究地图,每轮结束后必须更新。
研究地图
├── 原始问题: "..."
├── Search Contract: {decision, object, in_scope, out_of_scope, answer_shape, anchor_evidence, state}
├── 核心目标: "..."(一句话:最终要知道什么)
├── 当前假设: [对答案的初步猜测,每轮 Reflection 后更新]
├── 子问题列表:
│ - Q1: [问题] | 状态: 未知/部分/已知 | 置信度: 高/中/低
│ - Q2: ...
├── 已知事实: [每条必须带来源 URL 或本地路径]
├── 线索池:
│ - {描述, 来源, 相关性分 0-3, 已追/未追}
└── 搜索轮次: N / 上限: M
研究地图是思考过程的载体,不是最终输出。
目标: 验证问题前提,拆成 2-4 个可以独立回答的子问题。
node {baseDir}/scripts/doctor.mjs --require-ready --json
ready, tier, capabilities, missing keys(不要打印 secret)Trace init(READY 后立刻,失败不阻塞):
TRACE=$(node {baseDir}/scripts/trace.mjs init --question "原始问题摘要" --depth standard --tier min|good|full)
# stdout JSON: {run_id, run_dir, mode}
export RESEARCH_PRO_RUN_ID=$(node -e "let d='';process.stdin.read()||'{}';try{d=JSON.parse(d)}catch(e){d={}};process.stdout.write(d.run_id||'')" <<<"$TRACE")
状态行可附带 run_id=...。RESEARCH_PRO_TRACE=off 时 init 返回 skipped。
web_search / web_extract 这类 host-native 工具调用不会被 Python smart-search 自动拦截;直接调用会导致研究结果出现在聊天里,但不进入 calls.jsonl、cross-run cache 或 raw evidence。研究流程中禁止直接调用 host-native web 工具。
必须在 execute_code 中运行:
import runpy, sys, os
from pathlib import Path
# Resolve skill dir: Hermes uses {baseDir}; adjust if installed elsewhere
BASE = Path(os.environ.get("RESEARCH_PRO_SKILL_DIR",
os.path.expanduser("~/.hermes/external-skills/research-pro")))
bridge = BASE / "scripts" / "host_native_trace.py"
sys.argv = [str(bridge), "search", "--query", "QUERY", "--hint", "quick"]
runpy.run_path(str(bridge), run_name="__main__")
已知 URL 的正文提取:
import runpy, sys, os
from pathlib import Path
BASE = Path(os.environ.get("RESEARCH_PRO_SKILL_DIR",
os.path.expanduser("~/.hermes/external-skills/research-pro")))
bridge = BASE / "scripts" / "host_native_trace.py"
sys.argv = [str(bridge), "extract", "--urls", "https://example.com/page", "--hint", "scrape"]
runpy.run_path(str(bridge), run_name="__main__")
Bridge 会:
data.web 标准化为 trace/cache 可识别的 results[];raw/<call_id>.json,即使 RESEARCH_PRO_TRACE=light;calls.jsonl 和 search-cache.jsonl 后才把原始结果输出给研究流程;RESEARCH_PRO_TRACE_MAX_RAW_BYTES 限制。x_search、Grok、Tavily、Firecrawl 等优先走 smart-search / search_with_trace.sh。如果确实必须直接调用 host-native x_search,必须先把完整 JSON 保存到文件,再执行:
node {baseDir}/scripts/trace.mjs record-search \
--run-id "$RESEARCH_PRO_RUN_ID" \
--file /path/to/native-result.json \
--hint social \
--actual-tool x_search \
--requested-tool host-native-x-search \
--source host-native-manual \
--force-raw
禁止只记录“搜过了”或只记录摘要;没有 URL、结果列表和 raw response 的记录只能标为 metadata-only,不得作为 reference-supported 证据使用。
在搜索任何东西之前,先检查本地:
package.json、配置文件、extensions/、plugins/shared/docs/、DECISIONS.md、PROJECTS.md本地检查结果决定下一步:
目的: Gate 锁定研究的中心(WHAT:对象、边界、决策);螺旋收敛探索该中心内的半径(HOW:子问题、证据与细节)。不要把应由研究发现的内容细节拿来反复澄清。
先写紧凑的 Search Contract(中文;用户为其他语言时用其语言)。research object 必须锚定用户原话中的短语,或一个已检查的具体本地实体/路径;anchor_evidence 记录该原话或路径。凡是不在锚定对象覆盖范围内的内容,默认排除,不能靠无限枚举 adjacent interpretations。
## Search Contract
- decision/question: [要支持的决策或要回答的问题]
- research object: [锚定对象;不改写成相邻主题]
- in scope: [要比较/验证的边界]
- out of scope: [明确排除的相邻解释;其他未被 object 覆盖者默认排除]
- answer shape: [结论、比较、证据或可执行建议]
- anchor_evidence: [用户原话「…」或已检查的本地路径:…]
状态机(硬规则): 对所有交互式多源/外部研究,唯一流程是 DRAFT → CONTRACT_ACCEPTED → SEARCHING。必须先把 DRAFT contract 展示给用户;只有用户明确确认该已展示的 contract 后才能设为 CONTRACT_ACCEPTED,再进入 SEARCHING。DRAFT 状态不得构造 query、选/路由工具、调用 web/API/CLI 搜索或启动外部 research。
CONTRACT_ACCEPTED。可先做 doctor 与本地文件检查,禁止外部搜索。DRAFT contract、再次展示,并等待用户确认或纠正。不得用内部自检、清晰度判断或 accepted-selfcheck 替代用户确认。可见提问硬规则(Telegram/消息平台尤其重要):
clarify 的 question 参数必须包含完整的、紧凑的 Search Contract(decision/question、research object、in scope、out of scope、answer shape、anchor_evidence)以及明确的“请确认/纠正”请求。不能只把 Contract 放在此前的 assistant prose,随后调用 clarify(question="是否继续?", ...);消息平台可能只把 clarify 这一条作为可操作提问显示给用户。choices 只能放短的确认标签,不能成为唯一的范围说明。长内容放 question;choices 例如 ["确认:按以上 Search Contract 研究"]。clarify(
question="""Search Contract
- decision/question: ...
- research object: ...
- in scope: ...
- out of scope: ...
- answer shape: ...
- anchor_evidence: ...
请确认以上范围;如需调整请直接指出。""",
choices=["确认:按以上范围研究"],
)
question 必须包含触发发现、影响和可选路径,不得只写“是否调整方向?”。NARROW_SELFCHECK,直接进行该单一来源读取;这不是多源 research,也不进入 SEARCHING。任一条件不满足即回到完整交互式 contract 流程。CONTRACT_ACCEPTED:decision、锚定的 object、in_scope、out_of_scope、answer_shape、anchor_evidence。任一缺失、object 未锚定或字段互相冲突 → 在任务评论写 DRAFT contract,needs_input block;绝不静默扩展范围。收到用户纠正: 立即把 state 退回 DRAFT,删除旧方向的子问题、query seeds、计划工具、URL、发现和候选结论;从更正后的 contract 重建 Research Map,展示它并等待新的明确确认。被拒方向的结果不得作为相关证据报告。
精确失败示例:
⛔ Gate:
in scopePhase 1 结束时输出一行:
合同:accepted(anchor:[短语/路径])| 深度:[Quick/Standard/Deep](最多 N 轮)| 子问题:Q1, Q2, Q3 | 如需调整范围或深度请说明
目标: 为每个"未知"或"部分"子问题构建 query,选工具。
前置断言: 多源/外部 research 的 Search Contract.state 必须为 CONTRACT_ACCEPTED,且该状态必须来自用户对已展示 contract 的明确确认(headless 仅限任务正文的完整预批准 contract)。否则停止:不构建 query、不路由工具、不进行任何外部搜索。NARROW_SELFCHECK 只能读取其唯一的用户提供来源,绝不进入 Phase 2。
Keyword 构建原则:
对每个子问题,按顺序检查以下信号。匹配到的工具必须加入该子问题的工具组合(不是二选一,是叠加):
| # | 信号 | 触发条件 | 必须加入的工具 |
|---|---|---|---|
| S1 | 社区情绪 | 问题涉及"开发者怎么看"、"社区反馈"、"用户体验"、产品口碑 | Grok x_search + Tavily site:reddit.com |
| S2 | 实时性 | 问题涉及"最新"、"最近"、"2026"、"本周"、新闻、发布 | Grok web_search(引用可靠);Grok 不可用时 fallback Tavily |
| S3 | 深度对比 | 问题是 A vs B、技术选型、竞品分析 | Tavily Research + 至少一个实时工具(S2) |
| S4 | 教程/How-to | 问题涉及"怎么做"、实现方式、代码示例 | Tavily search + YouTube(可能有视频教程) |
| S5 | 市场/热度 | 问题涉及"有多少人用"、"趋势"、"市场份额" | DataForSEO + Grok x_search |
| S6 | 单一权威源 | 已知某个 URL 有关键信息 | Firecrawl scrape(非 Reddit)/ Tavily extract(Reddit) |
没有匹配任何信号? → 默认 Tavily search。
选完工具后,必须回答这个问题:
"这组子问题里,有没有哪个维度只用了 Tavily?如果是,有没有第二个工具能提供不同视角的信息?"
工具选择矩阵(基于实测 2026-04-12):
| 问题类型 | 时效 | 首选工具 | 命令 | 备用 |
|---|---|---|---|---|
| 通用技术搜索 | 不限 | Tavily | tvly search "query" | Firecrawl search |
| 深度综合报告 | 不限 | Tavily Research | tvly research "query" | — |
| 最新动态/实时 | 实时 | Grok web_search | Responses API /v1/responses | Tavily |
| 社区/Reddit 讨论 | 近期 | Tavily site filter | tvly search "query site:reddit.com" | WebSearch |
| 深挖单页(普通) | 不限 | Firecrawl scrape | firecrawl scrape "URL" | Tavily extract |
| 深挖单页(Reddit) | 不限 | Tavily extract | tvly extract "URL" | WebFetch |
| 视频内容 | 不限 | YouTube API + Transcript | 见下方两步流程 | — |
| 关键词热度/SERP | 不限 | DataForSEO | REST API | — |
| 复杂推理 + 实时搜索 | 实时 | Grok web_search | Responses API /v1/responses | Tavily Research |
| X/Twitter 实时讨论 | 实时 | Grok x_search | Responses API /v1/responses | Tavily site:x.com |
| Grok 不可用时的 fallback | 实时 | Perplexity sonar | OpenRouter REST API(⚠️ 引用幻觉 37%) | Tavily |
表内
tvly/firecrawl等命令均为简写;实际执行必须前缀node {baseDir}/scripts/run-with-creds.mjs(见上方「调用方式」的 shim 规则),否则拿不到凭据。
已知局限(选工具时必须考虑):
| 工具 | 局限 | 应对 |
|---|---|---|
| Tavily search | 结果偏 SEO 优化内容,深度不够;JS 重度渲染页可能抓不全 | 深度内容用 Firecrawl scrape 或 Tavily Research |
| Tavily Research | ~42s 慢;结果是 AI 综合的,可能丢原始细节 | 需要原始来源时用 search + extract 组合 |
| Tavily extract | 对复杂 JS SPA 页面效果差 | 换 Firecrawl scrape |
| Firecrawl | ❌ 无法抓 Reddit;Cloudflare 保护的站点可能被拦;付费墙内容抓不到 | Reddit → Tavily extract;被拦 → WebFetch |
| Grok x_search | ~50s 慢;日期过滤只支持 YYYY-MM-DD 精度到天;很老的帖子相关性下降 | 时效性强的问题优先用;历史讨论考虑 Tavily site:x.com |
| Grok web_search | ~50s 慢(Tavily 1.7s);非英文内容覆盖可能不如 Tavily;$5/1000 calls | 中文搜索优先 Tavily;速度敏感的 Quick 模式考虑先 Tavily 再 Grok |
| Perplexity sonar | ⚠️ 回答准确率 >90%,但引用幻觉率 37%(CJR 2025 基准,1/3 的引用不匹配内容);Sonar Pro 更差 45%。答案大概率对但来源可能对不上 | Critic 步骤必须用 Firecrawl/Tavily extract 验证关键引用 URL 是否真说了那些话 |
| YouTube | 不是所有视频有字幕;自动字幕质量参差;API quota 有限 | 检查 transcript 可用性再决定是否深挖 |
| DataForSEO | 中文关键词支持有限;数据有延迟(非实时) | 中文市场用 Grok x_search 补充 |
调用方式:
⚠️ 下面凡是裸 CLI(tvly/firecrawl/youtube_transcript_api)或用到
$XXX_API_KEY的 curl,都要经凭据 shim,否则冷启动报 "No API key"。 令RWC = node {baseDir}/scripts/run-with-creds.mjs(进程内注水 env 再 exec,secret 不进 stdout)。
# Tavily — 快速搜索(1.7s)
RWC tvly search "query"
RWC tvly extract "https://url"
# Tavily — 深度综合报告(~42s,自动整合多源)
RWC tvly research "query"
# Perplexity via OpenRouter — 实时网络搜索 + 推理(凭据由 credentials 解析,勿 source 平台 .env)
# sonar: 快速实时搜索;sonar-pro: 更深度,带引用。用到 $OPENROUTER_API_KEY → 经 shim:
RWC bash -c 'curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"model\":\"perplexity/sonar\",\"messages\":[{\"role\":\"user\",\"content\":\"QUERY\"}],\"max_tokens\":500}"'
# Firecrawl — 深挖单页完整内容(不支持 Reddit)
RWC firecrawl search "query" --limit 10
RWC firecrawl scrape "https://url"
# YouTube — 两步流程:先找视频,再提取字幕
# Step 1: YouTube Data API(YOUTUBE_API_KEY;兼容旧名 YOUTUBE_API)→ 经 shim:
RWC bash -c 'curl "https://www.googleapis.com/youtube/v3/search?part=snippet&q=QUERY&type=video&maxResults=5&key=$YOUTUBE_API_KEY"'
# Step 2: 提取字幕(无需额外 key)
RWC youtube_transcript_api "VIDEO_ID" --format text
# DataForSEO — 关键词搜索量 + SERP 结构分析
# 使用 DATAFORSEO_LOGIN / DATAFORSEO_PASSWORD env vars
# REST API: https://api.dataforseo.com/v3/serp/google/organic/live/advanced
# Grok web_search — 实时网页搜索,带引用(~50s,返回带 URL 引用的结构化回答)
# 必须用 grok-4 系列模型(grok-3 不支持 server-side tools)
# Prefer: node {baseDir}/scripts/grok_search.mjs "QUERY" --web --json
curl -s https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"grok-4","tools":[{"type":"web_search"}],"input":"QUERY","max_output_tokens":500}'
# Grok x_search — X/Twitter 实时讨论搜索
# Prefer: node {baseDir}/scripts/grok_search.mjs "QUERY" --x --json
curl -s https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"grok-4","tools":[{"type":"x_search"}],"input":"QUERY","max_output_tokens":500}'
# Grok web_search + x_search 同时使用(网页 + X/Twitter 双搜)
curl -s https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"grok-4","tools":[{"type":"web_search"},{"type":"x_search"}],"input":"QUERY","max_output_tokens":500}'
# 解析 Grok 响应:输出文本在 output[].content[].text(type=message 的元素里)
# 引用在 output[].content[].annotations[](type=url_citation)
# 计费: $5 / 1000 tool calls(单独计费)
# Credentials: scripts auto-load via lib/credentials.mjs — do NOT hardcode source ~/.openclaw/.env
⛔ Gate: 每个子问题有至少 2 个 keyword 组合才能开始搜索。
目标: 执行搜索,更新研究地图,发现并评分新线索。
步骤:
RESEARCH_PRO_RUN_ID 时自动写 calls.jsonl{baseDir}/scripts/search_with_trace.sh --query "..." --hint quick --sub-q Q1 --round 1node {baseDir}/scripts/trace.mjs lookup-search 做 exact cache lookup;只有 miss/stale 才调用 backend,结果 JSON 落盘后用 node {baseDir}/scripts/trace.mjs record-search --file /tmp/r.json --source host-native --sub-q Q1 --round 1 --force-raw。web_search / web_extract:必须通过 Step 1.0b 的 host_native_trace.py bridge;不要直接调用后再补记,因为 data.web 需要标准化且 raw 必须在输出前落盘。x_search 等没有 bridge 的 host tool:把完整 JSON 保存后用上面的 record-search --file ... --force-raw;(委托 worker 使用 --source delegated)。线索评分:
| 分 | 标准 | 动作 |
|---|---|---|
| 3 | 直接回答子问题,或根本改变核心目标理解 | 立即追 |
| 2 | 与核心目标相关,但是支线 | 加入线索池,本轮后追 |
| 1 | 边缘相关,不影响核心目标 | 记录但不追 |
| 0 | 不相关或重复 | 忽略 |
Critic(每轮必做):
Reflection(每轮必做,1-2 句):
"本轮最重要的新发现是什么?哪个假设被推翻或加强?下一轮优先追什么?"
更新研究地图中的"当前假设"。
自我校准规则:
Token 管理:
每轮 Phase 3 完成后(或 Phase 1 检查发现重大问题时)执行:
1. 方向转变检查(最优先)
2. 覆盖检查
2b. Deep 收敛前置(仅 Deep 深度;不满足不得进入输出)
3. 轮次上限
A. Finalize per-run trace(优先):
node {baseDir}/scripts/trace.mjs finalize \
--run-id "$RESEARCH_PRO_RUN_ID" \
--confidence high \
--summary "一句话结论" \
--tools-used tavily,grok_web \
--tools-contributed tavily \
--report-file /path/to/report.md # optional
# 同时写入 $RESEARCH_PRO_HOME/run-log.jsonl 一行摘要
B. 兼容:手动 append 一行 JSONL(若无 run_id):
RESEARCH_PRO_HOME="${RESEARCH_PRO_HOME:-$HOME/.config/research-pro}"
mkdir -p "$RESEARCH_PRO_HOME"
echo '{...}' >> "$RESEARCH_PRO_HOME/run-log.jsonl"
可选清理(不阻塞):node {baseDir}/scripts/trace.mjs prune --days 14
JSONL 字段(完整):
{
// 基础
"ts": "2026-04-13",
"question": "简短问题摘要",
"depth": "standard",
"rounds": 3,
"sub_questions": 3,
"direction_change": false,
"confidence": "high",
// 工具追踪
"tools_used": ["tavily", "grok_x", "perplexity"],
"tools_contributed": ["tavily", "grok_x"],
"tools_planned_not_used": ["youtube"],
"tool_calls": {"tavily": 4, "grok_x": 1, "perplexity": 1},
"signals_matched": ["S1", "S3"],
// 质量
"citations": 22,
"gaps": 0,
// Token & 费用(从 API 响应中提取)
"tokens": {
"grok": {"in": 4312, "out": 1696, "calls": 1},
"perplexity": {"in": 850, "out": 420, "calls": 1},
"tavily": {"calls": 4},
"firecrawl": {"calls": 0},
"youtube": {"calls": 0},
"dataforseo": {"calls": 0}
},
"cost_usd": {
"grok": 0.035,
"perplexity": 0.002,
"tavily": 0,
"total": 0.037
}
}
Token 数据提取方式:
# Grok — 响应自带(精确)
# response.usage.input_tokens / output_tokens / cost_in_usd_ticks
# cost_in_usd_ticks 除以 1,000,000,000 = USD
# Perplexity via OpenRouter — 响应自带(精确)
# response.usage.prompt_tokens / completion_tokens
# Tavily / Firecrawl / YouTube / DataForSEO — 只记调用次数
字段说明:
tools_used: 实际调用了的工具tools_contributed: 结果进入了最终报告的工具(关键指标)tools_planned_not_used: 计划用但没用的(信号误匹配)tool_calls: 每个工具调了几次(不只是用/没用)signals_matched: 触发了哪些 S1-S6 信号sub_questions: 拆了几个子问题direction_change: 是否触发了方向转变(Phase 4.1)confidence: 最终结论的整体置信度tokens: 每个 API 工具的精确 token 消耗cost_usd: 换算成美元的费用(grok 从 cost_in_usd_ticks 算,perplexity 按费率算)gaps: 未解决缺口数量Phase 1 开始前,检查日志行数:
RESEARCH_PRO_HOME="${RESEARCH_PRO_HOME:-$HOME/.config/research-pro}"
wc -l < "$RESEARCH_PRO_HOME/run-log.jsonl" 2>/dev/null || echo 0
如果行数是 10 的倍数且 > 0,在 Phase 1 之前输出复盘:
复盘必须回答这 5 个问题:
复盘格式:
📊 research-pro 复盘(过去 10 次)
工具效率:
- tavily: 10/10 用 → 8/10 贡献 (80%) ✅ 主力稳定
- grok_x: 3/10 用 → 3/3 贡献 (100%) ⚠️ 命中率高但触发太少
- youtube: 2/10 用 → 0/2 贡献 (0%) ⚠️ 考虑降优先级
信号调整建议:
- S1 扩大触发词(加入"争议"、"吐槽")
- S4 对 YouTube 改为可选而非默认
Token & 费用:
- 总计: ~58K tokens, $0.42
- 平均/次: ~5.8K tokens, $0.042
- grok: 15K tokens ($0.35) — 占总费用 83%,但贡献了 40% 关键发现
- perplexity: 8K tokens ($0.07) — 性价比高
整体:gaps 平均 0.3/次 → 质量良好
复盘只输出,不阻塞研究流程。
用户直接调用:
"帮我研究 [主题]" → 自动进入 Phase 1
深度默认 Standard(5轮)
Agent 结构化调用:
{
"question": "...",
"depth": "quick|standard|deep",
"context": "已知背景,跳过部分 Phase 1"
}
复盘调用(随时可用):
"复盘 research-pro" 或 "research-pro review"
→ 读 run-log.jsonl,输出复盘分析(不需要凑够 10 次)
Phase 1 结束时先输出一行状态:
合同:accepted(anchor:[短语/路径])| 深度:Standard(最多5轮)| 子问题:Q1, Q2, Q3 | 如需调整范围或深度请说明
最终报告格式:
---
type: research-report
question: "原始问题"
search_contract_state: CONTRACT_ACCEPTED|NARROW_SELFCHECK
search_contract_anchor: "用户原话短语或本地路径"
core_goal: "一句话核心目标"
depth: standard
rounds: 2
tools: [tavily, grok_web, grok_x]
signals: [S1, S2, S3]
confidence: high
date: YYYY-MM-DD
---
# [核心目标一句话]
> **结论:** 1-3 句直接回答。
## 发现
### Q1: [子问题]
| 维度 | 内容 |
|------|------|
| 答案 | ... |
| 置信度 | 高/中/低 |
| 证据强度 | 强/中/弱 |
| 关键来源 | [名称](URL), [名称](URL) |
### Q2: [子问题]
(同样表格格式,每个子问题结构统一)
## 对比矩阵
(如果是比较类问题,用表格并排展示差异)
| 维度 | A | B | C |
|------|---|---|---|
| ... | ... | ... | ... |
## 争议点
| 观点 A | 观点 B | 来源 |
|--------|--------|------|
| [主张] | [反面主张] | [URL] vs [URL] |
## 来源清单
| # | 来源 | 类型 | 证据强度 | 贡献 |
|---|------|------|---------|------|
| 1 | [title](URL) | 博客/论文/Reddit/X | 强/中/弱 | Q1, Q2 |
| 2 | ... | ... | ... | ... |
## 缺口
- [ ] 未解决的部分(如有,无则省略此节)
## 元数据
| 指标 | 值 |
|------|-----|
| 轮次 | N |
| 来源数 | M |
| 工具 | Tavily ×N, Grok web ×N, ... |
| Grok tokens | in: Nk, out: Nk |
| 费用 | $X.XX |
格式规则:
禁止:
accepted-selfcheck 或任何内部清晰度判断绕过交互式确认.env / secret 值必须:
--require-ready(或等价 JSON + 自行 fail-closed)CONTRACT_ACCEPTED 才能进入 Phase 2NARROW_SELFCHECK 仅限一个用户提供 URL/文件的读取、提取或摘要;不得进入 Phase 2 或扩展为跨源研究anchor_evidenceneeds_input block目的: 保留每次搜索结果供 checking / debugging / backend 对比。不进对话上下文,不挡搜索。
| Env | 默认 | 含义 |
|---|---|---|
RESEARCH_PRO_TRACE | light | off 关闭 / light 只记摘要+top urls / full 另存 raw JSON(截断) |
RESEARCH_PRO_RUN_ID | — | 当前 run;init 后 export |
RESEARCH_PRO_HOME | ~/.config/research-pro | 根目录 |
RESEARCH_PRO_TRACE_TOP_N | 10 | light 保留 url 数 |
RESEARCH_PRO_TRACE_MAX_RAW_BYTES | 200000 | full raw 上限 |
目录:
$RESEARCH_PRO_HOME/runs/<run_id>/
run.json # 问题、depth、status、tool 计数
calls.jsonl # 每次搜索 1 行
raw/<call_id>.json # 仅 full 模式
report.md # finalize 时可选
current-run.json # 最近 run 指针
run-log.jsonl # 跨 run 摘要(兼容旧 Phase 5)
calls.jsonl 字段: ts, run_id, call_id, query, hint, requested_tool, actual_tool, degraded, elapsed_ms, result_count, status, error, urls_top[], raw_path, sub_q, round, source
CLI:
node {baseDir}/scripts/trace.mjs init|append|record-search|lookup-search|finalize|prune|status
node {baseDir}/scripts/search_with_trace.sh --query "..." --hint quick
规则:
prune;不自动删除非显式调用搜索对比(可选任务): 同一 query 用不同 --hint 各跑一遍,读同一 calls.jsonl 比 urls_top / degraded / elapsed_ms。
degraded=true 意味着结果不匹配请求的 hint 类型,不能当强证据用$RESEARCH_PRO_HOME/runs/<id>/calls.jsonl 与 run-log.jsonl;smart-search 全局 log 仍在 ~/.hermes/logs/smart-search.jsonl(仅 Hermes 平台)当 smart-search 返回 degraded: true 时:
realtime 降级 → 不要声称"最新"信息social 降级 → 不要声称"社区/X 上说"scrape 降级 → 不要声称"页面内容显示"什么时候停止搜索:
什么时候需要补搜:
smart-search 是纯工具层,research-pro 是方法论层。smart-search 不判断研究是否充分,research-pro 不指定固定 backend。
| 查询类型 | 最佳 hint | 降级 fallback | 原因 |
|---|---|---|---|
| 快速事实(EN) | quick | — | Tavily ~1.5s,稳定 |
| 快速事实(CN) | quick | — | Tavily 中文可用 |
| 实时新闻 | realtime | quick(降级!) | 只有 Grok 有实时搜索 |
| X/Twitter 讨论 | social | — | 只有 Grok x_search |
| 已知 URL | scrape | quick(降级!) | Firecrawl 完整抓取 |
| Reddit 讨论 | community | — | Tavily site:reddit.com |
| 深度报告 | deep | official,community | Tavily Research ~42s |
| 视频教程 | video | quick | YouTube Data API |
| SEO/关键词 | serp | quick | DataForSEO |
| 场景 | Combo | 并行工具 |
|---|---|---|
| 值不值得集成 | official,community,realtime | 官方文档 + Reddit + 新闻 |
| 新技术调研 | deep,realtime,community | 深度报告 + 实时 + 社区 |
| 产品/市场分析 | serp,social,community | SEO + X/Twitter + Reddit |
| 教程 + 实操 | quick,video,scrape | 搜索 + 视频 + 页面抓取 |
DataForSEO $0.30 < Grok $5 < Firecrawl $5.3 < Tavily $8
smart-search 不做:
research-pro 不做:
tvly/curl 直接搜)