DEV Community

Elowen
Elowen

Posted on

Make LangChain Web Search Auditable with Source URLs and Timestamps

A LangChain agent with web search can answer with fresher context, but freshness is not enough.

When the answer looks wrong, you need to know what the agent searched, which URLs it used, when the search happened, and which results were passed into the final prompt. Without that trace, debugging becomes guesswork.

This walkthrough shows a small pattern for making a LangChain search step auditable with source URLs and timestamps using TalorData SERP API.

Basic setup

The confirmed LangChain package is langchain-talordata.

pip install langchain-talordata
Enter fullscreen mode Exit fullscreen mode

Set the package environment variable:

export TALOR_API_KEY="<TALORDATA_TOKEN>"
Enter fullscreen mode Exit fullscreen mode

A common starting point:

from langchain_talordata import TalorSerpTool

search_tool = TalorSerpTool.from_env()
Enter fullscreen mode Exit fullscreen mode

The package reads TALOR_API_KEY. The value should be your TalorData token.

What should be logged

A useful search trace should answer five questions:

  • What did the user ask?
  • What query did the agent search?
  • When did the search happen?
  • Which URLs were returned?
  • Which URLs were selected for the final answer?

That means the log should preserve both the tool call and the selected evidence.

A simple trace shape

Start with a small structure:

from dataclasses import dataclass, asdict
from datetime import datetime, timezone
from typing import Any


@dataclass
class SearchTrace:
    user_request: str
    generated_query: str
    searched_at: str
    selected_sources: list[dict[str, Any]]
    result_count: int
Enter fullscreen mode Exit fullscreen mode

The timestamp should be created when the search result is fetched, not after the final answer is generated.

def utc_now() -> str:
    return datetime.now(timezone.utc).isoformat()
Enter fullscreen mode Exit fullscreen mode

Shape the search results

Do not pass the entire SERP response into the final prompt by default. Keep a compact source object.

def compact_source(item: dict) -> dict:
    return {
        "position": item.get("position"),
        "title": item.get("title"),
        "url": item.get("link"),
        "snippet": item.get("description"),
    }
Enter fullscreen mode Exit fullscreen mode

For many agent tasks, the first useful source fields are position, title, URL, and snippet.

Build the search wrapper

Your exact wrapper depends on how your LangChain app calls tools, but the boundary should be clear:

def search_with_trace(user_request: str, generated_query: str) -> tuple[list[dict], dict]:
    searched_at = utc_now()

    result = search_tool.invoke(generated_query)

    organic = result.get("organic", []) if isinstance(result, dict) else []
    selected_sources = [compact_source(item) for item in organic[:5]]

    trace = SearchTrace(
        user_request=user_request,
        generated_query=generated_query,
        searched_at=searched_at,
        selected_sources=selected_sources,
        result_count=len(organic),
    )

    return selected_sources, asdict(trace)
Enter fullscreen mode Exit fullscreen mode

If your tool call returns a different object shape, adapt the extraction layer. The key idea is the same: preserve the generated query, timestamp, and selected URLs.

Use the trace in the final answer

The final prompt should receive only selected sources, not the entire raw response.

Example prompt input:

User request:
{user_request}

Search query:
{generated_query}

Search timestamp:
{searched_at}

Selected sources:
{selected_sources}

Answer the user using the selected sources. If the sources are weak or incomplete, say so.
Enter fullscreen mode Exit fullscreen mode

This gives the model a clearer boundary between evidence and reasoning.

Store the trace

For a prototype, writing JSON lines is enough:

import json


def append_trace(path: str, trace: dict) -> None:
    with open(path, "a", encoding="utf-8") as file:
        file.write(json.dumps(trace, ensure_ascii=False) + "\n")
Enter fullscreen mode Exit fullscreen mode

In production, this trace may belong in a database, observability system, or internal evaluation table.

What this helps debug

A source trace helps answer:

  • Did the agent search the wrong query?
  • Did the SERP return weak results?
  • Did the source selection remove something important?
  • Did the answer rely on inference instead of evidence?
  • Was the answer generated from fresh or old search context?

That is much better than trying to inspect a final answer with no search record.

Final thought

Adding web search to an agent is useful. Making the search auditable is what makes it maintainable.

Start by logging the generated query, timestamp, selected URLs, and result count. That small trace will save a lot of debugging time later.

If you want to test this pattern with live Google results, TalorData gives new accounts 500 responses to build and inspect a small source-logging workflow.

Top comments (0)