AAS 技能内容评审实践指南:以 lint-and-validate 与 sql-optimization-patterns 的定向复核为例
【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills
导读
本文基于 agentic-awesome-skills(AAS)仓库中的评审记录 docs/contributors/content-review-followup-2026-09-05.md,完整拆解一次"有边界、可复现、可验证"的技能内容复核流程:它以日常维护中高频使用的lint-and-validate与sql-optimization-patterns两个技能树为样本,围绕"检查未运行不得误报为通过""注解统计不得重复计数""SQL 示例必须可执行且语义严谨"三类问题展开修复,并配套 6 个真实可运行的回归用例。读完本文,你将掌握:如何为技能文档设计可执行的工作示例(worked example)、如何用 AST 与子进程做行为验证、如何用 SQLite 内存库校验发布出的 SQL 代码,以及如何以"不越界、不夸大"的方式撰写评审证据与局限性声明。
一、评审背景:为什么需要一次"有边界"的定向复核
在 AAS 仓库中,技能(Skill)是供 Agent 直接调用的可执行指导文档,位于 skills 目录,每份技能由SKILL.md与其附带脚本、资源共同组成。仓库此前已有一份 docs/contributors/content-review-2026-09-05.md,覆盖了 20 个高优先级技能与 8 组同体技能,属于"全量抽查"性质。
而本次关联文档记录的是第二次、刻意收敛范围的复核(follow-up),它有两个鲜明特征:
- 范围明确:仅完整覆盖
lint-and-validate与sql-optimization-patterns两棵技能树,不构成对整个目录的认证("not a whole-catalog certification"); - 证据优先:评审不采集流行度或使用量数据,所有结论都来自源码阅读、脚本执行与测试用例。
选择这两个技能的理由也很实在——它们分别提供可执行的校验(validation)示例和SQL 示例,属于日常维护中被反复引用的内容,最值得用"可运行代码"去证明文档所言非虚。
二、修复一:Lint 运行器——"未检查"绝不能被误报为"通过"
2.1 修复前的问题
评审发现,旧的lint_runner.py存在一个对 Agent 极其危险的缺陷:当项目没有配置任何检查时,运行器之前会返回passed: true并退出码 0。这等于告诉 Agent"校验全部通过",而实际上什么检查都没有跑。
本次修复确立了三条行为契约(lint_runner.py):
- 未配置检查 → 明确报告
not-checked,退出码 2:在 lint_runner.py#L127-L139,当检测不到任何 linter 时,输出 JSON 中的status字段为not-checked,passed为false,并以退出码 2 终止,与"失败(exit 1)"区分开——失败说明"检查跑了但没过",not-checked说明"检查根本没跑"。 - 无效的项目元数据是显式失败:若
package.json无法解析(如 JSON 语法错误),detect_project_type 会抛出ValueError,main 捕获后同样以退出码 2 终止并输出错误信息,而不是静默跳过。 - Node 回退检查器必须解析本地已安装的二进制:当
package.json声明了eslint/typescript依赖但没有对应lint脚本时,命令路径会指向项目的node_modules/.bin/eslint(Windows 下为eslint.cmd)或node_modules/.bin/tsc,见 lint_runner.py#L47-L52。绝不允许npx在运行期悄悄下载一个检查器——这既是安全检查(避免执行来路不明的代码),也是诚实性问题(检查器不存在时应当报告"未运行",而不是现场安装后佯装通过)。
运行器的其余设计同样值得记录:检测逻辑以package.json(Node)与pyproject.toml/requirements.txt(Python)为判定依据;Python 侧会生成ruff check .与mypy .候选命令;单个 linter 通过subprocess.run以 120 秒超时执行,stdout 截断到 2000 字符、stderr 截断到 500 字符,见 lint_runner.py#L71-L102。最终汇总输出一段 JSON,包含script、project、type、checks与passed字段,供 Agent 直接消费。
2.2 对应的回归测试
上述三条契约不是评审口头的承诺,而是被 tools/scripts/tests/test_skill_worked_examples.py 中的真实子进程测试锁定的:
test_no_checks_and_invalid_metadata_are_not_success:在空临时目录中运行lint_runner.py,断言退出码为 2 且 stdout 含"passed": false;再写入一个内容为{的非法package.json,断言同样退出码 2。test_node_fallback_never_downloads_a_checker:构造一个仅声明typescript与eslint依赖的临时项目,断言检测出的两个命令路径都包含node_modules,且运行run_linter返回passed == False(因为本地并没有真正的二进制)。
2.3 手动复现
在仓库根目录执行:
python3 tools/scripts/tests/test_skill_worked_examples.py需要强调的是,该套件使用 Python 标准库与 SQLite,不连接真实数据库、不运行外部 linter、不测量查询速度;Python 与 Node 的项目检测本质上是启发式的,实际使用时应先查看项目说明,并遵循仓库自身的检查契约(详见 SKILL.md 中的 "Limitations" 一节)。
三、修复二:注解盘点——AST 计数、确定性抽样与诚实的作用域声明
3.1 修复前的问题
type_coverage.py(文件名沿用了兼容性旧称,实际职责是"有界注解盘点")修复前有两个问题:
- 重复计数:旧实现基于正则统计函数,一个同时带参数注解和返回注解的函数会被计两次;
- 夸大样本:源码抽样可能声称"所有被发现的文件都被分析过",而实际受 30 文件上限约束。
3.2 修复后的实现
新版 type_coverage.py 确立了如下行为:
- AST 计数,每个函数只计一次:Python 侧用
ast.parse后遍历ast.FunctionDef/ast.AsyncFunctionDef节点,统计函数总数,以及"返回值有注解且全部参数(含posonlyargs、args、kwonlyargs、vararg、kwarg)均有注解"的完全注解函数数,见 type_coverage.py#L44-L52。 - 确定性抽样且如实报告:
source_files按字典序遍历,每语言最多抽样 30 个文件(MAX_FILES = 30),跳过.git、node_modules、venv、__pycache__、dist、build等目录,不跟随符号链接;读取上限MAX_BYTES = 1_000_000。当达到 30 文件上限时,输出中truncated: true,并且实际成功分析的文件数、截断状态、解析/读取错误都会被如实写入errors数组,见 type_coverage.py#L16-L59。 - TypeScript 观察明确为词法层面:TS 侧仅统计正则
:\s*any\b的文本命中次数,这会包含注释与字符串字面量中的: any,也会漏掉推断出的或别名的any。因此输出中明确声明"这不是类型覆盖,TypeScript 计数是词法的,请运行真正的类型检查器",见 type_coverage.py#L53-L56 与 type_coverage.py#L76。 - 退出码语义:无适用文件时退出码 2;存在解析/读取错误时退出码 1;正常则退出码 0。不再输出任何"类型安全度百分比"或"通过/失败阈值"——这类推断此前被明确移除。
3.3 对应的回归测试
test_inventory_does_not_double_count_or_claim_unread_files:生成 31 个各含一个完全注解函数的 Python 文件,断言结果恰好files == 30、truncated == True、stats == {'functions': 30, 'fully_annotated_functions': 30}(验证 30 文件上限与"一函数一计数");随后把一个文件改成非法语法,断言errors长度为 1(验证解析错误被如实上报,而非宣称全部文件已分析)。
四、修复三:SQL 批量加载——IN 列表绑定、空输入与注入式字符串
4.1 修复前的问题
技能文档中原先使用驱动语义模糊的IN (?)列表绑定写法。问题在于:大多数驱动中的单个?占位符并不会把一个 Python 列表自动展开成多个值,这会导致查询参数不匹配甚至执行错误。
4.2 修复后的可执行示例
修复后,implementation-playbook.md 中的 "Pattern 1: Eliminate N+1 Queries" 提供了完整的、可运行的 SQLite 批量加载函数:
# batch-loading-example def load_orders(connection, user_ids): if not user_ids: return [] if len(user_ids) > 500: raise ValueError("Batch limit is 500 IDs; split larger inputs") placeholders = ",".join("?" for _ in user_ids) return connection.execute( f"SELECT id, user_id, total FROM orders WHERE user_id IN ({placeholders}) ORDER BY id", tuple(user_ids), ).fetchall()该示例的关键设计:
- 每个值单独绑定:为每个 ID 生成一个
?占位符,并以元组传入,杜绝字符串插值; - 空输入安全返回:
user_ids为空时直接返回[],避免生成非法的IN (); - 上限保护:超过 500 个 ID 抛
ValueError,防止单条查询过大; - 可移植性提示:不同驱动的占位符语法不同(
?是 SQLite 风格),迁移到其他数据库驱动时需要相应调整。
测试test_published_batch_loading_preserves_values_and_empty_case直接从 playbook 中提取发布出的 Python 代码块并执行:在:memory:SQLite 库中建表并插入三行数据,断言load_orders(connection, [1])返回正确的两行、空列表返回空、以及注入式字符串'1) OR 1=1 --'被当作普通数据安全处理(返回空结果而非注入生效),500 个以上 ID 抛ValueError。
五、修复四:结果保留优先——先验证结果集,再谈性能
本次复核在 SQL 领域确立了一个贯穿始终的第一原则(implementation-playbook.md#L7):
在评估性能之前,先保留并验证查询结果(Preserve the query result before assessing performance)。
这意味着:任何改写、加索引、调参,都必须先确认新旧查询返回相同的结果集;而EXPLAIN ANALYZE会真正执行语句,可能触发函数副作用、触发器与 DDL 行为,因此只应在经过授权的代表性数据上使用,且不能假设事务回滚能撤销一切副作用。
围绕这一原则,复核针对 playbook 中的三类经典模式做了行为验证与语义澄清:
5.1 游标分页:处理时间戳并列(tie)
单列游标WHERE created_at < ...仅在created_at唯一且非空时才正确。对于时间戳并列的场景,playbook 给出复合游标:
SELECT * FROM users WHERE (created_at, id) < ('2024-01-15 10:30:00', 12345) ORDER BY created_at DESC, id DESC LIMIT 20;并配套索引建议CREATE INDEX idx_users_cursor ON users(created_at DESC, id DESC)。
测试test_published_cursor_handles_equal_timestamps构造了三条相同时间戳、不同 id 的记录与一条更早记录,从 playbook 提取发布的查询并断言结果只包含id = 12344与id = 1两条——证明复合游标在并列时间戳下不会漏掉或重复行。
5.2 相关子查询与 LEFT JOIN 聚合:父行零/一/多子行
相关子查询(SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id)与LEFT JOIN ... GROUP BY聚合在语义上应等价,但必须验证,尤其是**没有订单的用户(父行零子行)**这类边界。playbook 的 "Pattern 4: Subquery Optimization" 给出了两种写法;测试test_published_join_aggregation_preserves_zero_and_multiple_orders从 playbook 提取两种 SQL,在内存库中对比其排序后的结果集完全一致,并断言('C', 'c', 0)这样的零订单行在 JOIN 聚合结果中确实存在。
5.3 聚合与统计:近似数不是精确数
复核同时澄清了几个容易误用的点(implementation-playbook.md#L222-L261):
pg_class.reltuples给出的只是近似估算,不等价于精确的COUNT(*);- "筛选已完成订单再计数"(
WHERE status = 'completed')是不同的需求,不是等价改写,不能当作同一查询的优化; - 仅改变 JOIN 的书写方式(逗号连接 vs 显式
JOIN)通常不会保证产生新的执行计划,显式 JOIN 提升的是可读性而非必然的执行速度。
六、修复五:PostgreSQL 18 相关指引的勘误
复核对 playbook 中的 PostgreSQL 18 特定内容做了逐项勘误(见 implementation-playbook.md 全文):
- 语句统计列名:
pg_stat_statements查询使用total_exec_time/mean_exec_time等当前时间列,并明确该扩展需预先配置、且查询文本可能包含敏感值,不得未经许可导出; - 索引统计命名:
pg_stat_user_indexes与pg_stat_user_tables中的列名按 PostgreSQL 18 文档校正; - 物化视图并发刷新前置条件:
REFRESH MATERIALIZED VIEW CONCURRENTLY要求视图已填充且存在一个建在普通列上的非部分 UNIQUE 索引,playbook 中示例为CREATE UNIQUE INDEX idx_user_summary_id ON user_order_summary(id);(implementation-playbook.md#L371-L373); - 半开时间区间:分区示例
FOR VALUES FROM ('2024-01-01') TO ('2024-04-01')的区间语义(含下界、不含上界)得到澄清; - 移除不存在的捆绑引用:原先指向未随包分发的本地指南与脚本的链接被删除,改为引用 PostgreSQL 18 官方文档;
- 显式声明变更风险:
EXPLAIN ANALYZE会执行语句、USE INDEX不强制索引扫描、SET enable_nestloop = OFF只是诊断手段而非绝对禁用等,均在文中标注(implementation-playbook.md#L407-L421)。
需要强调:PostgreSQL 特定的修正依据 PostgreSQL 18 官方文档核查,并未在本仓库内运行真实的 PostgreSQL 服务器;未验证扩展安装、DDL 锁行为或生产环境供应商行为——这些都需要在使用者自己的环境中单独验证。
七、证据链与内容来源(provenance)
评审文档对"证据"本身也做了严格管理:
- 社区来源声明:两个技能都声明
source: community(见 lint-and-validate/SKILL.md 与 sql-optimization-patterns/SKILL.md 的 frontmatter),复核不推断任何新的上游身份、许可证或背书; - 全文件读取:全部 5 个被跟踪文件都被读取(两个 Python 助手、两份 SKILL.md、一份 SQL playbook),确认无符号链接、非二进制、无可执行模式文件;
- SHA-256 指纹:评审为 5 个文件记录了字节级指纹(见关联文档的表格),并明确说明"后续编辑会使这些指纹失效",即指纹是特定时点的快照,不是长期有效的徽章;
- 历史快照区分:文档特别说明,更早的 content-review-2026-09-05.md 是警告清理之前的历史快照,不代表当前警告数量。
八、回归验证与已知边界:如何复现这 6 个用例
从仓库根目录运行:
python3 tools/scripts/tests/test_skill_worked_examples.py该套件共 6 个用例,覆盖:
- 空项目与非法
package.json的not-checked/ 退出码 2 行为; - Node 回退检查器指向本地
node_modules且缺省时失败而非下载; - 30 文件抽样上限与"一函数一计数"、解析错误上报;
- 发布版批量加载函数的绑定语义、空输入与注入式字符串;
- 复合游标在时间戳并列下的正确性;
- 相关子查询与 LEFT JOIN 聚合在零/一/多子行场景下的结果等价。
测试完全基于 Python 标准库与 SQLite,不触网、不连库、不测速。文档同时声明:Python 与 Node 的项目检测是启发式的;"通过 lint"不能证明没有运行时或安全缺陷(SKILL.md 的 "Limitations" 一节);SQLite 的正确性校验也不代表 PostgreSQL 的性能或生产安全。
九、可复用的方法论:如何评审一份技能文档
从这次定向复核中可以提炼出一套可复用的评审方法论:
- 圈定有界范围:明确"评审了哪些树、没有评审哪些",绝不把局部结论上升为全目录认证;
- 把文档示例变成可执行测试:从文档中提取发布的代码/ SQL 原文(而非凭印象重写)去执行——
test_skill_worked_examples.py用re.findall从 playbook 提取代码块再exec/ 执行,确保测试的就是读者将看到的那份代码; - 为边界条件写用例:空输入、超限、注入式字符串、时间戳并列、父行零子行——这些正是真实世界最容易翻车的地方;
- 诚实报告无法验证的部分:哪些检查没跑、哪些是启发式、哪些依赖外部环境,全部显式声明;
- 保留证据指纹:文件清单、SHA-256、测试命令,让评审可复现、可追溯。
结语
这份 follow-up 文档的价值不在于"修复了多少行代码",而在于它示范了一种对 Agent 生态至关重要的评审纪律:让"未检查"与"失败"泾渭分明,让"近似"与"精确"界限清晰,让文档中发布的每一段代码都能被测试直接验证。当技能文档成为 Agent 的行为依据时,这种纪律本身就是一种安全边界——它保证了 Agent 永远不会把"什么都没跑"误读为"全部通过",也保证了 SQL 示例在真实驱动上不会因为占位符语义而静默出错。仓库中的 lint-and-validate 与 sql-optimization-patterns 两个技能树,连同 test_skill_worked_examples.py 这套回归套件,就是这一纪律的完整可运行样本。
【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,600+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/GitHub_Trending/an/agentic-awesome-skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考