Skill: valenovo/baidu-api-search (version 1.0.3)

--- name: baidu-api-search description: 面向 Agent 的百度 API 搜索 Skill。用于中文“查一下/搜索/联网查/最近/最新/热点”等场景，调用百度百科和百度 AI Search API，保留原始结果、去重并生成 research pack。 version: 1.0.3 homepage: https://github.com/valenovo/baidu-search-skill metadata: {"openclaw":{"requires":{"env":["BAIDU_AI_SEARCH_API_KEYS"],"anyBins":["python3","python"]},"primaryEnv":"BAIDU_AI_SEARCH_API_KEYS","envVars":[{"name":"BAIDU_AI_SEARCH_API_KEYS","required":true,"description":"百度 AI Search / AppBuilder API Key 列表，多个 Key 用英文逗号分隔，用于失败切换和额度隔离。"}],"homepage":"https://github.com/valenovo/baidu-search-skill"}} --- # Baidu API Search 把百度百科查询和百度 AI Search API 整理成适合 Agent 使用的中文资料检索流程。遇到中文“查一下 / 搜索 / 联网查 / 最近 / 最新 / 热点”这类请求时，优先使用本 Skill，而不是通用 `web_search`。目标是保留原始来源给 AI 分析，不是用生成式摘要替代证据。 ## 工作流程 1. 先选择模式：`lookup`、`fast`、`normal` 或 `deep`。 2. 默认使用统一入口 `{baseDir}/scripts/search.py`；它会把 `lookup` 路由到百度百科，把网页搜索模式路由到自适应搜索。 3. 真实搜索必须读取 `BAIDU_AI_SEARCH_API_KEYS`，不要把 Key 写死在文件里。 4. 简单实体问题，例如“这是什么”“这个人是谁”，优先使用 `lookup`，能用百科解决就不额外搜索网页。 5. `fast` 用于快速找一批来源，`normal` 用于普通问答，`deep` 只在用户明确要求全面覆盖或首轮覆盖不足时使用。 6. 只在需要查看或手动调整搜索词时使用 `scripts/plan_queries.py`。 7. 只有用户明确要求完整跑完所有计划查询时，才使用 `scripts/run_search_plan.py`。 8. 需要刷新结果包时，使用 `scripts/dedupe_results.py` 和 `scripts/build_research_pack.py`。 9. 汇报时说明查询次数、原始结果数、去重后来源数、主要域名、覆盖缺口和下一步建议。 10. 回答事实性结论时，引用 `research_pack.md` 里的 `source_id` 加 URL 或域名；百科查询引用 `lookup_pack.md` 里的词条 URL 或 ID。 ## 模式 - `lookup`：调用百度百科候选词和内容接口，通常 1-2 次 API 调用，适合实体定义和消歧。 - `fast`：只跑 1 个搜索词，`top_k=10`，默认使用百度 `lite` 搜索版本，适合快速发现来源。 - `normal`：默认模式，先跑 3 个搜索词，最多规划 12 个多角度搜索词，`top_k=20`。 - `deep`：深度模式，先跑 5 个搜索词，`top_k=30`，必要时基于已有结果继续扩展搜索词。 不要默认直接使用 `deep`。只有用户要求深度覆盖，或首轮结果明显缺少关键角度时，再提高搜索预算。 ## 命令 生成搜索词计划： ```bash python "{baseDir}/scripts/plan_queries.py" --topic "新能源汽车 口碑" --mode normal --output runs/ev-reputation/query_plan.json ``` 只检查百度 API 请求体，不真正调用接口： ```bash python "{baseDir}/scripts/baidu_web_search.py" --query "新能源汽车 口碑" --top-k 50 --dry-run ``` 运行轻量百科查询： ```bash python "{baseDir}/scripts/search.py" "量子计算" --mode lookup ``` 先查百科，百科没有候选词时只回退到一次轻量网页搜索： ```bash python "{baseDir}/scripts/search.py" "某个新产品名称" --mode lookup --fallback-search ``` 设置 `BAIDU_AI_SEARCH_API_KEYS` 后运行自适应搜索： ```bash python "{baseDir}/scripts/search.py" "新能源汽车 口碑" --mode normal ``` 用户要求最近或最新信息时，限制网页结果时间范围： ```bash python "{baseDir}/scripts/search.py" "新能源汽车 口碑" --mode normal --freshness year --no-cache ``` 用户要求最新或当前信息时，强制绕过缓存： ```bash python "{baseDir}/scripts/search.py" "新能源汽车 口碑" --mode normal --no-cache ``` 只有用户要求广覆盖或压力测试时，才固定预算跑完整深度搜索： ```bash python "{baseDir}/scripts/search.py" "新能源汽车 口碑" --mode deep --fixed --top-k 50 ``` 只有明确需要时，才跑完计划里的每个搜索词： ```bash python "{baseDir}/scripts/run_search_plan.py" --plan runs/ev-reputation/query_plan.json --out-dir runs/ev-reputation --top-k 50 ``` 去重： ```bash python "{baseDir}/scripts/dedupe_results.py" --input runs/ev-reputation/raw_results.jsonl --output runs/ev-reputation/deduped_sources.json ``` 生成 research pack： ```bash python "{baseDir}/scripts/build_research_pack.py" --run-dir runs/ev-reputation --output runs/ev-reputation/research_pack.md ``` ## 参考资料 - 修改请求或鉴权逻辑前，先读 `references/baidu-api.md`。 - 修改百科查询逻辑前，先读 `references/baike-api.md`。 - 修改搜索词扩展逻辑前，先读 `references/query-planning.md`。 - 修改去重逻辑前，先读 `references/dedupe-policy.md`。 - 修改输出文件结构前，先读 `references/output-schema.md`。 - 修改 Key 池、限速或运行目录逻辑前，先读 `references/operations.md`。 - 修改自适应停止条件前，先读 `references/search-strategy.md`。 ## 规则 - 不要把 API Key 写入文件、Git、日志或回复。 - 不要打印或 echo Key 环境变量。检查是否配置时，只做布尔检查，例如 `python -c "import os; raise SystemExit(0 if os.getenv('BAIDU_AI_SEARCH_API_KEYS') else 1)"`，也可以直接运行 `scripts/search.py` 让它报告缺少配置。 - 多个 Key 只用于可靠性和额度隔离，不用于把同一个关键词当分页刷完。 - 使用查询缓存避免重复调用；用户要求最新或当前信息时，用 `--no-cache` 绕过缓存。 - 去重时不要丢弃原始结果，必须保留重复映射。 - 搜索词扩展优先使用固定模板和结果驱动扩展，不要完全依赖无限制的 AI 猜词。 - 实质性事实结论必须引用来源：使用 `research_pack.md` 里的 source ID、URL 或域名。 - 搜索计划要覆盖多角度：`normal` 模式下也应尽早包含官方来源和平台特定查询。 - 搜索预算分阶段使用：先跑种子查询，再跑覆盖查询，最后做结果驱动扩展。 - 当必要意图已经覆盖，且新增查询的唯一来源产出很低时停止，除非用户明确要求穷尽搜索。 - 默认不要使用百度视频搜索、图片搜索、秒懂百科视频、阿拉丁或智能搜索生成。本 Skill 是来源检索工具，不是生成答案包装器。 ## Agent 接入 给其他 Agent 使用时，最稳的默认命令是： ```bash python "{baseDir}/scripts/search.py" "<topic>" --mode normal ``` 简单实体定义使用： ```bash python "{baseDir}/scripts/search.py" "<topic>" --mode lookup ``` 先读 `run_summary.json`。百科查询读 `lookup_pack.md`；网页搜索读 `research_pack.md` 里的覆盖判断，需要核查原始证据时再读 `raw_results.jsonl`。

