工具包、Python 执行器与 Artifact.md 35 KB

工具包、Python 执行器与 Artifact

本文引用的文件

  • AgentToolRegistry.java
  • AgentToolPackEntity.java
  • AgentToolCatalogServiceImpl.java
  • AgentPythonFileController.java
  • AgentArtifactController.java
  • artifacts.ts
  • artifactApi.ts
  • index.vue(工作台)
  • ArtifactPanel.vue
  • ArtifactPreviewModal.vue
  • ArtifactFileCard.vue
  • agent_tool_pack.sql

目录

  1. 引言
  2. 项目结构定位
  3. 核心组件总览
  4. 工具目录体系:AgentTool、AgentToolPackEntity、AgentToolRegistry
  5. 工具清单加载与匹配:AgentToolCatalogService
  6. Python 文件管理:AgentPythonFileController
  7. 产物管理:AgentArtifactController 与前端 artifacts.ts
  8. 示例流程
  9. 依赖关系分析
  10. 性能与并发特性
  11. 常见问题排查
  12. 结论

引言

本文件聚焦三个相互关联的能力:

  1. 工具目录体系:把业务侧只读查询能力包装成 Agent 可调用工具,并通过“工具组 + 工具包”进行分组、筛选和权限控制。
  2. Python 执行器产物访问:Python 脚本产生的图片等沙箱输出,通过受控的 HTTP 路径暴露给前端 Markdown 或结果展示使用。
  3. Agent 产物预览与下载:工具导出 CSV 等结构化结果以 Artifact 形式持久化,并提供轻量预览与完整下载。

这些能力共同构成 Agent 从“发现问题 → 调用工具 → 生成中间结果 → 展示最终产物”的后端支撑链路。

项目结构定位

相关代码主要分布在后端 ai-server 的前端 ai-electron/frontend:

graph TB
    subgraph "后端 ai-server"
        REG["AgentToolRegistry<br/>工具注册中心"]
        CATALOG["AgentToolCatalogServiceImpl<br/>工具清单同步与查询"]
        PYCTL["AgentPythonFileController<br/>Python 沙箱图片访问"]
        ARTCTL["AgentArtifactController<br/>CSV 产物预览与下载"]
        PACK["AgentToolPackEntity<br/>工具包实体"]
    end

    subgraph "前端 ai-electron/frontend"
        UTILS["artifacts.ts<br/>产物提取与预览状态"]
        API["artifactApi.ts<br/>预览与下载接口封装"]
        WORK["index.vue<br/>工作台产物面板入口"]
        PANEL["ArtifactPanel.vue<br/>产物列表"]
        MODAL["ArtifactPreviewModal.vue<br/>产物预览弹窗"]
        CARD["ArtifactFileCard.vue<br/>单条产物卡片"]
    end

    REG --> CATALOG
    CATALOG --> PACK
    ARTCTL --> UTILS
    UTILS --> API
    WORK --> PANEL
    PANEL --> MODAL
    PANEL --> CARD

图表来源

  • AgentToolRegistry.java:1-200
  • AgentToolCatalogServiceImpl.java:1-200
  • AgentPythonFileController.java:1-112
  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47
  • index.vue:77-144

章节来源

  • AgentToolRegistry.java:1-200
  • AgentToolCatalogServiceImpl.java:1-200
  • AgentPythonFileController.java:1-112
  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47
  • index.vue:77-144

核心组件总览

