Skip to content

genai: typed condition fields and source-aware span addressing - #164

Merged
wu-sheng merged 1 commit into
masterfrom
genai/typed-condition-and-trace-ref
Aug 14, 2026
Merged

genai: typed condition fields and source-aware span addressing#164
wu-sheng merged 1 commit into
masterfrom
genai/typed-condition-and-trace-ref

Conversation

@wu-sheng

Copy link
Copy Markdown
Member

Follow-up to #163, from reviewing the OAP implementation in apache/skywalking#13943. No OAP submodule pointer references #163 yet, so these changes carry no client impact.

1. Remove tags and GenAIEvaluationRecordTag

A tags condition exists so callers can filter on key-values the protocol cannot enumerate. This record has none — it persists no user-supplied attribute.

The asymmetry is the tell: Log returns tags: [KeyValue!] and LogQueryCondition filters them, whereas GenAIEvaluationRecord has no tags field at all — so the condition filtered something the API never returns.

In the OAP implementation the accepted key set turns out to be the record's own column names: 11 of 15 are already typed fields on the same condition, and the remaining 4 (operation_name, span_type, evalStringValue, reason) are fixed columns of a record the protocol fully defines. Nothing in the set is custom.

2. Address the span by its source scheme

GenAI evaluation accepts SkyWalking native, OTLP and Zipkin traces. Native span ids are a segment-local int index; OTLP and Zipkin ids are 16 hex characters. spanId: String cannot describe both honestly — and in the implementation it is parsed into an int, which throws for every OTLP/Zipkin span.

GenAITraceRef makes the scheme explicit, and spanIndex is named for what it is: an index, not an identifier, unique only with segmentId.

This stays GenAI-scoped. spanId: Int in trace.graphqls, profile.graphqls and TraceScopeCondition is correctly scoped to native-trace addressing and does not change.

3. Split the value slots

scoreValue (SCORE) / booleanValue (BOOLEAN) / stringValue (STRING, JSON), so valueType genuinely discriminates. BOOLEAN previously shared scoreValue as 0 / 1000000, which meant minScore/maxScore silently spanned both types. valuestringValue for parallel naming; reason stays separate because it is orthogonal and populated for every task.

4. Drop spanType

SpanEvaluationType has exactly one value, LLM_CALL — nothing to query and nothing to display. Reintroduce as an enum if a second span kind appears.

5. Document entity scope and layer

Provider is a service and model is its instance, both Layer.VIRTUAL_GENAI, while serviceId is a normal agent-detected service. Stating this on the fields makes an entity-id mistake visible at review time.


Scores remain Long on the 1,000,000 ppm scale, unchanged — SkyWalking does not carry Float/Double in stored or transported values; the convention is Long with the code controlling precision.

OAP-side changes this requires

  • getScoreValue() returns the stored Long rather than dividing into a Double
  • the Java condition takes Long for minScore/maxScore; the DAOs stop re-scaling an already-scaled input
  • booleanValue wired through the condition and all three DAOs
  • spanId becomes a String column plus a ref_type column; the Integer.parseInt is removed
  • value_type loses storageOnly so it is filterable on Elasticsearch
  • QUERYABLE_TAG_KEYS deleted from the ES and JDBC DAOs, and the BanyanDB tag loop with it
  • the writer must always set valueType, now non-null

🤖 Generated with Claude Code

Follow-up to #163, from reviewing the OAP implementation in
apache/skywalking#13943. No OAP submodule pointer references #163 yet,
so these changes are free of client impact.

- Remove `tags` and `GenAIEvaluationRecordTag`. A tag condition exists to
  filter key-values the protocol cannot enumerate; this record persists no
  user-supplied attribute. `Log` returns `tags` and `LogQueryCondition`
  filters them, whereas `GenAIEvaluationRecord` has no `tags` field at all,
  so the condition filtered something the API never returns.
- Add `GenAITraceRef` / `GenAITraceRefType`. GenAI evaluation accepts native,
  OTLP and Zipkin traces. Native span ids are a segment-local int index;
  OTLP and Zipkin ids are 16 hex characters. `spanIndex` is named for what
  it is - an index, not an identifier. Scoped to GenAI: `spanId: Int`
  elsewhere is correctly scoped to native addressing and is unchanged.
- Split the value slots into `scoreValue` / `booleanValue` / `stringValue`
  so `valueType` genuinely discriminates. BOOLEAN previously shared
  `scoreValue`, so score-range filters spanned both types.
- Drop `spanType`: `SpanEvaluationType` has one value, so there is nothing
  to query and nothing to display.
- Document entity scope and layer on the id fields - provider is a service
  and model is its instance, both VIRTUAL_GENAI, while `serviceId` is a
  normal agent-detected service.

Scores remain `Long` on the ppm scale; SkyWalking does not carry
Float/Double in stored or transported values.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@wu-sheng wu-sheng added the enhancement New feature or request label Aug 14, 2026
@wu-sheng
wu-sheng requested a review from peachisai August 14, 2026 05:02
@wu-sheng
wu-sheng merged commit 7026430 into master Aug 14, 2026
@wu-sheng
wu-sheng deleted the genai/typed-condition-and-trace-ref branch August 14, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant