- 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 模板端口和镜像映射 - 清理冗余文件和备份文件
12 KiB
Search Agent 问题诊断报告
Pod 信息
- Pod 名称:
search-agent-bd115e1f-fc89c0 - 命名空间:
agent-search-agent-bd115e1f-fc89c0 - 状态: Running
一、发现的问题
问题 0:为什么 Agent 还能返回内容?(即使 LiteLLM 返回 401)
现象
虽然 LiteLLM 返回 401 错误,但 Agent 仍然返回了内容,例如:
{
"query": "什么是人工智能",
"answer": "关于「什么是人工智能」,以下是搜索到的相关信息:\n### 来源 [1]: 人工智能 (AI)\n..."
}
原因:降级策略(Fallback Mechanism)
Agent 有一个降级策略,当 LLM 调用失败时,会直接从搜索结果中提取内容:
-
正常流程(LLM 成功时):
搜索 → 提取内容 → 重排序 → LLM 生成答案 → 返回 -
降级流程(LLM 失败时):
搜索 → 提取内容 → 重排序 → LLM 失败 → 使用 _fallback_answer() → 返回 -
降级答案生成逻辑(
answer_generator.py:125-150):def _fallback_answer(self, query: str, documents: List[RankedDocument]) -> Answer: """后备答案生成(LLM失败时)""" # 简单汇总文档内容 content_parts = [f"关于「{query}」,以下是搜索到的相关信息:\n"] for i, doc in enumerate(documents[:5], 1): content_parts.append(f"### 来源 [{i}]: {doc.title}\n") content_parts.append(f"{doc.content[:500]}...\n\n") return Answer( content="".join(content_parts), sources=sources, confidence="low" # 注意:置信度是 low ) -
日志证据:
2026-01-16 12:37:00.009 | ERROR | modules.answer_generator:generate:114 - 答案生成失败: LLM API请求失败: 401 2026-01-16 12:37:00.009 | INFO | agent.search_agent:search:131 - 答案生成完成: confidence=low注意:虽然 LLM 失败了,但答案生成"完成"了,只是
confidence=low。
这意味着什么?
- ✅ 搜索功能正常:Serper 搜索和 Jina 内容提取都成功了
- ✅ 内容提取正常:从网页提取了内容并进行了重排序
- ❌ LLM 生成失败:无法使用 LLM 生成高质量答案
- ⚠️ 返回降级答案:直接返回搜索结果的简单汇总,质量较低
所以 Agent 返回的内容是降级答案,不是 LLM 生成的,质量会明显下降。
问题 1:API Key 未正确使用(导致 LiteLLM 回调失败)
现象
日志显示 LiteLLM 收到的 API Key 是 placeholder,而不是用户传入的真实 API Key:
LLM API错误: 401 - {"error":{"message":"Authentication Error, LiteLLM Virtual Key expected. Received=placeholder, expected to start with 'sk-'.","type":"auth_error"}}
原因分析
-
代码逻辑:
search_agent_main.py第 276-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 search_agent = SearchAgent(config) # 重新初始化 -
问题:日志中没有看到 "使用请求中的 LLM API Key" 这条日志,说明:
- 要么
request.llm_api_key为空/None - 要么请求中的字段名不是
llm_api_key
- 要么
-
SearchAgent 初始化时机:
- 各个模块(QueryAnalyzer, AnswerGenerator 等)在
__init__时创建了LLMClient - 即使重新初始化
SearchAgent,如果模块内部已经缓存了旧的LLMClient,仍会使用 placeholder
- 各个模块(QueryAnalyzer, AnswerGenerator 等)在
验证方法
检查最近的请求日志,看是否有 "使用请求中的 LLM API Key" 这条日志:
kubectl logs -n agent-search-agent-bd115e1f-fc89c0 search-agent-bd115e1f-fc89c0 --tail=1000 | grep "使用请求中的"
如果没有这条日志,说明 API Key 没有被正确传入或处理。
问题 2:Agent 回调 URL 无法解析(Agent Manager 回调失败)
现象
日志显示回调请求失败,无法解析 mcp-server 主机名:
Failed to send callback: HTTPConnectionPool(host='mcp-server', port=8002): Max retries exceeded with url: /api/v1/billing/agent-callback
(Caused by NameResolutionError("HTTPConnection(host='mcp-server', port=8002): Failed to resolve 'mcp-server' ([Errno -2] Name or service not known)"))
回调 URL 信息
- 当前配置的 URL:
http://mcp-server:8002/api/v1/billing/agent-callback - 来源:
agent_callback_utils.py第 33-35 行self.callback_url = callback_url or os.getenv( "AGENT_CALLBACK_URL", "http://mcp-server:8002/api/v1/billing/agent-callback" )
原因分析
-
服务发现问题:
mcp-server服务在taiji-ai命名空间中- 当前 Pod 在
agent-search-agent-bd115e1f-fc89c0命名空间中 - 跨命名空间访问需要使用完整的服务名:
mcp-server.taiji-ai.svc.cluster.local
-
端口问题:
- mcp-server 服务实际端口是 8000(不是 8002)
- 代码中默认使用的是 8002 端口
-
正确的回调 URL 应该是:
http://mcp-server.taiji-ai.svc.cluster.local:8000/api/v1/billing/agent-callback或者(如果 mcp-server 在同一个集群中):
http://mcp-server.taiji-ai:8000/api/v1/billing/agent-callback注意:端口是 8000,不是 8002!
回调请求详情
从日志中可以看到回调请求的 payload:
{
"agentName": "search-agent-bd115e1f-fc89c0",
"userId": "bd115e1f-e2de-4bd2-a641-1ed74ac1a34a",
"podRunningTimeSeconds": 22,
"toolsUsed": ["web_search", "content_reader"],
"startTime": "2026-01-16T12:02:39.355978+00:00",
"endTime": "2026-01-16T12:03:01.701388+00:00",
"requestId": "search-1768564959"
}
问题 3:LiteLLM 回调失败(但直接测试密钥正常)
现象
- 用户使用
sk-rxegkFOciNmQLhOHr3qP3A直接测试模型回调正常 - 但通过 search_agent 调用时,LiteLLM 回调报错
原因分析
-
API Key 传递问题:
- Agent 使用的是
placeholder,不是真实的sk-rxegkFOciNmQLhOHr3qP3A - LiteLLM 无法识别
placeholder,导致鉴权失败 - 鉴权失败后,LiteLLM 的回调也会失败(因为无法识别租户)
- Agent 使用的是
-
为什么直接测试正常:
- 直接测试时使用的是真实的 API Key
sk-rxegkFOciNmQLhOHr3qP3A - 该 API Key 在 LiteLLM 中正确配置了租户信息
- 所以回调正常
- 直接测试时使用的是真实的 API Key
-
为什么 Agent 调用失败:
- Agent 实际使用的是
placeholder - LiteLLM 无法识别
placeholder,返回 401 错误 - 回调时也无法识别租户,导致回调失败
- Agent 实际使用的是
二、问题根源总结
核心问题链
用户传入 llm_api_key: "sk-rxegkFOciNmQLhOHr3qP3A"
↓
代码应该更新 config.llm_api_key 并重新初始化 SearchAgent
↓
❌ 但日志显示没有执行更新逻辑(没有 "使用请求中的 LLM API Key" 日志)
↓
SearchAgent 继续使用 placeholder
↓
LLMClient 使用 placeholder 调用 LiteLLM
↓
LiteLLM 返回 401: "Received=placeholder, expected to start with 'sk-'"
↓
LiteLLM 回调失败(无法识别租户)
三、验证步骤
1. 验证 API Key 是否被传入
检查最近的请求日志:
kubectl logs -n agent-search-agent-bd115e1f-fc89c0 search-agent-bd115e1f-fc89c0 --tail=1000 | grep -E "使用请求中的|llm_api_key|POST /search"
2. 验证回调 URL 配置
检查 Pod 的环境变量:
kubectl exec -n agent-search-agent-bd115e1f-fc89c0 search-agent-bd115e1f-fc89c0 -- env | grep -i "CALLBACK\|MCP"
3. 验证 mcp-server 服务
确认 mcp-server 服务的完整地址:
kubectl get svc -n taiji-ai mcp-server
kubectl get endpoints -n taiji-ai mcp-server
4. 测试回调 URL 连通性
从 Pod 内部测试回调 URL:
# 测试健康检查接口(端口 8000)
kubectl exec -n agent-search-agent-bd115e1f-fc89c0 search-agent-bd115e1f-fc89c0 -- curl -v http://mcp-server.taiji-ai.svc.cluster.local:8000/api/v1/billing/agent-callback/health
# 测试 DNS 解析
kubectl exec -n agent-search-agent-bd115e1f-fc89c0 search-agent-bd115e1f-fc89c0 -- nslookup mcp-server.taiji-ai.svc.cluster.local
四、修复建议(不改代码)
修复 1:配置正确的回调 URL
通过环境变量或 ConfigMap 设置正确的回调 URL:
env:
- name: AGENT_CALLBACK_URL
value: "http://mcp-server.taiji-ai.svc.cluster.local:8000/api/v1/billing/agent-callback"
或者如果 mcp-server 在同一个集群中:
env:
- name: AGENT_CALLBACK_URL
value: "http://mcp-server.taiji-ai:8000/api/v1/billing/agent-callback"
重要:
- 服务名:
mcp-server.taiji-ai.svc.cluster.local(跨命名空间访问) - 端口:8000(不是 8002)
- 路径:
/api/v1/billing/agent-callback
修复 2:确认 API Key 传递方式
检查请求格式是否正确:
{
"query": "什么是人工智能",
"llm_api_key": "sk-rxegkFOciNmQLhOHr3qP3A",
"user_id": "bd115e1f-e2de-4bd2-a641-1ed74ac1a34a"
}
注意:字段名必须是 llm_api_key(不是 LLM_API_KEY 或其他)。
修复 3:检查 LiteLLM 配置
确认 LiteLLM Proxy 中 sk-rxegkFOciNmQLhOHr3qP3A 的配置:
- API Key 是否正确注册
- 是否关联了
team_id或tenant_id - 是否有权限访问
taiji/gpt-4o-mini模型
五、关键日志位置
Agent 回调日志
Sending callback: {'agentName': '...', 'userId': '...', ...}
Failed to send callback: HTTPConnectionPool(host='mcp-server', port=8002): ...
LiteLLM 调用日志
LLM API错误: 401 - {"error":{"message":"Authentication Error, LiteLLM Virtual Key expected. Received=placeholder, ..."}}
API Key 更新日志(应该出现但没出现)
使用请求中的 LLM API Key: sk-rxegkFO...
SearchAgent 已使用新的 API Key 重新初始化
六、Agent 执行流程说明
完整执行流程
1. 接收请求(POST /search)
↓
2. 查询分析(QueryAnalyzer)→ ❌ LLM 失败,使用默认 intent
↓
3. 搜索规划(SearchPlanner)→ ✅ 成功
↓
4. 执行搜索(SearchExecutor + Serper)→ ✅ 成功,获取 10 条结果
↓
5. 提取内容(ContentExtractor + Jina Reader)→ ✅ 成功,提取 10 个文档
↓
6. 结果处理(ResultProcessor + Jina Reranker)→ ✅ 成功,排序后返回 5 个
↓
7. 生成答案(AnswerGenerator + LLM)→ ❌ LLM 失败(401)
↓
8. 降级处理(_fallback_answer)→ ✅ 从文档中提取内容,生成简单答案
↓
9. 质量评估(Reflector + LLM)→ ❌ LLM 失败(401),跳过评估
↓
10. 返回结果 → ✅ 返回降级答案(confidence=low)
为什么还能返回内容?
- 搜索和内容提取不依赖 LLM:使用 Serper API 和 Jina Reader API,这些服务都有独立的 API Key
- 降级策略:当 LLM 失败时,直接从搜索结果中提取内容并格式化返回
- 质量下降:降级答案只是简单汇总,没有 LLM 的智能整合和结构化
如何判断返回的是降级答案?
- 检查 confidence:降级答案的
confidence是"low" - 检查答案格式:降级答案通常以 "关于「xxx」,以下是搜索到的相关信息:" 开头
- 检查日志:日志中会有 "答案生成失败" 和 "confidence=low" 的记录
七、下一步行动
- 立即检查:确认请求中是否真的传入了
llm_api_key字段 - 修复回调 URL:通过环境变量设置正确的
AGENT_CALLBACK_URL - 验证修复:重新发送请求,检查日志中是否出现 "使用请求中的 LLM API Key"
- 监控回调:确认 Agent 回调和 LiteLLM 回调都成功
- 验证答案质量:修复后,答案的
confidence应该是"high"或"medium",而不是"low"