跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言Agent RuntimeTool RuntimePermissionSandbox试读章节

《Agent Runtime 工程化》试读章节:Tool Runtime 与权限审批

试读章节:Tool Runtime 与权限审批 这篇继续放《Agent Runtime 工程化》的试读。 上一篇讲 Agent Loop 的生命周期。 这一篇讲工具。 更准确地说,是 Tool Runtime。 因为在生产级 Agent 里

陈堂会发布于 —2 浏览
《Agent Runtime 工程化》试读章节:Tool Runtime 与权限审批

试读章节:Tool Runtime 与权限审批

这篇继续放《Agent Runtime 工程化》的试读。

上一篇讲 Agent Loop 的生命周期。

这一篇讲工具。

更准确地说,是 Tool Runtime。

因为在生产级 Agent 里,工具不是函数列表。

工具是 Agent 行动的治理入口。

工具不是 Map<string, Function>

很多 demo 会这样写:

const tools = {
  read_file,
  write_file,
  run_command,
};

模型返回:

{"name":"read_file","arguments":{"path":"README.md"}}

程序执行:

await tools[call.name](call.arguments);

这能跑。

但只适合 demo。

一旦工具能写文件、跑命令、联网、访问数据库,你就不能只关心'函数怎么调用'。

你要关心:

这个工具是否存在?
参数是否合法?
参数行为是否安全?
风险等级是什么?
是否需要用户批准?
输出太大怎么办?
失败如何反馈模型?
副作用如何进入 checkpoint?

所以工具要先'上户口'。

ToolDefinition 至少要说清楚什么

一个工具定义,最少要覆盖四类读者。

模型要读工具名、描述和 schema,用来决定是否调用。

Permission Gate 要读风险、副作用、资源范围和 preview,用来决定是否允许执行。

Executor 要读 timeout、并行安全、取消信号和输出策略,用来控制执行。

Context Builder 要读 output policy,用来决定工具结果如何进入上下文。

可以从这样的结构开始:

type ToolDefinition<TInput = unknown> = {
  name: string;
  version: string;
  description: string;
  inputSchema: ObjectSchema;
  risk: "read" | "write" | "shell" | "network" | "dangerous";
  parallelSafe: boolean;
  source: "local" | "mcp";
  outputPolicy: {
    maxChars: number;
    modelSummary: "full" | "head_tail" | "summary_only";
  };
  execute(input: TInput, context: ToolContext): Promise<ToolResult>;
};

少这些字段,系统不会立刻报错。

但后面某个模块一定会用猜的。

工程事故常常就是从'先随便填一下'开始的。

Schema 只说明长得对,不说明能执行

以 read_file 为例。

schema 可能只要求:

const ReadFileInput = {
  type: "object",
  required: ["path"],
  properties: {
    path: { type: "string" },
    startLine: { type: "integer", optional: true },
    endLine: { type: "integer", optional: true },
  },
};

这能证明什么?

只能证明 path 是字符串。

它不能证明:

path 在 workspace 内
path 不是 symlink escape
path 不是 .env
文件大小适合进入上下文
用户有权限读取

所以要分三层:

Schema validation:参数形状对不对。
Policy validation:这个行为是否允许。
Approval decision:是否需要人确认。

把这三层混在一起,后面测试会很痛。

Tool Registry 先生成计划

模型返回 tool call 后,不应该直接 execute。

Runtime 应先生成工具计划:

type ToolPlan = {
  call: ToolCall;
  tool?: ToolDefinition;
  validationErrors: string[];
};

示例:

class ToolRegistry {
  plan(call: ToolCall): ToolPlan {
    const tool = this.tools.get(call.name);
    if (!tool) {
      return { call, validationErrors: ["UNKNOWN_TOOL"] };
    }

    const validation = validateObjectSchema(tool.inputSchema, call.input);
    if (!validation.ok) {
      return { call, tool, validationErrors: validation.errors };
    }

    return { call, tool, validationErrors: [] };
  }
}

计划阶段的价值,是把风险摊开。

工具不存在,不执行。
参数非法,不执行。
高风险工具,进入审批。
只读工具,可以自动允许。
写入工具,生成 preview。