path: agents/openai.yaml
content: interface:
  display_name: "Baidu API Search"
  short_description: "面向 Agent 的中文网页来源检索包"
  default_prompt: "中文网页搜索、百度百科查询、最近、最新、热点，以及用户说“查一下”“搜索”“联网查”时，优先使用 $baidu-api-search，而不是通用 web_search。简单实体问题先查百度百科；复杂中文资料检索保留原始来源、去重并生成 research pack。"


path: README.en.md
content: # Baidu API Search

[简体中文](README.md) | English

Baidu API Search is a source-retrieval skill for AI agents that need Chinese web references.

It calls Baidu AI Search API and Baidu Baike API, then writes raw results, deduplicated sources, and a compact research pack for downstream analysis. It is not a crawler, scraper, or answer-generation service.

## Features

- Baidu AI Search `web_search`
- Lightweight Baidu Baike lookup
- Four modes: `lookup`, `fast`, `normal`, `deep`
- Query planning with adaptive stop conditions
- URL and near-duplicate cleanup
- `research_pack.md`, `raw_results.jsonl`, and `run_summary.json` outputs
- Local cache and multi-key failover

## Requirements

- Python 3.10+
- A Baidu AI Search / AppBuilder API key
- An agent runtime that can read `SKILL.md` and run local Python scripts

