FI Semantic Conventions

Use standardized attribute keys for spans to ensure consistent, queryable trace data across LLM models, frameworks, and vendors.

About

Every LLM provider returns data in a different format. Without a standard set of attribute keys, the same concept (model name, token count, input messages) ends up stored differently depending on which provider or framework was used, making filtering and comparison impossible. FI Semantic Conventions define a single set of attribute keys that the Future AGI platform recognizes. When spans carry these keys, they are highlighted in the UI and enable filtering, search, and analytics across providers.


When to use

  • Consistent tracing: Standardized keys across different LLM providers and frameworks so trace data is uniform and comparable.
  • LLM data capture: Record model name, token counts, input/output messages, and prompt templates in a structured, queryable schema.
  • Filtering and search: Filter and search traces in the Future AGI dashboard using well-known attribute keys.
  • Retrieval and reranker tracing: Attach document scores, query strings, and model names to retrieval and reranker spans for RAG pipeline visibility.
  • Session and user analytics: Use session.id and user.id to group traces and run per-user analytics.

How to

Install the package

Install the traceAI instrumentation package to access semantic convention constants.

pip install fi-instrumentation-otel
npm install @traceai/fi-core @opentelemetry/api

Browse available attributes

Choose your language to view the available semantic convention classes and constants.

class SpanAttributes:
    # Input/Output
    INPUT_VALUE = "input.value"
    INPUT_MIME_TYPE = "input.mime_type"
    OUTPUT_VALUE = "output.value"
    OUTPUT_MIME_TYPE = "output.mime_type"

    # LLM messages
    GEN_AI_INPUT_MESSAGES = "gen_ai.input.messages"
    GEN_AI_OUTPUT_MESSAGES = "gen_ai.output.messages"
    GEN_AI_OUTPUT_TYPE = "gen_ai.output.type"

    # Model and provider
    GEN_AI_REQUEST_MODEL = "gen_ai.request.model"
    GEN_AI_RESPONSE_MODEL = "gen_ai.response.model"
    GEN_AI_PROVIDER_NAME = "gen_ai.provider.name"
    GEN_AI_SYSTEM = "gen_ai.system"

    # Request parameters
    GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature"
    GEN_AI_REQUEST_TOP_P = "gen_ai.request.top_p"
    GEN_AI_REQUEST_MAX_TOKENS = "gen_ai.request.max_tokens"
    GEN_AI_REQUEST_PARAMETERS = "gen_ai.request.parameters"

    # Token usage
    GEN_AI_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens"
    GEN_AI_USAGE_OUTPUT_TOKENS = "gen_ai.usage.output_tokens"
    GEN_AI_USAGE_TOTAL_TOKENS = "gen_ai.usage.total_tokens"

    # Cost
    GEN_AI_COST_INPUT = "gen_ai.cost.input"
    GEN_AI_COST_OUTPUT = "gen_ai.cost.output"
    GEN_AI_COST_TOTAL = "gen_ai.cost.total"

    # Prompt templates
    GEN_AI_PROMPT_TEMPLATE_NAME = "gen_ai.prompt.template.name"
    GEN_AI_PROMPT_TEMPLATE_LABEL = "gen_ai.prompt.template.label"
    GEN_AI_PROMPT_TEMPLATE_VERSION = "gen_ai.prompt.template.version"
    GEN_AI_PROMPT_TEMPLATE_VARIABLES = "gen_ai.prompt.template.variables"
    GEN_AI_PROMPTS = "gen_ai.prompts"

    # Tool related
    GEN_AI_TOOL_NAME = "gen_ai.tool.name"
    GEN_AI_TOOL_DESCRIPTION = "gen_ai.tool.description"
    GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions"
    TOOL_PARAMETERS = "gen_ai.tool.parameters"

    # Embeddings
    EMBEDDING_EMBEDDINGS = "embedding.embeddings"
    EMBEDDING_MODEL_NAME = "embedding.model_name"

    # Retrieval
    RETRIEVAL_DOCUMENTS = "retrieval.documents"

    # Span kind
    GEN_AI_SPAN_KIND = "gen_ai.span.kind"

    # Session and user
    SESSION_ID = "session.id"
    USER_ID = "user.id"

    # Metadata and tags
    METADATA = "metadata"
    TAG_TAGS = "tag.tags"

    # Images
    INPUT_IMAGES = "gen_ai.input.images"
