openclaw websearch修改brave search 为百度搜索API
openclaw websearch修改为百度搜索API
·
openclaw websearch修改brave search 为百度搜索API接口
使用方法:
1.百度开发平台注册搜索接口APIKEY
2.替换dist/agents/tools/web-search.js JS文件里内容为:
import { Type } from "@sinclair/typebox";
import { formatCliCommand } from "../../cli/command-format.js";
import { jsonResult, readNumberParam, readStringParam } from "./common.js";
import {
DEFAULT_CACHE_TTL_MINUTES,
DEFAULT_TIMEOUT_SECONDS,
normalizeCacheKey,
readCache,
readResponseText,
resolveCacheTtlMs,
resolveTimeoutSeconds,
withTimeout,
writeCache,
} from "./web-shared.js";
const SEARCH_PROVIDERS = ["baidu"];
const DEFAULT_SEARCH_COUNT = 10;
const MAX_SEARCH_COUNT = 50;
const BAIDU_SEARCH_ENDPOINT = "https://qianfan.baidubce.com/v2/ai_search/web_search";
// 百度搜索缓存
const SEARCH_CACHE = new Map();
// 百度搜索参数定义
const WebSearchSchema = Type.Object({
query: Type.String({
description: "Search query string (max 72 characters)."
}),
count: Type.Optional(Type.Number({
description: `Number of results to return (1-${MAX_SEARCH_COUNT}).`,
minimum: 1,
maximum: MAX_SEARCH_COUNT,
})),
freshness: Type.Optional(Type.String({
description: "Filter results by publish time. Values: 'week' (last 7 days), 'month' (last 30 days), 'semiyear' (last 180 days), 'year' (last 365 days).",
})),
site: Type.Optional(Type.String({
description: "Specify a site to search within (e.g., 'example.com').",
})),
edition: Type.Optional(Type.String({
description: "Search edition. 'standard' (full version) or 'lite' (standard version with better latency).",
enum: ["standard", "lite"],
})),
safe_search: Type.Optional(Type.Boolean({
description: "Enable safe search to filter sensitive content. Default: false.",
})),
});
// 解析搜索配置
function resolveSearchConfig(cfg) {
const search = cfg?.tools?.web?.search;
if (!search || typeof search !== "object") {
return undefined;
}
return search;
}
// 解析搜索是否启用
function resolveSearchEnabled(params) {
if (typeof params.search?.enabled === "boolean") {
return params.search.enabled;
}
if (params.sandboxed) {
return true;
}
return true;
}
// 解析百度API Key
function resolveSearchApiKey(search) {
const fromConfig = search && "apiKey" in search && typeof search.apiKey === "string"
? search.apiKey.trim()
: "";
const fromEnv = (process.env.BAIDU_API_KEY || process.env.QIANFAN_API_KEY || "").trim();
return fromConfig || fromEnv || undefined;
}
// API Key缺失的错误信息
function missingSearchKeyPayload() {
return {
error: "missing_baidu_api_key",
message: `web_search needs a Baidu Qianfan API key. Run \`${formatCliCommand("openclaw configure --section web")}\` to store it, or set BAIDU_API_KEY in the Gateway environment.`,
docs: "https://docs.openclaw.ai/tools/web",
};
}
// 解析搜索提供商(仅百度)
function resolveSearchProvider(search) {
return "baidu"; // 目前只支持百度
}
// 解析搜索数量
function resolveSearchCount(value, fallback) {
const parsed = typeof value === "number" && Number.isFinite(value) ? value : fallback;
const clamped = Math.max(1, Math.min(MAX_SEARCH_COUNT, Math.floor(parsed)));
return clamped;
}
// 规范化新鲜度参数
function normalizeFreshness(value) {
if (!value) {
return undefined;
}
const trimmed = value.trim().toLowerCase();
const freshnessMap = {
"week": "week",
"month": "month",
"semiyear": "semiyear",
"year": "year",
"w": "week",
"m": "month",
"s": "semiyear",
"y": "year",
"7d": "week",
"30d": "month",
"180d": "semiyear",
"365d": "year",
};
return freshnessMap[trimmed] || undefined;
}
// 运行百度搜索
async function runBaiduSearch(params) {
const requestBody = {
messages: [
{
content: params.query.substring(0, 72), // 百度限制72字符
role: "user",
},
],
search_source: "baidu_search_v2",
resource_type_filter: [
{
type: "web",
top_k: params.count,
},
{
type: "video",
top_k: 0,
},
{
type: "image",
top_k: 0,
},
{
type: "aladdin",
top_k: 0,
},
],
};
// 可选参数
if (params.edition) {
requestBody.edition = params.edition;
}
if (params.freshness) {
requestBody.search_recency_filter = params.freshness;
}
if (params.site) {
requestBody.search_filter = {
match: {
site: [params.site],
},
};
}
if (typeof params.safe_search === "boolean") {
requestBody.safe_search = params.safe_search;
}
const start = Date.now();
const res = await fetch(BAIDU_SEARCH_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${params.apiKey}`,
"X-Appbuilder-Authorization": `Bearer ${params.apiKey}`,
},
body: JSON.stringify(requestBody),
signal: withTimeout(undefined, params.timeoutSeconds * 1000),
});
if (!res.ok) {
const detail = await readResponseText(res);
throw new Error(`Baidu Search API error (${res.status}): ${detail || res.statusText}`);
}
const data = await res.json();
// 处理错误响应
if (data.code) {
throw new Error(`Baidu Search API error (${data.code}): ${data.message || "Unknown error"}`);
}
// 转换百度响应格式为通用格式
const references = data.references || [];
const results = references
.filter(ref => ref.type === "web") // 只处理网页结果
.map((ref, index) => ({
title: ref.title || "",
url: ref.url || "",
description: ref.content || "",
published: ref.date || undefined,
siteName: ref.website || resolveSiteName(ref.url),
relevanceScore: ref.rerank_score || 0,
authorityScore: ref.authority_score || 0,
}));
return {
query: params.query,
provider: "baidu",
count: results.length,
totalCount: references.length,
tookMs: Date.now() - start,
requestId: data.request_id,
results: results,
};
}
// 从URL解析站点名称
function resolveSiteName(url) {
if (!url) {
return undefined;
}
try {
return new URL(url).hostname;
} catch {
return undefined;
}
}
// 运行Web搜索(主函数)
async function runWebSearch(params) {
const cacheKey = normalizeCacheKey(
`baidu:${params.query}:${params.count}:${params.freshness || "default"}:${params.site || "default"}:${params.edition || "standard"}:${params.safe_search || "false"}`
);
// 检查缓存
const cached = readCache(SEARCH_CACHE, cacheKey);
if (cached) {
return { ...cached.value, cached: true };
}
let result;
if (params.provider === "baidu") {
result = await runBaiduSearch(params);
} else {
throw new Error(`Unsupported web search provider: ${params.provider}`);
}
// 写入缓存
writeCache(SEARCH_CACHE, cacheKey, result, params.cacheTtlMs);
return result;
}
// 创建Web搜索工具
export function createWebSearchTool(options) {
const search = resolveSearchConfig(options?.config);
if (!resolveSearchEnabled({ search, sandboxed: options?.sandboxed })) {
return null;
}
const provider = resolveSearchProvider(search);
return {
label: "Web Search",
name: "web_search",
description: "Search the web using Baidu Qianfan Search API. Returns real-time web search results with titles, URLs, and content snippets. Supports site-specific search and freshness filtering.",
parameters: WebSearchSchema,
execute: async (_toolCallId, args) => {
//const apiKey = resolveSearchApiKey(search);
const apiKey=替换为自己的百度搜索APIKEY
if (!apiKey) {
return jsonResult(missingSearchKeyPayload());
}
const params = args;
const query = readStringParam(params, "query", { required: true });
// 验证查询长度
if (query.length > 72) {
return jsonResult({
error: "query_too_long",
message: "Search query must be 72 characters or less for Baidu Search API.",
docs: "https://docs.openclaw.ai/tools/web",
});
}
const count = readNumberParam(params, "count", { integer: true }) ?? search?.maxResults ?? undefined;
const rawFreshness = readStringParam(params, "freshness");
const site = readStringParam(params, "site");
const edition = readStringParam(params, "edition");
const safeSearch = params.safe_search; // 已经是boolean类型
// 验证新鲜度参数
const freshness = rawFreshness ? normalizeFreshness(rawFreshness) : undefined;
if (rawFreshness && !freshness) {
return jsonResult({
error: "invalid_freshness",
message: "freshness must be one of: 'week', 'month', 'semiyear', 'year'.",
docs: "https://docs.openclaw.ai/tools/web",
});
}
const result = await runWebSearch({
query,
count: resolveSearchCount(count, DEFAULT_SEARCH_COUNT),
apiKey,
timeoutSeconds: resolveTimeoutSeconds(search?.timeoutSeconds, DEFAULT_TIMEOUT_SECONDS),
cacheTtlMs: resolveCacheTtlMs(search?.cacheTtlMinutes, DEFAULT_CACHE_TTL_MINUTES),
provider,
freshness,
site,
edition,
safe_search: safeSearch,
});
return jsonResult(result);
},
};
}
// 导出测试用函数
export const __testing = {
normalizeFreshness,
resolveSearchCount,
};
3.此段代码中apikey替换为百度apikey
return {
label: “Web Search”,
name: “web_search”,
description: “Search the web using Baidu Qianfan Search API. Returns real-time web search results with titles, URLs, and content snippets. Supports site-specific search and freshness filtering.”,
parameters: WebSearchSchema,
execute: async (_toolCallId, args) => {
//const apiKey = resolveSearchApiKey(search);
const apiKey=替换为百度apikey
更多推荐

所有评论(0)