DeepSeek harness工具系统什么设计的?

工具系统------Agent的手脚

本周目标:

  • 工具是怎么定义的
  • 工具调用是怎么执行的
  • 怎么保证工具调用安全

怎么定义一个工具

java 复制代码
// 一个工具需要告诉系统四件事:
// 1. 我叫什么名字?
// 2. 我能干什么?
// 3. 我需要什么参数?
// 4. 我怎么执行?

ctx.tools.register({
  // 1. 名字
  name: 'search',
  
  // 2. 描述(LLM 看到这个来判断什么时候用它)
  description: '搜索网页,返回相关结果',
  
  // 3. 参数(LLM 需要提供什么)
  parameters: {
    query: { 
      type: 'string', 
      required: true, 
      description: '搜索关键词' 
    },
    limit: { 
      type: 'number', 
      description: '返回结果数量' 
    }
  },
  
  // 4. 执行逻辑
  async execute(args, exec) {
    const results = await fetch(`https://search.example.com?q=${args.query}`)
    return results.slice(0, args.limit ?? 10)
  }
})

LLM 看到的工具定义:

java 复制代码
{
  "name": "search",
  "description": "搜索网页,返回相关结果",
  "parameters": {
    "query": { "type": "string", "description": "搜索关键词" },
    "limit": { "type": "number", "description": "返回结果数量" }
  }
}

工具执行管道

dsh最复杂最核心的设计。用公司审批流程类比:

场景:员工(Agent)要调用一个工具(比如删除文件)

不能让员工直接删!需要经过层层检查:

员工发起请求

┌─────────────────────────────────────────────────────────────┐

│ 第1层:tools/pre-execute(审批大门) │

│ │

│ "这个调用允许吗?" │

│ → allow(允许)→ 继续 │

│ → deny(拒绝) → 停止,返回错误 │

│ → ask(询问) → 弹出确认框,等用户回答 │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第2层:ToolGuard(安全策略) │

│ │

│ "有没有硬性规则禁止这个调用?" │

│ → 返回 undefined(没意见)→ 继续 │

│ → 返回 "原因"(拒绝)→ 停止 │

│ │

│ 比如:"禁止删除系统文件" │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第3层:tools/execute(执行包装) │

│ │

│ 在执行外层加上: │

│ - 超时控制(超过5分钟自动停止) │

│ - 重试逻辑(失败后自动重试) │

│ - 指标收集(记录执行时间) │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第4层:Tool Body(真正执行) │

│ │

│ 实际运行工具的代码: │

│ const result = await search(args.query) │

│ return result │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第5层:tools/post-execute(结果处理) │

│ │

│ 执行完了,可以: │

│ - 接受结果(accept) │

│ - 替换结果(replace) │

│ - 阻止结果(block) │

│ - 附加上下文(add context) │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第6层:finalizeContent(最终处理) │

│ │

│ 工具定义自己的"最后一步": │

│ - 格式化输出 │

│ - 过滤敏感信息 │

│ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 第7层:tool/result(持久化到日志) │

│ │

│ 结果写入 Session Event Log │

│ → LLM 看到这个结果 │

│ │

└─────────────────────────────────────────────────────────────┘

上述流程有个大概印象就好,最主要理解的是下面三种拦截方式。

三种拦截策略

java 复制代码
// 方式1:pre-execute 审批
ctx.on('tools/pre-execute', (execution, next) => {
  if (execution.name === 'delete_file') {
    // 弹出确认框
    const allowed = await askUser('确定要删除吗?')
    if (!allowed) return { kind: 'deny', reason: '用户取消' }
  }
  return next()
})

// 方式2:Guard 硬性策略
ctx.tools.guard((execution) => {
  if (execution.name === 'delete_file') {
    const path = execution.arguments.path
    if (path.startsWith('/system/')) {
      return '禁止删除系统文件'  // 直接拒绝
    }
  }
  return undefined  // 不干涉
})

// 方式3:post-execute 结果处理
ctx.on('tools/post-execute', (execution, result, next) => {
  if (execution.name === 'read_file') {
    // 过滤敏感信息
    return { ...result, value: filterSecret(result.value) }
  }
  return next()
})

取消机制(协作式)

java 复制代码
场景:Agent 发起了一个耗时操作,用户想取消

传统做法(强制杀死):
  直接 kill 进程 → 可能导致数据损坏

dsh 的做法(协作式取消):
  发一个"请停止"信号 → 工具体自己决定怎么优雅停止
ctx.tools.register({
  name: 'long_task',
  async execute(args, exec) {
    // exec.signal 是取消信号
    for (let i = 0; i < 100; i++) {
      // 每次循环检查是否被取消
      if (exec.signal.aborted) {
        console.log('收到取消信号,优雅退出')
        break
      }
      await doSomething()
    }
  }
})

总结

一句话概括

工具是 Agent 的"手脚",dsh 通过多层执行管道实现工具的安全调用和灵活扩展。

核心知识点

  1. 工具定义

一个工具需要四要素:

  • name:叫什么
  • description:干什么(LLM 看这个决定什么时候用)
  • parameters:需要什么参数
  • execute:怎么执行
  1. 执行管道(7层)

pre-execute(审批)

→ guard(安全策略)

→ execute(超时/重试包装)

→ body(真正执行)

→ post-execute(结果处理)

→ finalizeContent(最终格式化)

→ result(持久化到日志)

  1. 三种拦截方式

方式 作用 特点

pre-execute 审批门 可 allow/deny/ask

ToolGuard 硬性策略 一旦拒绝不能翻案

post-execute 结果处理 可替换/阻止结果

  1. 关键设计

注册即效果 → 插件卸载时工具自动移除

协作式取消 → 发信号让工具自己优雅停止

Model-visible means logged → 工具调用和结果都写入 Session Log

面试怎么答

"dsh 的工具系统不是简单的直接调用,而是一个多层管道。每次工具调用要经过审批门、安全策略、超时包装、真正执行、结果处理等七个环节。任何环节都可以拦截或修改,这让安全策略和工具实现完全解耦。取消机制是协作式的------发信号让工具自己优雅停止,而不是强制杀死。"

一页速记

工具注册:ctx.tools.register(definition)

执行管道:pre-execute → guard → execute → body → post → finalize → result

拦截方式:pre-execute(审批) / Guard(硬性) / post-execute(结果)

取消机制:AbortSignal 协作式取消

持久化:tool/call + tool/result 写入 Session Log

相关推荐
luj_176820 分钟前
尾椎藏今生记忆?骨盆对应不确定性
开发语言·网络·c++·经验分享·算法
ttwuai25 分钟前
Go 后台接入 CAS 单点登录后,原来的权限怎么继续生效?
开发语言·后端·golang
烂蜻蜓31 分钟前
Flask入门教程(十五):错误处理与日志——打造健壮的Web应用
前端·python·flask
断点之下31 分钟前
C++类和对象:六个默认成员函数详解
开发语言·c++
吴声子夜歌37 分钟前
Java——类、对象及方法(二)
java·开发语言
2401_8906034040 分钟前
Python入门语法(一)
java·开发语言·python
烂蜻蜓1 小时前
Flask入门教程(十六):中间件与扩展——增强应用功能的两种机制
python·中间件·flask