Initial commit
This commit is contained in:
602
references/grounding-guide.md
Normal file
602
references/grounding-guide.md
Normal file
@@ -0,0 +1,602 @@
|
||||
# Grounding with Google Search Guide
|
||||
|
||||
Complete guide to using grounding with Google Search to connect Gemini models to real-time web information, reducing hallucinations and providing verifiable, up-to-date responses.
|
||||
|
||||
---
|
||||
|
||||
## What is Grounding?
|
||||
|
||||
Grounding connects the Gemini model to Google Search, allowing it to:
|
||||
- Access real-time information beyond training cutoff
|
||||
- Reduce hallucinations with fact-checked web sources
|
||||
- Provide citations and source URLs
|
||||
- Answer questions about current events
|
||||
- Verify information against the web
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Model receives query** (e.g., "Who won Euro 2024?")
|
||||
2. **Model determines** if current information is needed
|
||||
3. **Performs Google Search** automatically
|
||||
4. **Processes search results** (web pages, snippets)
|
||||
5. **Incorporates findings** into response
|
||||
6. **Provides citations** with source URLs
|
||||
|
||||
---
|
||||
|
||||
## Two Grounding APIs
|
||||
|
||||
### 1. Google Search (`googleSearch`) - Recommended for Gemini 2.5
|
||||
|
||||
**Simple, automatic grounding**:
|
||||
|
||||
```typescript
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Who won the euro 2024?',
|
||||
config: {
|
||||
tools: [{ googleSearch: {} }]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Features**:
|
||||
- Simple configuration (empty object)
|
||||
- Automatic search when model needs current info
|
||||
- Available on all Gemini 2.5 models
|
||||
- Recommended for new projects
|
||||
|
||||
### 2. Google Search Retrieval (`googleSearchRetrieval`) - Legacy for Gemini 1.5
|
||||
|
||||
**Dynamic threshold control**:
|
||||
|
||||
```typescript
|
||||
import { DynamicRetrievalConfigMode } from '@google/genai';
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-1.5-flash',
|
||||
contents: 'Who won the euro 2024?',
|
||||
config: {
|
||||
tools: [{
|
||||
googleSearchRetrieval: {
|
||||
dynamicRetrievalConfig: {
|
||||
mode: DynamicRetrievalConfigMode.MODE_DYNAMIC,
|
||||
dynamicThreshold: 0.7 // Search only if confidence < 70%
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Features**:
|
||||
- Control when searches happen via threshold
|
||||
- Used with Gemini 1.5 models
|
||||
- More configuration options
|
||||
|
||||
**Recommendation**: Use `googleSearch` for Gemini 2.5 models (simpler and newer).
|
||||
|
||||
---
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### SDK Approach (Gemini 2.5)
|
||||
|
||||
```typescript
|
||||
import { GoogleGenAI } from '@google/genai';
|
||||
|
||||
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'What are the latest developments in AI?',
|
||||
config: {
|
||||
tools: [{ googleSearch: {} }]
|
||||
}
|
||||
});
|
||||
|
||||
console.log(response.text);
|
||||
|
||||
// Check if grounding was used
|
||||
if (response.candidates[0].groundingMetadata) {
|
||||
console.log('✓ Search performed');
|
||||
console.log('Sources:', response.candidates[0].groundingMetadata.webPages);
|
||||
} else {
|
||||
console.log('✓ Answered from model knowledge');
|
||||
}
|
||||
```
|
||||
|
||||
### Fetch Approach (Cloudflare Workers)
|
||||
|
||||
```typescript
|
||||
const response = await fetch(
|
||||
`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-goog-api-key': env.GEMINI_API_KEY,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
contents: [{ parts: [{ text: 'What are the latest developments in AI?' }] }],
|
||||
tools: [{ google_search: {} }]
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data.candidates[0].content.parts[0].text);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Grounding Metadata
|
||||
|
||||
### Structure
|
||||
|
||||
```typescript
|
||||
{
|
||||
groundingMetadata: {
|
||||
// Search queries performed
|
||||
searchQueries: [
|
||||
{ text: "euro 2024 winner" }
|
||||
],
|
||||
|
||||
// Web pages retrieved
|
||||
webPages: [
|
||||
{
|
||||
url: "https://example.com/euro-2024",
|
||||
title: "UEFA Euro 2024 Results",
|
||||
snippet: "Spain won UEFA Euro 2024..."
|
||||
}
|
||||
],
|
||||
|
||||
// Citations (inline references)
|
||||
citations: [
|
||||
{
|
||||
startIndex: 42,
|
||||
endIndex: 47,
|
||||
uri: "https://example.com/euro-2024"
|
||||
}
|
||||
],
|
||||
|
||||
// Retrieval queries (alternative search terms)
|
||||
retrievalQueries: [
|
||||
{ query: "who won euro 2024 final" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Accessing Metadata
|
||||
|
||||
```typescript
|
||||
if (response.candidates[0].groundingMetadata) {
|
||||
const metadata = response.candidates[0].groundingMetadata;
|
||||
|
||||
// Display sources
|
||||
console.log('Sources:');
|
||||
metadata.webPages?.forEach((page, i) => {
|
||||
console.log(`${i + 1}. ${page.title}`);
|
||||
console.log(` ${page.url}`);
|
||||
});
|
||||
|
||||
// Display citations
|
||||
console.log('\nCitations:');
|
||||
metadata.citations?.forEach((citation) => {
|
||||
console.log(`Position ${citation.startIndex}-${citation.endIndex}: ${citation.uri}`);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## When to Use Grounding
|
||||
|
||||
### ✅ Good Use Cases
|
||||
|
||||
**Current Events**:
|
||||
```typescript
|
||||
'What happened in the news today?'
|
||||
'Who won the latest sports championship?'
|
||||
'What are the current stock prices?'
|
||||
```
|
||||
|
||||
**Recent Developments**:
|
||||
```typescript
|
||||
'What are the latest AI breakthroughs?'
|
||||
'What are recent changes in climate policy?'
|
||||
```
|
||||
|
||||
**Fact-Checking**:
|
||||
```typescript
|
||||
'Is this claim true: [claim]?'
|
||||
'What does the latest research say about [topic]?'
|
||||
```
|
||||
|
||||
**Real-Time Data**:
|
||||
```typescript
|
||||
'What is the current weather in Tokyo?'
|
||||
'What are today's cryptocurrency prices?'
|
||||
```
|
||||
|
||||
### ❌ Not Recommended For
|
||||
|
||||
**General Knowledge**:
|
||||
```typescript
|
||||
'What is the capital of France?' // Model knows this
|
||||
'How does photosynthesis work?' // Stable knowledge
|
||||
```
|
||||
|
||||
**Mathematical Calculations**:
|
||||
```typescript
|
||||
'What is 15 * 27?' // Use code execution instead
|
||||
```
|
||||
|
||||
**Creative Tasks**:
|
||||
```typescript
|
||||
'Write a poem about autumn' // No search needed
|
||||
```
|
||||
|
||||
**Code Generation**:
|
||||
```typescript
|
||||
'Write a sorting algorithm' // Internal reasoning sufficient
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chat with Grounding
|
||||
|
||||
### Multi-Turn Conversations
|
||||
|
||||
```typescript
|
||||
const chat = await ai.chats.create({
|
||||
model: 'gemini-2.5-flash',
|
||||
config: {
|
||||
tools: [{ googleSearch: {} }]
|
||||
}
|
||||
});
|
||||
|
||||
// First question
|
||||
let response = await chat.sendMessage('What are the latest quantum computing developments?');
|
||||
console.log(response.text);
|
||||
|
||||
// Display sources
|
||||
if (response.candidates[0].groundingMetadata) {
|
||||
const sources = response.candidates[0].groundingMetadata.webPages || [];
|
||||
console.log(`\nSources: ${sources.length} web pages`);
|
||||
sources.forEach(s => console.log(`- ${s.title}: ${s.url}`));
|
||||
}
|
||||
|
||||
// Follow-up question
|
||||
response = await chat.sendMessage('Which company made the biggest breakthrough?');
|
||||
console.log('\n' + response.text);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Combining with Other Features
|
||||
|
||||
### Grounding + Function Calling
|
||||
|
||||
```typescript
|
||||
const weatherFunction = {
|
||||
name: 'get_current_weather',
|
||||
description: 'Get weather for a location',
|
||||
parametersJsonSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: { type: 'string', description: 'City name' }
|
||||
},
|
||||
required: ['location']
|
||||
}
|
||||
};
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'What is the weather like in the city that won Euro 2024?',
|
||||
config: {
|
||||
tools: [
|
||||
{ googleSearch: {} }, // For finding Euro 2024 winner
|
||||
{ functionDeclarations: [weatherFunction] } // For weather lookup
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// Model will:
|
||||
// 1. Use Google Search to find Euro 2024 winner (Madrid/Spain)
|
||||
// 2. Call get_current_weather function with the city
|
||||
// 3. Combine both results in response
|
||||
```
|
||||
|
||||
### Grounding + Code Execution
|
||||
|
||||
```typescript
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Find the current stock prices for AAPL, GOOGL, MSFT and calculate their average',
|
||||
config: {
|
||||
tools: [
|
||||
{ googleSearch: {} }, // For current stock prices
|
||||
{ codeExecution: {} } // For averaging
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// Model will:
|
||||
// 1. Search for current stock prices
|
||||
// 2. Generate code to calculate average
|
||||
// 3. Execute code with the found prices
|
||||
// 4. Return result with citations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checking Grounding Usage
|
||||
|
||||
### Determine if Search Was Performed
|
||||
|
||||
```typescript
|
||||
const queries = [
|
||||
'What is 2+2?', // Should NOT use search
|
||||
'What happened in the news today?' // Should use search
|
||||
];
|
||||
|
||||
for (const query of queries) {
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: query,
|
||||
config: { tools: [{ googleSearch: {} }] }
|
||||
});
|
||||
|
||||
console.log(`Query: ${query}`);
|
||||
console.log(`Search used: ${response.candidates[0].groundingMetadata ? 'YES' : 'NO'}`);
|
||||
console.log();
|
||||
}
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```
|
||||
Query: What is 2+2?
|
||||
Search used: NO
|
||||
|
||||
Query: What happened in the news today?
|
||||
Search used: YES
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dynamic Retrieval (Gemini 1.5)
|
||||
|
||||
### Threshold-Based Grounding
|
||||
|
||||
```typescript
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-1.5-flash',
|
||||
contents: 'Who won the euro 2024?',
|
||||
config: {
|
||||
tools: [{
|
||||
googleSearchRetrieval: {
|
||||
dynamicRetrievalConfig: {
|
||||
mode: DynamicRetrievalConfigMode.MODE_DYNAMIC,
|
||||
dynamicThreshold: 0.7 // Search only if confidence < 70%
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.candidates[0].groundingMetadata) {
|
||||
console.log('Model answered from knowledge (confidence >= 70%)');
|
||||
} else {
|
||||
console.log('Search performed (confidence < 70%)');
|
||||
}
|
||||
```
|
||||
|
||||
**How It Works**:
|
||||
- Model evaluates confidence in its internal knowledge
|
||||
- If confidence < threshold → performs search
|
||||
- If confidence >= threshold → uses internal knowledge
|
||||
|
||||
**Threshold Values**:
|
||||
- `0.0`: Never search (always use internal knowledge)
|
||||
- `0.5`: Search if moderately uncertain
|
||||
- `0.7`: Search if somewhat uncertain (good default)
|
||||
- `1.0`: Always search
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ Do
|
||||
|
||||
1. **Check Metadata**: Always verify if grounding was used
|
||||
```typescript
|
||||
if (response.candidates[0].groundingMetadata) { ... }
|
||||
```
|
||||
|
||||
2. **Display Citations**: Show sources to users for transparency
|
||||
```typescript
|
||||
metadata.webPages.forEach(page => {
|
||||
console.log(`Source: ${page.title} (${page.url})`);
|
||||
});
|
||||
```
|
||||
|
||||
3. **Use Specific Queries**: Better search results with clear questions
|
||||
```typescript
|
||||
// ✅ Good: "What are Microsoft's Q3 2024 earnings?"
|
||||
// ❌ Vague: "Tell me about Microsoft"
|
||||
```
|
||||
|
||||
4. **Combine Features**: Use with function calling/code execution for powerful workflows
|
||||
|
||||
5. **Handle Missing Metadata**: Not all queries trigger search
|
||||
```typescript
|
||||
const sources = response.candidates[0].groundingMetadata?.webPages || [];
|
||||
```
|
||||
|
||||
### ❌ Don't
|
||||
|
||||
1. **Don't Assume Search Always Happens**: Model decides when to search
|
||||
2. **Don't Ignore Citations**: They're crucial for fact-checking
|
||||
3. **Don't Use for Stable Knowledge**: Waste of resources for unchanging facts
|
||||
4. **Don't Expect Perfect Coverage**: Not all information is on the web
|
||||
|
||||
---
|
||||
|
||||
## Cost and Performance
|
||||
|
||||
### Cost Considerations
|
||||
|
||||
- **Added Latency**: Search takes 1-3 seconds typically
|
||||
- **Token Costs**: Retrieved content counts as input tokens
|
||||
- **Rate Limits**: Subject to API rate limits
|
||||
|
||||
### Optimization
|
||||
|
||||
**Use Dynamic Threshold** (Gemini 1.5):
|
||||
```typescript
|
||||
dynamicThreshold: 0.7 // Higher = more searches, lower = fewer searches
|
||||
```
|
||||
|
||||
**Cache Grounding Results** (if appropriate):
|
||||
```typescript
|
||||
const cache = await ai.caches.create({
|
||||
model: 'gemini-2.5-flash-001',
|
||||
config: {
|
||||
displayName: 'grounding-cache',
|
||||
tools: [{ googleSearch: {} }],
|
||||
contents: 'Initial query that triggers search...',
|
||||
ttl: '3600s'
|
||||
}
|
||||
});
|
||||
// Subsequent queries reuse cached grounding results
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Grounding Not Working
|
||||
|
||||
**Symptom**: No `groundingMetadata` in response
|
||||
|
||||
**Causes**:
|
||||
1. Grounding not enabled: `tools: [{ googleSearch: {} }]`
|
||||
2. Model decided search wasn't needed (query answerable from knowledge)
|
||||
3. Google Cloud project not configured (grounding requires GCP)
|
||||
|
||||
**Solution**:
|
||||
- Verify `tools` configuration
|
||||
- Use queries requiring current information
|
||||
- Set up Google Cloud project
|
||||
|
||||
### Poor Search Quality
|
||||
|
||||
**Symptom**: Irrelevant sources or wrong information
|
||||
|
||||
**Causes**:
|
||||
- Vague query
|
||||
- Search terms ambiguous
|
||||
- Recent events not yet indexed
|
||||
|
||||
**Solution**:
|
||||
- Make queries more specific
|
||||
- Include context in prompt
|
||||
- Verify search queries in metadata
|
||||
|
||||
### Citations Missing
|
||||
|
||||
**Symptom**: `groundingMetadata` present but no citations
|
||||
|
||||
**Explanation**: Citations are **inline references** - they may not always be present if model doesn't directly quote sources.
|
||||
|
||||
**Solution**: Check `webPages` instead for full source list
|
||||
|
||||
---
|
||||
|
||||
## Important Requirements
|
||||
|
||||
### Google Cloud Project
|
||||
|
||||
**⚠️ Grounding requires a Google Cloud project, not just an API key.**
|
||||
|
||||
**Setup**:
|
||||
1. Create Google Cloud project
|
||||
2. Enable Generative Language API
|
||||
3. Configure billing
|
||||
4. Use API key from that project
|
||||
|
||||
**Error if Missing**:
|
||||
```
|
||||
Error: Grounding requires Google Cloud project configuration
|
||||
```
|
||||
|
||||
### Model Support
|
||||
|
||||
**✅ Supported**:
|
||||
- All Gemini 2.5 models (`googleSearch`)
|
||||
- All Gemini 1.5 models (`googleSearchRetrieval`)
|
||||
|
||||
**❌ Not Supported**:
|
||||
- Gemini 1.0 models
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### News Summary
|
||||
|
||||
```typescript
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'Summarize today's top 3 technology news headlines',
|
||||
config: { tools: [{ googleSearch: {} }] }
|
||||
});
|
||||
|
||||
console.log(response.text);
|
||||
metadata.webPages?.forEach((page, i) => {
|
||||
console.log(`${i + 1}. ${page.title}: ${page.url}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Fact Verification
|
||||
|
||||
```typescript
|
||||
const claim = "The Earth is flat";
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: `Is this claim true: "${claim}"? Use reliable sources to verify.`,
|
||||
config: { tools: [{ googleSearch: {} }] }
|
||||
});
|
||||
|
||||
console.log(response.text);
|
||||
```
|
||||
|
||||
### Market Research
|
||||
|
||||
```typescript
|
||||
const response = await ai.models.generateContent({
|
||||
model: 'gemini-2.5-flash',
|
||||
contents: 'What are the current trends in electric vehicle adoption in 2024?',
|
||||
config: { tools: [{ googleSearch: {} }] }
|
||||
});
|
||||
|
||||
console.log(response.text);
|
||||
console.log('\nSources:');
|
||||
metadata.webPages?.forEach(page => {
|
||||
console.log(`- ${page.title}`);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Official Docs: https://ai.google.dev/gemini-api/docs/grounding
|
||||
- Google Search Docs: https://ai.google.dev/gemini-api/docs/google-search
|
||||
- Templates: See `grounding-search.ts` for working examples
|
||||
- Combined Features: See `combined-advanced.ts` for integration patterns
|
||||
Reference in New Issue
Block a user