AI 工具

Andi Search API:校验 searchMode 与请求参数

发搜索前校验 q、searchMode、effort、format、limit 等,避免无效参数直接烧额度。

BINBHO · 图文教程

发搜索前校验 q、searchMode、effort、format、limit 等,避免无效参数直接烧额度。

先看清成品

  • sample_ok → OK;空 q / 非法 mode → INVALID。
  • 3 项 pytest 通过。

合规提醒:Andi 回答与搜索结果可能不完整,重要信息须打开原文核对。API 密钥仅放服务端;metrics.cost_dollars 反映计费,注意配额。遵守目标站点 robots/使用条款,勿用 fetch 做未授权批量抓取。本文不编造价格表。

运行说明:无正式 ANDI_API_KEY。A/B 用 mock;对官方 api.andiai.com 无效密钥实测 HTTP 401。C 为参数本地校验。2026-10-23(Asia/Shanghai)pytest 通过。

做完之后你会得到什么?

成果 说明
search_params.py 参数校验
样例 JSON ok/bad
test_107c.py 测试

需要准备哪些环境?

项目 说明
Python 3.10+

关键事实

事实 来源
searchMode 含 auto/low-cost/fast/balanced/deep/exhaustive 官方
effort 可用 low/medium/high/max 映射档位 官方
枚举以文档为准,脚本需随文档更新 重要

文件结构

107-andi-C-src/
├── search_params.py
├── sample_ok.json
├── sample_bad.json
└── test_107c.py

第 1 步:校验脚本

#!/usr/bin/env python3
"""Validate Andi search query parameters before spending credits."""
from __future__ import annotations
import argparse, json
from pathlib import Path

MODES = {"auto", "low-cost", "fast", "balanced", "deep", "exhaustive"}
EFFORTS = {"low", "medium", "high", "max"}
FORMATS = {"json", "context"}

def validate(p: dict) -> list[str]:
    errs = []
    q = p.get("q")
    if not q or not str(q).strip():
        errs.append("q 必填")
    elif len(str(q)) > 500:
        errs.append("q 过长(教程软限制 500)")
    mode = p.get("searchMode")
    if mode is not None and mode not in MODES:
        errs.append(f"searchMode 须为 {sorted(MODES)}")
    effort = p.get("effort")
    if effort is not None and effort not in EFFORTS:
        errs.append(f"effort 须为 {sorted(EFFORTS)}")
    fmt = p.get("format")
    if fmt is not None and fmt not in FORMATS:
        errs.append(f"format 须为 {sorted(FORMATS)}")
    limit = p.get("limit")
    if limit is not None:
        if not isinstance(limit, int) or not (1 <= limit <= 50):
            errs.append("limit 建议 1..50")
    domains = p.get("includeDomains") or p.get("include_domains")
    if domains is not None and not isinstance(domains, list):
        errs.append("includeDomains 须为数组")
    return errs

def main(argv=None) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("params_json")
    args = ap.parse_args(argv)
    p = json.loads(Path(args.params_json).read_text(encoding="utf-8"))
    errs = validate(p)
    if errs:
        print("INVALID")
        for e in errs: print("-", e)
        return 1
    print("OK")
    print(json.dumps(p, ensure_ascii=False))
    return 0

if __name__ == "__main__":
    raise SystemExit(main())

第 2 步:测试

from pathlib import Path
import json, subprocess, sys
from search_params import validate
HERE = Path(__file__).resolve().parent

def test_ok():
    assert validate(json.loads((HERE/"sample_ok.json").read_text())) == []

def test_bad():
    assert validate(json.loads((HERE/"sample_bad.json").read_text()))

def test_cli():
    assert subprocess.run([sys.executable, str(HERE/"search_params.py"), str(HERE/"sample_ok.json")]).returncode == 0

第 3 步:运行

$ search_params
OK
{"q": "what is RAG", "searchMode": "auto", "format": "context", "limit": 5}

INVALID
- q 必填
- searchMode 须为 ['auto', 'balanced', 'deep', 'exhaustive', 'fast', 'low-cost']
- format 须为 ['context', 'json']
- limit 建议 1..50

$ pytest -q
...                                                                      [100%]
3 passed in 0.03s

怎么检查结果?

  • OK 回显 JSON。
  • bad 列出非法字段。

调试示例

写成 search_mode 下划线。 官方参数名是 searchMode(camelCase)。先统一命名再校验。

常见问题

现象 原因 处理
新模式名 改 MODES 对照文档
limit 很大 嘈杂且贵 教程软上限 50
只要校验 不联网 再调 A 篇

模板规则

  • 参数先本地过。
  • 昂贵模式仅必要时用。
  • 查询不含密钥。

项目资源

用途 地址
Quickstart(官方) https://docs.andiai.com/getting-started/quickstart
andiai.com https://andiai.com/
Andi 搜索 https://andisearch.com/

参数干净,credits 才花在刀刃上。