
WebSearch.MTServer 是一个 OLE 公共类,继承自 Visual FoxPro 的 Session 类。它封装了 WebSearchManager 对象,对外提供统一的 Web 搜索接口,支持多个搜索引擎提供者(Ollama、Exa、SerpAPI、Tavily 等),并能够处理 HTTP 错误、标准化返回结果。
主要用途:它为各种 COM 客户端(VFP、C#、VB.NET、X#、Python、Delphi 等)实现了一句话搜索并获取结构化结果。
ProgID:WebSearch.MTServer
线程模型: 多线程单元(MTA) – 支持多线程并发调用(但需注意内部对象的线程安全性)
类层次:
Session ← MTServer (OlePublic)
依赖文件:
config.json – 提供者配置文件(需位于当前目录或指定路径,见配置章节)regsvr32 工具注册 DLL。导航到 DLL 所在目录,执行:regsvr32 WebSearch.dll
名称 | 类型 | 可见性 | 说明 |
|---|---|---|---|
oWebSearchManager | Object | Protected | 内部使用的 websearchmanager 对象实例。初始化时创建,不应直接访问。 |
其他属性均由
oWebSearchManager内部维护,外部无需关心。
语法
Procedure SetProvider(tcProvider) AS Logical
参数
参数 | 类型 | 说明 |
|---|---|---|
tcProvider | Character | 提供者名称(不区分大小写),见下表“支持的提供者” |
返回值
.T. 表示设置成功,.F. 表示提供者未在 config.json 中定义说明
config.json 中的 webSearch 数组决定。WebSearch 将使用新提供者。示例
loServer = CREATEOBJECT("WebSearch.MTServer")
IF loServer.SetProvider("exa")
? "已切换到 Exa 搜索"
ENDIF
语法
Procedure WebSearch(tcQuery) AS Object
参数
参数 | 类型 | 说明 |
|---|---|---|
tcQuery | Character | 搜索关键词、问题或 URL(具体取决于适配器类型) |
返回值 Object – 始终返回一个 Collection 对象,结构如下:
集合属性/方法 | 类型 | 说明 |
|---|---|---|
lError | Logical | 本次请求是否出错。.T. 表示错误,.F. 表示成功 |
.Count | Number | 结果条目数(错误时通常为 1) |
.Item(i) | Object (Empty) | 第 i 个搜索结果,包含以下属性:- Title (Character) – 标题- Link (Character) – 链接- Snippet (Character) – 摘要或内容片段 |
错误情况:
当 lError = .T. 时,集合中仅有一个 Empty 对象,其属性含义变为:
Title – HTTP 状态码(如 "401")Link – 错误类型说明(如 "API 密钥无效或缺失")Snippet – 服务器返回的原始错误信息备注
AnythingLLMAdapter 只返回 1 条,ExaAdapter 最多返回 nMaxResults 条)。TavilyCrawlAdapter),Title 可能为空字符串。示例
loServer = CREATEOBJECT("WebSearch.MTServer")
loServer.SetProvider("serpapi")
loResults = loServer.WebSearch("Visual FoxPro COM")
IF NOT loResults.lError
FOR i = 1 TO loResults.Count
? "标题:", loResults.Item(i).Title
? "链接:", loResults.Item(i).Link
? "摘要:", loResults.Item(i).Snippet
ENDFOR
ELSE
? "错误:", loResults.Item(1).Snippet
ENDIF
语法
Procedure GetDebugObject() AS Object
返回值 Object – 返回一个运行在独立 Visual FoxPro 应用程序实例中的 新 MTServer 对象。
说明
MTServer 一样调用 SetProvider、WebSearch 等方法。示例
loDebug = loServer.GetDebugObject()
? "调试对象类型:", VARTYPE(loDebug) && "O"
loDebug.SetProvider("tavily")
loResults = loDebug.WebSearch("天气预报")
注意:频繁调用此方法会产生多个 VFP 进程,谨慎使用。
WebSearchManager 内置了以下适配器,通过 SetProvider 传入对应的名称即可使用。
实际可用列表取决于 config.json 中是否配置了对应的 name。
提供者名称 | 说明 | 是否需要 API Key | 默认最大结果数 |
|---|---|---|---|
ollama | Ollama 云搜索(需注册) | 是 | 5 |
ollama_local | Ollama 本地模式(需本地安装 Ollama) | 否 | 5 |
exa | Exa API(每月 1000 次免费) | 是 | 5¹ |
serpapi | SerpAPI 标准搜索(每月 250 次免费) | 是 | 由 API 决定² |
serpapi_ai | SerpAPI AI 模式(返回 AI 生成摘要) | 是 | 1 |
tavily | Tavily 搜索(返回网页结果) | 是 | 5 |
ollama_fetch | Ollama 抓取单个 URL | 否 | 1 |
ollama_fetch_local | 同上(本地模式) | 否 | 1 |
anythingllm_fetch | AnythingLLM 抓取 URL(需本地安装 AnythingLLM) | 是 | 1 |
tavily_fetch | Tavily 批量抓取 URL(传入逗号分隔的多个 URL) | 是 | 按输入数量 |
tavily_crawl | Tavily 爬取指定 URL 的所有子页面 | 是 | 不定 |
tavily_research | Tavily 深度研究(异步,轮询获取报告) | 是 | 1(研究报告) |
¹
nMaxResults受searchadapterbase.nmaxresults属性控制,默认为 5。 ² SerpAPI 的结果数量由 API 自身决定,通常为 10 条左右。 ³ 对于“抓取类”适配器,查询参数应传入 URL 而非关键词。
config.jsonWebSearchManager 初始化时会读取 config.json 文件,结构如下:
{
"webSearch": [
{
"name": "ollama",
"desc": "Ollama云搜索",
"url": "https://api.ollama.ai/v1/search",
"apiKey": "your-ollama-key"
},
{
"name": "exa",
"desc": "Exa搜索",
"url": "https://api.exa.ai/search",
"apiKey": "exa-api-key"
}
]
}
要求:
SET DEFAULT 指定的路径。name 字段必须与 SetProvider 的参数小写形式匹配。url 和 apiKey 会被自动应用到对应的适配器。ollama_local),可留空字符串。WebSearch 返回的 Collection 对象在成功和错误时结构不同:
lError = .F.)Empty 对象,每个对象有三个属性:Title, Link, Snippet。loResults = loServer.WebSearch("VFP")
? loResults.lError && .F.
? loResults.Count && 5
? loResults.Item(1).Title
? loResults.Item(1).Link
? loResults.Item(1).Snippet
lError = .T.)Empty 对象,属性含义变化:? loResults.lError && .T.
? loResults.Item(1).Title && 例如 "401"
? loResults.Item(1).Link && 例如 "API 密钥缺失或无效"
? loResults.Item(1).Snippet && 详细的服务器错误信息
LOCAL loServer, loResults, i
loServer = CREATEOBJECT("WebSearch.MTServer")
* 切换到 Exa 搜索(确保 config.json 中有对应项)
IF NOT loServer.SetProvider("exa")
MESSAGEBOX("提供者不可用")
RETURN
ENDIF
* 执行搜索
loResults = loServer.WebSearch("人工智能 最新进展")
IF loResults.lError
MESSAGEBOX("搜索出错: " + loResults.Item(1).Snippet)
ELSE
FOR i = 1 TO loResults.Count
? "【" + TRANSFORM(i) + "】"
? "标题:" + loResults.Item(i).Title
? "链接:" + loResults.Item(i).Link
? "摘要:" + LEFT(loResults.Item(i).Snippet, 200) + "..."
?
ENDFOR
ENDIF
ollama_fetch)loServer.SetProvider("ollama_fetch")
loResults = loServer.WebSearch("https://example.com/article")
IF NOT loResults.lError
? "抓取到的内容片段:" + loResults.Item(1).Snippet
ENDIF
lError 属性,不要假设 Title/Link/Snippet 一定存在有效内容。WinHttp 捕获,Status 可能为 0,错误信息会放入 Snippet。SetProvider 返回 .F.,请检查 config.json 中是否定义了该提供者名称,且大小写匹配(内部会转为小写比较)。TRY...CATCH 包裹 CREATEOBJECT 和 WebSearch 调用,以防类库缺失等问题。项目 | 内容 |
|---|---|
版本 | 2026.04.28 |
作者 | xinjie |
最后更新 | 2026-04-28 |