Runtime 要在执行前知道自己准备做什么。

PermissionGate 是 Runtime 的裁判

工具自己不应该决定'我能不能执行'。

工具可以声明风险。

Runtime 根据工具风险、参数、用户策略和当前模式做裁决。

一个最小决策对象:

type PermissionDecision = {
  callId: string;
  toolName: string;
  action: "allow" | "deny" | "ask";
  reason: string;
  risk: "read" | "write" | "shell" | "network" | "dangerous";
  decidedAt: string;
  preview?: string;
};

demo 里可以这样处理:

read:自动允许
shell:如果 allowShellReadonly=true,允许只读 shell
network:默认拒绝
write:需要显式 allowWrites
dangerous:默认拒绝

真实产品里,ask 会进入 UI 审批。

但不管是 policy 自动裁决,还是用户点击批准,都要写入 trace。

审批是系统事实。

不是前端弹窗状态。

写文件为什么必须 preview

写文件工具不能只显示:

Allow write_file?

用户不知道它要写哪里,也不知道改什么。

一个可用 preview 至少要说清:

目标路径
内容长度
是否新建文件
diff 摘要
写入原因
是否会覆盖已有内容

学习 demo 可以先简化:

function previewWrite(plan: ToolPlan): string | undefined {
  if (plan.call.name !== "write_text") return undefined;
  const input = plan.call.input as { path?: unknown; content?: unknown };
  return `准备写入 ${String(input.path ?? "unknown")},内容长度 ${String(input.content ?? "").length} 字符。`;
}

生产系统里,最好给 diff。

因为用户批准的不是'运行一个工具'。

用户批准的是具体副作用。

Shell 工具要保守

Shell 是最有用也最危险的工具。

npm test 看起来安全,但 test script 可以做任何事。
node script.js 看起来普通,但脚本可以联网、删文件、读环境变量。
curl 可能只是查资料,也可能上传数据。

所以 shell policy 第一版应该保守。

示例:

const READONLY_COMMANDS = new Set(["pwd", "ls", "find", "rg", "cat", "sed", "wc"]);

