mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
feat(healthcheck): 内核状态快照报出内核版本号与 ONNX 模型启用状态
healthcheck_kernel 此前没有任何「ONNX 模型是否在用」的信息,只报「向量可用/不可用」, 分不清「统一多模态空间已加载」与「退回到词嵌入/TF-IDF 路径」;人格卡要求 「版本以运行时快照为准」,也缺一个可查字段(build.version 早就在,但没人知道)。 - KernelStatus 新增 onnx 段:enabled / provider / dim / fingerprint / modalities / reason。 判据取 Loaded()(provider 真正打开且元数据合法),**不是**「配置里写了 provider」 —— 后者在模型缺失 / 运行时缺失时也为真,报出去就是假绿。 - 未启用时 reason 给**具体原因**:未配置(说明会走回退路径)/ 打开失败的具体错误。 homed 把「配置的 provider 名」与「打开失败原因」透传给 Agent,仅供状态报告。 - ProviderAdapter 新增 Modalities()(可选能力,按接口断言取用,不改公开契约)。 - healthcheck_kernel 的工具描述同步说明它回答这两件事。 **顺带修一个真实 panic**:collectKernelStatus 的 knowledge 是**接口**参数, (*knowledge.Store)(nil) 塞进接口后 `ks != nil` 仍为真 → 调 List() 直接 panic, 而 healthcheck_kernel 正是走这条路径(panic 发生在工具 goroutine 里)。 GetKernelStatus 改为先按具体指针判空、再赋给接口;并加刻画测试钉住这个成因 (一旦不再 panic 说明参数形状已变,守卫与该测试应同步删除)。 验证:单测 4 例(已启用 / 打开失败 / 未配置 / 未加载)+ 刻画测试; 隔离实例 E2E 7/7:正例 provider=chineseclip → enabled=true、dim=512、模态 2; 反例 provider=nonexistent → enabled=false 且 reason 含具体错误与 provider 名, 真实对话仍通。
This commit is contained in:
@ -367,7 +367,11 @@ func main() {
|
|||||||
// 布局、预处理、解码、运行时全部属于 provider 内部实现。
|
// 布局、预处理、解码、运行时全部属于 provider 内部实现。
|
||||||
// provider 名为空时禁用多模态向量检索,退回纯 fastText 文本路径。
|
// provider 名为空时禁用多模态向量检索,退回纯 fastText 文本路径。
|
||||||
var multimodalSpace vector.MultimodalEmbedder
|
var multimodalSpace vector.MultimodalEmbedder
|
||||||
|
// 这两个值只用于状态报告(healthcheck_kernel 的 onnx 段):
|
||||||
|
// 「配了哪个 provider」与「为什么没启用」,避免只能看到 false 却不知原因。
|
||||||
|
var mmProviderName, mmErr string
|
||||||
if mmProvider := cfgReg.GetString("core.memory.multimodal_space.provider", ""); mmProvider != "" {
|
if mmProvider := cfgReg.GetString("core.memory.multimodal_space.provider", ""); mmProvider != "" {
|
||||||
|
mmProviderName = mmProvider
|
||||||
opts := map[string]string{}
|
opts := map[string]string{}
|
||||||
const optPrefix = "core.memory.multimodal_space.options."
|
const optPrefix = "core.memory.multimodal_space.options."
|
||||||
for _, key := range cfgReg.List("core.memory.multimodal_space.options.") {
|
for _, key := range cfgReg.List("core.memory.multimodal_space.options.") {
|
||||||
@ -375,10 +379,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
provider, err := embedding.Open(mmProvider, embedding.Config{Options: opts})
|
provider, err := embedding.Open(mmProvider, embedding.Config{Options: opts})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mmErr = err.Error()
|
||||||
log.Printf("[homed] warning: 多模态向量 provider %q 打开失败: %v(多模态向量检索已禁用;已注册: %s)",
|
log.Printf("[homed] warning: 多模态向量 provider %q 打开失败: %v(多模态向量检索已禁用;已注册: %s)",
|
||||||
mmProvider, err, strings.Join(embedding.Names(), ", "))
|
mmProvider, err, strings.Join(embedding.Names(), ", "))
|
||||||
} else if adapted, err := vector.AdaptProvider(provider); err != nil {
|
} else if adapted, err := vector.AdaptProvider(provider); err != nil {
|
||||||
provider.Close()
|
provider.Close()
|
||||||
|
mmErr = err.Error()
|
||||||
log.Printf("[homed] warning: 多模态向量 provider %q 元数据不合法: %v(多模态向量检索已禁用)", mmProvider, err)
|
log.Printf("[homed] warning: 多模态向量 provider %q 元数据不合法: %v(多模态向量检索已禁用)", mmProvider, err)
|
||||||
} else {
|
} else {
|
||||||
multimodalSpace = adapted
|
multimodalSpace = adapted
|
||||||
@ -533,6 +539,8 @@ func main() {
|
|||||||
EmbeddingModelPath: cfgReg.GetString("core.agent.embedding_model_path", ""),
|
EmbeddingModelPath: cfgReg.GetString("core.agent.embedding_model_path", ""),
|
||||||
Embedder: embedder,
|
Embedder: embedder,
|
||||||
MultimodalSpace: multimodalSpace,
|
MultimodalSpace: multimodalSpace,
|
||||||
|
EmbeddingProvider: mmProviderName,
|
||||||
|
EmbeddingError: mmErr,
|
||||||
StageHost: stageHost,
|
StageHost: stageHost,
|
||||||
EventBus: evBus,
|
EventBus: evBus,
|
||||||
ThinkingEnabled: cfg.LLM.ThinkingEnabled,
|
ThinkingEnabled: cfg.LLM.ThinkingEnabled,
|
||||||
|
|||||||
@ -154,6 +154,12 @@ type Agent struct {
|
|||||||
// 也可以是外部 API 客户端;两者共享同一套 L0/L2/L3 向量缓存与检索基础设施。
|
// 也可以是外部 API 客户端;两者共享同一套 L0/L2/L3 向量缓存与检索基础设施。
|
||||||
multimodalSpace vector.MultimodalEmbedder
|
multimodalSpace vector.MultimodalEmbedder
|
||||||
|
|
||||||
|
// embeddingProvider 是配置里指定的统一向量空间 provider 名;
|
||||||
|
// embeddingError 是打开/适配失败的原因(成功时为空)。
|
||||||
|
// 二者只用于状态报告:区分「没配」「配了但打不开」「已启用」。
|
||||||
|
embeddingProvider string
|
||||||
|
embeddingError string
|
||||||
|
|
||||||
// fusionCfg 控制文本路与视觉路的跨模态融合权重,可按模型实测结果配置。
|
// fusionCfg 控制文本路与视觉路的跨模态融合权重,可按模型实测结果配置。
|
||||||
fusionCfg CrossModalFusionConfig
|
fusionCfg CrossModalFusionConfig
|
||||||
|
|
||||||
@ -179,12 +185,16 @@ type AgentConfig struct {
|
|||||||
Indexer *memory.Indexer
|
Indexer *memory.Indexer
|
||||||
Tracker *tracker.Tracker
|
Tracker *tracker.Tracker
|
||||||
|
|
||||||
DocStore *document.Store
|
DocStore *document.Store
|
||||||
Knowledge *knowledge.Store
|
Knowledge *knowledge.Store
|
||||||
SocialStore *social.SocialStore
|
SocialStore *social.SocialStore
|
||||||
TextMemory *text.Memory
|
TextMemory *text.Memory
|
||||||
MediaStore *media.Store
|
MediaStore *media.Store
|
||||||
MultimodalSpace vector.MultimodalEmbedder
|
MultimodalSpace vector.MultimodalEmbedder
|
||||||
|
// EmbeddingProvider / EmbeddingError 是向量空间的配置身份与打开失败原因,
|
||||||
|
// 供 healthcheck_kernel 状态报告区分「未配置 / 打开失败 / 已启用」。
|
||||||
|
EmbeddingProvider string
|
||||||
|
EmbeddingError string
|
||||||
FusionCfg CrossModalFusionConfig // 跨模态融合权重;零值用默认
|
FusionCfg CrossModalFusionConfig // 跨模态融合权重;零值用默认
|
||||||
Personality *agentPkg.Personality
|
Personality *agentPkg.Personality
|
||||||
PersonaStore PersonaStore // 人格设定的读写面(首启门禁 + persona_set 工具)
|
PersonaStore PersonaStore // 人格设定的读写面(首启门禁 + persona_set 工具)
|
||||||
@ -256,46 +266,48 @@ func New(cfg AgentConfig) *Agent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Agent{
|
return &Agent{
|
||||||
id: cfg.ID,
|
id: cfg.ID,
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
provider: cfg.Provider,
|
provider: cfg.Provider,
|
||||||
providerManager: cfg.ProviderManager,
|
providerManager: cfg.ProviderManager,
|
||||||
io: cfg.IO,
|
io: cfg.IO,
|
||||||
memory: cfg.Memory,
|
memory: cfg.Memory,
|
||||||
indexer: cfg.Indexer,
|
indexer: cfg.Indexer,
|
||||||
tracker: cfg.Tracker,
|
tracker: cfg.Tracker,
|
||||||
context: rc,
|
context: rc,
|
||||||
systemPrompt: cfg.SystemPrompt,
|
systemPrompt: cfg.SystemPrompt,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
docStore: cfg.DocStore,
|
docStore: cfg.DocStore,
|
||||||
knowledge: cfg.Knowledge,
|
knowledge: cfg.Knowledge,
|
||||||
social: cfg.SocialStore,
|
social: cfg.SocialStore,
|
||||||
textMem: cfg.TextMemory,
|
textMem: cfg.TextMemory,
|
||||||
mediaStore: cfg.MediaStore,
|
mediaStore: cfg.MediaStore,
|
||||||
personality: cfg.Personality,
|
personality: cfg.Personality,
|
||||||
personaStore: cfg.PersonaStore,
|
personaStore: cfg.PersonaStore,
|
||||||
pluginReg: cfg.PluginReg,
|
pluginReg: cfg.PluginReg,
|
||||||
pluginDir: cfg.PluginDir,
|
pluginDir: cfg.PluginDir,
|
||||||
distillInterval: cfg.DistillInterval,
|
distillInterval: cfg.DistillInterval,
|
||||||
archiveInterval: cfg.ArchiveInterval,
|
archiveInterval: cfg.ArchiveInterval,
|
||||||
reviewInterval: cfg.ReviewInterval,
|
reviewInterval: cfg.ReviewInterval,
|
||||||
mergeInterval: cfg.MergeInterval,
|
mergeInterval: cfg.MergeInterval,
|
||||||
maxContextSize: cfg.MaxContextSize,
|
maxContextSize: cfg.MaxContextSize,
|
||||||
stageHost: cfg.StageHost,
|
stageHost: cfg.StageHost,
|
||||||
skillIndex: cfg.SkillIndexProvider,
|
skillIndex: cfg.SkillIndexProvider,
|
||||||
eventBus: cfg.EventBus,
|
eventBus: cfg.EventBus,
|
||||||
selfInputCh: make(chan selfInputMsg, 64),
|
selfInputCh: make(chan selfInputMsg, 64),
|
||||||
childTasks: make(map[string]*childTaskState),
|
childTasks: make(map[string]*childTaskState),
|
||||||
interceptCh: make(chan *agentIO.InputEvent, 64),
|
interceptCh: make(chan *agentIO.InputEvent, 64),
|
||||||
pluginHealth: newPluginHealthTracker(),
|
pluginHealth: newPluginHealthTracker(),
|
||||||
thinkingEnabled: cfg.ThinkingEnabled,
|
thinkingEnabled: cfg.ThinkingEnabled,
|
||||||
inputCfg: cfg.InputProcessing,
|
inputCfg: cfg.InputProcessing,
|
||||||
embedder: embedder,
|
embedder: embedder,
|
||||||
multimodalSpace: cfg.MultimodalSpace,
|
multimodalSpace: cfg.MultimodalSpace,
|
||||||
fusionCfg: cfg.FusionCfg,
|
embeddingProvider: cfg.EmbeddingProvider,
|
||||||
noMergeMarkers: make(map[string]int),
|
embeddingError: cfg.EmbeddingError,
|
||||||
lastInput: make(map[string]time.Time),
|
fusionCfg: cfg.FusionCfg,
|
||||||
|
noMergeMarkers: make(map[string]int),
|
||||||
|
lastInput: make(map[string]time.Time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -198,6 +198,14 @@ func (a *Agent) GetKernelStatus() *KernelStatus {
|
|||||||
trk = a.tracker
|
trk = a.tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注意:knowledge 在 collectKernelStatus 里是**接口**参数,
|
||||||
|
// 而 (*knowledge.Store)(nil) 塞进接口后 `ks != nil` 仍为真 → 调 List() 直接 panic。
|
||||||
|
// 所以这里必须先判具体指针再进行接口赋值(healthcheck_kernel 会走到这条路径)。
|
||||||
|
var knowledgeLister interface{ List() []string }
|
||||||
|
if a.knowledge != nil {
|
||||||
|
knowledgeLister = a.knowledge
|
||||||
|
}
|
||||||
|
|
||||||
ks := collectKernelStatus(
|
ks := collectKernelStatus(
|
||||||
a.startTime,
|
a.startTime,
|
||||||
string(a.id),
|
string(a.id),
|
||||||
@ -207,15 +215,43 @@ func (a *Agent) GetKernelStatus() *KernelStatus {
|
|||||||
a.io,
|
a.io,
|
||||||
a.pluginReg,
|
a.pluginReg,
|
||||||
a.memory,
|
a.memory,
|
||||||
a.knowledge,
|
knowledgeLister,
|
||||||
a.docStore,
|
a.docStore,
|
||||||
textMem,
|
textMem,
|
||||||
socialStore,
|
socialStore,
|
||||||
trk,
|
trk,
|
||||||
)
|
)
|
||||||
|
ks.ONNX = a.onnxStatus()
|
||||||
|
|
||||||
return ks
|
return ks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// onnxStatus 汇总统一多模态向量空间(ONNX 模型)的启用状态。
|
||||||
|
//
|
||||||
|
// 判据是 Loaded()(provider 真正打开且元数据合法),**不是**「配置里写了 provider」——
|
||||||
|
// 后者在模型缺失 / 运行时缺失时也为真,拿它当判据就是假绿。
|
||||||
|
func (a *Agent) onnxStatus() sdk.ONNXStatus {
|
||||||
|
st := sdk.ONNXStatus{Provider: a.embeddingProvider}
|
||||||
|
if a.multimodalSpace != nil && a.multimodalSpace.Loaded() {
|
||||||
|
st.Enabled = true
|
||||||
|
st.Dim = a.multimodalSpace.Dim()
|
||||||
|
st.Fingerprint = a.multimodalSpace.Fingerprint()
|
||||||
|
// 模态是可选能力:只有底层 provider 报出来时才带出。
|
||||||
|
if mr, ok := a.multimodalSpace.(interface{ Modalities() []string }); ok {
|
||||||
|
st.Modalities = mr.Modalities()
|
||||||
|
}
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case a.embeddingError != "":
|
||||||
|
st.Reason = "打开失败: " + a.embeddingError
|
||||||
|
case a.embeddingProvider == "":
|
||||||
|
st.Reason = "未配置统一向量空间 provider(走词嵌入/TF-IDF 回退路径)"
|
||||||
|
default:
|
||||||
|
st.Reason = "provider 未加载"
|
||||||
|
}
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
|
||||||
var _ StatusProvider = (*Agent)(nil)
|
var _ StatusProvider = (*Agent)(nil)
|
||||||
var _ sdk.StatusAPI = (*Agent)(nil)
|
var _ sdk.StatusAPI = (*Agent)(nil)
|
||||||
|
|||||||
103
internal/agent/core/status_onnx_test.go
Normal file
103
internal/agent/core/status_onnx_test.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
agentIO "gitcode.com/JianFeeeee/HomeAgent/internal/agent/io"
|
||||||
|
"gitcode.com/JianFeeeee/HomeAgent/internal/knowledge"
|
||||||
|
)
|
||||||
|
|
||||||
|
// statusSpace 是带模态元数据的假统一空间(ProviderAdapter 的 Modalities() 形状)。
|
||||||
|
type statusSpace struct{ fakeSpace }
|
||||||
|
|
||||||
|
func (statusSpace) Modalities() []string { return []string{"text", "image"} }
|
||||||
|
|
||||||
|
// statusSpaceUnloaded 模拟「provider 建了但没加载成功」。
|
||||||
|
type statusSpaceUnloaded struct{ fakeSpace }
|
||||||
|
|
||||||
|
func (statusSpaceUnloaded) Loaded() bool { return false }
|
||||||
|
|
||||||
|
// healthcheck_kernel 必须能回答两件事:内核版本号、以及**是否真的启用了 ONNX 模型**。
|
||||||
|
//
|
||||||
|
// 判据要点:只有 provider 真正 Loaded() 才算启用 ——「配置里写了 provider」不算,
|
||||||
|
// 否则模型缺失/运行时缺失时会报成已启用(假绿)。
|
||||||
|
func TestKernelStatusReportsVersionAndONNX(t *testing.T) {
|
||||||
|
t.Run("已启用:带出 provider/维度/指纹/模态", func(t *testing.T) {
|
||||||
|
a := &Agent{
|
||||||
|
io: agentIO.NewIOManager(),
|
||||||
|
multimodalSpace: statusSpace{},
|
||||||
|
embeddingProvider: "chineseclip",
|
||||||
|
}
|
||||||
|
st := a.GetKernelStatus()
|
||||||
|
if !st.ONNX.Enabled {
|
||||||
|
t.Fatal("Loaded() 为真时 onnx.enabled 必须为真")
|
||||||
|
}
|
||||||
|
if st.ONNX.Provider != "chineseclip" || st.ONNX.Dim != 2 || st.ONNX.Fingerprint != "fake-space" {
|
||||||
|
t.Fatalf("onnx 身份字段不对: %+v", st.ONNX)
|
||||||
|
}
|
||||||
|
if len(st.ONNX.Modalities) != 2 || st.ONNX.Reason != "" {
|
||||||
|
t.Fatalf("模态/原因不对: %+v", st.ONNX)
|
||||||
|
}
|
||||||
|
// 内核版本号必须随状态一起报:人格卡要求「版本以运行时快照为准」靠的就是这一项
|
||||||
|
if st.Build.Version == "" || st.Build.KernelName == "" {
|
||||||
|
t.Fatalf("build 段缺少版本/内核名: %+v", st.Build)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("打开失败:enabled=false 且给出具体原因", func(t *testing.T) {
|
||||||
|
a := &Agent{
|
||||||
|
io: agentIO.NewIOManager(),
|
||||||
|
embeddingProvider: "chineseclip",
|
||||||
|
embeddingError: `embedding: open provider "chineseclip": model dir missing`,
|
||||||
|
}
|
||||||
|
st := a.GetKernelStatus()
|
||||||
|
if st.ONNX.Enabled {
|
||||||
|
t.Fatal("打开失败时不能报 enabled")
|
||||||
|
}
|
||||||
|
if st.ONNX.Provider != "chineseclip" {
|
||||||
|
t.Fatalf("未启用时仍应带出配置的 provider: %+v", st.ONNX)
|
||||||
|
}
|
||||||
|
if !strings.Contains(st.ONNX.Reason, "model dir missing") {
|
||||||
|
t.Fatalf("原因应包含具体错误: %q", st.ONNX.Reason)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("未配置:说明会走回退路径", func(t *testing.T) {
|
||||||
|
a := &Agent{io: agentIO.NewIOManager()}
|
||||||
|
st := a.GetKernelStatus()
|
||||||
|
if st.ONNX.Enabled || st.ONNX.Reason == "" {
|
||||||
|
t.Fatalf("未配置时应 enabled=false 且有原因: %+v", st.ONNX)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("provider 存在但未加载", func(t *testing.T) {
|
||||||
|
a := &Agent{
|
||||||
|
io: agentIO.NewIOManager(),
|
||||||
|
multimodalSpace: statusSpaceUnloaded{},
|
||||||
|
embeddingProvider: "qwen3vl",
|
||||||
|
}
|
||||||
|
st := a.GetKernelStatus()
|
||||||
|
if st.ONNX.Enabled {
|
||||||
|
t.Fatal("Loaded() 为假时不能报 enabled")
|
||||||
|
}
|
||||||
|
if st.ONNX.Reason == "" {
|
||||||
|
t.Fatalf("应给出未加载的原因: %+v", st.ONNX)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectKernelStatus 的 knowledge 参数是**接口**类型,而 (*knowledge.Store)(nil)
|
||||||
|
// 塞进接口后 `ks != nil` 仍为真 → 调 List() 直接 panic。
|
||||||
|
// 这条测试钉住这个成因:一旦不再 panic,说明参数形状变了,
|
||||||
|
// GetKernelStatus 里的 typed-nil 守卫就该同步删掉(否则它变成无意义代码)。
|
||||||
|
func TestCollectKernelStatusTypedNilKnowledgePanics(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("typed-nil 交给接口参数却未 panic:成因已变,请更新守卫与本测试")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var nilStore *knowledge.Store
|
||||||
|
_ = collectKernelStatus(time.Now(), "a", "", 0, nil, nil, nil, nil, nilStore, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
@ -65,6 +65,18 @@ func (a *ProviderAdapter) embed(input embedding.Input) ([]float64, error) {
|
|||||||
func (a *ProviderAdapter) Fingerprint() string { return a.info.Fingerprint }
|
func (a *ProviderAdapter) Fingerprint() string { return a.info.Fingerprint }
|
||||||
func (a *ProviderAdapter) Dim() int { return a.info.Dimension }
|
func (a *ProviderAdapter) Dim() int { return a.info.Dimension }
|
||||||
|
|
||||||
|
// Modalities 报告该空间支持的输入模态(text/image/...)。
|
||||||
|
//
|
||||||
|
// 模态是**可选能力**:MultimodalEmbedder 契约里没有它,状态查询按接口断言取用,
|
||||||
|
// 所以这里既不改公开接口,也不影响其它实现(核心也不硬编码任何模型名)。
|
||||||
|
func (a *ProviderAdapter) Modalities() []string {
|
||||||
|
out := make([]string, 0, len(a.info.Modalities))
|
||||||
|
for _, m := range a.info.Modalities {
|
||||||
|
out = append(out, string(m))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (a *ProviderAdapter) Loaded() bool {
|
func (a *ProviderAdapter) Loaded() bool {
|
||||||
a.mu.RLock()
|
a.mu.RLock()
|
||||||
defer a.mu.RUnlock()
|
defer a.mu.RUnlock()
|
||||||
|
|||||||
@ -240,7 +240,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
p.selfToolNames["healthcheck_kernel"] = true
|
p.selfToolNames["healthcheck_kernel"] = true
|
||||||
s.RegisterTool("healthcheck_kernel", sdk.ToolDef{
|
s.RegisterTool("healthcheck_kernel", sdk.ToolDef{
|
||||||
Name: "healthcheck_kernel",
|
Name: "healthcheck_kernel",
|
||||||
Description: "查询 Agent 内核运行状态快照,包括插件/工具/记忆/知识库/LLM Provider/运行时等各子系统信息。Agent 可通过此工具自主监测内核健康。",
|
Description: "查询 Agent 内核运行状态快照,包括**内核版本号与构建身份**(build.version / commit / build_time)、**统一多模态向量空间(ONNX 模型)是否启用**(onnx.enabled,未启用时给出原因)、插件/工具/记忆/知识库/LLM Provider/运行时等各子系统信息。Agent 可通过此工具自主监测内核健康。",
|
||||||
Parameters: map[string]interface{}{
|
Parameters: map[string]interface{}{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": map[string]interface{}{},
|
"properties": map[string]interface{}{},
|
||||||
|
|||||||
@ -38,9 +38,29 @@ type KernelStatus struct {
|
|||||||
|
|
||||||
Runtime RuntimeStatus `json:"runtime"`
|
Runtime RuntimeStatus `json:"runtime"`
|
||||||
|
|
||||||
|
// ONNX 报告统一多模态向量空间(ONNX 模型)是否**真的在用**。
|
||||||
|
//
|
||||||
|
// 为何单列:内核的向量能力是三层降级(统一多模态空间 → 词嵌入 → TF-IDF),
|
||||||
|
// 只报「向量可用/不可用」分不清「ONNX 模型已加载」与「退回了纯文本路径」。
|
||||||
|
// 模型缺失 / 运行时缺失 / provider 打开失败时这里是 enabled=false + reason。
|
||||||
|
ONNX ONNXStatus `json:"onnx"`
|
||||||
|
|
||||||
Tracker TrackerStatus `json:"tracker"`
|
Tracker TrackerStatus `json:"tracker"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ONNXStatus 是统一多模态向量空间(ONNX 模型)的启用状态与身份。
|
||||||
|
type ONNXStatus struct {
|
||||||
|
// Enabled 是 provider 真正打开且元数据合法(不是「配置里写了 provider」)。
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
// Provider 是配置指定的 provider 名(如 chineseclip / qwen3vl / http)。
|
||||||
|
Provider string `json:"provider,omitempty"`
|
||||||
|
Dim int `json:"dim,omitempty"`
|
||||||
|
Fingerprint string `json:"fingerprint,omitempty"`
|
||||||
|
Modalities []string `json:"modalities,omitempty"`
|
||||||
|
// Reason 是未启用时的原因(未配置 / 打开失败的具体错误 / 其它)。
|
||||||
|
Reason string `json:"reason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type PluginInfo struct {
|
type PluginInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Loaded bool `json:"loaded"`
|
Loaded bool `json:"loaded"`
|
||||||
|
|||||||
Reference in New Issue
Block a user