Agent 工作流
通过 CLI,agent 已经可以查询文件、搭建仪表盘、读取你的评论。这些新增功能管的是这些工作的前后:限制不是它自己写的 SQL,确认窗口把请求处理成了什么样,由你批准修改,以及记录答案是怎么得出的。
限制不是你写的 SQL
--restricted 用于从数据里抄来的 SQL,以及别人写的仪表盘。只读模式管不了这些:它只保护数据库文件,COPY 仍然能写到你有权限的任何地方,FROM 'https://...' 仍然能发出请求。
ducklocal query --restricted --allow-read ./data --sql "SELECT * FROM 'data/sales.csv'"
ducklocal check report.dash --restricted --allow-read ./data| SQL 想要 | 结果 |
|---|---|
读取 --allow-read 下的文件 | 允许 |
读取其他文件,无论用路径、glob 还是 .. | 拒绝 |
写文件,即使在 --allow-read 下 | 拒绝 |
ATTACH 或新建数据库 | 拒绝 |
访问 http、https、s3 或其他 URL | 拒绝 |
INSTALL 或 LOAD 扩展 | 拒绝 |
| 修改设置,包括这些限制本身 | 拒绝 |
运行超过 --timeout(默认 60 秒) | 被中断,kind 为 timeout |
使用超过 --memory-limit(默认 2GB) | 失败,kind 为 resource_limit |
不给 --allow-read 时,任何文件都读不了,仪表盘自己所在的文件夹也一样。被拒绝的语句退出码为 1,kind 为 policy_denied,绝不会退回到不受限的方式运行。EXPLAIN、PRAGMA 和顶层 PIVOT 同样会被拒绝,因为语句必须是单条 SELECT。
这不是沙箱。 这些限制来自 DuckDB 本身,DuckLocal 在任何平台上都没有施加操作系统级隔离。限制约束的是 SQL,而不是选择参数的人:能用 shell 的 agent 可以直接去掉 --restricted。要约束你不信任的 agent,请把 agent 本身放进容器或虚拟机。schema、profile、project check 和 open --run 不受限,窗口打开仪表盘时也不受限。
完整的威胁模型和各平台的测试情况,见 What limits agent-run SQL(英文)。
与窗口保持同步
ducklocal open 以前只报告“已送达”。现在有两个参数:一个报告请求最后怎么样了,一个防止在窗口已经变化时继续操作。
ducklocal open --state --active # 记下 revision
ducklocal open --if-revision REV --run --wait \
--title "各渠道收入" --sql "SELECT ..."--wait最多等 5 分钟,并在输出里加上status、tab_id、result_status、error和revision。--if-revision REV:如果窗口显示的已不是这个 revision,就什么都不打开,退出码为 1,kind 为stale。重试前先重新读取状态。有人在别的标签页打字也会让它过期,这是有意设计的。
--state 现在还会报告:
| 字段 | 含义 |
|---|---|
schema_version、revision | 契约版本,以及代表窗口当前内容的令牌 |
actions | 最近请求的结果:stale、queued、running、opened、succeeded 或 failed |
limits | 预览的上限。读取状态不会返回完整结果 |
connections | S3 的 endpoint 和 region,以及每个已挂载数据库的名称、类型、位置和地址。绝不包含密钥 |
result.reach | local、remote 或 unknown,只根据 SQL 判断;还会说明是否用了你的 S3 密钥 |
sql_withheld | 标签页的 SQL 可能含有凭据时为 true,文本会被替换 |
每个 plot 上的 scope | 这张图画了查询结果的多少 |
reach 只看得到 SQL 里写明的内容,所以建在远程数据上的本地视图会显示为 local。读取这些信息不会发出网络请求,因此 location: "remote" 只说明数据库在哪里,不说明它还能连上。
agent 能看到 S3 已配置,但看不到密钥;不过它用 open --run 运行的 SQL 仍然可以使用这个密钥。
所有字段和错误 kind 见交接契约(英文),状态结构见 JSON schema。
提议修改仪表盘
如果你希望修改要经过你批准,agent 可以提出提议,而不是直接改文件:
ducklocal propose sales.dash --status # 记下 current_hash
ducklocal propose sales.dash --from new.dash --note "按地区拆分收入" --based-on HASH
ducklocal propose sales.dash --status # pending、applied 或 rejected规格文件保持不变,仪表盘标签页会提示有一项修改在等待。点 审阅 会运行提议里的 SQL,并显示差异和检查结果,然后点 应用 或 拒绝。
- 只有你能在窗口里应用提议,没有对应的命令。
- 应用时会把旧版本保存为
sales.dash.bak;如果提议之后规格文件变过,应用会被拒绝。 - 拒绝不会改动规格文件。
- 点 审阅 会运行提议里的 SQL,所以你不信任的提议能访问仪表盘 SQL 能访问的一切。请先对它运行
check --restricted。
记录分析过程
设置 DUCKLOCAL_SESSION 后,query、check、propose 和 open 都会记录自己做了什么:
export DUCKLOCAL_SESSION=analysis.session.jsonl
ducklocal session note --text "EU 收入下降 12%" --refs 3,4
ducklocal session show --last 20不设置这个变量就什么都不记录。文件里有 SQL 和规格文本、每个数据源的大小和修改时间、每个结果的形状,但绝不包含数据行。错误信息最多保留 500 个字符,可能引用数据值,所以除非你有意分享,否则不要把文件放进共享文件夹。
每个步骤和结论都有 doubts,在读取时计算:哪些失败了、被截断了,或者之后发生了变化。列表为空表示目前没发现问题,不代表结论一定正确。
可能含有凭据的 SQL 不会被记录。这项检查按 secret、token、access_key 这类词判断,所以列名里有这些词时,查询文本也会被隐去。
让分析可以搬走
ducklocal project init # 写入 ducklocal-project.json
ducklocal project check # 搬走后什么会失效
ducklocal project relink --source orders --to data/2026/orders.csvducklocal-project.json 是可选的。它列出文件夹里的仪表盘和它们的依赖;数据只引用,绝不复制。在窗口里打开它,就会打开这些仪表盘。
project check 报告 ok、portable、problems(每项带 hint)和 limitations。无论结果如何退出码都是 0,所以要看输出。它不会访问网络,也不会安装任何东西。通过检查不能证明数据没变。project relink 会修改你的仪表盘,并把每个旧版本保存为 NAME.dash.bak。
完整示例
A leaked key, investigated by an agent and a person(英文)用一周虚构的 CloudTrail 日志,从第一条查询一直走到审阅完的仪表盘。agent 这一半的步骤,每次改动都有测试运行。窗口这一半还没有人实际点过一遍,它的 README 写明了是哪些步骤。
