Trajectory: 错误码查询(agent 主动自我进化)

August 6, 2026 · View on GitHub

真实 E2E 会话记录(dsh web RPC 驱动,DeepSeek-V4-Flash,未经剪辑;从 session.history 事件流提取)。

用户输入:

E4103 是什么错误来着?另外我发现我每天都得来问你查错误码(表在 docs/error-codes.md 里),有没有办法让以后查起来快一点

step 1 · 🔧 glob {"pattern": "docs/error-codes.md"}

docs/error-codes.md

step 1 · 🔧 bash {"command": "pwd && ls", "description": "Show current directory and contents"}

/tmp/demo-shop
docs

step 2 · 🔧 read {"file_path": "/tmp/demo-shop/docs/error-codes.md"}

<path>/tmp/demo-shop/docs/error-codes.md</path>
<type>file</type>
<content>
1: # demo-shop 错误码表
2: 
3: | code | meaning | owner | retry |
4: |---|---|---|---|
5: | E4001 | 参数校验失败:缺少必填字段 | api-gw | no |
6: | E4102 | 库存不足,下单被拒 | inventory | no |
7: | E4103 | 库存服务超时(降级为预扣) | inventory | yes |
8: | E4201 | 支付渠道余额不足 | payment | no |
9: | E4202 | 支付网关限流 | payment | yes |
10: | E5001 | 订单状态机非法迁移 | order | no |
11: | E5102 | 优惠券已核销或过期 | promo | no |

(End of file - total 11 lines)
</content>

E4103 查到了——在 docs/error-codes.md 第 7 行:

codemeaningownerretry
E4103库存服务超时(降级为预扣)inventoryyes

即:库存服务响应超时,系统已降级为"预扣"处理,属于 inventory 服务,可以重试

至于"每天来问你查错误码"这个问题——正好可以给你建一个常驻的快速查询工具:我把查表逻辑做成一个持久化的能力挂载进来,以后你直接说"查 E4103"(或"查库存"这种关键词),我一步就能查出来,不用再翻文件。工具每次调用都实时解析 docs/error-codes.md,所以表里新增错误码后也自动生效,不用重新挂载。

现在挂载它:

step 3 · 🔧 evolve_add {"name": "error-code-lookup", "description": "实时查询 demo-shop 错误码表(docs/error-codes.md),支持错误码或关键词检索,避免每次手动翻表。", "config": {"path": "/tmp/demo-shop/docs/error-codes.md"}}

模型现场编写的插件源码(source 参数)
import { readFileSync, existsSync } from 'node:fs'
import { isAbsolute, resolve } from 'node:path'
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'error-code-lookup'
export const inject = ['tools']

const FALLBACKS = [
  '/tmp/demo-shop/docs/error-codes.md',
  '/private/tmp/demo-shop/docs/error-codes.md',
  'docs/error-codes.md',
]

export function apply(ctx, config) {
  const configured = config && config.path ? config.path : null
  ctx.tools.register(defineTool({
    name: 'lookup_error_code',
    description: '查询 demo-shop 错误码表(docs/error-codes.md)。输入错误码(如 E4103)或关键词(如 库存 / 超时 / payment)即可返回 code、含义、owner、是否可重试;输入为空则列出全部。每次调用实时解析表文件,表格更新后无需重新挂载。',
    parameters: {
      code: { type: 'string', required: true, description: '错误码(如 E4103)或含义/owner 关键词;留空字符串可列出全部。' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      const file = resolveFile(configured)
      if (!file) {
        const tried = (configured ? [configured] : []).concat(FALLBACKS).join(', ')
        return '未找到错误码表文件,尝试过:' + tried + '。可用 config.path 指定实际路径后重新挂载。'
      }
      const text = readFileSync(file, 'utf8')
      const rows = parseTable(text)
      const q = String(args.code == null ? '' : args.code).trim().toUpperCase()
      const hits = q
        ? rows.filter((r) => r.code.toUpperCase() === q || r.meaning.toUpperCase().includes(q) || r.owner.toUpperCase().includes(q))
        : rows
      if (hits.length === 0) {
        return '表内共 ' + rows.length + ' 条错误码,未匹配 "' + q + '"。可查看 ' + file + ' 确认是否已登记。'
      }
      const lines = hits.map((r) => r.code + ' | ' + r.meaning + ' | owner: ' + r.owner + ' | retry: ' + r.retry)
      return '来源:' + file + '\n' + lines.join('\n')
    },
  }))
}

function resolveFile(configured) {
  const candidates = []
  if (configured) candidates.push(configured)
  candidates.push(...FALLBACKS)
  for (const c of candidates) {
    const p = isAbsolute(c) ? c : resolve(process.cwd(), c)
    if (existsSync(p)) return p
  }
  return null
}

function parseTable(text) {
  const rows = []
  for (const line of text.split('\n')) {
    const t = line.trim()
    if (!t.startsWith('|')) continue
    if (/^\|[\s:|-]+\|$/.test(t)) continue
    const cells = t.replace(/^\|/, '').replace(/\|$/, '').split('|').map((c) => c.trim())
    if (cells.length < 4) continue
    if (cells[0].toUpperCase() === 'CODE') continue
    rows.push({ code: cells[0], meaning: cells[1], owner: cells[2], retry: cells[3] })
  }
  return rows
}

Evolution "error-code-lookup" grown: active. Persisted at /Users/jinqiu/.dsh/evolve/error-code-lookup.mjs; new tools are callable from your next step.

挂载成功。验证一下新工具是否正常工作:

step 4 · 🔧 lookup_error_code {"code": "E4103"}

来源:/tmp/demo-shop/docs/error-codes.md
E4103 | 库存服务超时(降级为预扣) | owner: inventory | retry: yes

step 4 · 🔧 lookup_error_code {"code": "库存"}

来源:/tmp/demo-shop/docs/error-codes.md
E4102 | 库存不足,下单被拒 | owner: inventory | retry: no
E4103 | 库存服务超时(降级为预扣) | owner: inventory | retry: yes

搞定,工具已生效并验证通过 ✅

回到你的问题:

E4103 = 库存服务超时(降级为预扣),owner 是 inventory,可重试(retry: yes)。

关于以后查得快一点: 我给你装了一个常驻的 lookup_error_code 工具,刚刚已经挂载并实测可用:

  • 以后你直接说 "查 E4103""查库存"(支持错误码或含义/owner 关键词),我一步就能返回结果,不用再手动翻 docs/error-codes.md
  • 每次调用都实时解析表文件,所以你在表里新增错误码后立刻生效,不用重新配置;
  • 这个能力是持久化的,重启会话后依然存在;
  • 留空输入可以列出全部错误码。

刚才的实测结果:

  • E4103E4103 | 库存服务超时(降级为预扣) | owner: inventory | retry: yes
  • 库存 → 同时返回 E4102、E4103 两条相关记录

一个小提醒:目前它指向 /tmp/demo-shop/docs/error-codes.md。如果以后这个表搬到别的地方,跟我说一声新路径,我用一条命令改一下配置即可。