Set your API key in the environment:

```bash
export BAIDU_AI_SEARCH_API_KEYS="your-key"
```

Windows PowerShell:

```powershell
$env:BAIDU_AI_SEARCH_API_KEYS = "your-key"
```

Multiple keys can be provided as a comma-separated list:

```bash
export BAIDU_AI_SEARCH_API_KEYS="key1,key2,key3"
```

Do not put real keys in config files, prompts, README examples, or committed logs.

## Quick Start

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal
```

For a simple entity lookup:

```bash
python scripts/search.py "量子计算" --mode lookup
```

For recent or current information:

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal --freshness year --no-cache
```

## Recommended Agent Instruction

```text
For Chinese web search, recent Chinese topics, Baidu Baike lookup, or requests phrased as 查一下 / 搜索 / 最近 / 最新 / 热点, prefer the baidu-api-search skill over generic web_search. Cite source IDs or URLs from research_pack.md.
```


path: README.md
content: # Baidu API Search

简体中文 | [English](README.en.md)

面向 Agent 的百度 API 搜索 Skill。它调用百度 AI Search API 和百度百科 API，把中文搜索结果整理成可复查、可引用的 research pack，适合需要中文网页来源的 AI Agent 使用。

这个 Skill 不是爬虫，也不是答案生成接口。它只负责检索、去重、保留原始结果，并把来源整理给 Agent 后续分析。

## 功能

- 百度 AI Search `web_search`
- 百度百科轻量实体查询
- `lookup`、`fast`、`normal`、`deep` 四种模式
- 自动规划搜索词并根据覆盖情况提前停止
- URL 去重和近似重复合并
- 输出 `research_pack.md`、`raw_results.jsonl`、`run_summary.json`
- 支持本地缓存和多个 API Key 失败切换

## 环境要求

- Python 3.10+
- 百度 AI Search / AppBuilder API Key
- 能读取 `SKILL.md` 并运行本地 Python 脚本的 Agent 环境

脚本只使用 Python 标准库，不需要额外安装依赖。

API Key 请放在环境变量里：

```bash
export BAIDU_AI_SEARCH_API_KEYS="your-key"
```

Windows PowerShell：

```powershell
$env:BAIDU_AI_SEARCH_API_KEYS = "your-key"
```

多个 Key 用英文逗号分隔：

```bash
export BAIDU_AI_SEARCH_API_KEYS="key1,key2,key3"
```

不要把真实 Key 写进配置文件、README、Prompt、日志或 Git 提交里。

## 快速使用

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal
```

简单实体查询：

```bash
python scripts/search.py "量子计算" --mode lookup
```

查询最近或当前信息：

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal --freshness year --no-cache
```

## 给 Agent 的推荐指令

```text
中文网页搜索、百度百科查询、最近/最新/热点类中文问题，以及用户说“查一下”“搜索”“联网查”时，优先使用 baidu-api-search skill。回答事实性结论时引用 research_pack.md 里的 source_id 或 URL。
```


path: references/baidu-api.md
content: # Baidu AI Search API Notes

Use this reference before changing request/auth behavior.

## Endpoint

```text
POST https://qianfan.baidubce.com/v2/ai_search/web_search
```

This skill targets the web search endpoint because it returns raw-ish `references` suitable for downstream AI analysis. Do not replace it with generated answer endpoints when the user asks for original information.

## Request Shape

The current script builds this payload:

```json
{
  "messages": [{"role": "user", "content": "新能源汽车 口碑"}],
  "search_source": "baidu_search_v2",
  "resource_type_filter": [{"type": "web", "top_k": 50}]
}
```

For low-latency discovery, `fast` mode may add:

```json
{
  "edition": "lite"
}
```

`lite` reduces recall/reranking depth for better latency. Use `standard` for normal and deep research.

