news 2026/10/1 1:54:27

Gallery 内置 Skill 实战:query-wikipedia 维基百科摘要查询的调用规范与源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gallery 内置 Skill 实战:query-wikipedia 维基百科摘要查询的调用规范与源码实现
  • 人工智能
  • 大模型
  • 本地部署
  • AI 应用
  • 移动开发
  • AI Agent
  • AI 技能
  • MCP Clients

【免费下载链接】gallery

A gallery that showcases on-device ML/GenAI use cases and allows people to try and use models locally.

项目地址:https://gitcode.com/GitHub_Trending/gallery44/gallery
点击查看免费下载

query-wikipedia 是 Android Gallery 项目内置的一个端侧 Agent Skill,它通过run_js工具驱动一段 JavaScript 脚本,从指定语言的 Wikipedia 拉取词条的简介(summary)与信息框(infobox),帮助端侧大模型在不联网搜索的情况下快速获取"某人 / 某事件 / 某作品"的权威概述。本文以 SKILL.md 为主线,完整讲解其参数规范、调用步骤、回答约束,并结合scripts/index.html与 Android 端RunJsTool的源码,剖析一条 Agent 调用从指令解析、WebView 执行到结果回传的完整链路。

一、Skill 是什么:一段可被 Agent 调用的"查询工具说明书"

在 Gallery 的架构中,一个 Skill 由两部分组成:

  • SKILL.md:面向 LLM 的指令文件,描述何时调用、传什么参数、如何回答,本质是"工具说明书";
  • scripts/index.html:真正执行逻辑的 WebView 页面,通过全局入口window["ai_edge_gallery_get_result"]接收 JSON 参数并返回结果。

query-wikipedia 位于 skills/built-in/query-wikipedia/,同时在 Android 应用的 assets 中也有一份镜像副本 Android/src/app/src/main/assets/skills/query-wikipedia/。其 frontmatter 定义如下:

--- name: query-wikipedia description: Query summary from Wikipedia for a given topic. ---

从源码结构看,Skill对象的name与description会被 SkillExtensions.kt 中的模板SKILL_INSTRUCTIONS_TEMPLATE拼装进注入给模型的多行指令:

const val SKILL_INSTRUCTIONS_TEMPLATE = "---\nname: %s\ndescription: %s\n---\n\n%s"

也就是说,SKILL.md 的 frontmatter 并不是摆设——load_skill工具在把 Skill 内容交给模型时,会完整带上name、description与instructions(即本文件正文部分),见 LoadSkillTool.kt。query-wikipedia 的存在意义在于:端侧模型对"事实性、时效性"问题的内部知识可能过时或缺失,而通过该 Skill 可以实时拿到维基百科的结构化摘要作为可信上下文。

二、调用方式:run_js工具 + data JSON 参数

SKILL.md 明确规定,Agent 应按如下方式调用:

Call therun_jstool usingindex.htmland a JSON string fordatawith the following fields.

对应到 Android 端,run_js是 RunJsTool.kt 中声明的工具,其三个参数为:

参数说明本 Skill 的取值
skillName要调用的 Skill 名称"query-wikipedia"
scriptName要执行的脚本名"index.html"(未提供时默认)
data传给脚本的 JSON 字符串{"topic": "...", "lang": "..."}

data中必须包含两个字段:topic(必填)与lang(必填)。

topic:只提取主体实体

Extract ONLY the primary entity, person, or event (e.g., "2026 Oscars", "Albert Einstein"). You MUST REMOVE all specific question details, action words, or conversational text (e.g., do NOT include words like "winner", "best picture", "who won", "history of"). Search for the broad subject so the tool can return the main article.

即把用户问题中的疑问词、动作词、限定细节全部剥离,只留核心词条。例如:

用户提问topic 取值理由
谁赢得了 2026 年奥斯卡最佳影片?"2026 Oscars"去掉 "winner / best picture / who won"
爱因斯坦的出生年份是什么?"Albert Einstein"去掉 "history of" 等描述性词
法国的首都是什么?"France"只保留国家实体

