AI-API - RAG in two calls (embed_and_search, then ai_summary)

AI API: Vectors, Images & LLM

An answer written from your own pages takes two calls: a search that finds the best results, and an answer written from them. The model reads only what the search found, so the answer comes from your content, not from what a model remembers.

01 · Step 1: find the content

Search your index with embed_and_search and keep the best 3 or 4 results. Send fresh=no, so results of every date count, and in=all when the index also holds files.

curl -s https://api.opensolr.com/solr_manager/api/embed_and_search \
  --data-urlencode "email=YOUR_EMAIL" \
  --data-urlencode "api_key=YOUR_API_KEY" \
  --data-urlencode "index_name=YOUR_INDEX" \
  --data-urlencode "q=How do I reset my password?" \
  --data-urlencode "rows=4" \
  --data-urlencode "fresh=no" \
  --data-urlencode "in=all"

02 · Step 2: write the answer

Put the question, your rules and the title, description and text of those results into one instruction for ai_summary. Number the documents, so you can tell which one the answer came from.

03 · PHP

<?php
$auth = ['email' => 'YOUR_EMAIL', 'api_key' => 'YOUR_API_KEY', 'index_name' => 'YOUR_INDEX'];
$question = 'How do I reset my password?';

function opensolr_post($endpoint, array $fields) {
    $ch = curl_init('https://api.opensolr.com/solr_manager/api/' . $endpoint);
    curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 300,
        CURLOPT_POSTFIELDS => http_build_query($fields)]);
    $body = curl_exec($ch);
    curl_close($ch);
    return $body;
}

// Step 1: the best 4 results
$found = json_decode(opensolr_post('embed_and_search', $auth + [
    'q' => $question, 'rows' => 4, 'fresh' => 'no', 'in' => 'all',
]), true);

// Step 2: one instruction with the question, the rules and the numbered content
$lines = [
    'Answer the question using only the content below: ' . $question,
    'Begin with the answer itself. Use only what the content states.',
    '',
    'CONTENT:',
];
foreach ($found['results']['docs'] ?? [] as $i => $doc) {
    $text = implode(' ', array_slice(preg_split('/\s+/', (string)($doc['text'] ?? '')), 0, 1500));
    $lines[] = '[' . ($i + 1) . '] ' . ($doc['title'] ?? '') . ' - ' . ($doc['description'] ?? '') . ' - ' . $text;
}

echo opensolr_post('ai_summary', $auth + ['instruction' => implode(PHP_EOL, $lines)]), PHP_EOL;

04 · Python

import requests

API = "https://api.opensolr.com/solr_manager/api/"
AUTH = {"email": "YOUR_EMAIL", "api_key": "YOUR_API_KEY", "index_name": "YOUR_INDEX"}
question = "How do I reset my password?"

# Step 1: the best 4 results
found = requests.post(API + "embed_and_search", data={
    **AUTH, "q": question, "rows": 4, "fresh": "no", "in": "all",
}, timeout=60).json()
docs = found.get("results", {}).get("docs", [])

# Step 2: one instruction with the question, the rules and the numbered content
lines = [
    "Answer the question using only the content below: " + question,
    "Begin with the answer itself. Use only what the content states.",
    "",
    "CONTENT:",
]
for i, doc in enumerate(docs, start=1):
    text = " ".join(str(doc.get("text", "")).split()[:1500])
    lines.append(f"[{i}] {doc.get('title', '')} - {doc.get('description', '')} - {text}")

answer = requests.post(API + "ai_summary", data={**AUTH, "instruction": "\n".join(lines)}, timeout=300)
print(answer.text)

05 · Good to know

Each call uses the monthly AI allowance of the account that owns the index: one request for a new search, one for a new answer. Both are free when they come from cache. Every plan includes a monthly AI allowance of 500 AI requests; see pricing and API Quota.

The search in step 1 uses the Search Tuning of your index; you can change it for that call only: Search Tuning for one call.

To ask for the answer as JSON with the documents it used, add answer_format=picks in step 2: ai_summary.

Ready made, with no code: AI Hints on the hosted search page, and the chat bot, which searches by itself and answers follow-up questions.