Files
pingtai_agent/plans/search_agent_migration_plan.md

15 KiB
Raw Permalink Blame History

Search Agent 迁移计划

将 search_agent/ 项目按照 agent_templates/ 模板结构进行重构

架构变更图

迁移前后目录结构对比

graph LR
    subgraph 迁移前
        A1[search_agent/]
        A1 --> A2[api.py]
        A1 --> A3[config.py]
        A1 --> A4[main.py]
        A1 --> A5[agent/]
        A1 --> A6[models/]
        A1 --> A7[modules/]
        A1 --> A8[tools/]
        A1 --> A9[utils/]
    end
    
    subgraph 迁移后
        B1[search_agent/]
        B1 --> B2[Dockerfile]
        B1 --> B3[run_api_server.py]
        B1 --> B4[src/]
        B4 --> B5[server/]
        B5 --> B6[api_server.py]
        B5 --> B7[mcp_server.py]
        B5 --> B8[core/]
        B8 --> B9[config.py]
        B8 --> B10[agent.py]
        B8 --> B11[modules/]
        B8 --> B12[tools/]
        B8 --> B13[utils/]
    end

API 端点变更

graph TB
    subgraph 原 API
        O1[GET /]
        O2[GET /health]
        O3[POST /search]
        O4[GET /config]
    end
    
    subgraph 新 API
        N1[GET /]
        N2[GET /health]
        N3[POST /mcp]
        N4[GET /mcp/sse]
        N5[POST /mcp/sse]
        N6[POST /api/v1/search]
        N7[POST /api/v1/quick_search]
    end
    
    O1 -.-> N1
    O2 -.-> N2
    O3 -.-> N6
    O4 -.删除.-> X[X]

MCP 工具调用流程

sequenceDiagram
    participant Client
    participant API as api_server.py
    participant MCP as mcp_server.py
    participant Agent as SearchAgent
    participant Tools as External APIs
    
    Client->>API: POST /mcp tools/call search
    API->>MCP: TOOL_MAP search
    MCP->>Agent: agent.search query
    Agent->>Tools: Serper/Jina APIs
    Tools-->>Agent: 搜索结果
    Agent-->>MCP: AgentResponse
    MCP-->>API: JSON result
    API-->>Client: MCP Response

概述

将 search_agent/ 项目按照 agent_templates/ 模板结构进行重构,使其符合统一的 Agent 项目规范。

当前结构 vs 目标结构

当前 search_agent 结构

search_agent/
├── .env                        # 环境变量配置
├── api.py                      # FastAPI 服务(独立文件)
├── config.py                   # 配置管理
├── main.py                     # CLI 入口
├── requirements.txt            # 依赖
├── agent/
│   ├── search_agent.py         # 主 Agent 类
│   └── prompts.py              # Prompt 模板
├── models/
│   └── schemas.py              # 数据模型
├── modules/                    # 7 个功能模块
│   ├── query_analyzer.py
│   ├── search_planner.py
│   ├── search_executor.py
│   ├── content_extractor.py
│   ├── result_processor.py
│   ├── answer_generator.py
│   └── reflector.py
├── tools/                      # 外部 API 封装
│   ├── serper.py
│   ├── jina_reader.py
│   └── jina_reranker.py
└── utils/
    ├── llm_client.py
    └── helpers.py

目标结构(按模板)

search_agent/
├── Dockerfile                  # 新增:Docker 配置
├── README.md                   # 更新:按模板格式
├── requirements.txt            # 更新:添加 pydantic-ai, mcp, fastmcp
├── run_api_server.py           # 新增:统一启动脚本
└── src/
    ├── __init__.py             # 新增
    └── server/
        ├── __init__.py         # 新增
        ├── api_server.py       # 重构:按模板格式
        └── mcp_server.py       # 新增:MCP 工具定义
        └── core/               # 新增:业务逻辑目录
            ├── __init__.py
            ├── config.py       # 移动:配置管理
            ├── agent.py        # 移动:SearchAgent 类
            ├── prompts.py      # 移动:Prompt 模板
            ├── schemas.py      # 移动:数据模型
            ├── modules/        # 移动:功能模块
            │   ├── __init__.py
            │   ├── query_analyzer.py
            │   ├── search_planner.py
            │   ├── search_executor.py
            │   ├── content_extractor.py
            │   ├── result_processor.py
            │   ├── answer_generator.py
            │   └── reflector.py
            ├── tools/          # 移动:外部 API 封装
            │   ├── __init__.py
            │   ├── serper.py
            │   ├── jina_reader.py
            │   └── jina_reranker.py
            └── utils/          # 移动:工具函数
                ├── __init__.py
                ├── llm_client.py
                └── helpers.py

主要变更点

1. 项目结构变更