设计意图在 index.html 中可以得到印证:脚本第一步用的是generator: "search"的模糊搜索,gsrsearch直接拿topic全文去匹配维基标题。搜索词越"干净",命中的就越是词条主页,返回的 extract 质量越高。

lang:与 topic 保持同语言的 2 字母代码

The 2-letter language code. This code MUST match the language of the keywords you provided in thetopicfield.

支持的常见代码:

  • en(English)、es(Spanish)、zh(Chinese)、fr(French)、de(German)
  • ja(Japanese)、ko(Korean)、it(Italian)、pt(Portuguese)
  • ru(Russian)、ar(Arabic)、hi(Hindi)

lang直接决定请求的维基域名:脚本用模板字符串拼接https://${lang}.wikipedia.org/w/api.php(见 index.html),所以zh会访问中文维基、de会访问德语维基。若 topic 用了德语关键词却传en,模糊搜索基本无法命中正确词条——这就是"lang 必须与 topic 语言一致"的原因。

三、回答约束:省上下文、保语言一致、兜底时效

SKILL.md 的 Constraints 部分定义了模型拿到结果后的回答规范,这是该 Skill 的输出侧协议,需要与输入侧参数一同遵守:

1. 摘要要短,且必须句子完整。

Provide a concise summary (1-3 complete sentences) to conserve context. Always ensure your response ends with a finished sentence.

端侧上下文窗口有限,维基正文很长,模型应把脚本返回的 extract 压缩成 1~3 个完整句子,不得在半句话处截断。

2. 回答语言与用户原问题一致。

your response MUST BE written in the SAME language as the user's original prompt.

注意:这里绑定的是"用户 prompt 的语言",而非lang字段。用户用中文提问,即使查询的lang是en,回答也要用中文。

3. 周期性事件 / 时效性事实,必须锁定具体届次。

For recurring events or time-sensitive facts, query the specific iteration (e.g., "2026 Oscars"). If the user omits the year, default to the current year.

例如"奥斯卡"是年度重复事件,topic 应为"2026 Oscars";若用户没说年份,则默认取当前年份。这与维基百科"词条按届次独立成页"的排版方式对应——只有带上届次才能命中正确的词条主页。

4. 找不到答案时,先说明,再给相关事实。

If the exact answer to the user's question is not found in the extract, briefly state this, then proactively offer a related piece of information thatwasfound in the text.

这是"诚实 + 有用"的兜底策略:不编造,明确告知 extract 中未命中,同时把文本中确实存在的邻近信息作为替代价值提供给用户。

四、底层实现:两段式维基 API 查询管线

scripts/index.html 的核心是fetchWikiFuzzyAndInfobox(topic, lang),整条管线分为四个阶段:

阶段 1:模糊搜索 + 取词条简介(extract)

const searchParams = new URLSearchParams({ action: "query", format: "json", generator: "search", gsrsearch: topic, gsrlimit: "1", prop: "extracts", explaintext: "1", exintro: "1", origin: "*", });

关键参数含义:

  • generator: "search"+gsrsearch: topic:以 topic 做模糊搜索,gsrlimit: "1"只取第一个结果;
  • prop: "extracts"+exintro: "1":只返回条目的引言段(intro),这是被判定为最干净的"摘要";
  • explaintext: "1":返回纯文本而非 HTML,便于 LLM 直接阅读;
  • origin: "*":允许跨域请求(WebView 页面发起 fetch 必需)。

如果searchData.query.pages为空,脚本直接返回错误对象:No Wikipedia articles found matching '<topic>' in language '<lang>'.

阶段 2:拉取第 0 节 HTML 解析信息框(infobox)

const parseParams = new URLSearchParams({ action: "parse", page: title, section: "0", prop: "text", format: "json", origin: "*", });
  • action: "parse"+section: "0":只取页面顶部(含标题、摘要和右侧 infobox)的 HTML;
  • 用DOMParser解析后,querySelector("table.infobox")找到信息框表格;
  • 遍历每一行,取th(键)与td(值),并用正则replace(/\[\d+\]/g, "")清除[1]、[2]这类引用角标,多行值用" | "连接。

