AI 应用AI 技能【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址https://gitcode.com/GitHub_Trending/ai/ai-job-search点击查看免费下载本指南是ai-job-search仓库中freehire-search技能所依赖的freehire.me 公开 REST API 接口参考原文即.agents/skills/freehire-search/url-reference.md它系统讲解该聚合器 API 的端点、查询参数、响应结构与错误语义。读完本文你将掌握如何直接构造/api/v1/agent/jobs/search的多面facet搜索请求、如何理解{data, meta, error}统一信封、如何解析 Job 对象的全部字段以及该技能 CLI 在 helpers.ts、search.ts、detail.ts 中如何实现重试回退、HTML 清洗与错误降级。本文同时是 API 契约的事实源头——若 freehire API 发生变更应首先更新该参考文档。一、概览这份参考文档在技能中的定位url-reference.md是整个freehire-search技能的数据契约层。技能通过 SKILL.md 对外暴露search/detail两个命令而命令背后实际请求的端点、参数、响应字段全部由这份参考文档统一定义与维护。三个关键前提Base URL 默认值https://freehire.me可通过环境变量FREEHIRE_API_URL覆盖。对应源码见 helpers.ts 的baseUrl()读取FREEHIRE_API_URL去掉首尾空白与尾部/为空则回退到默认值。这意味着指向自托管实例只需一行环境变量FREEHIRE_API_URLhttp://localhost:8080 bun run .agents/skills/freehire-search/cli/src/cli.ts search -q go数据形态freehire.me 是公开 JSON API 聚合器把约 50 个 ATS申请人跟踪系统平台的职位公告归一化成统一 schema——与仓库中linkedin-search、jobindex-search等解析 HTML 卡片的 portal 技能不同这里没有 HTML 需要抓取。服务依赖边界freehire.me 由个人项目维护、best-effort 运行、无正式 SLA因此客户端即本技能 CLI必须实现优雅降级——这一点直接决定了后文的重试与错误契约设计。二、认证模型读公开、写需密钥freehire API 的认证规则非常简单所有读取端点公开、免认证GET /api/v1/jobs/*与GET /api/v1/companies/*都是公共接口无需 API key与linkedin-search的零注册门槛一致。仅用户级跟踪变更需要 bearer API key例如apply投递、save收藏、me等写操作。而本技能刻意不触碰这些端点——它的契约是纯搜索 详情不承担任何投递/跟踪职责。参考文档记录了一组针对线上 API 实测验证的端点状态表端点状态说明GET /api/v1/agent/jobs/search200技能search命令实际使用的端点GET /api/v1/jobs/search200Web 变体本技能不使用GET /api/v1/jobs/facets200面facet取值分布GET /api/v1/jobs/{slug}200按 slug 取单条职位GET /api/v1/auth/me401需要认证本技能不使用这张表的价值在于它把技能依赖面与API 全部面划清界限——技能只依赖其中 3 个 200 端点其余包括需认证端点与技能无关。三、统一响应信封Envelope每个响应都遵循统一信封结构{ data: ..., meta: {...}, error: ... }具体规则列表数组放在data分页信息放在meta形如{ total, limit, offset }单条对象直接放在data错误形如{ error: message }伴随 4xx/5xx 状态码。例如 404 返回{ error: not found }。该信封在源码中由 helpers.ts 的EnvelopeT接口定义data: T、可选meta与error。注意一个细节apiGet读取响应体时是容忍式解析的——错误响应的 JSON 用于提取error消息而 2xx 响应体若无法解析 JSON 会显式抛出unparseable response body错误而不是被静默吞掉保证调用方永远不会拿到半截数据。四、核心端点一GET /api/v1/agent/jobs/search这是技能search命令唯一使用的搜索端点也是本文档最重要的一节。4.1 与 Web 搜索的同一查询、一个差异它与 Web 版GET /api/v1/jobs/search运行完全相同的查询相同的q关键词相同的 facets面过滤相同的排序ranking相同的分页保护offset limit ≤ 10000。唯一区别在于被要求时它会把搜索索引中被截断的description预览替换为从数据库读取的完整职位描述。这正是搜 N 个职位只需 1 次请求而不是 N1 次的关键机制——技能在 search.ts 中用SEARCH_PATH /api/v1/agent/jobs/search常量锁定该端点并明确注释了每个命中携带完整描述而非索引预览因此一次运行无需对每个命中追加detail请求。4.2 两个额外参数参数映射到 CLI 标志说明include_description恒为true不传则端点退化为提供索引预览与 Web 搜索一致。技能默认开启 hydration。description_format--description-formatmarkdown技能默认、text或html。非法值不构成 API 错误——API 会静默回退到html因此 CLI 自己校验该标志。源码印证search.tshydrate opts.includeDescription ! false两个参数总是结伴出行——include_descriptiontrue时同时发送description_format若调用方用--no-description显式退出 hydration则两者都不发送。而 cli.ts 在发送请求之前就对description_format做白名单校验markdown|text|html非法值以BAD_ARG错误码退出 1——注释点明了原因API 对非法格式返回的是原始 HTML 而非错误拼写错误会静默改变输出而不失败。4.3 逐条 hydration 是 best-effort需要特别澄清一个边界hydration 是尽力而为的。若某条结果的记录已从数据库消失搜索索引滞后于刚下架的职位该命中会保留预览而不是被丢弃。因此实践中description几乎总是全文但契约上从不保证是全文。4.4 404 的特殊语义是缺端点不是没结果从该路径收到 404意味着这个 freehire 实例早于该端点的出现例如通过FREEHIRE_API_URL指向的自托管后端版本过旧而不是职位不存在。CLI 因此把它报告为指明路径的错误而不是空结果集——search.ts 中apiGet返回null404 哨兵时runSearch输出错误消息/api/v1/agent/jobs/search not found — this freehire instance predates the agent search endpoint; upgrade it or unset FREEHIRE_API_URL to use the hosted API错误码SEARCH_FAILED退出 1。绝不会伪装成搜索无结果否则配置错误会被看似合理的空输出掩盖。五、核心端点二GET /api/v1/jobs/searchWeb 变体这是同一搜索的 Web 变体查询面完全相同唯一差异是description恒为索引的截断预览。技能不调用它但它承载着共享查询参数的文档定义——下面这些参数对两个端点同时生效。5.1 技能使用的查询参数全表参数映射到 CLI 标志说明q--query/-q关键词全文检索标题、技能、角色limit--limit/-n每页条数CLI 默认 25offset派生offset (page - 1) * limitsemantic_ratio固定0关键词检索语义索引是 opt-in 的posted_within_days--jobage只返回最近 N 天内的职位regions--region可重复面内 OR。取值如global、eu、us、apac、latam、ciscountries--country可重复ISO-3166 alpha-2小写cities--city可重复城市显示名seniority--seniority可重复junior、middle、senior、staff等category--category可重复backend、frontend、fullstack、devops、ml_ai等skills--skill可重复规范技能名company_slug--company单个公司work_mode--remoteremote|hybrid|onsite任意 facet 参数--facet keyvalue长尾逃逸口如salary_min、visa_sponsorship、employment_type、english_level源码中的请求构造search.tsbuildQuery逐项印证了这张表limit恒为字符串offset由(page - 1) * limit派生semantic_ratio固定为0注释关键词检索语义索引 opt-inposted_within_days仅在jobage 0 jobage 9999时发送CLI 层 jobage 默认 9999 表示不限制所有 facet 值在 CLI 层已被commaList拆成值列表然后通过p.append(param, value)逐值追加为重复参数——包括--facet逃逸口进入的Object.entries(opts.facets)与具名 facet 完全同构地追加。5.2 面过滤的布尔语义重复参数在同一面内是 OR例如?seniorityseniorsenioritystaff表示senior 或 staff不同面之间是 AND多个 facet 同时成立地理位置特殊规则地理面regions/countries/citiesOR 合并为一个位置组深分页服务端受限offset limit ≤ 10000超出即受保护。5.3 Job 对象技能读取的字段{ public_slug: golang-zensar-2bxu6dxm, // - 结果 id也是 detail 的 slug source: oracle, external_id: …, url: https://…, // 真实职位 URLATS 主机 title: GOLANG, company: Zensar, company_slug: zensar, location: India, // ATS 自由文本位置 description: - …, // agent 搜索按请求格式返回全文 // 其他场景返回 HTML客户端清洗 skills: [go, kubernetes, …], // 词典面顶层 work_mode: remote, // 可能缺失 regions: [apac], // 词典/混合面 countries: [in], cities: [], collections: [], posted_at: 2026-07-06T00:00:00Z, // - 结果 date可空 created_at: 2026-07-06T15:25:…Z, enrichment: { // 嵌套、带类型未富化时为 {} seniority: senior, category: backend, employment_type: full_time, salary_min: 90000, salary_max: 120000, salary_currency: EUR } }契约要点内部数字 id 刻意永不暴露public_slug是稳定标识符。源码 helpers.ts 的toResult把public_slug映射为结果id、posted_at映射为date缺失值一律null而非省略测试 parsing.test.ts 专门断言了company: 、posted_at: null等被归一到null。enrichment 恒存在未富化的职位序列化为{}见 helpers.ts 的注释其内部字段才可能缺失。toDetail会把富化字段展平并格式化薪资如EUR 90000–120000见 parsing.test.ts。skill 面在顶层skills不是 enrichment 的一部分。六、核心端点三GET /api/v1/jobs/{slug}按public_slug获取单条职位data中返回同一个 Job 对象。两条边界已关闭的职位仍然服务返回的closed_at非空但内容不丢失——技能detail命令因此能查已关闭的职位如跟踪记录里的职位、搜索中已消失的职位slug 不存在返回 404{ error: not found }。CLI 侧的对应实现detail.ts先把输入经normalizeSlug归一化接受裸 slug 或完整/jobs/slugURL见 helpers.ts再请求/api/v1/jobs/${encodeURIComponent(slug)}apiGet对 404 返回nullrunDetail随即把 404 映射为 stderr 上的{ error: job not found, code: NOT_FOUND }并退出 1——与参考文档404 → NOT_FOUND 错误的描述完全一致。测试 parsing.test.ts 亦验证了normalizeSlug对三种输入裸 slug、URL、非法字符串的行为。七、核心端点四GET /api/v1/jobs/facets受控词表来源该端点返回市场在各 facet 上的取值分布可带可选过滤条件——每个 facet 的实时取值及计数data.facets { facet: { value: count } }本技能不编程调用它但它是 SKILL.md 指引用户获取受控词表的来源。追加?qrole可将计数限定到该角色的市场子集例如GET /api/v1/jobs/facets?qreact为什么它重要因为 facet 值是受控词表——永远不要发明 facet 值。SKILL.md 特别强调Location 是 facet不是自由文本与linkedin-search的--location不同freehire 通过结构化的--region/--country/--city过滤地理位置动手过滤前应先查/api/v1/jobs/facets获取实时取值。八、客户端解析注意事项Parsing Notes这是参考文档中贴近工程实践的最后一节讲清了三条实现约束响应是 JSON无 HTML 卡片解析与仓库中解析门户 HTML 的技能不同这里没有标记需要从零解析。唯一遗留的客户端标记处理是detail/jobs/{slug}服务的是 HTML由cleanHtmlhelpers.ts剥离成可读文本——块级/换行标签br、/p、/li、/div、/h*转成换行、HTML 实体解码含十进制/十六进制数字实体、多余空白折叠。测试 parsing.test.ts 验证了pOne/ppTwo/p → One\nTwo与Caf#xE9; → Café等行为。搜索描述直通、不再清洗agent 搜索端点返回的描述已由 API 渲染完毕客户端原样透传——再次剥离会破坏 Markdown 结构。这正是--description-format markdown默认值的由来保留职位的标题与要求列表层级。HTTP 客户端契约请求携带浏览器风格的 User-Agent源码为freehire-search-skill/1.0 (https://freehire.me)见 helpers.ts与Accept: application/json对429/5xx执行带抖动的指数退避重试最多 6 次重试合计 7 次尝试起始延迟 500ms、每次加倍、上限 8s、每次加 0–500ms 随机抖动单请求超时 15s连接错误API 不可达快速失败、不重试因为那是非瞬态服务器负载重试只会挂住调用方——这正是优雅降级契约freehire 停机时该数据源快速降级而不是悬挂。上述重试行为在 helpers.ts 的apiGet中逐行实现并由 retry-backoff.test.ts 离线钉死429 后重试成功2 次调用404 不重试、返回null1 次调用持续 5xx 在初次 6 次重试后放弃共 7 次调用连接错误只调用 1 次即抛could not reach the freehire API。九、从 API 到 CLI 的完整闭环参数校验与错误契约把参考文档的 API 契约与 CLI 实现合起来看就能得到一份完整的端到端行为图景请求侧cli.ts数字参数--jobage/--page/--limit用Number()而非parseInt()校验必须为≥ 1的整数否则BAD_ARG退出 1。测试 cli-flag-validation.test.ts 明确指出parseInt(0.5) 0会静默跳过posted_within_days过滤的坑所以小数直接拒绝未知标志拒绝而非静默丢弃UNKNOWN_FLAG退出 1。理由在 cli.ts 与测试注释中写得很清楚——被丢弃的过滤条件会改变搜索结果而不报错曾有拼错标志名导致返回整个门户数据库13,862 条的教训--facet必须为keyvalue形式否则BAD_ARG--remote可裸用等价remote--no-description在客户端剥离描述体对应源码注释描述体约占默认搜索负载的 73%发现式扫描时跳过可显著省 token。输出侧所有错误写入stderr形如{ error: ..., code: ... }进程退出码 1成功路径的 search JSON 为{ meta: { count, page, total }, results: [...] }其中total取自 API 信封的meta.total估计匹配数每个结果至少携带idfreehire slug、title、company、location、date、url、description。十、实操要点速查最后把文档与源码中的可操作性结论浓缩如下搜索即全文勿循环 detailsearch已带完整描述markdown 默认对搜索命中去逐条detail只是重复读取已有内容detail只用于按 slug 查单条跟踪中的职位、已关闭职位。先查 facets 再过滤facet 取值是受控词表用/api/v1/jobs/facets?qrole查看实时计数不要发明取值。地理是 facet不是自由文本用--region/--country/--city--region none可匹配未解析出地理的职位多为远程岗且可与真实区域 OR如--region eu,none。缺失 ≠ 不适用区域/国家未解析时数组为空--region eu会静默丢弃实际在欧盟但未解析的职位需要时放宽或移除该 facet。分页有上限offset limit ≤ 10000由服务端强制。错误三分法404在搜索路径上 实例太旧缺端点报告为指明路径的错误429/5xx 指数退避最多 6 次重试连接失败 快速失败不重试。自托管换源只需环境变量FREEHIRE_API_URL指向本地实例即可切换数据源若实例版本早于 agent 搜索端点CLI 会以SEARCH_FAILED明确报错而非空结果。这份接口参考配合 SKILL.md命令用法、cli.ts参数解析与校验、helpers.ts信封/清洗/重试以及cli/tests/下的契约测试构成了一套文档 → 实现 → 测试三方可互相印证的数据源集成范本——fork 本仓库后若要对接新聚合器或需要更新 freehire 的接口契约这份参考文档就是第一个要修改的文件。赞分享AI 应用AI 技能【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址https://gitcode.com/GitHub_Trending/ai/ai-job-search点击查看免费下载相关推荐AMD Ryzen处理器硬件调试终极指南SMUDebugTool深度解析与实战应用AMD Ryzen处理器硬件调试终极指南SMUDebugTool深度解析与实战应用 面对AMD Ryzen处理器性能无法完全释放的困境硬件调试工具的选择往往AI 应用AI 技能ai-job-search 实战Akademikernes Jobbankjobbank.dk搜索 URL 构造完整参考ai job search 实战Akademikernes Jobbankjobbank.dk搜索 URL 构造完整参考 本指南以仓库 .agents/sAI 应用AI 技能为什么你需要 HumanLayer Skills3 大核心技能直击 Claude Code 三大痛点为什么你需要 HumanLayer Skills3 大核心技能直击 Claude Code 三大痛点 用 Claude Code 的你是否也遇到过这些墙精AI 应用AI 技能上一篇Cowabunga LiteiOS非越狱定制工具安全打造个性设备界面下一篇HackRF 硬件触发Hardware Triggering完全指南多设备亚采样周期同步实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考