本文引用的文件
本文件聚焦三个相互关联的能力:
这些能力共同构成 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 |
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 是业务工具的注册中心。它不负责具体查询逻辑,而是把已有只读 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"
图表来源
AgentToolPackEntity 对应数据库表 agent_tool_pack。它的核心语义是:
| 字段 | 含义 |
|---|---|
id |
雪花 ID |
userId |
创建者,用于用户隔离 |
isBuiltin |
是否为系统内置包;内置包全局可见且不可编辑删除 |
name |
同用户内唯一的工具包名 |
description |
一句话说明 |
toolNames |
JSON 字符串数组,值来自 agent_tool.tool_name |
createAt / updateAt |
时间戳 |
工具包不是“新工具”,而是对现有工具名的组合。新增业务工具时,应同时更新系统内置工具包的初始化 SQL,让新建方案可以一键勾选。
章节来源
AgentToolCatalogServiceImpl.syncFromCode() 负责把代码中的工具信息同步到 agent_tool 表。它合并两个数据源:
ToolAnnotationScanner 发现带注解的工具方法,得到工具名、类名、方法名、描述、是否只读。运行时装配:通过 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
图表来源
同步过程中,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["非表格材料档案"]
图表来源
agent_tool 表不存在,同步过程记录错误日志并返回,不阻断应用启动。章节来源
AgentPythonFileController 暴露 /py/files/{workspaceId}/{execId}/{filename} 路径,用于在 Markdown 或其他结果中直接显示 Python 脚本生成的图片。其关键约束是:
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
图表来源
| 检查项 | 处理方式 |
|---|---|
路径包含 /、\ 或 .. |
直接拒绝 |
| 字符不在字母、数字、下划线、连字符、点范围内 | 拒绝 |
| 请求文件不属于当前案件 | 返回无权访问 |
归一化后路径超出 py-out 根目录 |
返回非法文件路径 |
| 目标不是普通文件 | 返回文件不存在 |
章节来源
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 触发保存
图表来源
前端产物展示的核心是 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[]"]
图表来源
工作台入口在 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"]
图表来源
章节来源
假设要新增一个只读业务工具:
ToolAnnotationScanner 扫描)。AgentToolRegistry 中:
registerBusinessTools 中注册工具实例。createGroup 中把工具名加入对应组。sql/agent_tool_pack.sql 中的内置包 tool_names。agent_tool 表生效。注意:
章节来源
典型流程如下:
workspace/{workspaceId}/py-out/{execId}/。/py/files/{workspaceId}/{execId}/{filename}。后端校验当前案件、路径白名单和目标文件后返回图片。
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: 返回图片资源
图表来源
注意事项:
workspaceId 与当前案件不一致,会被拒绝。章节来源
虽然本文档重点不是通用文件上传,但根据上下文,数据文件通常通过 Agent 的工作空间或附件通道进入系统,再由工具或 Python 脚本消费。对于结构化结果,推荐走 ArtifactService 落盘 CSV,而不是随意写入任意目录,这样可以获得统一的预览、下载、归属和安全控制。
前端展示链路如下:
artifact 字段。artifacts.ts 从 message.toolSteps 中提取产物。ArtifactPanel 列出产物,显示文件名、行数、大小。fetchArtifactPreview 拉取前 N 行。点击下载时,调用 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
图表来源
章节来源
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
图表来源
耦合关系总结:
AgentToolRegistry 与大量业务 Service 耦合,但这些耦合集中在注册层,业务 Service 本身保持不变。AgentToolCatalogServiceImpl 同时依赖注解扫描、运行时 Toolkit 和数据库 Mapper,属于协调型 Service。AgentArtifactController 依赖 ArtifactService,不直接操作文件路径细节。artifacts.ts 解耦消息结构与产物展示,artifactApi.ts 解耦 HTTP 调用细节。章节来源
/py/files 返回 1 小时公共缓存。execId 作为隔离键,降低同名文件冲突风险。章节来源
现象:Python 脚本无法写入输出文件或图片。
排查要点:
workspace/{workspaceId}/py-out/ 存在且可写。章节来源
现象:Python 工具长时间无响应,最终失败。
排查要点:
现象:Agent 看不到某个工具,或工具清单同步数量为 0。
排查要点:
AgentToolRegistry 中已注册该工具实例。AgentToolCatalogServiceImpl 日志,关注“反射未扫到任何 @Tool 方法”或“运行时工具容器里有、但反射未扫到的工具”。agent_tool 表已创建并可读取。章节来源
现象:预览或下载返回 404,或前端报错。
排查要点:
artifact.id。ArtifactService.resolve 能解析到有效路径。章节来源
现象:多个 Agent 或用户之间出现产物混用、路径覆盖或权限问题。
排查要点:
execId。workspaceId。章节来源
现象:点击下载后没有文件,或下载到 JSON 错误内容。
排查要点:
<a href> 裸链接下载,因为不带 x-token。fetch 携带 x-token。text/csv,而不是登录失败的 JSON。artifactApi.ts 中是否正确处理非 JSON 响应。章节来源
工具包、Python 执行器与 Artifact 共同构成了 Agent 的可扩展能力层:
AgentToolRegistry 负责把业务查询能力组织成结构化、可分组、可控制的工具。AgentToolCatalogServiceImpl 负责把注解、运行时工具和数据库三者对齐,形成稳定工具清单。AgentToolPackEntity 和 agent_tool_pack 表提供用户级工具组合管理能力。AgentPythonFileController 提供安全的 Python 沙箱图片访问通道。AgentArtifactController 提供 CSV 产物的轻量预览和完整下载。artifacts.ts 和 artifactApi.ts 将产物从工具结果中抽取出来,并以直观方式展示和操作。维护这套体系的关键原则是:工具注册与业务逻辑分离、产物路径严格受控、前端与后端共享产物语义、错误路径给出明确反馈。新增工具或产物类型时,应优先考虑是否需要分组、是否需要 Artifact、是否需要 Python 输出、以及并发和权限边界是否清晰。