Skip to main content
Glama
README.md
# 星系形态学 MCP 工具

一个用于星系形态学分析的 MCP (Model Context Protocol) 服务器,封装了 GALFIT 和 GalfitS 工具,支持单波段和多波段星系图像拟合与分析。同时提供基于 FastAPI + Celery 的 HTTP 服务接口,支持异步任务提交。

## 功能特性

### 核心工具

| 工具名称 | 功能描述 | 可用条件 |
|---------|---------|---------|
| `run_galfit` | 执行 GALFIT 单波段拟合,返回优化的 FITS 文件、对比图像和拟合摘要 | 需设置 `GALFIT_BIN` |
| `run_galfits` | 执行 GalfitS 多波段同时拟合,返回摘要文件、图像、SED 模型等结果 | 需设置 `GALFITS_BIN` |
| `view_original_image` | 分析原始星系图像,提取形态分类和结构组件信息 | 要求提供2 panel图 |
| `component_analysis` | 分析拟合残差图像,诊断缺失或配置不当的物理组件(bulge、disk、bar、AGN 等);多轮迭代中维护"最优轮次"登记并做轮间对比 | 始终可用 |

### 输出说明

**GALFIT 输出:**
- `optimized_fits_file`: 包含原始数据、模型和残差的 FITS 文件
- `image_file`: 2×3 科学对比图(行0:低/高动态范围原图 \| 模型;行1:全场残差/σ \| 残差放大 \| 1D 表面亮度剖面)
- `summary_file`: Markdown 格式的拟合参数摘要

**GalfitS 输出:**
- `summary_files`: `.gssummary` 拟合摘要文件
- `imagefit_pngs`: 多波段图像拟合对比图
- `sedmodel_pngs`: SED (光谱能量分布) 模型图
- `result_fits`: 最佳拟合 FITS 结果文件

### HTTP 服务接口

除 MCP 协议外,还提供基于 FastAPI + Celery 的 HTTP 服务,支持异步拟合任务提交:

- `POST /api/fitting/` — 提交拟合任务(支持 image fitting / pure sed fitting / image sed fitting 三种模式)
- `GET /api/fitting-status/{task_id}` — 查询任务状态
- `GET /health` — MCP 服务健康检查
- `GET /api/tools` — 列出当前可用的 MCP 工具

## 安装

### 环境要求

- Python >= 3.10
- GALFIT(用于单波段拟合,可选)
- GalfitS(用于多波段拟合,可选)

### 通过 pip 安装

```bash
pip install -e .
```

### Docker 部署

```bash
docker-compose up -d
```

服务包含两个容器:
- **fastapi**: Web 服务 (端口 8000),负责任务提交和状态查询
- **celery**: 异步任务 Worker,执行后台拟合计算

## 配置

根据使用场景选择配置方式:

- **本地开发/直接运行**:创建 `.env` 文件(参考 `.env.example`),服务启动时自动加载。
- **MCP 客户端接入(如 Claude Code)**:优先在 `.mcp.json` 的 `env` 字段中配置环境变量,无需 `.env` 文件。

