mingx 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mingx/__init__.py +50 -0
- mingx/_default_attributes.py +76 -0
- mingx/_trace.py +147 -0
- mingx/adapters/__init__.py +21 -0
- mingx/adapters/base.py +77 -0
- mingx/adapters/langchain.py +646 -0
- mingx/decorator.py +185 -0
- mingx/genai/__init__.py +99 -0
- mingx/genai/attributes.py +176 -0
- mingx/genai/io.py +439 -0
- mingx/genai/span_attributes.py +172 -0
- mingx/genai/spans.py +175 -0
- mingx-0.1.0.dist-info/METADATA +373 -0
- mingx-0.1.0.dist-info/RECORD +15 -0
- mingx-0.1.0.dist-info/WHEEL +4 -0
mingx/genai/spans.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenTelemetry GenAI span factories and context managers.
|
|
3
|
+
|
|
4
|
+
Creates spans that follow GenAI semantic conventions (span names, attributes, SpanKind).
|
|
5
|
+
Uses mingx._trace.get_tracer() for consistency with global TracerProvider.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
from typing import Any, Dict, Iterator, Optional
|
|
12
|
+
|
|
13
|
+
from opentelemetry.trace import SpanKind, Status, StatusCode
|
|
14
|
+
|
|
15
|
+
from mingx._trace import get_tracer
|
|
16
|
+
|
|
17
|
+
from . import attributes as attrs
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@contextmanager
|
|
21
|
+
def inference_span(
|
|
22
|
+
operation_name: str,
|
|
23
|
+
provider_name: str,
|
|
24
|
+
*,
|
|
25
|
+
model: Optional[str] = None,
|
|
26
|
+
temperature: Optional[float] = None,
|
|
27
|
+
max_tokens: Optional[int] = None,
|
|
28
|
+
**extra_attributes: Any,
|
|
29
|
+
) -> Iterator[Any]:
|
|
30
|
+
"""
|
|
31
|
+
Context manager for an inference (chat/completion) span.
|
|
32
|
+
|
|
33
|
+
Span name: {operation_name} {model}. SpanKind CLIENT.
|
|
34
|
+
"""
|
|
35
|
+
tracer = get_tracer()
|
|
36
|
+
name = attrs.inference_span_name(operation_name, model)
|
|
37
|
+
base = attrs.inference_attributes(
|
|
38
|
+
operation_name,
|
|
39
|
+
provider_name,
|
|
40
|
+
model=model,
|
|
41
|
+
temperature=temperature,
|
|
42
|
+
max_tokens=max_tokens,
|
|
43
|
+
)
|
|
44
|
+
base.update(extra_attributes)
|
|
45
|
+
with tracer.start_as_current_span(name, kind=SpanKind.CLIENT, attributes=base) as span:
|
|
46
|
+
try:
|
|
47
|
+
yield span
|
|
48
|
+
except Exception as e:
|
|
49
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
50
|
+
span.record_exception(e)
|
|
51
|
+
span.set_attribute(attrs.ERROR_TYPE, type(e).__name__)
|
|
52
|
+
raise
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@contextmanager
|
|
56
|
+
def embeddings_span(
|
|
57
|
+
provider_name: str,
|
|
58
|
+
*,
|
|
59
|
+
model: Optional[str] = None,
|
|
60
|
+
**extra_attributes: Any,
|
|
61
|
+
) -> Iterator[Any]:
|
|
62
|
+
"""Context manager for an embeddings span. SpanKind CLIENT."""
|
|
63
|
+
tracer = get_tracer()
|
|
64
|
+
name = attrs.embeddings_span_name(model)
|
|
65
|
+
base = attrs.embeddings_attributes(provider_name, model=model)
|
|
66
|
+
base.update(extra_attributes)
|
|
67
|
+
with tracer.start_as_current_span(name, kind=SpanKind.CLIENT, attributes=base) as span:
|
|
68
|
+
try:
|
|
69
|
+
yield span
|
|
70
|
+
except Exception as e:
|
|
71
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
72
|
+
span.record_exception(e)
|
|
73
|
+
span.set_attribute(attrs.ERROR_TYPE, type(e).__name__)
|
|
74
|
+
raise
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@contextmanager
|
|
78
|
+
def execute_tool_span(
|
|
79
|
+
tool_name: str,
|
|
80
|
+
*,
|
|
81
|
+
tool_description: Optional[str] = None,
|
|
82
|
+
tool_call_id: Optional[str] = None,
|
|
83
|
+
tool_type: Optional[str] = None,
|
|
84
|
+
**extra_attributes: Any,
|
|
85
|
+
) -> Iterator[Any]:
|
|
86
|
+
"""
|
|
87
|
+
Context manager for an execute_tool span.
|
|
88
|
+
|
|
89
|
+
Span name: execute_tool {tool_name}. SpanKind INTERNAL.
|
|
90
|
+
"""
|
|
91
|
+
tracer = get_tracer()
|
|
92
|
+
name = attrs.execute_tool_span_name(tool_name)
|
|
93
|
+
base = attrs.execute_tool_attributes(
|
|
94
|
+
tool_name,
|
|
95
|
+
tool_description=tool_description,
|
|
96
|
+
tool_call_id=tool_call_id,
|
|
97
|
+
tool_type=tool_type,
|
|
98
|
+
)
|
|
99
|
+
base.update(extra_attributes)
|
|
100
|
+
with tracer.start_as_current_span(name, kind=SpanKind.INTERNAL, attributes=base) as span:
|
|
101
|
+
try:
|
|
102
|
+
yield span
|
|
103
|
+
except Exception as e:
|
|
104
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
105
|
+
span.record_exception(e)
|
|
106
|
+
span.set_attribute(attrs.ERROR_TYPE, type(e).__name__)
|
|
107
|
+
raise
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def build_inference_span_args(
|
|
111
|
+
operation_name: str,
|
|
112
|
+
provider_name: str,
|
|
113
|
+
*,
|
|
114
|
+
model: Optional[str] = None,
|
|
115
|
+
temperature: Optional[float] = None,
|
|
116
|
+
max_tokens: Optional[int] = None,
|
|
117
|
+
top_p: Optional[float] = None,
|
|
118
|
+
top_k: Optional[int] = None,
|
|
119
|
+
frequency_penalty: Optional[float] = None,
|
|
120
|
+
presence_penalty: Optional[float] = None,
|
|
121
|
+
stop_sequences: Optional[list[str]] = None,
|
|
122
|
+
**extra: Any,
|
|
123
|
+
) -> tuple[str, Dict[str, Any]]:
|
|
124
|
+
"""
|
|
125
|
+
Return (span_name, attributes) for an inference span.
|
|
126
|
+
Adapters can call tracer.start_as_current_span(name, attributes=attrs) with this.
|
|
127
|
+
"""
|
|
128
|
+
name = attrs.inference_span_name(operation_name, model)
|
|
129
|
+
base = attrs.inference_attributes(
|
|
130
|
+
operation_name,
|
|
131
|
+
provider_name,
|
|
132
|
+
model=model,
|
|
133
|
+
temperature=temperature,
|
|
134
|
+
max_tokens=max_tokens,
|
|
135
|
+
top_p=top_p,
|
|
136
|
+
top_k=top_k,
|
|
137
|
+
frequency_penalty=frequency_penalty,
|
|
138
|
+
presence_penalty=presence_penalty,
|
|
139
|
+
stop_sequences=stop_sequences,
|
|
140
|
+
)
|
|
141
|
+
base.update(extra)
|
|
142
|
+
return name, base
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def build_execute_tool_span_args(
|
|
146
|
+
tool_name: str,
|
|
147
|
+
*,
|
|
148
|
+
tool_description: Optional[str] = None,
|
|
149
|
+
tool_call_id: Optional[str] = None,
|
|
150
|
+
tool_type: Optional[str] = None,
|
|
151
|
+
**extra: Any,
|
|
152
|
+
) -> tuple[str, Dict[str, Any]]:
|
|
153
|
+
"""Return (span_name, attributes) for an execute_tool span."""
|
|
154
|
+
name = attrs.execute_tool_span_name(tool_name)
|
|
155
|
+
base = attrs.execute_tool_attributes(
|
|
156
|
+
tool_name,
|
|
157
|
+
tool_description=tool_description,
|
|
158
|
+
tool_call_id=tool_call_id,
|
|
159
|
+
tool_type=tool_type,
|
|
160
|
+
)
|
|
161
|
+
base.update(extra)
|
|
162
|
+
return name, base
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def build_embeddings_span_args(
|
|
166
|
+
provider_name: str,
|
|
167
|
+
*,
|
|
168
|
+
model: Optional[str] = None,
|
|
169
|
+
**extra: Any,
|
|
170
|
+
) -> tuple[str, Dict[str, Any]]:
|
|
171
|
+
"""Return (span_name, attributes) for an embeddings span."""
|
|
172
|
+
name = attrs.embeddings_span_name(model)
|
|
173
|
+
base = attrs.embeddings_attributes(provider_name, model=model)
|
|
174
|
+
base.update(extra)
|
|
175
|
+
return name, base
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mingx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenTelemetry trace Python SDK with GenAI semantic conventions, LangChain/LangGraph callbacks, and method-level @traced decorator
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: opentelemetry-api>=1.20.0
|
|
7
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0
|
|
8
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
|
|
9
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: langchain-core>=0.2.0; extra == 'dev'
|
|
12
|
+
Requires-Dist: langchain-openai>=1.1.7; extra == 'dev'
|
|
13
|
+
Requires-Dist: langgraph>=1.0.7; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
16
|
+
Provides-Extra: examples
|
|
17
|
+
Requires-Dist: langchain>=0.3.0; extra == 'examples'
|
|
18
|
+
Requires-Dist: langgraph>=0.2.0; extra == 'examples'
|
|
19
|
+
Provides-Extra: langchain
|
|
20
|
+
Requires-Dist: langchain>=0.3.0; extra == 'langchain'
|
|
21
|
+
Provides-Extra: langgraph
|
|
22
|
+
Requires-Dist: langgraph>=0.2.0; extra == 'langgraph'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# mingx
|
|
26
|
+
|
|
27
|
+
基于 OpenTelemetry 的 Trace Python SDK,具备:
|
|
28
|
+
|
|
29
|
+
- **OpenTelemetry GenAI 语义规范**:所有上报 Span 符合 GenAI 约定
|
|
30
|
+
- **可扩展适配器**:支持 LangChain、LangGraph,后续可扩展 CrewAI、Google ADK 等
|
|
31
|
+
- **默认输入/输出**:适配器默认记录所有节点的入参(输入)与返回值(输出),无返回值记空
|
|
32
|
+
- **手动上报**:原生 OTEL 风格 `with get_tracer().start_as_current_span("name") as span:` + `span_input` / `span_output` 按需添加输入或输出,支持自定义属性/Event
|
|
33
|
+
- **LangChain & LangGraph**:通过 Callback 上报(非自动插桩)
|
|
34
|
+
- **方法级跟踪**:通过 `@traced` 装饰器为任意方法自动建 Span,默认记录入参(输入)与返回值(输出)
|
|
35
|
+
|
|
36
|
+
## 安装
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv add mingx
|
|
40
|
+
# 或: pip install mingx
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
示例与可选依赖:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv add mingx[examples]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 快速开始
|
|
50
|
+
|
|
51
|
+
### 配置 Tracer 与装饰器
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from mingx import configure_tracer_provider, traced
|
|
55
|
+
|
|
56
|
+
# OTLP over gRPC(默认,端口 4317)
|
|
57
|
+
configure_tracer_provider("my-app", otlp_endpoint="http://localhost:4317")
|
|
58
|
+
|
|
59
|
+
# OTLP over HTTP/Protobuf(端口 4318)
|
|
60
|
+
configure_tracer_provider("my-app", otlp_endpoint="http://localhost:4318", protocol="http")
|
|
61
|
+
|
|
62
|
+
# 设置 API Key 与默认属性(workspace_id、user_id)
|
|
63
|
+
# 鉴权支持 Bearer(默认)或 Basic,通过 auth_scheme 选择
|
|
64
|
+
configure_tracer_provider(
|
|
65
|
+
"my-app",
|
|
66
|
+
otlp_endpoint="https://your-collector.example.com",
|
|
67
|
+
protocol="http",
|
|
68
|
+
api_key="your-api-key",
|
|
69
|
+
auth_scheme="bearer", # 默认 "bearer";Basic 时传 auth_scheme="basic"(api_key 可为 base64(user:pass))
|
|
70
|
+
workspace_id="ws-001",
|
|
71
|
+
user_id="user-123",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@traced # 默认 record_io=True,会记录函数入参与返回值
|
|
75
|
+
def my_function():
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
# span_type 在装饰器或适配器中设置,不在此处;可关闭输入/输出:@traced(record_io=False)
|
|
79
|
+
@traced(name="custom_span", span_type="model", attributes={"key": "value"})
|
|
80
|
+
def another():
|
|
81
|
+
...
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### LangChain / LangGraph 使用 Callback
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from mingx import get_langchain_callback
|
|
88
|
+
|
|
89
|
+
handler = get_langchain_callback()
|
|
90
|
+
chain.invoke({"input": "..."}, config={"callbacks": [handler]})
|
|
91
|
+
# 或 LangGraph:
|
|
92
|
+
graph.invoke({"messages": [...]}, config={"callbacks": [handler]})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 手动上报(span_input / span_output)
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from mingx import get_tracer, span_input, span_output
|
|
99
|
+
|
|
100
|
+
with get_tracer().start_as_current_span("call_model") as span:
|
|
101
|
+
span_input({"prompt": "..."}) # 可选:attributes=..., event_attributes=...
|
|
102
|
+
result = call_model()
|
|
103
|
+
span_output(result)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
详见下文「输入/输出记录」中的「手动上报输入/输出」。
|
|
107
|
+
|
|
108
|
+
## 默认属性与 Baggage
|
|
109
|
+
|
|
110
|
+
| 属性名 | 说明 | 设置方式 |
|
|
111
|
+
|--------|------|----------|
|
|
112
|
+
| `span_id` | Span ID | 默认属性,无需设置 |
|
|
113
|
+
| `trace_id` | Trace ID | 默认属性,无需设置 |
|
|
114
|
+
| `span_status` | span状态 | OK(成功)、UNSET(未上传,默认状态)、ERROR(错误)默认属性,无需设置 |
|
|
115
|
+
| `span_code` | span状态码 | UNSET = 0、OK = 1、ERROR = 2,默认属性,无需设置 |
|
|
116
|
+
| `reference_parent_span_id` | 父级spanID | 默认属性,无需设置 |
|
|
117
|
+
| `start_time` | 开始时间 | 默认属性,无需设置 |
|
|
118
|
+
| `end_time` | 结束时间 | 默认属性,无需设置 |
|
|
119
|
+
| `duration` | 时间差 | 默认属性,无需设置 |
|
|
120
|
+
| `operation_name` | span name | `@traced(name="custom_span")`方式指定 |
|
|
121
|
+
| `mingx.workspace_id` | 工作空间 ID | `configure_tracer_provider(..., workspace_id=...)` 或 Baggage |
|
|
122
|
+
| `mingx.user.id` | 用户 ID | `configure_tracer_provider(..., user_id=...)` 或 Baggage |
|
|
123
|
+
| `mingx.span_type` | Span 节点类型 | **不在初始化时设置**:由 `@traced(span_type=...)` 或适配器按调用类型自动设置 |
|
|
124
|
+
|
|
125
|
+
**span_type** 可选值(可扩展):`model`(大模型)、`retriever`(知识库召回)、`tool`(Tool Call)、`chain`、`agent` 等。
|
|
126
|
+
- 使用 **@traced** 时:`@traced(span_type="model")` 或 `@traced(span_type=SPAN_TYPE_TOOL)` 手动指定。
|
|
127
|
+
- 使用 **LangChain/LangGraph 适配器** 时:根据回调自动设置(LLM→model、Tool→tool、Retriever→retriever、Chain→chain)。
|
|
128
|
+
|
|
129
|
+
**Baggage**:跨服务/跨请求时可在入口设置 Baggage,SDK 会优先从 Baggage 读取上述键并写入 Span。`use_baggage=True`(默认)启用。
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from opentelemetry.baggage import set_baggage
|
|
133
|
+
|
|
134
|
+
set_baggage("mingx.workspace_id", "ws-001")
|
|
135
|
+
set_baggage("mingx.user.id", "user-123")
|
|
136
|
+
# span_type 也可通过 Baggage 覆盖(如上游已设置)
|
|
137
|
+
set_baggage("mingx.span_type", "model")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 输入/输出记录(Event 优先)
|
|
141
|
+
|
|
142
|
+
**默认行为**:适配器会**默认记录所有节点**的入参(输入)与返回值(输出);无返回值时记空即可。
|
|
143
|
+
模型的输入/输出按 **OpenTelemetry GenAI** 语义记录,与 Traceloop 等 SDK 一致:**优先使用 Span Event**,其次可选 Span 属性。
|
|
144
|
+
|
|
145
|
+
| 方式 | 说明 |
|
|
146
|
+
|------|------|
|
|
147
|
+
| **Event(推荐)** | 在 Span 上打两条 Event:`gen_ai.input`(属性 `gen_ai.input.messages`)、`gen_ai.output`(属性 `gen_ai.output.messages`)。Span 本体保持精简,后端可对 Event 单独采样、脱敏或存储。 |
|
|
148
|
+
| **Attribute** | 将输入/输出写入 Span 属性 `gen_ai.input.messages`、`gen_ai.output.messages`。适合小 payload 或需要与 Span 一起索引的场景。 |
|
|
149
|
+
| **none** | 不记录输入/输出,仅记录元数据(model、token 等)。 |
|
|
150
|
+
|
|
151
|
+
**配置**(LangChain 适配器):
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from mingx import get_langchain_callback
|
|
155
|
+
|
|
156
|
+
# 默认已开启输入/输出(trace_content=True),所有节点入参、返回值都会记录
|
|
157
|
+
handler = get_langchain_callback()
|
|
158
|
+
|
|
159
|
+
# 如需关闭或改用属性记录
|
|
160
|
+
handler = get_langchain_callback(
|
|
161
|
+
trace_content=False, # 关闭输入/输出
|
|
162
|
+
record_input_output_as="events", # "events" | "attributes" | "none"
|
|
163
|
+
max_content_length=2000, # 可选:单条 content 截断长度
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 手动上报输入/输出(原生 OTEL 风格)
|
|
168
|
+
|
|
169
|
+
使用与 OpenTelemetry 一致的方式:`with get_tracer().start_as_current_span("name") as span:` 创建 Span,在块内按需调用 `span_input` 或 `span_output`,只需添加输入或输出其一即可。支持自定义 Span 属性或 Event 属性。
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from mingx import get_tracer, span_input, span_output
|
|
173
|
+
|
|
174
|
+
with get_tracer().start_as_current_span("call_model") as span:
|
|
175
|
+
span_input({"prompt": "..."}) # 只添加输入
|
|
176
|
+
result = call_model()
|
|
177
|
+
span_output(result) # 只添加输出
|
|
178
|
+
|
|
179
|
+
# 自定义属性或 Event 属性
|
|
180
|
+
span_input({"prompt": "..."}, attributes={"my.key": "value"})
|
|
181
|
+
span_output(result, event_attributes={"custom": "meta"})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- **span_input(data, ...)**:向当前 Span 添加输入(入参),可序列化 dict/list/str 等。
|
|
185
|
+
- **span_output(data, ...)**:向当前 Span 添加输出(返回值);无返回值可不调用或传 `None`。
|
|
186
|
+
- **attributes**:自定义 Span 属性(写入当前 Span)。
|
|
187
|
+
- **event_attributes**:自定义 Event 属性(合并到 gen_ai.input / gen_ai.output 的 Event)。
|
|
188
|
+
- 可只调用其一(只添加输入或只添加输出)。
|
|
189
|
+
- 若未在 `with` 块内,可传 `span=span`:`span_input(data, span=span)` / `span_output(data, span=span)`。
|
|
190
|
+
- 可选参数:`record_as="events"`(默认)| `"attributes"` | `"none"`,`max_length` 截断长度。
|
|
191
|
+
|
|
192
|
+
**Event 名称与属性键**:
|
|
193
|
+
|
|
194
|
+
| Event 名 | 属性键 | 说明 |
|
|
195
|
+
|----------|--------|------|
|
|
196
|
+
| `gen_ai.input` | `gen_ai.input.messages` | 输入消息列表(JSON 数组,每项含 role、content) |
|
|
197
|
+
| `gen_ai.output` | `gen_ai.output.messages` | 输出消息列表(同上) |
|
|
198
|
+
| `gen_ai.system_instructions` | `gen_ai.system_instructions` | 可选,系统指令 |
|
|
199
|
+
|
|
200
|
+
手动上报时使用 `span_input` / `span_output`(见上文);LLM 消息结构可调用 `mingx.genai.record_llm_input_output(span, input_messages, output_messages, record_as="events")`。
|
|
201
|
+
|
|
202
|
+
## Span 类型与属性说明
|
|
203
|
+
|
|
204
|
+
所有 Span 均可携带以下**通用属性**(来自 `configure_tracer_provider` 或 Baggage):
|
|
205
|
+
|
|
206
|
+
| 属性名 | 类型 | 说明 |
|
|
207
|
+
|--------|------|------|
|
|
208
|
+
| `mingx.workspace_id` | string | 工作空间 ID |
|
|
209
|
+
| `mingx.user.id` | string | 用户 ID |
|
|
210
|
+
| `mingx.span_type` | string | Span 节点类型(见下表) |
|
|
211
|
+
|
|
212
|
+
以下为 **mingx.span_type** 的取值及每种类型对应的属性说明。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### 所有 span_type 取值
|
|
217
|
+
|
|
218
|
+
| span_type | 说明 | 典型来源 |
|
|
219
|
+
|-----------|------|----------|
|
|
220
|
+
| `model` | 大模型调用(LLM/推理) | LangChain 适配器 `on_llm_start`、`@traced(span_type="model")` |
|
|
221
|
+
| `retriever` | 知识库/检索召回 | LangChain 适配器 `on_retriever_start`、`@traced(span_type="retriever")` |
|
|
222
|
+
| `tool` | Tool Call 执行 | LangChain 适配器 `on_tool_start`、`@traced(span_type="tool")` |
|
|
223
|
+
| `chain` | 链/组合节点 | LangChain 适配器 `on_chain_start`、`@traced(span_type="chain")` |
|
|
224
|
+
| `agent` | Agent 节点 | `@traced(span_type="agent")` 或 Baggage |
|
|
225
|
+
| `custom` | 自定义类型(适配器未识别时的默认值) | 适配器在 span_type 为空时自动填充 |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### 各类型对应属性
|
|
230
|
+
|
|
231
|
+
#### 1. `model`(大模型节点)
|
|
232
|
+
|
|
233
|
+
| 属性/Event | 类型 | 说明 |
|
|
234
|
+
|------------|------|------|
|
|
235
|
+
| `mingx.span_type` | string | `"model"` |
|
|
236
|
+
| `gen_ai.operation.name` | string | 操作名,如 `"chat"` |
|
|
237
|
+
| `gen_ai.provider.name` | string | 厂商,如 `"openai"`, `"anthropic"`, `"gcp.vertex_ai"` 等 |
|
|
238
|
+
| `gen_ai.request.model` | string | 请求模型名 |
|
|
239
|
+
| `gen_ai.response.model` | string | 可选,响应实际使用的模型 |
|
|
240
|
+
| `gen_ai.response.id` | string | 可选,响应 ID |
|
|
241
|
+
| `gen_ai.response.finish_reasons` | string[] | 可选,结束原因 |
|
|
242
|
+
| `gen_ai.usage.input_tokens` | int | 可选,输入 token 数 |
|
|
243
|
+
| `gen_ai.usage.output_tokens` | int | 可选,输出 token 数 |
|
|
244
|
+
| **输入/输出** | **Event(推荐)或 Attribute** | 见上文「输入/输出记录」;`gen_ai.input` / `gen_ai.output` Event 或 `gen_ai.input.messages` / `gen_ai.output.messages` 属性 |
|
|
245
|
+
| `lc.run_id` | string | LangChain run_id(适配器时) |
|
|
246
|
+
| `error.type` | string | 出错时错误类型 |
|
|
247
|
+
|
|
248
|
+
#### 2. `retriever`(知识库召回节点)
|
|
249
|
+
|
|
250
|
+
| 属性名 | 类型 | 说明 |
|
|
251
|
+
|--------|------|------|
|
|
252
|
+
| `mingx.span_type` | string | `"retriever"` |
|
|
253
|
+
| `gen_ai.operation.name` | string | `"retriever"` |
|
|
254
|
+
| **输入/输出** | **Event 或 Attribute** | 适配器默认记录 query / documents(`trace_content=True`);也可用 `span_input` / `span_output` 手动记录 |
|
|
255
|
+
| `lc.run_id` | string | LangChain run_id(适配器时) |
|
|
256
|
+
| `error.type` | string | 出错时错误类型 |
|
|
257
|
+
|
|
258
|
+
#### 3. `tool`(Tool Call 节点)
|
|
259
|
+
|
|
260
|
+
| 属性名 | 类型 | 说明 |
|
|
261
|
+
|--------|------|------|
|
|
262
|
+
| `mingx.span_type` | string | `"tool"` |
|
|
263
|
+
| `gen_ai.operation.name` | string | `"execute_tool"` |
|
|
264
|
+
| `gen_ai.tool.name` | string | 工具名称 |
|
|
265
|
+
| `gen_ai.tool.description` | string | 可选,工具描述 |
|
|
266
|
+
| `gen_ai.tool.call.id` | string | 可选,工具调用 ID |
|
|
267
|
+
| `gen_ai.tool.type` | string | 可选,工具类型 |
|
|
268
|
+
| **输入/输出** | **Event 或 Attribute** | 适配器默认记录入参/出参(`trace_content=True`);支持 `attributes` / `event_attributes` 自定义属性 |
|
|
269
|
+
| `lc.run_id` | string | LangChain run_id(适配器时) |
|
|
270
|
+
| `error.type` | string | 出错时错误类型 |
|
|
271
|
+
|
|
272
|
+
#### 4. `chain`(链/组合节点)
|
|
273
|
+
|
|
274
|
+
| 属性名 | 类型 | 说明 |
|
|
275
|
+
|--------|------|------|
|
|
276
|
+
| `mingx.span_type` | string | `"chain"` |
|
|
277
|
+
| `gen_ai.operation.name` | string | `"invoke_agent"` |
|
|
278
|
+
| **输入/输出** | **Event 或 Attribute** | 适配器默认记录 inputs / outputs(`trace_content=True`) |
|
|
279
|
+
| `lc.run_id` | string | LangChain run_id(适配器时) |
|
|
280
|
+
| `error.type` | string | 出错时错误类型 |
|
|
281
|
+
|
|
282
|
+
#### 5. `agent`(Agent 节点)
|
|
283
|
+
|
|
284
|
+
| 属性名 | 类型 | 说明 |
|
|
285
|
+
|--------|------|------|
|
|
286
|
+
| `mingx.span_type` | string | `"agent"` |
|
|
287
|
+
| 其他 | — | 由 `@traced(span_type="agent", attributes={...})` 或 GenAI 语义层按需添加 |
|
|
288
|
+
|
|
289
|
+
#### 6. `custom`(自定义类型)
|
|
290
|
+
|
|
291
|
+
| 属性名 | 类型 | 说明 |
|
|
292
|
+
|--------|------|------|
|
|
293
|
+
| `mingx.span_type` | string | `"custom"` |
|
|
294
|
+
| 其他 | — | 适配器未识别类型时自动使用;也可通过 `@traced(span_type="custom", attributes={...})` 扩展 |
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
代码中可使用常量(来自 `mingx`):
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from mingx import (
|
|
302
|
+
SPAN_TYPE_MODEL,
|
|
303
|
+
SPAN_TYPE_RETRIEVER,
|
|
304
|
+
SPAN_TYPE_TOOL,
|
|
305
|
+
SPAN_TYPE_CHAIN,
|
|
306
|
+
SPAN_TYPE_AGENT,
|
|
307
|
+
SPAN_TYPE_CUSTOM,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
@traced(span_type=SPAN_TYPE_MODEL)
|
|
311
|
+
def call_llm(): ...
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## GenAI 规范
|
|
315
|
+
|
|
316
|
+
Span 遵循 [OpenTelemetry GenAI Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/)。可选:设置环境变量 `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental` 以使用最新实验属性。
|
|
317
|
+
|
|
318
|
+
## 项目结构
|
|
319
|
+
|
|
320
|
+
- `mingx._trace`:Tracer 与 TracerProvider 配置
|
|
321
|
+
- `mingx.genai`:GenAI 语义层(Span 名、属性、输入/输出 Event)
|
|
322
|
+
- `mingx.adapters`:框架适配器(LangChain,后续 CrewAI/ADK)
|
|
323
|
+
- `mingx.decorator`:`@traced` 方法级 Span
|
|
324
|
+
- `mingx._default_attributes`:默认属性与 Baggage 处理
|
|
325
|
+
|
|
326
|
+
## 打包
|
|
327
|
+
|
|
328
|
+
项目使用 [Hatchling](https://hatch.pypa.io/) 作为构建后端(见 `pyproject.toml`)。
|
|
329
|
+
|
|
330
|
+
**构建 wheel 与 sdist(推荐用 uv):**
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# 安装 uv 后,在项目根目录执行
|
|
334
|
+
uv build
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
产物在 `dist/` 目录:`mingx-<version>-py3-none-any.whl` 与 `mingx-<version>.tar.gz`。
|
|
338
|
+
|
|
339
|
+
**使用 pip 构建:**
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
pip install build
|
|
343
|
+
python -m build
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**本地可编辑安装(开发时):**
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
uv pip install -e .
|
|
350
|
+
# 或
|
|
351
|
+
pip install -e .
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**发布到 PyPI(示例):**
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
uv build
|
|
358
|
+
uv publish
|
|
359
|
+
# 或使用 twine
|
|
360
|
+
pip install twine
|
|
361
|
+
twine upload dist/*
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## 测试
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
uv sync --extra dev
|
|
368
|
+
uv run pytest tests/ -v
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## License
|
|
372
|
+
|
|
373
|
+
见仓库说明。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
mingx/__init__.py,sha256=cTuHXXyEShdAzaApsgUYg_CA5DowqFWwMPUT45pbaB8,1482
|
|
2
|
+
mingx/_default_attributes.py,sha256=UGs3IuPSlInTlseVeU7cZvITcSBQSpg4HYv7Fz5RzPM,2682
|
|
3
|
+
mingx/_trace.py,sha256=8xSypFw2vgw4uJnLLiB8yiGOA0Ga3dDcDWaUhQlVkic,5534
|
|
4
|
+
mingx/decorator.py,sha256=qKtSOI7eyHfhJeAc9-YApEBOHhhNif7efm0h3l-le_M,6638
|
|
5
|
+
mingx/adapters/__init__.py,sha256=shSWbWvkQTn0-yh3iBQWBn5OICEV5uoDDwLhDf8Rovw,496
|
|
6
|
+
mingx/adapters/base.py,sha256=hv0CPXgeBC0bxUtfnN-y0Q_jh7GxML9XxffK3CXB_34,2524
|
|
7
|
+
mingx/adapters/langchain.py,sha256=ZvPWLibpVwn0BAKqYUB3eYx5-5ezcd8yvxy3qwYvFJA,26309
|
|
8
|
+
mingx/genai/__init__.py,sha256=G9ygXhaM_uTU5q0hZoVhDkhRSaSERoYK02isiPRnkvY,2612
|
|
9
|
+
mingx/genai/attributes.py,sha256=ssRFX_YoyNNjYZrpct-Ixawtsz-zK6dlgR-7QgbVl8k,6376
|
|
10
|
+
mingx/genai/io.py,sha256=m4tYrzR4Kk2KxSjHApCf90gdssZWlB_WCzuBk1pQ_9w,17393
|
|
11
|
+
mingx/genai/span_attributes.py,sha256=UveEVnrXWNB10kk24dw0ZfVAxvxRNdmAyKJgk-FMfhs,5758
|
|
12
|
+
mingx/genai/spans.py,sha256=DWSOis5o2en9r_UM8UNqpjIXMqOyC2ru8tnGa8POsww,5259
|
|
13
|
+
mingx-0.1.0.dist-info/METADATA,sha256=ycRW6TuRNtgM4dyrSTLWkfNBB5xE5kqEp71jNyRqwVQ,14951
|
|
14
|
+
mingx-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
mingx-0.1.0.dist-info/RECORD,,
|