这一步是整个 Skill 的价值增量:除了段落摘要,还拿到出生日期、获奖年份、国籍等结构化键值对,这正是回答"谁获奖了"这类问题的关键证据。

阶段 3:合并 INFOBOX 与 SUMMARY

if (infoboxText) finalResult += `--- INFOBOX ---\n${infoboxText}\n\n`; if (extract) finalResult += `--- SUMMARY ---\n${extract}`;

最终返回结构为{ title, result },result以--- INFOBOX ---与--- SUMMARY ---两个分区组织,方便 LLM 快速定位两类信息。若两者皆空则返回错误Found page '<title>' but no text or infobox was available.

阶段 4:按语言设置安全截断上限

switch (lang.toLowerCase()) { case "zh": maxChars = 1500; break; case "fr": maxChars = 4300; break; case "es": maxChars = 4500; break; case "en": default: maxChars = 5000; break; } if (finalResult.length > maxChars) { finalResult = finalResult.substring(0, maxChars) + "\n\n... [TRUNCATED TO SAVE CONTEXT]"; }

中文单字信息密度高,所以截断阈值最低(1500 字符);英文默认 5000。超限部分追加... [TRUNCATED TO SAVE CONTEXT]标记,配合 SKILL.md 中"1~3 句摘要"的约束,共同把注入模型的 token 量控制在预算内。

统一入口:ai_edge_gallery_get_result

window["ai_edge_gallery_get_result"] = async (data) => { ... }

WebView 端通过这个全局函数接收 JSON 字符串:缺topic返回No topic provided to search.,缺lang返回No language code (lang) provided.,任何异常兜底返回Failed to query Wikipedia: <message>。

五、端到端运行链路:从指令到结果的五次跳转

综合 Android 端源码,一次 query-wikipedia 调用在运行时经历如下链路:

  1. 加载 Skill 指令:Agent(或用户)触发load_skill工具,SkillsProvider.loadSkill("query-wikipedia")取出 Skill,getSkillContent()按---\nname: ...\ndescription: ...\n---\n\n<instructions>模板格式化后注入对话,见 LoadSkillTool.kt 与 SkillExtensions.kt;
  2. 解析脚本地址:run_js内部调用skill.getJsSkillUrl("index.html")。built-in Skill 的importDirName非空,于是拼出$LOCAL_URL_BASE/query-wikipedia/scripts/index.html(逻辑见 SkillExtensions.kt);
  3. 发送执行动作:CallJsToolAction(url, data, secret)通过ToolExecutionContext.actionChannel发出(RunJsTool.kt),此时工具会在聊天面板中展示"Calling JS script..."的进度条目;
  4. WebView 执行:页面加载index.html后,以dataJSON 调用ai_edge_gallery_get_result,内部完成上文四阶段查询,返回{title, result}或{error};
  5. 结果回传解析:run_js用 Moshi 把返回值解析为CallJsSkillResult,有error则标记status: "failed",否则以mapOf("result" to ..., "status" to "succeeded")交还给模型(RunJsTool.kt)。模型随后按 SKILL.md 的约束生成 1~3 句摘要。

需要补充的是:若 Skill 声明了requireSecret(例如调用需要 API Key 的外部服务),run_js会先弹窗向用户索要密钥并写入 DataStore,而query-wikipedia 走的是公开的 Wikipedia API,不需要任何密钥,因此该 Skill 无此环节(逻辑见 RunJsTool.kt)。

六、边界情况与可观测性设计

脚本对异常做了多层防护,值得在实际开发中复用:

  • HTTP 非 2xx:if (!searchRes.ok) throw new Error(...),进入外层 catch;
  • 无匹配词条:返回{ error: "No Wikipedia articles found..." };
  • infobox 解析失败:单独try/catch包裹,仅console.warn后静默跳过,不影响 extract 返回——"部分可用"优于"整体失败";
  • 结果为空:返回{ error: "Found page ... but no text or infobox was available." };
  • 参数缺失:在ai_edge_gallery_get_result入口分别校验topic、lang。

