Fix widget i18n missing locale files and clean up unused locales

- widget/i18n/index.js: only import en.json and zh_CN.json (the only
  locale files present); remove 40+ imports for missing locale JSONs
  that caused Vite compile failure and global white screen
- dashboard/i18n/index.js: remove unused locale imports for consistency
- Remove 62 unused locale JSON files from widget/i18n/locale/
- Minor: update index.html, test helpers, e2e test, languages spec
This commit is contained in:
2026-07-08 09:57:00 +08:00
parent 9c74b83560
commit a1ae852eb2
67 changed files with 1019 additions and 8425 deletions
+632
View File
@@ -0,0 +1,632 @@
# GoChat AI 功能支持评估与开发路线图
> 调研日期:2026-07-08
> 基于代码库:main 分支 @ e61b2ac
> 对标项目:Chatwoot Captain AI (enterprise edition)
---
## 目录
1. [评估摘要](#1-评估摘要)
2. [当前 AI 基础设施盘点](#2-当前-ai-基础设施盘点)
3. [Chatwoot AI 功能对照表](#3-chatwoot-ai-功能对照表)
4. [关键缺口分析](#4-关键缺口分析)
5. [开发路线图](#5-开发路线图)
6. [风险评估与依赖](#6-风险评估与依赖)
7. [附录:关键文件索引](#7-附录关键文件索引)
---
## 1. 评估摘要
GoChat 已搭建了一套对标 Chatwoot Captain AI 的完整基础设施,覆盖了 LLM Provider 抽象层、
数据模型、Service 业务逻辑、Handler/路由、前端 UI 组件和后台 Worker。**约 90% 的 AI 代码
已经写好**,但存在若干"最后一公里"接缝未缝合的问题,导致部分功能无法实际运行。
核心结论:
- **可用功能**:Copilot 侧边栏对话、回复建议、会话摘要、改写润色、标签建议、跟进任务、
会话洞察、文档同步、批量 AI 操作、助手 CRUD/Playground、帮助中心文章 AI 翻译
- **代码就绪但未接入**:RAG 知识库问答(路由未注册)、自动回复规则(未接入消息流程)、
CaptainConversationService(被 `_ =` 忽略)
- **完全缺失**:帮助中心语义搜索、AgentBot + Captain 端到端 AI 客服、多 LLM Provider 支持
- **配置缺口**:config.yaml 无 captain 配置段,LLM API Key 未注入,AI 功能处于"空转"状态
整体评估:基础设施成熟度高(9/10),功能可用度中等(5/10),需补齐配置与接缝工作。
---
## 2. 当前 AI 基础设施盘点
### 2.1 LLM Provider 层
**文件**:`backend/internal/llm/provider.go` + `openai_provider.go`
- `Provider` 接口定义三个核心能力:
- `ChatCompletion` — 同步对话补全
- `CreateEmbedding` — 文本向量化
- `ChatCompletionStream` — SSE 流式对话补全(callback 模式)
- `OpenAIProvider` 实现完整:
- 支持自定义 `baseURL`(兼容国内厂商如火山引擎/豆包/通义千问)
- SSE 流式解析(自研 `sseReader` + `sseLineScanner`,处理 `[DONE]` 信号)
- 指数退避重试(1s→2s→4s,最多 3 次,429/5xx 可重试)
- API 错误结构化解析(`APIError` 类型)
- 数据结构:`ChatRequest`/`ChatResponse`/`ChatMessage`/`EmbeddingRequest`/`EmbeddingResponse`/
`StreamChunk`/`ToolDefinition`/`ToolFunction`
- **问题**:`ToolDefinition` 已定义但从未在调用时传入 LLM
### 2.2 数据模型层
**文件**:`backend/internal/model/captain_models.go` + `copilot_models.go` + `auto_reply_rule_models.go` + `article_embedding.go`
| 模型 | 表名 | 说明 |
|------|------|------|
| `CaptainAssistant` | `captain_assistants` | AI 助手核心实体(config/guardrails/response_guidelines JSONB) |
| `CaptainDocument` | `captain_documents` | 知识库文档(网页/PDF,含 content_fingerprint 去重) |
| `CaptainAssistantResponse` | `captain_assistant_responses` | FAQ 条目,带 pgvector 1536 维 embedding |
| `CaptainScenario` | `captain_scenarios` | 多场景 agent 配置(instruction + tools JSONB) |
| `CaptainCustomTool` | `captain_custom_tools` | 自定义 HTTP 工具(endpoint/auth/param_schema/request_template) |
| `CaptainInbox` | `captain_inboxes` | 助手↔收件箱绑定 |
| `CaptainPreference` | `captain_preferences` | 账户级 AI 偏好(tone/language/auto_label/auto_reply 等) |
| `CaptainAutoReplyRule` | `captain_auto_reply_rules` | 自动回复规则(static/llm/mixed 三模式) |
| `CopilotThread` | `copilot_threads` | Copilot 对话线程(account_id + user_id + assistant_id) |
| `CopilotMessage` | `copilot_messages` | 线程消息(JSONB content,支持 thinking/tool_result) |
| `CopilotSuggestionMessage` | `copilot_suggestion_messages` | 会话级建议(reply/suggestion/summary,pending/accepted/rejected) |
| `ArticleEmbedding` | `article_embeddings` | 帮助中心文章向量嵌入(JSONB 存储向量) |
- `CopilotThread.PreviousHistory()` 方法将消息历史转为 LLM `[]ChatMessage` 格式
- `CopilotMessage.BeforeSave()` 验证 JSONB key 白名单(content/reasoning/function_name/reply_suggestion)
### 2.3 Service 层
| Service | 文件 | 职责 | LLM 依赖 |
|---------|------|------|----------|
| `CaptainAssistantService` | `captain_assistant_service.go` | 助手 CRUD + Playground 对话 + `GenerateResponse` RAG 问答 | ✅ |
| `CaptainTaskService` | `captain_task_service.go` | 回复建议 / 摘要 / 改写(含 Stream 版本) | ✅ |
| `CaptainTaskExtendedService` | `captain_task_extended_service.go` | 批量标签建议 + 跟进任务 | ✅ |
| `CopilotService` | `copilot_service.go` | Copilot 线程管理 + 异步响应生成 | ✅ |
| `CopilotContextService` | `copilot_context_service.go` | 会话上下文组装(消息/联系人/历史) | ✅ |
| `RAGService` | `rag_service.go` | RAG 全流程:embedding→pgvector 搜索→LLM 生成 | ✅ |
| `ConversationInsightService` | `conversation_insight_service.go` | 参与者分析 / 行动项 / 标签建议 | ✅ |
| `CaptainConversationService` | `captain_conversation_service.go` | 会话级 AI 自动响应(handoff 模式) | ✅ |
| `CaptainDocumentService` | `captain_document_service.go` | 文档爬取/同步/embedding 生成 | ✅ |
| `CaptainBulkActionService` | `captain_bulk_action_service.go` | 批量 AI 操作 | ✅ |
| `CaptainAssistantResponseService` | `captain_assistant_response_service.go` | FAQ 生成与处理 | ✅ |
| `SystemPromptBuilder` | `system_prompt_builder.go` | 统一 prompt 构建 | — |
| `LLMArticleTranslationBackend` | `article_service.go` | 帮助中心文章 AI 翻译 | ✅ |
### 2.4 Handler + 路由层
**已注册路由**(`/api/v1/accounts/:account_id/captain/`):
```
# Assistant CRUD + 关联
assistants GET/POST/PUT/DELETE
assistants/:id/inboxes GET/POST/DELETE
assistants/:id/playground POST
assistants/:id/documents POST/GET/DELETE
assistants/:id/scenarios POST/GET/PUT/DELETE
# Document / Scenario / CustomTool
documents GET/POST/DELETE + /:id/sync
scenarios GET/POST/PUT/DELETE
custom_tools GET/POST/PUT/DELETE
# Copilot
copilot_threads GET/POST/GET/:id/DELETE/:id
copilot_threads/:id/copilot_messages GET/POST
copilot_threads/:id/messages POST
copilot_messages GET/POST
copilot/suggest_replies POST
copilot/summarize POST
copilot/translate POST
copilot/stream GET (SSE)
# Tasks (AI 任务)
tasks/reply_suggestion POST (+ /stream SSE)
tasks/summarize POST (+ /stream SSE)
tasks/rewrite POST (+ /stream SSE)
tasks/label_suggestion GET
tasks/follow_up GET
# Insight
conversation_insights/:id/analyze_participants POST
conversation_insights/:id/extract_action_items POST
conversation_insights/:id/suggest_labels POST
# Preference / Response / Bulk
preferences GET/PUT
assistant_responses CRUD + /process
bulk_actions POST
```
### 2.5 前端层
| 组件/文件 | 路径 | 说明 |
|-----------|------|------|
| Captain 设置页 | `routes/dashboard/settings/captain/Index.vue` | 模型选择 + 功能开关(label_suggestion/help_center_search/audio_transcription) |
| ModelSelector | `routes/dashboard/settings/captain/components/ModelSelector.vue` | 按 feature 选择 LLM 模型 |
| FeatureToggle | `routes/dashboard/settings/captain/components/FeatureToggle.vue` | AI 功能开关 |
| CopilotContainer | `components/copilot/CopilotContainer.vue` | 侧边栏 Copilot 聊天面板 |
| Copilot (next) | `components-next/copilot/Copilot.vue` | 新版 Copilot 组件 |
| useCaptain | `composables/useCaptain.js` | Captain 功能开关/配额/错误处理 |
| useCopilotReply | `composables/useCopilotReply.js` | 回复建议/改写/摘要的 composable |
| useLabelSuggestions | `composables/useLabelSuggestions.js` | 标签建议 |
| API 客户端 | `api/captain/` | 12 个文件:assistant/document/tasks/copilotThreads/copilotMessages/preferences/scenarios/tools/bulkActions/inboxes/customTools/response |
**Feature Flags**(`featureFlags.js`):
- `CAPTAIN` = `captain_integration`
- `CAPTAIN_V2` = `captain_integration_v2`
- `CAPTAIN_TASKS` = `captain_tasks`
- `CAPTAIN_CUSTOM_TOOLS` = `custom_tools`
- `CAPTAIN_DOCUMENT_AUTO_SYNC` = `captain_document_auto_sync`
### 2.6 后台 Worker
| Worker | 文件 | 任务类型 | 说明 |
|--------|------|----------|------|
| CaptainDocumentWorker | `captain_document_worker.go` | 6 种任务 | 文档同步/爬取/页面解析/embedding 更新/调度 |
| CopilotResponseWorker | `copilot_response_worker.go` | 1 种任务 | 异步 Copilot 响应生成 |
| CaptainConversationWorker | `captain_conversation_service.go` 内 | 1 种任务 | 会话响应构建(但 service 被 `_ =` 忽略) |
### 2.7 配置层
**文件**:`backend/internal/config/config.go`
`CaptainConfig` 结构体已定义:
```go
type CaptainConfig struct {
Enabled bool
LLMProvider string // openai, azure, custom
LLMModel string // gpt-4o, gpt-3.5-turbo
LLMAPIKey string
LLMBaseURL string // 自定义端点
EmbeddingModel string // text-embedding-3-small
EmbeddingDims int // 1536
MaxTokens int
Temperature float64
}
```
- `LLMConfig()` 方法将 `CaptainConfig` 转为 provider 友好格式
- 支持热重载(`config.go` reloader 中包含 captain 字段)
- ENV 映射:`GOCHAT_CAPTAIN_ENABLED` / `GOCHAT_CAPTAIN_LLM_PROVIDER` / `GOCHAT_CAPTAIN_LLM_MODEL` /
`GOCHAT_CAPTAIN_LLM_API_KEY` / `GOCHAT_CAPTAIN_LLM_BASE_URL` 等
**问题**:`backend/configs/config.yaml` 中**没有 captain 配置段**,所有 Captain 字段为默认零值。
bootstrap.go:536 创建 OpenAIProvider 时传入空 API Key 和空 BaseURL。
---
## 3. Chatwoot AI 功能对照表
| Chatwoot Captain 功能 | GoChat 状态 | 说明 |
|------------------------|-------------|------|
| Captain Assistant(AI 助手配置) | ✅ 完整 | 模型/服务/handler/路由/前端全链路 |
| Copilot(客服侧边栏 AI 助手) | ✅ 完整 | 含 SSE 流式 + 异步 Worker |
| Reply Suggestion(回复建议) | ✅ 完整 | 含流式 + RAG 上下文 |
| Summarize(会话摘要) | ✅ 完整 | 含流式 |
| Rewrite(改写润色) | ✅ 完整 | 含流式,7 种操作 |
| Label Suggestion(标签建议) | ✅ 完整 | 单会话 + 批量 |
| Follow-up Task(跟进任务) | ✅ 完整 | 批量 |
| Knowledge Base / RAG(知识库问答) | ⚠️ 代码完整,路由未注册 | RAGService + RAGHandler 存在但未接入 |
| Document Sync(文档爬取同步) | ✅ 完整 | 6 种 Worker 任务 |
| Custom Tools(Function Calling 定义) | ✅ 模型+服务完整 | 但 LLM 调用时未传 tools 参数 |
| Captain Preferences(AI 偏好) | ✅ 完整 | tone/language/auto_label/auto_reply |
| Auto-Reply Rules(自动回复规则) | ⚠️ 模型完整,未接入 | 模型+基础 service,无路由,无消息钩子 |
| Conversation Insight(会话洞察) | ✅ 完整 | 参与者分析/行动项/标签 |
| Bulk Actions(批量 AI 操作) | ✅ 完整 | |
| Help Center 语义搜索 | ❌ 缺失 | ArticleEmbedding 表存在但无搜索方法 |
| AgentBot + Captain(端到端 AI 客服) | ❌ 缺失 | AgentBot 仅支持 webhook 类型 |
| Captain Conversation Auto-Response | ⚠️ 代码存在,被忽略 | bootstrap.go:594 `_ = captainConversationService` |
| Article AI 翻译 | ✅ 完整 | LLMArticleTranslationBackend |
| Multi-Provider LLM | ❌ 仅 OpenAI | 无 Anthropic/国内模型 provider 实现 |
| Token 用量统计与配额 | ❌ 缺失 | 前端有 captainLimits 结构,后端无统计 |
| AI 审计日志 | ❌ 缺失 | |
---
## 4. 关键缺口分析
### 缺口 G1:config.yaml 缺少 captain 配置段
- **影响**:所有 AI 功能无法实际调用 LLM(API Key 为空)
- **位置**:`backend/configs/config.yaml` 缺少 captain 段;`bootstrap.go:536` 传入空值
- **修复成本**:极低(加几行 YAML + .env 注入)
### 缺口 G2:RAG 路由未注册
- **影响**:知识库问答 API 无法访问
- **位置**:`RAGHandler` 代码完整(`rag_handler.go`),但 `bootstrap.go` 未实例化
`RAGService`/`RAGHandler`,`router.go` 未注册 `/captain/rag/*` 路由
- **修复成本**:低(~20 行 bootstrap + router 代码)
### 缺口 G3:AutoReplyRule 未接入
- **影响**:无法实现"消息进来 → AI 自动回复"
- **位置**:`auto_reply_rule_models.go` 模型完整(static/llm/mixed),但:
- 无完整的条件匹配引擎
- 无消息接收时的规则匹配钩子
- 无路由注册
- **修复成本**:中(需实现条件匹配 + 消息流程集成)
### 缺口 G4:CaptainConversationService 被忽略
- **影响**:会话级 AI 自动响应(handoff 模式)不可用
- **位置**:`bootstrap.go:594` `_ = captainConversationService`
- **修复成本**:中(需接入消息接收流程 + handoff 逻辑)
### 缺口 G5:AgentBot 仅支持 Webhook
- **影响**:无法实现"AgentBot 绑定 Captain Assistant → 端到端 AI 客服"
- **位置**:`agent_bot.go` 只有 webhook 推送模式
- **修复成本**:中高(需扩展 AgentBot 类型 + 消息路由)
### 缺口 G6:Help Center 语义搜索缺失
- **影响**:帮助中心文章无法语义搜索
- **位置**:`ArticleEmbedding` 表存在,`article_service.go` 无搜索方法
- **修复成本**:中(需实现 embedding 生成 + pgvector 搜索 + API + 前端)
### 缺口 G7:Function Calling 未实际使用
- **影响**:CustomTool 定义了但 LLM 调用时未传 tools 参数,AI 无法调用工具
- **位置**:`llm/provider.go` 的 `ToolDefinition` 已定义;
`captain_task_service.go` / `captain_conversation_service.go` 的 `ChatRequest` 未设置 `Tools` 字段
- **修复成本**:中(需实现 tool_call 循环 + HTTP 执行 + 结果回传)
### 缺口 G8:多 LLM Provider 支持
- **影响**:仅支持 OpenAI 兼容 API,无法直接使用 Anthropic/本地模型
- **位置**:`llm/` 下只有 `openai_provider.go`
- **修复成本**:中(每个 provider ~200 行实现 + 接口适配)
---
## 5. 开发路线图
### 阶段 1:激活现有 AI 功能(P0,1-2 天)
**目标**:让已写好的 90% 代码真正跑起来,实现"配置即可用"。
**前提**:需要一个可用的 LLM API Key(OpenAI 或兼容端点)。
#### 任务 1.1:config.yaml 添加 captain 配置段
**文件**:`backend/configs/config.yaml`
```yaml
captain:
enabled: true
llm_provider: "openai" # openai, azure, custom
llm_model: "gpt-4o-mini" # 可按需改为 gpt-4o / gpt-3.5-turbo
llm_api_key: "" # 通过 .env: GOCHAT_CAPTAIN_LLM_API_KEY 注入
llm_base_url: "https://api.openai.com/v1" # 国内可改为火山引擎/豆芽等端点
embedding_model: "text-embedding-3-small"
embedding_dims: 1536
max_tokens: 1024
temperature: 0.7
```
同时更新 `config.dev.yaml` 和 `config.prod.yaml` 的 captain 段(如有)。
**验收**:`go run cmd/gochat/main.go serve` 启动后,日志输出 LLM provider 初始化成功。
#### 任务 1.2:注册 RAG 路由
**文件修改**:
1. `backend/internal/app/bootstrap.go`:
- 实例化 `RAGService`(注入 `captainAssistantResponseRepo` + `captainAssistantRepo` + `llmProvider`)
- 实例化 `RAGHandler`(注入 `RAGService`)
- 添加到 `Handlers` 结构体
2. `backend/internal/router/router.go`:
```go
// RAG Knowledge Base Q&A
rag := captain.Group("/rag")
{
rag.POST("/query", h.RAG.Query)
rag.POST("/index/:response_id", h.RAG.IndexResponse)
}
```
**验收**:`curl -X POST /api/v1/accounts/1/captain/rag/query -d '{"assistant_id":1,"question":"test"}'`
返回非 404。
#### 任务 1.3:取消 CaptainConversationService 忽略
**文件**:`backend/internal/app/bootstrap.go:594`
将 `_ = captainConversationService` 改为注入到 Handlers 或消息处理流程。
最小改动:将其传入 `CaptainAssistantHandler` 或新建一个 handler 方法,
供后续阶段 2 的 AgentBot 集成使用。
**验收**:编译通过,`captainConversationService` 不再被忽略。
#### 任务 1.4:端到端验证
配置真实 LLM API Key 后测试:
1. Playground 对话:`POST /captain/assistants/:id/playground`
2. 回复建议:`POST /captain/tasks/reply_suggestion`
3. RAG 问答:`POST /captain/rag/query`
4. Copilot 流式:`GET /captain/copilot/stream`
5. 前端 Copilot 面板对话
**交付物**:AI 功能在开发环境完整可用。
---
### 阶段 2:自动回复与端到端 AI 客服(P1,3-5 天)
**目标**:实现"客户消息进来 → AI 自动响应"的闭环。
#### 任务 2.1:AutoReplyRule 完整接入
**子任务**:
1. **条件匹配引擎**(`auto_reply_rule_service.go`):
- 实现 `MatchRules(ctx, accountID, conversationID, messageContent) ([]CaptainAutoReplyRule, error)`
- 支持 condition 字段:`message_content`(contains/regex/equals)、`sender_type`、
`conversation_status`、`language`、`keywords`
- 按 priority 排序,返回第一个匹配的规则
2. **消息钩子集成**:
- 在消息接收流程(`channel/incoming.go` 或 `message_service.go`)中,
消息入库后调用 `AutoReplyRuleService.MatchRules`
- 匹配到规则时:
- `static` 模式:直接发送 `ResponseText`
- `llm` 模式:调用 `CaptainAssistantService.GenerateResponse` 生成回复
- `mixed` 模式:static 前缀 + LLM 正文
- 尊重 `DelaySeconds` 和 `OneTimeOnly` 配置
- 通过 WorkerPool 异步执行(避免阻塞消息接收)
3. **路由注册**:
```go
autoReplyRules := captain.Group("/auto_reply_rules")
{
autoReplyRules.GET("", h.AutoReplyRule.List)
autoReplyRules.POST("", h.AutoReplyRule.Create)
autoReplyRules.GET("/:rule_id", h.AutoReplyRule.Get)
autoReplyRules.PUT("/:rule_id", h.AutoReplyRule.Update)
autoReplyRules.DELETE("/:rule_id", h.AutoReplyRule.Delete)
}
```
4. **前端**:
- 复用 Chatwoot 前端 auto-reply 设置页(如已 vendored)
- 新增 API 客户端 `api/captain/autoReplyRules.js`
**验收**:创建一条 llm 模式规则 → 发送匹配消息 → AI 自动回复。
#### 任务 2.2:AgentBot + Captain 集成
**子任务**:
1. **扩展 AgentBot 模型**(`agent_bot.go`):
- 新增 `BotType` 字段:`webhook`(现有) / `captain`(新增)
- `captain` 类型时关联 `AssistantID`
2. **消息路由**:
- 在消息分配逻辑中,当 inbox 的 AgentBot 类型为 `captain` 时,
消息直接路由到 `CaptainConversationService.BuildConversationResponseByAccount`
- AI 生成的回复作为 `agent_bot` 消息发送到会话
3. **Handoff 逻辑**:
- `CaptainConversationResponse.Action == "handoff"` 时,将会话转给人工客服
- 更新会话 status + assignee
4. **前端**:
- AgentBot 管理页支持选择 `captain` 类型 + 关联 Assistant
**验收**:配置一个 captain 类型 AgentBot → 客户发消息 → AI 自动回复 → AI 判断需转人工时 handoff。
#### 任务 2.3:CaptainConversationService 完整接入
**子任务**:
1. **工具调用实现**:
- 将 `CaptainCustomTool` 列表转为 `llm.ToolDefinition` 传入 `ChatRequest.Tools`
- 解析 LLM 返回的 `tool_call` → 执行 HTTP 请求(按 CustomTool 的 endpoint/auth/template)
- 将 tool 结果回传 LLM → 继续生成
2. **可用工具**(`AvailableTools` 已定义 7 个):
- `add_contact_note` / `add_private_note` / `update_priority`
- `add_label_to_conversation` / `faq_lookup` / `resolve_conversation` / `handoff`
- 实现每个工具的执行函数
**验收**:AI 能在对话中调用自定义工具(如查询订单、添加标签)。
---
### 阶段 3:增强 AI 能力深度(P2,1-2 周)
#### 任务 3.1:Help Center 语义搜索
**子任务**:
1. `article_service.go` 添加 `SearchByEmbedding(ctx, query, limit)` 方法
- 调用 `llmProvider.CreateEmbedding` 生成查询向量
- pgvector 余弦相似度搜索 `ArticleEmbedding` 表
2. 文章创建/更新时自动生成 embedding(通过 Worker 异步)
3. API:`GET /api/v1/portals/:portal_id/articles/search?q=...`
4. 前端帮助中心搜索框接入
**验收**:搜索"如何重置密码"能找到相关文章(即使标题不含"重置")。
#### 任务 3.2:Function Calling 完整实现
详见阶段 2 任务 2.3 的工具调用实现。此阶段将其推广到所有 AI 服务:
- `CopilotService` — Copilot 对话中可调用工具
- `CaptainTaskService` — 回复建议时可调用 FAQ 查询工具
- `CaptainAssistantService.GenerateResponse` — Playground 对话中可调用工具
#### 任务 3.3:多 LLM Provider 支持
**子任务**:
1. `llm/anthropic_provider.go` — Claude 系列(不同 API 格式,需适配)
2. `llm/volcengine_provider.go` — 火山引擎/豆包(OpenAI 兼容,可能只需 baseURL 配置)
3. `llm/qwen_provider.go` — 通义千问(OpenAI 兼容)
4. Provider 工厂函数:根据 `config.captain.llm_provider` 选择实现
5. 前端 `ModelSelector` 已有 UI,后端按 feature(editor/assistant/copilot)支持不同模型
**验收**:配置 `llm_provider: "anthropic"` 后,AI 功能使用 Claude 模型。
#### 任务 3.4:上下文窗口优化
**子任务**:
1. `CopilotContextService` 实现 token 计数(tiktoken Go 库或近似估算)
2. 滑动窗口截断:超过 token 上限时,截断早期消息
3. 长会话自动摘要:超过阈值时,用 LLM 摘要历史消息作为 system 上下文
4. 配置项:`captain.max_context_tokens`(默认 4096)
**验收**:100+ 条消息的长会话不会超出 token 限制,AI 仍能理解上下文。
---
### 阶段 4:企业级能力(P3,2-4 周,按需)
#### 任务 4.1:AI 用量统计与配额
- 按 account/user 统计 token 消耗(prompt_tokens + completion_tokens)
- 存储到 `captain_usage_logs` 表
- 配额限制:前端 `captainLimits` 结构已存在,后端实现拦截逻辑
- 用量仪表盘:`GET /captain/usage` 返回统计数据
- 前端设置页展示用量进度条
#### 任务 4.2:AI 响应质量管控
- `CopilotSuggestionMessage` 的 `accepted`/`rejected` 状态反馈循环
- 基于反馈优化 prompt(few-shot 示例注入:被接受的回复作为正例)
- A/B 测试框架:同一请求发到两个模型/prompt 配置,比较接受率
- 质量指标:接受率、拒绝率、编辑率(用户发送前修改了多少)
#### 任务 4.3:多语言 AI
- `CaptainPreference.Language` 传入 LLM system prompt
- 回复建议/摘要/改写尊重目标语言
- Help Center 文章跨语言语义搜索(embedding 包含语言信息)
- Auto-Reply Rule 的 `language` 条件匹配
#### 任务 4.4:AI 审计日志
- 记录每次 AI 调用:prompt / response / model / token 消耗 / user / timestamp / feature
- 存储到 `captain_audit_logs` 表
- API:`GET /captain/audit_logs`(管理员可见)
- 合规审计支持:导出 CSV / 按时间范围筛选
---
## 6. 风险评估与依赖
### 6.1 技术风险
| 风险 | 影响 | 缓解措施 |
|------|------|----------|
| LLM API 调用超时/失败 | AI 功能不可用 | 已有重试机制(3 次指数退避);需加 fallback 策略(降级到静态回复) |
| pgvector 维度不匹配 | RAG 搜索失败 | 当前固定 1536 维(text-embedding-3-small);更换 embedding 模型时需迁移 |
| Token 消耗成本 | 生产环境费用 | 阶段 4 实现配额限制;阶段 1-3 开发环境用 gpt-4o-mini 控制成本 |
| SSE 连接稳定性 | 流式响应中断 | 已有 `X-Accel-Buffering: no`;需加心跳机制和断线重连 |
| 并发 LLM 调用 | 速率限制 | 需实现请求队列 + 限流(令牌桶) |
### 6.2 外部依赖
| 依赖 | 用途 | 状态 |
|------|------|------|
| LLM API(OpenAI/兼容) | Chat + Embedding | 需配置 API Key |
| pgvector 扩展 | 向量搜索 | ✅ 已安装(PG 17 + pgvector) |
| 帮助中心爬取 | 文档同步 | 需 HTTP 客户端(已有 resty) |
### 6.3 前端依赖
前端代码来自 Chatwoot Vue 3 vendored,AI 相关 UI 组件已存在(CopilotContainer、Captain 设置页、
ModelSelector、FeatureToggle)。阶段 1-2 的前端改动极小,主要是确保 API 端点与前端调用路径一致。
---
## 7. 附录:关键文件索引
### 后端
| 文件 | 说明 |
|------|------|
| `backend/internal/llm/provider.go` | LLM Provider 接口 + 数据结构 |
| `backend/internal/llm/openai_provider.go` | OpenAI 兼容 Provider 实现 |
| `backend/internal/model/captain_models.go` | Captain 全部数据模型 |
| `backend/internal/model/copilot_models.go` | Copilot 线程/消息/建议模型 |
| `backend/internal/model/auto_reply_rule_models.go` | 自动回复规则模型 |
| `backend/internal/model/article_embedding.go` | 帮助中心文章 embedding |
| `backend/internal/config/config.go` | CaptainConfig 配置结构 |
| `backend/internal/app/bootstrap.go` | 依赖注入(LLM Provider + Captain Services) |
| `backend/internal/router/router.go` | 路由注册(captain 命名空间 ~L1319-1489) |
| `backend/internal/service/captain_assistant_service.go` | 助手 CRUD + Playground + RAG |
| `backend/internal/service/captain_task_service.go` | 回复建议/摘要/改写(含 Stream) |
| `backend/internal/service/captain_task_extended_service.go` | 批量标签/跟进 |
| `backend/internal/service/copilot_service.go` | Copilot 线程管理 |
| `backend/internal/service/copilot_context_service.go` | 会话上下文组装 |
| `backend/internal/service/rag_service.go` | RAG 全流程 |
| `backend/internal/service/conversation_insight_service.go` | 会话洞察 |
| `backend/internal/service/captain_conversation_service.go` | 会话级 AI 响应(被忽略) |
| `backend/internal/service/captain_document_service.go` | 文档同步 |
| `backend/internal/service/captain_document_worker.go` | 文档 Worker |
| `backend/internal/service/copilot_response_worker.go` | Copilot 响应 Worker |
| `backend/internal/service/system_prompt_builder.go` | Prompt 构建 |
| `backend/internal/handler/api/v1/rag_handler.go` | RAG Handler(未接入) |
| `backend/internal/handler/api/v1/sse_stream_handler.go` | SSE 流式 Handler |
| `backend/internal/handler/api/v1/captain_assistant_handler.go` | 助手 Handler |
| `backend/internal/handler/api/v1/captain_task_handler_test.go` | 任务 Handler 测试 |
| `backend/internal/handler/api/v1/auto_reply_rule_handler.go` | 自动回复规则 Handler |
### 前端
| 文件 | 说明 |
|------|------|
| `frontend/app/javascript/dashboard/routes/dashboard/settings/captain/Index.vue` | Captain 设置页 |
| `frontend/app/javascript/dashboard/routes/dashboard/settings/captain/components/ModelDropdown.vue` | 模型下拉选择 |
| `frontend/app/javascript/dashboard/components/copilot/CopilotContainer.vue` | Copilot 侧边栏 |
| `frontend/app/javascript/dashboard/components-next/copilot/Copilot.vue` | 新版 Copilot 组件 |
| `frontend/app/javascript/dashboard/composables/useCaptain.js` | Captain composable |
| `frontend/app/javascript/dashboard/composables/useCopilotReply.js` | 回复建议 composable |
| `frontend/app/javascript/dashboard/composables/useLabelSuggestions.js` | 标签建议 composable |
| `frontend/app/javascript/dashboard/api/captain/*.js` | 12 个 API 客户端 |
| `frontend/app/javascript/dashboard/featureFlags.js` | Feature flags 定义 |
### 配置
| 文件 | 说明 |
|------|------|
| `backend/configs/config.yaml` | 基础配置(**缺少 captain 段**) |
| `backend/internal/config/config.go` | CaptainConfig 结构体 + ENV 映射 |
### 文档
| 文件 | 说明 |
|------|------|
| `docs/comparison/M10-captain-chatwoot-vs-gochat.md` | Chatwoot vs GoChat 模型级对比 |
| `docs/PRD.md` | 产品需求文档 |
---
## 路线图时间线总览
```
阶段 1 (P0, 1-2天) 阶段 2 (P1, 3-5天) 阶段 3 (P2, 1-2周) 阶段 4 (P3, 2-4周)
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 1.1 config.yaml │ │ 2.1 AutoReply │ │ 3.1 HC 语义搜索 │ │ 4.1 用量统计 │
│ captain 段 │ │ 规则接入 │ │ 3.2 Function │ │ 4.2 质量管控 │
│ 1.2 RAG 路由 │ │ 2.2 AgentBot + │ │ Calling 推广│ │ 4.3 多语言 AI │
│ 1.3 取消忽略 │ │ Captain 集成 │ │ 3.3 多 Provider │ │ 4.4 审计日志 │
│ 1.4 端到端验证 │ │ 2.3 工具调用实现 │ │ 3.4 上下文优化 │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
▲ 激活现有功能 ▲ 自动回复闭环 ▲ 智能化增强 ▲ 企业级能力
│ │ │ │
└── 最高优先级 ───────┴── 核心价值 ──────────┴── 渐进增强 ───────────┴── 按需实现
```
---
*文档结束。如需开始执行阶段 1 的修改,请告知。*
+146
View File
@@ -0,0 +1,146 @@
# GoChat 问题修改计划清单
- **基于**: test-report-2026-07-08.md
- **创建日期**: 2026-07-08
- **状态说明**: [ ] 待办 [~] 进行中 [x] 已完成
---
## ISS-03: widget/i18n 缺失 locale 文件导致全局白屏 [P0]
- **状态**: [x] 已临时修复
- **目标**: 恢复全局页面可用性
### 已完成
- [x] 将 `widget/i18n/index.js` 改为只导入存在的 `en.json` 和 `zh_CN.json`
- [x] 验证 Campaigns / Dashboard 等页面恢复正常加载
### 后续可选优化
- [ ] 补充缺失的 38 个 locale JSON 文件 (从 Chatwoot 上游拉取或按需创建)
- [ ] 或改为动态 import 按需加载 locale, 避免 bundle 过大
- [ ] 检查 `widget/i18n/locale/` 目录为何缺失文件 (是否 decoupling 时遗漏)
---
## ISS-01: Reports 图表永久卡在 "Loading chart data..." [P0]
- **状态**: [ ] 待办
- **目标**: 修复 reporting_events_rollups 表结构与 GORM 模型不匹配, 使 timeseries 报表 API 正常返回
- **阻断**: 需要确认修复方向 (改迁移 vs 改模型)
### Step 1: 确认修复方向
- [ ] 对比 Chatwoot 上游 `reporting_events_rollups` 表结构, 确认正确列名
- [ ] 确认 GORM 模型 (`reporting_event.go:68-78`) 与迁移 SQL (`000001_init_schema.up.sql:337-353`) 哪个是期望结构
- [ ] 检查 `analytics_query_helpers.go` 和 `rollups` service 中所有引用该表的查询, 确认期望的列名
### Step 2: 编写迁移文件
- [ ] 新建迁移文件 `NNNNN_fix_reporting_events_rollups.{up,down}.sql`
- [ ] up: ALTER TABLE 调整列名/类型使其与 GORM 模型一致
- 期望列: `date (date)`, `dimension_type (varchar)`, `dimension_id (int)`, `metric (varchar)`, `count (bigint)`, `sum_value (float)`, `sum_value_business_hours (float)`
- 删除旧列: `dimension`, `dimension_value`, `metric_name`, `value`, `value_in_business_hours`, `period`
- 调整唯一索引: `UNIQUE(account_id, date, dimension_type, dimension_id, metric)`
- [ ] down: 回滚操作
- [ ] 迁移文件命名需遵循 `backend/migrations/` 的 sequential 编号规则
### Step 3: 修改代码 (如选择改模型)
- [ ] 若决定改 GORM 模型适配现有表, 则修改 `reporting_event.go:68-78` 的字段映射
- [ ] 同步修改 `analytics_query_helpers.go` 中所有查询条件 (`.Where("date = ?")` 等)
- [ ] 修改 `rollups` service 中 `ComputeDailyRollup` 等方法的写入逻辑
### Step 4: 验证
- [ ] 运行迁移: `cd backend && go run cmd/migrate/main.go up`
- [ ] 重启后端
- [ ] curl 测试: `GET /api/v2/accounts/1/reports` 返回 200
- [ ] 浏览器验证: Reports > Conversations 页面图表正常加载, 不再卡在 "Loading chart data..."
- [ ] 控制台无 JS 异常
---
## ISS-02: Settings > General 页面白屏 [P0]
- **状态**: [ ] 待办
- **目标**: AccountId / BuildInfo 组件添加空值保护, 确保页面正常渲染
### Step 1: 修复 AccountId.vue
- [ ] `AccountId.vue:11` 添加可选链和空值回退:
```js
const getAccountId = computed(() => currentAccount.value?.id?.toString() ?? '');
```
- [ ] 验证模板中 `<woot-code :script="getAccountId" />` 在空字符串时正常渲染
### Step 2: 排查 BuildInfo 组件
- [ ] 定位 BuildInfo 组件文件 (在 `settings/account/Index.vue` 中引用)
- [ ] 检查 BuildInfo 依赖的数据源, 添加空值保护
- [ ] 确认 BuildInfo 渲染失败是否与 `currentAccount` 相关
### Step 3: 排查 SidebarGroup mounted hook 错误 (关联 ISS-04)
- [ ] 检查 `components-next/sidebar/Sidebar.vue` 中 SidebarGroup 的 mounted hook
- [ ] 确认是否依赖某个在路由切换时未初始化的 store getter 或 feature flag
- [ ] 添加保护或确保数据在 mounted 前已加载
### Step 4: 根因排查 (账户数据未加载)
- [ ] 确认 `accounts/getAccount` getter 为何返回空对象 — 检查 account 记录是否在 store `records` 中
- [ ] 追踪登录后 account 数据的加载流程: `auth.js` → `accounts/fetch` action → `records` 填充
- [ ] 确认是否存在时序问题: 组件渲染时 account 数据尚未异步加载完成
- [ ] 考虑在路由守卫中确保 account 数据加载完成后再进入 Settings 页面
### Step 5: 验证
- [ ] 浏览器访问 `/app/accounts/1/settings/general`, 页面正常渲染
- [ ] Account ID 区域显示正确的 ID 数字
- [ ] 控制台无渲染异常
- [ ] 其他 Settings 子页面不受影响
---
## ISS-04: 每次页面导航产生 29 个 JS 异常 (SidebarGroup) [P2]
- **状态**: [ ] 待办 (与 ISS-02 Step 3 关联)
- **目标**: 消除 SidebarGroup mounted hook 的异常噪音
### Step 1: 定位异常
- [ ] 在 SidebarGroup 组件的 mounted hook 中添加 try-catch 或排查依赖
- [ ] 确认异常是否来自某个 store getter 返回 undefined 或 feature flag 未初始化
- [ ] 使用 `browser_console` 抓取完整异常堆栈 (当前 message 为空, 需要更详细的捕获)
### Step 2: 修复
- [ ] 添加空值保护或确保依赖数据在 mounted 前已加载
- [ ] 或在组件中添加 v-if 守卫, 数据就绪后再渲染 SidebarGroup
### Step 3: 验证
- [ ] 导航至任意 Settings 子页面, `browser_console` 报 0 个 JS 异常
---
## ISS-05: 非致命控制台警告 [P3]
- **状态**: [ ] 待办 (低优先级, 可批量处理)
- **目标**: 清理控制台噪音
### Vue Router 根路由警告
- [ ] 在路由配置中添加根路径 `/` 的重定向规则 (redirect 到 `/app/login` 或 `/app/accounts/:accountId/dashboard`)
- [ ] 文件: `frontend/.../routes/index.js` 或 `frontend/.../router/index.js`
### onClose prop 弃用
- [ ] 全局搜索 `onClose` prop 使用, 替换为 `@close` 事件
- [ ] 约 4 处, 可批量替换
### ServiceWorker / Lit 警告
- [ ] ServiceWorker: 开发环境正常现象, 可在 vite.config.ts 中条件禁用 SW 注册
- [ ] Lit 多版本: 检查 `package.json` 依赖树, 确认是否有重复 Lit 依赖, 执行 `pnpm dedupe`
+228
View File
@@ -0,0 +1,228 @@
# GoChat 前端功能测试报告
- **测试日期**: 2026-07-08
- **测试人员**: Hermes Agent (自动化浏览器测试)
- **测试环境**:
- 前端: Vite dev server `http://localhost:3036`
- 后端: Go backend `http://localhost:3000`
- 数据库: PostgreSQL 17 + pgvector (port 5444)
- 登录账号: `admin@gochat.local` / `changeme`
- **测试方式**: CDP 连接浏览器, 逐页导航 + 控制台错误检查 + DOM 快照验证
- **测试重点**: 页面切换是否报错、白屏问题
---
## 一、测试范围
| 序号 | 页面 | URL |
|------|------|-----|
| 1 | 登录页 | `/app/login` |
| 2 | Dashboard | `/app/accounts/1/dashboard` |
| 3 | 会话详情 | 点击会话列表项进入 |
| 4 | Contacts | `/app/accounts/1/contacts` |
| 5 | Reports Overview | `/app/accounts/1/reports/overview` |
| 6 | Reports Conversations | `/app/accounts/1/reports/conversation` |
| 7 | Settings General | `/app/accounts/1/settings/general` |
| 8 | Settings Agents | `/app/accounts/1/settings/agents` |
| 9 | Settings Inboxes | `/app/accounts/1/settings/inboxes` |
| 10 | Campaigns | `/app/accounts/1/campaigns` |
| 11 | Help Center | `/app/accounts/1/portals` |
---
## 二、问题汇总
共发现 **5 类问题**, 按严重程度排序:
| 编号 | 严重程度 | 问题 | 影响页面 |
|------|----------|------|----------|
| ISS-01 | P0 严重 | Reports 图表永久卡在 "Loading chart data..." | Reports > Conversations 等 timeseries 页 |
| ISS-02 | P0 严重 | Settings > General 页面白屏 | Settings > General |
| ISS-03 | P0 严重 | widget/i18n 缺失 locale 文件导致全局白屏 | Campaigns → 全局 (已临时修复) |
| ISS-04 | P2 中等 | 每次页面导航产生 29 个 JS 异常 (SidebarGroup) | 所有 Settings 子页面 |
| ISS-05 | P3 低 | 非致命控制台警告 | 全局 |
---
## 三、问题详情
### ISS-01: Reports 图表永久卡在 "Loading chart data..." [P0]
**影响范围**: Reports > Conversations、Reports > Agents、Reports > Labels 等所有依赖 timeseries 数据的报表页
**现象**:
- 页面加载后 7 个图表全部显示 "Loading chart data..." 且永不完成
- 每次加载产生 9+ 个 JS 异常 (前端图表组件因 API 500 错误反复重试)
- Reports Overview 页面的指标卡片和表格正常 (使用不同的 API 端点)
**根因**:
后端 `analytics_query_helpers.go:40` 使用 GORM 查询 `reporting_events_rollups` 表时引用了 `date` 列:
```go
s.db.Where("account_id = ? AND date = ?", accountID, d).Count(&count)
```
但数据库迁移文件 `000001_init_schema.up.sql:338-351` 中建表语句的列名与 GORM 模型完全不匹配:
| 迁移文件 (SQL) 实际列 | GORM 模型期望列 |
|----------------------|----------------|
| `dimension` | `date` |
| `dimension_value` | `dimension_type` |
| `metric_name` | `dimension_id` |
| `value` | `metric` |
| `value_in_business_hours` | `count` |
| `period` | `sum_value` |
| — | `sum_value_business_hours` |
**后端日志**:
```
ERROR: column "date" does not exist (SQLSTATE 42703)
SELECT count(*) FROM "reporting_events_rollups" WHERE (account_id = 1 AND date = '2026-07-01 00:00:00')
HTTP GET /api/v2/accounts/1/reports 500
```
**涉及文件**:
- `backend/internal/service/analytics_query_helpers.go:40` — 查询代码
- `backend/migrations/000001_init_schema.up.sql:337-353` — 建表语句
- `backend/internal/model/reporting_event.go:68-78` — GORM 模型定义
---
### ISS-02: Settings > General 页面白屏 [P0]
**影响范围**: `/app/accounts/1/settings/general` (Account Settings 主页)
**现象**:
- 页面完全空白, 无任何内容渲染
- 控制台报 19 个 JS 异常
- Vue 警告指向两个组件渲染失败
**根因**:
1. **AccountId.vue 渲染失败**: `currentAccount.value.id.toString()` 在 `currentAccount` 为空对象 `{}` 时报错
- `accounts/getAccount` getter (`store/modules/accounts.js:26`) 在 store 无匹配记录时返回 `findRecordById` 的结果 `|| {}` (空对象)
- `currentAccount.value.id` 为 `undefined`, 调用 `.toString()` 抛出 TypeError
- `AccountId.vue:11`: `const getAccountId = computed(() => currentAccount.value.id.toString());`
2. **BuildInfo 组件渲染失败**: 同样依赖未正确加载的账户数据
3. **SidebarGroup mounted hooks 失败**: Inbox/Conversation/Captain/Contacts/Companies/Reports/Campaigns/Portals/Settings 共 9 个 SidebarGroup 的 mounted hook 执行出错
**Vue 警告**:
```
[Vue warn]: Unhandled error during execution of render function
at <SectionLayout title="Account ID" ...>
at <AccountId>
at <Index key="/app/accounts/1/settings/general">
```
**涉及文件**:
- `frontend/.../settings/account/components/AccountId.vue:11` — 未做空值保护
- `frontend/.../settings/account/Index.vue` — 包含 BuildInfo 组件
- `frontend/.../composables/useAccount.js:25` — `currentAccount` 可能为空对象
- `frontend/.../store/modules/accounts.js:9-10` — `findRecordById` 返回 `|| {}`
**备注**: 其他 Settings 子页面 (Agents/Inboxes/Teams 等) 正常工作, 仅 General 页面白屏
---
### ISS-03: widget/i18n 缺失 locale 文件导致全局白屏 [P0] (已临时修复)
**影响范围**: 最初导致 Campaigns 页面白屏, 后蔓延至全局 (Dashboard 等所有页面)
**现象**:
- Campaigns 页面直接显示 Vite 编译错误页面而非应用内容
- 错误溯源至 `widget/i18n/index.js:1` 的 import 语句
- 后续 Dashboard 等页面也受影响 (因 widget 模块被间接引用)
**根因**:
`widget/i18n/index.js` 导入了 40+ 个 locale JSON 文件:
```js
import ar from './locale/ar.json';
import bg from './locale/bg.json';
// ...共 40 个 import
```
但 `locale/` 目录下实际只有 2 个文件:
```
en.json
zh_CN.json
```
缺失 38 个 locale 文件, 导致 Vite 编译失败。
**临时修复**:
已将 `index.js` 改为只导入存在的两个 locale:
```js
import en from './locale/en.json';
import zh_CN from './locale/zh_CN.json';
export default {
en,
zh_CN,
};
```
**涉及文件**:
- `frontend/app/javascript/widget/i18n/index.js` (已修复)
- `frontend/app/javascript/widget/i18n/locale/` — 缺失 38 个 locale JSON 文件
**备注**: 临时修复仅保留 en 和 zh_CN, 如需多语言支持需补充 locale 文件或改为动态加载
---
### ISS-04: 每次页面导航产生 29 个 JS 异常 (SidebarGroup) [P2]
**影响范围**: 所有 Settings 子页面导航 (也出现在其他页面导航中)
**现象**:
- 即使页面内容正常渲染, 控制台固定报 29 个空 message 的 exception
- 异常来源: SidebarGroup (Inbox/Conversation/Captain/Contacts/Companies/Reports/Campaigns/Portals/Settings) 的 mounted hooks 执行出错
- 不影响页面功能, 但属于不健康的异常噪音
**可能原因**: SidebarGroup 组件的 mounted hook 依赖某个 store getter 或 feature flag 在路由切换时未正确初始化, 需要进一步排查
**涉及文件**:
- `frontend/.../components-next/sidebar/Sidebar.vue`
- `frontend/.../components-next/sidebar/` 下的 SidebarGroup 相关组件
---
### ISS-05: 非致命控制台警告 [P3]
| 警告 | 说明 | 影响 |
|------|------|------|
| Vue Router warn: No match found for path "/" | 根路由 `/` 未定义路由, 登录后重定向时触发 | 无功能影响 |
| onClose prop 弃用警告 (4处) | Chatwoot 原始代码使用已弃用的 `onClose` prop, 应改用 `close` 事件 | 无功能影响, 需迁移 |
| ServiceWorker 注册失败 (SecurityError) | Vite dev server 返回 `text/html` MIME 类型, SW 需要 JS 类型 | 开发环境正常现象, 生产环境不影响 |
| Lit dev mode + 多版本加载 | Lit 处于开发模式且加载了多个版本 | 开发环境警告, 需检查依赖去重 |
---
## 四、正常工作的页面
| 页面 | 状态 | 说明 |
|------|------|------|
| 登录页 | ✅ 正常 | 表单完整, 登录成功, 无 JS 错误 |
| Dashboard | ✅ 正常 | 侧边栏 + 会话列表完整 (修复 i18n 后) |
| 会话详情 | ✅ 正常 | 消息列表 + 回复框 + 联系人信息完整渲染 |
| Contacts | ✅ 正常 | 联系人编辑表单完整 (姓名/邮箱/电话/社交链接等) |
| Reports Overview | ✅ 正常 | 指标卡片 (Open/Unattended/Unassigned) + Agent Status + 表格正常 |
| Settings Agents | ✅ 正常 | 代理列表 + 搜索框 + 添加按钮正常 |
| Settings Inboxes | ✅ 正常 | 收件箱列表 (Test Website Inbox) + 添加按钮正常 |
| Campaigns | ✅ 正常 | 修复 i18n 后正常, Live Chat/SMS 子菜单 + 空状态正常 |
| Help Center | ✅ 正常 | 文章列表 + 分类 + 语言切换 + 新建按钮正常 |
---
## 五、测试结论
1. **核心阻断问题**: ISS-01 (Reports 500) 和 ISS-02 (Settings General 白屏) 是当前最严重的两个问题, 直接阻断对应功能页面的使用
2. **已修复问题**: ISS-03 (widget/i18n) 已临时修复, 恢复了全局可用性
3. **可用功能**: 登录、Dashboard、会话、联系人、Help Center、Campaigns、Settings 大部分子页面均可正常使用
4. **建议**: 优先修复 ISS-01 和 ISS-02, 然后排查 ISS-04 的 SidebarGroup 异常