class MessageAttributes:
    # Attributes for a message sent to or from an LLM

    MESSAGE_ROLE = "message.role"
    # The role of the message, such as "user", "agent", "function".

    MESSAGE_CONTENT = "message.content"
    # The content of the message to or from the llm, must be a string.

    MESSAGE_CONTENTS = "message.contents"
    # The message contents to the llm, it is an array of message_content prefixed attributes.

    MESSAGE_NAME = "message.name"
    # The name of the message, often used to identify the function that was used to generate the message.

    MESSAGE_TOOL_CALLS = "message.tool_calls"
    # The tool calls generated by the model, such as function calls.

    MESSAGE_FUNCTION_CALL_NAME = "message.function_call_name"
    # The function name that is a part of the message list.
    # This is populated for role 'function' or 'agent' as a mechanism to identify
    # the function that was called during the execution of a tool.

    MESSAGE_FUNCTION_CALL_ARGUMENTS_JSON = "message.function_call_arguments_json"
    # The JSON string representing the arguments passed to the function during a function call.

    MESSAGE_TOOL_CALL_ID = "message.tool_call_id"
    # The id of the tool call.
class DocumentAttributes:
    # Attributes for a document.

    DOCUMENT_ID = "document.id"
    # The id of the document.

    DOCUMENT_SCORE = "document.score"
    # The score of the document

    DOCUMENT_CONTENT = "document.content"
    # The content of the document.

    DOCUMENT_METADATA = "document.metadata"
    # The metadata of the document represented as a dictionary JSON string
class RerankerAttributes:
    # Attributes for a reranker

    RERANKER_INPUT_DOCUMENTS = "reranker.input_documents"
    # List of documents as input to the reranker

    RERANKER_OUTPUT_DOCUMENTS = "reranker.output_documents"
    # List of documents as output from the reranker

    RERANKER_QUERY = "reranker.query"
    # Query string for the reranker

    RERANKER_MODEL_NAME = "reranker.model_name"
    # Model name of the reranker

    RERANKER_TOP_K = "reranker.top_k"
    # Top K parameter of the reranker
class EmbeddingAttributes:
    # Attributes for an embedding

    EMBEDDING_TEXT = "embedding.text"
    # The text represented by the embedding.

    EMBEDDING_VECTOR = "embedding.vector"
    # The embedding vector.
class ToolCallAttributes:
    # Attributes for a tool call

    TOOL_CALL_ID = "tool_call.id"
    # The id of the tool call.

    TOOL_CALL_FUNCTION_NAME = "tool_call.function.name"
    # The name of function that is being called during a tool call.

    TOOL_CALL_FUNCTION_ARGUMENTS_JSON = "tool_call.function.arguments"
    # The JSON string representing the arguments passed to the function during a tool call.
class ImageAttributes:
    IMAGE_URL = "image.url"
    # An http or base64 image url


class AudioAttributes:
    AUDIO_URL = "audio.url"
    # The url to an audio file
    AUDIO_MIME_TYPE = "audio.mime_type"
    # The mime type of the audio file
    AUDIO_TRANSCRIPT = "audio.transcript"
    # The transcript of the audio file
// Semantic Conventions for Span Attributes
export const SemanticConventions = {
  // Input/Output
  INPUT_VALUE: "input.value",
  INPUT_MIME_TYPE: "input.mime_type",
  OUTPUT_VALUE: "output.value",
  OUTPUT_MIME_TYPE: "output.mime_type",

  // LLM messages
  LLM_INPUT_MESSAGES: "gen_ai.input.messages",
  LLM_OUTPUT_MESSAGES: "gen_ai.output.messages",

  // Model and provider
  LLM_MODEL_NAME: "gen_ai.request.model",
  LLM_PROVIDER: "gen_ai.provider.name",
  LLM_SYSTEM: "gen_ai.provider.name",
  LLM_PROMPTS: "gen_ai.prompts",
  LLM_INVOCATION_PARAMETERS: "gen_ai.request.parameters",
  LLM_FUNCTION_CALL: "gen_ai.tool.call",
  LLM_TOOLS: "gen_ai.tool.definitions",

  // Token usage
  LLM_TOKEN_COUNT_PROMPT: "gen_ai.usage.input_tokens",
  LLM_TOKEN_COUNT_COMPLETION: "gen_ai.usage.output_tokens",
  LLM_TOKEN_COUNT_TOTAL: "gen_ai.usage.total_tokens",
  LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING: "gen_ai.usage.output_tokens.reasoning",
  LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO: "gen_ai.usage.output_tokens.audio",
  LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE: "gen_ai.usage.cache_write_tokens",
  LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ: "gen_ai.usage.cache_read_tokens",
  LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO: "gen_ai.usage.input_tokens.audio",

  // Prompt template attributes
  PROMPT_TEMPLATE_TEMPLATE: "llm.prompt_template.template",
  PROMPT_TEMPLATE_VARIABLES: "llm.prompt_template.variables",
  PROMPT_TEMPLATE_VERSION: "llm.prompt_template.version",

  // Tool related attributes
  TOOL_NAME: "tool.name",
  TOOL_DESCRIPTION: "tool.description",
  TOOL_PARAMETERS: "tool.parameters",
  TOOL_JSON_SCHEMA: "tool.json_schema",

  // Embedding attributes
  EMBEDDING_EMBEDDINGS: "embedding.embeddings",
  EMBEDDING_MODEL_NAME: "embedding.model_name",
  EMBEDDING_TEXT: "embedding.text",
  EMBEDDING_VECTOR: "embedding.vector",

  // Retrieval attributes
  RETRIEVAL_DOCUMENTS: "retrieval.documents",

  // Session and user tracking
  SESSION_ID: "session.id",
  USER_ID: "user.id",

  // Metadata and tagging
  METADATA: "metadata",
  TAG_TAGS: "tag.tags",
  FI_SPAN_KIND: "fi.span.kind",

  // Raw input/output
  RAW_INPUT: "raw.input",
  RAW_OUTPUT: "raw.output",
} as const;

