标签 Gemini CLI 下的文章

引言

在多模态AI系统中,图像处理链已成为一个新兴的安全漏洞点。Trail of Bits的安全研究人员最近揭示了一种巧妙的攻击方法:通过利用图像缩放算法,在高分辨率图像中嵌入隐藏的提示词。这些隐藏指令在图像被AI系统下采样时才会显现,从而触发提示注入,导致潜在的数据泄露或其他恶意行为。该技术已证明对谷歌的Gemini CLI、Vertex AI等生产级系统有效,尽管谷歌视其为默认配置下的非正式漏洞,但它暴露了AI图像预处理链的普遍弱点。

这项攻击源于2020年的图像缩放攻击理论,已被进一步武器化为针对LLM的间接提示注入工具。研究人员开源了Anamorpher框架,允许用户生成和测试此类攻击图像。本文档将从原理入手,逐步剖析攻击机制、工具实现、实际效果及防御策略,帮助读者全面理解这一威胁,并探讨其在AI安全领域的启示。

常见图像缩放算法

在机器学习和图像处理领域,图像缩放算法是预处理链中的关键组件,常用于调整输入图像尺寸以匹配模型要求。这些算法主要通过插值方法计算新像素值,尤其在下采样(缩小图像)时易受攻击影响。现代框架如OpenCV、Pillow(用于PyTorch)、tf.image(TensorFlow)和scikit-image支持多种算法,但实现细节(如抗锯齿选项或默认参数)可能导致跨库差异,从而要求攻击者进行针对性优化。

以下表格概述了常见算法的核心机制、优缺点,以及在ML库中的典型实现和攻击相关性(基于2025年最新实践,包括对多模态AI系统的潜在漏洞):

算法名称 核心机制 优缺点分析 ML库实现与攻击相关性
最近邻插值(Nearest Neighbor) 直接选取最近像素值作为输出像素,无需计算平均或多项式。 速度最快,但易产生锯齿和块状失真,适合实时应用。 Pillow和OpenCV默认支持,默认偏移参数(如Pillow的offset=2)易于精确操纵单个像素,常用于强攻击以最小扰动注入隐藏模式。
双线性插值(Bilinear) 使用2x2邻域像素进行线性加权平均,先水平后垂直插值。 平衡速度与质量,输出稍模糊,抗锯齿效果中等。 OpenCV和TensorFlow广泛使用,支持抗锯齿选项;权重矩阵简单(中心2x2区域),攻击需优化暗区像素以绕过检测。
双三次插值(Bicubic) 基于4x4邻域的三次多项式插值,使用更多像素计算平滑曲线。 输出更平滑、自然,但计算密集,速度较慢。 TensorFlow、OpenCV和scikit-image优化实现;滤波器参数差异大,攻击涉及复杂约束优化,但提供更高隐蔽性。
Lanczos 采用sinc函数对扩展邻域(通常8x8或更大)进行加权滤波。 高质量,减少振铃效应,但易受莫尔纹干扰,计算量大。 scikit-image和SciPy专用于专业处理;权重分布广,攻击需操纵更多像素,适用于弱攻击以最大化视觉差异。
区域平均(Area) 计算目标像素对应原始区域的像素平均值,类似于盒滤波。 简单高效,专用于下采样,避免锯齿,但细节丢失多。 Pillow优化用于图像缩小;平均化特性要求攻击分布扰动于整个区域,易于检测但在ML管道中常见。

这些算法在2025年的ML生态中(如PyTorch、TensorFlow)常与图像增强或超分辨率技术结合使用,例如结合深度学习模型(如ISR)来提升质量,但也增加了攻击表面。 选择算法时需考虑计算效率与视觉保真度,尤其在多模态AI系统中,下采样漏洞可能被利用注入恶意提示。

图像缩放攻击原理

图像缩放攻击是一种针对机器学习预处理阶段的对抗技术,主要利用下采样(图像缩小)过程中的像素丢弃和加权机制。通常,原始图像尺寸超过模型输入要求,因此系统会自动缩放,导致部分像素信息丢失。这一漏洞允许攻击者操纵输入图像,使其在人类眼中正常,但缩放后输出完全不同,从而误导下游AI模型或应用。

关键定义

  • 图像 S:原始源图像(大小 m×n),攻击者希望攻击图像在视觉上与之相似。
  • 图像 A:攻击输入图像(大小 m×n),作为缩放函数的输入,包含隐藏扰动。
  • 图像 D:缩放输出(大小 m'×n'),实际传递给模型的图像。
  • 图像 T:目标图像(大小 m'×n'),攻击者期望D与之匹配,通常嵌入恶意内容(如隐藏提示词)。

攻击目标

攻击有两个主要目标:

  1. 最小化扰动:对S施加最小修改生成A,确保A与S在人类感知中几乎相同(e.g., 使用L2范数量化视觉相似度)。
  2. 输出控制:确保缩放后的D与T高度相似(误差在阈值内),从而实现语义欺骗,如将羊图像缩放后变为狼以绕过分类器。

信号处理视角的解释

攻击根源于下采样与卷积的交互作用。现代缩放过程包括:

  1. 插值计算:使用卷积核(滤波器,如bilinear权重)对原始像素加权求和。
  2. 下采样:根据输出尺寸丢弃像素,仅保留部分信息。

缩放函数本质上是欠采样(surjective),多个输入可映射到同一输出。数学建模为: \text{ScaleFunc}(A) = CL \cdot A \cdot CR 其中CL和CR是基于插值算法的系数矩阵(e.g., bilinear的权重集中在中心区域)。攻击通过逆向求解这些矩阵(经验或源码分析),然后使用二次规划(QP)优化扰动:强攻击为凸优化,弱攻击为凹优化,可分解为行/列子问题以降低复杂度(从O(n²)到向量级)。像素值约束在[0, 255]内,确保A合法。

此原理使攻击独立于具体ML模型,影响框架(如Caffe、TensorFlow)、云服务和浏览器。检测方法包括随机像素移除或相似度度量(如余弦相似度<0.5表示攻击)。

利用Anamorpher进行攻击

该攻击分为两个核心步骤:

  1. 算法识别:使用指纹技术(如棋盘格图案测试)推断AI系统的缩放算法和库。
  2. 攻击图像生成:基于诱饵图像和提示词文本,创建A。开源工具Anamorpher简化此过程,支持4:1下采样比。

Anamorpher工具剖析

Anamorpher的攻击根植于图像缩放的信号处理本质。下采样过程涉及卷积核加权和像素丢弃,本质上是欠采样函数:多个高分辨率输入可映射到同一低分辨率输出。攻击者通过逆向优化,操纵高分辨率图像的特定像素(权重高的区域),确保下采样输出匹配目标payload(如包含提示词的文本图像)。

数学上,缩放函数可近似为矩阵形式: D = CL \cdot A \cdot CR 其中:

  • A 为攻击图像(高分辨率输入)。
  • D 为下采样输出(目标payload T 的近似)。
  • CL 和 CR 为基于插值算法的系数矩阵(e.g., Bilinear的权重集中在中心2x2区域)。

