fix: read system_instruction from _settings instead of removed attribute
Replace adapter-based extraction in traced_llm with direct reads from _settings.system_instruction (priority) and context messages (fallback). The old approach had three bugs: signature mismatch with Anthropic adapter, key name inconsistency, and unnecessary overhead from full message/tools conversion. Also deduplicate the system instruction in spans -- it was appearing as both "system" and "param.system_instruction".
This commit is contained in:
@@ -1 +1 @@
|
|||||||
- Fixed telemetry record correct system_instruction in span for LLM services
|
- Fixed stale `system_instruction` in LLM tracing spans by reading from `_settings.system_instruction` instead of the removed `_system_instruction` attribute.
|
||||||
|
|||||||
@@ -502,35 +502,45 @@ def traced_llm(func: Optional[Callable] = None, *, name: Optional[str] = None) -
|
|||||||
|
|
||||||
# Handle system message for different services
|
# Handle system message for different services
|
||||||
system_message = None
|
system_message = None
|
||||||
# Handle system message for different services
|
|
||||||
if isinstance(context, LLMContext):
|
if isinstance(context, LLMContext):
|
||||||
# Universal LLMContext - use adapter to convert and get system message
|
# settings.system_instruction takes priority (matches service behavior)
|
||||||
if hasattr(self, "get_llm_adapter"):
|
if hasattr(self, "_settings") and getattr(
|
||||||
adapter = self.get_llm_adapter()
|
self._settings, "system_instruction", None
|
||||||
try:
|
):
|
||||||
# Get LLM invocation params which includes system_instruction
|
system_message = self._settings.system_instruction
|
||||||
params = adapter.get_llm_invocation_params(context)
|
else:
|
||||||
|
# Fall back to extracting from context messages
|
||||||
|
ctx_messages = context.get_messages()
|
||||||
|
if ctx_messages:
|
||||||
|
first = ctx_messages[0]
|
||||||
if (
|
if (
|
||||||
isinstance(params, dict)
|
isinstance(first, dict)
|
||||||
and "system_instruction" in params
|
and first.get("role") == "system"
|
||||||
):
|
):
|
||||||
system_message = params["system_instruction"]
|
content = first.get("content")
|
||||||
except Exception as e:
|
if isinstance(content, str):
|
||||||
logging.debug(
|
system_message = content
|
||||||
f"Could not extract system instruction from adapter: {e}"
|
elif isinstance(content, list):
|
||||||
)
|
system_message = " ".join(
|
||||||
|
part.get("text", "")
|
||||||
|
for part in content
|
||||||
|
if isinstance(part, dict)
|
||||||
|
and part.get("type") == "text"
|
||||||
|
)
|
||||||
elif hasattr(context, "system"):
|
elif hasattr(context, "system"):
|
||||||
system_message = context.system
|
system_message = context.system
|
||||||
elif hasattr(context, "system_message"):
|
elif hasattr(context, "system_message"):
|
||||||
system_message = context.system_message
|
system_message = context.system_message
|
||||||
elif hasattr(self, "_system_instruction"):
|
|
||||||
system_message = self._system_instruction
|
|
||||||
|
|
||||||
# Use given_fields() defensively in case a service doesn't
|
# Use given_fields() defensively in case a service doesn't
|
||||||
# initialize all settings.
|
# initialize all settings.
|
||||||
params = {}
|
params = {}
|
||||||
if hasattr(self, "_settings"):
|
if hasattr(self, "_settings"):
|
||||||
for key, value in self._settings.given_fields().items():
|
for key, value in self._settings.given_fields().items():
|
||||||
|
# system_instruction is already captured as the
|
||||||
|
# "system" span attribute above.
|
||||||
|
if key == "system_instruction":
|
||||||
|
continue
|
||||||
if isinstance(value, (int, float, bool, str)):
|
if isinstance(value, (int, float, bool, str)):
|
||||||
params[key] = value
|
params[key] = value
|
||||||
elif value is None:
|
elif value is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user