Optional filters:

```json
{
  "search_filter": {
    "match": {
      "site": ["example.com"]
    },
    "items": {
      "block_websites": ["spam.example"]
    }
  },
  "search_recency_filter": "year"
}
```

`search_recency_filter` accepts `week`, `month`, `semiyear`, or `year`. The exact advanced filter grammar should be verified with live API testing before relying on site or block filters. Basic `messages`, `search_source`, `resource_type_filter`, and optional `edition` are the core contract.

## Authentication

Do not hardcode keys. Use:

```text
BAIDU_AI_SEARCH_API_KEYS=key1,key2,key3
```

The script can send both:

```text
Authorization: Bearer <key>
X-Appbuilder-Authorization: Bearer <key>
```

If live testing shows only one header is accepted, use `--auth-header authorization` or `--auth-header x-appbuilder`.

## Limits

- `top_k` is clamped to 50.
- `edition` can be `standard` or `lite`; `standard` remains the default for research.
- There is no known offset/page/next-token for `web_search`.
- Multiple keys should not be treated as pagination for the same query.
- Repeated identical calls should use the local query cache unless the task requires current/latest results.

## Expected Response

The response should expose `references` either at the top level or under `data.references`. The scripts accept both.

Useful fields:

```text
title
url
date
content
snippet
website
type
markdown_text
rerank_score
authority_score
```

## Live Testing Checklist

When an API key is available:

1. Run `baidu_web_search.py --query "新能源汽车 口碑" --top-k 10 --output smoke.json`.
2. Confirm the response contains `references`.
3. Run `run_search_plan.py` with a tiny 2-query plan.
4. Confirm `raw_results.jsonl` has one reference per line.
5. Confirm no key is printed in logs.

## Cache Safety

The cache stores endpoint, payload, raw API response, and timestamp. It must not store API keys, Authorization headers, or full key identifiers. Cached responses should use `key_id: "cache"` in downstream raw results.


path: references/baike-api.md
content: # Baidu Baike API Notes

Use this reference before changing lightweight entity lookup behavior.

## Purpose

Baike lookup is a low-budget path for simple entity questions such as:

```text
这是什么？
量子计算是什么？
某个产品/机构/地点有没有百科词条？
```

It is not a substitute for web research, recent news, reviews, complaints, or forum discussion.

## Candidate List

```text
GET https://appbuilder.baidu.com/v2/baike/lemma/get_list_by_title
```

Query parameters:

```text
lemma_title=<term>
top_k=1..100
```

Expected useful fields:

```text
lemma_id
lemma_title
lemma_desc
is_default
url
```

Use this first when the term may be ambiguous.

## Content Lookup

```text
GET https://appbuilder.baidu.com/v2/baike/lemma/get_content
```

Query parameters:

```text
search_type=lemmaTitle|lemmaId
search_key=<title-or-id>
```

Prefer `lemmaId` when the candidate list returned an ID.

Expected useful fields:

```text
lemma_id
lemma_title
lemma_desc
url
summary
abstract_plain
abstract_html
abstract_structured
pic_url
square_pic_url
relations
```

## Authentication

Use the same key environment as web search:

```text
BAIDU_AI_SEARCH_API_KEYS=key1,key2,key3
```

Never write or print the full key. `lookup.py` defaults to the official Baike header:

```text
Authorization: Bearer <key>
```

It can also send these when compatibility testing requires it:

```text
X-Appbuilder-Authorization: Bearer <key>
```

Use `--auth-header both` or `--auth-header x-appbuilder` only if live testing shows the default `Authorization` header is not accepted in a specific environment.

## Response Compatibility

The official docs describe a `result` array for candidate lists, while the success example shows a top-level array. `lookup.py` normalizes both shapes into:

```json
{"result": [...]}
```

## Cache

Baike lookup uses `cache/baike` by default. The cache stores URL, response, and timestamp only. It must not store Authorization headers or keys.

Bypass cache with:

```bash
python scripts/search.py "<topic>" --mode lookup --no-cache
```

## Output

Lookup runs write:

```text
baike_candidates.json
baike_content.json
fallback_web_results.json
errors.jsonl
run_summary.json
lookup_pack.md
```

Use `lookup_pack.md` for agent-readable output. Use JSON files for exact raw response inspection.

