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/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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any