给 Coding Agent 的方法论 Skill
hikarilan-skills

Coding Agent 总在过度设计?
用这 4 个 Skill 管住它

Coding Agent 能写代码,但在项目开发和 Agent 开发的最佳实践上,它的 taste 还差得远:堆无用的单测、只修一个切面、动不动就加抽象和兜底、在代码里替模型做决定。下面四个 Skill 是我在一个真实的 Agent 项目里和大模型反复斗智斗勇后总结出来的方法论。

agent-habits.diff4 files changed
-给每个函数补一堆 mock 满天飞的单元测试
+e2e-first-testing // 从入口写端到端场景
-只修报上来的那一处,再加个兜底 if
+structural-fix // 让整类缺陷消失
-新增三个配置项、一层抽象和一条兼容路径
+minimal-design-gate // 先说清为什么不能更简单
-if "取消" in reply or "cancel" in reply: ...
+llm-agent-surface // 语义交给模型

老实说,我也是那种能不用 Skill 就不用 Skill 的人。

但这几个 Skill 都在真实项目中验证过,有效,而且足够通用,不绑定任何语言或框架。它们都收在我的 Skill 合集仓库 shaokeyibb/hikarilan-skills 里,彼此独立,按需安装即可。下面每个 Skill 都按"痛点、引入了什么、效果"来讲,效果部分可以切换着看前后对比。

少写单测,从项目入口写覆盖全面的 E2E 测试。

痛点

让 Agent "补一下测试",它会给每个函数生成一大堆单元测试,把内部依赖全部 mock 掉,再断言 mock 被调用了一次。覆盖率很好看,可这些测试数量巨大,几乎抓不住任何回归:改个函数名就大面积变红,真出了 bug 反而全绿。

引入

一套以 E2E 为优先的测试方法论。测试的价值只有一条标准:调用方依赖的行为坏了它就变红,行为没变它就保持绿。

  • 从真实调用方的入口进入:CLI 命令、SDK 调用、HTTP 路由、MCP tool,并且使用和生产环境同一套依赖装配。
  • 测试替身只放在外部边界:LLM provider、浏览器驱动、远程服务、时钟、随机数。仓库自己的模块一律保持真实。
  • 隔离测试先列失败方式:解析器、调度算法这类值得单独测的逻辑,先列全所有出错方式再写代码。
  • 附带 exclusive_coverage.py 脚本,用来找出并清理遗留套件里的冗余测试。
一个 E2E 场景走过的路径
生产入口CLI / SDK / HTTP
→
生产装配同一套 factory
→
真实内部模块不 mock
→
外部边界替身LLM / 时钟 / 远程服务
效果
让 Agent 给"提问"功能补测试
# tests/unit/test_handler.py (同类文件还有 40 多个)
def test_handle_request(mocker):
    mocker.patch("app.router.dispatch")
    mocker.patch("app.store.save")
    mocker.patch("app.llm.client.chat")
    handle_request({"q": "hi"})
    app.router.dispatch.assert_called_once()
断言的是实现细节重构一下就红真实路径从没跑过

示例为示意代码。

  • 测试更少,但每个都有用每个测试对应一条调用方真正依赖的行为。
  • 重构不再大面积变红只要行为不变,内部怎么改测试都是绿的。
  • 回归能被抓住bug 就出在生产路径上,测试走的也是这条路径。
npx skills add shaokeyibb/hikarilan-skills --skill e2e-first-testing
GitHub ↗

修一个 BUG,就让这一类 BUG 一起消失。

痛点

报一个 BUG 给 Agent,它会精准地修好报告里的那一处:加个 if 判断、加个兜底、加个重试上限,然后说"已修复"。同样模式的代码在仓库别处还活着,过几天换个方向又冒出来,兜底分支也越积越多。

引入

一套系统性、结构化的修复流程:先给缺陷归类,再找出所有同类,最后从根上让错误写不出来。

  • 先给缺陷归类:动代码前写两句话,这是哪一类缺陷,违反了哪条通用规则。
  • 按"错误的形状"全仓搜索:仓库和上下游依赖一起搜,每个命中都要给出处置,并附上可复现的搜索命令。
  • 先看数据结构:常见根因是两类数据混在同一个结构里,修法是把结构拆开,而不是在读取端过滤。
  • 修输入,不拦输出:不用计数器、熔断、关键词守卫掩盖问题,而是用必填参数、封闭枚举、唯一入口让错误调用写不出来。
从实例到规则
实例对话框关闭了两次
类两个 owner 都在决定对话框的生命周期
规则生命周期只有一个 owner
效果
BUG:点击"确定"后弹窗关闭了两次
// ConfirmDialog.tsx
  function onConfirm() {
+   if (this.closed) return;   // 防止重复关闭
    this.close();
  }

修复说明:已修复确认弹窗重复关闭的问题。
只修了一个弹窗又多一个兜底分支根因还在

