# 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 流式体验。