解决 cc-connect + Claude Code 图片识别问题

解决 cc-connect + Claude Code 图片识别问题:一次完整的排查与修复之旅

背景

我使用 cc-connect 桥接飞书和本地 AI 编程代理 Claude Code,并配置了 mimo-media-recognition-mcp MCP 服务器用于图片/音频/视频分析。

架构如下:

飞书用户 → cc-connect → Claude Code → MIMO API(文本模型)
                              ↓
                         MCP 服务器 → MIMO API(多模态模型,支持图片)
  • Claude Code 主模型mimo-v2.5-pro(仅支持文本)
  • MCP 模型mimo-v2-omni(支持图片、音频、视频)

期望的行为:通过飞书发图片 → Claude Code 调用 MCP 分析图片 → 返回分析结果

实际的行为:通过飞书发图片 → Claude Code 返回"无法看到图片" → MCP 从未被调用


第一步:确认 MCP 本身是正常的

首先验证 MCP 服务器能否独立工作:

MIMO_API_KEY="your-key" MIMO_API_BASE="https://your-api-base" MIMO_MODEL="mimo-v2-omni" \
python -c "
from mimo_media_recognition_mcp.server import understand_image
import asyncio
result = asyncio.run(understand_image(
    prompt='描述这张图片',
    image_path='/path/to/test.jpg'
))
print(result)
"

结果:正常返回图片描述。MCP 服务器没有问题。


第二步:分析 cc-connect 日志

启动 cc-connect 并通过飞书发送图片,观察日志:

cc-connect --force 2>&1 | tee cc-connect.log

关键日志:

feishu: downloaded image key=img_xxx size=120814 mime=image/jpeg
claudeSession: image saved path=/home/user/projects/.cc-connect/attachments/img_xxx.jpg size=120814
turn complete tools=0 response_len=173 input_tokens=0 output_tokens=0

注意两个关键信息:

  1. tools=0 — Claude Code 没有调用任何工具(包括 MCP)
  2. input_tokens=0 — API 调用的输入 token 为 0

这说明 Claude Code 根本没有发送 API 请求


第三步:定位根本原因

通过阅读 cc-connect 源码,找到了问题所在。

cc-connect 如何处理图片

cc-connect 有两个 agent 实现:

  • agent/acp/session.go — ACP 协议代理(用于 Cursor、Windsurf 等)
  • agent/claudecode/session.go — Claude Code 专用代理

Claude Code 代理的 Send 函数agent/claudecode/session.go 第 530-598 行):

func (cs *claudeSession) Send(prompt string, images []core.ImageAttachment, files []core.FileAttachment) error {
    // ...

    // 保存图片到磁盘
    for i, img := range images {
        fpath := filepath.Join(attachDir, fname)
        os.WriteFile(fpath, img.Data, 0o644)
        savedPaths = append(savedPaths, fpath)

        // ⚠️ 问题在这里!把图片编码为 base64 发送给 Claude Code
        parts = append(parts, map[string]any{
            "type": "image",
            "source": map[string]any{
                "type":       "base64",
                "media_type": mimeType,
                "data":       base64.StdEncoding.EncodeToString(img.Data),
            },
        })
    }

    // 发送给 Claude Code
    return cs.writeJSON(map[string]any{
        "type":    "user",
        "message": map[string]any{"role": "user", "content": parts},
    })
}

cc-connect 把图片以 Anthropic 格式的 base64 数据内联发送给 Claude Code。

Claude Code 的图片检查机制

Claude Code 在发送 API 请求之前,会检查配置的模型是否支持图片。如果不支持,直接返回固定的"无法看到图片"回复,不会发送任何 API 请求

用户发图片 → cc-connect 编码为 base64 → 发给 Claude Code
→ Claude Code 检查模型(mimo-v2.5-pro)→ 不支持图片
→ 返回"无法看到图片"(不调用 API,不使用 MCP)

这就是为什么 input_tokens=0tools=0

对比:ACP 代理的处理方式

有趣的是,ACP 代理(agent/acp/session.go)的处理方式不同:

func (s *acpSession) appendImageRefs(prompt string, images []core.ImageAttachment) string {
    // 只保存图片到磁盘
    for i, img := range images {
        fpath := filepath.Join(attachDir, fname)
        os.WriteFile(fpath, img.Data, 0o644)
        paths = append(paths, fpath)
    }
    // 只发送文件路径,不发送 base64 数据
    return prompt + "\n\n(Image files saved locally: " + strings.Join(paths, ", ") + ")"
}

ACP 代理只发送文件路径,不发送 base64 数据。但 Claude Code 代理没有这样做。


第四步:修复方案

修改 agent/claudecode/session.goSend 函数,移除 base64 编码部分,只保留文件保存和路径引用。

修改前(原始代码):

