# GEO 系统与 AgentKit 联通指南

## 一、AgentKit 是什么

AgentKit 是一个**统一 Agent 开发框架**，核心能力：

| 能力 | 说明 |
|------|------|
| **ReAct 推理引擎** | Think → Act → Observe 循环，LLM 自主选择工具、决定何时输出 |
| **LLM Gateway** | 统一 LLM 调用入口，管理 API Key、模型路由、降级策略、用量统计 |
| **Skill 系统** | YAML 配置定义技能（Prompt + Tool + 质量门禁），无需写代码 |
| **意图路由** | 关键词匹配（零成本）+ LLM 分类（兜底），自动路由到最佳 Skill |
| **产出质量管理** | 必填字段、最低字数、Schema 校验、自定义验证器，不通过自动重试 |
| **标准化输出** | Schema 验证 + 类型归一化 + 元数据附加，所有 Skill 产出格式统一 |
| **记忆系统** | 语义记忆（pgvector）+ 情景记忆（Redis）+ 工作记忆 |
| **MCP 协议** | 支持 Model Context Protocol，可连接外部工具服务器 |
| **CLI 工具** | `agentkit` 命令行，支持 init/serve/task/skill/pair/doctor/usage |
| **独立部署** | FastAPI Server + Docker，业务系统通过 HTTP API 调用 |

**一句话总结**：AgentKit 让你从写 150 行 Agent 代码降为 10-20 行 YAML 配置。

---

## 二、架构关系

```
┌──────────────────────┐     HTTP API      ┌──────────────────────────┐
│    GEO Backend       │ ───────────────→  │   AgentKit Server        │
│    (FastAPI :8000)   │                   │   (FastAPI :8001)        │
│                      │  POST /tasks      │                          │
│  不再 import         │  GET /tasks/{id}  │  Intent Router           │
│  agentkit 内部类     │  GET /skills      │  ReAct Engine            │
│                      │  GET /llm/usage   │  LLM Gateway             │
│  只用 AgentKitClient │                   │  Quality Gate            │
│                      │  ←── callback ─── │  Output Standardizer     │
│  /internal/* API     │  (custom_handler) │  AgentPool + SkillRegistry│
└──────────────────────┘                   └──────────────────────────┘
                                                    │
                                              ┌─────┴─────┐
                                              │  LLM APIs  │
                                              │ (DeepSeek  │
                                              │  OpenAI…)  │
                                              └───────────┘
```

**关键原则**：
- GEO Backend **不 import agentkit 内部类**，只通过 HTTP API 调用
- AgentKit Server **不直接访问 GEO 数据库**，需要 DB 时回调 GEO 的内部 API
- LLM API Key **只在 AgentKit Server 中配置**，GEO 不需要

---

## 三、联通步骤

### Step 1：部署 AgentKit Server

```bash
cd fischer-agentkit

# 初始化配置
agentkit init

# 编辑 .env，填入 LLM API Key
cp .env.example .env
# DEEPSEEK_API_KEY=sk-xxx
# OPENAI_API_KEY=sk-xxx

# 配对 GEO 业务系统
agentkit pair --name geo-backend --skills-dir ./configs/skills
# 输出: API Key = ak_live_xxxxxxxxxxxx

# 启动 Server
agentkit serve --host 0.0.0.0 --port 8001

# 验证
agentkit doctor
```

### Step 2：GEO Backend 配置环境变量

在 GEO 的 `.env` 中添加：

```bash
# AgentKit Server 连接
AGENTKIT_SERVER_URL=http://localhost:8001
AGENTKIT_API_KEY=ak_live_xxxxxxxxxxxx   # Step 1 中 pair 生成的 key
```

### Step 3：改造 GEO 的 agent_framework 适配层

将 `app/agent_framework/adapter.py` 从 import 模式改为 HTTP API 模式：

```python
# app/agent_framework/adapter.py — Mode A 版本
import os
import logging
from agentkit.server.client import AgentKitClient

logger = logging.getLogger(__name__)
_CLIENT: AgentKitClient | None = None

def get_agentkit_client() -> AgentKitClient:
    """获取 AgentKit Server HTTP 客户端"""
    global _CLIENT
    if _CLIENT is None:
        base_url = os.getenv("AGENTKIT_SERVER_URL", "http://localhost:8001")
        api_key = os.getenv("AGENTKIT_API_KEY")
        _CLIENT = AgentKitClient(base_url=base_url, api_key=api_key)
    return _CLIENT

async def submit_task(input_data: dict, skill_name: str | None = None) -> dict:
    """提交任务到 AgentKit Server"""
    client = get_agentkit_client()
    return await client.submit_task(input_data=input_data, skill_name=skill_name)

async def get_task_status(task_id: str) -> dict:
    """查询任务状态"""
    client = get_agentkit_client()
    return await client.get_task_status(task_id)

async def get_llm_usage(agent_name: str | None = None) -> dict:
    """查询 LLM 用量"""
    client = get_agentkit_client()
    return await client.get_usage(agent_name=agent_name)
```

