In the tracing tab, our table view looks for the span attributes "input.value" (or SpanAttributes.INPUT_VALUE or SemanticConventions.INPUT_VALUE) to populate the Input column. Similarly, it looks for "output.value" (or SpanAttributes.OUTPUT_VALUE or SemanticConventions.OUTPUT_VALUE) for to populate the Output column.
When viewing a single span, certain fields show up more prominently. For example, for LLM types spans, the Input messages are populated by the key SpanAttributes.LLM_INPUT_MESSAGES. If you're sending multiple messages, this should allow you to view the entire series of messages, both from the user and assistant roles, in a single page. A similar concept applies for Output Messages.
This example code shows how you can instrument the inputs of a python app. If you have prompt templates and template variables, this will instrument that as well, giving you access to the prompt template tab.
One thing to note is the format of the LLM_INPUT_MESSAGES. This attribute is represented as a list of chat completion params, which have role and content fields. In order to set this, you need to set the index as well as each field for each message, as shown in the example below. This example uses the ChatCompletionMessageParam message type from OpenAi, but any data following the format of example_messages below will do.
import jsonfrom typing import Listfrom openai.types.chat import ChatCompletionMessageParamfrom openinference.semconv.trace import MessageAttributes, SpanAttributesfrom opentelemetry.trace import Spanexample_messages = [{"role":"user","content":"something the user said",},{"role":"assistant","content":"something the LLM responded with",},]defset_input_attrs(span: Span,messages: List[ChatCompletionMessageParam],prompt_template:str,prompt_vars:dict|str,) ->None:# INPUT_VALUE shows up on the table view under the input column# It also shows up under the `input` tab on the span span.set_attribute( SpanAttributes.INPUT_VALUE, messages[-1].get("content", ""), # get the last message for input )# LLM_INPUT_MESSAGES shows up under `input_messages` tab on the span pagefor idx, msg inenumerate(messages):# Set the role per message span.set_attribute(f"{SpanAttributes.LLM_INPUT_MESSAGES}.{idx}.{MessageAttributes.MESSAGE_ROLE}", msg["role"], )# Set the content per message span.set_attribute(f"{SpanAttributes.LLM_INPUT_MESSAGES}.{idx}.{MessageAttributes.MESSAGE_CONTENT}", msg.get("content", ""), )# LLM_PROMPT_TEMPLATE show up under the `prompt_template` tab span.set_attribute(SpanAttributes.LLM_PROMPT_TEMPLATE, prompt_template)# LLM_PROMPT_TEMPLATE_VARIABLES also shows up under the `prompt_template` tab# This must be in json format:ifisinstance(prompt_vars, dict): prompt_vars = json.dumps(prompt_vars) span.set_attribute(SpanAttributes.LLM_PROMPT_TEMPLATE_VARIABLES, prompt_vars)