Files
sundynix-agentix/sundynix-gateway/internal/handler/kb.go
T
Blizzard 8ff68078b7 feat: 知识库管理界面(入库监控 + 检索台)
桌面端「知识库」模块从占位变为可用:入库(切块/embedding/Milvus 监控) +
检索调试台(向量召回,带分数与来源)。

- mcp-go: 新工具 kb_search(返回结构化 JSON [{text,score}]);rag.Hit 加 json 标签
- gateway: POST /api/v1/kb/search → kb_search(结构化命中给检索台)
- desktop: lib/api ingestKb/searchKb;新 KbView(左 入库+监控日志 / 右 检索台命中列表
  带 Milvus 来源徽标+分数);App 接 kb 视图;LeftNav 知识库 ready
- 验证: gateway/mcp-go build✓ + e2e PASS + 前端 build✓;真实浏览器——入库3条→监控
  '已入库3块';语义查询'存储和搜索向量的组件'→Milvus(0.612)>Neo4j>NATS 排序正确,
  全走真实百炼 embedding(控制面下发)+Milvus

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 17:40:32 +08:00

65 lines
1.9 KiB
Go

package handler
import (
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sundynix/sundynix-shared/contract"
)
// KbIngest: POST /api/v1/kb/ingest —— 把文本入库到知识库(→ mcp-go kb_ingest → 切块/embedding/Milvus)。
// 供知识库管理页/脚本调用。
func (h *Handler) KbIngest(c *gin.Context) {
var body struct {
KB string `json:"kb"`
Text string `json:"text"`
}
if err := c.ShouldBindJSON(&body); err != nil || body.Text == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "text required"})
return
}
res, err := h.bus.CallTool(c.Request.Context(), contract.ToolSubjectGo("kb_ingest"),
&contract.ToolCall{Tool: "kb_ingest", Args: map[string]any{"kb": body.KB, "text": body.Text}})
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
if !res.OK {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": res.Error})
return
}
c.JSON(http.StatusOK, gin.H{"status": "ok", "message": res.Content})
}
// KbSearch: POST /api/v1/kb/search —— 检索台:查某知识库,返回带分数的命中(→ mcp-go kb_search)。
func (h *Handler) KbSearch(c *gin.Context) {
var body struct {
KB string `json:"kb"`
Q string `json:"q"`
TopK int `json:"topK"`
}
if err := c.ShouldBindJSON(&body); err != nil || body.Q == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "q required"})
return
}
args := map[string]any{"kb": body.KB, "q": body.Q}
if body.TopK > 0 {
args["topK"] = body.TopK
}
res, err := h.bus.CallTool(c.Request.Context(), contract.ToolSubjectGo("kb_search"),
&contract.ToolCall{Tool: "kb_search", Args: args})
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
if !res.OK {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": res.Error})
return
}
var hits []map[string]any
_ = json.Unmarshal([]byte(res.Content), &hits)
c.JSON(http.StatusOK, gin.H{"hits": hits})
}