Skip to main content

llmobs-integrations

dd-trace-py LLMObs integration development guide. Use when creating, modifying, or debugging LLMObs integrations for LLM/AI libraries in the Python tracer. Covers BaseLLMIntegration, stream handling, message extraction, token counting, tool call parsing, and VCR-based testing patterns. Triggers: "llmobs", "LLMObs", "BaseLLMIntegration", "llmobs_set_tags", "_llmobs_set_tags", "BaseStreamHandler", "submit_to_llmobs", "integration.trace", "LLM span", "VCR", "cassette", "anthropic", "openai", "google_genai", "claude_agent_sdk", "generative-ai", "LLM integration", "llmobs_enabled".

跳到安装

来源信息

仓库
DataDog/dd-trace-py
最近来源活动
2026年9月10日 19:53
检测到的 SKILL.md 语言
英语
星标
650
分支
548

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
4 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
llmobs-integrations
description
dd-trace-py LLMObs integration development guide. Use when creating, modifying, or debugging LLMObs integrations for LLM/AI libraries in the Python tracer. Covers BaseLLMIntegration, stream handling, message extraction, token counting, tool call parsing, and VCR-based testing patterns. Triggers: "llmobs", "LLMObs", "BaseLLMIntegration", "llmobs_set_tags", "_llmobs_set_tags", "BaseStreamHandler", "submit_to_llmobs", "integration.trace", "LLM span", "VCR", "cassette", "anthropic", "openai", "google_genai", "claude_agent_sdk", "generative-ai", "LLM integration", "llmobs_enabled".
# dd-trace-py LLMObs Integrations LLMObs integrations enable Datadog LLM Observability for AI/LLM libraries. They extract model inputs, outputs, token usage, and tool calls from traced spans. This skill should be used in addition to the `apm-integrations` skill. ## Two-Layer Architecture LLMObs integrations consist of two cooperating layers: 1. **Patch Layer** (`ddtrace/contrib/internal/{name}/patch.py`) -- wraps library functions. Standard request/response LLM integrations construct `LlmRequestEvent` and use `core.context_with_event()` so the LLM tracing subscriber owns span lifecycle and LLMObs tag extraction. 2. **Integration Layer** (`ddtrace/llmobs/_integrations/{name}.py`) -- extends `BaseLLMIntegration`, implements `_set_base_span_tags()` and `_llmobs_set_tags()` to extract and set provider-specific messages, tools, metadata, and token metrics. Both layers must work together. The patch layer identifies the operation and passes request/response data through the event; the integration layer controls what data is extracted. ## Active Patch Patterns - **Event-based request spans**: Use `LlmRequestEvent` with `core.context_with_event()` for new standard request/response LLM integrations. Anthropic is the canonical reference. This is the preferred pattern. - **Direct integration spans**: Some existing or specialized integrations still call `integration.trace()` and `integration.llmobs_set_tags()` directly, especially for child spans, agent/tool spans, or integrations not yet migrated. Google GenAI, OpenAI tool spans, and Claude Agent SDK are useful references. ## Key Files | Purpose | File | |---------|------| | Base LLM integration class | `ddtrace/llmobs/_integrations/base.py` (`BaseLLMIntegration`) | | Stream handler base classes | `ddtrace/llmobs/_integrations/base_stream_handler.py` (`BaseStreamHandler`, `StreamHandler`, `AsyncStreamHandler`) | | Shared utilities | `ddtrace/llmobs/_integrations/utils.py` | | LLMObs annotation helper | `ddtrace/llmobs/_utils.py` (`_annotate_llmobs_span_data`) | | LLMObs constants | `ddtrace/llmobs/_constants.py` | | LLMObs types | `ddtrace/llmobs/types.py` (`Message`, `AudioPart`, `ToolCall`, `ToolResult`, `ToolDefinition`) | | Integration registry | `ddtrace/llmobs/_integrations/__init__.py` | ## Reference Integrations **Always read 1-2 references before writing or modifying LLMObs code.** | Provider | Patch File | LLMObs Integration | LLMObs Tests | |----------|-----------|-------------------|--------------| | **Anthropic** (canonical) | `ddtrace/contrib/internal/anthropic/patch.py` | `ddtrace/llmobs/_integrations/anthropic.py` | `tests/contrib/anthropic/test_anthropic_llmobs.py` | | **Claude Agent SDK** (latest, agent pattern) | `ddtrace/contrib/internal/claude_agent_sdk/patch.py` | `ddtrace/llmobs/_integrations/claude_agent_sdk.py` | `tests/contrib/claude_agent_sdk/test_claude_agent_sdk_llmobs.py` | | OpenAI | `ddtrace/contrib/internal/openai/patch.py` | `ddtrace/llmobs/_integrations/openai.py` | `tests/contrib/openai/test_openai_llmobs.py` | | Google GenAI | `ddtrace/contrib/internal/google_genai/patch.py` | `ddtrace/llmobs/_integrations/google_genai.py` | `tests/contrib/google_genai/test_google_genai_llmobs.py` | Use **Anthropic** as the canonical reference for standard LLM integrations. Use **Claude Agent SDK** for agent-pattern integrations (agent spans, tool child spans, thinking blocks). ## Abstract Methods to Implement Subclass `BaseLLMIntegration` and implement: ### `_set_base_span_tags(span, **kwargs)` Set provider-specific APM tags on the span (e.g., `{name}.request.model`). ### `_llmobs_set_tags(span, args, kwargs, response, operation)` Extract and annotate all LLMObs fields on the span: | Field | Description | |-------------|-------------| | `kind` | `"llm"` for LLM calls, `"agent"` for agent calls, `"tool"` for tool calls | | `model_name` | Model identifier (e.g., `"claude-3-sonnet-20240229"`) | | `model_provider` | Provider name (e.g., `"anthropic"`, `"openai"`) | | `input_messages` | List of `Message` objects from request | | `output_messages` | List of `Message` objects from response | | `metadata` | Dict of sanitized request parameters (temperature, top_p, etc.), plus response-derived scalars such as `finish_reason` (see Response Metadata below) | | `metrics` | Token usage dict with `INPUT_TOKENS_METRIC_KEY`, `OUTPUT_TOKENS_METRIC_KEY`, `TOTAL_TOKENS_METRIC_KEY` | | `tool_definitions` | List of `ToolDefinition` objects if tools are passed | Fields are usually set via `_annotate_llmobs_span_data(...)`, not raw `span._set_ctx_items(...)`. ### Response Metadata `metadata` is not request-only. Scalars the provider reports on the *response* belong there too, so long as they are not already covered by `metrics` (token counts) or `output_messages`. The stop reason is the established case. Record it under the key `finish_reason` for every provider, so one facet answers "why did generation stop" regardless of integration, and keep each provider's own vocabulary as the value (`stop`/`length`/`content_filter`/`tool_calls` for the OpenAI family, `end_turn`/`max_tokens`/`refusal`/`tool_use` for Anthropic). Read it from: | Provider | Source | |---|---| | openai/litellm chat + legacy completions | `choice.finish_reason` (per choice) | | openai responses API | `incomplete_details.reason` | | anthropic | `response.stop_reason`, falling back to `response.finish_reason` for the streamed dict the aggregator rebuilds | Rules: - **Merge, do not replace.** Build the request metadata first, then update it with the response-derived keys (`parameters.update(...)`), so response data never clobbers request params. - **Omit the key when absent.** If the provider reports no reason, leave `finish_reason` out entirely rather than writing `None` or `""`. - **Keep the value a single string.** When a request returns multiple choices (`n > 1`), comma-join the per-choice reasons in choice order (`"stop,length"`) instead of emitting a list, so the key never changes type. `_openai_finish_reason_metadata()` in `_integrations/utils.py` does this. - **Guard on the response, not `span.error`.** A response can exist on an errored span (see the AI Guard case in `_integrations/anthropic.py`); gate on `response is not None`. Note two already-shipped integrations predate this key: bedrock and the claude-agent-sdk both write `metadata["stop_reason"]`. Renaming those is a breaking change and has not been done — follow `finish_reason` for new work. ## Key Constraints - **`submit_to_llmobs=True`** must be set on `LlmRequestEvent` for event-based request spans or passed to `integration.trace()` for direct LLMObs spans - **`ctx.dispatch_ended_event()`** must run on success and error paths for event-based patch wrappers - **Streaming** must use `BaseStreamHandler`/`AsyncStreamHandler` -- never consume streams directly - **Event-based patch wrappers** should not call `span.set_exc_info()`, `span.finish()`, or `integration.llmobs_set_tags()` directly; the tracing subscriber handles that when the event ends - **Direct integration spans** must keep `integration.llmobs_set_tags()` and span lifecycle handling aligned with the closest current reference - **Integration instance** must be stored on the module: `module._datadog_integration = MyLibIntegration(integration_config=config.mylib)` ## Message Types ```python from ddtrace.llmobs.types import AudioPart, ImagePart, Message, ToolCall, ToolResult, ToolDefinition # Input/output messages Message(content="text", role="user") Message(content="response", role="assistant", tool_calls=[...]) # Audio attachments in multimodal messages AudioPart(mime_type="audio/wav", content="<base64-audio>") Message(content="", role="user", audio_parts=[...]) # Image attachments in multimodal messages ImagePart(mime_type="image/png", content="<base64-image>") Message(content="", role="user", image_parts=[...]) # Tool calls (in output messages) ToolCall(name="get_weather", arguments={"city": "NYC"}, tool_id="toolu_123", type="tool") # Tool results (in input messages) ToolResult(result="72F sunny", tool_id="toolu_123", type="tool_result") # Tool definitions (from request parameters) ToolDefinition(name="get_weather", description="...", schema={...}) ``` ## Debugging Quick Tips - **No LLMObs spans** -- check `submit_to_llmobs=True`, `ctx.dispatch_ended_event()`, and `llmobs_enabled` - **Wrong messages** -- check message extraction handles multi-part content and tool blocks - **Wrong tokens** -- check field name mapping (libraries use different names for token counts) - **Streaming broken** -- verify `BaseStreamHandler` subclass, check `finalize_stream()` dispatches the ended event or finishes direct-trace spans according to the reference pattern - **DD_TRACE_DEBUG=true** to see patching activity and span creation See [Failure Modes](references/failure-modes.md) for detailed debugging guide. ## Reference Files - [Implementation Guide](references/implementation-guide.md) -- LLM-specific steps (references apm-integrations guide for the full workflow) - [Failure Modes](references/failure-modes.md) -- All 8 failure modes with causes and fixes - [Testing Guide](references/testing-guide.md) -- LLMObs test patterns, VCR cassettes, suitespec
在 GitHub 查看