GTM Galaxy

Article

Structured Outputs vs. Hallucinated Defaults: Benchmarking LLM Extraction on Messy Sales Notes

Sales notes are the dark matter of the CRM: they occupy most of the space but provide almost none of the gravity needed for accurate forecasting. For GTM operators, the goal is to transform a note like "Met w/ Sarah. Budget maybe 50k? Needs it by EOY. Competing with Clari?" into structured fields without forcing a rep to manually update a dozen picklists.

Technically, this has become easier. Features like OpenAI’s Structured Outputs and Anthropic’s Tool Use guarantee that an LLM will return valid JSON matching a specific schema. If your CRM expects an integer for budget, you get an integer. If it expects a specific competitor name, you get one from your defined enum.

But there is a trap. These mechanisms solve for syntactic compliance, not semantic truth. During a recent internal experiment, I benchmarked three extraction pipelines against a corpus of messy sales notes. The results were clear: while structured outputs prevent API write-back failures, they often degrade data quality by hallucinating "helpful" defaults for fields the rep never actually mentioned.

The Experiment: Testing the Pipeline

I used a dataset of 50 simulated sales notes containing standard shorthand: "ARR ~100k," vague timing ("sometime in H2"), and missing budget details. I tested three approaches to extract this data into a schema: Budget (Integer), Timeline (Enum: 0-3 months, 4-6 months, 7+ months), and Competitors (Enum list).

  1. Baseline Prompt: A system prompt requesting JSON. No schema enforcement.
  2. Strict Structured Outputs: Using OpenAI's json_schema with strict: true. All fields were marked as required to simulate a complete CRM record update.
  3. Two-Layer Pipeline: Structured outputs for the format, followed by a programmatic validation layer (Python) that cross-referenced extractions against raw text and deterministic rules.

The Failure of Required Fields

The baseline prompt failed on technical grounds: 14% of responses were unparseable due to trailing commas or conversational "here is the JSON" filler. This is an operational dead end because it requires constant retry loops or manual intervention.

Structured Outputs solved the parsing problem. Every response was valid JSON. However, a more insidious issue emerged: the empty field hallucination.

When a note didn't mention a budget, the model in the "Strict" pipeline still provided a budget integer 60% of the time. Because the JSON schema defined budget as a required integer, the LLM prioritized schema compliance over factual silence. It would often output 0, or worse, infer a budget based on the mentioned company size.

If you are writing this directly to a CRM, you aren't getting an API error—you're getting a successfully updated record with garbage data that corrupts your average deal size metrics.

Where Sales Shorthand Breaks Down

Sales shorthand like "ARR 100k-ish" or "follow up after the holiday" creates an interpretation gap that strict schemas cannot bridge.

In my benchmark, the Timeline field was the most frequent semantic failure point. When a rep wrote "follow up in a few weeks," the LLM consistently mapped this to the 0-3 months enum. While technically plausible, it’s a guess.

In the Two-Layer Pipeline, I implemented a simple check: I asked the LLM to provide a justification string for every extracted field. If the justification didn't contain a substring present in the original note, or if it used phrases like "assumed based on," the validation layer flagged the field for exclusion.

Why Your CRM Cares About 400 Errors

When writing to Salesforce or HubSpot via REST APIs, you usually face two types of failures:

  1. Syntax Errors (400 Bad Request): You sent a string to an integer field or a non-existent picklist value. Structured Outputs effectively eliminate these.
  2. Logic Errors: You successfully sent a valid picklist value that is factually incorrect.

Logic errors are far more expensive. A failed API call leaves a log you can monitor. A successful write of hallucinated data is invisible until a sales manager asks why their forecast is full of $0 deals or "Other" competitors.

In the benchmark, the Two-Layer Pipeline had a 22% lower "successful write" rate than the Strict Schema pipeline. While that sounds like a failure, it was the desired outcome: the pipeline rejected the records where the LLM had "filled in the blanks" for missing data.

Building a Robust GTM Extraction Pipeline

To move LLM extraction from an experiment to a production system, you need to decouple the format of the response from the requirement of the field.

1. Define Fields as Optional in the Schema

Even if a field is mandatory in your CRM (like Lead Source), do not make it required in your LLM JSON schema. Allow the LLM to return null. This reduces the pressure on the model to invent a value just to satisfy the API constraint.

{
  "name": "extract_sales_data",
  "parameters": {
    "type": "object",
    "properties": {
      "budget": { "type": ["integer", "null"] },
      "competitor": { "type": "string", "enum": ["Clari", "Gong", "BoostUp", "null"] }
    },
    "required": ["budget", "competitor"]
  }
}

2. Programmatic Post-Validation

Before calling your CRM’s /objects/deals endpoint, run a deterministic check.

  • Null Significance: If the LLM returns null, don't attempt to overwrite the existing CRM value. Only update if you have a high-confidence extraction.
  • Quote Matching: Require the model to return the specific snippet of text it used for the extraction. If the snippet isn't in the source text, discard the field.
  • Value Normalization: Use a simple mapping dictionary to catch the LLM's attempts to be too smart (e.g., mapping "H2" to a specific month range your company doesn't use).

The Maintenance Trade-off

The common counterargument is that a validation layer adds development overhead. If you add a new competitor to your Salesforce picklist, you now have to update your JSON schema and potentially your validation script.

This is a feature, not a bug. GTM systems are not "set and forget." Treating an LLM like a magic box that bypasses schema governance is how you end up with a broken revenue engine. The maintenance of a validation layer is the price of high-fidelity data.

For non-critical descriptive fields—like a call summary—strict schemas are likely over-engineered. But for any data that feeds into routing, scoring, or forecasting, the schema is only the beginning. Your pipeline must be as cynical about the LLM’s output as a RevOps leader is about a rep’s "commit" for the quarter.

— C.B.