```bash
# LLM API 配置(用于多模态分析)
OPENAI_API_KEY=your_api_key_here
OPENAI_BASE_URL=           # 可选,默认使用官方端点
OPENAI_MODEL=gemini-3-flash-preview  # 推荐 gemini-3-flash-preview(性价比高)

# 分析后端选择:vlm(默认)、cc 或 acp
# vlm: 使用 OpenAI 兼容 API 进行分析(需配置 OPENAI_*)
# cc:  使用 Claude Code Agent SDK 进行分析(需配置 CLAUDECODE_*)
# acp: 使用 Gemini CLI ACP 模式进行分析(默认使用本地已登录会话)
ANALYSIS_MODE=vlm

# Claude Code Agent SDK 配置(ANALYSIS_MODE=cc 时需要)
# cc 模式通过 claude-agent-sdk 调用 Anthropic API
# 如需使用非 Anthropic 模型(如第三方 LLM),可安装 Claude Code Router 作为本地代理:
# https://github.com/musistudio/claude-code-router
CLAUDECODE_API_KEY=your_anthropic_api_key_here
CLAUDECODE_BASE_URL=xxx
CLAUDECODE_MODEL=gemini-3-flash-preview 

# Gemini CLI ACP 模式配置 (ANALYSIS_MODE=acp 时)
# 默认使用本地通过 `gemini login` 建立的会话。
# 如在 CI 等无登录环境,可配置 GEMINI_API_KEY。
# GEMINI_API_KEY=your_google_api_key_here
# GEMINI_MODEL=gemini-2.0-flash

# GALFIT 配置
GALFIT_BIN=/path/to/galfit  # GALFIT 可执行文件路径

# GalfitS 配置
GALFITS_BIN=/path/to/galfits       # GalfitS 命令或 Python 模块路径
GS_DATA_PATH=/path/to/gs_data      # GalfitS 数据目录

# HTTP 服务(可选)
MCP_ALLOWED_HOSTS=*                # 允许的主机,默认允许所有

# visualRAG 残差检索增强(可选,仅 ANALYSIS_MODE=vlm 时生效)
# 留空 VISUALRAG_SERVICE_URL 即关闭(静默降级为无参考样例的单图分析)
VISUALRAG_SERVICE_URL=http://127.0.0.1:8765   # 检索服务地址;空 = 关闭(唯一真正的开启开关)
VISUALRAG_ENABLED=1                # kill-switch,仅 =0 关闭(判据 != "0",故 =false/no/off 不生效,须写 0)
VISUALRAG_TOP_K=5                  # 每个 role(baseline/positive/hard_negative)检索返回上限
VISUALRAG_STRATEGY=both            # 检索策略:both = DINOv2 视觉嵌入 + 参数化特征双特征
VISUALRAG_MIN_SCORE=0.3            # 质量门:服务端丢弃 score < 该值的样例;留空 = 不传,用服务端默认(当前 0.3)
```

## 使用方法

### 外部编排与轮次事件

本工程只提供 MCP 拟合与分析能力,不负责启动外部 Agent。平台侧的
`communication_service` 接收任务、拉起 Codex/Claude,并通过 stdio 挂载本 MCP。
`run_galfit` 和 `run_galfits_*` 的公开参数不包含通信字段。

编排服务可在启动 MCP 时设置任务级 `FIT_ROUND_EVENT_URL`。拟合成功后 tools 会发布标准
`fit_round_finished` 事件;普通 CLI 或独立 MCP 未配置该变量时自动使用空发布器,不产生网络请求。

### 启动 MCP 服务器

**STDIO 模式**(本地 MCP 客户端,如 Claude Code):
```bash
python -m mcp_server --transport stdio
```

**HTTP 模式**(远程网络访问):
```bash
python -m mcp_server --transport http --port 38507
```

支持的启动参数:

| 参数 | 说明 | 默认值 |
|------|------|--------|
| `--transport, -t` | 传输模式:stdio 或 http | stdio |
| `--host, -H` | HTTP 监听地址 | 0.0.0.0 |
| `--port, -p` | HTTP 监听端口 | 38507 |
| `--path, -P` | MCP 协议路径 | /mcp |

### 配置 Claude Code

在项目的 `.mcp.json` 中添加:

```json
{
  "mcpServers": {
    "galmcp": {
      "command": "python",
      "args": [
        "src/mcp_server.py",
        "--transport",
        "stdio"
      ],
      "env": {
        "GALFIT_BIN": "/usr/bin/galfit",
        "GALFITS_BIN": "python /path/to/GalfitS/src/galfits/galfitS.py",
        "GS_DATA_PATH": "/path/to/GalfitS",
        "OPENAI_API_KEY": "your-apikey",
        "OPENAI_BASE_URL": "https://open.bigmodel.cn/api/coding/paas/v4",
        "OPENAI_MODEL": "glm-4.6v",
        "ANALYSIS_MODE": "vlm",
        "CLAUDECODE_API_KEY": "your-anthropic-apikey",
        "CLAUDECODE_BASE_URL": "",
        "CLAUDECODE_MODEL": "gemini-3-flash-preview"
      }
    }
  }
}
```