组件 类型 职责 关键输入 关键输出
AgentToolRegistry Spring 组件 按业务域注册 Agent 工具,定义工具组名、默认激活组和工具清单 各业务 Service、ArtifactService 注入到 Toolkit 的工具实例与工具组
AgentToolPackEntity MyBatis-Plus 实体 表示用户或系统维护的“工具包”,即一组工具名的集合 数据库 agent_tool_pack 工具包元数据与 tool_names JSON
AgentToolCatalogServiceImpl Service 实现 扫描注解、合并运行时 Schema、同步 agent_tool 表,并对外提供工具清单 注解扫描器、Toolkit、Mapper 工具 VO 列表、同步计数
AgentPythonFileController REST Controller 安全读取 Python 沙箱产出的图片等文件 workspaceId、execId、filename 图片或二进制响应
AgentArtifactController REST Controller 预览 CSV 产物前 N 行、下载完整 CSV 产物 id、可选 limit 表格数据或文件流
artifacts.ts 前端工具模块 从聊天消息中提取产物元数据、统一数值字段、管理预览弹窗状态 ChatMessage[] SessionArtifact[]、预览状态
artifactApi.ts 前端 API 模块 调用预览与下载接口,处理 token 与 blob 下载 产物 id、文件名 预览对象或下载结果

章节来源

  • AgentToolRegistry.java:1-200
  • AgentToolPackEntity.java:1-50
  • AgentToolCatalogServiceImpl.java:1-200
  • AgentPythonFileController.java:1-112
  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47

工具目录体系:AgentTool、AgentToolPackEntity、AgentToolRegistry

工具分组模型

AgentToolRegistry 是业务工具的注册中心。它不负责具体查询逻辑,而是把已有只读 Service 封装为 Agent 可调用工具,并按领域划分为多个工具组:

  • call:通话分析
  • trans:交易与资金分析
  • track:轨迹、出行与快递
  • otg:全文检索(当前未启用)
  • graph:关系图谱
  • person:人物画像(默认激活)
  • file:非表格材料档案

每个工具组都有:

  • 组名常量
  • 中文标签
  • 面向模型的组描述
  • 工具名清单
  • 是否默认激活

    classDiagram
    class AgentToolRegistry {
        +String GROUP_CALL
        +String GROUP_TRANS
        +String GROUP_TRACK
        +String GROUP_OTG
        +String GROUP_GRAPH
        +String GROUP_PERSON
        +String GROUP_FILE
        +List~String~ DEFAULT_ACTIVE_GROUPS
        +List~String~ registeredGroupNames()
        +String groupLabel(groupName)
        +List~String~ groupToolNames(groupName)
        +List~String~ registeredToolNames()
        +registerBusinessTools(toolkit)
        +registerBusinessTools(toolkit, activeGroups)
        +registerBusinessTools(toolkit, enabledGroups, activeGroups)
        +registerBusinessTools(toolkit, enabledGroups, activeGroups, toolFilter)
    }
    
    class AgentToolPackEntity {
        +Long id
        +Long userId
        +Integer isBuiltin
        +String name
        +String description
        +String toolNames
        +LocalDateTime createAt
        +LocalDateTime updateAt
    }
    
    AgentToolRegistry --> "1..*" String : "工具名"
    AgentToolPackEntity --> "1..*" String : "tool_names 引用 agent_tool.tool_name"
    

图表来源

  • AgentToolRegistry.java:1-200
  • AgentToolRegistry.java:201-449
  • AgentToolPackEntity.java:1-50

工具包的存储语义

AgentToolPackEntity 对应数据库表 agent_tool_pack。它的核心语义是:

字段 含义
id 雪花 ID
userId 创建者,用于用户隔离
isBuiltin 是否为系统内置包;内置包全局可见且不可编辑删除
name 同用户内唯一的工具包名
description 一句话说明
toolNames JSON 字符串数组,值来自 agent_tool.tool_name
createAt / updateAt 时间戳

工具包不是“新工具”,而是对现有工具名的组合。新增业务工具时,应同时更新系统内置工具包的初始化 SQL,让新建方案可以一键勾选。

章节来源

  • AgentToolPackEntity.java:1-50
  • agent_tool_pack.sql:1-81

工具清单加载与匹配:AgentToolCatalogService

同步机制