// Save and encode images
for i, img := range images {
    ext := extFromMime(img.MimeType)
    fname := fmt.Sprintf("img_%d_%d%s", time.Now().UnixMilli(), i, ext)
    fpath := filepath.Join(attachDir, fname)
    if err := os.WriteFile(fpath, img.Data, 0o644); err != nil {
        slog.Error("claudeSession: save image failed", "error", err)
        continue
    }
    savedPaths = append(savedPaths, fpath)
    slog.Debug("claudeSession: image saved", "path", fpath, "size", len(img.Data))

    mimeType := img.MimeType
    if mimeType == "" {
        mimeType = "image/png"
    }
    // ❌ 这行发送 base64 数据给 Claude Code
    parts = append(parts, map[string]any{
        "type": "image",
        "source": map[string]any{
            "type":       "base64",
            "media_type": mimeType,
            "data":       base64.StdEncoding.EncodeToString(img.Data),
        },
    })
}

修改后:

// Save images to disk (do NOT send base64 inline)
for i, img := range images {
    ext := extFromMime(img.MimeType)
    fname := fmt.Sprintf("img_%d_%d%s", time.Now().UnixMilli(), i, ext)
    fpath := filepath.Join(attachDir, fname)
    if err := os.WriteFile(fpath, img.Data, 0o644); err != nil {
        slog.Error("claudeSession: save image failed", "error", err)
        continue
    }
    savedPaths = append(savedPaths, fpath)
    slog.Debug("claudeSession: image saved", "path", fpath, "size", len(img.Data))
    // ✅ 不再发送 base64 数据,只保存到磁盘
}

同时移除未使用的 encoding/base64 导入。


第五步:编译和部署

1. 克隆源码

git clone https://github.com/chenhg5/cc-connect.git
cd cc-connect

2. 修改代码

编辑 agent/claudecode/session.go,按上述方式修改 Send 函数。

3. 安装 Go 编译器

cc-connect 需要 Go 1.25.0:

# 从镜像下载
curl -L https://mirrors.aliyun.com/golang/go1.25.0.linux-amd64.tar.gz -o /tmp/go.tar.gz
mkdir -p ~/go-install
tar -C ~/go-install -xzf /tmp/go.tar.gz
export PATH=$HOME/go-install/go/bin:$PATH

4. 编译

cd ~/cc-connect
export GOPROXY=https://mirrors.aliyun.com/goproxy/
go build -tags no_web -o cc-connect-modified ./cmd/cc-connect

使用 -tags no_web 跳过 Web UI 构建(需要 Node.js 构建前端资源)。

5. 替换原版

# 停止原版 cc-connect
pkill -f cc-connect

# 启动修改版
~/cc-connect/cc-connect-modified --force

修复后的流程

飞书发图片
  → cc-connect 下载图片,保存到 .cc-connect/attachments/
  → cc-connect 发送文本消息给 Claude Code:
    "User sent image(s).

     (Images also saved locally: /path/to/img.jpg)"
  → Claude Code 收到文本消息
  → Claude Code 读取 CLAUDE.md 中的图片分析指令
  → Claude Code 调用 MCP 工具分析图片
  → MCP 使用 mimo-v2-omni 模型分析图片
  → 返回分析结果给用户

CLAUDE.md 配置

确保项目目录下有 CLAUDE.md,告诉 Claude Code 如何处理图片:

# Image Analysis Protocol

When you receive a message that mentions an image, picture, photo, or screenshot,
the image file has already been saved to disk by cc-connect.

## Steps to analyze an image:

1. Find the latest image file:
```bash
ls -t /home/user/projects/.cc-connect/attachments/ | head -1
  1. Analyze it using MCP:
MIMO_API_KEY="your-key" MIMO_API_BASE="your-api-base" MIMO_MODEL="mimo-v2-omni" \
python -c "
from mimo_media_recognition_mcp.server import understand_image
import asyncio
result = asyncio.run(understand_image(
    prompt='详细描述这张图片的内容',
    image_path='/home/user/projects/.cc-connect/attachments/IMAGE_FILENAME'
))
print(result)
"
  1. Reply with the analysis result in the user's language.

IMPORTANT: You MUST use the Bash tool to run the analysis command.
NEVER say you cannot see images.

总结

项目 说明
问题 cc-connect 把图片以 Anthropic base64 格式发给 Claude Code,但 MIMO 模型不支持图片格式,Claude Code 直接返回"无法看到图片"
根因 agent/claudecode/session.goSend 函数把图片编码为 base64 内联发送
修复 移除 base64 编码,只保存图片到磁盘,通过文件路径引用
效果 Claude Code 收到文本消息,读取 CLAUDE.md,调用 MCP 分析图片

核心思路:不让 Claude Code 看到图片数据(它处理不了),而是让它知道图片在哪里(文件路径),然后通过 MCP 工具去分析。


附录:一键启动脚本

#!/bin/bash
# start-cc-connect.sh

pkill -f cc-connect 2>/dev/null
sleep 1

# 使用修改版 cc-connect
~/cc-connect/cc-connect-modified --force
chmod +x start-cc-connect.sh
./start-cc-connect.sh
posted @ 2026-05-26 18:51  congxxx  阅读(239)  评论(0)    收藏  举报