> **分析模式说明:** `ANALYSIS_MODE` 控制残差分析(`component_analysis`)的后端:
> - `vlm`(默认):通过 OpenAI 兼容 API 调用多模态模型,需配置 `OPENAI_API_KEY`、`OPENAI_BASE_URL`、`OPENAI_MODEL`。
> - `cc`:通过 Claude Code Agent SDK 调用 Anthropic API,需配置 `CLAUDECODE_API_KEY`。支持通过 [Claude Code Router](https://github.com/musistudio/claude-code-router) 代理到其他 LLM 提供商。
> - `acp`:通过 Gemini CLI ACP 模式调用分析,默认使用 `gemini login` 后的本地会话。

## visualRAG 检索增强(可选)

visualRAG 是一个**在线残差检索服务**,为 `component_analysis` 的 `vlm` 分析模式提供 Few-shot 参考样例。开启后,分析的第 1 轮(turn-1)会在目标星系图之前注入若干「参考样例图 + 专家图注」(按顺序:基线样例 / 困难反例 / 正样例),帮助多模态模型校准「视觉特征 → 诊断 → 处方」的判别规则;最后一张图仍是本轮待分析的目标星系。

> 仅在 `ANALYSIS_MODE=vlm` 时生效;`cc` / `acp` 模式不调用。客户端实现见 `src/tools/visualrag_client.py`。

### 触发与数据流

每次 `component_analysis`(vlm 模式)执行 turn-1 前,会调用 `_maybe_fetch_reference_blocks`:

1. 从 comparison PNG 路径反推 GALFIT archive 目录(以 `galfit.[0-9]*` 为标记)。
2. 收集本轮原料打成一个自包含 zip 上传(文件路径引用改写为 basename):
   - feedme、**模型输出 cube**(`*_galfit.fits`)、mask、sigma、最新的 `galfit.NN`。
   - **不上传原始科学图像**——服务端只依据模型 cube + mask + sigma + feedme 抽特征。
3. POST 到 `{VISUALRAG_SERVICE_URL}/query`,服务端用 **DINOv2 视觉嵌入 + 主导成分参数化特征**(Re / n / b/a / mag)做 FAISS 检索。
4. 返回 JSON,含 `baseline`(基线)、`positive`(正样例)、`hard_negatives`(困难反例)、`perfect`、`query`(查询特征)、`warnings`。
5. 按 Few-shot 顺序 `[baseline → hard_negative → positive]` 下载各样例对比 PNG 到临时文件,拼到 turn-1 图像序列最前面;分析结束后清理临时文件。

整个过程是 **best-effort**:服务关闭 / 不可用 / 返回空 → 静默降级为普通单图 turn-1(无参考样例),不影响分析流程。

### 环境变量

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `VISUALRAG_SERVICE_URL` | `""`(空) | 检索服务地址(如 `http://127.0.0.1:8765`)。**空 = 检索关闭**,是唯一真正的开启开关。 |
| `VISUALRAG_ENABLED` | `"1"` | 显式 kill-switch。仅 `=0` 关闭;判据是 `!= "0"`,故 `=false`/`=no`/`=off` **不会**关闭(须写 `0`)。 |
| `VISUALRAG_TOP_K` | `5` | 每个 role 检索返回上限。 |
| `VISUALRAG_STRATEGY` | `both` | 检索策略:`both` = 视觉 + 参数化双特征。 |
| `VISUALRAG_MIN_SCORE` | 空(用 server 默认 `0.3`) | 检索质量下限:服务端丢弃 `score < min_score` 的样例(被丢弃的正样例会连带丢掉它的 hard-neg)。**留空 = 不传该字段,由服务端 config 默认决定**(当前 `0.3`)。 |

配置方式与其它变量一致(`.env` 或 `.mcp.json` 的 `env` 字段)。注意 `query_service` 对 `top_k`/`strategy` 的回退顺序是「显式参数 → 环境变量 → 默认值」,且用 `or` 判断,因此传 `0`/空串会被当成未传而回退到默认值。`min_score` 不同:用 `is None` 判断,空串/未设 = 不传该字段(服务端走其默认 `0.3`),而显式 `0` 会被如实发送(含义为「丢弃负分样例」)。服务端库规模、模型、当前 `min_score` 默认等可通过 `GET {VISUALRAG_SERVICE_URL}/health` 查看。


## 最优轮次登记与轮间对比(best-round registry)

`component_analysis` 在多轮迭代拟合中会维护一个**最优轮次登记表**(`src/tools/best_round_registry.py`),按星系主目录索引,记录当前星系的历史最优轮次及其成分参数、卡方、component_analysis 结论。

- 每轮分析前,若存在历史最优且与当前轮不同,会自动生成一份**轮间对比**(`run_round_comparison`):把历史最优轮与当前轮的对比图交给多模态模型判定 `CURRENT_BETTER / HISTORICAL_BETTER / EQUAL`;判定退步(`HISTORICAL_BETTER`)时额外输出结构化字段 `regression_focus / salvage / direction(REVERT|AUGMENT)`,指明下一轮应回到历史最优轮起点重拟(`REVERT`),还是在当前方向上补全缺失要素(`AUGMENT`)。
- 退步结论作为**软参考**注入 `component_analysis` 的参数审查阶段(turn-2),不干预 turn-1 的视觉特征提取。
- 登记状态默认持久化到星系主目录下的 `.best_round.json`(已加入 `.gitignore`),便于跨会话恢复;设置环境变量 `BEST_ROUND_PERSIST=0` 可关闭,退化为纯内存登记。

### 落锁前强制审计(best-round-verifier)

正式锁定"最优轮次"之前,工作流(`workflow_galfit` / `workflow_galfits`)的阶段三会调用只读 subagent **`best-round-verifier`**(定义见 `.claude/agents/best-round-verifier.md`),对候选轮按**成分 / 拟合 / 物理 / 参数 / 校验 / 指标**六个维度做独立、机械、可追溯的审计,返回 `PASS | FAIL`:

- `FAIL` → 严禁落锁,按"阻断性问题"清单修复后重拟、复审至 `PASS`;
- `PASS`(含 `WARN`)→ 方可落锁。

审计细则与工作流约束详见 `AGENTS.md`。

## 项目结构

```
src/
├── mcp_server.py          # MCP 服务主入口,工具注册与传输配置
├── tools/
│   ├── run_galfit.py      # GALFIT 单波段拟合执行
│   ├── run_galfits.py     # GalfitS 多波段拟合执行
│   ├── analyze_image.py   # VLM 多模态分析(GALFIT/GalfitS 结果)
│   ├── view_original_image.py  # 原始星系图像形态分类
│   ├── component_analysis.py   # 残差分析与组件诊断
│   ├── best_round_registry.py  # 最优轮次登记与轮间对比(持久化 .best_round.json)
│   ├── visualrag_client.py     # visualRAG Few-shot 检索客户端(vlm 模式)
│   ├── modify_feedme.py   # GALFIT feedme 配置文件修改
│   ├── extract_summary_galfit.py  # GALFIT 参数摘要提取
│   ├── pix2radec.py       # 像素坐标转赤经赤纬
│   ├── read_fits.py       # FITS 文件读取工具
│   ├── multi_thresh_plot.py  # 多阈值可视化
│   └── prompt.py          # 工作流 Prompt 定义
├── service/
│   ├── main.py            # FastAPI 应用,HTTP 任务提交接口
│   ├── tasks.py           # Celery 异步任务定义
│   └── file_manager.py    # 文件与工作空间管理
├── llms/
│   ├── base.py            # LLM 客户端基类
│   ├── openai_llm.py      # OpenAI API 客户端
│   └── glm_llm.py         # 智谱 GLM API 客户端
└── prompts/               # Prompt 模板(分类、分析、工作流)
```


## 许可证

MIT License

## 贡献

欢迎提交 Issue 和 Pull Request!