AgentToolCatalogServiceImpl.syncFromCode() 负责把代码中的工具信息同步到 agent_tool 表。它合并两个数据源:

  1. 反射扫描:由 ToolAnnotationScanner 发现带注解的工具方法,得到工具名、类名、方法名、描述、是否只读。
  2. 运行时装配:通过 AgentService.buildCapabilityToolkit() 获取实际注册进 Toolkit 的工具,从而获得工具所属组、组描述和参数 JSON Schema。

    flowchart TD
    Start(["开始同步"]) --> ReadDB["读取 agent_tool 现有数据"]
    ReadDB --> ScanAnno["反射扫描 @Tool 方法"]
    ScanAnno --> BuildToolkit["构建运行时 Toolkit"]
    BuildToolkit --> IndexSchema["按工具名索引 ToolSchema"]
    IndexSchema --> BuildGroupIndex["构建工具组索引"]
    BuildGroupIndex --> Merge["逐工具合并反射数据与运行时数据"]
    Merge --> InsertUpdate["新增或更新 agent_tool"]
    InsertUpdate --> SoftDelete["对已移除工具软删除"]
    SoftDelete --> WarnMissing{"运行时工具有但反射未扫到?"}
    WarnMissing -->|是| LogMissing["记录日志"]
    WarnMissing -->|否| Done(["完成"])
    LogMissing --> Done
    

图表来源

  • AgentToolCatalogServiceImpl.java:1-200

工具分组与排序

同步过程中,buildGroupIndex 会:

  • 按 AgentToolRegistry.registeredGroupNames() 的顺序建立业务组索引
  • 将不属于任何业务组的工具归入“基础工具”组
  • 把默认激活组标记为 defaultActive
  • 按组顺序和工具名排序后返回前端

    flowchart LR
    Registry["AgentToolRegistry<br/>registeredGroupNames()"] --> Index["GroupIndex"]
    Toolkit["Toolkit<br/>getToolGroup(...)"] --> Index
    Index --> Base["基础工具组<br/>BASE_GROUP_CODE"]
    Index --> Person["人物画像"]
    Index --> Call["通话分析"]
    Index --> Trans["交易与资金分析"]
    Index --> Track["轨迹、出行与快递"]
    Index --> Graph["关系图谱"]
    Index --> File["非表格材料档案"]
    

图表来源

  • AgentToolCatalogServiceImpl.java:201-281
  • AgentToolRegistry.java:1-200

错误容错

  • 如果 agent_tool 表不存在,同步过程记录错误日志并返回,不阻断应用启动。
  • 如果工具参数 JSON 解析失败,该工具按无参数处理,不会因一条脏数据导致整页崩溃。
  • 如果运行时工具容器中有工具但反射未扫到,会记录提示日志,常用于排查“注册了工具但忘记加注解”的问题。

章节来源

  • AgentToolCatalogServiceImpl.java:1-200
  • AgentToolCatalogServiceImpl.java:201-281

Python 文件管理:AgentPythonFileController

设计目标

AgentPythonFileController 暴露 /py/files/{workspaceId}/{execId}/{filename} 路径,用于在 Markdown 或其他结果中直接显示 Python 脚本生成的图片。其关键约束是:

  • 只允许白名单扩展名:png、jpg、jpeg、gif、webp、svg、bmp。
  • workspaceId、execId、filename 三段路径均做白名单校验。
  • 最终路径必须落在 workspace/{workspaceId}/py-out/ 下,防止目录穿越。
  • 只能访问当前打开案件对应的 py-out 目录,避免仅凭 UUID 读取其他案件产物。
  • 返回响应带有 1 小时公共缓存控制,适合浏览器重复渲染同一张图。

    sequenceDiagram
    participant FE as "前端"
    participant CTRL as "AgentPythonFileController"
    participant FS as "文件系统"
    
    FE->>CTRL: GET /py/files/workspaceId/execId/filename
    CTRL->>CTRL: 校验三段路径白名单
    CTRL->>CTRL: 校验当前案件 workspaceId
    CTRL->>FS: 计算目标路径
    FS-->>CTRL: 判断是否为普通文件
    alt 合法文件
        CTRL-->>FE: 200 + 图片 Content-Type
    else 非法路径
        CTRL-->>FE: 400 非法参数
    else 文件不存在
        CTRL-->>FE: 404 文件不存在或已被清理
    end
    

