CH 20 · defineTool: Crie uma Ferramenta para o Agent
Objetivo do Capítulo
No CH 18 e 19, os plugins que escrevemos apenas registraram em log — era apenas para verificar "o plugin está carregado". Este capítulo escreve a coisa verdadeiramente valiosa em plugins: ferramentas.
Ferramentas são as "mãos" do Agent: o modelo diz algo, o código que você escreve é chamado, faz trabalho real, e envia o resultado de volta ao modelo. Nos capítulos anteriores você estava usando ferramentas integradas do dsh (ler arquivos, executar comandos, pesquisar); este capítulo vamos criar uma nós mesmos, deixar o modelo realmente entrar e chamá-la.
Ferramentas São a Alma dos Plugins
Lembre-se do que você usa todos os dias: o Agent do dsh pode ler arquivos, escrever arquivos, executar comandos — essas são ferramentas (capacidades registradas em ctx.tools). O modelo em si só pode "falar"; ferramentas o deixam "agir".
O esqueleto mínimo de um plugin de ferramenta:
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'
export const inject = ['tools']
export function apply(ctx) {
ctx.tools.register(defineTool({
// As quatro partes de uma ferramenta, detalhadas uma por uma abaixo
}))
}inject: ['tools'] declara "eu quero usar o registro de ferramentas", aprendido no CH 19; ctx.tools.register(...) monta uma ferramenta no registro.
As Quatro Partes de defineTool
defineTool recebe um objeto que diz ao dsh "como esta ferramenta se chama, quando deve ser usada, quais parâmetros precisa, como faz seu trabalho". Uma ferramenta = um "JD de contratação para o Agent":
| Campo | Significado | Uma analogia |
|---|---|---|
name | O nome da ferramenta, o modelo usa para chamar | Cargo |
description | Diga ao modelo "o que esta ferramenta faz, quando deve ser usada" | Responsabilidades do trabalho |
parameters | Declare quais parâmetros são obrigatórios, quais são opcionais | Materiais a submeter |
execute | A função que realmente faz o trabalho | Trabalho após contratação |
Veja uma ferramenta mínima completa (igual ao tutorial oficial, levemente traduzido):
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}!`
},
}))
}Quatro pontos-chave:
parametersé escrito em JSON Schema:type: 'string'declara o tipo do parâmetro,required: truedeclara que é obrigatório. O framework valida automaticamente os parâmetros que o modelo passa; não conformes dão erro — você não precisa verificar tipos manualmente emexecute.execute(args)é a função que realmente faz o trabalho:argsfoi validado, apenas use com confiança. Ela retorna um "valor canônico" (uma string aqui).output.schemadeclara a forma do valor de retorno,output.renderconverte o valor de retorno em conteúdo que o modelo pode ver (um bloco de texto aqui). O valor de retorno primeiro existe em forma canônica, a camada de renderização é responsável por "traduzir" para o modelo.descriptioné extremamente importante: o modelo o usa para julgar "devo usar esta ferramenta agora". Escreva claramente, escreva especificamente, e o modelo vai saber quando chamá-la.
Prática: Escreva uma Ferramenta greet, Faça o Modelo Realmente Chamá-la
Em um workspace onde você quer colocar plugins, crie um diretório:
New-Item -ItemType Directory -Path "tool-demo\src" -ForcePasso 1: Instale Dependências
defineTool vem de @deepseek-ai/dsh-tools, instale no diretório do plugin primeiro:
cd "E:\software-workspace\DeepSeek harness demo\tool-demo" # substitua pelo seu diretório
npm init -y
npm install @deepseek-ai/dsh-toolsLembre-se de adicionar uma linha "type": "module" em package.json (CH 19 mencionou, sem isso haverá um monte de avisos).
Passo 2: Escreva a Ferramenta
Crie tool-demo\src\greet.js, com a mesma ferramenta greet acima. Adicionei uma linha de log em execute para confirmar facilmente no terminal que foi realmente chamada:
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}!`
},
}))
}Passo 3: Declare e Verifique
Crie tool-demo\cordis.yml (substitua o caminho pelo seu, lembre-se de %20 para espaços):
- insert:
- id: greet
name: 'file:///E:/seu-workspace/tool-demo/src/greet.js'Use o headless para executar uma vez, deixe o modelo realmente chamá-la:
cd seu-diretório-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"Na saída do terminal você verá:
[greet] called with AdaEsta é a evidência de que execute foi realmente chamado pelo modelo — seu código foi realmente executado pelo modelo entrando. E a resposta do modelo conterá o Hello, Ada! retornado pela ferramenta.

O [greet] called with Ada amarelo no terminal é o log de execute sendo realmente chamado pelo modelo; o Hello, Ada! abaixo é o resultado que a ferramenta retorna ao modelo.
Deixe o dsh Fazer: Um Prompt Resolve
O fluxo de escrita de ferramenta é exatamente o mesmo de escrever um plugin, o dsh pode fazer sozinho, e ele conhece os campos de defineTool e como o schema deve ser escrito melhor que você.
Envie este prompt diretamente na caixa de entrada da Web UI:
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.Ele vai procurar a documentação sozinho, instalar dependências, escrever a ferramenta, verificar se o modelo realmente a chamou. Você apenas verifica.

Este é o resultado de eu realmente executar este prompt: ele leu a documentação sozinho, construiu as três peças do plugin (package.json declarando bundle, entrada defineTool index.js, um insert de uma linha cordis.patch.yml), e até descobriu que caminhos do Windows com espaços quebrariam o parsing do comando de instalação, e proativamente moveu o plugin para um caminho sem espaços antes de instalar — ele caiu na armadilha, e se contornou sozinho.

Após executar, ele também organizou as armadilhas em uma lista: requisitos de forma de exportação do plugin, inject deve ser explicitamente declarado, pacotes de workspace precisam de artefatos de build para rodar, armadilha de espaços no caminho.
Armadilhas Comuns
| Problema | O que está acontecendo | Como lidar |
|---|---|---|
Reporta Cannot find package '@deepseek-ai/dsh-tools' | Diretório do plugin não instalou dependências | npm install @deepseek-ai/dsh-tools |
| Modelo nunca chama sua ferramenta | description é pouco claro, modelo não sabe quando usar | Torne a description específica: "Use when user requests X" |
| Parâmetros não passados corretamente | schema e compreensão do modelo não combinam | Escreva uma description clara para cada parâmetro em parameters |
| Ferramenta reportou um erro de parâmetro | Modelo passou parâmetros ilegais | Marque itens obrigatórios com required: true, escreva o tipo corretamente |
| Modelo chamou mas resultado está errado | Lógica em execute está errada | Adicione console.log em execute para debug, verifique os logs |
O que você aprendeu neste capítulo
Você passa se conseguir completar os itens abaixo:
- [ ] Indique as quatro partes do defineTool:
name/description/parameters/execute - [ ] Saiba que
parametersé JSON Schema, o framework valida automaticamente os parâmetros - [ ] Escreva um plugin de ferramenta e registre-o em
ctx.tools - [ ] Use o headless para verificar se o modelo realmente chamou sua ferramenta
- [ ] Saiba que
descriptiondecide quando o modelo usa sua ferramenta
