+18
-15
@@ -425,7 +425,7 @@ func (e *Engine) Scan(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pendingEmbeddings := len(e.Graph.NodesForEmbeddingFiltered(e.learningCategories()))
|
||||
pendingEmbeddings := len(e.Graph.NodesForEmbeddingScoped(e.effectiveLearningFilter()))
|
||||
if e.Graph.Version() != beforeVersion || pendingEmbeddings > 0 {
|
||||
e.Broker.Publish(model.Activity{Type: "scan.started", Source: "brain", Phase: "ingest", Message: "Neue oder geänderte Wissenselemente werden verarbeitet", Strength: .45, Metadata: map[string]any{"pending_embeddings": pendingEmbeddings}})
|
||||
}
|
||||
@@ -461,7 +461,7 @@ func (e *Engine) Scan(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
func (e *Engine) ensureEmbeddings(ctx context.Context) error {
|
||||
pending := e.Graph.NodesForEmbeddingFiltered(e.learningCategories())
|
||||
pending := e.Graph.NodesForEmbeddingScoped(e.effectiveLearningFilter())
|
||||
if len(pending) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -492,7 +492,7 @@ func (e *Engine) ensureEmbeddings(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
func (e *Engine) ensureFallbackEmbeddings() {
|
||||
for _, n := range e.Graph.NodesForEmbeddingFiltered(e.learningCategories()) {
|
||||
for _, n := range e.Graph.NodesForEmbeddingScoped(e.effectiveLearningFilter()) {
|
||||
e.Graph.SetVector(n.ID, hashEmbedding(embeddingText(n), 256))
|
||||
}
|
||||
}
|
||||
@@ -538,7 +538,7 @@ func (e *Engine) Query(ctx context.Context, q string) (model.QueryResponse, erro
|
||||
if err != nil || len(vecs) == 0 {
|
||||
vecs = [][]float64{hashEmbedding(q, 256)}
|
||||
}
|
||||
hits := e.Graph.Similar(vecs[0], e.Cfg.TopK)
|
||||
hits := e.Graph.SimilarFiltered(vecs[0], e.Cfg.TopK, e.effectiveLearningFilter())
|
||||
nodeIDs := make([]string, 0, len(hits))
|
||||
for i, h := range hits {
|
||||
nodeIDs = append(nodeIDs, h.NodeID)
|
||||
@@ -648,7 +648,7 @@ func (e *Engine) enrichOne(ctx context.Context, trigger string) (EnrichOutcome,
|
||||
e.setOllamaOK(true)
|
||||
}
|
||||
|
||||
a, b, sim, ok, comparisons := e.Graph.NextPairFilteredDepth(e.Cfg.SimilarityThreshold, e.Cfg.EnrichAnchors, e.thinkingCategories(), e.Cfg.ArticleMaxGenerationDepth)
|
||||
a, b, sim, ok, comparisons := e.Graph.NextPairScopedDepth(e.Cfg.SimilarityThreshold, e.Cfg.EnrichAnchors, e.effectiveThinkingFilter(), e.Cfg.ArticleMaxGenerationDepth)
|
||||
if !ok {
|
||||
e.stateMu.Lock()
|
||||
e.lastAttempt = time.Now().UTC()
|
||||
@@ -685,20 +685,23 @@ func (e *Engine) enrichOne(ctx context.Context, trigger string) (EnrichOutcome,
|
||||
slog.Warn("research failed", "query", decision.ResearchQuery, "base_url", diagnostic.BaseURL, "kind", diagnostic.ErrorKind, "http_status", diagnostic.HTTPStatus, "duration_ms", diagnostic.DurationMS, "error", err)
|
||||
e.Broker.Publish(model.Activity{Type: "research.failed", Source: "searxng", Phase: "research", NodeIDs: []string{a.ID, b.ID}, Message: "SearXNG-Recherche ist fehlgeschlagen", Strength: .35, Metadata: metadata})
|
||||
} else {
|
||||
resultMetadata := mergeResearchMetadata(researchEventMetadata(trigger, researchID, decision.ResearchQuery, results, time.Since(researchStarted)), researchDiagnosticMetadata(diagnostic))
|
||||
message := fmt.Sprintf("SearXNG hat %d verwertbare Webquellen geliefert", len(results))
|
||||
if len(results) == 0 {
|
||||
message = "SearXNG hat keine verwertbaren Webquellen geliefert"
|
||||
allowedResults := e.filterResearchEvidenceForThinking(results, unique(append(append([]string{}, a.Categories...), b.Categories...)))
|
||||
resultMetadata := mergeResearchMetadata(researchEventMetadata(trigger, researchID, decision.ResearchQuery, allowedResults, time.Since(researchStarted)), researchDiagnosticMetadata(diagnostic))
|
||||
resultMetadata["unfiltered_result_count"] = len(results)
|
||||
resultMetadata["source_filter_rejected_count"] = len(results) - len(allowedResults)
|
||||
message := fmt.Sprintf("SearXNG hat %d durch den Thinking-Filter erlaubte Webquellen geliefert", len(allowedResults))
|
||||
if len(allowedResults) == 0 {
|
||||
message = "SearXNG-Treffer lagen außerhalb des wirksamen Thinking-Quellenfilters"
|
||||
}
|
||||
e.Broker.Publish(model.Activity{Type: "research.results", Source: "searxng", Phase: "research-results", NodeIDs: []string{a.ID, b.ID}, Message: message, Strength: .92, Metadata: resultMetadata})
|
||||
if len(results) > 0 {
|
||||
researchResults = results
|
||||
refs := e.addResearch(a, b, results)
|
||||
if len(allowedResults) > 0 {
|
||||
researchResults = allowedResults
|
||||
refs := e.addResearch(a, b, allowedResults)
|
||||
ingestMetadata := mergeResearchMetadata(resultMetadata, map[string]any{"result_node_ids": refs.NodeIDs, "result_edge_ids": refs.EdgeIDs})
|
||||
e.Broker.Publish(model.Activity{Type: "research.ingested", Source: "searxng", Phase: "research-ingest", NodeIDs: append([]string{a.ID, b.ID}, refs.NodeIDs...), EdgeIDs: refs.EdgeIDs, Message: fmt.Sprintf("%d Webquellen wurden als neue Forschungs-Nodes in den Graphen übernommen", len(refs.NodeIDs)), Strength: 1, Metadata: ingestMetadata})
|
||||
var reviewed model.RelationDecision
|
||||
reviewSystem := "Bewerte die Beziehung erneut anhand der zwei internen Wissenseinträge und der beigefügten Web-Suchergebnisse. Suchtreffer sind Hinweise, keine garantierten Fakten. Erfinde nichts, kennzeichne verbleibende Unsicherheit und gib ausschließlich JSON nach Schema zurück."
|
||||
if err := e.Ollama.ChatJSON(ctx, reviewSystem, relationContextWithResearch(a, b, sim, results), relationSchema(), &reviewed); err != nil {
|
||||
if err := e.Ollama.ChatJSON(ctx, reviewSystem, relationContextWithResearch(a, b, sim, allowedResults), relationSchema(), &reviewed); err != nil {
|
||||
slog.Warn("research review failed; keeping pre-research decision", "error", err)
|
||||
} else {
|
||||
decision = reviewed
|
||||
@@ -743,7 +746,7 @@ func (e *Engine) addResearch(a, b model.Node, results []model.ResearchResult) re
|
||||
refs := researchGraphRefs{}
|
||||
for _, r := range results {
|
||||
id := graph.ID("external", r.URL)
|
||||
n := model.Node{ID: id, Kind: "external", Label: r.Title, Summary: clamp(r.Content, 700), Status: "research", Origin: "research", ExternalID: r.URL, URI: r.URL, Weight: .8, Metadata: map[string]any{"query_pair": []string{a.ID, b.ID}}, UpdatedAt: time.Now().UTC()}
|
||||
n := model.Node{ID: id, Kind: "external", Label: r.Title, Summary: clamp(r.Content, 700), Status: "research", Origin: "research", ExternalID: r.URL, URI: r.URL, Categories: unique(append(append([]string{}, a.Categories...), b.Categories...)), Weight: .8, Metadata: map[string]any{"query_pair": []string{a.ID, b.ID}}, UpdatedAt: time.Now().UTC()}
|
||||
e.Graph.UpsertNode(n)
|
||||
refs.NodeIDs = append(refs.NodeIDs, id)
|
||||
for _, targetID := range []string{a.ID, b.ID} {
|
||||
@@ -777,7 +780,7 @@ func (e *Engine) Status() map[string]any {
|
||||
"research_enabled": e.Cfg.ResearchEnabled, "chat_model": e.Cfg.ChatModel, "embedding_model": e.Cfg.EmbeddingModel,
|
||||
"searxng": e.ResearchStatus(),
|
||||
"ollama_pool": e.Ollama.PoolStatus(), "persistence": e.Persistence.Status(), "graph_storage": e.Graph.StorageStatus(),
|
||||
"runtime_settings": e.RuntimeSettings(),
|
||||
"runtime_settings": e.RuntimeSettingsView(),
|
||||
}
|
||||
if e.GLPIKB != nil {
|
||||
status["glpi_kb"] = e.GLPIKB.Status()
|
||||
|
||||
Reference in New Issue
Block a user