Files
aisou/README.md
T

5.4 KiB
Raw Blame History

AI Search Agent

独立实现的 AI 搜索 Agent,不复用仓库里原有的 search_agent。
这个版本按“较完整的最佳实践骨架”组织,不是最小脚本:

  1. 用 s.jina.ai 做网页搜索(不依赖 Bing DOM)
  2. 用 r.jina.ai 并发深读搜索结果正文
  3. 支持多轮搜索规划与反思(自动改写下一轮查询)
  4. 用可切换的 LLM 生成结构化回答
  5. 暴露 CLI、FastAPI 和 Azure Functions 三种入口
  6. 支持 SSE 流式事件输出

目录

ai_search_agent/
├── ai_search_agent/
│   ├── agent.py
│   ├── api.py
│   ├── config.py
│   ├── jina.py
│   ├── llm_client.py
│   ├── models.py
│   ├── parsers.py
│   ├── prompts.py
│   └── __init__.py
├── .env.example
├── tests/
│   └── test_parsers.py
├── main.py
├── README.md
├── serve.py
└── requirements.txt

环境变量

export JINA_API_KEY=your-jina-key
export LLM_API_KEY=your-llm-key
export LLM_API_STYLE=openai_chat
export LLM_ENDPOINT=https://dashscope-intl.aliyuncs.com/compatible-mode/v1
export MODEL_NAME=qwen3.5-flash
export SEARCH_PROVIDER=jina_search
export JINA_SEARCH_URL=https://s.jina.ai/
export TOP_K_PAGES=5
export MAX_PAGE_CHARS=5000
export MAX_CONCURRENCY=5
export MAX_SEARCH_ROUNDS=2
export SEARCH_TIMEOUT=20
export READER_TIMEOUT=25
export MODEL_TIMEOUT=90
export RETRY_ATTEMPTS=2
export AUDIT_LOG_PATH=logs/audit.jsonl

如果切回 xAI:

export JINA_API_KEY=your-jina-key
export LLM_API_KEY=your-xai-key
export LLM_API_STYLE=xai_responses
export MODEL_NAME=grok-4.20-multi-agent-0309

安装

cd ai_search_agent
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

运行

python main.py "PydanticAI 适合哪些场景?"

输出 JSON:

python main.py "PydanticAI 适合哪些场景?" --json

启动 API 服务

uvicorn serve:app --host 0.0.0.0 --port 8080

请求示例:

curl -X POST http://127.0.0.1:8080/search \
  -H "Content-Type: application/json" \
  -d '{"query":"PydanticAI 适合哪些场景?","top_k_pages":4}'

SSE 流式接口:

```bash
curl -N -X POST http://127.0.0.1:8080/search/stream \
  -H "Content-Type: application/json" \
  -d '{"query":"PydanticAI 适合哪些场景?","top_k_pages":4}'

事件类型示例:

  • round_started
  • round_finished
  • llm_started
  • result
  • audit

Azure Functions 部署(aisousuo)

1. 准备 Azure Function App

az login
az account set --subscription "<your-subscription-id-or-name>"

# 若资源组不存在
az group create -n <resource-group> -l eastasia

# 创建 Linux Consumption Function App(Python)
az storage account create -n <storage-account> -g <resource-group> -l eastasia --sku Standard_LRS
az functionapp create \
  -g <resource-group> \
  -n aisousuo \
  --storage-account <storage-account> \
  --consumption-plan-location eastasia \
  --runtime python \
  --runtime-version 3.11 \
  --functions-version 4 \
  --os-type Linux

2. 配置应用设置

az functionapp config appsettings set \
  -g <resource-group> \
  -n aisousuo \
  --settings \
  JINA_API_KEY="<your-jina-key>" \
  LLM_API_KEY="<your-llm-key>" \
  LLM_API_STYLE="openai_chat" \
  LLM_ENDPOINT="https://dashscope-intl.aliyuncs.com/compatible-mode/v1" \
  MODEL_NAME="qwen3.5-flash" \
  SEARCH_PROVIDER="jina_search" \
  JINA_SEARCH_URL="https://s.jina.ai/" \
  TOP_K_PAGES="5" \
  MAX_PAGE_CHARS="5000" \
  MAX_CONCURRENCY="5" \
  MAX_SEARCH_ROUNDS="2" \
  SEARCH_TIMEOUT="20" \
  READER_TIMEOUT="25" \
  MODEL_TIMEOUT="90" \
  RETRY_ATTEMPTS="2" \
  AUDIT_LOG_PATH="/tmp/audit.jsonl"

3. 发布

func azure functionapp publish aisousuo --python

4. 验证

curl https://aisousuo.azurewebsites.net/api/health
curl -X POST https://aisousuo.azurewebsites.net/api/search \
  -H "Content-Type: application/json" \
  -d '{"query":"PydanticAI 适合哪些场景?"}'

## 设计说明

- `SearchClient.search()` 固定走 `s.jina.ai`,通过 `X-Respond-With: no-content` 获取搜索结果文本
- `JinaClient.read_pages()` 负责通过 `r.jina.ai` 并发抓取页面内容,并带重试
- `AISearchAgent.run_stream()` 提供流式事件;`run()` 兼容一次性返回
- 支持多轮搜索规划和反思,证据不足时自动改写下一轮查询
- `LLMClient.answer()` 支持 `xai_responses` 和 `openai_chat` 两种模式
- 每次请求都会生成 `audit_id`,并把审计记录落到 `logs/audit.jsonl`
- 模型输出约束为 JSON 形状,解析失败时退化为纯文本答案
- `AISearchAgent.run()` 统一编排搜索、抓取、归纳和来源回填
- `create_app()` 复用同一套业务链路,不重复实现 API 逻辑

## 返回结构

```json
{
  "query": "PydanticAI 适合哪些场景?",
  "answer": {
    "summary": "...",
    "key_points": ["..."],
    "caveats": ["..."],
    "citations": [{"title": "...", "url": "https://..."}]
  },
  "search_rounds": [
    {
      "round_index": 1,
      "query": "...",
      "result_count": 10,
      "fetched_page_count": 8,
      "usable_page_count": 5,
      "reflection": "..."
    }
  ],
  "search_results": [],
  "pages": []
}

当前边界

  • 目前多轮规划使用规则策略,不是独立 Planner 模型
  • 流式接口是事件级流式(非 token 级模型流式)
  • 大查询下“读取全部搜索结果”会增加耗时和成本