### Step 4：改造业务调用

**内容生成**（原来 3 次 dispatch → 1 次 submit_task）：

```python
# 改造前
from app.agent_framework.dispatcher import TaskDispatcher
dispatcher = TaskDispatcher(settings.REDIS_URL)
task = TaskMessage(agent_name="content_generator", ...)
result = await dispatcher.dispatch(task, ...)

# 改造后
from app.agent_framework.adapter import submit_task
result = await submit_task(
    input_data={"target_keyword": keyword, "brand_name": brand, ...},
    skill_name="content_generator",
)
content = result["data"]["content"]
```

**引用检测**：

```python
# 改造前
from app.agent_framework.agents import CitationDetectorAgent
agent = CitationDetectorAgent()
result = await agent.execute(task)

# 改造后
from app.agent_framework.adapter import submit_task
result = await submit_task(
    input_data={"keyword": keyword, "platform": platform, ...},
    skill_name="citation_detector",
)
```

### Step 5：新增内部 API（供 AgentKit Server 回调）

custom_handler 需要 DB 访问时，AgentKit Server 通过 HTTP 回调 GEO：

```python
# app/api/internal.py
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db

router = APIRouter(prefix="/internal", tags=["internal"])

@router.post("/citation/detect")
async def citation_detect(input_data: dict, db: AsyncSession = Depends(get_db)):
    """供 AgentKit Server 的 citation_handler 回调"""
    from app.services.citation.citation import CitationService
    service = CitationService()
    return await service.detect_full(input_data, db=db)

@router.post("/knowledge/search")
async def knowledge_search(input_data: dict, db: AsyncSession = Depends(get_db)):
    """供 AgentKit Server 的 retrieve_knowledge Tool 回调"""
    from app.services.knowledge.rag_service import RAGService
    service = RAGService()
    results = await service.search(session=db, query=input_data["query"])
    return {"results": results}
```

### Step 6：Docker Compose 联合部署

```yaml
# docker-compose.yml
version: "3.8"
services:
  geo-backend:
    build: ./geo/backend
    ports: ["8000:8000"]
    environment:
      - AGENTKIT_SERVER_URL=http://agentkit-server:8001
      - AGENTKIT_API_KEY=${AGENTKIT_API_KEY}
    depends_on:
      - agentkit-server

  agentkit-server:
    build: ./fischer-agentkit
    command: serve --host 0.0.0.0 --port 8001
    ports: ["8001:8001"]
    env_file: ./fischer-agentkit/.env
    environment:
      - GEO_BACKEND_URL=http://geo-backend:8000
    depends_on:
      - redis
      - postgres

  redis:
    image: redis:7-alpine

  postgres:
    image: pgvector/pgvector:pg15
    environment:
      POSTGRES_USER: agentkit
      POSTGRES_PASSWORD: agentkit
      POSTGRES_DB: agentkit
```

---

## 四、GEO 当前 8 个 Skill 映射

| 原 Agent 名 | Skill 名 | 模式 | 改造要点 |
|-------------|---------|------|---------|
| citation_detector | citation_detector | custom | handler 回调 GEO `/internal/citation/detect` |
| monitor | monitor | custom | handler 回调 GEO `/internal/monitor/check` |
| schema_advisor | schema_advisor | custom | handler 回调 GEO `/internal/schema/advise` |
| content_generator | content_generator | llm_generate | 直接迁移 YAML，添加 intent + quality_gate |
| deai_agent | deai_agent | llm_generate | 直接迁移 YAML |
| geo_optimizer | geo_optimizer | llm_generate | 直接迁移 YAML |
| competitor_analyzer | competitor_analyzer | tool_call | Tool 迁移到 AgentKit Server |
| trend_agent | trend_agent | tool_call | Tool 迁移到 AgentKit Server |

**YAML 零修改**：现有 8 个 YAML 配置无需修改即可被 AgentKit 加载（SkillConfig 向后兼容 AgentConfig）。建议为 llm_generate 模式的 Skill 添加 `intent` 和 `quality_gate` 字段以启用新能力。

---

