Skip to content

CH 20 · defineTool: Fabrica una Herramienta para el Agent

Recuento de palabras~2,430 palabrasTiempo~20 minRequisitosCH 19 (Tres Formas de Plugin)NivelReproducible

Objetivo del capítulo

En CH 18 y 19, los plugins que escribimos solo hacían log — eso era solo para verificar "el plugin está cargado". Este capítulo escribe la cosa verdaderamente valiosa en los plugins: herramientas.

Las herramientas son las "manos" del Agent: el modelo dice algo, se llama al código que escribes, hace trabajo real, y envía el resultado de vuelta al modelo. En los capítulos anteriores has estado usando las herramientas integradas de dsh (leer archivos, ejecutar comandos, buscar); este capítulo fabricamos una nosotros mismos, dejamos que el modelo realmente se acerque y la llame.

Las herramientas son el alma de los plugins

Recuerda lo que usas cada día: el Agent de dsh puede leer archivos, escribir archivos, ejecutar comandos — esas son herramientas (capacidades registradas en ctx.tools). El modelo en sí solo puede "hablar"; las herramientas le permiten "actuar".

El esqueleto mínimo de un plugin de herramienta:

js
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx) {
  ctx.tools.register(defineTool({
    // Las cuatro partes de una herramienta, desglosadas una por una abajo
  }))
}

inject: ['tools'] declara "quiero usar el registro de herramientas", aprendido en CH 19; ctx.tools.register(...) monta una herramienta en el registro.

Las cuatro piezas de defineTool

defineTool toma un objeto que le dice a dsh "cómo se llama esta herramienta, cuándo debe usarse, qué parámetros necesita, cómo hace su trabajo". Una herramienta = un "JD de contratación para el Agent":

CampoSignificadoUna analogía
nameEl nombre de la herramienta, el modelo lo usa para llamarTítulo del puesto
descriptionDile al modelo "qué hace esta herramienta, cuándo debe usarse"Responsabilidades del puesto
parametersDeclara qué parámetros son obligatorios, cuáles son opcionalesMateriales a presentar
executeLa función que realmente hace el trabajoTrabajo tras la incorporación

Mira una herramienta mínima completa (igual que el tutorial oficial, ligeramente traducida):

js
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet by name',
    parameters: {
      name: { type: 'string', required: true, description: 'Name of the person to greet' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      return `Hello, ${args.name}!`
    },
  }))
}

Cuatro puntos clave:

  • parameters se escribe en JSON Schema: type: 'string' declara el tipo del parámetro, required: true declara que es obligatorio. El framework valida automáticamente los parámetros que pasa el modelo; los no conformes dan error — no necesitas hacer type-check manualmente en execute.
  • execute(args) es la función que realmente hace el trabajo: args ya ha sido validado, solo úsalo con confianza. Devuelve un "valor canónico" (una cadena aquí).
  • output.schema declara la forma del valor de retorno, output.render convierte el valor de retorno en contenido que el modelo puede ver (un bloque de texto aquí). El valor de retorno primero existe en forma canónica, la capa de renderizado se encarga de "traducirlo" al modelo.
  • description es extremadamente importante: el modelo lo usa para juzgar "¿debo usar esta herramienta ahora mismo?". Escríbelo claro, escríbelo específico, y el modelo sabrá cuándo llamarla.

Práctica: escribe una herramienta greet, haz que el modelo realmente la llame

En un workspace donde quieras poner plugins, crea un directorio:

powershell
New-Item -ItemType Directory -Path "tool-demo\src" -Force

Paso 1: instala dependencias

defineTool viene de @deepseek-ai/dsh-tools, instálalo en el directorio del plugin primero:

powershell
cd "E:\software-workspace\DeepSeek harness demo\tool-demo"   # sustituye por tu directorio
npm init -y
npm install @deepseek-ai/dsh-tools

Recuerda añadir una línea "type": "module" en package.json (CH 19 lo mencionó, sin ella habrá un montón de avisos).

Paso 2: escribe la herramienta

