Repository: truera/trulens
Issue: Groundedness does not work for VirtualApp
Root cause: Unimplemented Feature Gap

I am trying to evaluate Groundedness, Answer Relevance and Context Relevance , using Virtual App module on existing data. When I run the dashboard , I see answer relevance and context relevance, but groundedness is not calculated.

**TruLens version: 2.5.0** 



```
from pathlib import Path
import os
from time import time
import numpy as np
from typing import Any, Dict, List
from trulens.core import TruSession, Feedback
from trulens.dashboard import run_dashboard
from trulens.providers.openai import OpenAI as TruLensOpenAI
from trulens.core import Select
from trulens.apps.virtual import VirtualApp,VirtualRecord
from trulens.apps.virtual import TruVirtual
if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = ""

# Disable OTEL before anything else loads
os.environ["TRULENS_OTEL_TRACING"] = "0"

# Start a fresh TruLens session/db
session = TruSession()
session.reset_database()


def main():
    virtual_app = {
    'llm': {'modelname': 'gpt-4o'},
    'template': 'Sample app',
    'debug': 'This is a sample virtual app'
    }   
    # Converting the dictionary to a VirtualApp instance
    virtual_app = VirtualApp(virtual_app)
    virtual_app[Select.RecordCalls.llm.maxtokens] = 1024
    retriever_component = Select.RecordCalls.retriever
    virtual_app[retriever_component] = 'ElasticsearchRetrieverComponent' 
    # Selector for the context retrieval component's `get_context` call
    context_call = retriever_component.get_context
    # Creating virtual records
    rec1 = VirtualRecord(
        main_input='What is Biodiversity?',
        main_output='Biodiversity in agriculture enhances ecosystem resilience, supports essential ecological functions, and strengthens long-term food security.',
        calls={
            context_call: {
                'args': ['What is Biodiversity?'],
                'rets': [
                            "Biodiversity in agriculture supports resilient ecosystems by maintaining a wide variety of crops, livestock, and beneficial organisms.",
                            "It improves soil health, reduces vulnerability to pests, and enhances essential processes like pollination.",
                            "Greater diversity strengthens food security and helps farming systems adapt to environmental change."
                        ]
            }
        }
    )
   
    # Configure OpenAI provider for evaluation
    provider = TruLensOpenAI(model_engine="gpt-5-nano")
    
    context = context_call.rets[:]
    print(f"Context selector: {context}")
    # Check for groundedness of answer with respect to retrieved contexts.
    f_groundedness = (
    Feedback(
        provider.groundedness_measure_with_cot_reasons,
        name="Groundedness",
    )
    .on(context)
    .on_output()
    )
    
   # Question/answer relevance between overall question and answer.
    f_answer_relevance = (
        Feedback(provider.relevance_with_cot_reasons, name="Answer Relevance")
        .on_input()
        .on_output()
    )

    # Context relevance between question and each context chunk.
    f_context_relevance = (
        Feedback(
            provider.context_relevance_with_cot_reasons, name="Context Relevance"
        )
        .on_input()
        .on(context)
        .aggregate(np.mean)  
    )
    # Setting up the virtual recorder
    virtual_recorder = TruVirtual(
        app_name='Sample-Virtual-App',
        app_version='base',
        app=virtual_app,
        feedbacks=[f_groundedness, f_answer_relevance, f_context_relevance],
        session=session
    )
    virtual_recorder.add_record(rec1)
    session.get_leaderboard()
    run_dashboard(session)

if __name__ == "__main__":
    main()
```





When I launch the dashboard on the browser `Answer Relevance` and  `Context Relevance` are calculated properly but Groundedness is blank. The name of the column is somehow `Groundedness_calls` and not the name `Groundedness` which was provided in the code, it appends `_calls`. See screenshot below.

<img width="2050" height="388" alt="Image" src="https://github.com/user-attachments/assets/65dcd33c-09c4-408e-b3b5-34ff9caa8b63" />




<!-- Greeting -->
Hi @unnieayilliath! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the trulens team.