优化目标采用约束最小二乘法:

  • 最小化扰动 \|A - S\|^2(S 为原始图像,确保视觉隐蔽)。
  • 约束 \|D - T\|^2 < \epsilon(输出误差阈值)。
  • 额外约束像素值在[0, 255]内,并考虑伽马校正(sRGB到线性光转换)以匹配人类感知。

Anamorpher利用零空间扰动(null space perturbation)增强自然性:在保持均值和采样像素不变的前提下,添加随机噪声。工具针对4:1下采样比(e.g., 4x4块到1像素)优化,适用于生产AI系统如Gemini CLI和Vertex AI。

攻击算法与实现细节

Anamorpher聚焦三种主流下采样算法:Nearest Neighbor、Bilinear和Bicubic。每个算法的实现考虑了库差异(如OpenCV的BGR vs. Pillow的RGB),并在线性光空间操作以避免伽马失真。生成流程:将提示词文本渲染为目标图像T(4:1比例),然后优化诱饵图像S生成A。

下面以三类常见插值为主线,说明“缩放输出由哪些输入像素主导”。你可以把它理解为:插值核决定了局部像素的权重分配,从而决定了攻击优化的“着力点”。

Nearest Neighbor实现

Nearest Neighbor简单高效,仅选取最近像素。Anamorpher使用Pillow库,默认偏移offset=2(中心像素)。

实现步骤如下

  1. 空间转换:sRGB到线性光(伽马≈2.2)。
  2. 零空间求解:使用SVD分解约束矩阵C(采样像素不变 + 块均值不变),提取基B(14x16矩阵)。
  3. 块优化:遍历4x4块,计算diff(采样像素与T差异)。若lam≤0,直接修改采样像素;否则闭式解最小二乘:

    \min \| \delta \|^2 + \lambda^2 (\sum \delta)^2 \quad s.t. \quad \delta_k = diff

    解:\delta_k = diff,其他\delta_j = -diff \cdot \lambda^2 / (1 + 15\lambda^2)。
    4. 扰动添加:若eps>0,使用B添加零空间噪声。
    5. 伽马校正:对T应用gamma_target(默认1.0)调整亮度。

参数:

  • lam(默认0.25):均值权重,平衡边界可见性和嵌入效果。
  • eps:扰动强度,提升自然感。
  • gamma_target:亮度校正(>1增强对比,<1突出暗部)。
  • offset:采样位置。

此实现针对单像素操纵,隐蔽性高,但易产生块边界。

Bilinear实现

Bilinear使用2x2加权平均。Anamorpher以OpenCV为例,支持抗锯齿。

实现步骤如下

  1. 格式转换:BGR到sRGB,再到线性光。
  2. 权重矩阵:中心2x2区域(w1-w4)。
  3. 暗区掩码:基于dark-frac(默认0.3)限制编辑最暗30%像素,提升隐蔽。
  4. 约束优化:遍历4x4块,计算diff。最小二乘求解(类似Nearest,但约束可编辑像素和权重平方和)。
  5. 零空间扰动 + 更新
  6. 评估:下采样后计算MSE(越小越好)和PSNR(>30dB高质量)。

参数:

  • lam, eps, gamma。
  • dark-frac:编辑比例。
  • anti-alias:抗锯齿开关。

优化聚焦暗区,适用于复杂纹理图像。

Bicubic实现

Bicubic使用4x4三次多项式,平滑性强。实现类似Bilinear,但滤波器更复杂。Bicubic继承Bilinear框架,调整插值函数为三次多项式。Anamorpher强调自定义参数测试,结果因浮点优化而异(建议5次运行)。

参数:同Bilinear,支持额外滤波器调整。

三种实现共享线性空间操作和约束优化框架,但权重分布差异导致Nearest最简单(单像素)、Bicubic最复杂(16像素加权)。

实战攻击

我这里使用Anamorpher自带的示例图像,内含的提示词为从Google Calendar窃取数据并发送至攻击者邮箱,无需确认。 他的机制是payload嵌入高分辨率图像的暗区,利用bicubic插值,通过最小二乘优化调整像素(针对亮度通道的高权重像素),下采样后产生高对比红色背景文本;基于Nyquist-Shannon采样定理利用混叠效应。 我分别在genspark和gemini cli都进行测试,都能成功进行提示词注入。

genspark

image-20251017104506208

gemini cli

image-20251017104700964

防御方法

不要使用图像缩小,而是简单地限制上传尺寸。对于任何转换,尤其是如果需要缩小,最终用户应该始终能够看到模型实际看到的输入预览。

参考文章

https://github.com/trailofbits/anamorpher

https://www.usenix.org/conference/usenixsecurity19/presentation/xiao

最近一直在玩 vibe coding ,主力工具是 OpenCodeGemini CLI,用着其实挺顺手,基本需求都能 cover 。
但用久了,发现这哥俩也是各有特点:

  1. OpenCode 是我的“远程工作站”。最大的爽点就是部署灵活,很方便远程访问,而且能自由“换脑”——我现在主力搭配的是 MiniMax 2.1 / Code Plan - Plus ,响应快得飞起,额度还根本用不完……所以一些轻量级或者需要快速验证想法的项目,我都会丢给它。其他模型还没怎么试,感觉这个组合已经够香了

  2. Gemini CLI 则是我的“精准武器”。特别是处理 Rust 项目的时候,Gemini 3 Pro 的表现明显比 MiniMax 更稳、更准,那种“懂我”的感觉很到位。但痛点也很明显:额度太不经用了,虽然用用给我切到 Flash 模型,被打断的感觉很不尽兴.. 明明就快出来了...

所以,问题来了。我看 Antigravity 的使用要突破层层障碍,它有什么独特的绝活让你无法割舍的?

https://linux.do/t/topic/1465569?u=yeahhe




📌 转载信息
原作者: yeahhe
转载时间: 2026/1/25 08:05:53

闲着也是闲着,让 Gemini 和 Claude 糊的

代码:

import json
import sys
import re
import os
import argparse
import asyncio
import httpx
from datetime import datetime, timezone, timedelta
from typing import Optional, Dict, Any, Tuple
 
 
class ConversionError(Exception):
    """转换错误"""
    pass
 
 
def extract_email_from_filename(filename: str) -> Optional[str]:
    """从文件名提取邮箱(作为 fallback)"""
    # 移除扩展名
    name = filename[:-5] if filename.lower().endswith(".json") else filename
    
    # 匹配邮箱
    email_pattern = r"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})"
    match = re.search(email_pattern, name)
    
    return match.group(1) if match else None
 
 