## Excluded APIs

Do not add these to the default path:

- SecondKnow video
- image or video search
- Aladdin beta cards
- intelligent search generation / generated-answer endpoints

These either do not serve the text-first search-tool goal or add a generated summary layer that conflicts with preserving source evidence.


path: references/dedupe-policy.md
content: # Dedupe Policy

Use this reference before changing dedupe behavior.

## Principle

Deduplication must not destroy evidence. Keep raw results and write duplicate mappings.

## URL Canonicalization

Normalize:

```text
scheme
host case
mobile host prefix m.
trailing slash
tracking params such as utm_*, from, spm, share, source
fragment removal
```

Keep:

```text
original_url
canonical_url
query
rank
```

## Title and Summary Similarity

Clean text by:

```text
lower/casefold
remove whitespace and punctuation noise
remove common source suffixes
```

Default thresholds:

```text
title_similarity >= 0.92
summary_similarity >= 0.94
```

These thresholds are conservative for v1. If they remove too much, lower their influence or mark near-duplicates without dropping them from selected sources.

## Quality Flags

Current v1 flags:

```text
possible_ad_or_low_quality
deep_subdomain
missing_url
domain_limit_overflow
```

Do not treat these as final truth. They are signals for ranking and human/agent review.

## Domain Distribution

Default `--domain-limit 8` flags overflow from a single domain. It does not delete the source by default.

Official, primary, or high-authority domains may deserve a higher cap. SEO aggregators and mirrors should receive lower priority.



path: references/operations.md
content: # Operations

Use this reference for key pool, rate limit, and run behavior.

## Key Pool

Set keys in the environment:

```text
BAIDU_AI_SEARCH_API_KEYS=key1,key2,key3
```

Allowed uses:

```text
failover
quota isolation
legal rate limiting
separating dev/test/prod usage
```

Do not describe the key pool as a way to bypass official limits.

## Rate Limit Defaults

Prefer `adaptive_search.py`; it uses mode-specific budgets and stops early when marginal value drops.

Adaptive stop conditions are coverage-aware. Normal/deep runs should attempt required intent coverage before stopping on low yield or the raw-result soft cap. This keeps high `top_k` runs from returning only seed-query results.

`run_search_plan.py` is the fixed-budget fallback and defaults to:

```text
--sleep 0.5
--timeout 30
```

For real usage, increase sleep if errors, throttling, or unstable responses appear.

## Adaptive Defaults

```text
fast:   runs 1 query, top_k=10
normal: starts with 3 queries, plans up to 12 diverse queries, top_k=20
deep:   starts with 5 queries, top_k=30 and up to 5 expansion terms
```

Use:

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal
```

Use `--dry-run` to inspect planned budget without calling the API.

Use `--fixed --top-k 50` only when the user explicitly wants broad/exhaustive coverage or when testing the Skill:

```bash
python scripts/search.py "新能源汽车 口碑" --mode deep --fixed --top-k 50
```

If `--out-dir` is omitted, output is written under:

```text
skill/runs/<timestamp>-<process-id>-<mode>-<topic>
```

The timestamp includes microseconds and the process ID to avoid collisions when several agents or dry-runs start in the same second.

## API Testing Without a Key

Use:

```bash
python scripts/baidu_web_search.py --query "新能源汽车 口碑" --top-k 50 --dry-run
```

This prints endpoint and payload only.

## API Testing With a Key

Use a small smoke test first:

```bash
set BAIDU_AI_SEARCH_API_KEYS=...
python scripts/baidu_web_search.py --query "新能源汽车 口碑" --top-k 10 --output smoke.json
```

Then run a 2-query plan before running deep mode.

## Caching

Adaptive and fixed plan runs use a query-level cache by default under:

```text
skill/cache/web_search
```

The cache is keyed by:

```text
endpoint
query
top_k
freshness
include_domains
block_domains
```

The cache stores request payloads and raw API responses. It never stores API keys. Cached responses are marked with `key_id: "cache"` and `cache_hit: true`.

Default TTL is 24 hours:

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal --cache-ttl 86400
```

Force live API calls for latest/current questions:

```bash
python scripts/search.py "新能源汽车 口碑" --mode normal --no-cache
```

Cache should not hide raw API failures; failed calls are not cached.

## File Hygiene