图表来源

  • AgentPythonFileController.java:1-112

安全边界

检查项 处理方式
路径包含 /、\ 或 .. 直接拒绝
字符不在字母、数字、下划线、连字符、点范围内 拒绝
请求文件不属于当前案件 返回无权访问
归一化后路径超出 py-out 根目录 返回非法文件路径
目标不是普通文件 返回文件不存在

章节来源

  • AgentPythonFileController.java:1-112

产物管理:AgentArtifactController 与前端 artifacts.ts

后端产物接口

AgentArtifactController 提供两个端点:

端点 功能 输入 输出
GET /agent/artifact/preview 预览 CSV 前 N 行 id、可选 limit {columns, rows}
GET /agent/artifact/download 下载完整 CSV id 带 Content-Disposition 的文件流

预览默认限制 200 行,后端不会为了统计行数而全量读取大文件;总行数由工具结果中的 artifact.totalRows 提供。

鉴权方面,控制器本身不进入 sa-token 白名单,而是通过 ArtifactService.resolve 基于当前案件解析路径;前端下载时必须携带 x-token 请求头。

sequenceDiagram
    participant UI as "前端产物组件"
    participant API as "artifactApi.ts"
    participant CTRL as "AgentArtifactController"
    participant SVC as "ArtifactService"
    participant FS as "文件系统"

    UI->>API: fetchArtifactPreview(id, limit)
    API->>CTRL: GET /agent/artifact/preview?id=&limit=
    CTRL->>SVC: preview(id, limit)
    SVC->>FS: 流式读取前 N 行
    FS-->>SVC: columns + rows
    SVC-->>CTRL: Map<String,Object>
    CTRL-->>UI: {columns, rows}

    UI->>API: downloadArtifactFile({id, fileName})
    API->>CTRL: GET /agent/artifact/download?id=
    CTRL->>SVC: resolve(id)
    SVC-->>CTRL: Path
    CTRL-->>API: text/csv + attachment
    API-->>UI: blob 触发保存

图表来源

  • AgentArtifactController.java:1-76
  • artifactApi.ts:1-47

前端产物提取与展示

前端产物展示的核心是 artifacts.ts。它从聊天消息的 toolSteps 中恢复工具结果 JSON,并提取其中的 artifact 字段。这样实时流、历史会话刷新、打开历史会话三条路径共用同一套提取逻辑。

关键能力:

  • extractMessageArtifacts:从单条消息提取产物。
  • extractArtifacts:从整段会话提取产物。
  • artifactRowsText:格式化行数文本。
  • artifactSizeText:格式化文件大小。
  • openArtifactPreview / closeArtifactPreview:管理全局预览弹窗状态。
  • toCount:兼容后端 Long 序列化为字符串的情况。

    flowchart TD
    Msg["聊天消息 ChatMessage"] --> Steps["toolSteps"]
    Steps --> Parse["解析 step.result JSON"]
    Parse --> HasArtifact{"存在 artifact.id?"}
    HasArtifact -->|否| NextStep["跳过该步骤"]
    HasArtifact -->|是| Meta["提取 totalRows、sizeBytes、fileName"]
    Meta --> Normalize["数值字段归一化为 number"]
    Normalize --> Session["附加 messageId、toolName"]
    Session --> List["SessionArtifact[]"]
    

图表来源

  • artifacts.ts:1-106

前端展示链路

工作台入口在 index.vue 中:

  • 监听 store.messages。
  • 调用 extractArtifacts 生成产物列表。
  • 将产物传给 ArtifactPanel。
  • 全局挂载 ArtifactPreviewModal 消费 previewArtifact。

    graph LR
    Store["store.messages"] --> Extract["extractArtifacts"]
    Extract --> Panel["ArtifactPanel.vue"]
    Panel --> Card["ArtifactFileCard.vue"]
    Panel --> Modal["ArtifactPreviewModal.vue"]
    Card --> Modal
    Panel --> API["artifactApi.ts"]
    