// Span kind enumeration
export enum FISpanKind {
  LLM = "LLM",
  CHAIN = "CHAIN",
  TOOL = "TOOL",
  RETRIEVER = "RETRIEVER",
  RERANKER = "RERANKER",
  EMBEDDING = "EMBEDDING",
  AGENT = "AGENT",
  GUARDRAIL = "GUARDRAIL",
  EVALUATOR = "EVALUATOR",
  UNKNOWN = "UNKNOWN",
}
// Message related semantic conventions
export const MessageConventions = {
  MESSAGE_ROLE: "message.role",
  MESSAGE_CONTENT: "message.content",
  MESSAGE_CONTENTS: "message.contents",
  MESSAGE_NAME: "message.name",
  MESSAGE_TOOL_CALLS: "message.tool_calls",
  MESSAGE_TOOL_CALL_ID: "message.tool_call_id",
  MESSAGE_FUNCTION_CALL_NAME: "message.function_call_name",
  MESSAGE_FUNCTION_CALL_ARGUMENTS_JSON: "message.function_call_arguments_json",

  // Message content attributes
  MESSAGE_CONTENT_TYPE: "message_content.type",
  MESSAGE_CONTENT_TEXT: "message_content.text",
  MESSAGE_CONTENT_IMAGE: "message_content.image",
} as const;

// Message content types
export const MessageContentTypes = {
  TEXT: "text",
  IMAGE: "image",
} as const;
// Document related semantic conventions
export const DocumentConventions = {
  DOCUMENT_ID: "document.id",
  DOCUMENT_CONTENT: "document.content",
  DOCUMENT_SCORE: "document.score",
  DOCUMENT_METADATA: "document.metadata",
} as const;
// Reranker related semantic conventions
export const RerankerConventions = {
  RERANKER_INPUT_DOCUMENTS: "reranker.input_documents",
  RERANKER_OUTPUT_DOCUMENTS: "reranker.output_documents",
  RERANKER_QUERY: "reranker.query",
  RERANKER_MODEL_NAME: "reranker.model_name",
  RERANKER_TOP_K: "reranker.top_k",
} as const;
// Embedding related semantic conventions
export const EmbeddingConventions = {
  EMBEDDING_TEXT: "embedding.text",
  EMBEDDING_VECTOR: "embedding.vector",
  EMBEDDING_MODEL_NAME: "embedding.model_name",
  EMBEDDING_EMBEDDINGS: "embedding.embeddings",
} as const;
// Tool call related semantic conventions
export const ToolCallConventions = {
  TOOL_CALL_ID: "tool_call.id",
  TOOL_CALL_FUNCTION_NAME: "tool_call.function.name",
  TOOL_CALL_FUNCTION_ARGUMENTS_JSON: "tool_call.function.arguments",
} as const;
// Image related semantic conventions
export const ImageConventions = {
  IMAGE_URL: "image.url",
} as const;

// Audio related semantic conventions
export const AudioConventions = {
  AUDIO_URL: "audio.url",
  AUDIO_MIME_TYPE: "audio.mime_type",
  AUDIO_TRANSCRIPT: "audio.transcript",
} as const;