## 五、API 参考

### AgentKit Server REST API

| 路径 | 方法 | 说明 |
|------|------|------|
| `POST /api/v1/tasks` | POST | 提交任务（支持意图路由自动匹配 Skill） |
| `GET /api/v1/tasks/{id}` | GET | 查询任务状态和结果 |
| `GET /api/v1/tasks` | GET | 列出任务 |
| `DELETE /api/v1/tasks/{id}` | DELETE | 取消任务 |
| `POST /api/v1/agents` | POST | 创建 Agent 实例 |
| `GET /api/v1/agents` | GET | 列出 Agent 实例 |
| `POST /api/v1/skills` | POST | 注册 Skill |
| `GET /api/v1/skills` | GET | 列出已注册 Skill |
| `GET /api/v1/llm/usage` | GET | 查询 LLM 用量统计 |
| `GET /api/v1/health` | GET | 健康检查 |

### 认证

所有 API 请求需携带 Header：

```
X-API-Key: ak_live_xxxxxxxxxxxx
```

### 提交任务示例

```bash
# 指定 Skill
curl -X POST http://localhost:8001/api/v1/tasks \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_xxxxxxxxxxxx" \
  -d '{
    "skill_name": "content_generator",
    "input_data": {"target_keyword": "AI", "brand_name": "BrandX"}
  }'

# 意图路由自动匹配
curl -X POST http://localhost:8001/api/v1/tasks \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ak_live_xxxxxxxxxxxx" \
  -d '{
    "input_data": {"query": "帮我生成一篇关于AI的文章"}
  }'
```

### Python SDK

```python
from agentkit.server.client import AgentKitClient

client = AgentKitClient(
    base_url="http://localhost:8001",
    api_key="ak_live_xxxxxxxxxxxx",
)

# 提交任务
result = await client.submit_task(
    skill_name="content_generator",
    input_data={"target_keyword": "AI", "brand_name": "BrandX"},
)

# 查询用量
usage = await client.get_usage()
```

---

## 六、CLI 速查

```bash
agentkit init                    # 初始化项目配置
agentkit serve --port 8001       # 启动 Server
agentkit doctor                  # 诊断健康状态
agentkit version                 # 查看版本

agentkit pair --name geo-backend # 配对业务系统，生成 API Key
agentkit pair --list             # 查看已配对客户端
agentkit pair --revoke geo-backend  # 撤销配对

agentkit task submit --skill content_generator --input '{"topic":"AI"}' --server-url http://localhost:8001
agentkit task status <task_id> --server-url http://localhost:8001
agentkit task list --server-url http://localhost:8001

agentkit skill list --server-url http://localhost:8001
agentkit skill load ./my_skill.yaml
agentkit skill info content_generator --server-url http://localhost:8001

agentkit usage --server-url http://localhost:8001
```

---

## 七、迁移检查清单

### Phase 1：AgentKit Server 部署
- [ ] `agentkit init` 生成配置
- [ ] `.env` 填入 LLM API Key
- [ ] `agentkit pair --name geo-backend` 生成 API Key
- [ ] 8 个 YAML 配置复制到 `configs/skills/`
- [ ] 14 个 FunctionTool 迁移到 `configs/geo_tools.py`
- [ ] 3 个 custom_handler 迁移到 `configs/geo_handlers.py`
- [ ] `agentkit serve` 启动成功
- [ ] `agentkit doctor` 健康检查通过

### Phase 2：GEO Backend 改造
- [ ] `.env` 添加 `AGENTKIT_SERVER_URL` + `AGENTKIT_API_KEY`
- [ ] `adapter.py` 改为 HTTP API 模式
- [ ] `content_generation_service.py` 改用 `submit_task()`
- [ ] `citation.py` 改用 `submit_task()`
- [ ] `scheduler.py` 改用 `submit_task()`
- [ ] 新增 `/internal/*` API 路由
- [ ] 端到端测试通过

### Phase 3：清理
- [ ] 删除旧框架文件（base.py, dispatcher.py, registry.py 等）
- [ ] 删除旧 Agent 类
- [ ] 更新 `__init__.py` 导出
- [ ] 全量回归测试

---

## 八、配置优先级

```
客户端自定义配置（pair 时 --skills-dir 指定）
        ↓ 覆盖
init 默认配置（agentkit.yaml）
        ↓ 覆盖
硬编码默认值
```

业务系统可以通过 `agentkit pair --name geo-backend --skills-dir ./custom_skills` 指定自己的 Skill 目录，优先级高于 AgentKit Server 的默认配置。
