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 模板端口和镜像映射
- 清理冗余文件和备份文件
This commit is contained in:
zhanggangyong
2026-01-17 09:12:11 +00:00
parent 6eaffba1aa
commit 647f9e6e31
83 changed files with 9992 additions and 2138 deletions
@@ -0,0 +1,347 @@
# 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: <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 和租户信息。