变更类型 原路径 新路径
新增 - Dockerfile
新增 - run_api_server.py
新增 - src/__init__.py
新增 - src/server/__init__.py
重构 api.py src/server/api_server.py
新增 - src/server/mcp_server.py
移动 config.py src/server/core/config.py
移动 agent/search_agent.py src/server/core/agent.py
移动 agent/prompts.py src/server/core/prompts.py
移动 models/schemas.py src/server/core/schemas.py
移动 modules/* src/server/core/modules/*
移动 tools/* src/server/core/tools/*
移动 utils/* src/server/core/utils/*
删除 main.py - (功能合并到 api_server)
删除 .env - (环境变量由外部提供)
删除 多个 README 文件 合并为一个 README.md

2. 依赖变更

新增依赖(参考 agent_templates/requirements.txt):

pydantic-ai>=0.0.14
mcp>=0.9.0
fastmcp>=0.1.0

保留依赖:

aiohttp>=3.9.0
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
pydantic>=2.5.0
python-dotenv>=1.0.0
loguru>=0.7.0

可移除依赖:

requests>=2.31.0        # 改用 aiohttp
orjson>=3.9.0           # 可选
typing-extensions>=4.9.0 # Python 3.12 内置
asyncio-throttle>=1.0.2  # 未使用

3. 配置变更

原配置方式(config.py):

  • 使用 dataclass 定义 Config 类
  • 从 .env 文件加载配置
  • 包含 LLM、Serper、Jina 等多个 API 配置

新配置方式(按模板):

  • 使用环境变量直接读取
  • 主要配置项:
    • OPENAI_BASE_URL / LLM_BASE_URL:LiteLLM Gateway URL
    • OPENAI_API_KEY:API Key(运行时传入)
    • MODEL_NAME / LITELLM_MODEL:模型名称
    • SERPER_API_KEY:Serper API Key
    • JINA_API_KEY:Jina API Key
    • API_PORT:服务端口

4. API 变更

原 API 端点:

  • GET / - 健康检查
  • GET /health - 详细健康检查
  • POST /search - 执行搜索
  • GET /config - 获取配置

新 API 端点(按模板):

  • GET / - 服务状态
  • GET /health - 健康检查
  • POST /mcp - MCP HTTP 端点
  • GET /mcp/sse - MCP SSE 端点
  • POST /mcp/sse - MCP SSE POST 端点
  • POST /api/v1/search - 业务 API(搜索)
  • POST /api/v1/quick_search - 业务 API(快速搜索)

5. MCP 工具定义

新增 mcp_server.py,定义以下 MCP 工具:

@server.tool()
async def search(query: str, max_iterations: int = 3) -> str:
    """
    执行智能搜索
    
    Args:
        query: 搜索查询问题
        max_iterations: 最大迭代次数(1-10)
    
    Returns:
        JSON 格式的搜索结果
    """

@server.tool()
async def quick_search(query: str) -> str:
    """
    快速搜索(单次迭代)
    
    Args:
        query: 搜索查询问题
    
    Returns:
        JSON 格式的搜索结果
    """

迁移任务清单

Phase 1: 创建基础结构

  • 1.1 创建 src/ 目录结构
  • 1.2 创建 src/__init__.py
  • 1.3 创建 src/server/__init__.py
  • 1.4 创建 src/server/core/ 目录结构

Phase 2: 迁移核心业务代码

  • 2.1 迁移 config.py → src/server/core/config.py

    • 更新导入路径
    • 适配新的环境变量命名
  • 2.2 迁移 models/schemas.py → src/server/core/schemas.py

    • 更新导入路径
  • 2.3 迁移 agent/prompts.py → src/server/core/prompts.py

    • 更新导入路径
  • 2.4 迁移 utils/ → src/server/core/utils/

    • 更新 llm_client.py 导入路径
    • 更新 helpers.py 导入路径
  • 2.5 迁移 tools/ → src/server/core/tools/

    • 更新 serper.py 导入路径
    • 更新 jina_reader.py 导入路径
    • 更新 jina_reranker.py 导入路径
  • 2.6 迁移 modules/ → src/server/core/modules/

    • 更新所有模块的导入路径
  • 2.7 迁移 agent/search_agent.py → src/server/core/agent.py

    • 更新导入路径

Phase 3: 创建新的服务器文件

  • 3.1 创建 src/server/mcp_server.py

    • 定义 search 工具
    • 定义 quick_search 工具
    • 导出 TOOL_MAP 和 TOOL_LIST
  • 3.2 创建 src/server/api_server.py

    • 按模板格式重构
    • 添加 MCP 端点
    • 添加业务 API 端点
    • 移除原有的 LogCollector 和 AgentWrapper(简化)

Phase 4: 创建项目配置文件

  • 4.1 创建 Dockerfile

    • 基于 agent_templates/Dockerfile
  • 4.2 创建 run_api_server.py

    • 基于 agent_templates/run_api_server.py
  • 4.3 更新 requirements.txt

    • 添加 pydantic-ai, mcp, fastmcp
    • 移除不需要的依赖
  • 4.4 更新 README.md

    • 按模板格式重写

Phase 5: 清理和测试

  • 5.1 删除旧文件

    • api.py
    • main.py
    • config.py(根目录)
    • agent/ 目录
    • models/ 目录
    • modules/ 目录
    • tools/ 目录
    • utils/ 目录
    • 多余的 README 文件
  • 5.2 测试服务启动

    • python run_api_server.py
  • 5.3 测试 API 端点

    • 健康检查
    • MCP 端点
    • 搜索 API

关键代码变更示例

mcp_server.py 核心代码

"""Search Agent MCP 服务器"""
import os
import json
from typing import Optional
from mcp.server.fastmcp import FastMCP

from .core.config import Config
from .core.agent import SearchAgent

# 配置
_BASE_URL = os.getenv('OPENAI_BASE_URL', 
    os.getenv('LLM_BASE_URL', 'https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/v1'))
_API_KEY = os.getenv('OPENAI_API_KEY', 'sk')

os.environ.setdefault('OPENAI_API_KEY', _API_KEY)
os.environ.setdefault('OPENAI_BASE_URL', _BASE_URL)

server = FastMCP('Search Agent')

SYSTEM_PROMPT = '''你是一个智能搜索助手。
能够理解用户查询意图、自动规划搜索策略、从多个来源获取信息,
并生成高质量、有来源引用的答案。'''

# 全局 Agent 实例
_agent: Optional[SearchAgent] = None

def get_agent() -> SearchAgent:
    """获取或创建 Agent 实例"""
    global _agent
    if _agent is None:
        config = Config.from_env()
        _agent = SearchAgent(config)
    return _agent

@server.tool()
async def search(
    query: str,
    max_iterations: int = 3
) -> str:
    """
    执行智能搜索
    
    Args:
        query: 搜索查询问题
        max_iterations: 最大迭代次数(1-10)
    
    Returns:
        JSON 格式的搜索结果
    """
    try:
        agent = get_agent()
        # 临时修改迭代次数
        original = agent.config.max_iterations
        agent.config.max_iterations = min(max(1, max_iterations), 10)
        
        try:
            response = await agent.search(query)
        finally:
            agent.config.max_iterations = original
        
        return json.dumps({
            "success": True,
            "answer": response.answer.to_dict(),
            "statistics": {
                "iterations": response.iterations,
                "total_sources_consulted": response.total_sources_consulted,
                "search_queries_used": response.search_queries_used
            }
        }, ensure_ascii=False, indent=2)
        
    except Exception as e:
        return json.dumps({
            "success": False,
            "error": str(e)
        }, ensure_ascii=False)

@server.tool()
async def quick_search(query: str) -> str:
    """
    快速搜索(单次迭代)
    
    Args:
        query: 搜索查询问题
    
    Returns:
        JSON 格式的搜索结果
    """
    try:
        agent = get_agent()
        answer = await agent.quick_search(query)
        
        return json.dumps({
            "success": True,
            "answer": answer.to_dict()
        }, ensure_ascii=False, indent=2)
        
    except Exception as e:
        return json.dumps({
            "success": False,
            "error": str(e)
        }, ensure_ascii=False)

TOOL_MAP = {
    'search': search,
    'quick_search': quick_search,
}

TOOL_LIST = [
    {
        "name": "search",
        "description": "执行智能搜索,支持多轮迭代和自我反思",
        "inputSchema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "搜索查询问题"},
                "max_iterations": {"type": "integer", "description": "最大迭代次数", "default": 3}
            },
            "required": ["query"]
        }
    },
    {
        "name": "quick_search",
        "description": "快速搜索,单次迭代,适合简单问题",
        "inputSchema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "搜索查询问题"}
            },
            "required": ["query"]
        }
    }
]

导入路径变更对照表

原导入 新导入
from config import Config from .core.config import Config
from models.schemas import ... from .core.schemas import ...
from agent.search_agent import SearchAgent from .core.agent import SearchAgent
from agent.prompts import ... from .core.prompts import ...
from modules.xxx import ... from .core.modules.xxx import ...
from tools.xxx import ... from .core.tools.xxx import ...
from utils.xxx import ... from .core.utils.xxx import ...

环境变量配置

迁移后需要设置的环境变量:

变量名 必需 说明 默认值
OPENAI_BASE_URL 或 LLM_BASE_URL 是 LiteLLM Gateway URL -
OPENAI_API_KEY 是 API Key(运行时传入) sk
MODEL_NAME 或 LITELLM_MODEL 否 模型名称 taiji/gpt-4o-mini
SERPER_API_KEY 是 Serper API Key -
JINA_API_KEY 是 Jina API Key -
API_PORT 否 服务端口 8000
MAX_ITERATIONS 否 默认最大迭代次数 3
MAX_RESULTS_PER_QUERY 否 每次搜索结果数 10
CONTENT_MAX_LENGTH 否 内容最大长度 5000
LOG_LEVEL 否 日志级别 INFO
TIMEOUT 否 请求超时时间 30

注意事项

  1. 保持业务逻辑不变:迁移过程中不修改核心搜索逻辑,只调整项目结构和导入路径

  2. API 兼容性:新增 MCP 端点的同时,保留原有的 /search 端点(改为 /api/v1/search)

  3. 配置兼容:支持原有的环境变量命名,同时支持模板的命名方式

  4. 测试覆盖:迁移后需要测试所有功能模块是否正常工作

  5. 文档更新:合并多个 README 文件为一个统一的文档