同时run_js端也会对返回结果做"双重校验":若返回的 JSON 既没有result、webview也没有image,就把整个原始字符串当作结果返回(RunJsTool.kt),确保 WebView 端任何未预期的返回格式都不会导致 Agent 死循环或空响应。

七、给 Skill 作者与使用者的实践建议

综合 SKILL.md 与源码,可以提炼出几条可直接落地的经验:

  1. 参数语义即质量:topic越"纯"、越贴近维基词条标题,模糊搜索命中率越高。凡是在指令中对 LLM 强调"剥离疑问词与动作词"的 Skill,其搜索类脚本都应采用generator: search+gsrlimit: 1的"取首个结果"策略;
  2. 语言代码对齐:lang决定域名与截断阈值,务必与 topic 语言一致;对多语言场景,可在脚本内用switch维护每语言的字符上限;
  3. 结构化信息优先:先用action: parse拉第 0 节 HTML、再正则清洗引用角标,比直接要整页正文更省 token 且更利于回答"事实型"问题;
  4. 诚实的兜底协议:SKILL.md 中"未命中即说明 + 给邻近信息"的约束,配合脚本{ error }返回协议,能有效避免端侧模型在事实问题上编造答案。

以上规范与实现路径同样适用于本仓库其他基于run_js的 built-in Skill(如calculate-hash、text-spinner等,参见 skills/built-in/),可作为理解 Gallery 端侧技能系统的通用参考。

  • 人工智能
  • 大模型
  • 本地部署
  • AI 应用
  • 移动开发
  • AI Agent
  • AI 技能
  • MCP Clients

【免费下载链接】gallery

A gallery that showcases on-device ML/GenAI use cases and allows people to try and use models locally.

项目地址:https://gitcode.com/GitHub_Trending/gallery44/gallery
点击查看免费下载

相关推荐

上一篇:零依赖获取用户主目录:go-homedir跨平台解决方案全指南
下一篇:EMQX `GET /clients_v2` 分页游标修复解析:内存会话客户端列表为何不再返回多余 cursor

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 1:53:04

C++控制台小游戏实战:贪吃蛇、扫雷、2048从环境配置到完整实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:52:01

nginx部署vue包dist,页面刷新后,提示“404 Not Found”

nginx-1.9.10错误截图如下&#xff1a;处理方法&#xff1a;在指定的位置添加下面代码&#xff0c;即可&#xff1b;location / {root E:/workspace/dists/dist;index index.html index.htm;# 解决页面刷新后&#xff0c;报404的问题try_files $uri $uri/ /index.html;}重启…

作者头像 李华
网站建设 2026/10/1 1:51:14

【Excel】零碎技能积累

文章目录1.INDIRECT跨表引用2.常用功能快速使用&#xff08;快捷键&#xff09;3.excel数据透视表&#xff0c;非重复计数4.透视表计算字段、计算项5.条件格式&#xff0c;A列是条件&#xff0c;B列因A列条件显示格式6.快速全表替换某一范围的数7.批量合并单元格8.快速拆分单元…

作者头像 李华
网站建设 2026/10/1 1:51:12

USB蓝牙适配器Linux不识别?CM591/ATS2851内核与BlueZ排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:50:52

AAA级武士角色纹理制作全流程:PBR工作流与Substance Painter实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:49:44

从麦田到论文:作物生产与品质改良人的 AI 搭子怎么选 [特殊字符]

如果你学的是作物生产与品质改良&#xff0c;大概率会遇到这样一个毕业任务&#xff1a; 以小麦为材料&#xff0c;研究不同施氮量对群体生长、产量构成和籽粒品质的影响&#xff0c;最终完成一篇包含试验设计、数据分析、图表制作和讨论分析的毕业论文。 这不是“随便写写”的…

作者头像 李华