Crea tool-demo\src\greet.js, con la misma herramienta greet de arriba. Añadí una línea de log en execute para confirmar fácilmente en la terminal que fue realmente llamada:

js
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet by name',
    parameters: {
      name: { type: 'string', required: true, description: 'Name of the person to greet' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      console.log('[greet] called with', args.name)
      return `Hello, ${args.name}!`
    },
  }))
}

Paso 3: declara y verifica

Crea tool-demo\cordis.yml (sustituye la ruta por la tuya, recuerda %20 para los espacios):

yaml
- insert:
    - id: greet
      name: 'file:///E:/tu-workspace/tool-demo/src/greet.js'

Usa headless para ejecutar una vez, deja que el modelo realmente la llame:

powershell
cd tu-directorio-de-workspace
dsh --profile headless --patch "./tool-demo/cordis.yml" "You must call the greet tool, say hi to Ada, then tell me verbatim what the tool returned"

En la salida de la terminal verás:

text
[greet] called with Ada

Esta es la evidencia de que execute fue realmente llamado por el modelo — tu código fue realmente ejecutado por el modelo acercándose. Y la respuesta del modelo contendrá el Hello, Ada! devuelto por la herramienta.

El [greet] called with Ada amarillo en la terminal es el log de execute siendo realmente llamado por el modelo; el Hello, Ada! de abajo es el resultado que la herramienta devuelve al modelo.

Deja que dsh lo haga: un prompt lo resuelve

El flujo de escritura de herramientas es exactamente el mismo que escribir un plugin, dsh puede hacerlo por sí mismo, y conoce los campos de defineTool y cómo debe escribirse el schema mejor que tú.

Envía este prompt directamente en el cuadro de entrada de la Web UI:

text
In my current workspace, help me write a tool plugin: use defineTool to define the simplest tool (with one required parameter, returning some text in execute). First read the dsh official docs to understand defineTool's fields and parameter validation rules, implement per the official spec, then run a headless to have the model actually call it, and finally tell me the result and where the files are.

Irá a consultar los docs por sí mismo, instalará dependencias, escribirá la herramienta, verificará que el modelo realmente la llamó. Tú solo verificas.

Este es el resultado de ejecutar yo realmente este prompt: leyó los docs por sí mismo, construyó las tres piezas del plugin (package.json declarando bundle, defineTool entry index.js, un insert de una línea cordis.patch.yml), e incluso descubrió que las rutas de Windows con espacios romperían el parseo del comando de instalación, y movió proactivamente el plugin a una ruta sin espacios antes de instalar — cayó en el error, y lo sorteó por sí mismo.

Tras la ejecución, también organizó los errores en una lista: requisitos de la forma de export del plugin, inject debe declararse explícitamente, los paquetes del workspace necesitan artefactos de build para ejecutarse, error de espacios en la ruta.

Errores comunes

ProblemaQué está pasandoCómo manejarlo
Reporta Cannot find package '@deepseek-ai/dsh-tools'El directorio del plugin no instaló dependenciasnpm install @deepseek-ai/dsh-tools
El modelo nunca llama a tu herramientadescription no está claro, el modelo no sabe cuándo usarlaHaz la description específica: "Use when user requests X"
Parámetros no pasados correctamenteEl schema y el entendimiento del modelo no coincidenEscribe una description clara para cada parámetro en parameters
La herramienta reportó un error de parámetroEl modelo pasó parámetros ilegalesMarca los obligatorios con required: true, escribe el tipo correctamente
El modelo la llamó pero el resultado es incorrectoLa lógica en execute está malAñade console.log en execute para depurar, comprueba los logs

Lo que aprendiste en este capítulo

Apruebas si puedes completar los puntos de abajo:

  • [ ] Enuncias las cuatro piezas de defineTool: name / description / parameters / execute
  • [ ] Sabes que parameters es JSON Schema, el framework valida automáticamente los parámetros
  • [ ] Escribes un plugin de herramienta y lo registras en ctx.tools
  • [ ] Usas headless para verificar que el modelo realmente llamó a tu herramienta
  • [ ] Sabes que description decide cuándo el modelo usa tu herramienta

Open Source · MIT · Community Driven