示例为示意。

  • 同一个坑不踩第二次一次改动清掉整类问题,而不是等它从别处再冒出来。
  • 修复通常删的比加的多不靠堆兜底分支,代码越修越干净。
  • 修复说明可以审归类、搜索命令、每个命中的处置都写在明面上。
npx skills add shaokeyibb/hikarilan-skills --skill structural-fix
GitHub ↗

先给最小方案,并说明为什么不能更简单。

痛点

过度设计是 Coding Agent 最典型的毛病:一个小需求,它会顺手给你一个工厂、一层抽象、三个配置项、一条兼容旧数据的路径,外加一个"以防万一"的兜底。每一项单独看都合理,叠在一起就是没人敢删的复杂度。

引入

一道防过度设计的闸门,前后各过一次:动手前审提案,合并前审交付。不保留兼容遗留代码,有成熟的开源方案就优先用。

两道闸门
提出方案
→
GATE 1五个问题 + 最小方案
→
实现
→
GATE 2交付清单逐项过
→
合并
Gate 1 的五个问题(点开看解释)

它解决的是这一类问题,还是只解决眼前这一个实例?

用户、其他模块、填 Schema 的模型,是否因此多了要填的字段或要做的选择?

交给调用方的东西里,有没有系统本可以自己测量或推导出来的?能确定的由系统确定,调用方只负责选择。

方案带来的复杂度,是否超出了问题本身需要的程度?

它是不是只为某一次观察到的情况、某一个输入、某一个具体组件服务?

效果
需求:报表支持导出 CSV
方案:
+ exporters/base.py      AbstractExporter
+ exporters/factory.py   ExporterFactory + 插件注册
+ exporters/csv.py       CsvExporter
+ config  export.format / export.delimiter / export.legacy_mode
+ 兜底    CSV 导出失败时回退为 JSON
抽象只有一个实现三个配置项没人读为不存在的旧数据做兼容

示例为示意。

  • 方案先变小,再动手Agent 要先解释为什么不能更简单,而不是直接开写。
  • 交付前再筛一遍单调用方抽象、无读取方配置、兼容路径,要么删掉,要么写明理由。
  • 能用现成的就不造轮子重试、Schema 解析、缓存、限流,先看标准库和开源库。
npx skills add shaokeyibb/hikarilan-skills --skill minimal-design-gate
GitHub ↗

llm-agent-surface

Agent 开发

什么交给模型,什么交给框架。

痛点

让 Coding Agent 写 Agent 应用时,它总想在代码里替模型做决定:用关键词列表判断用户意图,让模型去填坐标、颜色这类框架自己就能算出来的字段,模型一输出不对就往 prompt 里再补一句"请务必严格遵守格式"。Schema 越来越长,模型反而越来越不稳定。

引入

一套 Agent 应用开发的最佳实践。框架只做两件事:把完整、准确的证据放到模型面前,再在硬边界内执行模型的决定。模型的输入输出面尽量精简,并且默认模型的输出一定是对的。

分工

框架负责

  • 能确定性测量的值:颜色、几何、计数、阈值
  • 把模型给出的标签精确映射到真实值
  • 记账、缺省值、控制流结果

模型负责

  • 语义判断:是否通过、是否等价、是否安全
  • 选择:用不用某机制、哪种模式、什么范围
  • 在结构化输出里声明自己的意图
  • 不用词表猜语义:影响控制流的逻辑里不出现关键词列表和子串匹配。词表永远列不全,中文之后还有英文,"和"之后还有"以及"。
  • Schema 只在有证据时才增长:模型要填的每个字段、枚举值、few-shot 示例,都会占用它每次调用的推理预算。
  • 拒绝消息只陈述规则:说明哪个字段、在什么条件下、必须是什么,不去猜模型本来想干什么。
效果
让 Agent 实现"点击对话框按钮"这个 tool
# 模型要填:x, y, width, height, color, label, action, confidence
out = llm.call(schema=ClickSchema)
if "取消" in out.label or "cancel" in out.label:
    abort()
elif not valid(out) and retries < 3:
    prompt += "\n注意:请务必严格按照格式输出!"
模型在填框架能算的值词表决定控制流prompt 越补越长

示例为示意代码。

  • 模型输出更稳定要填的东西少了,模型能把推理花在真正需要判断的地方。
  • 行为可以预测该确定的由框架确定,不再有藏在 if 里的隐式启发式规则。
  • 不再靠补 prompt 救火出错时先看证据给全了没有,而不是再加一句提示。
npx skills add shaokeyibb/hikarilan-skills --skill llm-agent-surface
GitHub ↗

仓库里还有这些

安装

支持 Claude Code 以及其他读取 Agent Skills 格式的 Coding Agent。下面的命令会列出仓库里所有 Skill,勾选需要的即可;加上 -g 装到用户级。

npx skills add shaokeyibb/hikarilan-skills
在 GitHub 上查看 ↗