一键导入
langgraph-interrupts
人机交互与动态中断和断点:暂停执行以供人工审查和使用 Command 恢复
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
人机交互与动态中断和断点:暂停执行以供人工审查和使用 Command 恢复
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | langgraph-interrupts |
| description | 人机交互与动态中断和断点:暂停执行以供人工审查和使用 Command 恢复 |
| language | js |
中断通过暂停图执行以等待外部输入来实现人机交互模式。LangGraph 保存状态并无限期等待,直到您恢复执行。
关键类型:
interrupt() 函数interruptBefore/interruptAfter| 类型 | 设置时机 | 使用场景 |
|---|---|---|
动态 (interrupt()) | 在节点代码内 | 基于逻辑的条件暂停 |
静态 (interruptBefore) | 在编译时 | 在特定节点之前调试/测试 |
静态 (interruptAfter) | 在编译时 | 在特定节点之后审查输出 |
import { interrupt, Command } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph";
const reviewNode = async (state) => {
// 有条件地暂停以供审查
if (state.needsReview) {
// 暂停并向用户展示数据
const userResponse = interrupt({
action: "review",
data: state.draft,
question: "Approve this draft?",
});
// userResponse 来自 Command({ resume: ... })
if (userResponse === "reject") {
return { status: "rejected" };
}
}
return { status: "approved" };
};
const checkpointer = new MemorySaver();
const graph = new StateGraph(State)
.addNode("review", reviewNode)
.addEdge(START, "review")
.addEdge("review", END)
.compile({ checkpointer }); // 必需!
// 初始调用 - 将暂停
const config = { configurable: { thread_id: "1" } };
const result = await graph.invoke(
{ needsReview: true, draft: "content" },
config
);
// 检查中断
if ("__interrupt__" in result) {
console.log(result.__interrupt__); // 查看中断负载
}
// 使用用户决策恢复
const finalResult = await graph.invoke(
new Command({ resume: "approve" }), // 用户的响应
config
);
const checkpointer = new MemorySaver();
const graph = new StateGraph(State)
.addNode("step1", step1)
.addNode("step2", step2)
.addNode("step3", step3)
.addEdge(START, "step1")
.addEdge("step1", "step2")
.addEdge("step2", "step3")
.addEdge("step3", END)
.compile({
checkpointer,
interruptBefore: ["step2"], // 在 step2 之前暂停
interruptAfter: ["step3"], // 在 step3 之后暂停
});
const config = { configurable: { thread_id: "1" } };
// 运行到第一个断点
await graph.invoke({ data: "test" }, config);
// 恢复(在下一个断点暂停)
await graph.invoke(null, config); // null = 恢复
// 再次恢复
await graph.invoke(null, config);
import { interrupt, Command } from "@langchain/langgraph";
const toolExecutor = async (state) => {
const toolCalls = state.messages.at(-1)?.tool_calls || [];
const results = [];
for (const toolCall of toolCalls) {
// 为每个工具调用暂停
const userDecision = interrupt({
tool: toolCall.name,
args: toolCall.args,
question: "Execute this tool?",
});
let result;
if (userDecision.type === "approve") {
// 执行工具
result = await executeTool(toolCall);
} else if (userDecision.type === "edit") {
// 使用编辑后的参数
result = await executeTool(userDecision.args);
} else { // reject
result = "Tool execution rejected";
}
// 存储结果
results.push(new ToolMessage({
content: result,
tool_call_id: toolCall.id,
}));
}
return { messages: results };
};
// 使用
const result = await graph.invoke({ messages: [...] }, config);
// 审查并批准
await graph.invoke(new Command({ resume: { type: "approve" } }), config);
// 或编辑参数
await graph.invoke(
new Command({ resume: { type: "edit", args: { query: "modified" } } }),
config
);
// 或拒绝
await graph.invoke(new Command({ resume: { type: "reject" } }), config);
const config = { configurable: { thread_id: "1" } };
// 运行到中断
await graph.invoke({ data: "test" }, config);
// 在恢复之前修改状态
await graph.updateState(config, { data: "manually edited" });
// 使用编辑后的状态恢复
await graph.invoke(null, config);
const config = {
configurable: { thread_id: "1" },
streamMode: ["updates", "messages"] as const,
};
for await (const [mode, chunk] of await graph.stream({ query: "test" }, config)) {
if (mode === "updates") {
if ("__interrupt__" in chunk) {
// 处理中断
const interruptInfo = chunk.__interrupt__[0].value;
const userInput = await getUserInput(interruptInfo);
// 恢复
await graph.invoke(new Command({ resume: userInput }), config);
break;
}
}
}
✅ 在节点中的任何位置调用 interrupt()
✅ 设置编译时断点
✅ 使用 Command({ resume: ... }) 恢复
✅ 在中断期间编辑状态
✅ 在处理中断时流式传输
✅ 条件中断逻辑
❌ 在没有检查点器的情况下中断 ❌ 修改中断机制 ❌ 在没有 thread_id 的情况下恢复
// ❌ 错误 - 没有检查点器
const graph = builder.compile(); // 没有持久化!
await graph.invoke(...); // 中断不起作用
// ✅ 正确
const checkpointer = new MemorySaver();
const graph = builder.compile({ checkpointer });
// ❌ 错误 - 没有 thread_id
await graph.invoke({ data: "test" }); // 无法恢复!
// ✅ 正确
const config = { configurable: { thread_id: "session-1" } };
await graph.invoke({ data: "test" }, config);
// ❌ 错误 - 传递常规对象
await graph.invoke({ resumeData: "approve" }, config); // 重新开始!
// ✅ 正确 - 使用 Command
import { Command } from "@langchain/langgraph";
await graph.invoke(new Command({ resume: "approve" }), config);
// ❌ 错误
const result = graph.invoke({}, config);
console.log(result); // Promise!
// ✅ 正确
const result = await graph.invoke({}, config);
console.log(result);
Mac 系统深度清理和优化工具。使用 Mole (mo 命令) 执行系统清理、磁盘分析、应用卸载、系统优化等任务。 触发场景(当用户提到以下任一内容时使用此 skill): - 清理 Mac、清理磁盘、释放空间、清理缓存、清理系统 - 卸载应用、删除应用、移除应用及其残留 - 磁盘分析、查看磁盘占用、大文件查找、空间分析 - 系统优化、系统维护、刷新系统、重建缓存 - 系统状态、系统监控、CPU/内存/磁盘监控 - 清理 node_modules、清理构建产物、清理项目依赖 - 清理安装包、删除 dmg/pkg 文件 - Mac 清理工具、类似 CleanMyMac 的功能 - "我的 Mac 太慢了"、"磁盘空间不足"、"电脑卡顿" - 即使没有明确说 "Mole",只要涉及上述场景就应使用
快速搭建和配置 pnpm monorepo 项目结构,包含 TypeScript、tsup 构建、私有 npm registry 配置。当用户需要"创建 monorepo"、"初始化 monorepo 项目"、"配置 pnpm workspace"、"设置 monorepo 构建"、"monorepo setup"时使用。特别适合需要统一管理多个包、配置构建工具、处理 TypeScript 路径问题的场景。即使用户只是说"帮我搭建项目结构"或"配置构建",如果涉及多包管理也应该使用此 skill。
智能拆分暂存区的代码变更为多个符合 Conventional Commits 规范的逻辑提交。当用户需要将大量变更按逻辑关系分组提交时使用,比如"拆分这些提交"、"把暂存区的变更分成多个 commit"、"按功能分别提交"、"split commits"等场景。特别适合处理包含多个模块、多种类型文件(配置、代码、测试、文档)的复杂变更集。
OKR 优化与质量评估专家。当用户需要:(1) 评估现有 OKR 的质量,(2) 优化模糊或不可量化的关键结果,(3) 检查 OKR 是否符合核心原则(聚焦、可量化、有挑战),(4) 将任务型 KR 转化为结果型 KR,(5) 提供具体的改进建议时使用。触发词包括"帮我优化 OKR"、"检查这个 OKR"、"这个 KR 写得好吗"、"如何量化这个目标"。
基于 git commits 自动生成 CHANGELOG.md 变更日志。支持语义化版本、分类整理、多格式输出。触发场景包括"生成变更日志"、"更新 CHANGELOG"、"版本记录"。
GitHub PR 代码审查技能。检查代码质量、安全性、性能和最佳实践,生成结构化审查报告。触发场景包括"审查 PR"、"代码检查"、"review pull request"。