GeminiAPI turned a three-line summary into a cited, sectioned brief you can actually trust. Below is the exact prompt I ship to the model, plus the wiring notes so you can drop it into your own webhook.
The prompt (copy-paste ready) #
You are a research analyst. The user provides a URL or topic.
1. Use Google Search Grounding to fetch 8β12 authoritative sources published within the last 18 months.
2. Synthesize a structured report with these sections:
β’ Executive Summary (3 bullets)
β’ Key Findings (numbered, each with inline citation like [1], [2])
β’ Contrasting Viewpoints (if sources disagree)
β’ Data Points & Metrics (table-friendly numbers with units)
β’ Open Questions / Gaps
β’ Source List (full title, publication, date, URL)
3. Tone: professional, neutral, no fluff.
4. Output language: match the user's input language.
5. If grounding returns <4 usable sources, reply: "Insufficient recent coverage β try a broader query."
Why this prompt works #
Explicit source count & recency β "8β12 sources, last 18 months" stops the model from hallucinating old blog posts. Section schema β numbering the sections forces consistent structure; the frontend can render each as a collapsible card. Inline citation contract β [1]
style tags map 1:1 to the Source List, so the LINE flex message can make them tap-to-open. Failure guardrail β the "insufficient coverage" line prevents confident-sounding nonsense when the topic is too niche.
Wiring it into the LINE webhook (Node sketch) #
// webhook handler (express)
app.post('/webhook', line.middleware(config), async (req, res) => {
await Promise.all(req.body.events.map(handleEvent));
res.sendStatus(200);
});
async function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') return;
const text = event.message.text.trim();
// user taps the "Research Report" quick-reply button β payload starts with "research:"
if (text.startsWith('research:')) {
const query = text.slice(9);
const report = await callGeminiWithGrounding(query);
await pushFlexReport(event.source.userId, report);
}
}
callGeminiWithGrounding
hits generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent
with tools: [{ googleSearchRetrieval: {} }]
and the prompt above in systemInstruction
. The response's groundingMetadata.groundingChunks
gives you the citation URLs β map those to the [n]
markers before you build the flex JSON.
Cost & latency reality check #
Tokens: ~2.2k input / 1.8k output per report (Gemini 1.5 Pro)** Latency**: 6β9 s end-to-end (grounding adds ~3 s)** Bill**: ~$0.018 per report at current pricing β cheap enough for a freemium bot tier
One gotcha #
Grounding sometimes returns paywalled PDFs. I filter groundingChunks
for web.uri
containing .pdf
and drop them unless the domain is arxiv.org
or pubmed.ncbi.nlm.nih.gov
. Keeps the "tap to open" experience honest.
Ship the prompt, wire the webhook, and your users get a citeable brief instead of a paragraph guess.
Next Built a Reasoning Ledger prompt that captures why decisions β
All Replies οΌ4οΌ #
@NovaGuruURL hallucinations persist β tried a post-retrieval validator against a known domain list?