# Search Agent LiteLLM 问题分析报告 ## 一、Search Agent 模型和密钥部署方式分析 ### 1.1 配置来源 Search Agent 的模型和密钥配置通过以下方式部署: #### 环境变量配置(主要方式) 从 `agent_templates/agents/search_agent/search_agent/config.py` 和 `search_agent_main.py` 可以看到: ```python # 必须的环境变量 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` 可以看到实际部署配置: ```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`): ```python # 临时更新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`): ```python # 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 回调需要包含租户信息: ```json { "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 都有: ```yaml # LiteLLM config.yaml 或数据库记录 api_keys: - sk-xxx: team_id: "team-123" metadata: tenant_id: "tenant-123" channel_id: "channel-456" ``` 2. **配置模型别名和团队访问权限** ```yaml # 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 传递租户信息: ```python # 在 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`,在请求中包含租户信息: ```python 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`,在搜索请求中包含租户信息: ```python 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 映射** ```bash # 使用 curl 测试 curl -X POST https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/chat/completions \ -H "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 和租户信息。