คำตอบสั้น
จะเรียก web search API สำหรับ AI agent จาก Node.js ได้อย่างไร?
ใช้ fetch ที่มีในตัวของ Node 18+ ส่ง POST คำค้นหาของคุณไปยัง https://llmwebsearch.com/api/v1/search พร้อม Bearer key LLMWebSearch ตอบกลับด้วยผลลัพธ์ที่จัดอันดับแล้วและหน้าเว็บ 3 อันดับแรกในรูปแบบ Markdown พร้อมใส่หมายเลขและส่งให้โมเดลเพื่อสร้างคำตอบพร้อมการอ้างอิง การค้นหาหนึ่งครั้งใช้ 1 เครดิต เริ่มต้นที่ US$1.20/1K การค้นหา ณ ตุลาคม 2026 ไม่ต้องใช้แพ็กเกจ npm ไม่ต้อง KYC จ่ายด้วยคริปโต
สิ่งที่คุณต้องมี
| Node.js | 18 ขึ้นไป สำหรับ fetch ที่มีในตัว; บันทึกสคริปต์เป็น .mjs เพื่อใช้ await ระดับบนสุด |
|---|---|
| แพ็กเกจ | ไม่มี |
| Key | LLMWEBSEARCH_API_KEY ใน environment ของคุณ |
| สำหรับลูปตอบ | chat endpoint ที่เข้ากันได้กับ OpenAI: LLM_BASE_URL, LLM_API_KEY, LLM_MODEL |
| การเรียกเก็บเงิน | หนึ่งเครดิตจ่ายสำหรับการค้นหาหนึ่งครั้ง: ผลลัพธ์แบบจัดอันดับสูงสุด 20 รายการ โดยอ่านหน้าเว็บของ 3 รายการแรกและส่งกลับเป็น Markdown การอ่าน 4 ถึง 10 หน้าใช้ 2 เครดิต การเรียกที่จบลงด้วยข้อผิดพลาดไม่มีค่าใช้จ่าย |
จะเขียนฟังก์ชันค้นหาที่ใช้ซ้ำได้อย่างไร?
ห่อการเรียกครั้งเดียวแล้วใช้ซ้ำได้ทุกที่ ฟังก์ชันด้านล่างส่ง body, โยนข้อผิดพลาดที่อ่านได้เมื่อ HTTP ล้มเหลว และคืน JSON ที่ parse แล้ว ข้อผิดพลาดมี code ของ API เอง เช่น rate_limited หรือ insufficient_credits เพื่อให้ผู้เรียกตัดสินใจได้ว่าจะทำอะไร
const API = 'https://llmwebsearch.com/api/v1/search';
export async function search(body) {
const res = await fetch(API, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LLMWEBSEARCH_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) {
const err = new Error(`${res.status} ${data.error?.code}: ${data.error?.message}`);
err.status = res.status;
throw err;
}
return data;
}
const data = await search({ q: 'how to size a postgres connection pool', read: 3 });
for (const r of data.results) {
console.log(r.position, r.content_status, r.url, r.word_count ?? '');
}
ฉันจะรันหลายการค้นหาโดยไม่ชน rate limit ได้อย่างไร
รันผ่านพูลเล็กๆ: จำนวน worker คงที่ที่แต่ละตัวหยิบคำค้นหาถัดไปจากรายการที่แชร์กัน สี่ worker ถือเป็นจุดเริ่มต้นที่สมเหตุสมผล ทุกบัญชีมีขีดจำกัดการเรียกต่อนาที แสดงในแดชบอร์ด; แจ้งฝ่ายสนับสนุนและสามารถเพิ่มได้
พูลด้านล่างไม่ต้องใช้ไลบรารี Worker แต่ละตัวเก็บผลลัพธ์ของตัวเอง และการค้นหาที่ล้มเหลวจะถูกบันทึกพร้อม error แทนที่จะหยุดทั้งรอบ ซึ่งสำคัญสำหรับ research agent ที่คำถามย่อยข้อเดียวที่ผิดไม่ควรทำให้งานทั้งชิ้นเสียหาย
const API = 'https://llmwebsearch.com/api/v1/search';
const questions = [
'what is connection pooling in postgres',
'recommended pool size per cpu core',
'pgbouncer transaction mode limitations',
'connection pool exhaustion symptoms',
'pool size for serverless functions',
];
async function search(q) {
const res = await fetch(API, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.LLMWEBSEARCH_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ q, read: 2, max_chars: 4000 }),
});
const data = await res.json();
if (!res.ok) return { q, error: data.error?.code ?? String(res.status) };
return { q, urls: data.results.filter((r) => r.content_status === 'ok').map((r) => r.url) };
}
async function runPool(items, size, task) {
const out = [];
let next = 0;
const worker = async () => {
while (next < items.length) {
const i = next++;
out[i] = await task(items[i]);
}
};
await Promise.all(Array.from({ length: size }, worker));
return out;
}
for (const row of await runPool(questions, 4, search)) console.log(row);
ฉันจะแปลงผลลัพธ์เป็นคำตอบพร้อม citation ได้อย่างไร
ใส่หมายเลขให้แหล่งอ้างอิง วาง URL ไว้ข้างๆ แต่ละแหล่ง ตัดให้พอดีงบประมาณ แล้วขอให้โมเดลอ้างอิงตามหมายเลข API ส่งคืนแหล่งข้อมูล ไม่ใช่คำตอบที่เขียนไว้: โมเดลของคุณเองอ่านหน้าเว็บ เขียนคำตอบ และอ้างอิง URL สคริปต์ด้านล่างคุยกับ endpoint ที่รองรับ OpenAI ได้ทุกตัว chat/completions ซึ่งเลือกด้วย environment variable สามตัว จึงใช้ได้ทั้งกับโมเดลแบบ hosted และ local
งบประมาณราว 24,000 ตัวอักษร หรือประมาณ 6,000 token ถูกแบ่งเท่าๆ กันระหว่างแหล่งอ้างอิง ผลลัพธ์ที่อ่านหน้าเว็บไม่ได้จะถูกส่งเป็น snippet พร้อมระบุว่าเป็นเช่นนั้น
const SEARCH = 'https://llmwebsearch.com/api/v1/search';
const BUDGET = 24000; // characters, about 6,000 tokens
async function sources(question) {
const res = await fetch(SEARCH, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.LLMWEBSEARCH_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: question, max_results: 5, read: 3 }),
});
const { results } = await res.json();
const share = Math.floor(BUDGET / Math.max(results.length, 1));
return results
.map((r, i) => {
const body = r.content_status === 'ok' ? r.content.slice(0, share) : `(snippet only) ${r.snippet}`;
return `[${i + 1}] ${r.title} - ${r.url}\n${body}`;
})
.join('\n\n');
}
async function answer(question) {
const prompt = 'Answer using only the sources below. Cite them as [1], [2] and so on. '
+ 'Say so if they do not answer the question.\n\n' + (await sources(question)) + '\n\nQuestion: ' + question;
const res = await fetch(`${process.env.LLM_BASE_URL.replace(/\/$/, '')}/chat/completions`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.LLM_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model: process.env.LLM_MODEL, messages: [{ role: 'user', content: prompt }] }),
});
const data = await res.json();
return data.choices[0].message.content;
}
console.log(await answer('How should I size a Postgres connection pool?'));
ควรใช้ GET หรือ POST จาก Node?
POST พร้อม JSON body ในโค้ดแอปพลิเคชัน อาร์เรย์อย่าง include_domains และคำถามยาวๆ เดินทางใน body ได้สะอาดกว่าใน query string GET มีไว้สำหรับการทดสอบเร็วๆ และสำหรับเครื่องมือที่ไม่สามารถส่ง body ได้ สร้าง query string ด้วย URLSearchParams และเชื่อมรายการด้วยเครื่องหมายจุลภาค
ทั้งสองแบบมีค่าใช้จ่ายเท่ากันและคืน JSON เหมือนกัน search reference แสดงรายการทุกพารามิเตอร์สำหรับทั้งสองแบบ
ควรเก็บ key ไว้ที่ไหน?
ใน environment variable ที่อ่านตอนรัน ไม่เคยอยู่ในไฟล์ซอร์ส บนเซิร์ฟเวอร์ ให้ใช้ secret store ของแพลตฟอร์มคุณ ในเบราว์เซอร์ อย่าเรียก API เลย: key จะมองเห็นได้โดยผู้เข้าชมทุกคน ให้เรียก backend ของคุณเอง ซึ่งจะเรียก LLMWebSearch ต่อ
สร้าง API key หนึ่งอันต่อเอเจนต์ แอป หรือเพื่อนร่วมทีม และเพิกถอนอันใดก็ได้จากแดชบอร์ดโดยไม่กระทบอันอื่น หนึ่ง key ต่อหนึ่งบริการทำให้ประวัติใน dashboard อ่านง่ายขึ้น และเพิกถอน key ที่รั่วไหลได้ง่าย
Node.js: คำถามที่พบบ่อย
มีแพ็กเกจ npm ไหม?
ไม่มี fetch มีมาในตัวใน Node 18 ขึ้นไป และ API เป็น JSON ธรรมดาผ่าน HTTPS ฟังก์ชันในหน้านี้คือการเชื่อมต่อทั้งหมด
ใช้ได้บน Deno, Bun หรือ edge runtime ไหม?
โค้ดใช้แค่ fetch, JSON และ process.env รันไทม์ที่มี fetch ใช้ได้หลังจากแทน process.env ด้วยวิธีอ่าน secret ของตัวเอง
ฉันจะ retry การเรียกที่ล้มเหลวได้อย่างไร?
Retry เฉพาะ 429, 502 และ 504 โดยหยุดพักที่เพิ่มเป็นสองเท่าในแต่ละครั้ง อย่า retry 400, 401 หรือ 402 เด็ดขาด errors page อธิบายเหตุผลและแสดง helper