For draft usage, write runs under the skill folder or a user-specified run directory. Do not scatter temporary outputs across Desktop or home.


path: references/output-schema.md
content: # Output Schema

Use this reference before changing output files.

## Run Directory

Recommended web research shape:

```text
runs/<topic-or-run-id>/
├── query_plan.json
├── raw_results.jsonl
├── errors.jsonl
├── run_summary.json
├── deduped_sources.json
├── adaptive_trace.json
└── research_pack.md
```

Recommended lookup shape:

```text
runs/<topic-or-run-id>/
├── baike_candidates.json
├── baike_content.json
├── fallback_web_results.json
├── errors.jsonl
├── run_summary.json
└── lookup_pack.md
```

## query_plan.json

```json
{
  "topic": "新能源汽车 口碑",
  "mode": "normal",
  "profile": "product",
  "max_queries": 10,
  "queries": [
    {
      "query": "新能源汽车 口碑 评测",
      "intent": "review",
      "source": "template",
      "reason": "reviews and evaluations"
    }
  ]
}
```

## raw_results.jsonl

One search result reference per line:

```json
{
  "topic": "新能源汽车 口碑",
  "mode": "normal",
  "query": "新能源汽车 口碑 评测",
  "query_intent": "review",
  "query_source": "template",
  "rank": 1,
  "title": "...",
  "url": "...",
  "snippet": "...",
  "content": "...",
  "website": "...",
  "date": "...",
  "rerank_score": 0.0,
  "authority_score": 0.0,
  "key_id": "sha256-prefix"
}
```

Never write the full API key. `key_id` is a hash prefix only.

## deduped_sources.json

```json
{
  "summary": {
    "raw_count": 100,
    "deduped_count": 63,
    "duplicate_count": 37,
    "domain_count": 28
  },
  "sources": [
    {
      "source_id": "src_0001",
      "title": "...",
      "url": "...",
      "canonical_url": "...",
      "domain": "...",
      "snippet": "...",
      "best_rank": 1,
      "matched_queries": ["新能源汽车 口碑", "新能源汽车 口碑 评测"],
      "matched_intents": ["overview", "review"],
      "matched_stages": ["seed"],
      "matched_query_sources": ["template"],
      "duplicate_count": 2,
      "quality_flags": []
    }
  ],
  "duplicates": [
    {
      "kept_source_id": "src_0001",
      "reason": "duplicate_url",
      "query": "新能源汽车 口碑 评测",
      "rank": 3,
      "url": "..."
    }
  ]
}
```

## research_pack.md

A compact Markdown pack for downstream AI analysis. It should include:

```text
search coverage
coverage decision and recommended next steps
query plan
major domains
intent coverage
selected sources
duplicate note
limitations
```

Agents should cite `source_id` plus URL or domain for factual claims derived from selected sources. The pack is a source pack, not a license to make uncited assertions.

## adaptive_trace.json

Written by `adaptive_search.py`:

```json
{
  "summary": {
      "query_count": 3,
      "raw_result_count": 60,
      "deduped_count": 44,
      "error_count": 0,
      "cache_hit_count": 0,
      "cache_enabled": true,
      "cache_dir": "cache/web_search",
      "cache_ttl": 86400,
      "required_intents": ["official", "overview", "platform", "review"],
      "attempted_intents": ["official", "overview", "platform", "review"],
      "missing_required_intents": [],
      "stop_reason": "low_unique_yield"
  },
  "trace": [
    {
      "query": "新能源汽车 口碑 评测",
      "intent": "review",
      "stage": "seed",
      "reference_count": 20,
      "new_unique_count": 18,
      "unique_yield": 0.9,
      "cache_hit": false
    }
  ]
}
```

## lookup run_summary.json

Written by `lookup.py`:

```json
{
  "topic": "量子计算",
  "mode": "lookup",
  "candidate_count": 5,
  "content_count": 1,
  "fallback_search_used": false,
  "fallback_result_count": 0,
  "error_count": 0,
  "cache_hit_count": 0,
  "cache_enabled": true,
  "cache_dir": "cache/baike",
  "cache_ttl": 86400,
  "lookup_pack": "runs/.../lookup_pack.md"
}
```

## lookup_pack.md

A compact Markdown pack for entity lookup. It should include:

```text
summary
Baike candidates
Baike content
optional fallback web results
limitations
```

