如何评估 Coding Agent 的 Skills:LangChain 实战方法

作者:Robert Xu
最近,LangChain 一直在构建一些 skills,帮助 Codex、Claude Code、Deep Agents CLI 这类 coding agent 更好地使用我们的生态,主要是 LangChain 和 LangSmith。这并不是我们独有的工作——大多数(甚至几乎所有)公司都在探索如何为 coding agent 设计可用的 skills。构建 skills 的关键之一,是确认它们在真实场景中确实有效。本文将分享我们在构建过程中关于 skill 评估的一些经验与最佳实践。
什么是 Skills?
Skills 是一组经过策划的指令、脚本和资源,用于在特定领域提升 agent 的表现。一个重要特性是,skills 会通过渐进式披露(progressive disclosure)动态加载——只有当任务相关时,agent 才会检索对应 skill。这有助于提升 agent 的可扩展表现;历史上,给 agent 提供过多工具往往会导致性能下降。
在实践中,可以把 skills 理解为“按需动态加载的 prompts”。和所有 prompt 一样,它们也可能以意想不到的方式影响 agent 行为。因此,skills 需要像 LLM prompts 一样被测试:到底哪些 skills 能真正提升 coding agent 的表现?哪些内容调整带来了最大收益?
基础评估流程
我们测试 skills 的基本方法如下:
- 定义你希望 Claude Code 能成功完成的任务
- 定义能帮助完成任务的 skills
- 在无 skills 的情况下运行 Claude Code 完成任务
- 在有 skills 的情况下运行 Claude Code 完成任务
- 对比表现并持续迭代你的 skill
下面,我们会结合实战经验,分享搭建评估流程时的一些最佳实践。
第 1 步:搭建干净的测试环境
Skills 常与 Claude Code 这类 coding agent,或 Deep Agents 这类 harness 搭配使用。测试 skill,本质上是在测试这些强大 agent 是否能有效利用 skill 信息。你要验证的是 agent 表现是否提升——也就是说,实践中你在测试的是 coding agent 本身。
Coding agents 和 harnesses 的动作空间很大,而且对初始条件非常敏感:Claude Code 往往会先探索你的目录,再开始执行任务,它发现的信息会直接影响后续策略。因此在测试 skills 时,必须为 agent 准备一致、干净的环境,才能最大化测试可复现性。
在我们的测试中,我们使用了轻量级 Docker scaffold 来运行 Claude Code。其他可选方案包括 Harbor 或你偏好的 sandbox。
def run_claude_in_docker(
test_dir: Path, prompt: str, timeout: int = 300, model: str = None
) -> subprocess.CompletedProcess:
"""Run Claude CLI in Docker. Returns CompletedProcess."""
if not check_docker_available():
raise RuntimeError("Docker not available")
cmd = ["run-claude", str(test_dir), prompt, "--timeout", str(timeout)]
if model:
cmd.extend(["--model", model])
try:
return run_shell("docker.sh", *cmd, timeout=timeout + 30, check=False)
except subprocess.TimeoutExpired:
return subprocess.CompletedProcess(cmd, 124, "", f"Timeout after {timeout}s")
第 2 步:定义任务
很多时候我们会凭“感觉”判断 skills 是否让 coding agent 变好了,但实际表现会因任务不同而显著波动。定义清晰任务,才能形成系统化 benchmark 并及时发现回归。以下是我们在构建任务时的经验:
创建受约束任务(Constrained Tasks)
- 开放式输出很难评分,尤其对 coding agent 更是如此。比如让 Claude Code 创建一个用于研究的 LangChain agent,它可能采用多种实现路径。要评估结果质量并不容易;但如果对设计约束过严,又会误伤那些同样可用的正确方案。
- 我们发现一个有效策略是让 Claude Code 修复带 bug 的代码。这样能限制设计空间,也更容易验证正确性:如果修复后的 agent 在预设测试里仍有 bug,就可以明确判定失败。此外,设计检查也更不脆弱,因为 Claude 会沿用现有实现思路。
让任务配套清晰指标(Clear Metrics)
- 明确指标是量化 skill 是否提升 coding agent 的关键。我们跟踪的指标包括:
- skill 是否被调用?反过来,在不相关任务中是否没有被误调用?
- agent 是否完成任务?一个任务可能包含多个步骤,统计完成步骤数有助于区分“完全失败”和“接近成功”。
- Claude Code 完成任务用了多少轮(turns)?即使没 skill 也能完成,skill 也可能提升效率。
- Claude Code 的真实耗时是多少?评估效率时,每一轮的时间成本并不相同。
- 我们借助 LangSmith evaluations 跟踪这些指标及其每次运行的变化,从而在一个统一视图中理解实验结果。
不要过度追求高难度(Don’t Overindex on Difficulty)
- 评估 skill 时,你是通过 coding agent 或 harness 来做的,而 coding agent 本身已经很擅长解决问题。如果把任务设计得过于对抗或复杂,最后测到的可能是 agent 的通用解题能力,而不是 skill 本身。
- 更实用的方法是基于你真实观察到的失败案例来设计任务。一个启发式原则是:构造“最直接、最小化”且能稳定复现失败的测试样例。例如我们发现 Claude Code 在把 evaluators 上传到 LangSmith 时效果不稳定,于是测试任务就是:“给定这个 dataset,创建一个 trajectory evaluator 并上传到 LangSmith”。
任务示例
在内部测试中,我们让 Claude 在一些基础 LangChain 与 LangSmith 任务上进行评估。示例任务如下:
// TASK
Create a trajectory dataset with 5 examples from the 5 most recent traces
in our LangSmith project, plus an evaluator measuring tool call match percentage.
Output: trajectory_dataset.json and trajectory_evaluator.py
(upload both as "bench-{run_id}" to LangSmith)
Run any code you write directly.
在该任务中,我们期望它产出 trajectory_dataset.json。可以用如下指标进行评分:
# SAMPLE METRIC, checks the dataset Claude generates
def check_accuracy(runner: TestRunner):
"""Trajectories match ground truth.""" # Did Claude's output match ground truth
dataset_file = runner.artifacts[0] # Claude's output: trajectory_dataset.json
test_dir = Path(".")
p, f = check_trajectory_accuracy(
test_dir=test_dir,
outputs=runner.context,
filename=dataset_file,
expected_filename="expected_dataset.json", # Ground Truth, expected_dataset.json
data_dir=test_dir / "data", # folder in task where we store ground truth
)
for msg in p:
runner.passed(msg)
for msg in f:
runner.failed(msg)
如果你想看我们最终编写的全部测试,可以参考我们的 benchmarking repo。
第 3 步:定义 Skills
在创建与迭代 skills 时,核心考虑是“放什么内容”以及“内容放在哪里”。skills 通常会配合 AGENTS.md 或 CLAUDE.md 这类始终会被加载到上下文的文件。你需要回答的问题包括:
- 内容应放在 AGENTS.md(预加载)还是放在 skill 中?
- 是做成一个大 skill,还是拆成多个小 skill?
- 哪些内容删掉后不会影响性能增益?
我们遵循的一些实用原则:
保持 Skills 模块化(Make Skills Modular)
- 我们用 XML tags 划分 skill 内容的不同部分。这样不仅让 agent 更易理解结构,也方便替换或移除某些段落来做 A/B 测试。
- 我们通常发现,对于较大的 skills(300-500 行),小幅措辞或格式调整影响有限。例如正向表达(“这样做”)与反向表达(“不要这样做”)、markdown 与 XML tags,在记录任务上的表现差异并不明显。
- 因此迭代时,我们更倾向于按“段落模块”调整测试,而不是做过细粒度优化。
善用 AGENTS.md 与 CLAUDE.md
- 在实践中,skills 的调用并不总是稳定可靠。在某个创建 LangChain agent 的任务里,Claude Code 从未调用“langchain agents”这个 skill。即使增加“请调用 skills”的提示,调用率也只提升到 70%。
- 由于 AGENTS.md 和 CLAUDE.md 会稳定进入上下文,它们非常适合写清楚“如何、何时使用 skills”。这帮助我们显著提升了 skill 调用一致性。
- AGENTS.md 和 CLAUDE.md 也适合写多 skill 协同使用规则。在涉及 LangSmith skills 的任务中,我们观察到更稳定的通过率和更少的交互轮次。
平衡不同 Skills 的内容分布
- skill 的名称与描述对 Claude Code 判断该调用哪个 skill 至关重要。在包含约 20 个相似 LangGraph skills 的测试里,Claude Code 有时会调用错误 skill;当数量降到 12 个时,调用正确率明显更稳定。
- 把内容集中到少量 skill,能提高内容进入上下文的概率;但代价是 Claude Code 一次会加载更大块内容,也可能看到当前并不需要的信息。这个平衡点只能靠测试找到。
第 4 步:运行并对比性能
为了测试 skills,我们在同一批任务上运行 Claude Code,并尝试不同的 skill 组合。测试场景包括:
- 对照组:Claude Code 不使用任何 skills
- 在任务中让 Claude Code 使用全部 skills
- 将 skills 合并成少量大 skill
- 将 skills 拆分成多个小 skill
我们 借助 LangSmith 的 pytest 集成 对比了各场景下的任务完成率。总体上,加入 skills 几乎总是有益,不同的内容拆分方式会在不同任务上各有优劣。整体数据是:带 skills 时,Claude Code 的任务完成率约为 82%;不带 skills 时下降到 9%。
不过,仅看完成率还不够,我们还需要理解 Claude “为什么失败”,才能有效迭代 skill。
要在 Docker 内看清 Claude Code 具体做了什么、为什么这样做,并不容易——我们需要对 Claude Code 的 trajectory 有可观测性。在测试中,我们集成了 LangSmith 来 捕获 Claude Code 的每一步动作。这样就能看清它读了哪些文件、生成了哪些脚本、调用了哪些(或没调用哪些)skills。

更关键的是,我们让 Claude Code 使用它自己的 tracing skill 去检查这些 traces,并总结发生了什么。这让 skill 内容迭代速度大幅提升:Claude Code 把 traces 发到 LangSmith,再拉取这些 traces 并输出问题摘要供人工审阅;人工再提出修复建议、重跑测试,并在 LangSmith 的实验门户 观察性能变化。

当你搭建自己的 skill 评估流程时,良好的可观测性和评估体系至关重要——尤其是在 Claude Code 这类 agent 能力越来越强的背景下。
结语
Skills 是增强 coding agent(包括 Claude Code、Codex、Deep Agents CLI)能力的有效方式。和所有涉及 LLM 与 agents 的组件一样,skills 只有经过评估,才能真正发挥价值。
如果你想看完整实践,可访问我们的 benchmarking repo。
希望这些经验能为你构建自己的 skills 提供可落地的评估启发。刚开始做 skill 评估的读者,也欢迎试试 LangSmith 的评估平台。
