最近 LangChain 提出了一种很实用的思路:Interpreter Skills。它不是简单给 Agent 多一段提示词,而是把“可复用的工作流程”做成一个可执行模块,让模型决定何时调用,代码负责把流程跑稳。
这件事的价值很直接:当一个 Agent 需要反复执行固定套路时,纯靠提示词很容易飘;而把关键步骤收进代码后,流程就能被测试、复用、评审,也更容易做评估。
先说结论
Interpreter Skills 本质上是在补 Agent 架构里最缺的一块:把确定性的部分从模型脑子里拿出来,放进可审计的代码里。
如果你只记住一句话,那就是:
- 普通 Skill 负责“告诉模型怎么想”
- Interpreter Skill 负责“告诉系统怎么跑”
这两个层次分开后,Agent 的行为会更稳定,尤其适合 triage、分类、整理、聚合、批处理这类重复性高、步骤明确的任务。
为什么普通 Skill 不够
传统 Skill 的形态通常是:
- 在 SKILL.md 里写规则和例子
- 模型读取这些说明
- 模型自己决定怎么执行
问题在于,模型并不会每次都严格按同一个流程走。只要任务稍复杂一点,它就可能:
- 省略中间步骤
- 调整执行顺序
- 用“看起来合理”的方式替代“规定的方式”
- 在长任务里逐渐漂移
这对一次性问答没什么大问题,但对需要稳定复现的工作流就很危险。
Interpreter Skills 的核心结构
LangChain 这套设计把 Skill 分成了两层:
- SKILL.md:负责发现和说明,告诉 Agent 什么时候该用它
- index.ts:负责真正执行,里面是可测试、可复用的确定性逻辑
可以把它理解成“说明书 + 执行器”的组合。
flowchart LR
U[用户请求] --> A[Agent]
A --> S[SKILL.md<br/>判断是否适用]
S --> I[index.ts<br/>执行确定性流程]
I --> T[工具 / 子 Agent / 任务图]
T --> R[结构化结果]
R --> A
A --> O[最终回答]
这里最关键的变化是:模型不再亲自手工拼流程,而是把流程交给代码,自己只负责判断“要不要调用、传什么参数、怎么解释结果”。
它解决了什么问题
1. 让流程更稳定
如果一个动作每次都要靠模型临场发挥,结果就会受上下文长度、提示词顺序、局部噪声影响。
把流程收进代码后,步骤就固定了。比如:
- 拉取待处理列表
- 为每项创建子任务
- 汇总子任务结果
- 按规则聚类或分类
这种活交给代码更靠谱,因为代码不会“心情不好就跳步骤”。
2. 让评估更明确
纯提示词流程的评估往往很虚:
- 是不是“看起来像做对了”?
- 最终答案是不是“差不多”?
Interpreter Skill 之后,评估目标会变得具体很多:
- 有没有调用预期函数
- 有没有传入正确参数
- 返回值结构对不对
- 某个步骤有没有完整跑完
这对 Agent 迭代非常重要,因为你终于能评价“过程”而不只是“结果”。
3. 让复杂工作流可以复用
很多 Agent 工作并不是单次推理,而是重复性的业务流程。
比如:
- GitHub issue triage
- 工单分类
- 数据清洗
- 文档摘要
- 批量审核
这些任务的最佳实践往往稳定存在。把它们写成代码后,团队就能共享同一套路,而不是每个 Prompt 各写一版。
和普通 Skill 的区别
| 维度 | 普通 Skill | Interpreter Skill |
|---|---|---|
| 主要内容 | 文字说明、规则、例子 | 说明 + 可执行模块 |
| 流程稳定性 | 依赖模型执行 | 确定性逻辑由代码保证 |
| 可测试性 | 弱 | 强 |
| 评估粒度 | 结果偏主观 | 过程更可观测 |
| 适合场景 | 轻量、低风险任务 | 重复性高、步骤明确的工作流 |
一句话总结:普通 Skill 更像“操作手册”,Interpreter Skill 更像“操作手册 + 自动化脚本”。
LangChain 的 Repo Triage 思路
文章里给了一个很典型的例子:仓库 triage。
想象一下,你要处理一个仓库里的大量 issue 或 PR。这个任务看起来像“让 Agent 看一遍然后总结”,但真正难点是:
- 数据很多
- 决策很多
- 中间状态很多
- 过程不能乱
如果完全交给模型,它很容易在长流程里丢状态、漏步骤,或者在多个候选之间来回摇摆。
Interpreter Skill 的做法是把 triage 做成一个可执行流程,大致可以抽象成这样:
flowchart TD
A[拉取 open items] --> B[为每个 item 创建子 Agent 摘要]
B --> C[结果进入队列]
C --> D[逐个消费队列]
D --> E{放进已有簇吗}
E -- 是 --> F[更新现有簇]
E -- 否 --> G[创建新簇]
F --> H[生成结构化报告]
G --> H
这里的关键点不是“Agent 很聪明”,而是流程本身被固定了。
模型只需要:
- 判断何时调用 triage 工作流
- 给出输入参数
- 读取结构化结果
- 再做下一步决策
这样一来,最容易出错的那部分,不再靠模型临场组织。
一个更贴近工程实践的理解
你可以把 Interpreter Skill 看成三层分工:
- SKILL.md 负责“发现”
- index.ts 负责“执行”
- Agent 负责“调度和解释”
这其实非常符合工程里最稳的分层方式:
- 文档解决“什么时候用”
- 代码解决“怎么做”
- 模型解决“何时启动、如何组合”
这比把所有逻辑都塞进 prompt 里更像真正的系统设计。
一个简化版示例
下面这个例子不追求和原文逐字一致,而是帮助你理解它的工程形态。
// skills/github-triage/index.ts
export async function triage(repo: string, options: { issues?: boolean; prs?: boolean }) {
const items = await fetchOpenItems(repo, options);
const summaries = [];
for (const item of items) {
const summary = await spawnSubagent(`Summarize ${item.id}`, {
task: item.title,
});
summaries.push({ item, summary });
}
const clusters = await clusterByTheme(summaries);
return {
repo,
total: items.length,
clusters,
toMarkdown() {
return renderReport(clusters);
},
};
}
这段代码的重点不是语法,而是思路:
- 输入可以动态变化
- 过程由代码固定
- 子任务可以并发或排队执行
- 最终返回结构化结果
这就是 Agent 工作流从“自然语言驱动”走向“可编排系统”的分水岭。
什么时候该用它
适合用 Interpreter Skills 的场景,通常有几个共同特征:
- 流程重复,且希望每次执行一致
- 中间步骤多,不适合全靠模型记忆
- 需要子任务编排、队列、聚类、汇总
- 需要过程评估,而不是只看最终答案
不太适合的场景也很明确:
- 一次性、短平快的问答
- 没有固定流程的探索性任务
- 任务本身比“怎么做”更重要,而不是“按什么步骤做”
落地建议
如果你在自己的 Agent 系统里想借鉴这个思路,我建议按这个顺序做:
- 先找出最稳定、最重复的那段流程
- 把它从 prompt 中抽出来,做成函数
- 让 Skill 只负责发现和触发
- 让函数返回结构化结果
- 给这个函数单独写测试和评估
这样改造的收益最大,因为你不是一次性重构整个 Agent,而是在最容易漂移的地方先加护栏。
最后怎么理解这篇文章
LangChain 这篇文章真正想讲的,不只是“Skill 能跑代码了”,而是一个更大的方向:
Agent 系统里,模型负责灵活性,代码负责确定性。
这个边界一旦划清楚,你会发现很多以前只能靠 prompt 碰运气的事情,都可以逐步工程化。
这也是我觉得 Interpreter Skills 最有价值的地方:它不是为了炫技,而是把“好用的 Agent 工作流”变成了“可维护的工程组件”。