DEV Community

naoki_JPN
naoki_JPN

Posted on

I Built a Sales Prep AI and It Went Deeper Than Expected

Introduction

"Before a first sales meeting, you always research the other company. That part is kind of a pain, right?"

That thought is where this started. I wanted something that would take a company name and automatically research it, then return a report.

I figured I could get something working in 2–3 days. But getting it to a genuinely usable level turned out to be much deeper than expected. This is the story of that process.

What I built: Sales Prep AI (LINE bot)

https://pre-talk.vercel.app


Tech Stack

Tech Stack


How It Came Together

Phase 1: Just Get It Working

I started with a simple web form. Enter company name, department, and contact name → it searches the web → GPT-4o-mini analyzes the results → returns a report.

As I worked on improving reasoning quality, I switched from GPT-4o-mini to Claude Sonnet for the analysis layer. Light input-interpretation tasks go to Claude Haiku; heavy analysis and OCR go to Claude Sonnet. That division of labor stuck.

For search, I started with DuckDuckGo, but the quality wasn't great, so I switched to Tavily. That one change made a noticeable difference in search quality.

Phase 2: Fighting Vercel Hobby's 10-Second Timeout

Research involves multiple steps — search, then AI analysis — and it realistically takes 1–2 minutes. Vercel's Hobby plan times out at 10 seconds.

The solution: streaming responses. By returning a response while continuing to process, you keep the function alive.

const stream = new ReadableStream({
  async start(controller) {
    const heartbeat = setInterval(() => {
      controller.enqueue(new TextEncoder().encode(" "));
    }, 5000);

    try {
      // Heavy processing happens here
      await runResearch(input);
    } finally {
      clearInterval(heartbeat);
      controller.close();
    }
  },
});

return new Response(stream, { status: 200 });
Enter fullscreen mode Exit fullscreen mode

Sending a blank space every 5 seconds keeps the connection alive. Brute-force, but it works.

Phase 3: Slack Bot → LINE Bot

A web form creates friction — you have to actively open it when you need it. It's better to use it from a tool you already have open.

I built a Slack bot first. But when I ended up canceling the paid Slack plan I was using, I migrated to LINE.

Phase 4: Fighting Hallucinations

This was the hardest part.

The AI was confidently returning information that sounded plausible but wasn't true. Specifically:

  • Asserting fabricated problems as "challenges faced by [department]"
  • Returning outdated information as if it were current
  • Filling in gaps with information not in any search result

I approached this on two axes.

Axis 1: Improve output accuracy

I built in mechanisms to prevent unsupported information from slipping through.

  • Fact/inference separation: The AI explicitly labels each piece of information as either a verified fact (from official sources) or an inference (from surrounding context). The report displays these separately.
  • Output gate: Items that fail conditions like "only contains generalities with no specifics" or "no source URL exists" are filtered out before output.

Axis 2: Make it human-verifiable

Improving accuracy alone isn't enough. Whether done by humans or AI, mistakes happen. What matters is making the process transparent.

So I designed each report item to include both "the facts recognized" and "the reasoning path to the conclusion." Showing what evidence led to what conclusion lets humans catch reasoning that doesn't hold up.

The goal is to save prep time, not to replace human judgment. That's fine.

Phase 5: The Official Website Detection Rabbit Hole

Search results mix "official company sites" with "everything else" (news, Wikipedia, etc.).

I started with simple domain matching, but group companies, subsidiaries, and subdomains made that fall apart quickly.

I eventually settled on:

  • Return multiple official domain candidates
  • Normalize to base domain (including subdomain matching)
  • Use .some() to check against the array

Phase 6: Business Card Scanning

"Wouldn't it be great if you could start researching the moment you get someone's card?"

I added business card scanning using Claude's Vision capability. Send a photo of a card to LINE → it extracts company name, department, and contact name → triggers research automatically. OCR quality mattered, so I used Claude Sonnet here.


A Lesson in Agent Sprawl

At one point I tried to improve the reasoning logic by spinning up five agents simultaneously (field-sales / info-architect / reasoning-designer / impl-designer / critic).

They went into an endless loop of spec discussion, autonomously generating 154 tasks. When I told them to stop, they kept going. I had to force-shutdown. Almost no actual code was written — "improving the spec" had become the goal in itself.

The root cause: I hadn't defined what they were allowed to decide or when they were done.

After that, I redesigned the agent structure. Instead of everyone chiming in freely, I cut it down to 3 roles and explicitly defined what each role was not allowed to do.

Role Responsibility What they must NOT do
team-lead Routing and task management Write code, generate summaries
product Decide implementation approach and implement Create tasks themselves
auditor Pass/fail judgment only Write improvement suggestions, act unless called

Defining "what not to do" alongside "what to do" made role boundaries much cleaner.


Cost

API cost per research run (measured)

Varies by company size and available information.

Item Cost
Claude Sonnet (analysis) ~$0.35
Tavily (web search) ~$0.05
Total ~$0.40/run (range: $0.24–$0.52)

At 100 runs/month that's ~$40; at 500 runs it's ~$200. It's currently free to use, so I'm entirely out of pocket. I'm in a "prove the value first" phase.

Fixed costs (monthly)

Hosting, DB, LINE, domain, etc. I've minimized these by combining free tiers, but it's not zero.


Current Architecture

LINE bot
  ↓ business card image or text
Claude Haiku (input interpretation)
Claude Sonnet (business card OCR)
  ↓
Tavily (parallel web search: 12–15 queries)
  ↓
Claude Sonnet (fact extraction → issue inference → proposal generation)
  ↓
Supabase (report storage) ← auto-deleted after 30 days (personal data compliance)
  ↓
Report URL pushed to LINE
Enter fullscreen mode Exit fullscreen mode

Closing

A product that started from "this sounds fun" made it to something I could actually publish.

Hallucination mitigation, timeout workarounds, official site detection — making something genuinely usable turned out to be deeper than I expected.

If you're curious, add it as a friend on LINE. Just send a photo of a business card and it runs.

https://pre-talk.vercel.app

Top comments (0)