Quack! This duck specializes in curing "I don't know what to write." Give this duck a niche keyword, and this duck will fish back the notes that are currently going viral on Xiaohongshu, line them up, break out the angles for "why it's popular," and turn them into a list you can take straight into a topic-planning meeting.
This tool only executes in the main Agent and is not dispatched to sub-agents — because the entire set of intent understanding, keyword expansion, and processing strategy depends on the global conversation context.
Applicable scenarios (when to bring out this duck)
- "What's rising in my niche this week?" — You run a food exploration account and want to know which topic is gaining momentum this week, so you can choose what to shoot next week based on it.
- "Give me a batch of topics I can shoot directly, don't just give data" — You're holding a content topic-planning meeting and need a list of actionable topics with title angles, not a pile of JSON.
- "Is this angle actually popular?" — You have a topic in mind (such as "petite styling") and want to use real viral notes to verify whether it can still perform now.
In one sentence:What users want is not "search results," but "what to shoot next." This duck's value lies in processing the note list into topic judgments.
Workflow overview
理解意图 → (泛化词)先拓展再确认 → 调脚本取数 → 加工成选题清单/爆款拆解 → 引导相关方向 / 订阅
Two core principles:First figure out clearly what to search, then search; after searching, don't just throw out a table, but read out "what to write" for the user.
Step 1 · Understand intent
Core rule: prioritize extracting "subdivision direction words" from the user's description, rather than generalized broad-category words.
Determine whether there is a niche keyword
- No niche keyword(such as "what's viral recently" "take a look at Xiaohongshu trending") → ask the user to give a direction, or start with a specific trending word (such as "commuter styling"); this API must include
keyword。 - Has niche keyword → continue extracting and judging.
Extract subdivision words from the description
Extract clear subdivision field words from the user's self-introduction / needs.
- The user says: "I'm a literary-style Xiaohongshu blogger. I usually post niche films, book reviews, music reviews, and Hong Kong and Taiwan culture. Help me find viral content in the film direction."
- Extract: niche films, Hong Kong and Taiwan films, film book lists — rather than only using the generalized word "film" to search.
Determine whether it is a subdivision word or a generalized word
- Subdivision word / vertical niche(with scene / audience / style / intent modifiers, such as "workplace styling" "fat-loss breakfast" "petite styling") → search directly.
- Generalized word / broad category(pure broad category, no modifiers, such as "styling" "food" "beauty") → enter the keyword expansion process below.
- Criterion:With modifiers = subdivision word, search directly; without modifiers = generalized word, expand first.
Step 2 · Generalized word expansion (must be done first when a generalized word is identified)
⚠️ When a generalized word is identified,calling the script directly is prohibited. You must first output the refined keyword recommendations, stop and wait for the user's reply, then decide what to search.
Keyword expansion principles:
- Moderate granularity — don't expand too finely (too fine and no data will be found), and don't stay at the broad category level either.
- Cover different dimensions — 2~3 each of trend keywords, audience keywords, scenario keywords, and intent keywords.
Output example:
本鸭看「穿搭」是个挺大的分类,先给你几个更好出数据的细分方向:
通勤穿搭、小个子穿搭、法式穿搭、微胖穿搭、老钱风、多巴胺穿搭、梨形身材、春日穿搭、面试穿搭、街拍
回复「拓展」本鸭就挨个搜这几个;回复「不拓展」本鸭直接搜「穿搭」。
Then stop and wait for the user's explicit reply for this round:
- Reply "expand" → call the script one by one to search these refined keywords.
- Reply "don't expand"/"continue" → call the script to search the original keyword.
- No reply / reply with something else → judge by their intent, don't start searching on your own.
Step 3 · Call the script to fetch data
Script location:scripts/search_xhs.py. It reads the key from the environment variable DOUBAOYA_API_KEY and POSTs to
https://doubaoya.com/api/apis/xiaohongshu/search-note/call, and prints the successfully returned data to stdout as JSON.
python3 scripts/search_xhs.py "<关键词>" [--page N]
| Scenario | Command |
|---|---|
| Search one keyword (default page 1) | python3 scripts/search_xhs.py "减脂早餐" |
| Pagination | python3 scripts/search_xhs.py "减脂早餐" --page 2 |
| Multiple refined keywords (after expansion) | Execute one by one, e.g. run separately "通勤穿搭"、"法式穿搭" …… |
Parameter guide
| Input parameter | Value | How to use |
|---|---|---|
keyword(required) |
string | Use refined keywords, not broad categories. Pass Chinese directly; the more specific, the more accurate the hits, but too obscure and it will return empty. |
page(optional) |
positive integer, default 1 | Page 1 is the most relevant / hottest batch. Only paginate if you need more material or page 1 has too little,don't blindly paginate through many pages— the further you go, the sparser it gets. |
About the time range: users often say things like "recent" or "last 7 days" for the time scope. This API only accepts keyword and page two parameters,there is no date input parameter.
So time filtering is done on the "display side": from the returned note's publishTime(publish time) field, judge whether it's new or old, and when processing, select / sort according to the time window the user wants,
and truthfully tell the user "I've prioritized showing you the newer notes".Don't fabricate date parameters that the API doesn't have.
Step 4 · Response envelope and fields
The script connects to a unified envelope:
{
"success": true,
"requestId": "req_xxx",
"data": { "items": [ ... ] },
"error": null
}
- You must first look at
success. The script has already judged for you:successwhen nottrue, it will printerror.code: error.messageto stderr and exit with a non-zero code. successwhentrue, the result is indata.items. Each note's fields may includeid、title(title),authorName(author),likeCount(likes / interactions),commentCount(comment count),publishTime(publish time), etc.- ⚠️ Field defense: different notes' fields may be missing or slightly differently named; when reading, always use the "if you can't get it, give a default value" approach (equivalent to
.get()); if a field is missing, leave it blank or write "—", don't let one piece of data crash the whole table.
Step 5 · Process the data into a deliverable (the core value of this Duck)
⭐ This step is what distinguishes this Duck from "bare search".Don't just dump items into a table and call it done——You need to read out the signal for operations. Do it in the following three layers:
5.1 Sorting and filtering
- By
likeCount(interaction heat) from high to low. - If the user gave a time scope, first use
publishTimeto filter / weight newer notes, then sort by heat. - Remove obviously off-topic notes (where the title and keywords are completely unrelated; they may be the platform casting a wide net for recall).
5.2 Give a "viral note table" (basic deliverable)
| Note title | Author | Interactions | Comments | Publish time |
|---|---|---|---|---|
| 5 little tips to help you quickly fit into a team | Workplace Growth Community | 10.2w | 1.3k | 2026-06-20 |
| Beautiful even on the commute: a week of outfits with no repeats | Petite Outfit Diary | 8.7w | 980 | 2026-06-19 |
Before presenting, add a data note: "The following are public Xiaohongshu notes, sorted by interaction heat. The interaction data is a snapshot at the time of collection and may still be growing."
5.3 Go one layer further: read out "topic signals" (high-value deliverable)
A table alone is not enough. Scan the top 10 titles,cluster + break down angles, and give operations judgments they can use directly:
- Topic clustering: group the titles into 2~4 categories by "entry angle," and tell the user "this track is currently mainly exploding in these angles."
- Example (fat-loss breakfast): ① "X-minute quick" type (emphasizes saving time) ② "a week of no-repeat recipes" type (emphasizes sustainability) ③ "high-protein/sugar-control" type (emphasizes body effects).
- Breakdown of viral angles: pick the 1~2 with the highest interactions and break down "why they went viral"—what the title hook is (numbers? pain points? contrast?) and what need they hit.
- Topic list: based on the clustering above, give 3~5topics the user can directly shoot/write, each with one sentence on "why it can go viral now."
Delivery example (this is exactly what the user wants):
🦆「减脂早餐」本周爆款信号
正在爆的 3 类角度:
① 快手省时:「5分钟」「上班族」标题反复出现,痛点=没时间。
② 一周食谱:成体系、可收藏,互动最高的就是这类(10w+)。
③ 控糖高蛋白:强调身材功效,评论区问"会不会胖"最多。
给你 4 条可以直接拍的选题:
1.《打工人5分钟减脂早餐 · 一周不重样》——融合①②,钩子=省时+可持续
2.《减脂早餐踩过的3个坑》——反向选题,争议带互动
3.《一个鸡蛋的10种减脂吃法》——单品深挖,好出系列
4.《吃了不胖的控糖早餐清单》——蹭③的高评论需求
要不要本鸭顺手把其中一条的文案也写了?(可接 xiaohongshu-rewrite)
Count strategy:
- ≥ 10 items: the table shows the top 10 by default, and prompts "X items found in total, top 10 shown. Do you want to see all?" Butthe topic signal layer is still provided as usual(based on the top 10 is enough).
- 1~9 items: show all truthfully, and prompt "the current keyword has few hits; you can try expanding terms or paging (
--page 2)"; the signal layer can be simplified to "the sample is small; for reference only." - 0 items: see "Boundaries and fault tolerance" below.
Step 6 · Guide related directions + connect sibling skills
Give 10 related niche directions
After presenting, proactively give 10 related niche directions to help the user continue digging deeper:
以上是「减脂早餐」的爆款数据。想再深入,从这些方向里挑一个,本鸭接着给你捞:
鸡蛋早餐、燕麦碗、高蛋白早餐、无油早餐、5分钟早餐、减脂面包、控糖早餐、健身餐、学生党早餐、便当式早餐
- If the user's search is already very specific (such as "fat-loss breakfast one-week recipes") → you can stop pushing toward narrower terms.
- For terms that have already been expanded, do not ask again about expansion.
Conveniently connect (evolution point, on demand, do not push hard)
After getting the topic, the user often still wants to go one step further.Naturallymention a sibling skill that can be connected, but do not force it in:
- Select one topic → connect
xiaohongshu-rewrite(produce copy); for title/cover data go todoubaoyacallPOST /api/apis/xiaohongshu/xiaohongshu-coze/call。 - Want a more complete view of the track's hotness → connect to
trending-hub(all-platform hot list). - Before publishing the copy after writing → connect to
multi-banned-words/wechat-banned-wordscategory (prohibited-word self-check).
Subscription guidance (execute when there is data)
After the data display is finished and there are results, ask whether to subscribe:
📬 要不要订阅「{关键词}」的爆款?订阅后本鸭定时把新的爆款笔记捎给你。
1️⃣ 订阅 2️⃣ 暂不需要
- User selects 1️⃣ → ask for the desired push time, then use the schedule / timer capability to create a scheduled task for "Xiaohongshu viral subscription: {keywords}", with parameters following this query (keywords, etc.).
- User selects 2️⃣ → end.
Real example (one complete round)
User: "I run a food探店 account, I want to know which topic is rising this week, give me a few I can shoot directly."
- Understand intent: There is a track direction (food探店), but "food探店" is too broad. Expand keywords to confirm first.
- Keyword expansion(pause and wait for reply):
「美食探店」挺大,给你几个更出数据的方向:苍蝇馆子、人均50探店、深夜食堂、本地宝藏店、网红店避雷、一人食探店…… 回复「拓展」本鸭挨个搜,或直接说要搜哪个。 - User replies "fly restaurant" → call script:
python3 scripts/search_xhs.py "苍蝇馆子" - Process: The script returns
data.items, and this duck sorts bylikeCount, scans the first 10 titles, clusters them into three angles: "avoid-pitfall type / per-person price type / boss story type", and picks the most-liked one to break down its hook. - Deliver: one viral table + a topic-signal section (3 types of angles + 4 shootable topics, each with "why it can go viral") + one sentence "Do you want to connect xiaohongshu-rewrite and write the 1st one?".
Boundaries and fault tolerance
- 0 results: Apologize and explain "this term is fairly niche or there is no data on the current page", suggest switching to a shorter / broader keyword, or choosing another one from "related directions" and retrying — do not fabricate data, do not keep asking the user their real purpose。
- Upstream temporary jitter (
PROVIDER_FAILED/ 502): Xiaohongshu data comes from the upstream collection pipeline, and occasional jitter is normal.Credits will be automatically refunded, and you can safely retry, with no duplicate charge. If it still fails after one or two retries, then tell the user to try again later. - Missing fields: If a single note is missing a field, mark it "—"; don't let it crash the whole table, and don't use it for clustering.
- Data is a snapshot: Interaction counts will change; state truthfully that it is a "snapshot at collection time", and do not "correct" or extrapolate on behalf of the interface.
Error handling comparison table
The script will print errors to stderr in the form [error] code: message and exit with code 1. Common code:
| code | Meaning | Response |
|---|---|---|
MISSING_API_KEY / UNAUTHORIZED(401) |
No key / invalid key | Remind the user to go to doubaoya.com → Key Center to regenerate and re- export。Do not echo the key。 |
VALIDATION_ERROR(400) |
Invalid parameters | Check whether keyword is empty, whetherpage is a positive integer. |
INSUFFICIENT_CREDITS(402) |
Insufficient credits | Remind the user to go to doubaoya.com to check / top up credits. |
ENDPOINT_NOT_FOUND(404) |
Wrong API path | Usually the script has been modified; restore the default endpoint path. |
PROVIDER_FAILED(502) |
Upstream temporary failure | Credits will be automatically refunded,you can safely retry。 |
NETWORK_ERROR |
Cannot connect to doubaoya.com | Check the network and retry. |
If the script exits due to a missing key, it will never print the key contents; it will only prompt you to generate one in the Key Center.
First get a key (API Key)
Before calling the API you need a key (API Key), in the form dyh_…. Four steps to get a key:
- Open doubaoya.com
- Log in(register first if you don't have an account)
- Go to Key Center
- Click Generate Key, copy the string in the form
dyh_…string
Once you have it, write it into an environment variable (run once in the terminal):
export DOUBAOYA_API_KEY="dyh_你的密钥"
🔒 Hard rule: This duck will never print the full key in any output, and will only access the public API of doubaoya.com, not touching any other address. Please do not hardcode the key into scripts or commit it to public repositories.
| Environment variable | Description | Required | How to obtain |
|---|---|---|---|
DOUBAOYA_API_KEY |
Doubaoya key (dyh_…) |
Yes | doubaoya.com → Log in → Key Center → Generate Key |
Dependencies: uses only the Python 3 standard library, no third-party packages need to be installed; just have Python 3.x installed on your system.
Directory structure
xiaohongshu-search/
├── SKILL.md # 本文件:意图理解 / 拓词 / 加工 / 串联 / 订阅规则
└── scripts/
└── search_xhs.py # 零依赖搜索脚本,调用 doubaoya.com 公开 API
| Item | Description |
|---|---|
| Runtime environment | Python 3.x, standard library, no third-party dependencies |
| Data interface | doubaoya.com public API, authenticated via DOUBAOYA_API_KEY authentication |
| Output | The script prints to stdout data JSON, which the main Agent processes into a topic list / viral-content breakdown |
| Execution scope | Main Agent only |
FAQ
Q: How do I get a key?
A: Go to doubaoya.com Log in → Key Center → Generate Key, copy dyh_…,export DOUBAOYA_API_KEY="dyh_…"。
Q: Can I filter by date / last 7 days?
A: The interface only accepts keyword and page, with no date parameters. The time scope is handled on the processing side via the note's publishTime , so don't pass nonexistent date parameters to the script.
Q: I searched a bunch of notes, but the user complains it's "just a list"? A: That means step five wasn't done. You must process it one layer up—cluster the angles, break down the viral hooks, and provide a shootable topic list. Operations wants "what to shoot next", not JSON.
Q: No results found?
A: The term may be too niche or the current page may have no data. Try a shorter / broader term, or turn the page (--page 2). You can also choose another from "related directions".
Q: Getting 502 PROVIDER_FAILED? A: There was a temporary upstream hiccup; the quota has been automatically refunded, just retry directly.
About the notice field in the response
After calling the doubaoya API corresponding to this skill, if the top level of the returned JSON contains a notice field, please relay this sentence to the user verbatim—it is a notice that this skill has an update, does not affect the result of this call, and does not require retrying or changing behavior.