Skip to content

Commit c543831

Browse files
committed
feat(backend): enhance graphiti search tool with langfuse integration
- Added langfuse observability support to the graphiti search tool, allowing for detailed tracking of search operations. - Introduced a mapping of search types to human-readable titles for better traceability in logs. - Implemented a new method to build the input payload for langfuse retrievers, encapsulating relevant search parameters. - Enhanced error handling to include retriever status updates on success and failure, improving observability and debugging capabilities.
1 parent e909f40 commit c543831

1 file changed

Lines changed: 87 additions & 3 deletions

File tree

backend/pkg/tools/graphiti_search.go

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"pentagi/pkg/graphiti"
1111
obs "pentagi/pkg/observability"
12+
"pentagi/pkg/observability/langfuse"
1213

1314
"github.com/sirupsen/logrus"
1415
)
@@ -52,6 +53,18 @@ var (
5253
"medium": {},
5354
"high": {},
5455
}
56+
57+
// graphitiRetrieverTitles maps each search_type to a human-readable
58+
// langfuse observation title so the retrieval intent is clear in traces.
59+
graphitiRetrieverTitles = map[string]string{
60+
"temporal_window": "retrieve temporal window context from graphiti knowledge graph",
61+
"entity_relationships": "retrieve entity relationships from graphiti knowledge graph",
62+
"diverse_results": "retrieve diverse results from graphiti knowledge graph",
63+
"episode_context": "retrieve episode context from graphiti knowledge graph",
64+
"successful_tools": "retrieve successful tools from graphiti knowledge graph",
65+
"recent_context": "retrieve recent context from graphiti knowledge graph",
66+
"entity_by_label": "retrieve entities by label from graphiti knowledge graph",
67+
}
5568
)
5669

5770
// graphitiSearchTool provides search access to Graphiti knowledge graph
@@ -110,16 +123,36 @@ func (t *graphitiSearchTool) Handle(ctx context.Context, name string, args json.
110123
return "", fmt.Errorf("search_type parameter is required")
111124
}
112125

126+
// Get group ID from flow context
127+
groupID := fmt.Sprintf("flow-%d", t.flowID)
128+
113129
ctx, observation := obs.Observer.NewObservation(ctx)
130+
131+
retrieverTitle, ok := graphitiRetrieverTitles[searchArgs.SearchType]
132+
if !ok {
133+
retrieverTitle = "retrieve context from graphiti knowledge graph"
134+
}
135+
136+
retriever := observation.Retriever(
137+
langfuse.WithRetrieverName(retrieverTitle),
138+
langfuse.WithRetrieverInput(searchArgs.retrieverInput(groupID)),
139+
langfuse.WithRetrieverMetadata(langfuse.Metadata{
140+
"tool_name": name,
141+
"engine": "graphiti",
142+
"search_type": searchArgs.SearchType,
143+
"group_id": groupID,
144+
"query": searchArgs.Query,
145+
}),
146+
)
147+
ctx, observation = retriever.Observation(ctx)
148+
149+
// Nest Graphiti server-side observations under the retriever observation
114150
observationObject := &graphiti.Observation{
115151
ID: observation.ID(),
116152
TraceID: observation.TraceID(),
117153
Time: time.Now().UTC(),
118154
}
119155

120-
// Get group ID from flow context
121-
groupID := fmt.Sprintf("flow-%d", t.flowID)
122-
123156
// Route to appropriate search method
124157
var (
125158
err error
@@ -145,13 +178,64 @@ func (t *graphitiSearchTool) Handle(ctx context.Context, name string, args json.
145178
}
146179

147180
if err != nil {
181+
retriever.End(
182+
langfuse.WithRetrieverStatus(err.Error()),
183+
langfuse.WithRetrieverLevel(langfuse.ObservationLevelError),
184+
)
148185
logger.WithError(err).Errorf("failed to perform graphiti search '%s'", searchArgs.SearchType)
149186
return "", err
150187
}
151188

189+
retriever.End(
190+
langfuse.WithRetrieverStatus("success"),
191+
langfuse.WithRetrieverLevel(langfuse.ObservationLevelDebug),
192+
langfuse.WithRetrieverOutput(result),
193+
)
194+
152195
return result, nil
153196
}
154197

198+
// retrieverInput builds the langfuse retriever input payload, including only
199+
// the search parameters relevant to the requested search_type.
200+
func (args GraphitiSearchAction) retrieverInput(groupID string) map[string]any {
201+
input := map[string]any{
202+
"query": args.Query,
203+
"search_type": args.SearchType,
204+
"group_id": groupID,
205+
}
206+
if args.MaxResults != nil {
207+
input["max_results"] = args.MaxResults.Int()
208+
}
209+
if args.TimeStart != "" {
210+
input["time_start"] = args.TimeStart
211+
}
212+
if args.TimeEnd != "" {
213+
input["time_end"] = args.TimeEnd
214+
}
215+
if args.CenterNodeUUID != "" {
216+
input["center_node_uuid"] = args.CenterNodeUUID
217+
}
218+
if args.MaxDepth != nil {
219+
input["max_depth"] = args.MaxDepth.Int()
220+
}
221+
if len(args.NodeLabels) > 0 {
222+
input["node_labels"] = args.NodeLabels
223+
}
224+
if len(args.EdgeTypes) > 0 {
225+
input["edge_types"] = args.EdgeTypes
226+
}
227+
if args.DiversityLevel != "" {
228+
input["diversity_level"] = args.DiversityLevel
229+
}
230+
if args.MinMentions != nil {
231+
input["min_mentions"] = args.MinMentions.Int()
232+
}
233+
if args.RecencyWindow != "" {
234+
input["recency_window"] = args.RecencyWindow
235+
}
236+
return input
237+
}
238+
155239
// handleTemporalWindowSearch performs time-bounded search
156240
func (t *graphitiSearchTool) handleTemporalWindowSearch(
157241
ctx context.Context,

0 commit comments

Comments
 (0)