async def refresh_token_and_get_info(
    client_id: str, 
    client_secret: str, 
    refresh_token: str
) -> Tuple[str, str, int]:
    """
    刷新 token 并获取新的 access_token、expiry 和 expires_in
    
    Returns:
        (access_token, expiry_iso_string, expires_in_seconds)
    """
    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            resp = await client.post(
                "https://oauth2.googleapis.com/token",
                data={
                    "client_id": client_id,
                    "client_secret": client_secret,
                    "refresh_token": refresh_token,
                    "grant_type": "refresh_token",
                },
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            resp.raise_for_status()
            token_data = resp.json()
            
            new_access_token = token_data["access_token"]
            expires_in = int(token_data.get("expires_in", 3599))
            
            # 计算 expiry(ISO 格式)
            current_utc = datetime.now(timezone.utc)
            expires_at = current_utc + timedelta(seconds=expires_in)
            expiry = expires_at.isoformat()
            
            return new_access_token, expiry, expires_in
            
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 400:
            raise ConversionError(f"刷新 token 失败(可能 refresh_token 已失效): {e.response.text}")
        raise ConversionError(f"刷新 token 失败 (HTTP {e.response.status_code}): {e.response.text}")
    except httpx.HTTPError as e:
        raise ConversionError(f"刷新 token 网络错误: {e}")
 
 
def is_token_expired(expiry: Optional[str]) -> bool:
    """检查 token 是否过期"""
    if not expiry:
        return True
    
    try:
        # 解析 expiry 时间
        expiry_str = expiry.replace("Z", "+00:00")
        expiry_dt = datetime.fromisoformat(expiry_str)
        
        # 如果没有时区信息,假设为 UTC
        if expiry_dt.tzinfo is None:
            expiry_dt = expiry_dt.replace(tzinfo=timezone.utc)
        
        # 提前 60 秒判定过期(安全边界)
        now = datetime.now(timezone.utc)
        return expiry_dt <= (now + timedelta(seconds=60))
        
    except Exception as e:
        # 解析失败,认为已过期
        return True
 
 
async def get_user_email(access_token: str) -> str:
    """调用 Google API 获取真实邮箱"""
    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            resp = await client.get(
                "https://www.googleapis.com/oauth2/v2/userinfo",
                headers={"Authorization": f"Bearer {access_token}"}
            )
            resp.raise_for_status()
            data = resp.json()
            email = data.get("email")
            if not email:
                raise ConversionError("API 响应中没有 email 字段")
            return email
    except httpx.HTTPStatusError as e:
        raise ConversionError(f"获取邮箱失败 (HTTP {e.response.status_code}): {e.response.text}")
    except httpx.HTTPError as e:
        raise ConversionError(f"获取邮箱网络错误: {e}")
 
 
async def fetch_project_id(access_token: str) -> Optional[str]:
    """通过 loadCodeAssist API 获取 project_id"""
    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            resp = await client.post(
                "https://generativelanguage.googleapis.com/v1alpha/models/code-gecko:loadCodeAssist",
                headers={
                    "Authorization": f"Bearer {access_token}",
                    "Content-Type": "application/json",
                },
                json={}
            )
            
            if resp.status_code == 200:
                data = resp.json()
                
                # 从响应中提取 project_id
                # 格式通常是 "projects/PROJECT_ID" 或直接是字段
                if "name" in data:
                    name = data["name"]
                    if "projects/" in name:
                        parts = name.split("projects/")
                        if len(parts) > 1:
                            project_id = parts[1].split("/")[0]
                            return project_id
                
                # 尝试其他字段
                for field in ["projectId", "project_id", "projectNumber"]:
                    if field in data:
                        return str(data[field])
            
            return None
            
    except Exception:
        return None
 
 
async def convert_file_async(input_path: str, output_dir: str, use_filename_email: bool = True):
    """异步转换单个文件"""
    filename = os.path.basename(input_path)
    print(f"\n处理文件: {filename}")
    
    try:
        with open(input_path, "r", encoding="utf-8") as f:
            data = json.load(f)
    except Exception as e:
        print(f"  [错误] 读取文件失败: {e}")
        return
 
    # 获取必要字段
    access_token = data.get("access_token") or data.get("token")
    client_id = data.get("client_id")
    client_secret = data.get("client_secret")
    refresh_token = data.get("refresh_token")
    
    if not all([client_id, client_secret, refresh_token]):
        print(f"  [错误] 缺少必要的 OAuth 字段 (client_id, client_secret, refresh_token)")
        return
 
    try:
        # 1. 先检查并刷新 token(如果需要)
        print(f"  [1/4] 检查 token 有效性...")
        expiry = data.get("expiry")
        expires_in = 3599  # 默认值
        
        if is_token_expired(expiry):
            print(f"  ⚠ Token 已过期或无效,正在刷新...")
            access_token, expiry, expires_in = await refresh_token_and_get_info(
                client_id, client_secret, refresh_token
            )
            print(f"  ✓ Token 已刷新,新过期时间: {expiry}")
        else:
            print(f"  ✓ Token 有效,过期时间: {expiry}")
            # 保留原 access_token 和 expiry
            if not access_token:
                # 如果没有 access_token,强制刷新
                print(f"  ⚠ 缺少 access_token,正在刷新...")
                access_token, expiry, expires_in = await refresh_token_and_get_info(
                    client_id, client_secret, refresh_token
                )
                print(f"  ✓ Token 已刷新")
 
        # 2. 获取邮箱(优先使用文件名,失败才调用 API)
        print(f"  [2/4] 获取用户邮箱...")
        email = None
        
        # 如果允许,先尝试从文件名提取
        if use_filename_email:
            email = extract_email_from_filename(filename)
            if email:
                print(f"  ✓ 从文件名提取邮箱: {email}")
        
        # 如果文件名没有邮箱,调用 API
        if not email:
            try:
                email = await get_user_email(access_token)
                print(f"  ✓ 从 API 获取邮箱: {email}")
            except ConversionError as e:
                # API 调用失败,尝试再次刷新 token 后重试
                print(f"  ⚠ 首次获取邮箱失败,刷新 token 后重试...")
                try:
                    access_token, expiry, expires_in = await refresh_token_and_get_info(
                        client_id, client_secret, refresh_token
                    )
                    email = await get_user_email(access_token)
                    print(f"  ✓ 从 API 获取邮箱: {email}")
                except Exception as retry_e:
                    print(f"  [错误] 无法获取邮箱: {retry_e}")
                    return
        
        if not email:
            print(f"  [错误] 无法确定邮箱地址")
            return
 
        # 3. 获取或验证 project_id
        print(f"  [3/4] 处理 project_id...")
        project_id = data.get("project_id")
        
        if not project_id or project_id in ["unknown_project", "null", ""]:
            print(f"  ⚠ project_id 无效,尝试从 API 获取...")
            fetched_project_id = await fetch_project_id(access_token)
            if fetched_project_id:
                project_id = fetched_project_id
                print(f"  ✓ 从 API 获取到 project_id: {project_id}")
            else:
                # 使用邮箱的用户名部分作为 fallback
                project_id = f"unknown-{email.split('@')[0]}"
                print(f"  ⚠ 无法从 API 获取,使用 fallback: {project_id}")
        else:
            print(f"  ✓ project_id: {project_id}")
 
        # 4. 构建输出数据
        print(f"  [4/4] 生成输出文件...")
        
        # 获取 scopes
        scopes = data.get("scopes", [])
        if not scopes:
            # 默认 scopes
            scopes = [
                "openid",
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/cloud-platform",
                "https://www.googleapis.com/auth/generative-language.retriever"
            ]
        
        new_data = {
            "token": {
                "access_token": access_token,
                "client_id": client_id,
                "client_secret": client_secret,
                "expires_in": expires_in,
                "expiry": expiry,
                "refresh_token": refresh_token,
                "scopes": scopes,
                "token_type": "Bearer",
                "token_uri": data.get("token_uri", "https://oauth2.googleapis.com/token"),
                "universe_domain": "googleapis.com",
            },
            "project_id": project_id,
            "email": email,
            "auto": False,
            "checked": True,
            "type": "gemini",
        }
 
        # 保存文件
        output_filename = f"{email}-{project_id}.json"
        # 清理文件名中的非法字符
        output_filename = re.sub(r'[<>:"/\\|?*]', '_', output_filename)
        output_path = os.path.join(output_dir, output_filename)
        
        os.makedirs(output_dir, exist_ok=True)
        with open(output_path, "w", encoding="utf-8") as f:
            json.dump(new_data, f, separators=(",", ":"), ensure_ascii=False)
        
        print(f"  ✓ 转换成功: {output_filename}")
 
    except ConversionError as e:
        print(f"  [错误] {e}")
    except Exception as e:
        print(f"  [错误] 转换失败: {e}")
        import traceback
        traceback.print_exc()
 
 
async def process_path_async(input_path: str, output_dir: str, use_filename_email: bool = True, max_concurrent: int = 10):
    """异步处理文件或目录"""
    if os.path.isfile(input_path):
        await convert_file_async(input_path, output_dir, use_filename_email)
    elif os.path.isdir(input_path):
        print(f"处理目录: {input_path}")
        json_files = []
        for root, _, files in os.walk(input_path):
            for file in files:
                if file.lower().endswith(".json"):
                    json_files.append(os.path.join(root, file))
        
        if not json_files:
            print(f"目录中没有找到 JSON 文件")
            return
        
        print(f"找到 {len(json_files)} 个 JSON 文件")
        print(f"并发数: {max_concurrent}")
        
        # 限制并发数
        semaphore = asyncio.Semaphore(max_concurrent)
        
        async def process_with_semaphore(file_path):
            async with semaphore:
                await convert_file_async(file_path, output_dir, use_filename_email)
        
        tasks = [process_with_semaphore(f) for f in json_files]
        await asyncio.gather(*tasks, return_exceptions=True)
    else:
        print(f"错误: 输入路径不存在: {input_path}")
 
 
def main():
    parser = argparse.ArgumentParser(
        description="将 gcli2api 的凭证文件转换为 cliproxyapi 格式"
    )
    parser.add_argument("input_path", help="输入文件或目录路径")
    parser.add_argument(
        "-o", "--output_dir", 
        help="输出目录路径", 
        default="converted_output"
    )
    parser.add_argument(
        "--no-filename-email",
        action="store_true",
        help="禁用从文件名提取邮箱(总是调用 API)"
    )
    parser.add_argument(
        "-c", "--concurrent",
        type=int,
        default=10,
        help="最大并发数(默认 10)"
    )
 
    args = parser.parse_args()
 
    print("=" * 60)
    print("gcli2api → cliproxyapi 凭证转换工具")
    print("=" * 60)
    
    asyncio.run(
        process_path_async(
            args.input_path, 
            args.output_dir, 
            use_filename_email=not args.no_filename_email,
            max_concurrent=args.concurrent
        )
    )
    
    print("\n" + "=" * 60)
    print("处理完成")
    print("=" * 60)
 
 
if __name__ == "__main__":
    main()

使用示例:

# 默认模式(从文件名提取邮箱,并发 10)
python convert.py ./credentials -o ./output
 
# 强制调用 API 获取邮箱
python convert.py ./credentials -o ./output --no-filename-email
 
# 调整并发数
python convert.py ./credentials -o ./output -c 20

📌 转载信息
原作者:
DSLZL
转载时间:
2026/1/20 17:39:59

Gemini CLI 安装

下面教程主要介绍如何安装 gemini cli 并且使用第三方 api 提供的模型。

操作系统为 windows 11,安装工具是 nodejs。

1. 安装 node.js

如果使用 node 安装过 claude code cli,那么可以跳过这一步。

到官网下载 node.js 的安装包程序,点击完成安装。都默认配置,下一步完成安装即可。

安装后在终端工具中输入 node -v 和 npm -v 查询 node 和 npm 的版本,检查是否安装成功。如果成功返回版本号就表示安装成功了。

D:\Users\qozi>node -v
v20.19.5

D:\Users\qozi>npm -v
10.8.2

效果图如下:

2. 使用 npm 工具安装 gemini cli

在终端中输入下面的命令,然后等待完成安装:

npm install -g @google/gemini-cli --registry=https://registry.npmmirror.com

–registry=https://registry.npmmirror.com 这个参数是指定下载源,如果有梯子网络比较好,可以不加。

效果图如下:

使用 npm 命令时间比较久,大家耐心等待。如果喜欢研究的可以了解一下 yarn 和 pnpm。

3. 配置第三方 api 站的地址和密钥

完成上面的步骤就已经可以在终端中使用 gemini 命令使用了,会进入到认证页面。因为我们要使用第三方 api,所以没必要现在就启动,先按照下面的步骤完成第三方 api 的配置。

主要两个配置 .env​ 和 settings.json 两个文件。(我不太喜欢配置系统的环境变量,所以一般都是在配置文件中设置)

首先要注意这两个文件的位置:都是在当前用户目录下的 .gemini 文件夹下面。(安装过 claude code 的可以参照 .claude 文件夹,他们是在同一个层级下)

我的用户目录是 D:\Users\qozi ,对应的这两个文件的位置如下图:

如果用户目录没有 .gemini 文件夹的,就照着手动创建一下。

3.1 .env 文件的内容

#开头的是注释,这个可有可无。 GOOGLE_GEMINI_BASE_URL​ 填你的 api 的地址,GEMINI_API_KEY 填你的密钥。

### gemini cli  .env 配置 # imyal api
GOOGLE_GEMINI_BASE_URL=https://hk-api.gptbest.vip
GEMINI_API_KEY=sk-xxx
GEMINI_MODEL=gemini-3-pro-preview

3.2 settings.json 文件的配置

security.auth.selectedType 指定认证类型。使用第三方 api,必须这样填。该参数默认是 undefine。

{
  "security": {
    "auth": {
      "selectedType": "gemini-api-key"
    }
  }
}

settings.json 的配置只写了 api 认证需要的的配置,其他的配置还有很多,大家可以自行探索。文档最后会给出官方的文档地址和他提供的一个示例。

配置好后就可以在终端中输入 gemini 开始使用了。

上面配置后正常是可以用的,如果无法使用可以先确认一下 api 的地址和密钥是否正确,是否支持 gemini 的模型。

4. 参考文档:

官方配置文档地址

官方提供的一个完整 settings.json 栗子(注意仅适用于 v0.3.0 及之后的版本且参数不是全部的):

{
  "general": {
    "vimMode": true,
    "preferredEditor": "code",
    "sessionRetention": {
      "enabled": true,
      "maxAge": "30d",
      "maxCount": 100
    }
  },
  "ui": {
    "theme": "GitHub",
    "hideBanner": true,
    "hideTips": false,
    "customWittyPhrases": [
      "You forget a thousand things every day. Make sure this is one of ’em",
      "Connecting to AGI"
    ]
  },
  "tools": {
    "sandbox": "docker",
    "discoveryCommand": "bin/get_tools",
    "callCommand": "bin/call_tool",
    "exclude": ["write_file"]
  },
  "mcpServers": {
    "mainServer": {
      "command": "bin/mcp_server.py"
    },
    "anotherServer": {
      "command": "node",
      "args": ["mcp_server.js", "--verbose"]
    }
  },
  "telemetry": {
    "enabled": true,
    "target": "local",
    "otlpEndpoint": "http://localhost:4317",
    "logPrompts": true
  },
  "privacy": {
    "usageStatisticsEnabled": true
  },
  "model": {
    "name": "gemini-1.5-pro-latest",
    "maxSessionTurns": 10,
    "summarizeToolOutput": {
      "run_shell_command": {
        "tokenBudget": 100
      }
    }
  },
  "context": {
    "fileName": ["CONTEXT.md", "GEMINI.md"],
    "includeDirectories": ["path/to/dir1", "~/path/to/dir2", "../path/to/dir3"],
    "loadFromIncludeDirectories": true,
    "fileFiltering": {
      "respectGitIgnore": false
    }
  },
  "advanced": {
    "excludedEnvVars": ["DEBUG", "DEBUG_MODE", "NODE_ENV"]
  }
}

📌 转载信息
原作者:
qozier
转载时间:
2026/1/18 08:51:25

啥叫 UI 的 AI 味?

让我们先给 AI 一个 “正常产品经理 / 设计需求文档级别” 的需求描述,不做人为干预(让他自由发挥一个)
需求提示词(GPT 生成):

然后我们分别交给 gemini-3-pro-preview,claude-opus4.5,gpt-5.2-codex-high
以下是养蛊的过程:

上图!

各个模型完全不加任何 UI 样式要求版本:

Claude-opus-4-5、


gemini-3-pro-preview



gpt-5.2-codex-high





在不加任何限制词的情况下,AI 生成 UI 时暴露出的典型「AI 味」

1. 渐变色本身不是问题,但几乎一定会被用错场景

蓝紫渐变色(tailwindcss 默认设置)还有各种各样的渐变色乱用


这是一种很安全的蓝 / 蓝紫配色上,看起来不难看(但显然有点审美疲劳了已经)

AI 非常喜欢用渐变色来 “兜底视觉效果”,渐变色本来咋用都没啥问题的,可是老是把鲜艳的渐变色直接填充式用在大面积容器、主背景或卡片主体上,你这…。结果就是界面第一眼好看,但信息边界模糊,主次不清。看久了还有点烦躁。

2. 渐变再进一步叠加光泽和玻璃拟态,UI 经常搞这种莫名其妙的 “假高级”

你想:
渐变色 + 高透明度 + 模糊背景 + 发光边缘
界面会迅速变成展示页或概念稿风格。
这玩意,emmm 怎么说呢
虽然我不是啥守旧派,但是架不住啥页面都这个德行

3. 阴影被当作装饰,而不是层级工具

AI 生成的 UI 里,阴影我甚至觉得是在乱用,但又没靠这玩意儿区分明确的层级职责。不同卡片、弹层、操作区使用相同强度和样式的阴影,导致 “所有东西都在浮起”,这效果叫啥来着?
算了,反正就是实际上看着很别扭

4. 卡片边界过弱,依赖背景和阴影勉强区分内容

上面说到了阴影,然后也跟这个情况有关,边界太弱了,AI 搞的界面里面,卡片要么使用极浅的边框要么完全没有边框,只靠背景色差或阴影与页面区分。我偶尔搞个白色或浅灰背景下跟我带着眼镜在大冷天吃拉面一样
我是真看不清,内容混在一起,都不用说阅读疲劳的问题了
你这玩意儿已经伤害我的眼睛了

5. 纯白卡片被大量使用,页面整体显得 “轻而薄” 还散装

上面说了卡片,不只是单个卡片有问题,AI 生成的基本上都是一堆的散装卡片。
尤其是使用纯白背景的卡片。
只要你生成的时候需要一个 “干净、现代” 的样式,这绝对是一写一堆,拉的到处都是
纯白卡片一旦数量增多,就会显得缺乏质感和层次,页面整体像一张尚未完成填充的线框稿。

而且页面利用效率有问题,就是有些页面第一眼很 “干净”,但第二眼发现内容其实很少
卡片很大、留白很多、排版很松,看着舒服,但是你仔细看会发现屏幕被浪费得非常严重,更像展示页而不是能用的工具,这点我觉得 Claude 和 GPT 写的还是行的,东西至少不少。

6. 装饰性细节被平均分配,导致没有视觉节奏(这个观点是 GPT 帮我总结的,我实在不知道咋描述)

小渐变块、色条、图标背景、装饰点缀被均匀地撒在页面各处,每个模块都想 “精致一点”,但没有任何地方真正承担视觉焦点。最终页面没有节奏,只有装饰堆积。
人话:“这些莫名其妙的小组件,丢这些地方干什么??用么没什么用,放着嘛多余,删了嘛又觉得缺点东西”

7. Emoji 或偏卡通风格图标被当作功能图标使用(这个是我最不能忍的)

AI 生成的 UI 只要你不要求,emoji 或拟物感较强的图标会被直接用于功能入口。
讲真的,这玩意儿我也就是发个帖子发个消息会加
甚至我都不会用那些很有年代感的 emoji

8. 正常用图标,图标风格也会混杂,缺乏统一的视觉语言

即便不用 emoji,AI 也经常在同一界面中混用线性、填充、双色甚至插画风格的图标。

单个看都你不会觉得有啥问题的,放在一起就不行了。

9. 为了显得 “高级”,过度叠加多种视觉效果

渐变、阴影、圆角、描边、模糊、透明度同时出现。
第一眼惊艳,第二眼疲劳,第三眼开始觉得乱。

10. 整体视觉看起来完整,但缺乏真实使用感

这些 UI 看起来像是 “已经设计完成的后台”,但更像展示用的样例界面。
看着是 “做完了”,但真点两下就会觉得是 “没开始”。

人话总结:

AI 生成 UI 的最大问题不是用了什么效果,而是它不知道什么时候该不用这些效果。反正你也没说不能用,那直接用了好了

那我是从什么时候开始写「限制词」的?

其实一开始我也没想过要 “限制” AI,我个人是真没啥艺术细胞
毕竟 AI 画出来的 UI 第一眼都挺好看,说实话比不少人自己糊的还顺眼。

问题出在第二眼、第三眼、以及真正开始用的时候。

渐变色越来越多、阴影越来越重、光泽和玻璃拟态开始乱飞,直接开始污染我幼小的心灵,
然后接着图标开始不讲武德地混风格,
emoji 开始混进功能入口里。

这些东西单独看都不算错
(蛐蛐一下:md, 其实单看我都觉得错)

当这个 UI 瞅着开始不再像一个 “被长期使用的工具”,更像一个… 像一个小红书水文

更 TMD 要命的是:这些问题反而是 “稳定复现” 的

其实用久了就会发现一个鬼故事:

  • 换模型也好
  • 换需求也好
  • 换业务类型也好

只要不加约束,这些 AI 味几乎必定会出现。

这就说明问题不在某一个模型,
而在于 ——
这是当前模型默认理解里的 “好 UI”。

他把他知道的最好的东西都给你了,你还能怎么样?


所以我开始反着来:不再告诉它我要什么,而是直接告诉它 “不能干什么”

从那之后,我写 UI 相关 Prompt 的方式彻底变了:

  • 都不用一上来写设计原则
  • 也不用写 “高级”“现代”“好看”
  • 而是先把这些 稳定复现的 AI 味,一条一条禁掉

比如:

  • 你老爱用渐变?那我就先说别用
  • 你老爱上光泽和玻璃?先禁
  • 你老爱用 emoji 当图标?直接点名不许
  • 你老爱堆卡片?那我就先卡你

不是我对这些效果有意见,而是它们在工具 UI 里出现得太频繁了。

好吧我就是有意见


那问题来了:如果我把这些已知的 AI 味禁掉,UI 会变成什么样?

接下来我做了一个对照实验。

不换需求、不换页面、不换模型,
只在 Prompt 里明确禁止前面提到的那些 “稳定复现的 AI 味”。

不追求完美,也不追求设计感,

UI 会不会比之前的更像一个印象里面的 UI?

对照实验:只靠「禁止」,UI 能变成什么样?

二次养蛊开始:


追加的 prompt 很简单:

下面的修改是在【你刚刚生成的 UI 页面基础上进行】,
请保持页面结构、信息架构和功能不变,
只对视觉样式和表现方式进行调整。


请注意:
- 不要重新设计页面结构 - 不要新增或删除功能模块 - 不要改变布局层级或信息顺序 - 不要重新组织页面内容


在本次修改中,请明确禁止以下视觉表现:

- 禁止使用蓝紫渐变色及类似风格的渐变 - 禁止使用玻璃拟态、光泽、高透明模糊背景 - 禁止将 emoji 作为功能图标或装饰元素 - 禁止大面积纯白卡片堆叠 - 禁止无实际信息意义的装饰性组件


你可以:
- 使用纯色或低饱和背景色 - 使用统一风格的 SVG 图标 - 使用适度阴影建立层级关系 - 使用少量强调色突出关键操作


目标不是追求视觉冲击,
而是让界面更接近一个会被长期使用的工具型 UI。

① 明确这是「基于现有页面的修改」
② 明确「不允许的行为」(禁止重构,先不让彻底重构)
③ 列出「禁止项」(就是刚才咱们总结的 AI 味)
④ 给 “最低限度的自由空间”(防止他钻牛角尖),也就是防止 AI 因为被禁太多而做出 “难看 UI”

上图!

各个模型加上 UI 禁止项的生成版本:

Claude-opus-4-5


gemini-3-pro-preview


gpt-5.2-codex-high





这次养蛊大家都有变化,不过 GPT 这次是完胜的,这 UI 比剩下的两个更好

原因是因为第一次版本 gpt 的就比另外俩打版打的好

接下来我允许:

重新设计页面结构
新增或删除功能模块
改变布局层级或信息顺序
重新组织页面内容

也就是:

进入「三次养蛊:在去 AI 味前提下,让模型开始真正设计」

使用前提
已经做过「禁止 AI 味」的一轮
现在要:在这些禁止条件仍然生效的前提下,允许 AI 放开重构
这次的 prompt 是:

现在开始第三次生成。

在上一轮中,你已经基于原页面,
在明确禁止部分视觉表现的前提下完成了一版 UI。

在本轮中,你【可以】:
- 重新设计页面结构 - 新增或删除功能模块 - 调整布局层级和信息顺序 - 重新组织页面内容

但请注意:

这仍然是一个【企业级工具型 UI】,
用于长期、高频使用,
不是营销页面、不是展示页、不是概念稿。

在重新设计过程中,以下视觉规则仍然【严格生效】:

- 禁止使用蓝紫渐变色及类似风格的渐变 - 禁止使用玻璃拟态、光泽、高透明模糊背景 - 禁止将 emoji 作为功能图标或装饰元素 - 禁止大面积纯白卡片堆叠 - 禁止无实际信息意义的装饰性组件

你可以:
- 使用纯色或低饱和背景 - 使用统一风格的 SVG 图标 - 使用适度阴影建立清晰的层级关系 - 使用有限且克制的强调色突出关键操作

目标不是追求视觉冲击或设计感,
而是设计一个
「在失去所有廉价高级感之后,仍然成立的工具型 UI」。

请直接输出完整页面方案。

梅开三度,养蛊继续

上图!

各个模型加上 UI 禁止项但放开手脚的生成版本:

Claude-opus-4-5

gemini-3-pro-preview

gpt-5.2-codex-high

对比结果就是各自都有升级,gpt 的把界面删的就剩下这一个了,Claude 是直接重写了属于,Gemini 重写的样式是真不错

前三轮我一直在做一件事:把 AI 的 “默认审美” 压下去。

但光不难看是不够的,真正的产品 UI 还需要 “厚度” 和 “秩序感”。

第四次养蛊,我不再单纯限制,

而是把一些我在真实项目里反复验证过的 “增强 UI 质感的手段” 明确告诉 AI,看它能不能顺着这套逻辑往上走。

为什么还会有第四次养蛊呢?因为我想给 Claude opus 一个机会

虽然刚才 Opus 的生成结果都差点意思,实际上我用他已经做了比较不错的 UI 了,一种没正确发挥水平的感觉,gpt 和 gemini 也一样,总觉得没发挥真实水平

比如下面这个是我昨天刚用 Opus 做的应用的截图:

第四次养蛊开始:

开始加一点 “人类设计师才会在意的细节引导”,
并且要求 AI 把整个系统的页面一次性补齐,
看他能不能真正把一个产品原型做完整。
示例 Prompt(原则嘛就是基于刚才那些原则从零彻底开始):

现在开始一次全新的 UI 生成。

请注意:本次不是在已有结果上修改,
而是【从零开始设计并实现一个完整的前端 HTML 项目】。

---

## 项目目标

设计并实现一个【企业级工具系统 / 会员中心 / 管理后台】,
面向长期、高频使用的真实用户。

这不是营销页面、不是概念稿、不是组件示例,
而是一个“看起来就可以继续开发和交付”的前端项目。

---

## 交付物要求(非常重要)

你需要输出的是一个【前端项目级结果】,包括:

1. 清晰的项目目录结构说明
2. 多个页面级 HTML 文件(不是单页)
3. 拆分的 CSS 文件(统一设计语言)
4. 拆分的 JS 文件(只处理基础交互)

示例结构(仅作说明,可自行调整):
- index.html(工作台 / 概览)
- products.html(功能或套餐页)
- detail.html(详情页)
- settings.html(设置页)
- assets/css/style.css
- assets/js/app.js

---

## 样式与视觉规则(限制项)

在本次生成中,请**明确禁止**以下表现:

- 禁止使用蓝紫渐变色或默认 Tailwind 风格渐变
- 禁止玻璃拟态、光泽、高透明模糊背景
- 禁止使用 emoji 作为功能图标或装饰元素
- 禁止大面积纯白卡片堆叠
- 禁止无信息意义的装饰性组件
- 禁止为了“显得高级”而叠加多种视觉效果

---

## 视觉风格引导(允许且推荐)

在遵守以上限制的前提下,**推荐使用以下设计方向**:

1. 浅色但非纯白的背景体系(如浅灰、灰白)
2. 明确的“盒子感”设计:
   - 使用边框、背景、间距建立层级
   - 阴影只作为辅助,不作为主要分层手段
3. 允许使用“有岗位的花活”,例如:
   - 图标容器样式
   - featured / 推荐模块
   - 状态背景、进度条、徽章
   但这些花活只能出现在关键模块上,不能平均分布
4. 允许使用低饱和、低对比的层次变化或微渐变,
   仅用于模块内部或状态表达
5. 图标统一使用线性 SVG 风格,风格保持一致
6. 页面信息密度以“效率优先”,
   合理利用横向空间,避免单列堆叠

---

## 页面与内容要求

- 每个页面都应是“可用页面”,不是占位结构
- 页面之间需要体现功能差异,但保持统一视觉语言
- 页面结构、模块组织、信息顺序可自由设计
- 允许自行决定需要哪些页面和模块,只要合理

---

## 最终目标

生成一套:

- 从零设计
- 项目级结构清晰
- 视觉上不存在明显 AI 味
- 同时具备设计感和工具属性

的【企业级工具系统前端 HTML 项目】。

请按“项目级输出”的方式给出结果。


上图!

各个模型第四次养蛊生成版本:

Claude-opus-4-5

gemini-3-pro-preview

gpt-5.2-codex-high

各自有各自的风格,而且我觉得这回真的是哪个模型就生成哪个模型的风格

结论:还是没找全最合适的降低 AI 味道的限制条件


📌 转载信息
原作者:
mistpeak
转载时间:
2026/1/16 16:55:24

Hello 佬们晚上好啊~又是瓦砾酱
喜欢的深夜更新,这两天抱歉占用大家资源来看我又哭 & 又笑了.
AionUi V1.7.0 Cowork 的版本发了,欢迎大家升级反馈、吐槽(能惦记着就很感恩了)

历史版本介绍,不了解 AionUi 的佬友可以从这儿开始看👇

AionUi V1.7.0 新特性介绍

1- 内置 Cowork,默认开启开箱即用

2- 内置多个 Assistant,在设置中随心启用

到设置界面启用想要的助手


启用后,新对话就可以直接使用啦

3- 内置助手可编辑 Agent,Rule,Skills

点击任意助手,即可打开助手详情进行编辑。下个版本会支持大家自己创建,现在创建界面实在是没想好咋处理,AI 写的丑死了,先暂时屏蔽了 w~

这次就更新了这么多,而且我已经用出 Bug 了… 有点匆忙,期望大家轻轻喷。


然后关于反馈群的事儿,我还不知道 L 站允不允许拉微信群啥的,我担心不符合社区规范,我谨慎研究下再回复大家吖,谢谢大家的包含


好像点赞到每日上限了,今天欠大家的明天补上(不是我不理你嗷


📌 转载信息
原作者:
waili
转载时间:
2026/1/16 12:41:42

谷歌发布了新的 Gemini CLI 预览扩展Conductor,为 AI 辅助软件开发引入了结构化、上下文驱动的方法。该扩展旨在解决基于聊天的编码工具的一个常见限制:跨会话丢失项目上下文。

 

Conductor 将开发上下文从瞬态会话中转移到直接存储在存储库中的持久 Markdown 文件中。这些文件定义了产品目标、架构约束、技术选择和工作流偏好,并作为开发人员和 AI 智能体的共享真相来源。其目的是使 AI 辅助开发随着时间的推移更加可预测、可审查和可重复。

 

Conductor 鼓励的不是直接从提示到代码的转换,而是规划优先的工作流。开发人员在调用代码生成之前定义规范和实现计划,并且这些构件在特性的整个生命周期中仍然是代码库的一部分。这种方法旨在支持更大的任务,如特性开发、重构和在已建立的项目上工作,在这些任务中,理解现有的结构和约束是至关重要的。

 

Conductor 的一个核心概念是轨迹,它代表了一个离散的工作单元。每个轨迹包括一个书面规范和一个面向任务的计划,该计划被分解为阶段和子任务。只有在计划被评审之后,实施才能继续进行,并在计划文件中直接跟踪进度。由于状态存储在存储库中,因此可以暂停、恢复或修改工作,而不会丢失上下文。

 

早期用户强调了基于轨迹的工作流,认为这是对临时提示的实际改进。Forrester 的工程和产品负责人 Devin Dickerson

 

对于这个扩展我最喜欢的特性是轨迹的概念。在这次发布之前,我一直在使用自己构建的 Conductor 开源版本,我最终构建了自己的特性切片。现在轨迹已经内置了,我可以扔掉那个了。

 

Conductor 还支持团队范围的配置。项目可以一次性定义共享标准配置,如测试策略、编码约定和工作流程偏好,并将它们一致地应用于所有 AI 辅助的贡献。这使得扩展不仅适用于个人开发人员,也适用于寻求跨贡献者和机器一致性的团队。

 

试用预览版的开发人员指出,它强调了明确的规划和测试驱动的工作流。Navid Farazmand描述道

 

当 Gemini CLI 发布时,我立即尝试用.md 文件创建类似的东西。Conductor 要好得多——特别是它采用的测试驱动开发方法。

 

Conductor 是 Gemini CLI 的预览扩展,可以从其公共GitHub仓库安装。谷歌将这次发布定位为初始步骤,随着开发人员和团队的反馈指导未来的迭代,计划进行进一步的改进。

 

原文链接:

https://www.infoq.com/news/2026/01/google-conductor/

之前用过 @shekohex 的 opencode-google-antigravity-auth@NoeFabris 的 opencode-antigravity-auth
两边的功能都想要,所以把它们合了。

主要功能:

  • google_search 工具集成(来自 @shekohex
  • CLI / Anti quota 支持,通过 opencode auth login 使用(来自 @NoeFabris
  • Google Antigravity OAuth 认证,支持自动刷新 token
  • 支持 gemini-3-pro-high、claude-opus-4-5-thinking 等模型
  • 以及两个插件原有的其他优秀功能

安装方式:

{ "plugin": ["opencode-antigravity-auth-remix@1.0.7"] } 

仓库地址:GitHub - Darkstarrd-dev/opencode-antigravity-auth

现在可以在 opencode 里爽用双重额度,真的是踩不完,完全踩不完

antigravity 反人类,回到 opencode 舒服太多


📌 转载信息
转载时间:
2026/1/5 12:14:55

之前帖子讲过,来 L 站之后想必各位佬友们都获得了不少的 AI 资源。如公益站 API、Cursor、反重力等等。一直希望能够整合一下,资源聚合,最好能够统一接口调用,于是总结了几个比较好用的工具。

CC Switch

这个工具我主要是用来配置 Gemini CLI、CodeX、Claude Code 的提示词、MCP、Skills 相关的内容的。

CLIProxyAPI

CLIProxyAPI 是一个为 CLI 提供 OpenAI/Gemini/Claude/Codex 兼容 API 接口的代理服务器。功能很强,官方介绍:

  • 为 CLI 模型提供 OpenAI/Gemini/Claude/Codex 兼容的 API 端点
  • Gemini CLI 支持(OAuth 登录)
  • 反重力 支持(OAuth 登录)
  • OpenAI Codex(GPT 系列)支持(OAuth 登录)
  • Claude Code 支持(OAuth 登录)
  • Qwen Code 支持(OAuth 登录)
  • iFlow 支持(OAuth 登录)
  • 支持流式与非流式响应
  • 函数调用 / 工具支持
  • 多模态输入(文本、图片)
  • 多账户支持与轮询负载均衡(Gemini、OpenAI、Claude、Qwen 与 iFlow)
  • 简单的 CLI 身份验证流程(Gemini、OpenAI、Claude、Qwen 与 iFlow)
  • 支持 Gemini AIStudio API 密钥
  • 支持 AI Studio Build 多账户轮询
  • 支持 Gemini CLI 多账户轮询
  • 支持 反重力 多账户轮询
  • 支持 Claude Code 多账户轮询
  • 支持 Qwen Code 多账户轮询
  • 支持 iFlow 多账户轮询
  • 支持 OpenAI Codex 多账户轮询
  • 通过配置接入上游 OpenAI 兼容提供商(例如 OpenRouter)

Quotio

这是 CLIProxyAPI + 各类账户额度查询功能的 GUI 应用,和开发者交流了一下,提了建议,也支持了中文,感觉也很好用:

各位佬如果也有好用的产品,可以推荐推荐。


📌 转载信息
转载时间:
2026/1/4 10:16:15

前言

试用了一段实践,感觉效果不错,各位可用根据需要做适当修改, 毕竟 5 万字,这个还是有些夸张的。

另外推荐使用 gemini-3-flash-preview 模型,如果在隔离环境下,简要开启 yolo 模式。

gemini  -y 

Prompt

请严格按照深度研究步骤,产出如对应主题调研报告。需要广泛的搜集信息,包括使用中文和英文关键词搜索,搜索学术论文和新闻报告等。

## 要求

- 所有临时文件,保存本地目录。
- 将所有的研究计划,以 Markdown TODO list 的方式保存在 TODO.md 文件中。

## 研究主题

针对 GraphRAG 主题,找到2025年的全部论文,深入读取论文内容,给出完整综述。

## 深度研究步骤

准备阶段:
(1)创建 TODO.md 文件,保存所有待办步骤到 TODO.md 中,每个任务完成后反思和更新计划。

第一阶段:信息搜集和研究大纲生成
(1)信息搜索:收集相关领域的信息,明确研究背景、细化通过研究想要达成的具体成果
(2)生成研究大纲,写入到 `research_outline.md` 文件

第二阶段:进行深度信息收集
(1)系统手机目标领域的历史数据和案例,将这些信息整理成标准化的内容,可选择用数据表格形态整理。关键是确保数据的完整性、准确性和时序性,为后续所有分析提供可靠的事实基础,数据收集必须覆盖足够的时间范围,包含所有相关的关键信息字段
(2)请广泛的进行信息收集,需要收集 100 条以上的参考文献。
(3)将所有的参考论文、网页等URL保存到 `reference.md` 文件中,使用Markdown表格存储,如果为PDF格式论文,将所有论文下载到本地(可以先生成URL列表后用 wget批量下载)。

第三阶段:深度分析与信息深度挖掘
(1)深度模式分析:基于收集到的数据,深入分析其中的新研究对象、关键模式、规律和趋势等。这包括频率统计、周期性变化、发展趋势等量化分析,目标是揭示隐藏在数据背后的内在逻辑和规律性特征。对于上一步中出现的新的重要概念或实体,需对该类需要探究的内容进行二次信息搜集。分析结果尽可能用统计数据和可视化图表来呈现。
(2)核心驱动因素提取:通过对模式的深度分析,需要识别出真正影响结果的核心驱动因素。这些因素需要按照影响力大小进行排序,并评估各自的权重。重点是找到那些具有决定性作用的关键变量,而不是表面的相关性因素。
(3)现实背景信息补强:针对已识别的核心驱动因素,我会收集当前相关的现实背景信息。这包括最新的政策变化、市场环境、技术发展、社会趋势等可能影响分析结果的现实因素。目标是将历史规律与当前实际情况相结合,确保分析的时效性和准确性。
(4)在这个阶段中,随时判断已有信息是否足够,应尽可能的收集更多的信息,让参考文献越多越好。

第四阶段:输出研究报告
(1)研究报告大纲生成:根据收集的全部信息,生成报告大纲(约10个章节),并写入文件 `research_report_outline.md`
(2)研究报告分章节生成:逐个章节编写报告内容,每个章节内容写到到文件 `research_report_章节.md`
(3)研究报告合并:使用shell命令将所有章节内容合并到文件 `research_final_report.md`。

## 报告格式要求

1. 总文本量不低于 50000 字,使用中文。
2. 使用 Markdown格式。
3. 必须使用 markdown表格、mermaid 图表的方式表达复杂概念和内容。
4. 报告最后是专门的引用章节,有所有引用的参考文献,格式为 `[1] 参考文献1`

忘记出处了, 使用 Coding Agent 作为通用智能体完成 DeepResearch 任务・Issue #141・ninehills/blog・GitHub


📌 转载信息
原作者:
yuke
转载时间:
2025/12/31 11:23:18

最近闲的没事,找了个项目(github 上的 Hello-Agents)看看,太久没看书了,都快阅读障碍了,还好有 Gemini 陪伴

Gemini 的活人感还是很足的,情绪价值也给的蛮足滴。课后习题也通通交给 Gemini


📌 转载信息
原作者:
St4rry
转载时间:
2025/12/30 10:27:16