发搜索前校验
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 才花在刀刃上。