From 4c5b623aee617a15927ef655dbe3f91b9f00bd26 Mon Sep 17 00:00:00 2001 From: rm Date: Tue, 14 Jul 2026 12:34:22 -0400 Subject: [PATCH 1/4] Switch enrichment cookbook from REST client to google-genai SDK Parallel grounding is available natively in the Gemini Python SDK as the parallel_ai_search tool, so the notebook no longer needs the local REST client: setup is now genai.Client plus one pip install, the hand-rolled pydantic-to-responseSchema converter is replaced by the SDK's native response_schema/parsed support, and a new section 1.4 attaches inline per-claim citations in code from grounding_supports byte offsets. Also adds a third use case, product catalog enrichment, reusing the same pipeline, and consolidates cells for a leaner read. Re-executed live end-to-end with all citations verified. Co-authored-by: Cursor --- .../gemini_search_enrichment.ipynb | 765 ++++++++++-------- 1 file changed, 444 insertions(+), 321 deletions(-) diff --git a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb index 4a9760e..0a5f473 100644 --- a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb +++ b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "29e31474", + "id": "de627238", "metadata": {}, "source": [ "# Grounded data enrichment with the Gemini API and Parallel Web Search\n", @@ -16,67 +16,50 @@ "- Parallel authentication, via either:\n", " - a **Parallel API key** from [platform.parallel.ai](https://platform.parallel.ai) (Bring Your Own Key), or\n", " - an active [Parallel Web Search subscription on the Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/parallel-web-systems-public/parallel-web-systems) for your project — in that case no API key is needed.\n", - "- The `gemini_parallel` package from this directory (installed in the next cell), which brings `pydantic` with it.\n", + "- Two pip packages, installed in the next cell: `google-genai` (the Gemini SDK) and `pydantic`.\n", "\n", "> Grounding with Parallel on Gemini Enterprise is currently in **Preview**. See the [Parallel integration docs](https://docs.parallel.ai/integrations/google-gemini-enterprise) and [Google's grounding documentation](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/grounding/grounding-with-parallel) for the current list of supported models.\n", "\n", - "The saved outputs below were generated on July 5, 2026. Because they use the live web, rerunning the notebook may return different sources and answers." + "The saved outputs below were generated on July 14, 2026. Because they use the live web, rerunning the notebook may return different sources and answers." ] }, { "cell_type": "markdown", - "id": "f3b07642", + "id": "a8b7333a", "metadata": {}, "source": [ "## 1. Set up Gemini with Parallel grounding\n", "\n", - "### 1.1 Install the `gemini_parallel` client\n", + "### 1.1 Install dependencies\n", "\n", - "The client lives in this directory (`src/gemini_parallel/`); installing it in editable mode also pulls in `pydantic`, which defines the typed output contracts in sections 2 and 3." + "Parallel grounding is available natively in the official Gemini Python SDK, [`google-genai`](https://googleapis.github.io/python-genai/), as the `parallel_ai_search` tool — no raw REST calls needed. `pydantic` defines the typed output contracts in sections 2–4." ] }, { "cell_type": "code", "execution_count": 1, - "id": "8793572e", + "id": "65f11f3b", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:07:48.525326Z", - "iopub.status.busy": "2026-07-07T02:07:48.525263Z", - "iopub.status.idle": "2026-07-07T02:07:50.436073Z", - "shell.execute_reply": "2026-07-07T02:07:50.435602Z" + "iopub.execute_input": "2026-07-14T16:31:29.490009Z", + "iopub.status.busy": "2026-07-14T16:31:29.489932Z", + "iopub.status.idle": "2026-07-14T16:31:30.392311Z", + "shell.execute_reply": "2026-07-14T16:31:30.391849Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.1.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.1.2\u001b[0m\r\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49m/Users/ruthvikmukkamala/parallel-cookbook/.scratch/venv/bin/python3.14 -m pip install --upgrade pip\u001b[0m\r\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], + "outputs": [], "source": [ - "%pip install --quiet -e ." + "%pip install --quiet --upgrade google-genai pydantic" ] }, { "cell_type": "markdown", - "id": "3eb01d31", + "id": "e4d69c87", "metadata": {}, "source": [ "### 1.2 Configure credentials and create the client\n", "\n", - "`GroundedGeminiClient` resolves Google Cloud auth through application default credentials and caches the OAuth token between requests. Three values configure it:\n", + "The SDK client targets the Gemini API on Google Cloud (`vertexai=True`) and resolves auth through application default credentials. Three values configure it:\n", "\n", "- **Project** — read from `GOOGLE_CLOUD_PROJECT` (must have the Gemini API enabled).\n", "- **Parallel API key** — read from `PARALLEL_API_KEY` for BYOK auth. Leave it unset if your project has a Google Cloud Marketplace subscription; if both are present, the API key takes precedence.\n", @@ -88,13 +71,13 @@ { "cell_type": "code", "execution_count": 2, - "id": "4276ca31", + "id": "1467d5e6", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:07:50.437204Z", - "iopub.status.busy": "2026-07-07T02:07:50.437118Z", - "iopub.status.idle": "2026-07-07T02:07:51.210734Z", - "shell.execute_reply": "2026-07-07T02:07:51.210225Z" + "iopub.execute_input": "2026-07-14T16:31:30.393806Z", + "iopub.status.busy": "2026-07-14T16:31:30.393708Z", + "iopub.status.idle": "2026-07-14T16:31:31.098816Z", + "shell.execute_reply": "2026-07-14T16:31:31.098460Z" } }, "outputs": [ @@ -103,7 +86,7 @@ "output_type": "stream", "text": [ "model : gemini-3.5-flash\n", - "endpoint : https://aiplatform.googleapis.com/v1/projects/your-gcp-project-id/locations/global/publishers/google/models/gemini-3.5-flash:generateContent\n" + "location : global\n" ] } ], @@ -112,7 +95,8 @@ "import os\n", "from getpass import getpass\n", "\n", - "from gemini_parallel import GroundedGeminiClient\n", + "from google import genai\n", + "from google.genai import types\n", "\n", "PROJECT_ID = os.environ.get(\"GOOGLE_CLOUD_PROJECT\")\n", "LOCATION = os.environ.get(\"GOOGLE_CLOUD_LOCATION\", \"global\")\n", @@ -121,61 +105,102 @@ " \"PARALLEL_API_KEY\"\n", ") or getpass(\"Parallel API key (leave blank if using a Marketplace subscription): \").strip()\n", "\n", - "client = GroundedGeminiClient(\n", - " project_id=PROJECT_ID,\n", - " location=LOCATION,\n", - " parallel_api_key=PARALLEL_API_KEY or None,\n", - ")\n", + "client = genai.Client(vertexai=True, project=PROJECT_ID, location=LOCATION)\n", "\n", "print(f\"model : {MODEL}\")\n", - "print(f\"endpoint : {client._get_endpoint_url(MODEL)}\")" + "print(f\"location : {LOCATION}\")" ] }, { "cell_type": "markdown", - "id": "a41fc29d", + "id": "8ff0068f", "metadata": {}, "source": [ "### 1.3 How grounding works — and how we'll call it\n", "\n", - "Grounding is enabled by a `parallelAiSearch` entry in the request's `tools` array, which the client builds from its `GroundingConfig`. When it is present, Gemini translates the prompt into web search queries, Parallel retrieves LLM-optimized excerpts from the live web, and the model composes its answer from that retrieved evidence.\n", + "Grounding is enabled by passing a `parallel_ai_search` tool in the request config. When it is present, Gemini translates the prompt into web search queries, Parallel retrieves LLM-optimized excerpts from the live web, and the model composes its answer from that retrieved evidence.\n", + "\n", + "The tool's `custom_configs` accepts any Parallel Search API parameter, but every field is optional and the defaults are the right starting point: per [Parallel's search best practices](https://docs.parallel.ai/search/best-practices), restrictive retrieval parameters (domain allowlists, low result caps, geo filters) can unnecessarily limit results and reduce quality, so we don't set any.\n", "\n", - "All of the grounding configuration is optional, and the defaults are the right starting point: per [Parallel's search best practices](https://docs.parallel.ai/search/best-practices), restrictive retrieval parameters (domain allowlists, low result caps, geo filters) can unnecessarily limit results and reduce quality, so we don't set any. The full parameter list is in the appendix.\n", + "We call `client.models.generate_content` in two modes:\n", "\n", - "We use `client.generate()` in two modes:\n", + "- **Grounded** for research calls — the config carries the Parallel tool, and the response's `grounding_metadata` holds the executed `web_search_queries`, the retrieved source documents (`grounding_chunks`), and per-claim attribution spans (`grounding_supports`).\n", + "- **Tool-free** for extraction calls — Gemini cannot combine a grounding tool with `response_schema` in one request, so structured output is a separate call with no tools attached.\n", "\n", - "- **Grounded** (the default) for research calls — returns a `GroundedResponse` whose `text` is the evidence prose, `web_search_queries` are the queries Gemini executed through Parallel, and `sources` are the retrieved documents parsed from the response's `groundingMetadata`.\n", - "- **Tool-free** (`grounded=False`) for extraction calls — Gemini cannot combine a grounding tool with `responseSchema` in one request, so structured output must be a separate call, with the schema and related settings passed through `generation_config`." + "The first grounded call below asks a current factual question and prints the queries Gemini ran through Parallel before the answer." ] }, { - "cell_type": "markdown", - "id": "cfc20361", - "metadata": {}, + "cell_type": "code", + "execution_count": 3, + "id": "eda3a5f2", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-14T16:31:31.104380Z", + "iopub.status.busy": "2026-07-14T16:31:31.104107Z", + "iopub.status.idle": "2026-07-14T16:31:40.138127Z", + "shell.execute_reply": "2026-07-14T16:31:40.137434Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Executed search queries:\n", + " - \"7,477\" \"selling, general and administrative\" Apple 2026\n", + "\n", + "Answer:\n", + "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (which ended March 28, 2026)—the company's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million).\n" + ] + } + ], "source": [ - "## 2. Company enrichment, step by step\n", + "parallel_tool = types.Tool(\n", + " parallel_ai_search=types.ToolParallelAiSearch(\n", + " api_key=PARALLEL_API_KEY or None, # omit for Marketplace-subscription auth\n", + " )\n", + ")\n", "\n", - "We enrich one record at a time so the Gemini and Parallel integration stays visible; applying the pattern to many rows is a loop over the same three calls.\n", + "response = client.models.generate_content(\n", + " model=MODEL,\n", + " contents=(\n", + " \"What was Apple's selling, general and administrative (SG&A) expense in its most \"\n", + " \"recently reported fiscal quarter? Give the exact figure and state which quarter it covers.\"\n", + " ),\n", + " config=types.GenerateContentConfig(tools=[parallel_tool], temperature=0.2),\n", + ")\n", "\n", - "### 2.1 Define the output contract\n", + "grounding = response.candidates[0].grounding_metadata\n", + "print(\"Executed search queries:\")\n", + "for query in grounding.web_search_queries or []:\n", + " print(f\" - {query}\")\n", "\n", - "Pydantic gives us a single source of truth for three things: the JSON Schema sent to Gemini, the validation of the model's output, and the typed object handed to downstream code. The field descriptions do real work here — they tell the model what each field means and, critically, the exact format it must use. `headquarters` and `founded_year` are good examples: their descriptions pin the formats (\"City, Region, Country\" and `YYYY`), so values come back machine-comparable rather than free-text like \"the Bay Area\" or \"founded about five years ago\".\n", + "print(f\"\\nAnswer:\\n{response.text.strip()}\")" + ] + }, + { + "cell_type": "markdown", + "id": "51c38fb6", + "metadata": {}, + "source": [ + "### 1.4 Attach inline citations from the grounding metadata\n", "\n", - "Structured output guarantees that the response follows this shape. It does not guarantee that every fact is correct, so the schema also carries per-field `citations` to keep the evidence visible.\n", + "The response's `grounding_supports` maps byte-range segments of the answer text to the indices of the `grounding_chunks` that back them. That lets us attach citations **in code** instead of asking the model to write links: the model never generates a URL, so it cannot invent or rewrite one — every footnote is copied from the grounding metadata by our own program.\n", "\n", - "Gemini's `responseSchema` accepts an OpenAPI-style subset of JSON Schema, not pydantic's dialect (it rejects `$ref`/`$defs` and unknown keys, and models `Optional` with `nullable` rather than `anyOf`), so `to_gemini_schema` performs that mechanical conversion." + "One implementation detail: segment offsets (`start_index`/`end_index`) count **UTF-8 bytes**, not characters, so we insert markers into the encoded text and decode at the end." ] }, { "cell_type": "code", - "execution_count": 3, - "id": "1b5cfbf5", + "execution_count": 4, + "id": "f7a7f5ca", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:07:51.212129Z", - "iopub.status.busy": "2026-07-07T02:07:51.211942Z", - "iopub.status.idle": "2026-07-07T02:07:51.217686Z", - "shell.execute_reply": "2026-07-07T02:07:51.217170Z" + "iopub.execute_input": "2026-07-14T16:31:40.140924Z", + "iopub.status.busy": "2026-07-14T16:31:40.140820Z", + "iopub.status.idle": "2026-07-14T16:31:40.144488Z", + "shell.execute_reply": "2026-07-14T16:31:40.144034Z" } }, "outputs": [ @@ -183,27 +208,72 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\n", - " \"required\": [\n", - " \"company_name\",\n", - " \"official_domain\",\n", - " \"ceo_name\",\n", - " \"headquarters\",\n", - " \"headquarters_address\",\n", - " \"founded_year\",\n", - " \"citations\"\n", - " ],\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"company_name\": {\n", - " \"description\": \"Company name, copied exactly from the input record.\",\n", - " \"type\": \"string\"\n", - " },\n", - " \"official_domain\": {\n", - " \"description\": \"Official domain, copi …\n" + "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (which ended March 28, 2026)—the company's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million)[1].\n", + "\n", + "Sources:\n", + "[1] UNITED STATES SECURITIES AND EXCHANGE COMMISSION Washington, D.C. 20549 — https://s2.q4cdn.com/470004039/files/doc_earnings/2026/q2/filing/10Q-Q2-2026-as-filed.pdf\n" ] } ], + "source": [ + "def with_inline_citations(response) -> str:\n", + " \"\"\"Insert [n] markers after each supported claim and append the numbered source list.\"\"\"\n", + " metadata = response.candidates[0].grounding_metadata\n", + " chunks = metadata.grounding_chunks or []\n", + " supports = metadata.grounding_supports or []\n", + "\n", + " encoded = response.text.encode(\"utf-8\") # segment offsets are byte offsets\n", + " insertions = []\n", + " for support in supports:\n", + " end = support.segment.end_index\n", + " indices = support.grounding_chunk_indices or []\n", + " if end is not None and indices:\n", + " insertions.append((end, \"\".join(f\"[{i + 1}]\" for i in indices)))\n", + " for end, marker in sorted(insertions, key=lambda pair: -pair[0]): # right to left\n", + " encoded = encoded[:end] + marker.encode(\"utf-8\") + encoded[end:]\n", + "\n", + " footnotes = \"\\n\".join(\n", + " f\"[{i}] {' '.join((chunk.web.title or '(untitled)').split())} — {chunk.web.uri}\"\n", + " for i, chunk in enumerate(chunks, start=1)\n", + " if chunk.web\n", + " )\n", + " return f\"{encoded.decode('utf-8').strip()}\\n\\nSources:\\n{footnotes}\"\n", + "\n", + "\n", + "print(with_inline_citations(response))" + ] + }, + { + "cell_type": "markdown", + "id": "d01fc327", + "metadata": {}, + "source": [ + "## 2. Company enrichment, step by step\n", + "\n", + "We enrich one record at a time so the Gemini and Parallel integration stays visible; applying the pattern to many rows is a loop over the same three calls.\n", + "\n", + "### 2.1 Define the output contract\n", + "\n", + "Pydantic gives us a single source of truth for three things: the JSON Schema sent to Gemini, the validation of the model's output, and the typed object handed to downstream code. The field descriptions do real work here — they tell the model what each field means and, critically, the exact format it must use. `headquarters` and `founded_year` are good examples: their descriptions pin the formats (\"City, Region, Country\" and `YYYY`), so values come back machine-comparable rather than free-text like \"the Bay Area\" or \"founded about five years ago\".\n", + "\n", + "Structured output guarantees that the response follows this shape. It does not guarantee that every fact is correct, so the schema also carries per-field `citations` to keep the evidence visible.\n", + "\n", + "The SDK accepts a pydantic model directly as `response_schema` — it converts the model to the API's OpenAPI-subset schema and parses the response back into a typed instance on `response.parsed`, so no hand-written schema conversion is needed." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "683494b4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-14T16:31:40.145508Z", + "iopub.status.busy": "2026-07-14T16:31:40.145451Z", + "iopub.status.idle": "2026-07-14T16:31:40.149512Z", + "shell.execute_reply": "2026-07-14T16:31:40.149113Z" + } + }, + "outputs": [], "source": [ "from pydantic import BaseModel, Field\n", "\n", @@ -230,79 +300,19 @@ " founded_year: str = Field(\n", " description=\"Year the company was founded, as a four-digit year in YYYY format, or 'unknown'.\"\n", " )\n", - " citations: list[Citation] = Field(description=\"Sources supporting every populated field.\")\n", - "\n", - "\n", - "GEMINI_SCHEMA_KEYS = {\n", - " \"type\", \"format\", \"description\", \"nullable\", \"enum\",\n", - " \"required\", \"minimum\", \"maximum\", \"minItems\", \"maxItems\",\n", - "}\n", - "\n", - "\n", - "def to_gemini_schema(model_cls: type[BaseModel]) -> dict:\n", - " \"\"\"Convert a pydantic JSON Schema to the OpenAPI subset the Gemini API's responseSchema accepts:\n", - " inline $refs, collapse Optional[...] anyOf into nullable, drop unsupported keys.\"\"\"\n", - " schema = model_cls.model_json_schema()\n", - " defs = schema.get(\"$defs\", {})\n", - "\n", - " def clean(node: dict) -> dict:\n", - " if \"$ref\" in node:\n", - " node = defs[node[\"$ref\"].split(\"/\")[-1]]\n", - " if \"anyOf\" in node: # pydantic emits Optional[X] as anyOf [X, null]\n", - " variant = next(v for v in node[\"anyOf\"] if v.get(\"type\") != \"null\")\n", - " node = {**variant, \"nullable\": True, **{k: v for k, v in node.items() if k != \"anyOf\"}}\n", - " cleaned = {key: value for key, value in node.items() if key in GEMINI_SCHEMA_KEYS}\n", - " if \"properties\" in node:\n", - " cleaned[\"properties\"] = {name: clean(sub) for name, sub in node[\"properties\"].items()}\n", - " if \"items\" in node:\n", - " cleaned[\"items\"] = clean(node[\"items\"])\n", - " return cleaned\n", - "\n", - " return clean(schema)\n", - "\n", - "\n", - "company_schema = to_gemini_schema(CompanyEnrichment)\n", - "print(json.dumps(company_schema, indent=2)[:400], \"…\")" + " citations: list[Citation] = Field(description=\"Sources supporting every populated field.\")" ] }, { "cell_type": "markdown", - "id": "a4f510ff", + "id": "ab9b6b0b", "metadata": {}, "source": [ - "### 2.2 Define the input record\n", + "### 2.2 Define the input record and the two instruction blocks\n", "\n", - "The input is deliberately small: it contains what we already know. The workflow's job is to add verified fields without changing the original identity of the record — exactly the shape of a CRM row or a vendor list entry waiting to be filled in." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "183f1d5c", - "metadata": { - "execution": { - "iopub.execute_input": "2026-07-07T02:07:51.218694Z", - "iopub.status.busy": "2026-07-07T02:07:51.218635Z", - "iopub.status.idle": "2026-07-07T02:07:51.220153Z", - "shell.execute_reply": "2026-07-07T02:07:51.219852Z" - } - }, - "outputs": [], - "source": [ - "company_row = {\n", - " \"company_name\": \"Anthropic\",\n", - " \"official_domain\": \"anthropic.com\",\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "96ccc836", - "metadata": {}, - "source": [ - "### 2.3 Separate the research objective from the enrichment policy\n", + "The input record is deliberately small: it contains what we already know. The workflow's job is to add verified fields without changing the original identity of the record — exactly the shape of a CRM row or a vendor list entry waiting to be filled in.\n", "\n", - "The two model calls get two different instruction blocks, mirroring the two jobs:\n", + "The two model calls then get two different instruction blocks, mirroring the two jobs:\n", "\n", "- **The research objective** goes to the *grounding* call. Per Parallel's best practices for search objectives, it is a natural-language description of the research goal that names the key entity, states exactly what to find, and carries source guidance (\"prefer the company's official website, press releases, and filings\") in prose. Retrieval itself stays unrestricted — the guidance steers ranking without excluding evidence.\n", "- **The enrichment policy** goes to the *structuring* call. It contains only output rules: copy identity fields exactly, copy citation URLs only from the supplied source list, honor each field's declared format, and represent uncertainty as `\"unknown\"` rather than a guess. It never mentions searching, because the structuring call has no tools.\n", @@ -312,18 +322,24 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "6c11ee00", + "execution_count": 6, + "id": "3b58b9ec", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:07:51.221043Z", - "iopub.status.busy": "2026-07-07T02:07:51.220990Z", - "iopub.status.idle": "2026-07-07T02:07:51.222664Z", - "shell.execute_reply": "2026-07-07T02:07:51.222371Z" + "iopub.execute_input": "2026-07-14T16:31:40.150467Z", + "iopub.status.busy": "2026-07-14T16:31:40.150411Z", + "iopub.status.idle": "2026-07-14T16:31:40.152324Z", + "shell.execute_reply": "2026-07-14T16:31:40.152009Z" } }, "outputs": [], "source": [ + "company_row = {\n", + " \"company_name\": \"Anthropic\",\n", + " \"official_domain\": \"anthropic.com\",\n", + "}\n", + "\n", + "\n", "def company_objective(record: dict) -> str:\n", " return f\"\"\"Research the company {record[\"company_name\"]} (official website: {record[\"official_domain\"]}).\n", "\n", @@ -348,29 +364,29 @@ }, { "cell_type": "markdown", - "id": "a57501d1", + "id": "4fe95c6a", "metadata": {}, "source": [ - "### 2.4 Ground: gather cited evidence\n", + "### 2.3 Ground: gather cited evidence\n", "\n", - "The grounding call sends the research objective through `client.generate()` with default (unrestricted) retrieval and a low temperature — this is factual research, not creative writing. The returned `GroundedResponse` carries, parsed from the response's `groundingMetadata`:\n", + "The grounding call sends the research objective with the Parallel tool attached, default (unrestricted) retrieval, and a low temperature — this is factual research, not creative writing. From the response's `grounding_metadata` we keep:\n", "\n", "- **`web_search_queries`** — the queries Gemini executed through Parallel, useful for observability.\n", - "- **`sources`** — the retrieved source documents. Each one is a document-level **citable unit**, and its `uri` is the identifier we carry into citations, alongside the page title.\n", + "- **`grounding_chunks`** — the retrieved source documents. Each one is a document-level **citable unit**, and its `web.uri` is the identifier we carry into citations, alongside the page title.\n", "\n", "`normalize_sources` turns those into deduplicated `{url, title}` dicts. That list, produced by retrieval rather than by the model's text, is the trust anchor for the whole enrichment: it defines the only URLs the structuring step is allowed to cite." ] }, { "cell_type": "code", - "execution_count": 6, - "id": "aae130c9", + "execution_count": 7, + "id": "c1d17806", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:07:51.223565Z", - "iopub.status.busy": "2026-07-07T02:07:51.223506Z", - "iopub.status.idle": "2026-07-07T02:08:02.295434Z", - "shell.execute_reply": "2026-07-07T02:08:02.294982Z" + "iopub.execute_input": "2026-07-14T16:31:40.153233Z", + "iopub.status.busy": "2026-07-14T16:31:40.153174Z", + "iopub.status.idle": "2026-07-14T16:31:51.524045Z", + "shell.execute_reply": "2026-07-14T16:31:51.523328Z" } }, "outputs": [ @@ -379,66 +395,68 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - Anthropic founded year\n", - " - Anthropic headquarters address\n", " - Anthropic CEO 2026\n", - " - \"548 Market St\" \"PMB\" Anthropic\n", + " - Anthropic founded year\n", + " - \"Anthropic\" \"500 Howard\" OR \"548 Market\"\n", + " - \"548 Market St\" Anthropic\n", + " - Anthropic headquarters address city region country\n", + " - \"500 Howard Street\" Anthropic\n", "\n", "Grounded sources (12):\n", - " - Where is Anthropic Located? HQ, Global Offices & Company Insights — https://www.highperformr.ai/company/anthropicresearch\n", " - Anthropic - Wikipedia — https://en.wikipedia.org/wiki/Anthropic\n", - " - Company \\ Anthropic — https://www.anthropic.com/company\n", + " - description: This article will cover the contact details and the professional and educational background of Dario Amodei, the CEO of Anthropic title: Who is the CEO of Anthropic in 2026? Dario Amodei's Bio | Clay — https://www.clay.com/dossier/anthropic-ceo\n", " - Anthropic’s C.E.O. Says It Could Grow by 80 Times This Year - The New York Times — https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\n", - " - 2028: Two scenarios for global AI leadership \\ Anthropic — https://www.anthropic.com/research/2028-ai-leadership\n", - " - description: Learn about Anthropic's headquarters location and see a list of their major offices across different regions. Find out where they operate worldwide. title: Where is Anthropic's Headquarters? Main Office Location and Global Offices | Clay — https://www.clay.com/dossier/anthropic-headquarters-office-locations\n", - " - Who founded Anthropic, the makers of Claude AI, and why? | Britannica — https://www.britannica.com/question/Who-founded-Anthropic-the-makers-of-Claude-AI-and-why\n", - " - Anthropic, PBC — https://www.lobbyfacts.eu/datacard/anthropic-pbc?rid=511227350325-42&sid=178563\n", - " - ANTHROPIC - Anthropic, PBC Trademark Registration — https://uspto.report/TM/98046928\n", - " - 548 Market St., PMB 90375 — https://downloads.regulations.gov/USCIS-2023-0005-1139/attachment_1.pdf\n", - " - Anthropic Corporate Headquarters, Office Locations and Addresses | Craft.co — https://craft.co/anthropic/locations\n", - " - Anthropic 2026 Company Profile: Valuation, Funding & ... — https://pitchbook.com/profiles/company/466959-97\n", + " - Anthropic | History, Controversies, & Claude AI | Britannica Money — https://www.britannica.com/money/Anthropic-PBC\n", + " - Anthropic, Inc. San Francisco, CA - filing information — https://www.bizprofile.net/ca/san-francisco/anthropic-inc\n", + " - News | How Anthropic is growing its office empire in downtown San Francisco — https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\n", + " - Anthropic Cements 240K SF Lease On Howard Street — https://www.bisnow.com/san-francisco/news/office/anthropic-cements-240k-sf-lease-howard-street-133989\n", + " - anthropic, pbc, inc. - Detail by Entity Name — https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", + " - ANTHROPIC Trademark | Trademarkia — https://www.trademarkia.com/anthropic-98256909\n", + " - Anthropic strikes deal to remain at 500 Howard for the long term - San Francisco Business Times — https://www.bizjournals.com/sanfrancisco/news/2026/04/06/anthropic-500-howard-direct-lease.html?ana=brss_1049\n", + " - What Is Anthropic? | Built In — https://builtin.com/articles/anthropic\n", + " - ANTHROPIC, PBC - LEI: 984500B6DEB8CEBC4Z70 | LEI Lookup — https://www.lei-lookup.com/record/984500B6DEB8CEBC4Z70\n", "\n", - "Evidence (1262 chars, first 600):\n", - "Based on the company's official filings, trademark applications, and reputable business publications, here is the researched information for Anthropic:\n", + "Evidence (1634 chars, first 600):\n", + "Based on official corporate filings, reputable business publications, and real estate records, here is the researched information for Anthropic:\n", "\n", - "### 1. Current Chief Executive Officer\n", + "### 1. Chief Executive Officer\n", "* **Full Name:** Dario Amodei\n", - "* *Source:* Official Anthropic Governance Page, *The New York Times*, and *The Wall Street Journal*.\n", + "* **Source:** *The New York Times*, *Encyclopaedia Britannica*, and official state corporate filings.\n", "\n", "### 2. Headquarters Location\n", "* **City:** San Francisco\n", - "* **Region:** California\n", + "* **Region:** California (CA)\n", "* **Country:** United States\n", - "* *Source:* Official Anthropic Research Publications and *Encyclopaedia Britannica*.\n", + "* **Source:** *CoStar News* and California Secretary of State business registry.\n", "\n", "### 3. Headquarters Mailing Address\n", - "* **Full Mailing Address:** \n", - " Anthropic, PBC…\n" + "Anthropic maintains a physical principal office address fo…\n" ] } ], "source": [ "def normalize_sources(response) -> list[dict]:\n", - " \"\"\"Deduplicated {url, title} dicts from a GroundedResponse, in retrieval order.\"\"\"\n", + " \"\"\"Deduplicated {url, title} dicts from a grounded response, in retrieval order.\"\"\"\n", + " metadata = response.candidates[0].grounding_metadata\n", " sources, seen = [], set()\n", - " for source in response.sources:\n", - " if source.uri and source.uri not in seen:\n", - " seen.add(source.uri)\n", - " sources.append({\"url\": source.uri, \"title\": \" \".join((source.title or \"\").split())})\n", + " for chunk in metadata.grounding_chunks or []:\n", + " if chunk.web and chunk.web.uri and chunk.web.uri not in seen:\n", + " seen.add(chunk.web.uri)\n", + " sources.append({\"url\": chunk.web.uri, \"title\": \" \".join((chunk.web.title or \"\").split())})\n", " return sources\n", "\n", "\n", - "grounding_response = client.generate(\n", - " company_objective(company_row),\n", - " model_id=MODEL,\n", - " temperature=0.2,\n", + "grounding_response = client.models.generate_content(\n", + " model=MODEL,\n", + " contents=company_objective(company_row),\n", + " config=types.GenerateContentConfig(tools=[parallel_tool], temperature=0.2),\n", ")\n", "\n", "evidence = grounding_response.text.strip()\n", "grounded_sources = normalize_sources(grounding_response)\n", "\n", "print(\"Executed search queries:\")\n", - "for query in grounding_response.web_search_queries:\n", + "for query in grounding_response.candidates[0].grounding_metadata.web_search_queries or []:\n", " print(f\" - {query}\")\n", "\n", "print(f\"\\nGrounded sources ({len(grounded_sources)}):\")\n", @@ -450,30 +468,30 @@ }, { "cell_type": "markdown", - "id": "8be0cd9f", + "id": "94210558", "metadata": {}, "source": [ - "### 2.5 Structure: extract the typed record\n", + "### 2.4 Structure: extract the typed record\n", "\n", "The structuring call is configured for mechanical extraction, the opposite profile from research:\n", "\n", - "- **`grounded=False`** — no tools are attached, so the model may only reorganize the evidence it is given, never fetch more.\n", - "- **`temperature=0`** and **`responseSchema`** — decoding is deterministic and constrained to `CompanyEnrichment`'s shape, with `responseMimeType: application/json`.\n", - "- **`thinkingBudget: 0`** — extraction doesn't benefit from extended thinking, and disabling it prevents a thinking model from spending the output budget on thoughts.\n", + "- **No tools** — the model may only reorganize the evidence it is given, never fetch more.\n", + "- **`temperature=0`** and **`response_schema=CompanyEnrichment`** — decoding is deterministic and constrained to the contract's shape, with `response_mime_type=\"application/json\"`.\n", + "- **`thinking_budget=0`** — extraction doesn't benefit from extended thinking, and disabling it prevents a thinking model from spending the output budget on thoughts.\n", "\n", - "The prompt stacks the enrichment policy on top of three clearly delimited data blocks: the input record, the grounded evidence, and the sources list. Pydantic then validates the raw JSON — if the model ever returned a malformed or schema-violating object, `model_validate_json` would raise here rather than let a bad record flow downstream." + "The prompt stacks the enrichment policy on top of three clearly delimited data blocks: the input record, the grounded evidence, and the sources list. The SDK validates and parses the JSON into a `CompanyEnrichment` instance on `response.parsed` — if the model ever returned a malformed or schema-violating object, parsing would raise here rather than let a bad record flow downstream." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "54e6e084", + "execution_count": 8, + "id": "3c6f42d7", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:08:02.296585Z", - "iopub.status.busy": "2026-07-07T02:08:02.296517Z", - "iopub.status.idle": "2026-07-07T02:08:04.913991Z", - "shell.execute_reply": "2026-07-07T02:08:04.913469Z" + "iopub.execute_input": "2026-07-14T16:31:51.525376Z", + "iopub.status.busy": "2026-07-14T16:31:51.525286Z", + "iopub.status.idle": "2026-07-14T16:31:55.360859Z", + "shell.execute_reply": "2026-07-14T16:31:55.360246Z" } }, "outputs": [ @@ -486,28 +504,38 @@ " \"official_domain\": \"anthropic.com\",\n", " \"ceo_name\": \"Dario Amodei\",\n", " \"headquarters\": \"San Francisco, California, United States\",\n", - " \"headquarters_address\": \"548 Market St, PMB 90375, San Francisco, CA, 94104, United States\",\n", + " \"headquarters_address\": \"548 Market Street, PMB 90375, San Francisco, CA 94104, United States\",\n", " \"founded_year\": \"2021\",\n", " \"citations\": [\n", " {\n", " \"field\": \"ceo_name\",\n", " \"url\": \"https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\",\n", - " \"note\": \"Dario Amodei is the Chief Executive Officer of Anthropic.\"\n", + " \"note\": \"Dario Amodei is the CEO of Anthropic.\"\n", + " },\n", + " {\n", + " \"field\": \"ceo_name\",\n", + " \"url\": \"https://www.britannica.com/money/Anthropic-PBC\",\n", + " \"note\": \"Dario Amodei is the CEO of Anthropic.\"\n", " },\n", " {\n", " \"field\": \"headquarters\",\n", - " \"url\": \"https://www.britannica.com/question/Who-founded-Anthropic-the-makers-of-Claude-AI-and-why\",\n", + " \"url\": \"https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\",\n", " \"note\": \"Anthropic's headquarters is located in San Francisco, California, United States.\"\n", " },\n", " {\n", " \"field\": \"headquarters_address\",\n", - " \"url\": \"https://uspto.report/TM/98046928\",\n", - " \"note\": \"The official corporate mailing address of record is 548 Market St, PMB 90375, San Francisco, CA 94104, United States.\"\n", + " \"url\": \"https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\",\n", + " \"note\": \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"\n", + " },\n", + " {\n", + " \"field\": \"headquarters_address\",\n", + " \"url\": \"https://www.trademarkia.com/anthropic-98256909\",\n", + " \"note\": \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"\n", " },\n", " {\n", " \"field\": \"founded_year\",\n", - " \"url\": \"https://pitchbook.com/profiles/company/466959-97\",\n", - " \"note\": \"Anthropic was founded in the year 2021.\"\n", + " \"url\": \"https://builtin.com/articles/anthropic\",\n", + " \"note\": \"Anthropic was founded in 2021.\"\n", " }\n", " ]\n", "}\n" @@ -532,45 +560,43 @@ "\"\"\"\n", "\n", "\n", - "structuring_response = client.generate(\n", - " extraction_prompt(company_row, evidence, grounded_sources),\n", - " model_id=MODEL,\n", - " grounded=False,\n", - " temperature=0.0,\n", - " max_output_tokens=8192,\n", - " generation_config={\n", - " \"responseMimeType\": \"application/json\",\n", - " \"responseSchema\": company_schema,\n", - " \"thinkingConfig\": {\"thinkingBudget\": 0},\n", - " },\n", + "structuring_response = client.models.generate_content(\n", + " model=MODEL,\n", + " contents=extraction_prompt(company_row, evidence, grounded_sources),\n", + " config=types.GenerateContentConfig(\n", + " temperature=0.0,\n", + " response_mime_type=\"application/json\",\n", + " response_schema=CompanyEnrichment,\n", + " thinking_config=types.ThinkingConfig(thinking_budget=0),\n", + " ),\n", ")\n", "\n", - "company_enrichment = CompanyEnrichment.model_validate_json(structuring_response.text)\n", + "company_enrichment: CompanyEnrichment = structuring_response.parsed\n", "print(json.dumps(company_enrichment.model_dump(), indent=2))" ] }, { "cell_type": "markdown", - "id": "9ac8f537", + "id": "a7a73685", "metadata": {}, "source": [ - "### 2.6 Verify citations and load the record\n", + "### 2.5 Verify citations and load the record\n", "\n", - "Structured output guaranteed the shape and pydantic validated it; the last step is verifying provenance. Because the policy requires citation URLs to be copied from the grounded source list, we can check every one mechanically against the URLs that came out of the grounding metadata in step 2.4 — and confirm that every populated fact field carries at least one citation. A citation that fails this check would mean the model wrote a URL retrieval never returned, which is exactly the failure mode this pattern exists to catch.\n", + "Structured output guaranteed the shape and pydantic validated it; the last step is verifying provenance. Because the policy requires citation URLs to be copied from the grounded source list, we can check every one mechanically against the URLs that came out of the grounding metadata in step 2.3 — and confirm that every populated fact field carries at least one citation. A citation that fails this check would mean the model wrote a URL retrieval never returned, which is exactly the failure mode this pattern exists to catch.\n", "\n", "`verify_citations` is written once, generically: fact fields are whatever the contract declares beyond the input record's identity fields and the bookkeeping field (`citations`). Section 3 reuses it unchanged. After the checks pass, `model_dump()` turns the record into plain Python data, ready for a dataframe, database, or API response." ] }, { "cell_type": "code", - "execution_count": 8, - "id": "7f1b644a", + "execution_count": 9, + "id": "e190b3db", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:08:04.914994Z", - "iopub.status.busy": "2026-07-07T02:08:04.914925Z", - "iopub.status.idle": "2026-07-07T02:08:04.919001Z", - "shell.execute_reply": "2026-07-07T02:08:04.918569Z" + "iopub.execute_input": "2026-07-14T16:31:55.362048Z", + "iopub.status.busy": "2026-07-14T16:31:55.361985Z", + "iopub.status.idle": "2026-07-14T16:31:55.366364Z", + "shell.execute_reply": "2026-07-14T16:31:55.365966Z" } }, "outputs": [ @@ -578,11 +604,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "field verified against grounded sources url\n", - "ceo_name True https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\n", - "headquarters True https://www.britannica.com/question/Who-founded-Anthropic-the-makers-of-Claude-AI-and-why\n", - "headquarters_address True https://uspto.report/TM/98046928\n", - "founded_year True https://pitchbook.com/profiles/company/466959-97\n", + "field verified against grounded sources url\n", + "ceo_name True https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\n", + "ceo_name True https://www.britannica.com/money/Anthropic-PBC\n", + "headquarters True https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\n", + "headquarters_address True https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", + "headquarters_address True https://www.trademarkia.com/anthropic-98256909\n", + "founded_year True https://builtin.com/articles/anthropic\n", "\n", "All citations verified.\n" ] @@ -594,23 +622,29 @@ " 'official_domain': 'anthropic.com',\n", " 'ceo_name': 'Dario Amodei',\n", " 'headquarters': 'San Francisco, California, United States',\n", - " 'headquarters_address': '548 Market St, PMB 90375, San Francisco, CA, 94104, United States',\n", + " 'headquarters_address': '548 Market Street, PMB 90375, San Francisco, CA 94104, United States',\n", " 'founded_year': '2021',\n", " 'citations': [{'field': 'ceo_name',\n", " 'url': 'https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html',\n", - " 'note': 'Dario Amodei is the Chief Executive Officer of Anthropic.'},\n", + " 'note': 'Dario Amodei is the CEO of Anthropic.'},\n", + " {'field': 'ceo_name',\n", + " 'url': 'https://www.britannica.com/money/Anthropic-PBC',\n", + " 'note': 'Dario Amodei is the CEO of Anthropic.'},\n", " {'field': 'headquarters',\n", - " 'url': 'https://www.britannica.com/question/Who-founded-Anthropic-the-makers-of-Claude-AI-and-why',\n", + " 'url': 'https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco',\n", " 'note': \"Anthropic's headquarters is located in San Francisco, California, United States.\"},\n", " {'field': 'headquarters_address',\n", - " 'url': 'https://uspto.report/TM/98046928',\n", - " 'note': 'The official corporate mailing address of record is 548 Market St, PMB 90375, San Francisco, CA 94104, United States.'},\n", + " 'url': 'https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930',\n", + " 'note': \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"},\n", + " {'field': 'headquarters_address',\n", + " 'url': 'https://www.trademarkia.com/anthropic-98256909',\n", + " 'note': \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"},\n", " {'field': 'founded_year',\n", - " 'url': 'https://pitchbook.com/profiles/company/466959-97',\n", - " 'note': 'Anthropic was founded in the year 2021.'}]}" + " 'url': 'https://builtin.com/articles/anthropic',\n", + " 'note': 'Anthropic was founded in 2021.'}]}" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -624,9 +658,9 @@ " if name not in record and name != \"citations\"\n", " ]\n", "\n", - " print(f\"{'field':<17} {'verified against grounded sources':<36} url\")\n", + " print(f\"{'field':<21} {'verified against grounded sources':<36} url\")\n", " for citation in enriched.citations:\n", - " print(f\"{citation.field:<17} {str(citation.url in grounded_urls):<36} {citation.url}\")\n", + " print(f\"{citation.field:<21} {str(citation.url in grounded_urls):<36} {citation.url}\")\n", "\n", " unverified = [c.url for c in enriched.citations if c.url not in grounded_urls]\n", " uncited = [\n", @@ -645,34 +679,79 @@ }, { "cell_type": "markdown", - "id": "0b749f31", + "id": "91955542", "metadata": {}, "source": [ "## 3. People enrichment with the same pipeline\n", "\n", - "Nothing in sections 2.4–2.6 was specific to companies: ground, structure, and verify only care about *a record*, *a contract*, and *an objective*. To enrich people instead, we swap the two record-type-specific pieces:\n", + "Nothing in sections 2.3–2.5 was specific to companies: ground, structure, and verify only care about *a record*, *a contract*, and *an objective*. To enrich people instead, we swap the two record-type-specific pieces:\n", "\n", "- **A new contract.** `PersonEnrichment` declares the fields a recruiting or sales list needs — current title, current employer, and location — with the same format-precise descriptions and the same `citations` bookkeeping.\n", "- **A new objective template.** People are harder to disambiguate than companies, so the input record carries a `known_affiliation` field and the objective instructs the model to use it — and to say so if the identification is uncertain, rather than blending two people who share a name.\n", "\n", - "The enrichment policy, the schema converter, and the verification logic are reused verbatim.\n", - "\n", - "### 3.1 Define the person contract and objective" + "The enrichment policy and the verification logic are reused verbatim: `enrich` below packages the three steps exactly as sections 2.3–2.5 ran them, and is the loop body you would run once per row to enrich a whole dataset." ] }, { "cell_type": "code", - "execution_count": 9, - "id": "e3d261c0", + "execution_count": 10, + "id": "604cdd13", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:08:04.920012Z", - "iopub.status.busy": "2026-07-07T02:08:04.919937Z", - "iopub.status.idle": "2026-07-07T02:08:04.922527Z", - "shell.execute_reply": "2026-07-07T02:08:04.922137Z" + "iopub.execute_input": "2026-07-14T16:31:55.367876Z", + "iopub.status.busy": "2026-07-14T16:31:55.367808Z", + "iopub.status.idle": "2026-07-14T16:32:03.280737Z", + "shell.execute_reply": "2026-07-14T16:32:03.280345Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Executed search queries:\n", + " - Lisa Su AMD current job title official website\n", + " - Lisa Su AMD professional location city state country\n", + "Grounded sources: 5\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "field verified against grounded sources url\n", + "current_title True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "current_employer True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "location True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "\n", + "All citations verified.\n" + ] + }, + { + "data": { + "text/plain": [ + "{'full_name': 'Lisa Su',\n", + " 'known_affiliation': 'AMD',\n", + " 'current_title': 'Chair, President and Chief Executive Officer',\n", + " 'current_employer': 'Advanced Micro Devices, Inc. (AMD)',\n", + " 'location': 'Austin, Texas, United States',\n", + " 'citations': [{'field': 'current_title',\n", + " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", + " 'note': 'Her official job title is Chair, President and Chief Executive Officer.'},\n", + " {'field': 'current_employer',\n", + " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", + " 'note': 'She works for Advanced Micro Devices, Inc. (AMD).'},\n", + " {'field': 'location',\n", + " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", + " 'note': 'Dr. Su is professionally based in Austin, Texas, United States.'}]}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "class PersonEnrichment(BaseModel):\n", " full_name: str = Field(description=\"Person's full name, copied exactly from the input record.\")\n", @@ -708,29 +787,65 @@ "person_row = {\n", " \"full_name\": \"Lisa Su\",\n", " \"known_affiliation\": \"AMD\",\n", - "}" + "}\n", + "\n", + "\n", + "def enrich(record: dict, contract: type[BaseModel], objective: str) -> BaseModel:\n", + " \"\"\"Ground -> structure -> verify one record against a pydantic contract.\"\"\"\n", + " grounding = client.models.generate_content(\n", + " model=MODEL,\n", + " contents=objective,\n", + " config=types.GenerateContentConfig(tools=[parallel_tool], temperature=0.2),\n", + " )\n", + " evidence = grounding.text.strip()\n", + " sources = normalize_sources(grounding)\n", + "\n", + " print(\"Executed search queries:\")\n", + " for query in grounding.candidates[0].grounding_metadata.web_search_queries or []:\n", + " print(f\" - {query}\")\n", + " print(f\"Grounded sources: {len(sources)}\\n\")\n", + "\n", + " structuring = client.models.generate_content(\n", + " model=MODEL,\n", + " contents=extraction_prompt(record, evidence, sources),\n", + " config=types.GenerateContentConfig(\n", + " temperature=0.0,\n", + " response_mime_type=\"application/json\",\n", + " response_schema=contract,\n", + " thinking_config=types.ThinkingConfig(thinking_budget=0),\n", + " ),\n", + " )\n", + " enriched = structuring.parsed\n", + " verify_citations(enriched, record, sources)\n", + " return enriched\n", + "\n", + "\n", + "person_enrichment = enrich(person_row, PersonEnrichment, person_objective(person_row))\n", + "person_enrichment.model_dump()" ] }, { "cell_type": "markdown", - "id": "9e90e1ff", + "id": "a12ced9f", "metadata": {}, "source": [ - "### 3.2 Run the pipeline end to end\n", + "## 4. Product catalog enrichment\n", + "\n", + "A third record type, same pipeline. Product catalogs are a classic enrichment target: a merchandising or procurement dataset knows a product's name and manufacturer, but launch dates, category placement, and list prices go stale or arrive incomplete from upstream feeds.\n", "\n", - "`enrich` packages the three steps exactly as sections 2.4–2.6 ran them: ground with unrestricted retrieval, structure against the contract's converted schema, verify against the grounded source list. This is the loop body you would run once per row to enrich a whole dataset — and because `GroundedGeminiClient` caches its OAuth token, the loop doesn't pay an auth round trip per record." + "`ProductEnrichment` follows the same recipe as the previous contracts — identity fields copied from the input, format-precise fact fields (`release_date` pinned to `YYYY-MM-DD`, `list_price_usd` to a plain decimal number, so both stay machine-comparable), and the same `citations` bookkeeping. The objective steers retrieval toward the manufacturer's product pages and reputable technology press. Everything else — the policy, `extraction_prompt`, `verify_citations`, and `enrich` — is reused untouched." ] }, { "cell_type": "code", - "execution_count": 10, - "id": "f98df8ea", + "execution_count": 11, + "id": "e92f2dc9", "metadata": { "execution": { - "iopub.execute_input": "2026-07-07T02:08:04.923504Z", - "iopub.status.busy": "2026-07-07T02:08:04.923431Z", - "iopub.status.idle": "2026-07-07T02:08:13.017143Z", - "shell.execute_reply": "2026-07-07T02:08:13.016636Z" + "iopub.execute_input": "2026-07-14T16:32:03.282237Z", + "iopub.status.busy": "2026-07-14T16:32:03.282152Z", + "iopub.status.idle": "2026-07-14T16:32:17.234378Z", + "shell.execute_reply": "2026-07-14T16:32:17.232824Z" } }, "outputs": [ @@ -739,9 +854,10 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - AMD headquarters location\n", - " - Lisa Su AMD current title 2026\n", - "Grounded sources: 5\n", + " - Apple Vision Pro base model price US\n", + " - Apple Vision Pro release date sale date\n", + " - \"Apple Vision Pro\"\n", + "Grounded sources: 3\n", "\n" ] }, @@ -749,10 +865,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "field verified against grounded sources url\n", - "current_title True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", - "current_employer True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", - "location True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "field verified against grounded sources url\n", + "category True https://en.wikipedia.org/wiki/Apple_Vision_Pro\n", + "release_date True https://www.apple.com/newsroom/2024/01/apple-vision-pro-available-in-the-us-on-february-2/\n", + "list_price_usd True https://www.macrumors.com/2026/06/25/apple-vision-pro-just-got-even-more-expensive/\n", "\n", "All citations verified.\n" ] @@ -760,58 +876,65 @@ { "data": { "text/plain": [ - "{'full_name': 'Lisa Su',\n", - " 'known_affiliation': 'AMD',\n", - " 'current_title': 'Chair and Chief Executive Officer',\n", - " 'current_employer': 'Advanced Micro Devices, Inc.',\n", - " 'location': 'Austin, Texas, United States',\n", - " 'citations': [{'field': 'current_title',\n", - " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'Her official title as stated by her employer is Chair and Chief Executive Officer'},\n", - " {'field': 'current_employer',\n", - " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'She works for Advanced Micro Devices, Inc.'},\n", - " {'field': 'location',\n", - " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': \"Dr. Lisa Su is professionally based out of AMD's major campus in Austin, Texas, United States\"}]}" + "{'product_name': 'Apple Vision Pro',\n", + " 'manufacturer': 'Apple',\n", + " 'category': 'spatial computer',\n", + " 'release_date': '2024-02-02',\n", + " 'list_price_usd': '3699.00',\n", + " 'citations': [{'field': 'category',\n", + " 'url': 'https://en.wikipedia.org/wiki/Apple_Vision_Pro',\n", + " 'note': 'Apple officially avoids this term in its marketing, defining the product category as a \"spatial computer\".'},\n", + " {'field': 'release_date',\n", + " 'url': 'https://www.apple.com/newsroom/2024/01/apple-vision-pro-available-in-the-us-on-february-2/',\n", + " 'note': 'it officially went on sale in U.S. Apple Store locations and online on February 2, 2024.'},\n", + " {'field': 'list_price_usd',\n", + " 'url': 'https://www.macrumors.com/2026/06/25/apple-vision-pro-just-got-even-more-expensive/',\n", + " 'note': 'raising the base price of the Apple Vision Pro by $200 to $3,699.'}]}" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def enrich(record: dict, contract: type[BaseModel], objective: str) -> BaseModel:\n", - " \"\"\"Ground -> structure -> verify one record against a pydantic contract.\"\"\"\n", - " grounding = client.generate(objective, model_id=MODEL, temperature=0.2)\n", - " evidence = grounding.text.strip()\n", - " sources = normalize_sources(grounding)\n", + "class ProductEnrichment(BaseModel):\n", + " product_name: str = Field(description=\"Product name, copied exactly from the input record.\")\n", + " manufacturer: str = Field(description=\"Manufacturer, copied exactly from the input record.\")\n", + " category: str = Field(\n", + " description=\"Product category as a short noun phrase, e.g. 'mixed-reality headset', or 'unknown'.\"\n", + " )\n", + " release_date: str = Field(\n", + " description=\"Date the product first went on sale, in YYYY-MM-DD format, or 'unknown'.\"\n", + " )\n", + " list_price_usd: str = Field(\n", + " description=(\n", + " \"Current US list price of the base model as a plain decimal number with no currency \"\n", + " \"symbol or thousands separators, e.g. '3499.00', or 'unknown'.\"\n", + " )\n", + " )\n", + " citations: list[Citation] = Field(description=\"Sources supporting every populated field.\")\n", "\n", - " print(\"Executed search queries:\")\n", - " for query in grounding.web_search_queries:\n", - " print(f\" - {query}\")\n", - " print(f\"Grounded sources: {len(sources)}\\n\")\n", "\n", - " structuring = client.generate(\n", - " extraction_prompt(record, evidence, sources),\n", - " model_id=MODEL,\n", - " grounded=False,\n", - " temperature=0.0,\n", - " max_output_tokens=8192,\n", - " generation_config={\n", - " \"responseMimeType\": \"application/json\",\n", - " \"responseSchema\": to_gemini_schema(contract),\n", - " \"thinkingConfig\": {\"thinkingBudget\": 0},\n", - " },\n", - " )\n", - " enriched = contract.model_validate_json(structuring.text)\n", - " verify_citations(enriched, record, sources)\n", - " return enriched\n", + "def product_objective(record: dict) -> str:\n", + " return f\"\"\"Research the product {record[\"product_name\"]} made by {record[\"manufacturer\"]}.\n", "\n", + "Find:\n", + "1. The product's category, as a short noun phrase.\n", + "2. The date the product first went on sale.\n", + "3. The current US list price of the base model.\n", "\n", - "person_enrichment = enrich(person_row, PersonEnrichment, person_objective(person_row))\n", - "person_enrichment.model_dump()" + "Prefer the manufacturer's official product and press pages for specifications and pricing,\n", + "and reputable technology press for launch details. Cite the source of every fact.\"\"\"\n", + "\n", + "\n", + "product_row = {\n", + " \"product_name\": \"Apple Vision Pro\",\n", + " \"manufacturer\": \"Apple\",\n", + "}\n", + "\n", + "product_enrichment = enrich(product_row, ProductEnrichment, product_objective(product_row))\n", + "product_enrichment.model_dump()" ] } ], From 92518de97e292ab82c1457c8f9f3bfec1853b593 Mon Sep 17 00:00:00 2001 From: rm Date: Tue, 14 Jul 2026 17:12:23 -0400 Subject: [PATCH 2/4] Use Google Pixel 10 Pro in product enrichment example; trim notebook prose Co-authored-by: Cursor --- .../gemini_search_enrichment.ipynb | 52 ++++++++----------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb index 0a5f473..7f164fd 100644 --- a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb +++ b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb @@ -18,7 +18,6 @@ " - an active [Parallel Web Search subscription on the Google Cloud Marketplace](https://console.cloud.google.com/marketplace/product/parallel-web-systems-public/parallel-web-systems) for your project — in that case no API key is needed.\n", "- Two pip packages, installed in the next cell: `google-genai` (the Gemini SDK) and `pydantic`.\n", "\n", - "> Grounding with Parallel on Gemini Enterprise is currently in **Preview**. See the [Parallel integration docs](https://docs.parallel.ai/integrations/google-gemini-enterprise) and [Google's grounding documentation](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/grounding/grounding-with-parallel) for the current list of supported models.\n", "\n", "The saved outputs below were generated on July 14, 2026. Because they use the live web, rerunning the notebook may return different sources and answers." ] @@ -120,7 +119,7 @@ "\n", "Grounding is enabled by passing a `parallel_ai_search` tool in the request config. When it is present, Gemini translates the prompt into web search queries, Parallel retrieves LLM-optimized excerpts from the live web, and the model composes its answer from that retrieved evidence.\n", "\n", - "The tool's `custom_configs` accepts any Parallel Search API parameter, but every field is optional and the defaults are the right starting point: per [Parallel's search best practices](https://docs.parallel.ai/search/best-practices), restrictive retrieval parameters (domain allowlists, low result caps, geo filters) can unnecessarily limit results and reduce quality, so we don't set any.\n", + "The tool's `custom_configs` accepts any Parallel Search API parameter, but every field is optional and the defaults are the right starting point: per [Parallel's search best practices](https://docs.parallel.ai/search/best-practices). \n", "\n", "We call `client.models.generate_content` in two modes:\n", "\n", @@ -186,9 +185,7 @@ "source": [ "### 1.4 Attach inline citations from the grounding metadata\n", "\n", - "The response's `grounding_supports` maps byte-range segments of the answer text to the indices of the `grounding_chunks` that back them. That lets us attach citations **in code** instead of asking the model to write links: the model never generates a URL, so it cannot invent or rewrite one — every footnote is copied from the grounding metadata by our own program.\n", - "\n", - "One implementation detail: segment offsets (`start_index`/`end_index`) count **UTF-8 bytes**, not characters, so we insert markers into the encoded text and decode at the end." + "The response's `grounding_supports` maps segments of the answer text to the indices of the `grounding_chunks` that back them. That lets us attach citations **in code** instead of asking the model to write links: the model never generates a URL, so it cannot invent or rewrite one — every footnote is copied from the grounding metadata.\n" ] }, { @@ -473,12 +470,6 @@ "source": [ "### 2.4 Structure: extract the typed record\n", "\n", - "The structuring call is configured for mechanical extraction, the opposite profile from research:\n", - "\n", - "- **No tools** — the model may only reorganize the evidence it is given, never fetch more.\n", - "- **`temperature=0`** and **`response_schema=CompanyEnrichment`** — decoding is deterministic and constrained to the contract's shape, with `response_mime_type=\"application/json\"`.\n", - "- **`thinking_budget=0`** — extraction doesn't benefit from extended thinking, and disabling it prevents a thinking model from spending the output budget on thoughts.\n", - "\n", "The prompt stacks the enrichment policy on top of three clearly delimited data blocks: the input record, the grounded evidence, and the sources list. The SDK validates and parses the JSON into a `CompanyEnrichment` instance on `response.parsed` — if the model ever returned a malformed or schema-violating object, parsing would raise here rather than let a bad record flow downstream." ] }, @@ -854,10 +845,9 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - Apple Vision Pro base model price US\n", - " - Apple Vision Pro release date sale date\n", - " - \"Apple Vision Pro\"\n", - "Grounded sources: 3\n", + " - Google Pixel 10 Pro release date\n", + " - \"Pixel 10 Pro\"\n", + "Grounded sources: 4\n", "\n" ] }, @@ -866,9 +856,9 @@ "output_type": "stream", "text": [ "field verified against grounded sources url\n", - "category True https://en.wikipedia.org/wiki/Apple_Vision_Pro\n", - "release_date True https://www.apple.com/newsroom/2024/01/apple-vision-pro-available-in-the-us-on-february-2/\n", - "list_price_usd True https://www.macrumors.com/2026/06/25/apple-vision-pro-just-got-even-more-expensive/\n", + "category True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", + "release_date True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", + "list_price_usd True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", "\n", "All citations verified.\n" ] @@ -876,20 +866,20 @@ { "data": { "text/plain": [ - "{'product_name': 'Apple Vision Pro',\n", - " 'manufacturer': 'Apple',\n", - " 'category': 'spatial computer',\n", - " 'release_date': '2024-02-02',\n", - " 'list_price_usd': '3699.00',\n", + "{'product_name': 'Google Pixel 10 Pro',\n", + " 'manufacturer': 'Google',\n", + " 'category': 'smartphone',\n", + " 'release_date': '2025-08-28',\n", + " 'list_price_usd': '999.00',\n", " 'citations': [{'field': 'category',\n", - " 'url': 'https://en.wikipedia.org/wiki/Apple_Vision_Pro',\n", - " 'note': 'Apple officially avoids this term in its marketing, defining the product category as a \"spatial computer\".'},\n", + " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", + " 'note': 'Smartphone (specifically, a flagship Android smartphone).'},\n", " {'field': 'release_date',\n", - " 'url': 'https://www.apple.com/newsroom/2024/01/apple-vision-pro-available-in-the-us-on-february-2/',\n", - " 'note': 'it officially went on sale in U.S. Apple Store locations and online on February 2, 2024.'},\n", + " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", + " 'note': 'August 28, 2025'},\n", " {'field': 'list_price_usd',\n", - " 'url': 'https://www.macrumors.com/2026/06/25/apple-vision-pro-just-got-even-more-expensive/',\n", - " 'note': 'raising the base price of the Apple Vision Pro by $200 to $3,699.'}]}" + " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", + " 'note': '$999.00'}]}" ] }, "execution_count": 11, @@ -929,8 +919,8 @@ "\n", "\n", "product_row = {\n", - " \"product_name\": \"Apple Vision Pro\",\n", - " \"manufacturer\": \"Apple\",\n", + " \"product_name\": \"Google Pixel 10 Pro\",\n", + " \"manufacturer\": \"Google\",\n", "}\n", "\n", "product_enrichment = enrich(product_row, ProductEnrichment, product_objective(product_row))\n", From 07f19a9a4180c5e16be87f3fb9995d0e5abdb5ce Mon Sep 17 00:00:00 2001 From: rm Date: Tue, 14 Jul 2026 17:26:18 -0400 Subject: [PATCH 3/4] Re-run enrichment notebook end to end for fresh grounded outputs Co-authored-by: Cursor --- .../gemini_search_enrichment.ipynb | 237 ++++++++---------- 1 file changed, 103 insertions(+), 134 deletions(-) diff --git a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb index 7f164fd..61a4d05 100644 --- a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb +++ b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb @@ -40,13 +40,21 @@ "id": "65f11f3b", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:29.490009Z", - "iopub.status.busy": "2026-07-14T16:31:29.489932Z", - "iopub.status.idle": "2026-07-14T16:31:30.392311Z", - "shell.execute_reply": "2026-07-14T16:31:30.391849Z" + "iopub.execute_input": "2026-07-14T21:25:14.057768Z", + "iopub.status.busy": "2026-07-14T21:25:14.057707Z", + "iopub.status.idle": "2026-07-14T21:25:16.363107Z", + "shell.execute_reply": "2026-07-14T21:25:16.362609Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], "source": [ "%pip install --quiet --upgrade google-genai pydantic" ] @@ -73,10 +81,10 @@ "id": "1467d5e6", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:30.393806Z", - "iopub.status.busy": "2026-07-14T16:31:30.393708Z", - "iopub.status.idle": "2026-07-14T16:31:31.098816Z", - "shell.execute_reply": "2026-07-14T16:31:31.098460Z" + "iopub.execute_input": "2026-07-14T21:25:16.365375Z", + "iopub.status.busy": "2026-07-14T21:25:16.365260Z", + "iopub.status.idle": "2026-07-14T21:25:18.176060Z", + "shell.execute_reply": "2026-07-14T21:25:18.175660Z" } }, "outputs": [ @@ -135,10 +143,10 @@ "id": "eda3a5f2", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:31.104380Z", - "iopub.status.busy": "2026-07-14T16:31:31.104107Z", - "iopub.status.idle": "2026-07-14T16:31:40.138127Z", - "shell.execute_reply": "2026-07-14T16:31:40.137434Z" + "iopub.execute_input": "2026-07-14T21:25:18.188761Z", + "iopub.status.busy": "2026-07-14T21:25:18.188624Z", + "iopub.status.idle": "2026-07-14T21:25:26.338864Z", + "shell.execute_reply": "2026-07-14T21:25:26.337672Z" } }, "outputs": [ @@ -147,10 +155,11 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - \"7,477\" \"selling, general and administrative\" Apple 2026\n", + " - \"Apple\" \"Q2 2026\" earnings release OR \"second quarter\" 2026\n", + " - Apple Q2 2026 financial statements pdf\n", "\n", "Answer:\n", - "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (which ended March 28, 2026)—the company's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million).\n" + "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (ended March 28, 2026)—its selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million).\n" ] } ], @@ -194,10 +203,10 @@ "id": "f7a7f5ca", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:40.140924Z", - "iopub.status.busy": "2026-07-14T16:31:40.140820Z", - "iopub.status.idle": "2026-07-14T16:31:40.144488Z", - "shell.execute_reply": "2026-07-14T16:31:40.144034Z" + "iopub.execute_input": "2026-07-14T21:25:26.342686Z", + "iopub.status.busy": "2026-07-14T21:25:26.342562Z", + "iopub.status.idle": "2026-07-14T21:25:26.346376Z", + "shell.execute_reply": "2026-07-14T21:25:26.345984Z" } }, "outputs": [ @@ -205,10 +214,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (which ended March 28, 2026)—the company's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million)[1].\n", + "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (ended March 28, 2026)—its selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million)[1][2].\n", "\n", "Sources:\n", - "[1] UNITED STATES SECURITIES AND EXCHANGE COMMISSION Washington, D.C. 20549 — https://s2.q4cdn.com/470004039/files/doc_earnings/2026/q2/filing/10Q-Q2-2026-as-filed.pdf\n" + "[1] UNITED STATES SECURITIES AND EXCHANGE COMMISSION Washington, D.C. 20549 — https://s2.q4cdn.com/470004039/files/doc_earnings/2026/q2/filing/10Q-Q2-2026-as-filed.pdf\n", + "[2] Apple Inc. CONDENSED CONSOLIDATED STATEMENTS OF OPERATIONS (Unaudited) — https://www.apple.com/newsroom/pdfs/fy2026q2/FY26_Q2_Consolidated_Financial_Statements.pdf\n" ] } ], @@ -247,8 +257,6 @@ "source": [ "## 2. Company enrichment, step by step\n", "\n", - "We enrich one record at a time so the Gemini and Parallel integration stays visible; applying the pattern to many rows is a loop over the same three calls.\n", - "\n", "### 2.1 Define the output contract\n", "\n", "Pydantic gives us a single source of truth for three things: the JSON Schema sent to Gemini, the validation of the model's output, and the typed object handed to downstream code. The field descriptions do real work here — they tell the model what each field means and, critically, the exact format it must use. `headquarters` and `founded_year` are good examples: their descriptions pin the formats (\"City, Region, Country\" and `YYYY`), so values come back machine-comparable rather than free-text like \"the Bay Area\" or \"founded about five years ago\".\n", @@ -264,10 +272,10 @@ "id": "683494b4", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:40.145508Z", - "iopub.status.busy": "2026-07-14T16:31:40.145451Z", - "iopub.status.idle": "2026-07-14T16:31:40.149512Z", - "shell.execute_reply": "2026-07-14T16:31:40.149113Z" + "iopub.execute_input": "2026-07-14T21:25:26.347855Z", + "iopub.status.busy": "2026-07-14T21:25:26.347764Z", + "iopub.status.idle": "2026-07-14T21:25:26.352003Z", + "shell.execute_reply": "2026-07-14T21:25:26.351641Z" } }, "outputs": [], @@ -323,10 +331,10 @@ "id": "3b58b9ec", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:40.150467Z", - "iopub.status.busy": "2026-07-14T16:31:40.150411Z", - "iopub.status.idle": "2026-07-14T16:31:40.152324Z", - "shell.execute_reply": "2026-07-14T16:31:40.152009Z" + "iopub.execute_input": "2026-07-14T21:25:26.353042Z", + "iopub.status.busy": "2026-07-14T21:25:26.352979Z", + "iopub.status.idle": "2026-07-14T21:25:26.354870Z", + "shell.execute_reply": "2026-07-14T21:25:26.354539Z" } }, "outputs": [], @@ -380,10 +388,10 @@ "id": "c1d17806", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:40.153233Z", - "iopub.status.busy": "2026-07-14T16:31:40.153174Z", - "iopub.status.idle": "2026-07-14T16:31:51.524045Z", - "shell.execute_reply": "2026-07-14T16:31:51.523328Z" + "iopub.execute_input": "2026-07-14T21:25:26.355769Z", + "iopub.status.busy": "2026-07-14T21:25:26.355718Z", + "iopub.status.idle": "2026-07-14T21:25:36.492391Z", + "shell.execute_reply": "2026-07-14T21:25:36.490740Z" } }, "outputs": [ @@ -392,42 +400,21 @@ "output_type": "stream", "text": [ "Executed search queries:\n", + " - \"Anthropic\" \"548 Market\" OR \"500 Howard\"\n", " - Anthropic CEO 2026\n", - " - Anthropic founded year\n", - " - \"Anthropic\" \"500 Howard\" OR \"548 Market\"\n", - " - \"548 Market St\" Anthropic\n", - " - Anthropic headquarters address city region country\n", - " - \"500 Howard Street\" Anthropic\n", + " - Anthropic \"500 Howard\"\n", "\n", - "Grounded sources (12):\n", + "Grounded sources (8):\n", " - Anthropic - Wikipedia — https://en.wikipedia.org/wiki/Anthropic\n", - " - description: This article will cover the contact details and the professional and educational background of Dario Amodei, the CEO of Anthropic title: Who is the CEO of Anthropic in 2026? Dario Amodei's Bio | Clay — https://www.clay.com/dossier/anthropic-ceo\n", - " - Anthropic’s C.E.O. Says It Could Grow by 80 Times This Year - The New York Times — https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\n", - " - Anthropic | History, Controversies, & Claude AI | Britannica Money — https://www.britannica.com/money/Anthropic-PBC\n", - " - Anthropic, Inc. San Francisco, CA - filing information — https://www.bizprofile.net/ca/san-francisco/anthropic-inc\n", + " - Company \\ Anthropic — https://www.anthropic.com/company\n", + " - Corporate Development at Anthropic — https://startup.jobs/corporate-development-anthropic-3-7482285\n", + " - anthropic, pbc, inc. - Detail by Entity Name — https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", + " - Anthropic, PBC · 548 Market St PMB 90375, San Francisco, CA 94104 — https://opengovco.com/business/20241311617\n", " - News | How Anthropic is growing its office empire in downtown San Francisco — https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\n", " - Anthropic Cements 240K SF Lease On Howard Street — https://www.bisnow.com/san-francisco/news/office/anthropic-cements-240k-sf-lease-howard-street-133989\n", - " - anthropic, pbc, inc. - Detail by Entity Name — https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", - " - ANTHROPIC Trademark | Trademarkia — https://www.trademarkia.com/anthropic-98256909\n", - " - Anthropic strikes deal to remain at 500 Howard for the long term - San Francisco Business Times — https://www.bizjournals.com/sanfrancisco/news/2026/04/06/anthropic-500-howard-direct-lease.html?ana=brss_1049\n", - " - What Is Anthropic? | Built In — https://builtin.com/articles/anthropic\n", - " - ANTHROPIC, PBC - LEI: 984500B6DEB8CEBC4Z70 | LEI Lookup — https://www.lei-lookup.com/record/984500B6DEB8CEBC4Z70\n", - "\n", - "Evidence (1634 chars, first 600):\n", - "Based on official corporate filings, reputable business publications, and real estate records, here is the researched information for Anthropic:\n", - "\n", - "### 1. Chief Executive Officer\n", - "* **Full Name:** Dario Amodei\n", - "* **Source:** *The New York Times*, *Encyclopaedia Britannica*, and official state corporate filings.\n", + " - What is the mailing address for Anthropic? - Ask and Answer - Glarity — https://askai.glarity.app/search/What-is-the-mailing-address-for-Anthropic\n", "\n", - "### 2. Headquarters Location\n", - "* **City:** San Francisco\n", - "* **Region:** California (CA)\n", - "* **Country:** United States\n", - "* **Source:** *CoStar News* and California Secretary of State business registry.\n", - "\n", - "### 3. Headquarters Mailing Address\n", - "Anthropic maintains a physical principal office address fo…\n" + "Evidence (1240…\n" ] } ], @@ -460,7 +447,7 @@ "for source in grounded_sources:\n", " print(f\" - {source['title'] or '(untitled)'} — {source['url']}\")\n", "\n", - "print(f\"\\nEvidence ({len(evidence)} chars, first 600):\\n{evidence[:600]}…\")" + "print(f\"\\nEvidence ({len(evidence)}…\")" ] }, { @@ -479,10 +466,10 @@ "id": "3c6f42d7", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:51.525376Z", - "iopub.status.busy": "2026-07-14T16:31:51.525286Z", - "iopub.status.idle": "2026-07-14T16:31:55.360859Z", - "shell.execute_reply": "2026-07-14T16:31:55.360246Z" + "iopub.execute_input": "2026-07-14T21:25:36.505876Z", + "iopub.status.busy": "2026-07-14T21:25:36.505473Z", + "iopub.status.idle": "2026-07-14T21:25:38.689279Z", + "shell.execute_reply": "2026-07-14T21:25:38.685819Z" } }, "outputs": [ @@ -495,38 +482,28 @@ " \"official_domain\": \"anthropic.com\",\n", " \"ceo_name\": \"Dario Amodei\",\n", " \"headquarters\": \"San Francisco, California, United States\",\n", - " \"headquarters_address\": \"548 Market Street, PMB 90375, San Francisco, CA 94104, United States\",\n", + " \"headquarters_address\": \"548 Market Street, PMB 90375, San Francisco, California, 94104, United States\",\n", " \"founded_year\": \"2021\",\n", " \"citations\": [\n", " {\n", " \"field\": \"ceo_name\",\n", - " \"url\": \"https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\",\n", - " \"note\": \"Dario Amodei is the CEO of Anthropic.\"\n", - " },\n", - " {\n", - " \"field\": \"ceo_name\",\n", - " \"url\": \"https://www.britannica.com/money/Anthropic-PBC\",\n", - " \"note\": \"Dario Amodei is the CEO of Anthropic.\"\n", + " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", + " \"note\": \"Dario Amodei is the Chief Executive Officer of Anthropic.\"\n", " },\n", " {\n", " \"field\": \"headquarters\",\n", - " \"url\": \"https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\",\n", + " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", " \"note\": \"Anthropic's headquarters is located in San Francisco, California, United States.\"\n", " },\n", " {\n", " \"field\": \"headquarters_address\",\n", - " \"url\": \"https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\",\n", - " \"note\": \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"\n", - " },\n", - " {\n", - " \"field\": \"headquarters_address\",\n", - " \"url\": \"https://www.trademarkia.com/anthropic-98256909\",\n", - " \"note\": \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"\n", + " \"url\": \"https://opengovco.com/business/20241311617\",\n", + " \"note\": \"Anthropic's official corporate mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104.\"\n", " },\n", " {\n", " \"field\": \"founded_year\",\n", - " \"url\": \"https://builtin.com/articles/anthropic\",\n", - " \"note\": \"Anthropic was founded in 2021.\"\n", + " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", + " \"note\": \"Anthropic was founded in the year 2021.\"\n", " }\n", " ]\n", "}\n" @@ -584,10 +561,10 @@ "id": "e190b3db", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:55.362048Z", - "iopub.status.busy": "2026-07-14T16:31:55.361985Z", - "iopub.status.idle": "2026-07-14T16:31:55.366364Z", - "shell.execute_reply": "2026-07-14T16:31:55.365966Z" + "iopub.execute_input": "2026-07-14T21:25:38.708425Z", + "iopub.status.busy": "2026-07-14T21:25:38.707400Z", + "iopub.status.idle": "2026-07-14T21:25:38.720223Z", + "shell.execute_reply": "2026-07-14T21:25:38.719827Z" } }, "outputs": [ @@ -596,12 +573,10 @@ "output_type": "stream", "text": [ "field verified against grounded sources url\n", - "ceo_name True https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html\n", - "ceo_name True https://www.britannica.com/money/Anthropic-PBC\n", - "headquarters True https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\n", - "headquarters_address True https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", - "headquarters_address True https://www.trademarkia.com/anthropic-98256909\n", - "founded_year True https://builtin.com/articles/anthropic\n", + "ceo_name True https://en.wikipedia.org/wiki/Anthropic\n", + "headquarters True https://en.wikipedia.org/wiki/Anthropic\n", + "headquarters_address True https://opengovco.com/business/20241311617\n", + "founded_year True https://en.wikipedia.org/wiki/Anthropic\n", "\n", "All citations verified.\n" ] @@ -613,26 +588,20 @@ " 'official_domain': 'anthropic.com',\n", " 'ceo_name': 'Dario Amodei',\n", " 'headquarters': 'San Francisco, California, United States',\n", - " 'headquarters_address': '548 Market Street, PMB 90375, San Francisco, CA 94104, United States',\n", + " 'headquarters_address': '548 Market Street, PMB 90375, San Francisco, California, 94104, United States',\n", " 'founded_year': '2021',\n", " 'citations': [{'field': 'ceo_name',\n", - " 'url': 'https://www.nytimes.com/2026/05/06/technology/anthropic-ceo-ai-growth.html',\n", - " 'note': 'Dario Amodei is the CEO of Anthropic.'},\n", - " {'field': 'ceo_name',\n", - " 'url': 'https://www.britannica.com/money/Anthropic-PBC',\n", - " 'note': 'Dario Amodei is the CEO of Anthropic.'},\n", + " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", + " 'note': 'Dario Amodei is the Chief Executive Officer of Anthropic.'},\n", " {'field': 'headquarters',\n", - " 'url': 'https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco',\n", + " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", " 'note': \"Anthropic's headquarters is located in San Francisco, California, United States.\"},\n", " {'field': 'headquarters_address',\n", - " 'url': 'https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930',\n", - " 'note': \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"},\n", - " {'field': 'headquarters_address',\n", - " 'url': 'https://www.trademarkia.com/anthropic-98256909',\n", - " 'note': \"Anthropic's official mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104, United States.\"},\n", + " 'url': 'https://opengovco.com/business/20241311617',\n", + " 'note': \"Anthropic's official corporate mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104.\"},\n", " {'field': 'founded_year',\n", - " 'url': 'https://builtin.com/articles/anthropic',\n", - " 'note': 'Anthropic was founded in 2021.'}]}" + " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", + " 'note': 'Anthropic was founded in the year 2021.'}]}" ] }, "execution_count": 9, @@ -689,10 +658,10 @@ "id": "604cdd13", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:31:55.367876Z", - "iopub.status.busy": "2026-07-14T16:31:55.367808Z", - "iopub.status.idle": "2026-07-14T16:32:03.280737Z", - "shell.execute_reply": "2026-07-14T16:32:03.280345Z" + "iopub.execute_input": "2026-07-14T21:25:38.721228Z", + "iopub.status.busy": "2026-07-14T21:25:38.721154Z", + "iopub.status.idle": "2026-07-14T21:25:44.553611Z", + "shell.execute_reply": "2026-07-14T21:25:44.553052Z" } }, "outputs": [ @@ -701,9 +670,8 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - Lisa Su AMD current job title official website\n", - " - Lisa Su AMD professional location city state country\n", - "Grounded sources: 5\n", + " - Lisa Su AMD current job title employer website\n", + "Grounded sources: 4\n", "\n" ] }, @@ -714,7 +682,7 @@ "field verified against grounded sources url\n", "current_title True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", "current_employer True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", - "location True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "location True https://tamest.org/news/profile-member-lisa-su\n", "\n", "All citations verified.\n" ] @@ -724,18 +692,18 @@ "text/plain": [ "{'full_name': 'Lisa Su',\n", " 'known_affiliation': 'AMD',\n", - " 'current_title': 'Chair, President and Chief Executive Officer',\n", - " 'current_employer': 'Advanced Micro Devices, Inc. (AMD)',\n", + " 'current_title': 'Chair and Chief Executive Officer',\n", + " 'current_employer': 'AMD',\n", " 'location': 'Austin, Texas, United States',\n", " 'citations': [{'field': 'current_title',\n", " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'Her official job title is Chair, President and Chief Executive Officer.'},\n", + " 'note': 'Her current job title, as stated by her employer, is Chair and Chief Executive Officer'},\n", " {'field': 'current_employer',\n", " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'She works for Advanced Micro Devices, Inc. (AMD).'},\n", + " 'note': 'She currently works for AMD'},\n", " {'field': 'location',\n", - " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'Dr. Su is professionally based in Austin, Texas, United States.'}]}" + " 'url': 'https://tamest.org/news/profile-member-lisa-su',\n", + " 'note': 'Dr. Su is professionally based in: City: Austin, Region: Texas, Country: United States'}]}" ] }, "execution_count": 10, @@ -833,10 +801,10 @@ "id": "e92f2dc9", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T16:32:03.282237Z", - "iopub.status.busy": "2026-07-14T16:32:03.282152Z", - "iopub.status.idle": "2026-07-14T16:32:17.234378Z", - "shell.execute_reply": "2026-07-14T16:32:17.232824Z" + "iopub.execute_input": "2026-07-14T21:25:44.555364Z", + "iopub.status.busy": "2026-07-14T21:25:44.555285Z", + "iopub.status.idle": "2026-07-14T21:25:55.273971Z", + "shell.execute_reply": "2026-07-14T21:25:55.273408Z" } }, "outputs": [ @@ -845,9 +813,10 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - Google Pixel 10 Pro release date\n", " - \"Pixel 10 Pro\"\n", - "Grounded sources: 4\n", + " - Google Pixel 10 Pro release date\n", + " - \"Pixel 10 Pro\" \"August 20, 2025\" OR \"August 28, 2025\"\n", + "Grounded sources: 7\n", "\n" ] }, @@ -873,7 +842,7 @@ " 'list_price_usd': '999.00',\n", " 'citations': [{'field': 'category',\n", " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", - " 'note': 'Smartphone (specifically, a flagship Android smartphone).'},\n", + " 'note': 'Smartphone'},\n", " {'field': 'release_date',\n", " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", " 'note': 'August 28, 2025'},\n", @@ -944,7 +913,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.14.5" + "version": "3.12.11" } }, "nbformat": 4, From 7db80b1a825a6b7a29250166abcd445136e41448 Mon Sep 17 00:00:00 2001 From: rm Date: Tue, 14 Jul 2026 17:33:37 -0400 Subject: [PATCH 4/4] Drop verified column from citation table; refresh notebook outputs Co-authored-by: Cursor --- .../gemini_search_enrichment.ipynb | 190 +++++++++--------- 1 file changed, 94 insertions(+), 96 deletions(-) diff --git a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb index 61a4d05..8565eaf 100644 --- a/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb +++ b/python-recipes/gemini_ai_demo/gemini_search_enrichment.ipynb @@ -40,10 +40,10 @@ "id": "65f11f3b", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:14.057768Z", - "iopub.status.busy": "2026-07-14T21:25:14.057707Z", - "iopub.status.idle": "2026-07-14T21:25:16.363107Z", - "shell.execute_reply": "2026-07-14T21:25:16.362609Z" + "iopub.execute_input": "2026-07-14T21:29:58.128434Z", + "iopub.status.busy": "2026-07-14T21:29:58.128377Z", + "iopub.status.idle": "2026-07-14T21:29:59.477081Z", + "shell.execute_reply": "2026-07-14T21:29:59.476600Z" } }, "outputs": [ @@ -81,10 +81,10 @@ "id": "1467d5e6", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:16.365375Z", - "iopub.status.busy": "2026-07-14T21:25:16.365260Z", - "iopub.status.idle": "2026-07-14T21:25:18.176060Z", - "shell.execute_reply": "2026-07-14T21:25:18.175660Z" + "iopub.execute_input": "2026-07-14T21:29:59.478156Z", + "iopub.status.busy": "2026-07-14T21:29:59.478089Z", + "iopub.status.idle": "2026-07-14T21:29:59.951442Z", + "shell.execute_reply": "2026-07-14T21:29:59.951018Z" } }, "outputs": [ @@ -143,10 +143,10 @@ "id": "eda3a5f2", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:18.188761Z", - "iopub.status.busy": "2026-07-14T21:25:18.188624Z", - "iopub.status.idle": "2026-07-14T21:25:26.338864Z", - "shell.execute_reply": "2026-07-14T21:25:26.337672Z" + "iopub.execute_input": "2026-07-14T21:29:59.953585Z", + "iopub.status.busy": "2026-07-14T21:29:59.953482Z", + "iopub.status.idle": "2026-07-14T21:30:06.522241Z", + "shell.execute_reply": "2026-07-14T21:30:06.521748Z" } }, "outputs": [ @@ -155,11 +155,11 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - \"Apple\" \"Q2 2026\" earnings release OR \"second quarter\" 2026\n", - " - Apple Q2 2026 financial statements pdf\n", + " - \"Selling, general and administrative\" Apple Q2 2026 10-Q\n", + " - Apple investor relations financial results\n", "\n", "Answer:\n", - "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (ended March 28, 2026)—its selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million).\n" + "In its most recently reported fiscal quarter—the **second quarter of fiscal year 2026** (which ended on **March 28, 2026**)—Apple's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million).\n" ] } ], @@ -203,10 +203,10 @@ "id": "f7a7f5ca", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:26.342686Z", - "iopub.status.busy": "2026-07-14T21:25:26.342562Z", - "iopub.status.idle": "2026-07-14T21:25:26.346376Z", - "shell.execute_reply": "2026-07-14T21:25:26.345984Z" + "iopub.execute_input": "2026-07-14T21:30:06.527064Z", + "iopub.status.busy": "2026-07-14T21:30:06.526943Z", + "iopub.status.idle": "2026-07-14T21:30:06.530216Z", + "shell.execute_reply": "2026-07-14T21:30:06.529825Z" } }, "outputs": [ @@ -214,11 +214,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "In Apple's most recently reported fiscal quarter—the **second quarter of fiscal 2026** (ended March 28, 2026)—its selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million)[1][2].\n", + "In its most recently reported fiscal quarter—the **second quarter of fiscal year 2026** (which ended on **March 28, 2026**)—Apple's selling, general and administrative (SG&A) expense was **$7.477 billion** ($7,477 million)[1][2].\n", "\n", "Sources:\n", - "[1] UNITED STATES SECURITIES AND EXCHANGE COMMISSION Washington, D.C. 20549 — https://s2.q4cdn.com/470004039/files/doc_earnings/2026/q2/filing/10Q-Q2-2026-as-filed.pdf\n", - "[2] Apple Inc. CONDENSED CONSOLIDATED STATEMENTS OF OPERATIONS (Unaudited) — https://www.apple.com/newsroom/pdfs/fy2026q2/FY26_Q2_Consolidated_Financial_Statements.pdf\n" + "[1] Apple SG&A Expenses 2012-2026 | AAPL | MacroTrends — https://www.macrotrends.net/stocks/charts/AAPL/apple/selling-general-administrative-expenses\n", + "[2] aapl-20260328 — https://www.sec.gov/Archives/edgar/data/320193/000032019326000013/aapl-20260328.htm\n" ] } ], @@ -272,10 +272,10 @@ "id": "683494b4", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:26.347855Z", - "iopub.status.busy": "2026-07-14T21:25:26.347764Z", - "iopub.status.idle": "2026-07-14T21:25:26.352003Z", - "shell.execute_reply": "2026-07-14T21:25:26.351641Z" + "iopub.execute_input": "2026-07-14T21:30:06.532037Z", + "iopub.status.busy": "2026-07-14T21:30:06.531964Z", + "iopub.status.idle": "2026-07-14T21:30:06.535207Z", + "shell.execute_reply": "2026-07-14T21:30:06.534839Z" } }, "outputs": [], @@ -331,10 +331,10 @@ "id": "3b58b9ec", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:26.353042Z", - "iopub.status.busy": "2026-07-14T21:25:26.352979Z", - "iopub.status.idle": "2026-07-14T21:25:26.354870Z", - "shell.execute_reply": "2026-07-14T21:25:26.354539Z" + "iopub.execute_input": "2026-07-14T21:30:06.536263Z", + "iopub.status.busy": "2026-07-14T21:30:06.536180Z", + "iopub.status.idle": "2026-07-14T21:30:06.538045Z", + "shell.execute_reply": "2026-07-14T21:30:06.537760Z" } }, "outputs": [], @@ -388,10 +388,10 @@ "id": "c1d17806", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:26.355769Z", - "iopub.status.busy": "2026-07-14T21:25:26.355718Z", - "iopub.status.idle": "2026-07-14T21:25:36.492391Z", - "shell.execute_reply": "2026-07-14T21:25:36.490740Z" + "iopub.execute_input": "2026-07-14T21:30:06.538930Z", + "iopub.status.busy": "2026-07-14T21:30:06.538874Z", + "iopub.status.idle": "2026-07-14T21:30:16.397962Z", + "shell.execute_reply": "2026-07-14T21:30:16.397514Z" } }, "outputs": [ @@ -400,21 +400,19 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - \"Anthropic\" \"548 Market\" OR \"500 Howard\"\n", + " - \"548 Market Street\"\n", " - Anthropic CEO 2026\n", - " - Anthropic \"500 Howard\"\n", + " - \"Anthropic\" \"548 Market\" OR \"500 Howard\"\n", "\n", - "Grounded sources (8):\n", + "Grounded sources (6):\n", " - Anthropic - Wikipedia — https://en.wikipedia.org/wiki/Anthropic\n", - " - Company \\ Anthropic — https://www.anthropic.com/company\n", - " - Corporate Development at Anthropic — https://startup.jobs/corporate-development-anthropic-3-7482285\n", - " - anthropic, pbc, inc. - Detail by Entity Name — https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?inquirytype=EntityName&directionType=Initial&searchNameOrder=ANTHROPICPBC+F240000015680&aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&searchTerm=ANTHRO-ED+LLC&listNameOrder=ANTHROED+L200000257930\n", - " - Anthropic, PBC · 548 Market St PMB 90375, San Francisco, CA 94104 — https://opengovco.com/business/20241311617\n", + " - Anthropic, Pbc, Inc. San Francisco, CA - filing information — https://www.bizprofile.net/ca/san-francisco/anthropic-pbc-inc\n", " - News | How Anthropic is growing its office empire in downtown San Francisco — https://www.costar.com/article/390354131/how-anthropic-is-growing-its-office-empire-in-downtown-san-francisco\n", - " - Anthropic Cements 240K SF Lease On Howard Street — https://www.bisnow.com/san-francisco/news/office/anthropic-cements-240k-sf-lease-howard-street-133989\n", " - What is the mailing address for Anthropic? - Ask and Answer - Glarity — https://askai.glarity.app/search/What-is-the-mailing-address-for-Anthropic\n", + " - anthropic, pbc, inc. - Detail by Entity Name — https://search.sunbiz.org/Inquiry/corporationsearch/SearchResultDetail?aggregateId=forp-f24000001568-aa469358-d133-43d9-9fc6-3c7c00c42c1d&directionType=Initial&inquirytype=EntityName&listNameOrder=ANTHROED%20L200000257930&searchNameOrder=ANTHROPICPBC%20F240000015680&searchTerm=ANTHRO-ED%20LLC\n", + " - Anthropic, Pbc San Francisco, CA - filing information — https://www.bizprofile.net/ca/san-francisco/anthropic-pbc-2\n", "\n", - "Evidence (1240…\n" + "Evidence (1139…\n" ] } ], @@ -466,10 +464,10 @@ "id": "3c6f42d7", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:36.505876Z", - "iopub.status.busy": "2026-07-14T21:25:36.505473Z", - "iopub.status.idle": "2026-07-14T21:25:38.689279Z", - "shell.execute_reply": "2026-07-14T21:25:38.685819Z" + "iopub.execute_input": "2026-07-14T21:30:16.400137Z", + "iopub.status.busy": "2026-07-14T21:30:16.400042Z", + "iopub.status.idle": "2026-07-14T21:30:18.758019Z", + "shell.execute_reply": "2026-07-14T21:30:18.757530Z" } }, "outputs": [ @@ -482,28 +480,28 @@ " \"official_domain\": \"anthropic.com\",\n", " \"ceo_name\": \"Dario Amodei\",\n", " \"headquarters\": \"San Francisco, California, United States\",\n", - " \"headquarters_address\": \"548 Market Street, PMB 90375, San Francisco, California, 94104, United States\",\n", + " \"headquarters_address\": \"548 Market Street, PMB 90375, San Francisco, CA 94104, United States\",\n", " \"founded_year\": \"2021\",\n", " \"citations\": [\n", " {\n", " \"field\": \"ceo_name\",\n", " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", - " \"note\": \"Dario Amodei is the Chief Executive Officer of Anthropic.\"\n", + " \"note\": \"Dario Amodei\"\n", " },\n", " {\n", " \"field\": \"headquarters\",\n", " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", - " \"note\": \"Anthropic's headquarters is located in San Francisco, California, United States.\"\n", + " \"note\": \"San Francisco, California, United States\"\n", " },\n", " {\n", " \"field\": \"headquarters_address\",\n", - " \"url\": \"https://opengovco.com/business/20241311617\",\n", - " \"note\": \"Anthropic's official corporate mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104.\"\n", + " \"url\": \"https://askai.glarity.app/search/What-is-the-mailing-address-for-Anthropic\",\n", + " \"note\": \"548 Market Street, PMB 90375, San Francisco, CA 94104, United States\"\n", " },\n", " {\n", " \"field\": \"founded_year\",\n", " \"url\": \"https://en.wikipedia.org/wiki/Anthropic\",\n", - " \"note\": \"Anthropic was founded in the year 2021.\"\n", + " \"note\": \"2021\"\n", " }\n", " ]\n", "}\n" @@ -561,10 +559,10 @@ "id": "e190b3db", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:38.708425Z", - "iopub.status.busy": "2026-07-14T21:25:38.707400Z", - "iopub.status.idle": "2026-07-14T21:25:38.720223Z", - "shell.execute_reply": "2026-07-14T21:25:38.719827Z" + "iopub.execute_input": "2026-07-14T21:30:18.759616Z", + "iopub.status.busy": "2026-07-14T21:30:18.759530Z", + "iopub.status.idle": "2026-07-14T21:30:18.764761Z", + "shell.execute_reply": "2026-07-14T21:30:18.764115Z" } }, "outputs": [ @@ -572,11 +570,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "field verified against grounded sources url\n", - "ceo_name True https://en.wikipedia.org/wiki/Anthropic\n", - "headquarters True https://en.wikipedia.org/wiki/Anthropic\n", - "headquarters_address True https://opengovco.com/business/20241311617\n", - "founded_year True https://en.wikipedia.org/wiki/Anthropic\n", + "field url\n", + "ceo_name https://en.wikipedia.org/wiki/Anthropic\n", + "headquarters https://en.wikipedia.org/wiki/Anthropic\n", + "headquarters_address https://askai.glarity.app/search/What-is-the-mailing-address-for-Anthropic\n", + "founded_year https://en.wikipedia.org/wiki/Anthropic\n", "\n", "All citations verified.\n" ] @@ -588,20 +586,20 @@ " 'official_domain': 'anthropic.com',\n", " 'ceo_name': 'Dario Amodei',\n", " 'headquarters': 'San Francisco, California, United States',\n", - " 'headquarters_address': '548 Market Street, PMB 90375, San Francisco, California, 94104, United States',\n", + " 'headquarters_address': '548 Market Street, PMB 90375, San Francisco, CA 94104, United States',\n", " 'founded_year': '2021',\n", " 'citations': [{'field': 'ceo_name',\n", " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", - " 'note': 'Dario Amodei is the Chief Executive Officer of Anthropic.'},\n", + " 'note': 'Dario Amodei'},\n", " {'field': 'headquarters',\n", " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", - " 'note': \"Anthropic's headquarters is located in San Francisco, California, United States.\"},\n", + " 'note': 'San Francisco, California, United States'},\n", " {'field': 'headquarters_address',\n", - " 'url': 'https://opengovco.com/business/20241311617',\n", - " 'note': \"Anthropic's official corporate mailing address is 548 Market Street, PMB 90375, San Francisco, CA 94104.\"},\n", + " 'url': 'https://askai.glarity.app/search/What-is-the-mailing-address-for-Anthropic',\n", + " 'note': '548 Market Street, PMB 90375, San Francisco, CA 94104, United States'},\n", " {'field': 'founded_year',\n", " 'url': 'https://en.wikipedia.org/wiki/Anthropic',\n", - " 'note': 'Anthropic was founded in the year 2021.'}]}" + " 'note': '2021'}]}" ] }, "execution_count": 9, @@ -618,9 +616,9 @@ " if name not in record and name != \"citations\"\n", " ]\n", "\n", - " print(f\"{'field':<21} {'verified against grounded sources':<36} url\")\n", + " print(f\"{'field':<21} url\")\n", " for citation in enriched.citations:\n", - " print(f\"{citation.field:<21} {str(citation.url in grounded_urls):<36} {citation.url}\")\n", + " print(f\"{citation.field:<21} {citation.url}\")\n", "\n", " unverified = [c.url for c in enriched.citations if c.url not in grounded_urls]\n", " uncited = [\n", @@ -658,10 +656,10 @@ "id": "604cdd13", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:38.721228Z", - "iopub.status.busy": "2026-07-14T21:25:38.721154Z", - "iopub.status.idle": "2026-07-14T21:25:44.553611Z", - "shell.execute_reply": "2026-07-14T21:25:44.553052Z" + "iopub.execute_input": "2026-07-14T21:30:18.766877Z", + "iopub.status.busy": "2026-07-14T21:30:18.766806Z", + "iopub.status.idle": "2026-07-14T21:30:26.917197Z", + "shell.execute_reply": "2026-07-14T21:30:26.916801Z" } }, "outputs": [ @@ -671,7 +669,8 @@ "text": [ "Executed search queries:\n", " - Lisa Su AMD current job title employer website\n", - "Grounded sources: 4\n", + " - AMD headquarters address city state country\n", + "Grounded sources: 8\n", "\n" ] }, @@ -679,10 +678,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "field verified against grounded sources url\n", - "current_title True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", - "current_employer True https://www.amd.com/en/corporate/leadership/lisa-su.html\n", - "location True https://tamest.org/news/profile-member-lisa-su\n", + "field url\n", + "current_title https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "current_employer https://www.amd.com/en/corporate/leadership/lisa-su.html\n", + "location https://www.linkedin.com/in/lisasu-amd\n", "\n", "All citations verified.\n" ] @@ -693,17 +692,17 @@ "{'full_name': 'Lisa Su',\n", " 'known_affiliation': 'AMD',\n", " 'current_title': 'Chair and Chief Executive Officer',\n", - " 'current_employer': 'AMD',\n", + " 'current_employer': 'Advanced Micro Devices, Inc. (AMD)',\n", " 'location': 'Austin, Texas, United States',\n", " 'citations': [{'field': 'current_title',\n", " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'Her current job title, as stated by her employer, is Chair and Chief Executive Officer'},\n", + " 'note': 'Chair and Chief Executive Officer'},\n", " {'field': 'current_employer',\n", " 'url': 'https://www.amd.com/en/corporate/leadership/lisa-su.html',\n", - " 'note': 'She currently works for AMD'},\n", + " 'note': 'Advanced Micro Devices, Inc. (AMD)'},\n", " {'field': 'location',\n", - " 'url': 'https://tamest.org/news/profile-member-lisa-su',\n", - " 'note': 'Dr. Su is professionally based in: City: Austin, Region: Texas, Country: United States'}]}" + " 'url': 'https://www.linkedin.com/in/lisasu-amd',\n", + " 'note': 'Austin, Texas, United States'}]}" ] }, "execution_count": 10, @@ -801,10 +800,10 @@ "id": "e92f2dc9", "metadata": { "execution": { - "iopub.execute_input": "2026-07-14T21:25:44.555364Z", - "iopub.status.busy": "2026-07-14T21:25:44.555285Z", - "iopub.status.idle": "2026-07-14T21:25:55.273971Z", - "shell.execute_reply": "2026-07-14T21:25:55.273408Z" + "iopub.execute_input": "2026-07-14T21:30:26.919172Z", + "iopub.status.busy": "2026-07-14T21:30:26.919076Z", + "iopub.status.idle": "2026-07-14T21:30:37.291060Z", + "shell.execute_reply": "2026-07-14T21:30:37.290619Z" } }, "outputs": [ @@ -813,10 +812,9 @@ "output_type": "stream", "text": [ "Executed search queries:\n", - " - \"Pixel 10 Pro\"\n", " - Google Pixel 10 Pro release date\n", - " - \"Pixel 10 Pro\" \"August 20, 2025\" OR \"August 28, 2025\"\n", - "Grounded sources: 7\n", + " - \"Pixel 10 Pro\" \"999\"\n", + "Grounded sources: 6\n", "\n" ] }, @@ -824,10 +822,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "field verified against grounded sources url\n", - "category True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", - "release_date True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", - "list_price_usd True https://en.wikipedia.org/wiki/Pixel_10_Pro\n", + "field url\n", + "category https://en.wikipedia.org/wiki/Pixel_10_Pro\n", + "release_date https://en.wikipedia.org/wiki/Pixel_10_Pro\n", + "list_price_usd https://9to5google.com/2025/08/20/google-pixel-10-pro-xl-series-launch-price-specs-hands-on\n", "\n", "All citations verified.\n" ] @@ -847,7 +845,7 @@ " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", " 'note': 'August 28, 2025'},\n", " {'field': 'list_price_usd',\n", - " 'url': 'https://en.wikipedia.org/wiki/Pixel_10_Pro',\n", + " 'url': 'https://9to5google.com/2025/08/20/google-pixel-10-pro-xl-series-launch-price-specs-hands-on',\n", " 'note': '$999.00'}]}" ] },