图表来源

  • index.vue:77-144
  • ArtifactPanel.vue:54-140
  • ArtifactFileCard.vue:3-106
  • ArtifactPreviewModal.vue:13-138
  • artifacts.ts:1-106
  • artifactApi.ts:1-47

章节来源

  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47
  • index.vue:77-144
  • ArtifactPanel.vue:54-140
  • ArtifactPreviewModal.vue:13-138
  • ArtifactFileCard.vue:3-106

示例流程

示例一:注册新工具

假设要新增一个只读业务工具:

  1. 在合适的业务 Service 中实现查询方法。
  2. 在工具实现类中增加对应方法,并加上工具注解(由 ToolAnnotationScanner 扫描)。
  3. 在 AgentToolRegistry 中:
    • 将该工具名加入对应工具的常量清单。
    • 在 registerBusinessTools 中注册工具实例。
    • 在 createGroup 中把工具名加入对应组。
  4. 如果是系统内置工具包的一部分,更新 sql/agent_tool_pack.sql 中的内置包 tool_names。
  5. 重启服务并执行工具清单同步,使 agent_tool 表生效。

注意:

  • 新增工具不应修改底层 Service 与 Mapper 的既有行为。
  • 工具分组描述要写清楚“什么时候该激活这个组”。
  • 工具名必须保持唯一,否则工具包白名单和工具清单映射会出现歧义。

章节来源

  • AgentToolRegistry.java:1-200
  • AgentToolRegistry.java:201-449
  • agent_tool_pack.sql:1-81
  • AgentToolCatalogServiceImpl.java:1-200

示例二:调用 Python 脚本

典型流程如下:

  1. Agent 通过 Python 工具执行脚本。
  2. Python 执行器将图片等产物写入工作空间下的 workspace/{workspaceId}/py-out/{execId}/。
  3. 工具返回中包含图片访问地址。
  4. 前端 Markdown 或结果展示组件请求 /py/files/{workspaceId}/{execId}/{filename}。
  5. 后端校验当前案件、路径白名单和目标文件后返回图片。

    sequenceDiagram
    participant Agent as "Agent"
    participant PyExec as "PythonExecutor"
    participant FS as "工作空间 py-out"
    participant FE as "前端"
    participant Ctrl as "AgentPythonFileController"
    
    Agent->>PyExec: 执行 Python 脚本
    PyExec->>FS: 写入 execId 子目录图片
    PyExec-->>Agent: 返回图片 URL
    FE->>Ctrl: GET /py/files/workspaceId/execId/image.png
    Ctrl-->>FE: 返回图片资源
    

图表来源

  • AgentPythonFileController.java:1-112

注意事项:

  • 如果图片被 LRU 清理,前端会收到 404。
  • 如果 workspaceId 与当前案件不一致,会被拒绝。
  • 如果文件名包含非法字符或尝试目录穿越,会返回 400。

章节来源

  • AgentPythonFileController.java:1-112

示例三:上传数据文件

虽然本文档重点不是通用文件上传,但根据上下文,数据文件通常通过 Agent 的工作空间或附件通道进入系统,再由工具或 Python 脚本消费。对于结构化结果,推荐走 ArtifactService 落盘 CSV,而不是随意写入任意目录,这样可以获得统一的预览、下载、归属和安全控制。

示例四:查看工具调用结果与 Artifact 预览

前端展示链路如下:

  1. 工具返回 JSON 中包含 artifact 字段。
  2. artifacts.ts 从 message.toolSteps 中提取产物。
  3. ArtifactPanel 列出产物,显示文件名、行数、大小。
  4. 点击预览时,调用 fetchArtifactPreview 拉取前 N 行。
  5. 点击下载时,调用 downloadArtifactFile,携带 x-token 下载完整 CSV。

    sequenceDiagram
    participant Message as "聊天消息"
    participant Utils as "artifacts.ts"
    participant Panel as "ArtifactPanel"
    participant Modal as "ArtifactPreviewModal"
    participant API as "artifactApi.ts"
    participant Server as "AgentArtifactController"
    
    Message-->>Utils: toolSteps
    Utils-->>Panel: SessionArtifact[]
    Panel->>Modal: openArtifactPreview(artifact)
    Modal->>API: fetchArtifactPreview(id, limit)
    API->>Server: GET /agent/artifact/preview
    Server-->>API: {columns, rows}
    API-->>Modal: 预览数据
    Panel->>API: downloadArtifactFile({id, fileName})
    API->>Server: GET /agent/artifact/download
    Server-->>API: CSV blob
    

