Is your feature request related to a problem? Please describe.
compose 在 FieldMapping 失败时抛出的大多是字符串错误,例如(来自 compose/workflow_test.go 的断言):
"field mapping from a struct field, but field not found. field=B"
"field mapping from a struct field, but field not exported."
这带来几个维护性问题:
下游 trace / 监控无法对错误分类
错误信息不含源/目标 node,定位要靠人肉
compose/state_test.go:115 有 TODO「how to trace this kind of error in the goroutine of processing stream」,缺结构化错误难以推进
buildFieldMappingConverter logic is incomplete #957 反映 buildFieldMappingConverter 逻辑不完整、PR fix(compose): pass through when field mapping input already matches target type #976 做 passthrough 优化,都没动错误结构
注:compose/field_mapping.go:419 已存在 typed error errInterfaceNotValidForFieldMapping,说明结构化错误是仓库认可的方向,只是没有推广。
Describe the solution you'd like
抽取统一的结构化错误,覆盖所有 FieldMapping 失败路径:
// compose/field_mapping.go
type FieldMappingError struct {
FromNode string
ToNode string
FromField string // 可空(passthrough 时)
ToField string // 可空
Reason FieldMappingErrorReason // FieldNotFound / FieldNotExported / TypeMismatch / InterfaceNotValid / ...
ExpectedType reflect.Type
ActualType reflect.Type
Cause error
}
func (e * FieldMappingError ) Error () string { /* 统一格式化 */ }
func (e * FieldMappingError ) Unwrap () error { return e .Cause }
迁移方式:
现有 errInterfaceNotValidForFieldMapping 收敛为 FieldMappingError{Reason: InterfaceNotValid},旧 type 保留为 deprecated alias 一个版本
其它字符串错误点改为构造 *FieldMappingError
Error() 输出的字符串格式保持向后兼容(用户已有的 strings.Contains 判断不会断)
Describe alternatives you've considered
保持现状 :错误仍是字符串,trace / IDE 无法利用。
仅靠 strings.Contains 匹配错误文案 :脆弱,文案一改即断,且拿不到 node 名。
每个错误点各自定义 typed error :碎片化,调用方要 errors.As 一长串类型。统一一个带 Reason 字段的类型更易用。
Additional context
愿意提交 PR。
Issue 2:OTel GenAI 语义约定原生 handler
Title(中) :[Proposal] 提供原生 OpenTelemetry handler,按 GenAI 语义约定为 ChatModel / Tool / Retriever / Graph / ADK 上报 span
Title(英) :[Proposal] First-party OpenTelemetry handler emitting GenAI semantic-convention spans across ChatModel / Tool / Retriever / Graph / ADK
Labels :C-feature-request, D-tracing, D-callback
Is your feature request related to a problem? Please describe.
要给 eino 应用接入可观测性,目前必须自行实现 callbacks.Handler。社区生态里有 Langfuse / cozeloop 两个实现(位于 eino-ext),但它们都是面向各自后端的专有映射 ,无法直接对接通用的 OTel collector / APM。eino-ext#328 提出 OTel 上报,但范围只限 Indexer / Retriever。
OpenTelemetry 已经发布 GenAI Semantic Conventions(gen_ai.system、gen_ai.request.model、gen_ai.usage.input_tokens、gen_ai.operation.name 等),主流框架普遍原生支持(Google ADK、Pydantic AI + Logfire、Mastra、LlamaIndex)。eino 缺一个框架自带、与后端解耦 的 OTel handler。这本质上是「切面扩展」能力的标准化输出。
Describe the solution you'd like
新增 callbacks/otel 包,提供一个标准 handler:
package otel
func NewHandler (tp trace.TracerProvider , mp metric.MeterProvider , opts ... Option ) callbacks.Handler
行为:
按 RunInfo.Component(model / tool / retriever / ...)映射到 gen_ai.operation.name(chat / execute_tool / embeddings / ...)。
OnStart 注入 gen_ai.request.*,OnEnd 注入 gen_ai.response.* 与 gen_ai.usage.*。
流式场景在 OnEndWithStreamOutput 内累计 token,stream 关闭时一次性落 span。
Graph / ADK 节点产生父 span,Component 调用作为子 span,形成完整调用树。
Metrics:gen_ai.client.token.usage、gen_ai.client.operation.duration 直方图。
分期:
一期:ChatModel / Tool / Embedding / Retriever / Indexer 的 span + 标准 attribute
二期:Graph 节点与 ADK Agent 的父子 span 层级 + AgentEvent 拓扑
三期:AgenticMessage(Responses API)的 reasoning / tool 双 span 表示
Describe alternatives you've considered
继续用 Langfuse / cozeloop handler :绑定特定后端,无法对接已有的 OTel collector / Jaeger / Tempo / 各类 APM。
由用户各自实现 OTel handler :每个团队重复造轮子,且很难统一遵循 GenAI semconv,trace 不可跨项目复用。
只做 metrics 不做 trace :丢失调用树,无法定位多 Agent / 多节点链路。
Additional context
愿意在 maintainer 认可方向后承担实现。
Is your feature request related to a problem? Please describe.
compose在 FieldMapping 失败时抛出的大多是字符串错误,例如(来自compose/workflow_test.go的断言):"field mapping from a struct field, but field not found. field=B""field mapping from a struct field, but field not exported."这带来几个维护性问题:
compose/state_test.go:115有 TODO「how to trace this kind of error in the goroutine of processing stream」,缺结构化错误难以推进buildFieldMappingConverter逻辑不完整、PR fix(compose): pass through when field mapping input already matches target type #976 做 passthrough 优化,都没动错误结构注:
compose/field_mapping.go:419已存在 typed errorerrInterfaceNotValidForFieldMapping,说明结构化错误是仓库认可的方向,只是没有推广。Describe the solution you'd like
抽取统一的结构化错误,覆盖所有 FieldMapping 失败路径:
迁移方式:
errInterfaceNotValidForFieldMapping收敛为FieldMappingError{Reason: InterfaceNotValid},旧 type 保留为 deprecated alias 一个版本*FieldMappingErrorError()输出的字符串格式保持向后兼容(用户已有的strings.Contains判断不会断)Describe alternatives you've considered
strings.Contains匹配错误文案:脆弱,文案一改即断,且拿不到 node 名。errors.As一长串类型。统一一个带Reason字段的类型更易用。Additional context
errors.As(err, &fme)拿到源/目标 node;切面 handler 可给 graph 节点补eino.fieldmapping.*属性;测试断言不再依赖字符串子串。compose/field_mapping.go、compose/workflow.go、compose/graph.go的错误构造点,附带更新测试断言。errors.As(err, *errInterfaceNotValidForFieldMapping)用法(保留一个版本兼容期)。compose/state_test.go:115TODO。愿意提交 PR。
Issue 2:OTel GenAI 语义约定原生 handler
Title(中):[Proposal] 提供原生 OpenTelemetry handler,按 GenAI 语义约定为 ChatModel / Tool / Retriever / Graph / ADK 上报 span
Title(英):
[Proposal] First-party OpenTelemetry handler emitting GenAI semantic-convention spans across ChatModel / Tool / Retriever / Graph / ADKLabels:
C-feature-request,D-tracing,D-callbackIs your feature request related to a problem? Please describe.
要给 eino 应用接入可观测性,目前必须自行实现
callbacks.Handler。社区生态里有 Langfuse / cozeloop 两个实现(位于 eino-ext),但它们都是面向各自后端的专有映射,无法直接对接通用的 OTel collector / APM。eino-ext#328 提出 OTel 上报,但范围只限 Indexer / Retriever。OpenTelemetry 已经发布 GenAI Semantic Conventions(
gen_ai.system、gen_ai.request.model、gen_ai.usage.input_tokens、gen_ai.operation.name等),主流框架普遍原生支持(Google ADK、Pydantic AI + Logfire、Mastra、LlamaIndex)。eino 缺一个框架自带、与后端解耦的 OTel handler。这本质上是「切面扩展」能力的标准化输出。Describe the solution you'd like
新增
callbacks/otel包,提供一个标准 handler:行为:
RunInfo.Component(model/tool/retriever/ ...)映射到gen_ai.operation.name(chat/execute_tool/embeddings/ ...)。OnStart注入gen_ai.request.*,OnEnd注入gen_ai.response.*与gen_ai.usage.*。OnEndWithStreamOutput内累计 token,stream 关闭时一次性落 span。gen_ai.client.token.usage、gen_ai.client.operation.duration直方图。分期:
Describe alternatives you've considered
Additional context
callbacks/langfuse。callbacks/otelvs eino-ext)可讨论;倾向主仓库,因为 OTel 是行业标准、且不引入重后端依赖。愿意在 maintainer 认可方向后承担实现。