状态:已实施(2026-10-29)。决策见 ADR-0026。
MCP 服务的工具往往比较底层,一个分析任务可能要调用几百次(例如查询 500 台设备的状态再汇总)。模型逐次调用时:
模型自己的沙箱里写脚本调用不到 MCP 工具(工具只经网关提供给引擎)。而事先为每种分析方式都在服务端做好汇总工具,又不够灵活。
网关新增工具 run_script(code, tools, description):模型写一段 Python 脚本,由网关在沙箱中执行。脚本通过 agent_tools 模块调用 MCP 工具:每次调用都经过网关(工具策略、结果处理与普通调用相同),只是不经过模型。循环、筛选、汇总、写文件都在脚本中完成,只有脚本打印的内容交回模型。
from agent_tools import call, call_many, call_raw, progress, ToolError
rows = call_many("fleet__get_device_status", [{"sn": sn} for sn in sns]) # 平台并发执行
progress(len(rows), len(sns), "汇总")
| 函数 | 说明 |
|---|---|
call(tool, args) |
返回结构化结果(dict)或文本;工具报错时抛出 ToolError |
call_many(tool, args_list, return_errors=False) |
批量调用同一个工具,按顺序返回;每批 50 个请求,平台按并发上限执行 |
call_raw(tool, args) |
返回 {text, structured, is_error},不抛出工具错误 |
progress(done, total, message) |
报告进度,显示在对话中 |
run_script。RUN_SCRIPT_DESCRIPTION)中写明了用法和规则,模型据此决定何时使用。services/office.ts 的 sandboxArgs):系统目录只读、Python 运行环境只读、会话工作区可读写(只读模式下只读)、不能联网、/tmp 独立。当前目录为工作区。data/script-runtime/agent_tools.py,沙箱中只读。scripts):每个脚本最多调用 2000 次工具、同时 4 次、最长 30 分钟。超时或取消时结束整个进程树。backgroundCalls.autoAfterSec 转为后台,完成后把结果作为新消息发给发起方;可以在后台调用栏取消。服务重启后中断,与"保持连接等待"的后台调用一样按失败通知。| 工具 | 在脚本中 |
|---|---|
| 只读工具 | 直接调用 |
| 写工具(跟随权限模式、直接调用) | 必须在 tools 参数中列出;"需审批"模式下,执行前统一审批一次(卡片列出这些工具和脚本内容,只有"允许一次"和"拒绝");已"本会话允许"的不再询问;自动模式不询问 |
| 破坏性工具(总是审批) | 不能在脚本中调用,请模型直接调用、逐次确认 |
| 只能以长任务方式调用的工具 | 不能在脚本中调用 |
| 关闭的工具、只读模式下的写工具 | 不提供 |
没有列出的写工具在脚本中调用时,脚本收到 ToolError。
.agent/scripts/<脚本 id>/:script.py(脚本)、calls.jsonl(每次调用一行:时间、工具、参数、耗时、是否出错、结果摘要)、output.txt(完整输出)。gateway_call):说明、调用次数与失败次数、各工具的次数、用时、退出码、明细目录、脚本内容。不为每次调用写审计,避免淹没审计页面。script.progress(只推送、不保存,每秒最多一次):已调用次数、失败次数、脚本报告的进度、用时、状态。<AgentChat> 在时间线底部显示进度(有总数时带进度条),结束后几秒移除。工作组中暂不显示。