# Insight 工作区与 Workspace Catalog
**本文引用的文件**
- [AgentInsightSession.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightSession.java)
- [AgentInsightMessage.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightMessage.java)
- [InsightAgentFactory.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java)
- [InsightServiceImpl.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java)
- [InsightController.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java)
- [InsightPromptBuilder.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/prompt/InsightPromptBuilder.java)
- [InsightContextBuilder.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java)
- [WorkspaceSchemaCatalog.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java)
- [WorkspaceManagerFactory.java](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java)
- [useInsightStream.ts](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts)
- [api.ts](file://ai-electron/frontend/src/graph/insight/api.ts)
- [types.ts](file://ai-electron/frontend/src/graph/insight/types.ts)
- [insight_agent_tables.sql](file://sql/insight_agent_tables.sql)
- [continuous-insight-plan.md](file://docs/design/continuous-insight-plan.md)
## 目录
1. [引言](#引言)
2. [项目结构定位](#项目结构定位)
3. [核心数据模型](#核心数据模型)
4. [架构总览](#架构总览)
5. [关键组件分析](#关键组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能与可靠性特征](#性能与可靠性特征)
8. [常见问题排查](#常见问题排查)
9. [操作示例](#操作示例)
10. [结论](#结论)
## 引言
本文件聚焦 Insight 工作区与 Workspace Catalog,目标是解释以下问题:
- `AgentInsightSession` 与 `AgentInsightMessage` 的数据模型、持久化边界与安全隔离。
- `InsightAgentFactory` 如何启动分析型 Agent,以及与通用 Agent 的区别。
- 前端 `useInsightStream` 如何通过 SSE 消费 Insight 流式输出。
- Workspace Catalog(`WorkspaceSchemaCatalog`)与案件数据源、用户会话的关系。
- Insight 与普通 Agent 对话在持久化、图谱分析结果、API 联动上的差异。
- 创建 Insight 会话、关联图谱或外部数据、查看消息流、清理工作区的操作流程。
- 常见故障:会话丢失、消息未落库、工作区跨节点不一致、SSE 被网关切断等。
## 项目结构定位
Insight 能力位于后端 `ai-server/module/agent/insight` 和前端 `ai-electron/frontend/src/graph/insight` 两个区域:
- 后端负责:会话/消息表、动态提示词、Agent 实例池、SSE 流、案件访问守卫。
- 前端负责:抽屉 UI、状态机、分页消息加载、结构化产物渲染、SSE 事件处理。
- 数据库 DDL 独立存放于 `sql/insight_agent_tables.sql`,不复用通用对话表。
- 设计意图由 `docs/design/continuous-insight-plan.md` 明确说明。
```mermaid
graph TB
subgraph "前端"
FE_UI["Insight 抽屉 UI"]
FE_HOOK["useInsightStream.ts"]
FE_API["graph/insight/api.ts"]
end
subgraph "后端"
CTRL["InsightController"]
SVC["InsightServiceImpl"]
ENTITY_S["AgentInsightSession"]
ENTITY_M["AgentInsightMessage"]
FACTORY["InsightAgentFactory"]
PROMPT["InsightPromptBuilder"]
CTX["InsightContextBuilder"]
CATALOG["WorkspaceSchemaCatalog"]
DB[("PostgreSQL
agent_insight_session / agent_insight_message")]
end
FE_UI --> FE_HOOK
FE_HOOK --> FE_API
FE_API --> CTRL
CTRL --> SVC
SVC --> ENTITY_S
SVC --> ENTITY_M
SVC --> FACTORY
SVC --> PROMPT
SVC --> CTX
FACTORY --> CATALOG
ENTITY_S --> DB
ENTITY_M --> DB
```
**图表来源**
- [InsightController.java:1-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L1-L127)
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [AgentInsightSession.java:1-90](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightSession.java#L1-L90)
- [AgentInsightMessage.java:1-85](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightMessage.java#L1-L85)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
- [InsightPromptBuilder.java:1-145](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/prompt/InsightPromptBuilder.java#L1-L145)
- [InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
- [WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [api.ts:1-81](file://ai-electron/frontend/src/graph/insight/api.ts#L1-L81)
**章节来源**
- [continuous-insight-plan.md:1-200](file://docs/design/continuous-insight-plan.md#L1-L200)
- [insight_agent_tables.sql:1-107](file://sql/insight_agent_tables.sql#L1-L107)
## 核心数据模型
Insight 使用两张独立表,与通用对话表物理隔离:
- `agent_insight_session`:会话元数据、上下文快照、系统提示词、消息水位、统计字段。
- `agent_insight_message`:用户提问、助手回答、首轮自动分析结果、工具调用明细、结构化产物。
### 会话实体 `AgentInsightSession`
关键字段职责如下:
- `id`:主键,应用侧生成,非单调。
- `caseId`:案件级硬隔离边界,所有查询强制携带。
- `bizType`:研判场景维度,当前固定为图谱关系。
- `scope`:分析范围,本期主要为整批结果集。
- `agentRowId`、`modelId`:使用的 Agent 配置行与默认模型。
- `title`:会话标题,包含时间信息。
- `context`:查询条件加图谱快照的 JSONB,是动态系统提示词的数据源。
- `contextHash`:对 `context` 做 SHA-256,用于同条件复用和去重提示。
- `sysPrompt`:会话内实际使用的完整系统提示词,不可变且不下发接口。
- `messageCount`、`lastSeq`、`totalTokens`、`lastMessageAt`:列表展示与排序辅助。
- `pinned`:是否置顶。
- `status`:ACTIVE、STREAMING、ARCHIVED,STREAMING 用于并发抢占。
- `createAt`、`updateAt`:创建与更新时间。
该实体的注释明确指出:隔离通过“独立表 + case_id 强制过滤 + session_id 与 case_id 双条件”建立;本实体只承载会话元数据,查询条件与结果快照落在 `context`,完整提示词落在 `sys_prompt`。
**章节来源**
- [AgentInsightSession.java:1-90](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightSession.java#L1-L90)
- [insight_agent_tables.sql:20-63](file://sql/insight_agent_tables.sql#L20-L63)
### 消息实体 `AgentInsightMessage`
关键字段职责如下:
- `id`:主键,应用侧生成。
- `sessionId`、`caseId`:归属到具体 Insight 会话,并冗余案件 ID 以强化越权防护。
- `seq`:会话内单调递增序号,是稳定排序列。
- `role`:user、assistant、system。
- `content`:正文文本。
- `contentType`:text 或 insight。
- `messageType`:chat、first_round、followup。
- `metadata`:轻量 JSONB,如思考过程、中断标记、耗时。
- `toolEvents`:工具调用明细,单条可达数百 KB,列表查询不 select。
- `outputJson`:首轮 assistant 消息的结构化产物 JSONB。
- `tokenCount`:Token 用量。
- `replyToMessageId`:追问指向的首轮消息,供 UI 分组。
- `starred`:收藏标记。
- `status`:DONE 或 INTERRUPTED。
- `createAt`:创建时间。
DDL 中定义了 `(session_id, seq)` 唯一约束和外键级联删除,并说明:不能用 `id` 或 `create_at` 排序,必须用 `seq`;并发分配 `seq` 应通过原子更新会话水位而非 SELECT MAX。
**章节来源**
- [AgentInsightMessage.java:1-85](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightMessage.java#L1-L85)
- [insight_agent_tables.sql:65-107](file://sql/insight_agent_tables.sql#L65-L107)
### 前端类型契约
前端 `types.ts` 把后端 VO 映射为 TypeScript 类型,并强调:ID 一律按字符串处理,避免 Long 精度丢失。主要类型包括:
- `InsightCreateParams`:创建会话入参,包含案件、业务类型、分析范围、过滤条件、图谱快照、topN。
- `InsightSessionVO`:会话返回体,含 status、context、messageCount 等。
- `InsightMessageVO`:消息返回体,不含 toolEvents。
- `InsightMessagePage`:MyBatis-Plus Page 形状。
- `InsightStreamParams`:流式入参,首轮 message 留空。
- `InsightPayloadWithSource`:结构化产物扩展类型。
**章节来源**
- [types.ts:1-199](file://ai-electron/frontend/src/graph/insight/types.ts#L1-L199)
## 架构总览
Insight 的整体流程可以分成三类路径:
1. **创建会话**:前端 POST `/insight/sessions` → 后端构建上下文与提示词 → 写入 `agent_insight_session`。
2. **流式分析**:前端 POST `/insight/stream` → 后端获取 Agent 实例 → 执行 AgentScope 事件流 → 写消息 → SSE 推送 token、工具调用、thinking、insight、done/error。
3. **历史与追溯**:GET `/insight/sessions`、`/sessions/{id}`、`/sessions/{id}/messages`、`/messages/{messageId}/trace`、`/sessions/{id}/delete`。
```mermaid
sequenceDiagram
participant FE as "前端 useInsightStream"
participant API as "graph/insight/api.ts"
participant CTRL as "InsightController"
participant SVC as "InsightServiceImpl"
participant CTX as "InsightContextBuilder"
participant PROMPT as "InsightPromptBuilder"
participant DB as "PostgreSQL"
participant FACTORY as "InsightAgentFactory"
participant AG as "HarnessAgent"
FE->>API: createInsightSession(params)
API->>CTRL: POST /insight/sessions
CTRL->>SVC: createSession(dto)
SVC->>CTX: build(caseId, caseName, dto)
SVC->>PROMPT: build(context)
SVC->>DB: INSERT agent_insight_session
SVC-->>FE: InsightSessionVO
FE->>API: streamInsight({sessionId, caseId})
API->>CTRL: POST /insight/stream
CTRL->>SVC: stream(dto)
SVC->>FACTORY: getOrCreate(sessionId, modelId, sysPrompt)
FACTORY->>AG: 构造 HarnessAgent
loop 流式事件
AG-->>SVC: token / thinking / tool_call / tool_result / insight / done
SVC->>DB: 插入或更新 agent_insight_message
SVC-->>FE: ServerSentEvent
end
```
**图表来源**
- [InsightController.java:28-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L28-L127)
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
- [InsightPromptBuilder.java:1-145](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/prompt/InsightPromptBuilder.java#L1-L145)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
- [api.ts:1-81](file://ai-electron/frontend/src/graph/insight/api.ts#L1-L81)
## 关键组件分析
### 数据模型类图
```mermaid
classDiagram
class AgentInsightSession {
+Long id
+Long caseId
+String bizType
+String scope
+Long agentRowId
+Long modelId
+String title
+String context
+String contextHash
+String sysPrompt
+Integer messageCount
+Long lastSeq
+Long totalTokens
+LocalDateTime lastMessageAt
+Boolean pinned
+String status
+LocalDateTime createAt
+LocalDateTime updateAt
}
class AgentInsightMessage {
+Long id
+Long sessionId
+Long caseId
+Long seq
+String role
+String content
+String contentType
+String messageType
+String metadata
+String toolEvents
+String outputJson
+Integer tokenCount
+Long replyToMessageId
+Boolean starred
+String status
+LocalDateTime createAt
}
AgentInsightSession <|-- AgentInsightMessage : "一对多"
```
**图表来源**
- [AgentInsightSession.java:1-90](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightSession.java#L1-L90)
- [AgentInsightMessage.java:1-85](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/entity/AgentInsightMessage.java#L1-L85)
### Insight 会话创建与提示词装配
创建 Insight 会话时,后端完成以下关键步骤:
1. 通过 `CaseAccessGuard` 校验请求中的 `caseId` 属于当前用户打开的案件。
2. 从 `AgentModelService` 获取默认模型,无默认模型直接拒绝。
3. 通过 `InsightContextBuilder.build` 规整分析条件、图谱快照、topN,并裁剪图谱。
4. 通过 `InsightPromptBuilder.build` 拼接静态人设、动态上下文块、结构化产物契约、RAG 指引。
5. 将 `context`、`contextHash`、`sysPrompt` 写入会话表。
6. 返回 `InsightSessionVO`,不包含完整的 `sysPrompt`。
`InsightPromptBuilder` 的注释强调:它不复用通用对话的渲染契约,因为 Insight 的 `` ```insight `` 围栏结构与通用表格/ECharts/graph 载荷不同,混在一起会互相污染。首次自动分析的指令由 `firstRoundInstruction()` 提供,前端打开抽屉时不敲字,由服务端注入。
```mermaid
flowchart TD
Start(["创建 Insight 会话"]) --> Guard["案件归属校验"]
Guard --> ModelCheck{"是否存在默认模型"}
ModelCheck -->|否| Error["返回错误:未配置默认模型"]
ModelCheck -->|是| BuildCtx["InsightContextBuilder 构建上下文"]
BuildCtx --> TrimGraph["裁剪图谱快照
按度数保留 topN 节点与两端节点边"]
TrimGraph --> BuildPrompt["InsightPromptBuilder 拼装系统提示词"]
BuildPrompt --> Persist["写入 agent_insight_session"]
Persist --> Return["返回 InsightSessionVO"]
```
**图表来源**
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
- [InsightPromptBuilder.java:1-145](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/prompt/InsightPromptBuilder.java#L1-L145)
**章节来源**
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightPromptBuilder.java:1-145](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/prompt/InsightPromptBuilder.java#L1-L145)
- [InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
### InsightAgentFactory:分析型 Agent 启动与实例池
`InsightAgentFactory` 的核心职责是“取或建研判 Agent 实例”,并维护一个独立实例池。关键点如下:
- 池 key 前缀为 `insight-s`,附加 `sessionId`,确保动态提示词不会在不同会话之间串台。
- 通用 Agent 池 key 是 `w{ws}-a{agent}-m{model}`,不含 `sysPrompt` 维度;复用会导致第二次分析拿到第一次的提示词。
- LRU 上限为 64,空闲超过 30 分钟回收。
- 记忆由 `AgentStateStore` 按 `(userId, sessionId)` 隔离;实例回收不影响会话记忆,只是下次重建 Agent 配置。
- `buildAgent` 刻意为之的差异:
- 不挂意图识别中间件;
- 不挂 Followup 中间件;
- 默认装备 graph 组而非 person 组,起点就是关系图谱数据。
```mermaid
classDiagram
class InsightAgentFactory {
+String AGENT_NAME
-Map~String, HarnessAgent~ agentPool
-Map~String, Long~ lastAccessAt
-ReentrantLock poolLock
+getOrCreate(sessionId, modelId, sysPrompt) HarnessAgent
+evict(sessionId) void
-buildAgent(modelId, sysPrompt) HarnessAgent
}
class HarnessAgent {
<>
}
InsightAgentFactory --> HarnessAgent : "创建并缓存"
```
**图表来源**
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
**章节来源**
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
### 前端 `useInsightStream`:SSE 流式消费
`useInsightStream` 是一个独立的组合式 hook,专门管理 Insight 抽屉的状态机,而不是复用全局 chat store。其状态流转为:
- idle → creating(创建会话)→ streaming(首轮或追问)→ done
- 异常分支:error(模型未配置、网络失败、超限、409 进行中)
主要行为包括:
- 使用本地临时负数 ID 表示尚未落库的前端消息。
- 拉取第 N 页消息,服务端返回 `seq DESC`,前端 reverse 后升序展示。
- 流式期间实时累积工具调用步骤和思考过程。
- 从内容块中提取第一个合法的 `insight` 载荷作为结构化产物。
- 历史消息通过 hydrate 解析富内容块,必要时按需拉取 trace。
- 使用 AbortController 支持关闭抽屉时中止流。
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Creating : "创建会话"
Creating --> Streaming : "开始流式"
Streaming --> Done : "收到 done"
Streaming --> Error : "模型未配置 / 网络 / 超限 / 409"
Done --> Idle : "关闭或切换会话"
Error --> Idle : "重试或关闭"
```
**图表来源**
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
**章节来源**
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [api.ts:1-81](file://ai-electron/frontend/src/graph/insight/api.ts#L1-L81)
### Workspace Catalog 与 Workspace 文件系统
这里有两个容易混淆的概念需要区分:
1. **Workspace Schema Catalog**:`WorkspaceSchemaCatalog` 是可查表目录,来源是模板库元数据,不是 DuckDB 运行时扫描。它聚合既有模板库 `table_info`/`table_field` 与 AI 智能清洗动态表 `ai_clean_template`/`ai_clean_field`,输出 Agent 可使用的表结构清单。它不读取 DuckDB 系统表,也不暴露内部表给模型。
2. **Agent 工作目录**:`WorkspaceManagerFactory` 解析 Agent 运行时工作目录,路径形如 `{cwd}/.agentscope/users/{userId}/workspaces/{workspaceId}/agents/{agentRowId}/`,用于 skills、记忆、子 Agent、事件转录等文件系统隔离。
因此,Workspace Catalog 不等于 DuckDB 数据源目录;它是“模型知道有哪些表可以查”的元数据目录。而 Workspace 文件系统是 AgentScope 运行时的工作空间根。
```mermaid
graph TB
WS_CAT["WorkspaceSchemaCatalog
模板库元数据目录"]
FILE_WS["WorkspaceManagerFactory
Agent 工作目录"]
TEMPLATE["table_info / table_field"]
AICLEAN["ai_clean_template / ai_clean_field"]
USER["用户"]
WORKSPACE["业务工作空间"]
AGENT["Agent 配置"]
TEMPLATE --> WS_CAT
AICLEAN --> WS_CAT
USER --> FILE_WS
WORKSPACE --> FILE_WS
AGENT --> FILE_WS
```
**图表来源**
- [WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
- [WorkspaceManagerFactory.java:1-79](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java#L1-L79)
**章节来源**
- [WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
- [WorkspaceManagerFactory.java:1-79](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java#L1-L79)
## 依赖关系分析
Insight 模块的关键依赖链如下:
```mermaid
graph LR
Controller["InsightController"] --> Service["InsightServiceImpl"]
Service --> SessionEntity["AgentInsightSession"]
Service --> MessageEntity["AgentInsightMessage"]
Service --> ContextBuilder["InsightContextBuilder"]
Service --> PromptBuilder["InsightPromptBuilder"]
Service --> AgentFactory["InsightAgentFactory"]
AgentFactory --> StateStore["AgentStateStore"]
AgentFactory --> Catalog["WorkspaceSchemaCatalog"]
Service --> CaseAccess["CaseAccessGuard"]
Service --> ModelService["AgentModelService"]
Service --> CaseInfo["CaseInfoMapper"]
```
**图表来源**
- [InsightController.java:1-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L1-L127)
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
- [WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
### 耦合与内聚
- Insight 模块与通用对话模块解耦:独立表、独立 Mapper、独立 Service、独立 Agent 实例池。
- 安全性内聚于 Service 层:案件归属校验、case_id 强制过滤、外键级联删除。
- 提示词组装内聚于 PromptBuilder,避免污染通用渲染契约。
- 前端状态机内聚于 `useInsightStream`,避免与全局 chat store 冲突。
### 潜在循环依赖
从现有结构看,没有明显的循环导入:Controller → Service → Entity/Mapper/Factory/Prompt/Context,Factory 依赖 Catalog 和 StateStore,Catalog 依赖模板库 Mapper,彼此单向。
**章节来源**
- [InsightController.java:1-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L1-L127)
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
## 性能与可靠性特征
### 持久化策略
- Insight 会话与消息**持久化入库**,不复用 `agent_chat_session` / `agent_message`。
- 消息列表接口不返回 `tool_events` 与 `output_json`,避免大字段拖慢列表。
- 结构化产物 `output_json` 仅首轮 assistant 消息有值,前端也可从 SSE 的 `insight` 帧提前渲染。
- 单条 trace 按需拉取,避免每次打开对话都加载全部工具调用明细。
### 并发控制
- 会话级互斥闸门使用 `Semaphore`,因为抢占发生在订阅线程,释放发生在 Reactor 回调线程;`ReentrantLock` 跨线程 unlock 会抛异常。
- 多实例并发抢占靠数据库 `status` 字段:ACTIVE、STREAMING、ARCHIVED。
- 同一案件创建会话有进程内锁,防止重复创建。
### 排序与分页
- 消息排序列是 `seq`,不是 `id` 或 `create_at`。
- 前端第 1 页是最新 N 条,上滑加载更多更早消息。
- 分页追加时前端用消息 id 去重兜底,防止持续追加导致同一条出现在两页。
### Token 与迭代控制
- Insight Agent 最大迭代轮数刻意压到 6,因为它是“读一批数据 → 给出结论”的任务,不适合长链路探索。
- 图谱快照会被裁剪到 topN,避免一次性把过多节点和边塞进提示词。
**章节来源**
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [insight_agent_tables.sql:1-107](file://sql/insight_agent_tables.sql#L1-L107)
## 常见问题排查
### Insight 会话丢失
可能原因:
- 删除了 `agent_insight_session`,但消息随外键级联删除,因此消息也消失。
- 前端重新打开页面后没有正确传入 `sessionId`,导致新会话替代旧会话。
- 会话状态异常卡在 STREAMING,后续追问被拦截。
排查建议:
- 检查 `agent_insight_session.status` 是否为 ACTIVE 或 ARCHIVED。
- 确认前端 `useInsightStream` 的 `sessionId` 与 `caseId` 是否一致。
- 若怀疑内存实例残留,检查 `InsightAgentFactory` 实例池是否已 evict。
**章节来源**
- [insight_agent_tables.sql:65-107](file://sql/insight_agent_tables.sql#L65-L107)
- [InsightAgentFactory.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/agent/InsightAgentFactory.java#L1-L200)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
### 消息未落库
可能原因:
- SSE 流被网关或代理切断,前端收不到 token/done。
- 事务异常或数据库写入失败。
- 前端只渲染流式状态,但未等待 done 后再触发刷新历史消息。
排查建议:
- 检查后端日志中是否有 Agent 执行异常、工具调用异常。
- 检查 `agent_insight_message.content` 是否为空。
- 确认 SSE 事件协议是否包含 token、thinking、tool_call、tool_result、insight、done。
**章节来源**
- [api.ts:1-81](file://ai-electron/frontend/src/graph/insight/api.ts#L1-L81)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [InsightController.java:28-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L28-L127)
### 工作区跨节点不一致
可能原因:
- Agent 工作目录基于本地文件系统,多节点部署时每个节点有自己的 `.agentscope` 目录。
- Skills、记忆、子 Agent 状态如果依赖本地文件,跨节点无法共享。
- 真正需要共享的状态应放在 PostgreSQL:会话、消息、上下文快照、提示词。
排查建议:
- 若需要跨节点共享 Agent 状态,应迁移到分布式存储或使用统一文件服务器。
- 对于 Insight 主流程,优先依赖数据库持久化;本地文件只作运行期临时状态。
- 注意 `WorkspaceManagerFactory` 生成的路径是本地绝对路径,不是共享卷路径。
**章节来源**
- [WorkspaceManagerFactory.java:1-79](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java#L1-L79)
- [insight_agent_tables.sql:1-107](file://sql/insight_agent_tables.sql#L1-L107)
### SSE 流被网关切断
可能原因:
- 网关超时时间短于 Insight 流式输出时长。
- 网关未正确透传 `text/event-stream`。
- 前端网络重试策略不正确,导致断流后状态不一致。
排查建议:
- 调整网关 SSE 超时和缓冲大小。
- 检查响应头是否包含 `Content-Type: text/event-stream`。
- 前端应在 error 分支显示可重试提示,并保留当前会话状态。
**章节来源**
- [api.ts:1-81](file://ai-electron/frontend/src/graph/insight/api.ts#L1-L81)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [InsightController.java:56-68](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L56-L68)
## 操作示例
### 创建 Insight 会话
1. 前端准备 `InsightCreateParams`:包含 `caseId`、可选 `bizType`、`scope`、`filters`、`graph`、`topN`。
2. 调用 `createInsightSession`,即 POST `/insight/sessions`。
3. 后端校验案件归属、获取默认模型、构建上下文、拼装提示词、写入会话表。
4. 前端获得 `InsightSessionVO`,随后立即发起首轮流式分析。
参考实现位置:
- 前端 API:[api.ts:25-33](file://ai-electron/frontend/src/graph/insight/api.ts#L25-L33)
- 前端类型:[types.ts:59-86](file://ai-electron/frontend/src/graph/insight/types.ts#L59-L86)
- 后端控制器:[InsightController.java:38-48](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L38-L48)
- 后端服务:[InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
**章节来源**
- [api.ts:25-33](file://ai-electron/frontend/src/graph/insight/api.ts#L25-L33)
- [types.ts:59-86](file://ai-electron/frontend/src/graph/insight/types.ts#L59-L86)
- [InsightController.java:38-48](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L38-L48)
- [InsightServiceImpl.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/service/impl/InsightServiceImpl.java#L1-L200)
### 关联图谱或外部数据
Insight 的图谱关联方式是“快照”:
- 前端把画布中的节点和边序列化为 `InsightGraphSnapshot`,随创建会话请求发送。
- 后端 `InsightContextBuilder.trimGraph` 按度数裁剪,只保留 topN 节点及其两端都在的边。
- 外部数据通过 `WorkspaceSchemaCatalog` 暴露的模板库元数据间接影响 Agent:Agent 可通过 RAG 工具检索表结构,再写 SQL 查询。
参考实现位置:
- 前端快照类型:[types.ts:22-58](file://ai-electron/frontend/src/graph/insight/types.ts#L22-L58)
- 后端上下文裁剪:[InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
- 可查表目录:[WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
**章节来源**
- [types.ts:22-58](file://ai-electron/frontend/src/graph/insight/types.ts#L22-L58)
- [InsightContextBuilder.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/context/InsightContextBuilder.java#L1-L200)
- [WorkspaceSchemaCatalog.java:1-200](file://ai-server/src/main/java/com/zsjz/ai/module/agent/rag/WorkspaceSchemaCatalog.java#L1-L200)
### 查看 Insight 消息流
1. 创建会话成功后,前端调用 `streamInsight`,连接 `/insight/stream`。
2. 流式事件与通用聊天流同构,新增 `insight` 帧用于结构化产物。
3. 前端 `useInsightStream` 根据消息类型区分首轮分析与追问。
4. 列表消息通过分页接口加载,滚动向上加载更多。
参考实现位置:
- 前端流式入口:[api.ts:73-81](file://ai-electron/frontend/src/graph/insight/api.ts#L73-L81)
- 前端流式状态机:[useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- 后端流式接口:[InsightController.java:56-68](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L56-L68)
**章节来源**
- [api.ts:73-81](file://ai-electron/frontend/src/graph/insight/api.ts#L73-L81)
- [useInsightStream.ts:1-200](file://ai-electron/frontend/src/graph/insight/hooks/useInsightStream.ts#L1-L200)
- [InsightController.java:56-68](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L56-L68)
### 清理工作区
Insight 的“清理”有两种层次:
1. **清理 Insight 会话**:调用 DELETE `/insight/sessions/{id}/delete`,消息随外键级联删除。
2. **清理 Agent 工作目录**:`WorkspaceManagerFactory` 提供路径解析,但不直接提供删除方法;删除应由运维或上层生命周期管理,注意多节点部署下本地文件不一致风险。
参考实现位置:
- 前端删除接口:[api.ts:65-71](file://ai-electron/frontend/src/graph/insight/api.ts#L65-L71)
- 后端删除接口:[InsightController.java:118-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L118-L127)
- 外键级联:[insight_agent_tables.sql:90-107](file://sql/insight_agent_tables.sql#L90-L107)
- 工作目录解析:[WorkspaceManagerFactory.java:15-79](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java#L15-L79)
**章节来源**
- [api.ts:65-71](file://ai-electron/frontend/src/graph/insight/api.ts#L65-L71)
- [InsightController.java:118-127](file://ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java#L118-L127)
- [insight_agent_tables.sql:90-107](file://sql/insight_agent_tables.sql#L90-L107)
- [WorkspaceManagerFactory.java:15-79](file://ai-server/src/main/java/com/zsjz/ai/module/agent/WorkspaceManagerFactory.java#L15-L79)
## 结论
Insight 工作区的设计核心是“独立、安全、可追溯”:
- 独立:会话、消息、Agent 实例池、提示词装配都与通用对话解耦。
- 安全:`case_id` 冗余、外键级联、案件访问守卫、SQL 层越权防护。
- 可追溯:消息按 `seq` 稳定排序,trace 按需拉取,结构化产物持久化。
Workspace Catalog 负责告诉 Agent “有哪些模板表可以查”,Workspace 文件系统负责隔离 Agent 运行态文件;两者共同支撑 Insight 的外部数据能力,但不应与 Insight 自身的持久化数据混淆。普通 Agent 对话侧重通用交互,Insight 侧重图谱关系研判、结构化线索产出与 SSE 流式体验。