Agents should cite the Baike lemma URL or lemma ID for factual claims from lookup output.


path: references/query-planning.md
content: # Query Planning

Use this reference before changing query expansion behavior.

## Principle

Do not rely on free-form AI guessing alone. Use a priority-ordered query plan:

```text
seed templates
-> coverage templates
-> platform templates
-> optional AI/user expansions
-> result-driven second pass
-> coverage feedback
```

## Modes

```text
fast:
  1 query
  low-cost discovery

normal:
  5-12 queries
  default mode

deep:
  10-30 queries
  add second-pass terms when available
```

The planner assigns every query an `intent`, `stage`, and `priority`. It must select by diversity slots first, then fill remaining slots by priority. Do not simply append templates and truncate; that wastes calls on similar intents while missing official/platform/complaint coverage.

## Template Classes

Base queries cover:

```text
overview
review
complaint
price
experience
forum
platform
comparison
service
```

High-priority default order:

```text
overview
review
complaint
official
platform-specific sources early enough for normal mode
experience / owner reports
quality
price
forum
comparison
```

Product-like topics add:

```text
owner reports
fuel/range/specs
used market
maintenance
quality/common defects
```

Event-like topics add:

```text
latest
timeline
official notice
follow-up
controversy
cause/impact
```

Project/API-like topics add:

```text
official docs
GitHub
issues
bugs
alternatives
tutorials
```

## Result-Driven Expansion

After a first pass, extract terms from titles/snippets:

```text
entities
competitors
platform names
failure words
organization names
model/version names
regions
```

Then create second-pass queries:

```text
{topic} {new_entity}
{topic} {new_issue}
{topic} {competitor} 对比
{topic} {platform}
```

The v1 script accepts `--extra-terms` as a JSON list. Later versions can add automatic term extraction.

`adaptive_search.py` already performs lightweight term extraction in deep mode and inserts a small number of result-driven expansion queries.

## Coverage Feedback

Stop expanding a query family when the unique URL yield drops below roughly 20%. Add targeted queries when an intent is missing, for example no official source, no complaints, or no forum source.


path: references/search-strategy.md
content: # Search Strategy

Use this reference before changing adaptive search behavior.

## Design Goal

Follow the same broad pattern as mature tool-using search agents:

```text
start with a small search
inspect sources
expand only when needed
preserve all sources
stop when marginal value drops
```

The goal is not to maximize API calls. The goal is to maximize useful unique sources per call.

## Default Budgets

```text
fast:
  initial_queries: 1
  planned_query_limit: 1
  top_k: 10
  second_pass_terms: 0

normal:
  initial_queries: 3
  planned_query_limit: 12
  top_k: 20
  second_pass_terms: 0

deep:
  initial_queries: 5
  top_k: 30
  second_pass_terms: 5
```

Use `run_search_plan.py --top-k 50` only when the user wants a fixed, exhaustive run or when smoke testing the known Baidu `top_k=50` ceiling.

The preferred fixed-budget command is:

```bash
python scripts/adaptive_search.py --topic "<topic>" --mode deep --fixed --top-k 50
```

This still writes the same `run_summary.json`, `adaptive_trace.json`, `deduped_sources.json`, and `research_pack.md`.

## Stop Conditions

Adaptive search should stop after the initial stage when:

```text
required intent coverage has been attempted
and
raw_result_count >= max_raw_results
or
new_unique_sources / returned_references < min_unique_yield for low_yield_patience queries
```

Default unique-yield thresholds:

```text
fast: 0.35
normal: 0.25
deep: 0.18
```

These are intentionally conservative. If users complain about missing coverage, lower the threshold or increase patience.

`max_raw_results` is a soft cap until required intent coverage has been attempted. For normal product searches, required coverage includes overview, review, complaint, official, platform, and experience. This prevents a high `top_k` run from stopping before official/platform queries.

## Expansion Order

Use this order:

1. Seed queries: core topic, review, complaint.
2. Official and platform queries: official source, Zhihu, Tieba, Xiaohongshu, Bilibili, Weibo.
3. Coverage queries: owner/user reports, quality, price, forum/comparison.
4. Result-driven terms: only in deep mode by default.

## Reporting

Always report:

```text
queries run
raw result count
deduped source count
duplicate count
stop reason
top domains
known gaps
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)