function classifyReadonlyCommand(command: string) {
  const first = command.trim().split(/\s+/)[0] ?? "";
  if (!READONLY_COMMANDS.has(first)) return "DENY_UNKNOWN_COMMAND";
  if (/[>|;&`$]/.test(command)) return "DENY_SHELL_OPERATOR";
  if (/\b(rm|mv|cp|chmod|chown|curl|wget|ssh|sudo)\b/.test(command)) {
    return "DENY_RISKY_TOKEN";
  }
  return "ALLOW_READONLY_COMMAND";
}

这不是完美沙箱。

它是第一层策略。

后面还要配合:

workspace cwd
环境变量过滤
timeout
输出上限
进程树清理
网络策略
sandbox profile
trace

不要指望一个正则表达式守住所有安全边界。

Workspace 边界是底线

文件工具必须限制在 workspace 内。

这件事不能靠 prompt。

路径检查也不能只做字符串前缀。

更稳的方式是:

先 path.resolve
再 realpath
再 path.relative 判断是否逃出 workspace
写入时检查父目录真实路径
拒绝写入 symlink

本书 demo 里,resolveForWrite 会拒绝 symlink 写入:

if (stat.isSymbolicLink()) {
  throw new WorkspaceSecurityError("拒绝写入符号链接目标", "DENY_SYMLINK_WRITE");
}

这类代码看着不酷。

但很重要。

很多工具事故不是发生在模型'想作恶'。

而是发生在路径、符号链接、环境变量、默认工作目录这些细节里。

ToolResult 要同时服务模型和工程系统

工具结果不能只返回:

done

也不能把完整日志一股脑塞回模型。

一个更可用的结构:

type ToolResult = {
  callId: string;
  toolName: string;
  status: "ok" | "error" | "denied" | "timeout" | "cancelled";
  content: string;
  errorCode?: string;
  metadata: {
    durationMs: number;
    outputChars: number;
    truncated: boolean;
    retryable: boolean;
    sideEffects?: ToolSideEffect[];
  };
};

content 是给模型继续推理的 observation。

metadata 是给 Runtime、trace、eval 和 checkpoint 的证据。

如果工具被拒绝,要返回 denied。
如果命令超时,要返回 timeout。
如果输出被截断,要标记 truncated。
如果写了文件,要记录 sideEffects。

这就是 Tool Runtime 和普通函数调用的差别。

权限拒绝也要写回模型

当写入被拒绝时,不应该直接崩溃。

更好的做法是生成一个 tool result:

status: denied
errorCode: PERMISSION_DENIED
content: 写入工具需要显式开启 --allow-writes。
retryable: false

然后写回 message history。

模型下一步应该基于这个 observation 停止,或者找低风险替代方案。

如果 Runtime 只是抛异常,模型看不到拒绝原因,用户也只看到程序失败。

一条工具治理管线

把整个流程串起来,是这样:

ToolDefinition
  ↓
ToolRegistry.plan()
  ↓
schema validation
  ↓
policy validation
  ↓
PermissionGate.review()
  ↓
preview / allow / ask / deny
  ↓
ToolExecutor.execute()
  ↓
ToolResult normalize
  ↓
MessageStore + Trace + Checkpoint

这条线少一步都容易出事。

少 schema validation,模型乱填参数。
少 policy validation,路径越界和危险命令混进来。
少 PermissionGate,高风险动作自动执行。
少 ToolResult normalize,模型只能猜失败原因。
少 trace,事故后没人知道发生了什么。
少 checkpoint,恢复时不知道副作用到哪一步。

试读小结

Tool Runtime 的目标不是让模型拥有更多按钮。

目标是让 Runtime 能稳定、安全、可追溯地使用这些按钮。

模型负责提出:

我想调用哪个工具,参数是什么。

Runtime 负责判断:

这个工具是否存在,参数是否合法,风险是否可接受,用户是否批准,怎样执行,失败如何反馈。

这是生产级 Agent 的分水岭。


推荐阅读

  • 一个 Agent Runtime 失败案例的完整 Trace
  • 生产级 Agent 上线前必须检查的 50 件事
  • Agent Runtime Engineering v0.1 发布

目录

  1. 试读章节:Tool Runtime 与权限审批
  2. 工具不是 Map<string, Function>
  3. ToolDefinition 至少要说清楚什么
  4. Schema 只说明长得对,不说明能执行
  5. Tool Registry 先生成计划
  6. PermissionGate 是 Runtime 的裁判
  7. 写文件为什么必须 preview
  8. Shell 工具要保守
  9. Workspace 边界是底线
  10. ToolResult 要同时服务模型和工程系统
  11. 权限拒绝也要写回模型
  12. 一条工具治理管线
  13. 试读小结
  14. 推荐阅读
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 后仿 SDF 反标 Warning 描述与解决方案
  • Docker 部署 MySQL 8.0 完整指南:从拉取镜像到配置远程访问
  • ChatGPT 与 DALL·E 制作日漫风格小故事全流程
  • Stable Diffusion WebUI 本地安装与配置教程
  • Python 核心语法详解:测试脚本开发基础
  • 在 Linux 桌面里跑 Windows 应用:Winboat 实战笔记
  • AI 编程工具深度对比:Trae、Cursor、Copilot 与 Windsurf
  • 论文阅读--Agent AI 探索多模态交互的前沿领域(一)
  • OpenCode 开源 AI 编程助手使用教程
  • Linux diff 与 patch 命令实战指南
  • 网络安全工程师职业定义、核心技能与认证体系详解
  • Python 为何如此流行?深度解析其核心优势与应用场景
  • 大疆无人机如何导出日志并解析
  • 前端 WebSocket 通信实战与最佳实践
  • OpenClaw 进阶教程:记忆系统、定时任务、多模型与子代理解析
  • Python 爬虫实战指南:从基础请求到分布式框架
  • Kubernetes Python 客户端实战教程
  • Java IO 核心:BufferedReader、BufferedWriter、PrintStream 与 PrintWriter 详解
  • AI 辅助编程工具:GitHub Copilot 安装与使用指南
  • 基于 Rokid AR 眼镜的聚会游戏助手开发实践

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online