<!-- Answer -->
The reason you see the column as `Groundedness_calls` instead of just `Groundedness` is due to how Trulens handles feedback functions that use selectors like `.on(context)`. When you apply a feedback to a specific call path or selector, Trulens appends a suffix (like `_calls`) to the column name in the dashboard to reflect this path—this is expected behavior and not a bug. The metric is being calculated and stored correctly; you can interpret the `Groundedness_calls` column as your intended Groundedness score. The small value is likely due to the scale of the groundedness metric, not an error in calculation or display. If you want a different column name, you would need to adjust how you configure the feedback selectors, but the current setup is functioning as intended. More details on this naming convention are discussed [here](https://github.com/truera/trulens/issues/2291) and [here](https://github.com/truera/trulens/issues/1739).


<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*

---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/d94a6fde-a6bb-49ba-98cc-c1f750fc402c?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/e16d1378-a540-46b6-bd0e-816c493d2aee/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/truera/trulens/issues/2292)

@dosu thanks the column name is clear. However, there is no value for Groundedness_calls . The field is blank

<!-- Answer -->
A blank Groundedness_calls field usually means the feedback wasn't computed or stored. Here are the most common fixes:

- Make sure to call virtual_recorder.wait_for_feedback_results() after adding records, before accessing the dashboard or leaderboard—this ensures all feedback is finished computing [source](https://github.com/truera/trulens/issues/1884).
- Avoid passing app_id filters to get_leaderboard() or get_records_and_feedback(), as this can filter out feedback results [source](https://github.com/truera/trulens/issues/1884).
- Double-check your feedback function setup: for groundedness, you should instantiate a Groundedness object with your provider, then use its methods in Feedback, not the provider method directly [source](https://github.com/truera/trulens/issues/1739).
- If you see errors in your logs (especially from the feedback function or provider), that can also cause blank values—check for any exceptions or warnings during evaluation [source](https://github.com/truera/trulens/issues/1987).
- If you're on TruLens <2.3.0, upgrade—there were bugs in groundedness_measure_with_cot_reasons that could cause this issue [source](https://github.com/truera/trulens/issues/2174).

If none of these solve it, try switching to a different provider/model or use server-side feedback computation to rule out provider-specific issues [source](https://github.com/truera/trulens/issues/1717). Let me know what you find!


<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*

---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/46a5e813-fe3a-4b72-8afc-90b708edef05?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/e16d1378-a540-46b6-bd0e-816c493d2aee/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/truera/trulens/issues/2292)

@dosu 

1. virtual_recorder.wait_for_feedback_results()  did not make any difference
2. There is no app_id filters on the get_leaderboard or get_records_and_feedback
3. Feedback function for groundedness looks all correct.
4. There are no errors in the logs.
5. TruLens version used is 2.5.0


<!-- Answer -->
Given your setup and that the usual fixes haven't worked, there are two likely causes left:

1. There was a known bug with feedback functions (including groundedness) in TruLens when using Python 3.12 or 3.13, which resulted in blank feedback values—even if no errors appeared in logs. The fix for this was merged, but if your environment is still on Python 3.12/3.13, try running with Python 3.9–3.11 to see if the issue resolves [details here](https://github.com/truera/trulens/issues/1987).

2. Groundedness feedback is sensitive to the format of the context input. If the context passed to the feedback is not a list of semantically meaningful strings (e.g., it's raw text chunks or not properly preprocessed), the evaluator can silently fail or return blanks. Make sure your context is a list of clean, meaningful statements or sentences, not just arbitrary text splits [see discussion](https://github.com/truera/trulens/issues/1690).

If both of these check out, try running a minimal example with a single, simple context string and see if the groundedness score appears. This can help isolate whether the issue is with the input data or something deeper in the environment.


<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*

---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/b187e580-f567-4281-a156-0fb029f4b6a9?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/e16d1378-a540-46b6-bd0e-816c493d2aee/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/truera/trulens/issues/2292)

Hi @unnieayilliath - I see you are disabling OpenTelemetry mode. Can you try enabling it (you can just not set the env variable, otel is default for your trulens version)

@sfc-gh-jreini  once otel is enabled , virtual_recorder.add_record does not work anymore and throws an error that it is not supported when otel is enabled. 

Got it, will look into enabling this for otel.