xenm/map-me-search
GitHub: xenm/map-me-search
基于 Google ADK 多 Agent Pipeline 的 AI 地点推荐系统,同时提供了一套在公开源码条件下跨多平台零信任安全部署的完整参考架构。
Stars: 0 | Forks: 1
# MapMe 搜索
[](https://www.a2as.org/certified/agents/xenm/map-me-search?utm_source=github&utm_medium=pull_request)
[](https://github.com/xenm/map-me-search/actions/workflows/deploy-agent-api.yaml)
[](https://github.com/xenm/map-me-search/actions/workflows/deploy-hf-app.yaml)
基于 AI 的地点推荐系统,在 Google ADK 上采用多 Agent Pipeline 构建。您只需提供一个城市和您的兴趣,三个专门的 Agent——research、filter 和 format——将按顺序工作,返回排序后的推荐结果。
值得注意的工程挑战是:源代码完全公开,前端运行在第三方平台 (Hugging Face) 上,而后端持有 GCP 凭据。在整个构建过程中确保没有任何 Secret 泄露到 GitHub 上,这是最有趣的部分。
## 系统架构
```
flowchart LR
B([Browser]) -->|Turnstile token| HF
subgraph HF["Hugging Face Space"]
UI[Gradio UI\nthin relay only]
end
HF -->|POST /search\nX-Proxy-Auth header| CR
subgraph CR["Google Cloud Run"]
API[FastAPI + ADK pipeline]
API -->|read secrets| SM[(Secret Manager)]
API -->|preferences| DB[(PostgreSQL)]
API -->|verify token| CF[Cloudflare\nTurnstile API]
API -->|search| GS[Google Search]
API -->|LLM| GM[Gemini 2.5 Flash]
end
CR -->|result JSON| HF
```
### Agent Pipeline
三个 Agent 顺序运行。每个 Agent 的输出键是下一个 Agent 的输入上下文。
```
sequenceDiagram
participant R as ResearchAgent
participant F as FilterAgent
participant C as CalculationAgent
participant Fm as FormatterAgent
R->>R: google_search (5-7 places)
R-->>F: research_findings
F->>F: calculate_distance_score()
F->>F: get_place_category_boost()
F->>C: score data
C->>C: execute Python scoring code
C-->>F: calculation_results
F-->>Fm: filtered_results (top 5)
Fm-->>Fm: format recommendations
```
## 安全机制
该架构假设源代码是公开的,并将每个边界视为不受信任的。
| 边界 | 机制 |
|----------|-----------|
| 浏览器 → HF Space | Cloudflare Turnstile 验证用户为真人 |
| HF Space → Cloud Run | `X-Proxy-Auth` 共享密钥,采用恒定时间比较 |
| Cloud Run → Cloudflare | 服务端 Turnstile 验证 — Token 为一次性且具有时间限制 |
| GitHub Actions → GCP | Workload Identity Federation + OIDC — 无需任何 JSON 密钥文件 |
| Cloud Run → Secret Manager | 运行时 Service Account 仅对其自身的 Secret 拥有 `secretAccessor` 权限 |
**核心特性:**
- **GitHub 中零 GCP Secret** — 部署 Job 使用 OIDC 联合身份验证;所有运行时 Secret 存放于 Secret Manager,并在部署时注入
- **最小权限 Service Account** — `deploy@` 可以推送镜像并部署一个服务;`run@` 可以读取其自身的 Secret;两者均无项目级别的角色
- **不可变的容器镜像** — 采用 SHA 标签,Artifact Registry 仓库设置了 `--immutable-tags`;一旦推送,标签就无法被覆盖
- **非 Root 容器** — `Dockerfile` 创建并使用 `appuser` 运行
- **最小的前端爆炸半径** — HF Space 仅安装 `gradio`、`httpx`、`python-dotenv`;无 GCP SDK,无 Agent 代码;遭到入侵的 Space 无法访问 Google API
- **默认失败关闭** — 缺少 `PROXY_AUTH_TOKEN` 或 `TURNSTILE_SECRET_KEY` → HTTP 500,绝不回退至开放状态
- **默认拒绝的工作流** — 所有工作流中包含顶级 `permissions: {}`;仅部署 Job 获取 `id-token: write` 权限
- **SHA 绑定的 Actions** — 所有第三方 Actions 均绑定至 Commit SHA;由 Dependabot 监控更新
## 主题偏好持久化
在单个请求期间,所有会话状态均存储在内存中。唯一写入 PostgreSQL 的内容是每个指定主题积累的用户偏好。
- **带有主题** → 在 LLM 调用之前,会从 `topic_preferences` 中读取该主题的历史偏好,并将其作为偏好上下文注入到 ResearchAgent 提示词中。成功响应后,新的偏好将作为要点追加。每第 10 次更新会触发一次 LLM 总结过程,合并重复项并精简列表,仅保留最具体和最有用的偏好。
- **不带主题** → 完全匿名;不从数据库读取或写入任何内容。
该表包含三列:`topic`(主键)、`preferences`(积累的要点)和 `version`(整数,每次更新时递增)。
`DATABASE_URL` 是**必需的** — 没有 SQLite 或内存回退机制。对于本地开发,代码库根目录下的 `docker-compose.yml` 会启动一个 `postgres:16-alpine` 容器,该容器与 `agent/.env.example` 中提供的默认 `DATABASE_URL` 相匹配。如果在请求时数据库无法连接,搜索仍会返回带有空白历史偏好上下文的响应,并通过 `logger.exception` 记录失败信息。
## CI/CD
```
flowchart LR
PR[Pull request / push to main] --> CI
CI -->|lint + unit + integration tests| Gate{passed?}
Gate -->|yes| DA[deploy-agent-api\nCloud Run]
Gate -->|yes| DH[deploy-hf-app\nHugging Face]
Gate -->|no| Blocked[✗ blocked]
```
| 工作流 | 触发条件 | 功能描述 |
|----------|---------|--------------|
| `ci.yaml` | PR + 推送至 main 分支 | Ruff 代码检查、单元测试、集成测试 |
| `deploy-agent-api.yaml` | main 分支 CI 通过 | 构建 Docker 镜像 → 推送至 Artifact Registry → 部署至 Cloud Run → 对 `/health` 进行冒烟测试 |
| `deploy-hf-app.yaml` | main 分支 CI 通过 | 通过 Git 推送 `frontend/` 至 HF Space |
## 快速开始
有关完整的本地设置,请参阅 [docs/QUICKSTART.md](docs/QUICKSTART.md)。
```
# Agent API
cp agent/.env.example agent/.env # set GOOGLE_API_KEY
uvicorn agent.agent_api:app --port 8080
# Frontend(第二个终端)
cp frontend/.env.example frontend/.env
python frontend/hf_app.py
```
打开 `http://localhost:7860`。
## 代码库结构
```
├── agent/
│ ├── agent_api.py # FastAPI app — Cloud Run entry point
│ ├── requirements.txt
│ ├── .env.example
│ └── utils/
│ ├── places_agent_core.py # Multi-agent pipeline (agents, runner, retry)
│ ├── topic_preferences.py # topic_preferences table — read/write/summarise
│ └── scoring_tools.py # Distance / category scoring tools
├── frontend/
│ ├── hf_app.py # Gradio relay — HF Space entry point
│ ├── requirements.txt
│ └── .env.example
├── tests/
│ ├── test_api.py # Security layer unit tests
│ ├── test_integration.py # Frontend → API integration tests
│ ├── test_persistence.py # topic_preferences CRUD + summarisation (testcontainers)
│ ├── test_tools.py # Scoring tool unit tests
│ └── requirements-test.txt
├── docs/
│ ├── QUICKSTART.md
│ └── SECRETS.md # Secrets reference for all three platforms
├── .github/
│ └── workflows/
│ ├── ci.yaml
│ ├── deploy-agent-api.yaml
│ └── deploy-hf-app.yaml
├── Dockerfile # python:3.14-slim, non-root appuser
└── SECURITY.md
```
## 技术栈
| 层级 | 技术 |
|-------|-----------|
| AI 框架 | Google Agent Development Kit (ADK) |
| LLM | Gemini 2.5 Flash + 遇到 503/429 时回退至 Lite |
| API | FastAPI + Uvicorn |
| 前端 | Gradio |
| 语言 | Python 3.14 |
| 容器 | Docker (`python:3.14-slim`, 非 Root) |
| 偏好数据库 | PostgreSQL via `asyncpg` (本地使用 Docker,生产环境使用 Cloud SQL) |
| CI/CD | GitHub Actions (SHA 绑定, WIF 身份验证) |
| Secrets | Google Secret Manager |
| 仓库 | Artifact Registry (不可变标签, 漏洞扫描) |
| 机器人防护 | Cloudflare Turnstile |
| 测试 | pytest + testcontainers |
## 测试
```
# Unit + API 安全测试(无外部服务)
python3 -m pytest tests/ -v -k "not integration"
# 完整套件包括 PostgreSQL 持久化(需要 Docker)
pip install -r tests/requirements-test.txt
python3 -m pytest tests/ -v
```
## Secrets 参考
有关 GitHub、Google Cloud 和 Hugging Face 之间各 Secret 配置位置的详细说明,请参阅 [docs/SECRETS.md](docs/SECRETS.md)。
## 开源许可证
有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
**使用 [Google ADK](https://ai.google.dev/adk)、[FastAPI](https://fastapi.tiangolo.com) 和 [Gradio](https://gradio.app) 构建**
标签:ADK, AI推荐, API部署, AV绕过, Cloudflare Turnstile, DLL 劫持, DNS解析, FastAPI, GCP凭证管理, Gemini, GitHub Actions, Google Cloud Run, Google Search, Gradio, Hugging Face Spaces, PostgreSQL, PyRIT, Python, Secret Manager, 云计算, 人机验证, 前后端分离, 地点推荐, 城市探索, 多智能体系统, 大语言模型, 安全架构, 安全认证, 开源项目, 微服务架构, 推荐系统, 搜索引擎, 数据库, 旅游推荐, 无后门, 智能体开发套件, 测试用例, 特权提升, 自动化部署, 自动笔记, 规则引擎, 请求拦截, 逆向工具, 零泄露