图表来源

  • artifacts.ts:1-106
  • ArtifactPanel.vue:54-140
  • ArtifactPreviewModal.vue:59-138
  • artifactApi.ts:1-47
  • AgentArtifactController.java:1-76

章节来源

  • artifacts.ts:1-106
  • ArtifactPanel.vue:54-140
  • ArtifactPreviewModal.vue:59-138
  • artifactApi.ts:1-47
  • AgentArtifactController.java:1-76

依赖关系分析

graph LR
    ToolAnnotationScanner["ToolAnnotationScanner"] --> Catalog["AgentToolCatalogServiceImpl"]
    AgentService["AgentService"] --> Catalog
    AgentToolRegistry["AgentToolRegistry"] --> Catalog
    AgentToolMapper["AgentToolMapper"] --> Catalog
    Catalog --> AgentToolVO["AgentToolVO"]
    AgentToolRegistry --> Toolkit["Toolkit"]
    AgentToolRegistry --> ArtifactService["ArtifactService"]
    AgentArtifactController --> ArtifactService
    Frontend["前端产物组件"] --> ArtifactsTS["artifacts.ts"]
    ArtifactsTS --> ArtifactApi["artifactApi.ts"]
    ArtifactApi --> AgentArtifactController

图表来源

  • AgentToolCatalogServiceImpl.java:1-200
  • AgentToolRegistry.java:201-449
  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47

耦合关系总结:

  • AgentToolRegistry 与大量业务 Service 耦合,但这些耦合集中在注册层,业务 Service 本身保持不变。
  • AgentToolCatalogServiceImpl 同时依赖注解扫描、运行时 Toolkit 和数据库 Mapper,属于协调型 Service。
  • AgentArtifactController 依赖 ArtifactService,不直接操作文件路径细节。
  • 前端通过 artifacts.ts 解耦消息结构与产物展示,artifactApi.ts 解耦 HTTP 调用细节。

章节来源

  • AgentToolCatalogServiceImpl.java:1-200
  • AgentToolRegistry.java:201-449
  • AgentArtifactController.java:1-76
  • artifacts.ts:1-106
  • artifactApi.ts:1-47

性能与并发特性

工具清单同步

  • 同步过程按扫描到的工具数量线性处理。
  • 对每个工具最多一次查找 Schema、一次组索引查询、一次插入或更新。
  • 最后对“已存在于数据库但不再扫描到的工具”执行软删除。
  • 若数据库表缺失,同步失败不会阻止应用启动。

Artifact 预览

  • 预览接口采用流式读取前 N 行,避免整文件载入内存。
  • 不统计总行数,总行数来自工具结果元数据。
  • 这避免了在大 CSV 上重复 IO。

Python 图片缓存

  • /py/files 返回 1 小时公共缓存。
  • 适合多次渲染同一张图的场景。
  • 如果文件被 LRU 清理,浏览器再次请求会拿到 404,前端需要正确处理。

并发访问

  • Python 文件和 Artifact 都基于文件系统路径访问。
  • 多 Agent 并发执行 Python 脚本时,execId 作为隔离键,降低同名文件冲突风险。
  • Artifact 的 id 通常来自工具结果,应避免不同任务复用相同 id。
  • 若高并发产生相同 id,需要在上层保证 id 生成唯一性。

章节来源

  • AgentToolCatalogServiceImpl.java:1-200
  • AgentArtifactController.java:1-76
  • AgentPythonFileController.java:1-112

常见问题排查

Python 执行权限不足

现象:Python 脚本无法写入输出文件或图片。

