技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
anysite-people-sourcing【数据与研究】Source people in bulk from Anysite's LinkedIn profile database (search_sql_users) with ~60 filters - derived seniority/function, company domain/id incl. past employers (alumni), career-shape (new in role, tenure, promotions), education, skills, deterministic territory buckets. Use when the user wants to find people in bulk - persona lists, buyers/can…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
linkedin/search/sql/users (endpoint search_sql_users) searches a very large
profile database with filters no live LinkedIn search has: derived seniority and
function, career-shape maths (tenure, promotions, months in role), past-employer
alumni, company domains and deterministic bucketing. It is the bulk people
workhorse; live search_users stays the tool for one-off lookups and namesake
disambiguation.
Verified live: filters compose correctly (seniority_min=head + function=sales +
US + 51–500 headcount + new-in-role returned exactly that, role histories fresh
to the current quarter; alumni via past_company_id returns people whose role at
that company has an end date, never current staff).
count result is an unbiased SAMPLE, and repeating the request
returns the SAME people (verified: two identical calls → identical 5
aliases; and raising count only appends — the list is prefix-stable, not
reshuffled). Calling again is not pagination.bucket_total:2, index 0 vs 1
→ zero overlap across 40). Walk them for volume: bucket_total:N, bucket_index:0..N-1, also the built-in territory splitter. Ceiling:
bucket_total max is 100, so the reachable population is ~100×1000 = 100k;
size bucket_total so each bucket is < 1000, otherwise a bucket is itself a
sample and you silently lose the tail.The derived fields you filter on are not in the response: no seniority,
function, profile_score, months_in_role, promotion_count, industry,
employee_count (verified on a live record). Consequences:
experience[] by hand: take roles with
end_date == null (the current ones) and check .position / .company.name.
You cannot re-sort or re-segment the result by seniority/function via
query_cache — those columns aren't there.experience[].company.employee_range,
and that string is unreliable (see Company filters). There is no trustworthy
company-size value in a people result to write to a CRM.discover(linkedin, search))alias[], urn[], member_id[]; last_name[]
(diacritics/case/spacing-folded) + first_initial[] for "J. Smith".|=OR no spaces around it, "phrase", -not):
name, headline, summary, current_title, any_title (past roles
included), skills, languages, location, keywords, edu_*.
IRON RULE — quote every multi-word alternative in an OR chain. Whitespace
binds tighter than |, so an unquoted phrase SHATTERS the chain into
impossible AND groups: current_company_name: "Tencent|Tencent Games|Level Infinite|Proxima Beta" parses as (Tencent|Tencent) AND (Games|Level) AND (Infinite|Proxima) AND Beta → 0 results on Tencent-scale companies
(verified live — this exact failure burned a real user session). Correct:
"Tencent"|"Tencent Games"|"Level Infinite"|"Proxima Beta"|Krafton.
Lint before EVERY send: any token containing a space inside an OR chain
without quotes → do not send, fix first.seniority /
seniority_min (entry→ic→senior_ic→manager→head→vp→founder→cxo), function /
any_function (sales, marketing, engineering, product, data, finance, hr, ops,
legal, support, exec, …). Catch titles a text search can't (CRO, CCO, "VP
Business Development" all matched a function:sales+seniority_min:vp query —
none would survive a "vp of sales" DSL). Two traps, both measured:
seniority_min:"head" includes founder → pulls solo owners of 2-person
shops. For enterprise buyers list the levels explicitly:
seniority:["head","vp","cxo"], and always add employee_count_min.experience[].current_company_name DSL with QUOTED brand variants — the default. A bare
token like Tencent also matches subsidiaries ("Tencent Korea", "Fintech at
Tencent") — a feature for brand families, a bug if you need one legal entity.current_company_id[] (numeric LinkedIn page ids, resolve via company
search first) — when strictness matters: separating Level Infinite from the
rest of Tencent, excluding brand-name lookalikes.current_company_domain[] (bare domains) — when domains are what you have
(e.g. a CRM list).keywords — LAST resort, only WITH ≥1 selective filter (company/title/
seniority/country) and never as the employer filter itself: it's full-text
across all fields, and an unselective keywords query is a DB scan
(measured: 140s → HTTP 500).
Also: any_company_id/domain (ever worked);
past_company_id[] (worked and LEFT — alumni); employee_count_min/max of
the current company. Do NOT use employee_range[] — the band string
contradicts the true headcount often (measured ~35%: a 104-person company
banded "11-50", a 58-person one "501-1000"); filter size only with the numeric
employee_count_min/max.industry[] / any_industry[] take exact LinkedIn-taxonomy
labels (e.g. "Software Development" works), NOT market words — ["fintech"]
returns 0 (measured). Resolve labels via search_industries; for "fintech",
"SaaS" and the like, filter on the company side (anysite-company-sourcing
specialities) or on headline/skills DSL instead.country[] ISO2 (reliable); location DSL for cities/metros.
"Responsible for a market" ≠ "located in it." When the user wants people
FOCUSED on a region (CIS/MENA/emerging markets), do NOT filter country by
that region — BD/publishing teams of global companies sit in HQ (KR/CN/US/NL/
SG). Search the market mention in the profile instead:
headline/summary: CIS|Russia|Kazakhstan|MENA|"emerging markets"|"Middle East". Measured on a live case: country:[RU,KZ,UZ,AE,SA,…] → 2 profiles;
the headline variant → 84. Use country only when the person must physically
BE in the region — and warn the user the pool will be narrow.edu_slug[], edu_institution, edu_field,
edu_ended_year_min/max (graduation cohort ≈ age proxy).months_in_role_max (new in role), months_in_role_min,
months_since_change_max (started OR ended a role recently — job-change
radar), experience_years_min, n_roles_*, n_companies_* (stability vs
hopping), promotion_count_min (promoted without changing employer),
avg_tenure_months_*.profile_score_min (0–8) — do NOT set it by default:
it silently drops sparse-but-on-target profiles (a real user's default of 5
cut exactly the people they were hunting). Add it only when the user asks for
"complete/outreach-grade profiles" (then 5+), or as a tie-breaker on an
over-1000 pool. Plus the has_* family (has_current_role, has_role_dates,
has_education, has_company_size, has_engagement…).open_to_work, hiring, verified, is_premium,
is_top_voice, follower_count_min, connection_count_min. (is_creator /
is_influencer filter but are NOT returned — you can't confirm them.)similar_to / also_viewed
by alias. Measured unreliable: two seeds returned namesakes (same name,
different people) or nothing — NOT semantic lookalikes. Do not use it as a
"people like our champion" shortcut; if you try it, probe count:5 and confirm
the surnames differ from the seed's before trusting a single row. For real
lookalikes, replicate the champion's attributes as explicit filters instead.fetched_after (unix ts) — only recently refreshed profiles.Not every profile states a current employer, industry, company size or dated
roles — those filters answer only for people who do. The API's own numbers:
current title, seniority and function resolve for about a third of people;
current_company_id, current_company_domain and employee_range for about one
person in five. So a company-id or domain rung returns roughly a fifth of the
people who really work there — say so, and for coverage run the
current_company_name rung alongside it. Set the matching has_* flag
deliberately and tell the user the trade-off ("filtering by company size skips
people whose company doesn't state one"). open_to_work: false = "no badge
observed", not "not looking". Follower/connection counts exist on a small share —
gate with has_engagement.
Two data-shape facts to expect: some profiles carry multiple concurrent open
roles (measured: 4/10 in one slice; one person had ~19 — advisory boards,
visiting posts). "Current company" is then ambiguous, and a
current_company_domain/employee_count filter may match on a quarter-time
advisory role, not the day job — so verify the target company is an operational
current role before anchoring an opener on it. And urn is occasionally null
even when alias is present — the vanity URL still enables user_find_email_by_url
and user_posts (it accepts the alias/URL and resolves it at the cost of one extra
lookup).
keywords (it only helps for distinctive words
and must ride a selective filter). No persona in the request → use the titles,
seniority and function from the Personas section of anysite-gtm-profile when
it exists.count:10, validate against INTENT via experience[] (structural
filters aren't semantic: "Director of Sales, 51–200, US" returned a coffee
wholesaler). Precision comes from current_company_domain[] (a list from
anysite-company-sourcing), taxonomy industry[], or headline/skills DSL.bucket_total so each bucket
< 1000 and walk it.query_cache (only on returned fields); export with
export_data. In clients that render MCP Apps, show the result with
show_entity_table(cache_key, group_by="company_id") so people are grouped by
account; people at approved accounts from review_leads start from that
selection's company ids.Zero results — debug in this order, don't flail:
profile_score_min, widen seniority,
drop industry) — never jump straight to a bare keywords full-text.500/408 on a broad query: don't retry as-is — narrow it (add a selective
filter) or raise timeout (≤1500). An unselective query is a scan; retrying a
scan just times out again.
seniority:["vp","cxo"], function:["sales"], country:["US"], employee_count_min:50, employee_count_max:500, industry:["Software Development"]. (SaaS ≠ a taxonomy label — narrow via the
company-side list or headline DSL. profile_score_min only if asked.)current_company_name: "\"Tencent\"|\"Tencent Games\"|\"Level Infinite\"| \"Proxima Beta\"|Krafton", current_title: "\"business development\"|bizdev| partnership|partnerships|licensing|monetization|payments|commercial", seniority:["manager","head","vp","cxo"], has_current_role:true — every
multi-word alternative quoted; regional focus goes in headline, not
country (see Geo).months_in_role_max:3
(default 90 days). Too few → widen the title family first, then relax size or
geography, and only then the window (6 months; 9 is the ceiling).anysite-buying-committee.past_company_id:[<customer ids>] + your persona filters; name the shared
employer in the message only if the user confirms it may be mentioned.promotion_count_min:2 + avg_tenure_months_min:24.past_company_id:[<ids>] (+ function/seniority) — people
who LEFT. Note: this is ex-employees, NOT the competitor's customers; for
customers use anysite-crm-competitor-intel (wappalyzer + reviews).languages:"german", country:["DE","AT","CH"].edu_slug:[...] + edu_ended_year_min/max.skills/edu_field DSL + avg_tenure_months_min (stability) +
n_companies_max (not a hopper) + open_to_work:true as a bonus tier only.bucket_total:<reps>, bucket_index:<rep #>.current_company_id/domain) come from
anysite-company-sourcing; people OUT go to anysite-crm-prospect
(dedup + CRM push).alias beat one mega-query — each
stays selective and each angle surfaces people the others rank low.alias is the vanity URL, ready for the email cascade (anysite-mcp →
Email finding): user_email first (cheap, ~half personal addresses, low
yield), then user_find_email_by_url (~75% yield but 50cr each — estimate
50cr × N and confirm before a big run) with its valid_email/email_status
as the deliverability gate. Personal/unverified addresses never go into a work
sequence. For bounce-critical sends, run the address through emails/verify
(status valid / invalid / risky, is_personal); it may answer from a verdict
stored up to a year ago (resolved_by says which).linkedin/user with a small
cache_max_age_days (e.g. 7) — without it the call may return a profile up to
180 days old, which defeats the check; it also yields the vanity URL. Job-change detection on CRM
contacts belongs to anysite-crm-champions (this DB's months_since_change_max
is its cheap pre-filter, not its evidence).