Files
agent_management/plans/search_agent_LiteLLM问题分析报告.md
zhanggangyong 647f9e6e31 feat: 更新 agent 模板支持 MODEL_NAME 环境变量
- search_agent: 支持 MODEL_NAME 环境变量配置模型名称
- a2a_litellm_agent: 支持 MODEL_NAME 或 LITELLM_MODEL 环境变量
- mysql_agent/postgresql_agent: 新增数据库查询 agent
- echo_agent: 新增回显测试 agent
- jina_search_agent: 新增 Jina 搜索 agent
- 更新 callback_utils 默认回调 URL
- 优化 k8s_manager 模板端口和镜像映射
- 清理冗余文件和备份文件
2026-01-17 09:12:11 +00:00

9.9 KiB
Raw Permalink Blame History

Search Agent LiteLLM 问题分析报告

一、Search Agent 模型和密钥部署方式分析

1.1 配置来源

Search Agent 的模型和密钥配置通过以下方式部署:

环境变量配置(主要方式)

从 agent_templates/agents/search_agent/search_agent/config.py 和 search_agent_main.py 可以看到:

# 必须的环境变量
LLM_BASE_URL: str          # LLM API基础URL(如:https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/)
LLM_API_KEY: str           # LLM API密钥(可选,可在请求中传入)
LLM_MODEL: str             # 模型名称(默认:gpt-4o-mini,实际使用:taiji/gpt-4o-mini)
SERPER_API_KEY: str        # Serper 搜索 API 密钥
JINA_API_KEY: str          # Jina Reader API 密钥

部署配置示例

从 k8s-test-deployment.yaml 可以看到实际部署配置:

env:
  - name: LLM_BASE_URL
    value: "https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/"
  - name: LLM_MODEL
    value: "taiji/gpt-4o-mini"
  - name: LLM_API_KEY
    valueFrom:
      secretKeyRef:
        name: search-agent-secrets
        key: LLM_API_KEY

1.2 密钥使用流程

  1. 初始化阶段:

    • Agent 启动时从环境变量读取 LLM_BASE_URL 和 LLM_MODEL
    • LLM_API_KEY 可以为空(使用占位符),等待请求时传入
  2. 请求处理阶段(search_agent_main.py:233-282):

    # 临时更新API key - 重要:在搜索前设置
    if config and request.llm_api_key:
        logger.info(f"使用请求中的 LLM API Key: {request.llm_api_key[:10]}...")
        config.llm_api_key = request.llm_api_key
        # 重新初始化整个 SearchAgent 以使用新的 API key
        search_agent = SearchAgent(config)
    
  3. LLM 调用(llm_client.py:49-89):

    # Azure OpenAI 风格的URL
    url = f"{self.base_url}/chat/completions?api-version={self.API_VERSION}"
    
    # Azure OpenAI 使用 api-key 头
    headers = {
        "api-key": self.api_key,  # 使用传入的 API Key
        "Content-Type": "application/json"
    }
    

1.3 关键发现

  1. 模型名称:使用的是 taiji/gpt-4o-mini,这是一个模型别名(model alias),不是原始模型名
  2. API Key 传递方式:
    • 通过 HTTP Header api-key 传递(Azure OpenAI 风格)
    • 支持在请求中动态传入,覆盖环境变量
  3. LiteLLM Proxy 地址:https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/

二、LiteLLM 回调报错原因分析

2.1 错误现象

根据提供的日志信息:

"call_type": "/chat/completions",
"model": "taiji/gpt-4o-mini",
"status": "failure",
"response_time": 0.00039  # 极短的响应时间,说明在鉴权阶段就被拒绝

异常位置:
ProxyException
File ".../auth_checks.py", line 1756
can_team_access_model(model=_model, team_model_aliases=...)

2.2 根本原因

LiteLLM Proxy 在鉴权阶段无法将当前请求使用的 API Key 映射到任何租户(tenant/team),因此直接拒绝了模型调用。

问题链路:

  1. 请求到达 LiteLLM Proxy

    • Search Agent 发送请求到 https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/chat/completions
    • Header: api-key: <用户提供的API Key>
    • Model: taiji/gpt-4o-mini
  2. LiteLLM 鉴权流程

    LiteLLM Proxy 收到请求
    ↓
    查找 API Key 对应的 team/tenant
    ↓
    检查该 team/tenant 是否有权限访问 "taiji/gpt-4o-mini"
    ↓
    ❌ 失败:无法找到 API Key 对应的租户,或租户没有该模型的访问权限
    ↓
    抛出 ProxyException,拒绝请求
    
  3. 为什么 Agent 还有回复?

    • 可能的原因:
      • Agent 使用了备用 API Key(环境变量中的默认值)
      • 或者 LiteLLM Proxy 配置了降级策略(fallback)
      • 或者请求被重试,使用了不同的 API Key

2.3 具体问题点

问题 1:API Key 未正确映射到租户

LiteLLM Proxy 需要知道:

  • 哪个 API Key 属于哪个 team/tenant
  • 该 team/tenant 可以访问哪些模型

可能的原因:

  • API Key 未在 LiteLLM 的数据库中注册
  • API Key 没有关联 team_id 或 tenant_id
  • API Key 的 auth_metadata 中缺少租户信息

问题 2:模型别名权限配置缺失

模型 taiji/gpt-4o-mini 是一个别名,需要:

  • 在 LiteLLM 中配置该别名映射到实际模型
  • 配置哪些 team/tenant 可以访问该别名

