{"slug": "llm-deal-flow-automation-in-crm", "title": "LLM Deal Flow Automation in CRM", "summary": "A developer built a system that uses large language models to automatically extract structured deal intelligence from sales call transcripts and store it in a CRM. The system, built with PostgreSQL and the Anthropic API, analyzes transcripts to capture sentiment, objections, next steps, risk flags, and recommended stage movements with accuracy comparable to human analysts. The data model uses JSONB columns with GIN indexes to store flexible deal attributes and activity intelligence without requiring schema migrations.", "body_md": "**In This Article**\n\nMost CRM systems are excellent at storing what happened — call logged, email sent, stage updated — and poor at capturing what was learned. A sales call produces qualitative intelligence that is genuinely valuable for deal strategy: what objections surfaced, how strongly the prospect signaled interest, what next steps were agreed to, and what risk flags the conversation revealed. That intelligence almost never makes it into the CRM because it requires someone to spend 15 minutes synthesizing unstructured notes into structured fields.\n\nLarge language models change this equation. Given a call transcript, Claude can extract structured deal intelligence in seconds — categorizing sentiment, identifying specific objections, recommending stage movement, and flagging risk signals — with accuracy that equals or exceeds what a well-trained sales analyst would produce manually.\n\nThe data model centers on two tables. The `deals`\n\ntable stores core deal attributes as a JSONB column, which allows flexible schema evolution without migrations as the intelligence fields change over time. The `deal_activities`\n\ntable records each interaction — calls, emails, meetings — with the raw content in `TEXT`\n\nand the extracted intelligence in a separate `JSONB`\n\ncolumn. A GIN index on both JSONB columns enables fast attribute queries across the deal pipeline.\n\n```\nCREATE TABLE deals (\n    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    company     TEXT NOT NULL,\n    contact     TEXT,\n    stage       TEXT,\n    attributes  JSONB DEFAULT '{}',\n    created_at  TIMESTAMPTZ DEFAULT now(),\n    updated_at  TIMESTAMPTZ DEFAULT now()\n);\n\nCREATE TABLE deal_activities (\n    id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    deal_id      UUID REFERENCES deals(id),\n    activity_type TEXT,\n    raw_content  TEXT,\n    intelligence JSONB,\n    created_at   TIMESTAMPTZ DEFAULT now()\n);\n\nCREATE INDEX ON deals USING GIN (attributes);\nCREATE INDEX ON deal_activities USING GIN (intelligence);\n```\n\nThe `DealIntelligence`\n\nclass wraps the Anthropic API call and parses the structured JSON response. The prompt instructs the model to return a fixed schema — sentiment, objections, next steps, deal signals, risk flags, recommended stage, and a summary — which can be validated and stored directly without post-processing.\n\n``` python\nimport anthropic, json, psycopg2\nfrom dataclasses import dataclass\nfrom typing import Dict, List\n\n@dataclass\nclass DealRecord:\n    deal_id: str\n    company: str\n    contact: str\n    stage: str\n\nclass DealIntelligence:\n    def __init__(self, db_conn: str):\n        self.client = anthropic.Anthropic()\n        self.db     = psycopg2.connect(db_conn)\n\n    def analyze_transcript(self, transcript: str, deal: DealRecord) -> Dict:\n        prompt = f\"\"\"Analyze this sales call transcript for deal intelligence.\nReturn valid JSON only, with these exact keys:\n- sentiment: \"positive\" | \"neutral\" | \"negative\"\n- objections: list of specific objections raised\n- next_steps: list of agreed action items\n- deal_signals: list of positive buying signals\n- risk_flags: list of concerns or blockers identified\n- recommended_stage: suggested CRM stage based on this conversation\n- summary: 2-3 sentence executive summary\n\nCompany: {deal.company}\nContact: {deal.contact}\nCurrent Stage: {deal.stage}\n\nTranscript:\n{transcript}\"\"\"\n\n        response = self.client.messages.create(\n            model=\"claude-opus-4-7\", max_tokens=1500,\n            messages=[{\"role\": \"user\", \"content\": prompt}]\n        )\n        return json.loads(response.content[0].text)\n\n    def draft_followup_email(self, intelligence: Dict, deal: DealRecord) -> str:\n        objections_text = \", \".join(intelligence.get('objections', []))\n        next_steps_text = \"\\n- \".join(intelligence.get('next_steps', []))\n\n        prompt = f\"\"\"Draft a professional follow-up email for this sales conversation.\n\nContact: {deal.contact} at {deal.company}\nCall Summary: {intelligence.get('summary', '')}\nObjections Raised: {objections_text}\nNext Steps Agreed:\n- {next_steps_text}\n\nWrite a concise, personalized follow-up that confirms next steps and addresses\nthe main objections without being pushy. Professional but warm tone.\"\"\"\n\n        response = self.client.messages.create(\n            model=\"claude-opus-4-7\", max_tokens=600,\n            messages=[{\"role\": \"user\", \"content\": prompt}]\n        )\n        return response.content[0].text\n\n    def save_activity(self, deal_id: str, transcript: str, intelligence: Dict):\n        with self.db.cursor() as cur:\n            cur.execute(\n                \"\"\"INSERT INTO deal_activities\n                   (deal_id, activity_type, raw_content, intelligence)\n                   VALUES (%s, 'call', %s, %s)\"\"\",\n                (deal_id, transcript, psycopg2.extras.Json(intelligence))\n            )\n            # Update stage if recommended stage differs\n            recommended = intelligence.get('recommended_stage')\n            if recommended:\n                cur.execute(\n                    \"UPDATE deals SET stage = %s WHERE id = %s\",\n                    (recommended, deal_id)\n                )\n        self.db.commit()\n```\n\nThe follow-up email draft uses the intelligence output as its input — pulling objections, next steps, and the summary to generate a personalized message that is specific to the actual conversation rather than a generic template. The draft goes into a review queue rather than sending automatically. A human confirms and sends. This keeps the LLM in an assistive role and preserves the personal judgment that high-stakes business development requires.\n\nStoring intelligence as JSONB rather than normalized columns is deliberate. The schema of deal intelligence evolves as the LLM prompt evolves — new keys appear, existing ones are renamed, arrays grow. JSONB absorbs these changes without schema migrations. The GIN index makes these fields queryable: finding all deals where a pricing objection was flagged is a straightforward `WHERE intelligence @> '{\"objections\": [\"pricing\"]}'`\n\nquery.\n\nThe complete workflow is: transcript arrives (from a recording integration, a manual paste, or an email thread) → `analyze_transcript()`\n\nextracts structured intelligence → `save_activity()`\n\npersists it and updates the deal stage → `draft_followup_email()`\n\ngenerates a draft for human review. The entire flow completes in under 10 seconds per call, turning what was a 15-minute manual task into a background process that surfaces better intelligence than most teams produce by hand.\n\n*This post was originally published on White Oak Intelligence. Read the full article there for formatted diagrams, code examples, and related content.*", "url": "https://wpnews.pro/news/llm-deal-flow-automation-in-crm", "canonical_source": "https://dev.to/white_oak_intel/llm-deal-flow-automation-in-crm-52j5", "published_at": "2026-05-31 05:49:20+00:00", "updated_at": "2026-05-31 06:11:51.652111+00:00", "lang": "en", "topics": ["large-language-models", "artificial-intelligence", "natural-language-processing", "ai-products", "ai-tools"], "entities": ["Claude", "CRM"], "alternates": {"html": "https://wpnews.pro/news/llm-deal-flow-automation-in-crm", "markdown": "https://wpnews.pro/news/llm-deal-flow-automation-in-crm.md", "text": "https://wpnews.pro/news/llm-deal-flow-automation-in-crm.txt", "jsonld": "https://wpnews.pro/news/llm-deal-flow-automation-in-crm.jsonld"}}