From bfd0d74c34c4703a5372b9725b6c57c388b45dbd Mon Sep 17 00:00:00 2001 From: Blizzard Date: Mon, 20 Jul 2026 13:44:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(status):=20=E5=85=A8=E6=96=87=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E9=99=8D=E7=BA=A7=E4=B8=8A=E6=8A=A5=E5=88=B0=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=8F=B0=20=E2=80=94=E2=80=94=20=E8=AE=A9=E9=9D=99?= =?UTF-8?q?=E9=BB=98=E9=99=8D=E7=BA=A7=E7=9C=8B=E5=BE=97=E8=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一个提交修的是"卷没挂"这个实例,这个提交修的是"它坏了几周没人发现"这个 类别问题:全文路退内存兜底后,混合检索只表现为召回变差,不报错、无告警。 - mcp-go: bleveStore 记录 persistent;health 工具多报一个 fulltext_disk。 仍是 map[string]bool,gateway 现有反序列化不受影响(加非 bool 字段会让 整个 health 解析失败,连带 Milvus/Neo4j 健康灯一起黑)。 - gateway: 基建灯新增「全文索引」一项,退内存时给出后果与排查方向, 而不只是一盏灰灯。 - admin: 基建列表此前只渲染 name/up,detail 字段一直没露出——而降级原因 恰恰只存在于 detail 里。补上渲染(离线态用琥珀色),并给「全文索引」 补 INFRA_META(它不是独立服务,没有端口,落在容器卷上)。 Co-Authored-By: Claude Opus 4.8 --- sundynix-admin/src/pages/StatusPage.tsx | 10 +++++++++- .../internal/handler/status_handler.go | 18 ++++++++++++++++++ sundynix-mcp-go/internal/rag/bleve.go | 5 ++++- sundynix-mcp-go/internal/rag/rag.go | 3 +++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/sundynix-admin/src/pages/StatusPage.tsx b/sundynix-admin/src/pages/StatusPage.tsx index 34ff63e..ab9af84 100644 --- a/sundynix-admin/src/pages/StatusPage.tsx +++ b/sundynix-admin/src/pages/StatusPage.tsx @@ -17,6 +17,8 @@ const INFRA_META: Record milvus: { role: "向量检索库", port: "19530", icon: "db" }, neo4j: { role: "图关系库", port: "7687", icon: "bus" }, minio: { role: "对象存储 (OSS)", port: "9000", icon: "db" }, + // 全文索引不是独立服务,是 mcp-go 进程内的本地 bleve —— 没有端口,落在容器卷上。 + 全文索引: { role: "全文检索 (bleve)", port: "本地卷", icon: "db" }, }; function toolCategory(t: string): string { @@ -313,9 +315,15 @@ export function StatusPage() { const meta = INFRA_META[item.name]; return (
-
+
{item.name} {meta?.role || "后端组件"} + {/* detail 是降级原因/后果的唯一载体(如"内存兜底·重启即清零"),必须露出来 */} + {item.detail && ( + + · {item.detail} + + )}
diff --git a/sundynix-gateway/internal/handler/status_handler.go b/sundynix-gateway/internal/handler/status_handler.go index 3e75ba6..8cc4a97 100644 --- a/sundynix-gateway/internal/handler/status_handler.go +++ b/sundynix-gateway/internal/handler/status_handler.go @@ -56,6 +56,7 @@ func (h *Handler) AdminStatus(c *gin.Context) { wg sync.WaitGroup milvus, neo4j bool // mcp-go health + ftDisk bool // 全文索引是否落盘持久(false=退内存兜底,重启清零) goUp bool // mcp-go 在线 goTools []toolInfo // mcp-go 注册工具 goLatency int // mcp-go 探针耗时 @@ -81,6 +82,7 @@ func (h *Handler) AdminStatus(c *gin.Context) { var sub map[string]bool if json.Unmarshal([]byte(res.Content), &sub) == nil { milvus, neo4j = sub["milvus"], sub["neo4j"] + ftDisk = sub["fulltext_disk"] } } }() @@ -138,6 +140,9 @@ func (h *Handler) AdminStatus(c *gin.Context) { {Name: "milvus", Up: milvus}, {Name: "neo4j", Up: neo4j}, {Name: "minio", Up: minioUp}, // 对象存储(报告/KB 正文/blob,126) + // 全文索引:mcp-go 本地 bleve,是唯一不在 128 集中存储上的检索路, + // 也是唯一会"静默降级"的一路(退内存后重启清零,检索只是变差不报错)。 + {Name: "全文索引", Up: goUp && ftDisk, Detail: fulltextDetail(goUp, ftDisk)}, }, Services: []statusItem{ {Name: "gateway", Up: true, Detail: "在线"}, @@ -207,3 +212,16 @@ func humanDuration(s int) string { } return fmt.Sprintf("%dh%dm", m/60, m%60) } + +// fulltextDetail 说明全文(bleve)索引的持久化状态。退内存兜底时必须讲清后果—— +// 否则一盏灰灯没人知道意味着"重启就没了"。 +func fulltextDetail(goUp, disk bool) string { + switch { + case !goUp: + return "mcp-go 离线,无法判定" + case disk: + return "落盘持久" + default: + return "内存兜底 · 重启即清零(检查 BLEVE_PATH 与挂载卷权限)" + } +} diff --git a/sundynix-mcp-go/internal/rag/bleve.go b/sundynix-mcp-go/internal/rag/bleve.go index b9a660f..a95c24c 100644 --- a/sundynix-mcp-go/internal/rag/bleve.go +++ b/sundynix-mcp-go/internal/rag/bleve.go @@ -19,6 +19,9 @@ import ( // 落盘不可用时退回内存索引(功能在、重启会丢),好过全文路全哑。 type bleveStore struct { idx bleve.Index + // persistent=false 表示退了内存兜底:功能在但重启即清零。这是**静默降级**—— + // 混合检索只会少一路召回、不报错,所以必须上报出去(health → 控制台),否则没人发现。 + persistent bool } // bleveMapping:text 字段用 cjk 分词器(bigram,能切中文,否则默认标准分词器把整段中文当一个 @@ -62,7 +65,7 @@ func openBleve() *bleveStore { return memBleve() } log.Printf("[rag] bleve 全文索引落盘就绪: %s", path) - return &bleveStore{idx: idx} + return &bleveStore{idx: idx, persistent: true} } // memBleve 内存兜底:落盘不可用时退回内存索引(功能在、重启会丢),好过全文路全哑。 diff --git a/sundynix-mcp-go/internal/rag/rag.go b/sundynix-mcp-go/internal/rag/rag.go index 1da1f40..c81b7f4 100644 --- a/sundynix-mcp-go/internal/rag/rag.go +++ b/sundynix-mcp-go/internal/rag/rag.go @@ -155,6 +155,9 @@ func (e *Engine) Status() map[string]bool { "milvus": e.mv != nil, "neo4j": e.graph.ready(), "embedding": e.embed().ready(), + // 全文路是否落盘持久。false = 退了内存兜底,重启清零 —— 不上报的话这种降级 + // 只表现为"召回变差",看不出故障(曾因此静默坏了很久)。 + "fulltext_disk": e.bleve != nil && e.bleve.persistent, } }