构建 SQLite/SQL 查询检索工具,并在 Harness Trajectory 视图中分析多轮调用轨迹。
在上一节中,你已经掌握了通过 defineTool 与 ctx.tools.register 向 DeepSeek Harness 注册外部 API 聚合工具的方法,并借助 parameters 参数规范、output 呈现管道与 execute 异步逻辑,让智能体准确解析用户自然语言意图、完成外部数据获取。
顺着这条工具注册链路,当所需数据并不在外部 API 中、而是沉淀在本地数据库里时,智能体同样需要一类注册工具来触达它。本节我们将构建一个本地 SQLite 只读检索插件 sqlite-query-tool:智能体能够自主编写 SQL 查询本地数据库、获取结构化结果并综合回答用户问题。同时,你将学会如何借助 Harness 内置的 Trajectory 视图,逐帧复盘智能体的多轮工具调用轨迹。
核心概念
Trajectory 执行轨迹追踪与 Session 日志流
把智能体的推理执行过程想象成飞机上的“黑匣子飞行记录仪”。黑匣子不会只记录飞机最终降落的地点,而是以不可篡改的流水账(Append-only)形式忠实记录每一秒的高度、航向与操作指令。如果在飞行途中发生颠簸或故障,工程师可以通过黑匣子完整重放飞行轨迹。
在技术定义上,Trajectory 执行轨迹追踪是 DeepSeek Harness 提供的核心可观测性机制。Harness 内部维护着一条仅追加(append-only)的 Session 日志流,记录了包括 turn/*、step/*、tool/call 和 tool/result 在内的全部持久化会话事件。Trajectory 视图将该事件流直观呈现为时间线,使开发者能够精确审查每一次工具调用的入参、执行耗时、返回内容以及 Token 消耗分布,实现多轮交互与状态回放的透明化调试。
向大模型暴露数据库查询工具时,必须强制限制权限。切勿允许大模型执行非授权的修改或破坏性操作(如 DROP、DELETE、UPDATE)。在插件层务必开启底层连接的只读模式(readonly: true),并在执行前校验 SQL 关键字,防止提示词注入带来的破坏风险。
编写 SQLite 只读检索插件并观察 Trajectory
- 1
在本地初始化 SQLite 测试数据库,创建包含示例数据的
analytics.db文件。bashnode -e "const Database = require('better-sqlite3'); const db = new Database('analytics.db'); db.exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, role TEXT, active INTEGER); INSERT INTO users VALUES (1, \'Alice\', \'admin\', 1), (2, \'Bob\', \'developer\', 1), (3, \'Charlie\', \'tester\', 0);'); db.close();" - 2
编写 SQLite 数据库检索插件
src/sqlite-plugin.ts,声明服务依赖并在apply中注册只读 SQL 查询工具。typescriptimport type { Context } from '@deepseek-ai/cordis' import { defineTool } from '@deepseek-ai/dsh-tools' import Database from 'better-sqlite3' export const name = 'sqlite-query-tool' export const inject = ['tools'] export function apply(ctx: Context) { ctx.tools.register(defineTool({ name: 'query_sqlite', description: '在本地 SQLite 数据库中执行只读 SQL 查询并返回 JSON 格式结果。', parameters: { query: { type: 'string', required: true, description: '需要执行的 SQL SELECT 语句' } }, output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }] }, async execute(args) { const trimmed = args.query.trim() if (!/^select\b/i.test(trimmed)) { throw new Error('只允许执行 SELECT 只读查询语句。') } const db = new Database('analytics.db', { readonly: true, fileMustExist: true }) try { const rows = db.prepare(trimmed).all() return JSON.stringify(rows) } finally { db.close() } } })) } - 3
使用 dsh web 启动开发服务器并挂载该插件。
bashpnpm dsh web --patch ./cordis.yml - 4
在浏览器打开 Web 界面(默认 http://127.0.0.1:3080),向智能体发送任务指令:“请查询数据库中所有处于 active 状态的管理员用户名”。
- 5
在 Web 界面右侧或调试面板中切换到 Trajectory 视图,检查 Session 事件流中记录的
tool/call参数(SELECT name FROM users WHERE active = 1 AND role = 'admin')与tool/result响应数据。
你应该看到
智能体成功生成正确的 SQL 语句调用 query_sqlite 工具,获取到用户 Alice 的记录并生成解答。在 Trajectory 视图中能够清晰看到橙色高亮的工具调用记录、返回值及耗时明细。
遇到问题:智能体调用 query_sqlite 时直接抛出错误:“只允许执行 SELECT 只读查询语句”或数据库文件无法打开。
可能原因
- 智能体尝试生成包含
PRAGMA、SHOW或包含写操作的非SELECT语句,触发了前端校验拦截。 analytics.db文件路径不正确或进程没有该文件的读取权限。
排查步骤
- 在
parameters.query.description中明确提示模型:“必须是标准 SELECT 查询语句,不支持其他指令”。 - 确保数据库文件位于 Harness 运行根目录下,或在插件配置中传入可配置的绝对路径。
自检:在 DeepSeek Harness 中,为什么 Trajectory 调试不仅依赖聊天消息本身,而是基于底层仅追加(append-only)的 Session 日志流?
聊天窗口通常会折叠或省略中间环节的原始请求与完整工具 Payload;而基于 append-only 的 Session 日志流记录了包括 turn/*、step/*、tool/call 和 tool/result 在内的全部不可篡改的原子事件,为断点恢复、分叉重放和精准排查提供了完整的数据轨迹支撑。