最近 LangChain 提出了一种很实用的思路:Interpreter Skills。它不是简单给 Agent 多一段提示词,而是把“可复用的工作流程”做成一个可执行模块,让模型决定何时调用,代码负责把流程跑稳。

这件事的价值很直接:当一个 Agent 需要反复执行固定套路时,纯靠提示词很容易飘;而把关键步骤收进代码后,流程就能被测试、复用、评审,也更容易做评估。

先说结论

Interpreter Skills 本质上是在补 Agent 架构里最缺的一块:把确定性的部分从模型脑子里拿出来,放进可审计的代码里。

如果你只记住一句话,那就是:

  • 普通 Skill 负责“告诉模型怎么想”
  • Interpreter Skill 负责“告诉系统怎么跑”

这两个层次分开后,Agent 的行为会更稳定,尤其适合 triage、分类、整理、聚合、批处理这类重复性高、步骤明确的任务。

为什么普通 Skill 不够

传统 Skill 的形态通常是:

  1. 在 SKILL.md 里写规则和例子
  2. 模型读取这些说明
  3. 模型自己决定怎么执行

问题在于,模型并不会每次都严格按同一个流程走。只要任务稍复杂一点,它就可能:

  • 省略中间步骤
  • 调整执行顺序
  • 用“看起来合理”的方式替代“规定的方式”
  • 在长任务里逐渐漂移

这对一次性问答没什么大问题,但对需要稳定复现的工作流就很危险。

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 的区别

维度普通 SkillInterpreter 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 看成三层分工:

  1. SKILL.md 负责“发现”
  2. index.ts 负责“执行”
  3. 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 系统里想借鉴这个思路,我建议按这个顺序做:

  1. 先找出最稳定、最重复的那段流程
  2. 把它从 prompt 中抽出来,做成函数
  3. 让 Skill 只负责发现和触发
  4. 让函数返回结构化结果
  5. 给这个函数单独写测试和评估

这样改造的收益最大,因为你不是一次性重构整个 Agent,而是在最容易漂移的地方先加护栏。

最后怎么理解这篇文章

LangChain 这篇文章真正想讲的,不只是“Skill 能跑代码了”,而是一个更大的方向:

Agent 系统里,模型负责灵活性,代码负责确定性。

这个边界一旦划清楚,你会发现很多以前只能靠 prompt 碰运气的事情,都可以逐步工程化。

这也是我觉得 Interpreter Skills 最有价值的地方:它不是为了炫技,而是把“好用的 Agent 工作流”变成了“可维护的工程组件”。

参考资料:https://www.langchain.com/blog/interpreter-skills