> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Conversational Search

> Learn how to trace Google Cloud Discovery Engine conversational search calls with the Openlayer Ruby SDK

Openlayer traces the [Google Cloud Discovery Engine](https://cloud.google.com/generative-ai-app-builder/docs/introduction)
`ConversationalSearchService` through the `openlayer` Ruby gem. Once you trace a client, every
`answer_query` call it makes is published to Openlayer with the query, the grounded answer,
latency, and the retrieval steps Discovery Engine ran to produce that answer.

<Note>
  This tracer is Ruby only, and it is separate from the [Dialogflow
  CX](/integrations/dialogflow-cx) integration. Dialogflow CX reads agent logs
  from BigQuery; this tracer wraps a Discovery Engine SDK client in your own
  process.
</Note>

## Install and require

Install the Openlayer gem alongside the Google Discovery Engine client:

```bash theme={null}
gem install openlayer google-cloud-discovery_engine-v1
```

The tracer is not loaded by `require "openlayer"`, so require it explicitly:

```ruby theme={null}
require "openlayer"
require "openlayer/integrations/google_conversational_search_tracer"
require "google/cloud/discovery_engine/v1"
```

<Info>
  **Prerequisites**:

  * A [project](/workspace-and-projects/creating-and-loading-projects) in Openlayer with monitoring mode enabled.

  * An [Openlayer API key](/workspace-and-projects/find-your-api-key).

  * The inference pipeline ID of the data source you want to publish to.
</Info>

## Trace a ConversationalSearchService client

Pass your Google client to `trace_client`. It patches `answer_query` on that client instance, so
you keep calling the Google SDK exactly as you did before:

```ruby theme={null}
google_client = Google::Cloud::DiscoveryEngine::V1::ConversationalSearchService::Client.new
openlayer = Openlayer::Client.new(api_key: ENV["OPENLAYER_API_KEY"])

Openlayer::Integrations::GoogleConversationalSearchTracer.trace_client(
  google_client,
  openlayer_client: openlayer,
  inference_pipeline_id: "your-pipeline-id"
)

response = google_client.answer_query(
  serving_config: "projects/.../servingConfigs/default",
  query: { text: "What is the meaning of life?" }
)
```

Both calling styles work: pass a request object positionally, or pass `serving_config` and `query`
as keyword arguments as above.

<Tip>
  Tracing never breaks your application. If publishing a trace fails, the error
  is swallowed and `answer_query` still returns Google's response. Set
  `OPENLAYER_DEBUG` in your environment to print those failures to stderr while
  you are setting the integration up.
</Tip>

## Sessions, users, additional columns

`trace_client` takes the following keyword arguments:

| Keyword                 | Required | Description                                                                                  |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------- |
| `openlayer_client`      | Yes      | The `Openlayer::Client` that publishes the traces.                                           |
| `inference_pipeline_id` | Yes      | The inference pipeline the traces are published to.                                          |
| `session_id`            | No       | Pins every trace from this client to one session. Overrides the session on the request.      |
| `user_id`               | No       | Pins every trace from this client to one user. Overrides the user pseudo ID on the response. |
| `additional_columns`    | No       | Static column values merged into every trace, for example `{ environment: "production" }`.   |

When you do not set `session_id`, Openlayer falls back to the `session` on the request, and when
you do not set `user_id`, it falls back to `user_pseudo_id` on the response's session. Either way,
you can group and filter traces by [session and user](/monitoring/sessions-and-users) in Openlayer.

To attach data to a single call rather than to every call, pass `additional_columns` to
`answer_query`. The tracer strips that argument before forwarding the call, so Google never sees
it:

```ruby theme={null}
Openlayer::Integrations::GoogleConversationalSearchTracer.trace_client(
  google_client,
  openlayer_client: openlayer,
  inference_pipeline_id: "your-pipeline-id",
  additional_columns: { environment: "production" }
)

response = google_client.answer_query(
  serving_config: "projects/.../servingConfigs/default",
  query: { text: "What is the meaning of life?" },
  additional_columns: { trace_id: "abc-123" }
)
```

On a key conflict, the per-call value wins over the static default. Keys that collide with a
column the tracer computes itself are dropped: `query`, `answer`, `latency_ms`, `timestamp`,
`metadata`, `steps`, `context`, `session_id`, and `user_id`.

## What is captured

Each `answer_query` call becomes one row with the query, the answer text, the latency, and the
request timestamp. The row carries a single top-level step named **Conversational Search
answer\_query**, recorded with provider `Google` and model `google-discovery-engine`.

Underneath that step, Openlayer captures:

* **Retrieval steps**: each execution step Discovery Engine reports becomes a retriever step,
  showing the rephrased query next to your original one and the documents it returned.
* **Grounding**: citations, references, and related questions, when the answer includes them.
* **Context**: the content of the answer's references, so the
  [context column](/monitoring/context) is populated for retrieval-based tests.
* **Metadata**: the serving config, the grounding score, the answer state, citation and reference
  counts, and any reasons the answer was skipped.

With calls flowing into Openlayer, you can [create tests](/tests/overview) that run continuously
on top of them.
