0
# Ingestion API
1
2
The Ingestion API provides batched ingestion of tracing data for Langfuse. This is the primary API for tracing operations, supporting event deduplication and multiple event types in a single batch. The API handles traces, observations (spans, events, generations), and scores.
3
4
Note: The recommended approach for tracing is via OpenTelemetry instrumentation rather than direct Ingestion API usage, as it provides more detailed and standardized tracing without requiring manual batching and update handling.
5
6
## Capabilities
7
8
### IngestionClient
9
10
Client for batched ingestion of tracing events.
11
12
```java { .api }
13
/**
14
* Batched ingestion for Langfuse Tracing
15
*
16
* Features:
17
* - Event deduplication using event IDs
18
* - Multiple event types in a single batch
19
* - Batch size limit: 3.5 MB
20
* - Returns 207 Multi-Status with individual error details
21
* instead of 4xx for input errors
22
*
23
* @param request Batch of ingestion events
24
* @param requestOptions Optional request configuration
25
* @return Response with success/error details for each event
26
*/
27
IngestionResponse batch(IngestionRequest request);
28
IngestionResponse batch(IngestionRequest request, RequestOptions requestOptions);
29
```
30
31
**Usage Example:**
32
33
```java
34
import com.langfuse.client.LangfuseClient;
35
import com.langfuse.client.resources.ingestion.requests.IngestionRequest;
36
import com.langfuse.client.resources.ingestion.types.*;
37
import com.langfuse.client.resources.commons.types.CreateScoreValue;
38
import java.time.OffsetDateTime;
39
import java.util.List;
40
import java.util.Map;
41
42
LangfuseClient client = LangfuseClient.builder()
43
.url("https://cloud.langfuse.com")
44
.credentials("pk-lf-...", "sk-lf-...")
45
.build();
46
47
// Create a batch of events
48
// Note: All event types use staged builders requiring id(), timestamp(), body() in that order
49
IngestionRequest request = IngestionRequest.builder()
50
.batch(List.of(
51
// Trace event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()
52
IngestionEvent.traceCreate(TraceEvent.builder()
53
.id("event-trace-123") // Event ID for deduplication (required first)
54
.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String ISO 8601 (required second)
55
.body(TraceBody.builder() // Event body (required third)
56
.id("trace-123")
57
.name("User Query")
58
.userId("user-456")
59
.input(Map.of("query", "What is AI?"))
60
.timestamp(OffsetDateTime.now())
61
.build())
62
.metadata(Map.of("source", "api")) // Optional event metadata
63
.build()),
64
65
// Span event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()
66
IngestionEvent.spanCreate(CreateSpanEvent.builder()
67
.id("event-span-123") // Event ID for deduplication (required first)
68
.timestamp(OffsetDateTime.now().plusSeconds(1).toString()) // Event timestamp as String ISO 8601 (required second)
69
.body(CreateSpanBody.builder() // Event body (required third)
70
.id("span-123")
71
.traceId("trace-123")
72
.name("LLM Call")
73
.startTime(OffsetDateTime.now().plusSeconds(1))
74
.endTime(OffsetDateTime.now().plusSeconds(3))
75
.input(Map.of("prompt", "What is AI?"))
76
.output(Map.of("response", "AI is..."))
77
.build())
78
.build()),
79
80
// Score event - staged builder: id() -> timestamp() -> body() -> metadata() (optional) -> build()
81
IngestionEvent.scoreCreate(ScoreEvent.builder()
82
.id("event-score-123") // Event ID for deduplication (required first)
83
.timestamp(OffsetDateTime.now().plusSeconds(2).toString()) // Event timestamp as String ISO 8601 (required second)
84
.body(ScoreBody.builder() // Score body uses staged builder: name() -> value() -> other fields -> build()
85
.name("quality") // Required first: score name
86
.value(CreateScoreValue.of(0.95)) // Required second: score value as CreateScoreValue union
87
.id("score-123") // Optional: score ID (available in _FinalStage)
88
.traceId("trace-123") // Optional: trace ID
89
.build())
90
.build())
91
))
92
.build();
93
94
// Send batch
95
IngestionResponse response = client.ingestion().batch(request);
96
97
// Check results
98
for (IngestionSuccess success : response.getSuccesses()) {
99
System.out.println("Success: " + success.getId());
100
}
101
for (IngestionError error : response.getErrors()) {
102
System.err.println("Error: " + error.getId() + " - " + error.getMessage());
103
}
104
```
105
106
## Request Types
107
108
### IngestionRequest
109
110
```java { .api }
111
/**
112
* Batch ingestion request containing multiple events
113
*/
114
public final class IngestionRequest {
115
List<IngestionEvent> getBatch();
116
Optional<Object> getMetadata();
117
118
static Builder builder();
119
}
120
```
121
122
### IngestionEvent
123
124
Union type representing all possible event types.
125
126
```java { .api }
127
/**
128
* Union type for ingestion events
129
* Supports all event types for tracing
130
*/
131
public final class IngestionEvent {
132
// Factory methods for creating typed events
133
static IngestionEvent traceCreate(TraceEvent value);
134
static IngestionEvent scoreCreate(ScoreEvent value);
135
static IngestionEvent observationCreate(CreateObservationEvent value);
136
static IngestionEvent observationUpdate(UpdateObservationEvent value);
137
static IngestionEvent eventCreate(CreateEventEvent value);
138
static IngestionEvent spanCreate(CreateSpanEvent value);
139
static IngestionEvent spanUpdate(UpdateSpanEvent value);
140
static IngestionEvent generationCreate(CreateGenerationEvent value);
141
static IngestionEvent generationUpdate(UpdateGenerationEvent value);
142
static IngestionEvent sdkLog(SdkLogEvent value);
143
144
// Visitor pattern for type-safe access
145
<T> T visit(Visitor<T> visitor);
146
}
147
```
148
149
## Event Types
150
151
### TraceEvent
152
153
Create or update a trace.
154
155
```java { .api }
156
/**
157
* Event for creating/updating a trace
158
* Type: "trace-create"
159
*
160
* Staged Builder Pattern (required order):
161
* 1. id(String) - Event ID for deduplication
162
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
163
* 3. body(TraceBody) - Trace data
164
* 4. metadata(Object) - Optional SDK metadata
165
* 5. build() - Build the event
166
*/
167
public final class TraceEvent {
168
String getId(); // Event ID for deduplication
169
String getTimestamp(); // Event timestamp as String (ISO 8601)
170
Optional<Object> getMetadata(); // Optional SDK metadata
171
TraceBody getBody();
172
173
static IdStage builder(); // Returns staged builder starting with id()
174
}
175
```
176
177
### ScoreEvent
178
179
Create a score for a trace or observation.
180
181
```java { .api }
182
/**
183
* Event for creating a score
184
* Type: "score-create"
185
*
186
* Staged Builder Pattern (required order):
187
* 1. id(String) - Event ID for deduplication
188
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
189
* 3. body(ScoreBody) - Score data
190
* 4. metadata(Object) - Optional SDK metadata
191
* 5. build() - Build the event
192
*/
193
public final class ScoreEvent {
194
String getId(); // Event ID for deduplication
195
String getTimestamp(); // Event timestamp as String (ISO 8601)
196
Optional<Object> getMetadata(); // Optional SDK metadata
197
ScoreBody getBody();
198
199
static IdStage builder(); // Returns staged builder starting with id()
200
}
201
```
202
203
### Observation Events
204
205
Observations represent spans, events, and generations in traces.
206
207
```java { .api }
208
/**
209
* Event for creating an observation
210
* Type: "observation-create"
211
*
212
* Staged Builder Pattern (required order):
213
* 1. id(String) - Event ID for deduplication
214
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
215
* 3. body(ObservationBody) - Observation data
216
* 4. metadata(Object) - Optional SDK metadata
217
* 5. build() - Build the event
218
*/
219
public final class CreateObservationEvent {
220
String getId();
221
String getTimestamp();
222
Optional<Object> getMetadata();
223
ObservationBody getBody();
224
225
static IdStage builder();
226
}
227
228
/**
229
* Event for updating an observation
230
* Type: "observation-update"
231
*
232
* Staged Builder Pattern (required order):
233
* 1. id(String) - Event ID for deduplication
234
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
235
* 3. body(OptionalObservationBody) - Observation data
236
* 4. metadata(Object) - Optional SDK metadata
237
* 5. build() - Build the event
238
*/
239
public final class UpdateObservationEvent {
240
String getId();
241
String getTimestamp();
242
Optional<Object> getMetadata();
243
OptionalObservationBody getBody();
244
245
static IdStage builder();
246
}
247
```
248
249
### Span Events
250
251
Spans represent operations or sub-processes within a trace.
252
253
```java { .api }
254
/**
255
* Event for creating a span
256
* Type: "span-create"
257
*
258
* Staged Builder Pattern (required order):
259
* 1. id(String) - Event ID for deduplication
260
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
261
* 3. body(CreateSpanBody) - Span data
262
* 4. metadata(Object) - Optional SDK metadata
263
* 5. build() - Build the event
264
*/
265
public final class CreateSpanEvent {
266
String getId();
267
String getTimestamp();
268
Optional<Object> getMetadata();
269
CreateSpanBody getBody();
270
271
static IdStage builder();
272
}
273
274
/**
275
* Event for updating a span
276
* Type: "span-update"
277
*
278
* Staged Builder Pattern (required order):
279
* 1. id(String) - Event ID for deduplication
280
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
281
* 3. body(UpdateSpanBody) - Span data
282
* 4. metadata(Object) - Optional SDK metadata
283
* 5. build() - Build the event
284
*/
285
public final class UpdateSpanEvent {
286
String getId();
287
String getTimestamp();
288
Optional<Object> getMetadata();
289
UpdateSpanBody getBody();
290
291
static IdStage builder();
292
}
293
```
294
295
### Event Events
296
297
Events represent point-in-time occurrences within a trace.
298
299
```java { .api }
300
/**
301
* Event for creating an event
302
* Type: "event-create"
303
*
304
* Staged Builder Pattern (required order):
305
* 1. id(String) - Event ID for deduplication
306
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
307
* 3. body(CreateEventBody) - Event data
308
* 4. metadata(Object) - Optional SDK metadata
309
* 5. build() - Build the event
310
*/
311
public final class CreateEventEvent {
312
String getId();
313
String getTimestamp();
314
Optional<Object> getMetadata();
315
CreateEventBody getBody();
316
317
static IdStage builder();
318
}
319
```
320
321
### Generation Events
322
323
Generations represent LLM generation calls within a trace.
324
325
```java { .api }
326
/**
327
* Event for creating a generation
328
* Type: "generation-create"
329
*
330
* Staged Builder Pattern (required order):
331
* 1. id(String) - Event ID for deduplication
332
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
333
* 3. body(CreateGenerationBody) - Generation data
334
* 4. metadata(Object) - Optional SDK metadata
335
* 5. build() - Build the event
336
*/
337
public final class CreateGenerationEvent {
338
String getId();
339
String getTimestamp();
340
Optional<Object> getMetadata();
341
CreateGenerationBody getBody();
342
343
static IdStage builder();
344
}
345
346
/**
347
* Event for updating a generation
348
* Type: "generation-update"
349
*
350
* Staged Builder Pattern (required order):
351
* 1. id(String) - Event ID for deduplication
352
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
353
* 3. body(UpdateGenerationBody) - Generation data
354
* 4. metadata(Object) - Optional SDK metadata
355
* 5. build() - Build the event
356
*/
357
public final class UpdateGenerationEvent {
358
String getId();
359
String getTimestamp();
360
Optional<Object> getMetadata();
361
UpdateGenerationBody getBody();
362
363
static IdStage builder();
364
}
365
```
366
367
### SdkLogEvent
368
369
SDK log messages for debugging.
370
371
```java { .api }
372
/**
373
* Event for SDK log messages
374
* Type: "sdk-log"
375
*
376
* Staged Builder Pattern (required order):
377
* 1. id(String) - Event ID for deduplication
378
* 2. timestamp(String) - Event timestamp (ISO 8601 format)
379
* 3. body(SdkLogBody) - Log message data
380
* 4. metadata(Object) - Optional SDK metadata
381
* 5. build() - Build the event
382
*/
383
public final class SdkLogEvent {
384
String getId();
385
String getTimestamp();
386
Optional<Object> getMetadata();
387
SdkLogBody getBody();
388
389
static IdStage builder();
390
}
391
```
392
393
## Event Body Types
394
395
### TraceBody
396
397
```java { .api }
398
/**
399
* Trace data for trace events
400
*/
401
public final class TraceBody {
402
Optional<String> getId(); // Unique trace ID
403
Optional<OffsetDateTime> getTimestamp(); // Timestamp as OffsetDateTime
404
Optional<String> getName();
405
Optional<String> getUserId();
406
Optional<Object> getMetadata();
407
Optional<String> getRelease();
408
Optional<String> getVersion();
409
Optional<String> getSessionId();
410
Optional<Object> getInput();
411
Optional<Object> getOutput();
412
Optional<List<String>> getTags();
413
Optional<String> getEnvironment();
414
Optional<Boolean> getPublic(); // Make trace publicly accessible
415
416
static Builder builder();
417
}
418
```
419
420
### ScoreBody
421
422
```java { .api }
423
/**
424
* Score data for score events
425
* Uses staged builder: name() -> value() -> optional fields -> build()
426
*/
427
public final class ScoreBody {
428
Optional<String> getId(); // Unique score ID
429
Optional<String> getTraceId();
430
String getName(); // Required: score name
431
CreateScoreValue getValue(); // Required: Union type (String, Integer, or Double)
432
Optional<String> getSessionId();
433
Optional<String> getObservationId();
434
Optional<String> getDatasetRunId();
435
Optional<String> getComment();
436
Optional<Object> getMetadata();
437
Optional<ScoreDataType> getDataType(); // NUMERIC, CATEGORICAL, BOOLEAN
438
Optional<String> getConfigId();
439
Optional<String> getEnvironment();
440
441
static NameStage builder(); // Returns staged builder starting with name()
442
}
443
```
444
445
### ObservationBody
446
447
```java { .api }
448
/**
449
* Observation data (for spans, events, generations)
450
*/
451
public final class ObservationBody {
452
Optional<String> getId(); // Unique observation ID
453
Optional<String> getTraceId();
454
ObservationType getType(); // SPAN, EVENT, GENERATION (required)
455
Optional<String> getName();
456
Optional<OffsetDateTime> getStartTime(); // Start time as OffsetDateTime
457
Optional<OffsetDateTime> getEndTime(); // End time as OffsetDateTime
458
Optional<OffsetDateTime> getCompletionStartTime(); // Completion start time as OffsetDateTime
459
Optional<String> getModel();
460
Optional<Map<String, MapValue>> getModelParameters();
461
Optional<Object> getInput();
462
Optional<Object> getOutput();
463
Optional<Usage> getUsage(); // Token/cost usage (from commons.types)
464
Optional<Object> getMetadata();
465
Optional<ObservationLevel> getLevel(); // DEBUG, DEFAULT, WARNING, ERROR
466
Optional<String> getStatusMessage();
467
Optional<String> getParentObservationId();
468
Optional<String> getVersion();
469
Optional<String> getEnvironment();
470
471
static Builder builder();
472
}
473
```
474
475
### OptionalObservationBody
476
477
```java { .api }
478
/**
479
* Observation data with all optional fields (for updates)
480
* Contains a subset of ObservationBody fields, all optional
481
*/
482
public final class OptionalObservationBody {
483
Optional<String> getTraceId();
484
Optional<String> getName();
485
Optional<OffsetDateTime> getStartTime(); // Start time as OffsetDateTime
486
Optional<Object> getMetadata();
487
Optional<Object> getInput();
488
Optional<Object> getOutput();
489
Optional<ObservationLevel> getLevel();
490
Optional<String> getStatusMessage();
491
Optional<String> getParentObservationId();
492
Optional<String> getVersion();
493
Optional<String> getEnvironment();
494
495
static Builder builder();
496
}
497
```
498
499
### Typed Observation Bodies
500
501
```java { .api }
502
/**
503
* Span-specific body
504
* Shares fields with ObservationBody through interface implementation
505
*/
506
public final class CreateSpanBody {
507
// Has all ObservationBody fields
508
static Builder builder();
509
}
510
511
/**
512
* Update span body
513
* Shares fields with OptionalObservationBody through interface implementation
514
*/
515
public final class UpdateSpanBody {
516
static Builder builder();
517
}
518
519
/**
520
* Event-specific body
521
* Shares fields with ObservationBody through interface implementation
522
*/
523
public final class CreateEventBody {
524
static Builder builder();
525
}
526
527
/**
528
* Update event body
529
* Shares fields with OptionalObservationBody through interface implementation
530
*/
531
public final class UpdateEventBody {
532
static Builder builder();
533
}
534
535
/**
536
* Generation-specific body
537
* Shares fields with ObservationBody through interface implementation
538
*/
539
public final class CreateGenerationBody {
540
static Builder builder();
541
}
542
543
/**
544
* Update generation body
545
* Shares fields with OptionalObservationBody through interface implementation
546
*/
547
public final class UpdateGenerationBody {
548
static Builder builder();
549
}
550
```
551
552
### SdkLogBody
553
554
```java { .api }
555
/**
556
* SDK log message data
557
*/
558
public final class SdkLogBody {
559
String getLog(); // Log message content
560
561
static Builder builder();
562
}
563
```
564
565
## Usage Types
566
567
### IngestionUsage
568
569
Union type for different usage formats.
570
571
```java { .api }
572
/**
573
* Union type for usage information
574
* Supports OpenAI usage formats and custom usage details
575
*/
576
public final class IngestionUsage {
577
static IngestionUsage openAiUsage(OpenAiUsage value);
578
static IngestionUsage usageDetails(UsageDetails value);
579
580
<T> T visit(Visitor<T> visitor);
581
}
582
```
583
584
### OpenAiUsage
585
586
OpenAI-style usage with token counts.
587
588
```java { .api }
589
/**
590
* OpenAI usage with token counts
591
*/
592
public final class OpenAiUsage {
593
Optional<Integer> getPromptTokens();
594
Optional<Integer> getCompletionTokens();
595
Optional<Integer> getTotalTokens();
596
597
static Builder builder();
598
}
599
```
600
601
### OpenAiCompletionUsageSchema
602
603
```java { .api }
604
/**
605
* OpenAI completion usage schema
606
*/
607
public final class OpenAiCompletionUsageSchema {
608
Optional<Integer> getPromptTokens();
609
Optional<Integer> getCompletionTokens();
610
Optional<Integer> getTotalTokens();
611
612
static Builder builder();
613
}
614
```
615
616
### OpenAiResponseUsageSchema
617
618
```java { .api }
619
/**
620
* Extended OpenAI response usage schema
621
*/
622
public final class OpenAiResponseUsageSchema {
623
Optional<Integer> getPromptTokens();
624
Optional<Integer> getCompletionTokens();
625
Optional<Integer> getTotalTokens();
626
// Extended fields for detailed token breakdown
627
628
static Builder builder();
629
}
630
```
631
632
### UsageDetails
633
634
```java { .api }
635
/**
636
* Union type for detailed usage information
637
* Use static factory methods to create instances
638
*/
639
public final class UsageDetails {
640
// Factory methods for creating UsageDetails
641
static UsageDetails of(Map<String, Integer> value); // Custom usage map
642
static UsageDetails of(OpenAiCompletionUsageSchema value); // OpenAI completion usage
643
static UsageDetails of(OpenAiResponseUsageSchema value); // OpenAI response usage
644
645
// Visitor pattern for type-safe access
646
<T> T visit(Visitor<T> visitor);
647
}
648
```
649
650
## Response Types
651
652
### IngestionResponse
653
654
```java { .api }
655
/**
656
* Response from batch ingestion
657
* HTTP 207 Multi-Status with individual event results
658
*/
659
public final class IngestionResponse {
660
List<IngestionSuccess> getSuccesses();
661
List<IngestionError> getErrors();
662
663
static Builder builder();
664
}
665
```
666
667
### IngestionSuccess
668
669
```java { .api }
670
/**
671
* Successful ingestion of an event
672
*/
673
public final class IngestionSuccess {
674
String getId(); // Event ID
675
int getStatus(); // HTTP status (200, 201, etc.)
676
677
static Builder builder();
678
}
679
```
680
681
### IngestionError
682
683
```java { .api }
684
/**
685
* Failed ingestion of an event
686
*/
687
public final class IngestionError {
688
String getId(); // Event ID
689
int getStatus(); // HTTP status (400, 422, etc.)
690
String getMessage(); // Error message
691
Optional<String> getError(); // Additional error details
692
693
static Builder builder();
694
}
695
```
696
697
## Enums
698
699
### ObservationType
700
701
```java { .api }
702
/**
703
* Type of observation
704
*/
705
public enum ObservationType {
706
SPAN,
707
EVENT,
708
GENERATION
709
}
710
```
711
712
### ObservationLevel
713
714
```java { .api }
715
/**
716
* Log level for observations
717
*/
718
public enum ObservationLevel {
719
DEBUG,
720
DEFAULT,
721
WARNING,
722
ERROR
723
}
724
```
725
726
### ModelUsageUnit
727
728
```java { .api }
729
/**
730
* Unit for usage measurement
731
*/
732
public enum ModelUsageUnit {
733
CHARACTERS,
734
TOKENS,
735
REQUESTS,
736
IMAGES,
737
SECONDS
738
}
739
```
740
741
### ScoreDataType
742
743
```java { .api }
744
/**
745
* Data type for scores
746
*/
747
public enum ScoreDataType {
748
NUMERIC,
749
CATEGORICAL,
750
BOOLEAN
751
}
752
```
753
754
## Complete Tracing Example
755
756
```java
757
import com.langfuse.client.LangfuseClient;
758
import com.langfuse.client.resources.ingestion.requests.IngestionRequest;
759
import com.langfuse.client.resources.ingestion.types.*;
760
import com.langfuse.client.resources.commons.types.CreateScoreValue;
761
import java.time.OffsetDateTime;
762
import java.util.List;
763
import java.util.Map;
764
765
public class TracingExample {
766
public static void main(String[] args) {
767
LangfuseClient client = LangfuseClient.builder()
768
.url("https://cloud.langfuse.com")
769
.credentials("pk-lf-...", "sk-lf-...")
770
.build();
771
772
String traceId = "trace-" + System.currentTimeMillis();
773
String spanId = "span-" + System.currentTimeMillis();
774
String generationId = "gen-" + System.currentTimeMillis();
775
776
IngestionRequest request = IngestionRequest.builder()
777
.batch(List.of(
778
// 1. Create trace - Note: Staged builder requires id() -> timestamp() -> body()
779
IngestionEvent.traceCreate(TraceEvent.builder()
780
.id("event-" + traceId) // Event ID for deduplication
781
.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String (ISO 8601)
782
.body(TraceBody.builder() // Trace body data
783
.id(traceId)
784
.name("Chat Completion")
785
.userId("user-123")
786
.sessionId("session-456")
787
.input(Map.of("message", "Hello, AI!"))
788
.timestamp(OffsetDateTime.now())
789
.tags(List.of("chat", "production"))
790
.build())
791
.build()),
792
793
// 2. Create span for preprocessing - Staged builder: id() -> timestamp() -> body()
794
IngestionEvent.spanCreate(CreateSpanEvent.builder()
795
.id("event-" + spanId) // Event ID for deduplication
796
.timestamp(OffsetDateTime.now().toString()) // Event timestamp as String (ISO 8601)
797
.body(CreateSpanBody.builder() // Span body data
798
.id(spanId)
799
.traceId(traceId)
800
.name("Preprocess Input")
801
.startTime(OffsetDateTime.now())
802
.endTime(OffsetDateTime.now().plusSeconds(1))
803
.input(Map.of("raw", "Hello, AI!"))
804
.output(Map.of("processed", "hello ai"))
805
.build())
806
.build()),
807
808
// 3. Create generation for LLM call - Staged builder: id() -> timestamp() -> body()
809
IngestionEvent.generationCreate(CreateGenerationEvent.builder()
810
.id("event-" + generationId) // Event ID for deduplication
811
.timestamp(OffsetDateTime.now().plusSeconds(1).toString()) // Event timestamp as String (ISO 8601)
812
.body(CreateGenerationBody.builder() // Generation body data
813
.id(generationId)
814
.traceId(traceId)
815
.parentObservationId(spanId)
816
.name("OpenAI Chat")
817
.model("gpt-4")
818
.startTime(OffsetDateTime.now().plusSeconds(1))
819
.endTime(OffsetDateTime.now().plusSeconds(3))
820
.input(Map.of("messages", List.of(
821
Map.of("role", "user", "content", "Hello, AI!")
822
)))
823
.output(Map.of("content", "Hello! How can I help you?"))
824
.usage(IngestionUsage.openAiUsage(
825
OpenAiUsage.builder()
826
.promptTokens(10)
827
.completionTokens(8)
828
.totalTokens(18)
829
.build()
830
))
831
.build())
832
.build()),
833
834
// 4. Add quality score - Staged builder: id() -> timestamp() -> body()
835
IngestionEvent.scoreCreate(ScoreEvent.builder()
836
.id("event-score-" + System.currentTimeMillis()) // Event ID for deduplication
837
.timestamp(OffsetDateTime.now().plusSeconds(3).toString()) // Event timestamp as String (ISO 8601)
838
.body(ScoreBody.builder() // Score body uses staged builder: name() -> value() -> optional fields
839
.name("quality") // Required first: score name
840
.value(CreateScoreValue.of(0.95)) // Required second: score value
841
.id("score-" + System.currentTimeMillis()) // Optional: available in _FinalStage
842
.traceId(traceId) // Optional: trace ID
843
.dataType(ScoreDataType.NUMERIC) // Optional: data type
844
.build())
845
.build())
846
))
847
.build();
848
849
// Send batch
850
IngestionResponse response = client.ingestion().batch(request);
851
852
// Handle results
853
System.out.println("Successes: " + response.getSuccesses().size());
854
System.out.println("Errors: " + response.getErrors().size());
855
856
for (IngestionError error : response.getErrors()) {
857
System.err.println("Failed event " + error.getId() + ": " + error.getMessage());
858
}
859
}
860
}
861
```
862
863
## Best Practices
864
865
1. **Use Event IDs for Deduplication**: Always provide unique event IDs to enable deduplication on retries
866
2. **Batch Related Events**: Send related events (trace + observations + scores) in a single batch
867
3. **Handle Partial Failures**: Check both successes and errors in the response (207 Multi-Status)
868
4. **Stay Under Size Limit**: Keep batch sizes under 3.5 MB
869
5. **Use Timestamps**: Provide accurate ISO 8601 timestamps for all events
870
6. **Link Observations**: Use `traceId` and `parentObservationId` to build trace hierarchy
871
7. **Prefer OpenTelemetry**: For production use, consider OpenTelemetry instrumentation instead
872
873
## Related Documentation
874
875
- [Traces and Observations](./traces-observations.md) - Retrieving and managing traces
876
- [Scores](./scores.md) - Score management and configuration
877
- [Common Types](./common-types.md) - Shared type definitions
878