// Prompt related semantic conventions
export const PromptConventions = {
  PROMPT_VENDOR: "prompt.vendor",
  PROMPT_ID: "prompt.id",
  PROMPT_URL: "prompt.url",
} as const;

// Common enums
export enum MimeType {
  TEXT = "text/plain",
  JSON = "application/json",
  AUDIO_WAV = "audio/wav",
}

export enum LLMSystem {
  OPENAI = "openai",
  ANTHROPIC = "anthropic",
  MISTRALAI = "mistralai",
  COHERE = "cohere",
  VERTEXAI = "vertexai",
}

export enum LLMProvider {
  OPENAI = "openai",
  ANTHROPIC = "anthropic",
  MISTRALAI = "mistralai",
  COHERE = "cohere",
  // Cloud Providers of LLM systems
  GOOGLE = "google",
  AWS = "aws",
  AZURE = "azure",
}

Use semantic conventions in your code

Import the constants and set them as span attributes in your instrumented functions.

# pip install fi-instrumentation-otel

from fi_instrumentation.fi_types import SpanAttributes, FiSpanKindValues

def chat(message: str):
    with tracer.start_as_current_span("an_llm_span") as span:
        span.set_attribute(
            SpanAttributes.GEN_AI_SPAN_KIND,
            FiSpanKindValues.LLM.value
        )

        # Equivalent to:
        # span.set_attribute(
        #     "gen_ai.span.kind",
        #     "LLM",
        # )

        span.set_attribute(
            SpanAttributes.INPUT_VALUE,
            message,
        )
import { SemanticConventions, FISpanKind } from '@traceai/fi-semantic-conventions';

function chat(message: string) {
    const span = tracer.startSpan("an_llm_span");

    span.setAttributes({
        [SemanticConventions.FI_SPAN_KIND]: FISpanKind.LLM,
        [SemanticConventions.INPUT_VALUE]: message,
        [SemanticConventions.LLM_MODEL_NAME]: "gpt-4",
    });

    // Your LLM logic here...

    span.setAttributes({
        [SemanticConventions.OUTPUT_VALUE]: response,
        [SemanticConventions.LLM_TOKEN_COUNT_TOTAL]: tokenCount,
    });

    span.end();
}

Convert messages to span attributes

OpenTelemetry span attributes must be simple types (bool, str, bytes, int, float, or flat lists of these). To export a list of message objects, flatten each object using an index prefix.

# List of messages from OpenAI or another LLM provider
messages = [{"message.role": "user", "message.content": "hello"},
            {"message.role": "assistant", "message.content": "hi"}]

# Assuming you have a span object already created
for i, obj in enumerate(messages):
    for key, value in obj.items():
        span.set_attribute(f"input.messages.{i}.{key}", value)
import { MessageConventions } from '@traceai/fi-semantic-conventions';

// List of messages from OpenAI or another LLM provider
const messages = [
    { "message.role": "user", "message.content": "hello" },
    { "message.role": "assistant", "message.content": "hi" }
];

// Assuming you have a span object already created
messages.forEach((obj, i) => {
    Object.entries(obj).forEach(([key, value]) => {
        span.setAttribute(`input.messages.${i}.${key}`, value);
    });
});

// Or using semantic conventions constants:
messages.forEach((message, i) => {
    span.setAttributes({
        [`input.messages.${i}.${MessageConventions.MESSAGE_ROLE}`]: message["message.role"],
        [`input.messages.${i}.${MessageConventions.MESSAGE_CONTENT}`]: message["message.content"],
    });
});

Attribute overview