排查要点:

  1. 确认 Python 执行进程对工作空间目录有读写权限。
  2. 确认 workspace/{workspaceId}/py-out/ 存在且可写。
  3. 检查 Python 执行器配置的执行目录、超时时间和工作目录。
  4. 观察 Python 执行日志,确认异常发生在写入阶段还是命令启动阶段。

章节来源

  • AgentPythonFileController.java:1-112

脚本超时

现象:Python 工具长时间无响应,最终失败。

排查要点:

  1. 检查 Python 执行器的超时配置。
  2. 确认脚本是否卡在读库、网络请求或大数据集处理。
  3. 优先改为分页查询或先采样再分析。
  4. 对需要较长时间的任务,考虑异步执行或分步工具。

工具未注册

现象:Agent 看不到某个工具,或工具清单同步数量为 0。

排查要点:

  1. 确认工具方法加了正确的工具注解。
  2. 确认工具类位于注解扫描包路径下。
  3. 确认 AgentToolRegistry 中已注册该工具实例。
  4. 检查 AgentToolCatalogServiceImpl 日志,关注“反射未扫到任何 @Tool 方法”或“运行时工具容器里有、但反射未扫到的工具”。
  5. 确认 agent_tool 表已创建并可读取。

章节来源

  • AgentToolCatalogServiceImpl.java:1-200
  • AgentToolRegistry.java:1-200

Artifact 路径不存在

现象:预览或下载返回 404,或前端报错。

排查要点:

  1. 确认工具成功导出了 CSV,并设置了 artifact.id。
  2. 确认 ArtifactService.resolve 能解析到有效路径。
  3. 确认当前案件的 Artifact 根目录存在。
  4. 检查是否有清理策略删除了产物文件。
  5. 确认前端传递的 id 与工具结果中的 id 一致。

章节来源

  • AgentArtifactController.java:1-76
  • artifactApi.ts:1-47

并发访问冲突

现象:多个 Agent 或用户之间出现产物混用、路径覆盖或权限问题。

排查要点:

  1. 确保 Python 执行 id 唯一,避免多个任务写入同一 execId。
  2. 确保 Artifact id 全局唯一。
  3. 确认 Python 图片访问限制在当前 workspaceId。
  4. 确认 Artifact 路径按当前案件解析,不能跨案件访问。
  5. 在高并发场景下,检查文件系统清理策略是否与产物生命周期匹配。

章节来源

  • AgentPythonFileController.java:1-112
  • AgentArtifactController.java:1-76

前端无法下载 CSV

现象:点击下载后没有文件,或下载到 JSON 错误内容。

排查要点:

  1. 不要使用 <a href> 裸链接下载,因为不带 x-token。
  2. 确认前端通过 fetch 携带 x-token。
  3. 确认后端返回的是 text/csv,而不是登录失败的 JSON。
  4. 检查 artifactApi.ts 中是否正确处理非 JSON 响应。
  5. 检查桌面端下载管理器是否正常接收 blob。

章节来源

  • artifactApi.ts:1-47
  • AgentArtifactController.java:1-76

结论

工具包、Python 执行器与 Artifact 共同构成了 Agent 的可扩展能力层:

  • AgentToolRegistry 负责把业务查询能力组织成结构化、可分组、可控制的工具。
  • AgentToolCatalogServiceImpl 负责把注解、运行时工具和数据库三者对齐,形成稳定工具清单。
  • AgentToolPackEntity 和 agent_tool_pack 表提供用户级工具组合管理能力。
  • AgentPythonFileController 提供安全的 Python 沙箱图片访问通道。
  • AgentArtifactController 提供 CSV 产物的轻量预览和完整下载。
  • 前端 artifacts.ts 和 artifactApi.ts 将产物从工具结果中抽取出来,并以直观方式展示和操作。

维护这套体系的关键原则是:工具注册与业务逻辑分离、产物路径严格受控、前端与后端共享产物语义、错误路径给出明确反馈。新增工具或产物类型时,应优先考虑是否需要分组、是否需要 Artifact、是否需要 Python 输出、以及并发和权限边界是否清晰。