可能的原因:

  • 模型别名 taiji/gpt-4o-mini 未在 LiteLLM 中配置
  • 或者配置了,但当前租户没有访问权限

问题 3:回调时缺少租户信息

从回调文档可以看到,LiteLLM 回调需要包含租户信息:

{
  "metadata": {
    "user_api_key_auth_metadata": {
      "tenant_id": "tenant-123",
      "channel_id": "channel-456"
    }
  }
}

如果回调中缺少这些信息,计费系统无法识别租户,导致计费失败。


三、修复方案

3.1 立即修复(LiteLLM Proxy 配置)

方案 A:在 LiteLLM 中正确配置 API Key 和租户映射

  1. 检查 LiteLLM 数据库中的 API Key 配置

    确保每个 API Key 都有:

    # LiteLLM config.yaml 或数据库记录
    api_keys:
      - sk-xxx:
          team_id: "team-123"
          metadata:
            tenant_id: "tenant-123"
            channel_id: "channel-456"
    
  2. 配置模型别名和团队访问权限

    # LiteLLM config.yaml
    model_list:
      - model_name: taiji/gpt-4o-mini
        litellm_params:
          model: gpt-4o-mini
          api_key: os.environ/OPENAI_API_KEY
    
    # 团队模型访问配置
    team_settings:
      team-123:
        team_model_aliases:
          - taiji/gpt-4o-mini
    

方案 B:在请求中添加租户信息(如果 LiteLLM 支持)

如果 LiteLLM Proxy 支持通过 Header 传递租户信息:

# 在 llm_client.py 中修改
headers = {
    "api-key": self.api_key,
    "Content-Type": "application/json",
    "x-tenant-id": tenant_id,  # 如果 LiteLLM 支持
    "x-team-id": team_id       # 如果 LiteLLM 支持
}

3.2 代码层面修复(Search Agent)

修复 1:在 LLM 调用时传递租户信息

修改 search_agent/utils/llm_client.py,在请求中包含租户信息:

class LLMClient:
    def __init__(
        self,
        base_url: str,
        api_key: str,
        model: str = "xchat52",
        timeout: int = 60,
        tenant_id: Optional[str] = None,  # 新增
        team_id: Optional[str] = None     # 新增
    ):
        self.base_url = base_url.rstrip("/")
        self.api_key = api_key
        self.model = model
        self.timeout = timeout
        self.tenant_id = tenant_id
        self.team_id = team_id
    
    async def chat(self, ...):
        headers = {
            "api-key": self.api_key,
            "Content-Type": "application/json"
        }
        
        # 如果 LiteLLM 支持通过 Header 传递租户信息
        if self.tenant_id:
            headers["x-tenant-id"] = self.tenant_id
        if self.team_id:
            headers["x-team-id"] = self.team_id
        
        # ... 其余代码

修复 2:从请求中提取并传递租户信息

修改 search_agent_main.py,在搜索请求中包含租户信息:

class SearchRequest(BaseModel):
    query: str
    llm_api_key: str
    user_id: Optional[str] = None
    tenant_id: Optional[str] = None  # 新增
    team_id: Optional[str] = None    # 新增

# 在初始化 SearchAgent 时传递租户信息
config = Config(
    ...
    tenant_id=request.tenant_id,  # 传递租户信息
    team_id=request.team_id
)

3.3 LiteLLM Proxy 配置检查清单

  1. ✅ API Key 配置

    • 所有使用的 API Key 都在 LiteLLM 数据库中
    • 每个 API Key 都关联了 team_id 或 tenant_id
    • API Key 的 auth_metadata 包含租户信息
  2. ✅ 模型别名配置

    • taiji/gpt-4o-mini 在 model_list 中定义
    • 模型别名正确映射到实际模型
  3. ✅ 团队/租户访问权限

    • 每个 team/tenant 的 team_model_aliases 包含 taiji/gpt-4o-mini
    • 或者使用通配符允许所有模型
  4. ✅ 回调配置

    • LiteLLM 的 webhook_url 指向正确的回调地址
    • 回调中包含 metadata.user_api_key_auth_metadata 信息

3.4 验证步骤

  1. 测试 API Key 映射

    # 使用 curl 测试
    curl -X POST https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/chat/completions \
      -H "api-key: <your-api-key>" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "taiji/gpt-4o-mini",
        "messages": [{"role": "user", "content": "test"}]
      }'
    
  2. 检查 LiteLLM 日志

    • 查看 LiteLLM Proxy 的日志,确认 API Key 是否被正确识别
    • 检查是否有 can_team_access_model 相关的错误
  3. 验证回调数据

    • 检查回调请求中的 metadata 字段
    • 确认包含 user_api_key_auth_metadata.tenant_id

四、总结

核心问题

LiteLLM Proxy 的多租户鉴权机制无法将 API Key 映射到租户,导致模型调用被拒绝。

修复优先级

  1. 高优先级:修复 LiteLLM Proxy 配置

    • 确保 API Key 正确映射到租户
    • 配置模型别名和访问权限
  2. 中优先级:代码层面改进

    • 在请求中传递租户信息(如果 LiteLLM 支持)
    • 改进错误处理和日志记录
  3. 低优先级:长期优化

    • 统一租户信息管理
    • 添加更详细的监控和告警

为什么 Agent 还有回复?

可能的原因:

  1. Agent 使用了环境变量中的备用 API Key(有权限的)
  2. LiteLLM Proxy 配置了降级策略
  3. 请求被重试,使用了不同的 API Key

建议:检查 LiteLLM Proxy 的日志,确认实际使用的 API Key 和租户信息。