AttributeTypeExampleDescription
document.contentString”This is a sample document content.”The content of a retrieved document
document.idString/Integer”1234” or 1Unique identifier for a document
document.metadataJSON String"{'author': 'John Doe', 'date': '2023-09-09'}"Metadata associated with a document
document.scoreFloat0.98Score representing the relevance of a document
embedding.embeddingsList of objects[{"embedding.vector": [...], "embedding.text": "hello"}]List of embedding objects including text and vector data
embedding.model_nameString”BERT-base”Name of the embedding model used
embedding.textString”hello world”The text represented in the embedding
embedding.vectorList of floats[0.123, 0.456, …]The embedding vector consisting of a list of floats
exception.escapedBooleantrueIndicator if the exception has escaped the span’s scope
exception.messageString”Null value encountered”Detailed message describing the exception
exception.stacktraceString”at app.main(app.java:16)“The stack trace of the exception
exception.typeString”NullPointerException”The type of exception that was thrown
input.mime_typeString”text/plain” or “application/json”MIME type representing the format of input.value
input.valueString"{'query': 'What is the weather today?'}"The input value to an operation
llm.function_callJSON String"{function_name: 'add', args: [1, 2]}"Object recording details of a function call in models or APIs
llm.input_messagesList of objects[{"message.role": "user", "message.content": "hello"}]List of messages sent to the LLM in a chat API request
llm.invocation_parametersJSON string"{'model_name': 'gpt-3', 'temperature': 0.7}"Parameters used during the invocation of an LLM or API
llm.model_nameString”gpt-3.5-turbo”The name of the language model being utilized
llm.output_messagesList of objects[{"message.role": "user", "message.content": "hello"}]List of messages received from the LLM in a chat API request
llm.prompt_template.templateString"Weather forecast for {city} on {date}"Template used to generate prompts as Python f-strings
llm.prompt_template.variablesJSON String"{'context': '<context from retrieval>', 'subject': 'math'}"JSON of key value pairs applied to the prompt template
llm.prompt_template.versionString”v1.0”The version of the prompt template
llm.token_count.completionInteger15The number of tokens in the completion
llm.token_count.promptInteger5The number of tokens in the prompt
llm.token_count.totalInteger20Total number of tokens, including prompt and completion
message.contentString”What’s the weather today?”The content of a message in a chat
message.function_call_arguments_jsonJSON String"{'x': 2}"The arguments to the function call in JSON
message.function_call_nameString”multiply” or “subtract”Function call function name
message.roleString”user” or “system”Role of the entity in a message (e.g., user, system)
message.tool_callsList of objects[{"tool_call.function.name": "get_current_weather"}]List of tool calls (e.g. function calls) generated by the LLM
metadataJSON String"{'author': 'John Doe', 'date': '2023-09-09'}"Metadata associated with a span
fi.span.kindString”CHAIN”The kind of span (e.g., CHAIN, LLM, RETRIEVER, RERANKER)
output.mime_typeString”text/plain” or “application/json”MIME type representing the format of output.value
output.valueString”Hello, World!”The output value of an operation
reranker.input_documentsList of objects[{"document.id": "1", "document.score": 0.9, "document.content": "..."}]List of documents as input to the reranker
reranker.model_nameString”cross-encoder/ms-marco-MiniLM-L-12-v2”Model name of the reranker
reranker.output_documentsList of objects[{"document.id": "1", "document.score": 0.9, "document.content": "..."}]List of documents outputted by the reranker
reranker.queryString”How to format timestamp?”Query parameter of the reranker
reranker.top_kInteger3Top K parameter of the reranker
retrieval.documentsList of objects[{"document.id": "1", "document.score": 0.9, "document.content": "..."}]List of retrieved documents
session.idString”26bcd3d2-cad2-443d-a23c-625e47f3324a”Unique identifier for a session
tag.tagsList of strings[“shopping”, “travel”]List of tags to give the span a category
tool.descriptionString”An API to get weather data.”Description of the tool’s purpose and functionality
tool.nameString”WeatherAPI”The name of the tool being utilized
tool.parametersJSON string"{'a': 'int'}"The parameters definition for invoking the tool
tool_call.function.argumentsJSON string"{'city': 'London'}"The arguments for the function being invoked by a tool call
tool_call.function.nameString”get_current_weather”The name of the function being invoked by a tool call
user.idString”9328ae73-7141-4f45-a044-8e06192aa465”Unique identifier for a user

Key concepts

  • SpanAttributes: Python class containing attribute key constants for span-level data (inputs, outputs, model name, token counts, prompt templates, and more). Import from fi_instrumentation.fi_types.
  • MessageAttributes: Attribute keys for structuring LLM input/output messages (role, content, tool calls, function call details).
  • DocumentAttributes: Attribute keys for retrieved documents, including ID, content, score, and metadata.
  • RerankerAttributes: Attribute keys for reranker spans (input/output documents, query, model name, top-k).
  • EmbeddingAttributes: Attribute keys for embedding spans (text and vector).
  • ToolCallAttributes: Attribute keys for tool call objects generated by an LLM (ID, function name, arguments).
  • FiSpanKindValues: Enumeration of valid values for fi.span.kind: LLM, CHAIN, RETRIEVER, RERANKER, EMBEDDING, AGENT, TOOL, GUARDRAIL, EVALUATOR, UNKNOWN.
  • Flattening: OpenTelemetry span attributes must be simple scalar types or flat lists. Nested objects (such as lists of messages) must be flattened with index prefixes like llm.input_messages.0.message.role.

Next Steps

Was this page helpful?

Questions & Discussion