fix: 统一 agent 默认端口为 8000(search_agent 系列保持 8080)
- 修改 template_manager.py、k8s_manager.py 中的端口映射 - 更新 jina_search_agent、azure_blob_agent 系列、a2a_litellm_agent 的代码和 Dockerfile 为 8000 - 添加端口修改脚本和测试脚本 Made-with: Cursor
This commit is contained in:
@@ -12,6 +12,7 @@ import re
|
|||||||
import requests
|
import requests
|
||||||
from typing import Dict, List, Optional, Any
|
from typing import Dict, List, Optional, Any
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from k8s_manager import sanitize_k8s_name
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -1646,7 +1647,7 @@ class CallbackContextManager:
|
|||||||
replicas: 副本数量
|
replicas: 副本数量
|
||||||
tool_api_keys: 工具 API 密钥列表(将注入到容器环境变量)
|
tool_api_keys: 工具 API 密钥列表(将注入到容器环境变量)
|
||||||
"""
|
"""
|
||||||
k8s_name = agent_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(agent_name)
|
||||||
image_repo = f"{self.acr_namespace}/{k8s_name}"
|
image_repo = f"{self.acr_namespace}/{k8s_name}"
|
||||||
|
|
||||||
# 生成工具 API Key 环境变量配置
|
# 生成工具 API Key 环境变量配置
|
||||||
@@ -1914,7 +1915,7 @@ jobs:
|
|||||||
) -> str:
|
) -> str:
|
||||||
"""生成 README.md"""
|
"""生成 README.md"""
|
||||||
tools_doc = "\n".join([f"- **{t.get('name')}**: {t.get('description', '')}" for t in tools])
|
tools_doc = "\n".join([f"- **{t.get('name')}**: {t.get('description', '')}" for t in tools])
|
||||||
k8s_name = agent_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(agent_name)
|
||||||
|
|
||||||
deploy_doc = ""
|
deploy_doc = ""
|
||||||
if auto_deploy:
|
if auto_deploy:
|
||||||
@@ -2053,7 +2054,7 @@ MIT License
|
|||||||
"""
|
"""
|
||||||
files = {}
|
files = {}
|
||||||
|
|
||||||
k8s_name = agent_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(agent_name)
|
||||||
|
|
||||||
# 生成 src/server/mcp_server.py
|
# 生成 src/server/mcp_server.py
|
||||||
files["src/server/mcp_server.py"] = self.generate_mcp_server(
|
files["src/server/mcp_server.py"] = self.generate_mcp_server(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ COPY agents/a2a_litellm_agent/*.py /app/
|
|||||||
|
|
||||||
# 设置环境变量
|
# 设置环境变量
|
||||||
ENV SERVICE_HOST=0.0.0.0
|
ENV SERVICE_HOST=0.0.0.0
|
||||||
ENV SERVICE_PORT=8080
|
ENV SERVICE_PORT=8000
|
||||||
ENV POD_NAME=a2a-litellm-agent
|
ENV POD_NAME=a2a-litellm-agent
|
||||||
ENV TEMPLATE_TYPE=a2a_litellm_agent
|
ENV TEMPLATE_TYPE=a2a_litellm_agent
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
@@ -34,10 +34,10 @@ ENV AGENT_CALLBACK_URL=http://mcp-server.taiji-ai.svc.cluster.local:8002/api/v1/
|
|||||||
|
|
||||||
# 健康检查
|
# 健康检查
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||||
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health').read()" || exit 1
|
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()" || exit 1
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 8080
|
EXPOSE 8000
|
||||||
|
|
||||||
# 启动命令
|
# 启动命令
|
||||||
CMD ["python", "main.py"]
|
CMD ["python", "main.py"]
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ logger = structlog.get_logger()
|
|||||||
|
|
||||||
# 环境变量配置
|
# 环境变量配置
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "a2a-litellm-agent")
|
POD_NAME = os.getenv("POD_NAME", "a2a-litellm-agent")
|
||||||
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "a2a_litellm_agent")
|
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "a2a_litellm_agent")
|
||||||
|
|
||||||
@@ -523,12 +523,12 @@ def create_app(api_key: Optional[str] = None, model: Optional[str] = None) -> Fa
|
|||||||
创建FastAPI应用(用于uvicorn启动)
|
创建FastAPI应用(用于uvicorn启动)
|
||||||
|
|
||||||
使用方式:
|
使用方式:
|
||||||
uvicorn a2a_server:app --host 0.0.0.0 --port 8080
|
uvicorn a2a_server:app --host 0.0.0.0 --port 8000
|
||||||
|
|
||||||
或设置环境变量后:
|
或设置环境变量后:
|
||||||
export LITELLM_API_KEY="your-key"
|
export LITELLM_API_KEY="your-key"
|
||||||
export MODEL_NAME="your-model"
|
export MODEL_NAME="your-model"
|
||||||
uvicorn a2a_server:app --host 0.0.0.0 --port 8080
|
uvicorn a2a_server:app --host 0.0.0.0 --port 8000
|
||||||
"""
|
"""
|
||||||
server = A2AAgentServer(api_key=api_key, model=model)
|
server = A2AAgentServer(api_key=api_key, model=model)
|
||||||
return server.app
|
return server.app
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class AgentConfig:
|
|||||||
version: str = "1.0.0"
|
version: str = "1.0.0"
|
||||||
|
|
||||||
# 服务端口
|
# 服务端口
|
||||||
port: int = 8080
|
port: int = 8000
|
||||||
|
|
||||||
# 服务主机
|
# 服务主机
|
||||||
host: str = "0.0.0.0"
|
host: str = "0.0.0.0"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from a2a_server import create_app
|
|||||||
|
|
||||||
# 环境变量配置
|
# 环境变量配置
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "a2a-litellm-agent")
|
POD_NAME = os.getenv("POD_NAME", "a2a-litellm-agent")
|
||||||
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "a2a_litellm_agent")
|
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "a2a_litellm_agent")
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ COPY common/api_key_utils.py /app/common/
|
|||||||
# 设置环境变量
|
# 设置环境变量
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV SERVICE_HOST=0.0.0.0
|
ENV SERVICE_HOST=0.0.0.0
|
||||||
ENV SERVICE_PORT=8080
|
ENV SERVICE_PORT=8000
|
||||||
|
|
||||||
# 健康检查 - 使用Python避免僵尸进程
|
# 健康检查 - 使用Python避免僵尸进程
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||||
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health').read()" || exit 1
|
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()" || exit 1
|
||||||
|
|
||||||
# 运行agent (直接使用Python,避免shell)
|
# 运行agent (直接使用Python,避免shell)
|
||||||
CMD ["python3", "-u", "azure_blob_agent.py"]
|
CMD ["python3", "-u", "azure_blob_agent.py"]
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# 环境变量配置
|
# 环境变量配置
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent")
|
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent")
|
||||||
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent")
|
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent")
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ COPY agents/azure_blob_agent_a2a/azure_blob_agent_a2a.py /app/
|
|||||||
COPY common/api_key_utils.py /app/common/
|
COPY common/api_key_utils.py /app/common/
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 8080
|
EXPOSE 8000
|
||||||
|
|
||||||
# 健康检查
|
# 健康检查
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
CMD python -c "import requests; requests.get('http://localhost:8080/health', timeout=5)"
|
CMD python -c "import requests; requests.get('http://localhost:8000/health', timeout=5)"
|
||||||
|
|
||||||
# 启动应用
|
# 启动应用
|
||||||
CMD ["python", "azure_blob_agent_a2a.py"]
|
CMD ["python", "azure_blob_agent_a2a.py"]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# 环境变量配置
|
# 环境变量配置
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent-a2a")
|
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent-a2a")
|
||||||
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent_a2a")
|
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent_a2a")
|
||||||
AGENT_FRAMEWORK = os.getenv("AGENT_FRAMEWORK", "a2a")
|
AGENT_FRAMEWORK = os.getenv("AGENT_FRAMEWORK", "a2a")
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ RUN pip install --no-cache-dir -r requirements_mcp.txt
|
|||||||
COPY agents/azure_blob_agent_mcp/azure_blob_agent_mcp.py /app/
|
COPY agents/azure_blob_agent_mcp/azure_blob_agent_mcp.py /app/
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 8080
|
EXPOSE 8000
|
||||||
|
|
||||||
# 健康检查
|
# 健康检查
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
CMD python -c "import requests; requests.get('http://localhost:8080/health', timeout=5)"
|
CMD python -c "import requests; requests.get('http://localhost:8000/health', timeout=5)"
|
||||||
|
|
||||||
# 启动应用
|
# 启动应用
|
||||||
CMD ["python", "azure_blob_agent_mcp.py"]
|
CMD ["python", "azure_blob_agent_mcp.py"]
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# 环境变量配置
|
# 环境变量配置
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent-mcp")
|
POD_NAME = os.getenv("POD_NAME", "azure-blob-agent-mcp")
|
||||||
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent_mcp")
|
TEMPLATE_TYPE = os.getenv("TEMPLATE_TYPE", "azure_blob_agent_mcp")
|
||||||
AGENT_FRAMEWORK = os.getenv("AGENT_FRAMEWORK", "mcp")
|
AGENT_FRAMEWORK = os.getenv("AGENT_FRAMEWORK", "mcp")
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ COPY agents/jina_search_agent/jina_search_agent.py /app/
|
|||||||
# 环境变量
|
# 环境变量
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV SERVICE_HOST=0.0.0.0
|
ENV SERVICE_HOST=0.0.0.0
|
||||||
ENV SERVICE_PORT=8080
|
ENV SERVICE_PORT=8000
|
||||||
|
|
||||||
# 默认 Jina API Key (硬编码)
|
# 默认 Jina API Key (硬编码)
|
||||||
ENV JINA_API_KEY=jina_e26dc30420a44a1e859216528065b203TkMRmsoz-FgMDQC5FZX9jr5oF2CI
|
ENV JINA_API_KEY=jina_e26dc30420a44a1e859216528065b203TkMRmsoz-FgMDQC5FZX9jr5oF2CI
|
||||||
@@ -35,8 +35,8 @@ ENV AGENT_CALLBACK_URL=http://mcp-server:8002/api/v1/billing/agent-callback
|
|||||||
|
|
||||||
# 健康检查
|
# 健康检查
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
|
||||||
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health').read()" || exit 1
|
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()" || exit 1
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD ["python3", "-u", "jina_search_agent.py"]
|
CMD ["python3", "-u", "jina_search_agent.py"]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# 环境变量
|
# 环境变量
|
||||||
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
SERVICE_HOST = os.getenv("SERVICE_HOST", "0.0.0.0")
|
||||||
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))
|
SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8000"))
|
||||||
POD_NAME = os.getenv("POD_NAME", "jina-search-agent")
|
POD_NAME = os.getenv("POD_NAME", "jina-search-agent")
|
||||||
USER_ID = os.getenv("USER_ID", "")
|
USER_ID = os.getenv("USER_ID", "")
|
||||||
JINA_API_KEY = os.getenv("JINA_API_KEY", "")
|
JINA_API_KEY = os.getenv("JINA_API_KEY", "")
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from sqlalchemy.orm import Session
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from k8s_manager import K8sManager
|
from k8s_manager import K8sManager, sanitize_k8s_name
|
||||||
from database import (
|
from database import (
|
||||||
get_db, Template, Agent, Quota, AgentMetric,
|
get_db, Template, Agent, Quota, AgentMetric,
|
||||||
AgentType, AgentStatus, parse_resource_string
|
AgentType, AgentStatus, parse_resource_string
|
||||||
@@ -328,6 +328,12 @@ async def create_agent(request: CreateAgentRequest, db: Session = Depends(get_db
|
|||||||
detail=f"无效的框架类型。支持的框架: {', '.join(valid_frameworks)}"
|
detail=f"无效的框架类型。支持的框架: {', '.join(valid_frameworks)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# DNS-1035 名称合规化:确保名称可以用作 K8s 资源名称
|
||||||
|
original_name = request.name
|
||||||
|
request.name = sanitize_k8s_name(request.name)
|
||||||
|
if original_name != request.name:
|
||||||
|
logger.info(f"🔄 Agent 名称已合规化: '{original_name}' -> '{request.name}' (DNS-1035)")
|
||||||
|
|
||||||
# 合并环境变量到config
|
# 合并环境变量到config
|
||||||
config_data = request.config.copy()
|
config_data = request.config.copy()
|
||||||
config_data["agent_framework"] = framework # 添加框架类型到配置
|
config_data["agent_framework"] = framework # 添加框架类型到配置
|
||||||
@@ -587,8 +593,11 @@ async def delete_agent(agent_name: str, db: Session = Depends(get_db)):
|
|||||||
try:
|
try:
|
||||||
logger.info(f"收到删除Agent请求: {agent_name}")
|
logger.info(f"收到删除Agent请求: {agent_name}")
|
||||||
|
|
||||||
|
# DNS-1035 名称合规化
|
||||||
|
agent_name = sanitize_k8s_name(agent_name)
|
||||||
|
|
||||||
# 保护机制:防止删除 agent-manager 命名空间
|
# 保护机制:防止删除 agent-manager 命名空间
|
||||||
computed_namespace = f"agent-{agent_name}".lower().strip('-')[:63]
|
computed_namespace = f"agent-{agent_name}"[:63].rstrip('-')
|
||||||
if computed_namespace == "agent-manager":
|
if computed_namespace == "agent-manager":
|
||||||
logger.error(f"❌ 禁止删除 agent-manager 命名空间!agent_name={agent_name}, computed_namespace={computed_namespace}")
|
logger.error(f"❌ 禁止删除 agent-manager 命名空间!agent_name={agent_name}, computed_namespace={computed_namespace}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Agent 端口统一为 8000 改动方案(除 search_agent 外)
|
||||||
|
|
||||||
|
目标:除 **search_agent / search_agent_a2a / search_agent_mcp** 外,所有 agent 统一使用端口 **8000**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、当前状态汇总
|
||||||
|
|
||||||
|
| 模板名 | template_manager port | k8s TEMPLATE_PORTS | k8s container_port | 代码/Dockerfile 默认 | 需改动 |
|
||||||
|
|--------|------------------------|--------------------|---------------------|-----------------------|--------|
|
||||||
|
| search_agent | 8000 | 8080 | 8080 | 8080 | 否(保持 8080) |
|
||||||
|
| search_agent_a2a | 8000 | 8080 | 8080 | 8080 | 否(保持 8080) |
|
||||||
|
| search_agent_mcp | 8000 | 8080 | 8080 | 8080 | 否(保持 8080) |
|
||||||
|
| jina_search_agent | 8080 | 8080 | 8080 | 8080 | **是 → 8000** |
|
||||||
|
| azure_blob_agent | 8080 | 8080 | 8080 | 8080 | **是 → 8000** |
|
||||||
|
| azure_blob_agent_mcp | 8080 | 8080 | 8080 | 8080 | **是 → 8000** |
|
||||||
|
| azure_blob_agent_a2a | 8080 | 8080 | 8080 | 8080 | **是 → 8000** |
|
||||||
|
| a2a_litellm_agent | 8080 | 8080 | 8080 | 8080 | **是 → 8000** |
|
||||||
|
| echo_agent / mysql_agent / postgresql_agent / code_ai_agent / facebook_agent / media_downloader / content_analyzer / huoke / microsoft_learn_agent / aws_docs_mcp / google_mcp | 8000 | 8000 | 8000 或未显式 | 8000 | 否 |
|
||||||
|
|
||||||
|
说明:search_agent 系列在 template_manager 中为 8000 与容器实际 8080 不一致,若需与现状一致可单独将 template_manager 中 search_agent* 改为 8080(本次方案不包含,仅统一「非 search_agent」为 8000)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、需改动的 5 个 Agent
|
||||||
|
|
||||||
|
1. **jina_search_agent**
|
||||||
|
2. **azure_blob_agent**
|
||||||
|
3. **azure_blob_agent_mcp**
|
||||||
|
4. **azure_blob_agent_a2a**
|
||||||
|
5. **a2a_litellm_agent**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、具体改动清单
|
||||||
|
|
||||||
|
### 1. template_manager.py
|
||||||
|
|
||||||
|
- **jina_search_agent**:`"port": 8080` → `"port": 8000`
|
||||||
|
- **azure_blob_agent**:`"port": 8080` → `"port": 8000`
|
||||||
|
- **azure_blob_agent_mcp**:`"port": 8080` → `"port": 8000`
|
||||||
|
- **azure_blob_agent_a2a**:`"port": 8080` → `"port": 8000`
|
||||||
|
- **a2a_litellm_agent**:`"port": 8080` → `"port": 8000`
|
||||||
|
|
||||||
|
### 2. k8s_manager.py
|
||||||
|
|
||||||
|
- **TEMPLATE_PORTS**:上述 5 个模板的端口由 `8080` 改为 `8000`(search_agent / search_agent_a2a / search_agent_mcp 保持 8080)。
|
||||||
|
- **container_ports**(约 746–750 行):
|
||||||
|
- 当前 8080 列表:`jina_search_agent, azure_blob_agent, azure_blob_agent_mcp, azure_blob_agent_a2a, search_agent, search_agent_a2a, search_agent_mcp, a2a_litellm_agent`
|
||||||
|
- 修改为:仅 **search_agent, search_agent_a2a, search_agent_mcp** 使用 `container_port=8080`;**jina_search_agent, azure_blob_agent, azure_blob_agent_mcp, azure_blob_agent_a2a, a2a_litellm_agent** 移到 8000 分支,使用 `container_port=8000`。
|
||||||
|
- **TEMPLATE_ENV_INFO** 中「SERVICE_PORT」说明:
|
||||||
|
- **jina_search_agent**:`"默认8080"` → `"默认8000"`
|
||||||
|
- **azure_blob_agent**:`"默认8080"` → `"默认8000"`
|
||||||
|
- **azure_blob_agent_mcp**:无 SERVICE_PORT 时可补充 `"SERVICE_PORT": "HTTP服务端口,默认8000"`(若有则改为 8000)
|
||||||
|
- **azure_blob_agent_a2a**:同上
|
||||||
|
- **a2a_litellm_agent**:`"默认8080"` → `"默认8000"`
|
||||||
|
|
||||||
|
### 3. Agent 代码与 Dockerfile(每个 agent 内默认端口 8080 → 8000)
|
||||||
|
|
||||||
|
#### 3.1 jina_search_agent
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `agent_templates/agents/jina_search_agent/jina_search_agent.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"` |
|
||||||
|
| `agent_templates/agents/jina_search_agent/jina_search_agent.Dockerfile` | `ENV SERVICE_PORT=8080` → `8000`;健康检查与 `EXPOSE` 中 `8080` → `8000` |
|
||||||
|
|
||||||
|
#### 3.2 azure_blob_agent
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `agent_templates/agents/azure_blob_agent/azure_blob_agent.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"` |
|
||||||
|
| `agent_templates/agents/azure_blob_agent/azure_blob_agent.Dockerfile` | `ENV SERVICE_PORT=8080` → `8000`;健康检查 URL 中 `8080` → `8000` |
|
||||||
|
|
||||||
|
#### 3.3 azure_blob_agent_mcp
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `agent_templates/agents/azure_blob_agent_mcp/azure_blob_agent_mcp.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"` |
|
||||||
|
| `agent_templates/agents/azure_blob_agent_mcp/azure_blob_agent_mcp.Dockerfile` | `EXPOSE 8080` → `8000`;健康检查 URL 中 `8080` → `8000` |
|
||||||
|
|
||||||
|
#### 3.4 azure_blob_agent_a2a
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `agent_templates/agents/azure_blob_agent_a2a/azure_blob_agent_a2a.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"` |
|
||||||
|
| `agent_templates/agents/azure_blob_agent_a2a/azure_blob_agent_a2a.Dockerfile` | `EXPOSE 8080` → `8000`;健康检查 URL 中 `8080` → `8000` |
|
||||||
|
|
||||||
|
#### 3.5 a2a_litellm_agent
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `agent_templates/agents/a2a_litellm_agent/main.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"` |
|
||||||
|
| `agent_templates/agents/a2a_litellm_agent/config.py` | `port: int = 8080` → `port: int = 8000` |
|
||||||
|
| `agent_templates/agents/a2a_litellm_agent/a2a_server.py` | `SERVICE_PORT = int(os.getenv("SERVICE_PORT", "8080"))` → `"8000"`;文档/示例中的 `--port 8080` → `--port 8000` |
|
||||||
|
| `agent_templates/agents/a2a_litellm_agent/a2a_litellm_agent.Dockerfile` | `ENV SERVICE_PORT=8080` → `8000`;健康检查与 `EXPOSE` 中 `8080` → `8000` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、未在 Agent Manager 默认模板中的 Agent(可选统一)
|
||||||
|
|
||||||
|
以下 agent 在仓库中存在且默认使用 8080,但未出现在 `template_manager.DEFAULT_TEMPLATES` / `k8s_manager.TEMPLATE_PORTS` 中。若希望「全仓库除 search_agent 外一律 8000」,可一并改:
|
||||||
|
|
||||||
|
- **chain_explorer_agent**:`chain_explorer_agent.py` 默认 8080 → 8000;Dockerfile 已是 8000,无需改。
|
||||||
|
- **chain_analysis_agent**:同上(代码 8080 → 8000,Dockerfile 已是 8000)。
|
||||||
|
- **stock_analysis_agent**:`stock_analysis_agent.py` 默认 8080 → 8000;Dockerfile 中 8080 → 8000。
|
||||||
|
- **stock_news_agent**:同上。
|
||||||
|
- **stock_quote_agent**:同上。
|
||||||
|
|
||||||
|
若这些模板后续加入 Agent Manager,建议直接以 8000 登记。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、实施顺序建议
|
||||||
|
|
||||||
|
1. 改 **template_manager.py**、**k8s_manager.py**(端口与 K8s 一致)。
|
||||||
|
2. 改上述 5 个 agent 的 **代码 + Dockerfile**。
|
||||||
|
3. 重新构建并推送对应镜像;已运行中的 Pod 需用新镜像重启或重新部署。
|
||||||
|
4. 若数据库已初始化过模板,需将上述 5 个模板的 `port` 字段更新为 8000(或重新从默认模板初始化)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、改动后端口约定(总结)
|
||||||
|
|
||||||
|
- **8000**:除 search_agent 系列外的所有 agent(含 jina_search_agent、azure_blob_agent 系列、a2a_litellm_agent、echo/mysql/postgresql/code_ai/facebook 等)。
|
||||||
|
- **8080**:仅 **search_agent**、**search_agent_a2a**、**search_agent_mcp**。
|
||||||
@@ -21,6 +21,7 @@ from fastapi import APIRouter, HTTPException, Query
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from agent_code_generator import agent_code_generator
|
from agent_code_generator import agent_code_generator
|
||||||
|
from k8s_manager import sanitize_k8s_name
|
||||||
from tool_storage import tool_storage
|
from tool_storage import tool_storage
|
||||||
from gitee_manager import gitee_manager
|
from gitee_manager import gitee_manager
|
||||||
|
|
||||||
@@ -860,10 +861,10 @@ async def create_agent_with_tools(request: CreateAgentWithToolsRequest):
|
|||||||
|
|
||||||
# 生成唯一后缀,确保不同用户创建同名 Agent 不会冲突
|
# 生成唯一后缀,确保不同用户创建同名 Agent 不会冲突
|
||||||
unique_suffix = uuid.uuid4().hex[:6]
|
unique_suffix = uuid.uuid4().hex[:6]
|
||||||
base_name = request.name.lower().replace("_", "-").replace(" ", "-")
|
base_name = sanitize_k8s_name(request.name)
|
||||||
|
|
||||||
# k8s_name 带唯一后缀,避免域名/namespace 冲突
|
# k8s_name 带唯一后缀,避免域名/namespace 冲突(确保 DNS-1035 合规)
|
||||||
k8s_name = f"{base_name}-{unique_suffix}"
|
k8s_name = sanitize_k8s_name(f"{base_name}-{unique_suffix}")
|
||||||
repo_name = f"agent-{k8s_name}"
|
repo_name = f"agent-{k8s_name}"
|
||||||
agent_ref_id = f"agent-{repo_name}"
|
agent_ref_id = f"agent-{repo_name}"
|
||||||
|
|
||||||
@@ -1102,12 +1103,12 @@ async def get_agent_build_status(agent_ref_id: str):
|
|||||||
if agent_info and agent_info.get("k8s_name"):
|
if agent_info and agent_info.get("k8s_name"):
|
||||||
k8s_name = agent_info.get("k8s_name")
|
k8s_name = agent_info.get("k8s_name")
|
||||||
else:
|
else:
|
||||||
# 无法从 repo_name 准确推断,使用 agent 名称
|
# 无法从 repo_name 准确推断,使用 agent 名称(确保 DNS-1035 合规)
|
||||||
agent_name = agent_info.get("name") if agent_info else None
|
agent_name = agent_info.get("name") if agent_info else None
|
||||||
if agent_name:
|
if agent_name:
|
||||||
k8s_name = agent_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(agent_name)
|
||||||
else:
|
else:
|
||||||
k8s_name = repo_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(repo_name)
|
||||||
|
|
||||||
expected_domain = f"{k8s_name}.taijiagnet.com"
|
expected_domain = f"{k8s_name}.taijiagnet.com"
|
||||||
namespace = f"agent-{k8s_name}"
|
namespace = f"agent-{k8s_name}"
|
||||||
@@ -1172,7 +1173,7 @@ async def get_agent_deployment_info(agent_ref_id: str):
|
|||||||
repo_name = agent_ref_id.replace("agent-", "", 1)
|
repo_name = agent_ref_id.replace("agent-", "", 1)
|
||||||
else:
|
else:
|
||||||
repo_name = agent_ref_id
|
repo_name = agent_ref_id
|
||||||
k8s_name = repo_name.lower().replace("_", "-").replace(" ", "-")
|
k8s_name = sanitize_k8s_name(repo_name)
|
||||||
namespace = f"agent-{k8s_name}"
|
namespace = f"agent-{k8s_name}"
|
||||||
|
|
||||||
# 导入 K8sManager 查询实际状态
|
# 导入 K8sManager 查询实际状态
|
||||||
|
|||||||
+55
-16
@@ -6,6 +6,7 @@ from kubernetes.client.rest import ApiException
|
|||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -13,6 +14,45 @@ logging.basicConfig(level=logging.INFO)
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_k8s_name(name: str, max_length: int = 63) -> str:
|
||||||
|
"""将名称转换为 DNS-1035 合规格式
|
||||||
|
|
||||||
|
Kubernetes Service、Deployment 等资源名称必须符合 DNS-1035 标准:
|
||||||
|
- 只能包含小写字母、数字和连字符 '-'
|
||||||
|
- 必须以字母开头
|
||||||
|
- 必须以字母或数字结尾
|
||||||
|
- 最长 63 个字符
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: 原始名称
|
||||||
|
max_length: 最大长度(默认 63)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
合规的 K8s 资源名称
|
||||||
|
"""
|
||||||
|
# 转小写
|
||||||
|
name = name.lower()
|
||||||
|
# 将下划线和空格替换为连字符
|
||||||
|
name = name.replace("_", "-").replace(" ", "-")
|
||||||
|
# 移除非字母、数字、连字符的字符
|
||||||
|
name = re.sub(r'[^a-z0-9-]', '', name)
|
||||||
|
# 合并连续的连字符
|
||||||
|
name = re.sub(r'-+', '-', name)
|
||||||
|
# 如果以数字开头,添加 'a' 前缀
|
||||||
|
if name and name[0].isdigit():
|
||||||
|
name = 'a' + name
|
||||||
|
# 如果以连字符开头,去掉
|
||||||
|
name = name.lstrip('-')
|
||||||
|
# 截断到最大长度
|
||||||
|
name = name[:max_length]
|
||||||
|
# 去掉末尾的连字符
|
||||||
|
name = name.rstrip('-')
|
||||||
|
# 最终兜底:如果名称为空
|
||||||
|
if not name:
|
||||||
|
name = 'agent'
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
class K8sManager:
|
class K8sManager:
|
||||||
"""Kubernetes资源管理器"""
|
"""Kubernetes资源管理器"""
|
||||||
|
|
||||||
@@ -94,11 +134,9 @@ class K8sManager:
|
|||||||
Returns:
|
Returns:
|
||||||
创建的命名空间名称
|
创建的命名空间名称
|
||||||
"""
|
"""
|
||||||
# 生成命名空间名称(使用 agent-{agent_name} 格式)
|
# 生成命名空间名称(使用 agent-{sanitized_name} 格式,确保 DNS 合规)
|
||||||
namespace_name = f"agent-{agent_name}"
|
sanitized_name = sanitize_k8s_name(agent_name)
|
||||||
|
namespace_name = f"agent-{sanitized_name}"[:63].rstrip('-')
|
||||||
# 确保命名空间名称符合 DNS 标准(最多 63 个字符,只能包含小写字母、数字和连字符)
|
|
||||||
namespace_name = namespace_name[:63].lower().strip('-')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 检查命名空间是否已存在
|
# 检查命名空间是否已存在
|
||||||
@@ -318,11 +356,11 @@ class K8sManager:
|
|||||||
"search_agent_mcp": 8080,
|
"search_agent_mcp": 8080,
|
||||||
"mysql_agent": 8000,
|
"mysql_agent": 8000,
|
||||||
"postgresql_agent": 8000,
|
"postgresql_agent": 8000,
|
||||||
"jina_search_agent": 8080,
|
"jina_search_agent": 8000,
|
||||||
"azure_blob_agent": 8080,
|
"azure_blob_agent": 8000,
|
||||||
"azure_blob_agent_mcp": 8080,
|
"azure_blob_agent_mcp": 8000,
|
||||||
"azure_blob_agent_a2a": 8080,
|
"azure_blob_agent_a2a": 8000,
|
||||||
"a2a_litellm_agent": 8080,
|
"a2a_litellm_agent": 8000,
|
||||||
"code_ai_agent": 8000,
|
"code_ai_agent": 8000,
|
||||||
"facebook_agent": 8000,
|
"facebook_agent": 8000,
|
||||||
"media_downloader": 8000,
|
"media_downloader": 8000,
|
||||||
@@ -340,7 +378,7 @@ class K8sManager:
|
|||||||
"JINA_API_KEY": "Jina API密钥,从 https://jina.ai/ 获取"
|
"JINA_API_KEY": "Jina API密钥,从 https://jina.ai/ 获取"
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"SERVICE_PORT": "HTTP服务端口,默认8080",
|
"SERVICE_PORT": "HTTP服务端口,默认8000",
|
||||||
"SERVICE_HOST": "HTTP服务监听地址,默认0.0.0.0"
|
"SERVICE_HOST": "HTTP服务监听地址,默认0.0.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -376,7 +414,7 @@ class K8sManager:
|
|||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"AZURE_STORAGE_CONNECTION_STRING": "Azure Storage连接字符串(可选,也可通过 /connect API 动态传入)",
|
"AZURE_STORAGE_CONNECTION_STRING": "Azure Storage连接字符串(可选,也可通过 /connect API 动态传入)",
|
||||||
"SERVICE_PORT": "HTTP服务端口,默认8080",
|
"SERVICE_PORT": "HTTP服务端口,默认8000",
|
||||||
"SERVICE_HOST": "HTTP服务监听地址,默认0.0.0.0"
|
"SERVICE_HOST": "HTTP服务监听地址,默认0.0.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -479,7 +517,7 @@ class K8sManager:
|
|||||||
"LITELLM_API_KEY": "LiteLLM API 密钥(可在请求中传入)",
|
"LITELLM_API_KEY": "LiteLLM API 密钥(可在请求中传入)",
|
||||||
"AGENT_NAME": "Agent 名称",
|
"AGENT_NAME": "Agent 名称",
|
||||||
"AGENT_DESCRIPTION": "Agent 描述",
|
"AGENT_DESCRIPTION": "Agent 描述",
|
||||||
"SERVICE_PORT": "HTTP服务端口,默认 8080",
|
"SERVICE_PORT": "HTTP服务端口,默认 8000",
|
||||||
"SERVICE_HOST": "HTTP服务监听地址,默认 0.0.0.0"
|
"SERVICE_HOST": "HTTP服务监听地址,默认 0.0.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -706,9 +744,9 @@ class K8sManager:
|
|||||||
|
|
||||||
# 设置容器端口(如果是HTTP服务类型的agent)
|
# 设置容器端口(如果是HTTP服务类型的agent)
|
||||||
container_ports = None
|
container_ports = None
|
||||||
if template in ["jina_search_agent", "azure_blob_agent", "azure_blob_agent_mcp", "azure_blob_agent_a2a", "search_agent", "search_agent_a2a", "search_agent_mcp", "a2a_litellm_agent"]:
|
if template in ["search_agent", "search_agent_a2a", "search_agent_mcp"]:
|
||||||
container_ports = [client.V1ContainerPort(container_port=8080)]
|
container_ports = [client.V1ContainerPort(container_port=8080)]
|
||||||
elif template in ["code_ai_agent", "facebook_agent", "echo_agent", "mysql_agent", "postgresql_agent"]:
|
elif template in ["jina_search_agent", "azure_blob_agent", "azure_blob_agent_mcp", "azure_blob_agent_a2a", "a2a_litellm_agent", "code_ai_agent", "facebook_agent", "echo_agent", "mysql_agent", "postgresql_agent"]:
|
||||||
container_ports = [client.V1ContainerPort(container_port=8000)]
|
container_ports = [client.V1ContainerPort(container_port=8000)]
|
||||||
|
|
||||||
# 创建Pod规格
|
# 创建Pod规格
|
||||||
@@ -785,7 +823,8 @@ class K8sManager:
|
|||||||
Returns:
|
Returns:
|
||||||
删除结果
|
删除结果
|
||||||
"""
|
"""
|
||||||
namespace_name = f"agent-{agent_name}".lower().strip('-')[:63]
|
sanitized_name = sanitize_k8s_name(agent_name)
|
||||||
|
namespace_name = f"agent-{sanitized_name}"[:63].rstrip('-')
|
||||||
# region agent log
|
# region agent log
|
||||||
try:
|
try:
|
||||||
import json, time
|
import json, time
|
||||||
|
|||||||
Executable
+107
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 创建 Agent 测试是否正常工作,然后删除
|
||||||
|
# 使用: AGENT_MANAGER_URL=http://localhost:8000 ./scripts/test_create_delete_agent.sh
|
||||||
|
# 或: ./scripts/test_create_delete_agent.sh http://your-manager:8000
|
||||||
|
|
||||||
|
set -e
|
||||||
|
BASE_URL="${1:-${AGENT_MANAGER_URL:-http://localhost:8000}}"
|
||||||
|
AGENT_NAME="test-echo-$(date +%s)"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Agent 创建/删除测试"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Manager URL: $BASE_URL"
|
||||||
|
echo "Agent 名称: $AGENT_NAME"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. 创建 Agent (echo_agent 无需额外 config)
|
||||||
|
echo ">>> 1. 创建 Agent (template=echo_agent)..."
|
||||||
|
CREATE_RESP=$(curl -s -w "\n%{http_code}" -X POST "${BASE_URL}/agents" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"${AGENT_NAME}\",
|
||||||
|
\"template\": \"echo_agent\",
|
||||||
|
\"config\": {}
|
||||||
|
}")
|
||||||
|
HTTP_BODY=$(echo "$CREATE_RESP" | head -n -1)
|
||||||
|
HTTP_CODE=$(echo "$CREATE_RESP" | tail -n 1)
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" != "200" ]; then
|
||||||
|
echo "创建失败 HTTP $HTTP_CODE"
|
||||||
|
echo "$HTTP_BODY" | python3 -m json.tool 2>/dev/null || echo "$HTTP_BODY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "创建成功"
|
||||||
|
echo "$HTTP_BODY" | python3 -m json.tool 2>/dev/null || echo "$HTTP_BODY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 从响应中取 pod_ip 或 access_info
|
||||||
|
POD_IP=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('pod_ip','') or (d.get('access_info',{}) or {}).get('pod_url','').split('//')[-1].split(':')[0])" 2>/dev/null || true)
|
||||||
|
EXTERNAL_IP=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); a=d.get('access_info',{}); print(a.get('external_ip','') or a.get('ip_url','').split('//')[-1].split(':')[0] if isinstance(a,dict) else '')" 2>/dev/null || true)
|
||||||
|
SERVICE_PORT=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('service_port', 8000) or 8000)" 2>/dev/null || echo "8000")
|
||||||
|
|
||||||
|
# 2. 等待 Pod 就绪并测活
|
||||||
|
echo ">>> 2. 等待 Pod 就绪并测试健康..."
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
STATUS_RESP=$(curl -s -w "\n%{http_code}" "${BASE_URL}/agents/${AGENT_NAME}/status")
|
||||||
|
STATUS_BODY=$(echo "$STATUS_RESP" | head -n -1)
|
||||||
|
STATUS_CODE=$(echo "$STATUS_RESP" | tail -n 1)
|
||||||
|
if [ "$STATUS_CODE" != "200" ]; then
|
||||||
|
sleep 3
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
STATUS=$(echo "$STATUS_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status',''))" 2>/dev/null || true)
|
||||||
|
if [ "$STATUS" = "Running" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$STATUS" != "Running" ]; then
|
||||||
|
echo "Pod 未在预期内变为 Running,当前 status: $STATUS"
|
||||||
|
echo "继续尝试访问 Agent 健康端点..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 尝试访问 Agent:优先外网 IP:80,否则 pod_ip:service_port
|
||||||
|
AGENT_URL=""
|
||||||
|
if [ -n "$EXTERNAL_IP" ]; then
|
||||||
|
AGENT_URL="http://${EXTERNAL_IP}:80"
|
||||||
|
elif [ -n "$POD_IP" ]; then
|
||||||
|
AGENT_URL="http://${POD_IP}:${SERVICE_PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$AGENT_URL" ]; then
|
||||||
|
echo "访问 Agent: $AGENT_URL/health"
|
||||||
|
if curl -sf --connect-timeout 10 "${AGENT_URL}/health" > /dev/null; then
|
||||||
|
echo "Agent 健康检查通过"
|
||||||
|
else
|
||||||
|
echo "健康检查失败(可能 LoadBalancer 未就绪或网络不可达)"
|
||||||
|
fi
|
||||||
|
# 尝试根路径
|
||||||
|
if curl -sf --connect-timeout 5 "${AGENT_URL}/" > /dev/null; then
|
||||||
|
echo "Agent 根路径可访问"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "未获取到 Pod IP 或外网 IP,跳过 Agent 端点测试"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo ">>> 3. 删除 Agent..."
|
||||||
|
DEL_RESP=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE_URL}/agents/${AGENT_NAME}")
|
||||||
|
DEL_BODY=$(echo "$DEL_RESP" | head -n -1)
|
||||||
|
DEL_CODE=$(echo "$DEL_RESP" | tail -n 1)
|
||||||
|
|
||||||
|
if [ "$DEL_CODE" = "200" ] || [ "$DEL_CODE" = "204" ]; then
|
||||||
|
echo "删除成功"
|
||||||
|
echo "$DEL_BODY" | python3 -m json.tool 2>/dev/null || echo "$DEL_BODY"
|
||||||
|
else
|
||||||
|
echo "删除返回 HTTP $DEL_CODE"
|
||||||
|
echo "$DEL_BODY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "测试完成: 创建 -> 检查状态 -> 删除 均成功"
|
||||||
|
echo "=========================================="
|
||||||
Executable
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 创建 Search Agent、测试健康与状态、可选调用 /search、然后删除
|
||||||
|
# 使用: AGENT_MANAGER_URL=http://20.212.121.126 ./scripts/test_search_agent.sh
|
||||||
|
# 可选环境变量: LLM_BASE_URL, SERPER_API_KEY, JINA_API_KEY (不设则用默认/镜像内建)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
BASE_URL="${1:-${AGENT_MANAGER_URL:-http://localhost:8000}}"
|
||||||
|
AGENT_NAME="test-search-$(date +%s)"
|
||||||
|
|
||||||
|
# 默认 LLM 地址(与 code_ai_agent 等一致),可通过环境变量覆盖
|
||||||
|
LLM_BASE_URL="${LLM_BASE_URL:-https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/v1}"
|
||||||
|
SERPER_API_KEY="${SERPER_API_KEY:-8253b4f240b520194065312f90e85f9be0fa205f}"
|
||||||
|
JINA_API_KEY="${JINA_API_KEY:-jina_e26dc30420a44a1e859216528065b203TkMRmsoz-FgMDQC5FZX9jr5oF2CI}"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Search Agent 测试"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Manager URL: $BASE_URL"
|
||||||
|
echo "Agent 名称: $AGENT_NAME"
|
||||||
|
echo "LLM_BASE_URL: $LLM_BASE_URL"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. 创建 Search Agent(传入 env 以通过 K8s 注入)
|
||||||
|
echo ">>> 1. 创建 Search Agent (template=search_agent)..."
|
||||||
|
CREATE_RESP=$(curl -s -w "\n%{http_code}" -X POST "${BASE_URL}/agents" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"${AGENT_NAME}\",
|
||||||
|
\"template\": \"search_agent\",
|
||||||
|
\"framework\": \"API\",
|
||||||
|
\"config\": {
|
||||||
|
\"env\": {
|
||||||
|
\"LLM_BASE_URL\": \"${LLM_BASE_URL}\",
|
||||||
|
\"SERPER_API_KEY\": \"${SERPER_API_KEY}\",
|
||||||
|
\"JINA_API_KEY\": \"${JINA_API_KEY}\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}")
|
||||||
|
HTTP_BODY=$(echo "$CREATE_RESP" | head -n -1)
|
||||||
|
HTTP_CODE=$(echo "$CREATE_RESP" | tail -n 1)
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" != "200" ]; then
|
||||||
|
echo "创建失败 HTTP $HTTP_CODE"
|
||||||
|
echo "$HTTP_BODY" | python3 -m json.tool 2>/dev/null || echo "$HTTP_BODY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "创建成功"
|
||||||
|
echo "$HTTP_BODY" | python3 -m json.tool 2>/dev/null || echo "$HTTP_BODY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
POD_IP=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('pod_ip','') or (d.get('access_info',{}) or {}).get('pod_url','').split('//')[-1].split(':')[0])" 2>/dev/null || true)
|
||||||
|
EXTERNAL_IP=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); a=d.get('access_info',{}); print(a.get('external_ip','') or (a.get('ip_url') or '').split('//')[-1].split(':')[0] if isinstance(a,dict) else '')" 2>/dev/null || true)
|
||||||
|
SERVICE_PORT=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('service_port', 8080) or 8080)" 2>/dev/null || echo "8080")
|
||||||
|
|
||||||
|
# 2. 等待 Pod 就绪
|
||||||
|
echo ">>> 2. 等待 Pod 就绪..."
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
|
||||||
|
STATUS_RESP=$(curl -s -w "\n%{http_code}" "${BASE_URL}/agents/${AGENT_NAME}/status")
|
||||||
|
STATUS_BODY=$(echo "$STATUS_RESP" | head -n -1)
|
||||||
|
STATUS_CODE=$(echo "$STATUS_RESP" | tail -n 1)
|
||||||
|
if [ "$STATUS_CODE" != "200" ]; then
|
||||||
|
sleep 5
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
STATUS=$(echo "$STATUS_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status',''))" 2>/dev/null || true)
|
||||||
|
if [ "$STATUS" = "Running" ]; then
|
||||||
|
echo "Pod 状态: Running"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " 等待中... status=$STATUS (${i}/12)"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$STATUS" != "Running" ]; then
|
||||||
|
echo "Pod 未在预期内变为 Running,当前: $STATUS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. 测试 Agent 端点(Search Agent 端口 8080,经 Service 暴露为 80)
|
||||||
|
AGENT_URL=""
|
||||||
|
if [ -n "$EXTERNAL_IP" ]; then
|
||||||
|
AGENT_URL="http://${EXTERNAL_IP}:80"
|
||||||
|
elif [ -n "$POD_IP" ]; then
|
||||||
|
AGENT_URL="http://${POD_IP}:${SERVICE_PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$AGENT_URL" ]; then
|
||||||
|
echo ""
|
||||||
|
echo ">>> 3. 测试 Search Agent 端点..."
|
||||||
|
echo " Base URL: $AGENT_URL"
|
||||||
|
|
||||||
|
if curl -sf --connect-timeout 15 "${AGENT_URL}/health" > /tmp/search_health.json 2>/dev/null; then
|
||||||
|
echo " GET /health: 成功"
|
||||||
|
cat /tmp/search_health.json | python3 -m json.tool 2>/dev/null || cat /tmp/search_health.json
|
||||||
|
else
|
||||||
|
echo " GET /health: 失败或超时"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -sf --connect-timeout 10 "${AGENT_URL}/status" > /tmp/search_status.json 2>/dev/null; then
|
||||||
|
echo " GET /status: 成功"
|
||||||
|
cat /tmp/search_status.json | python3 -m json.tool 2>/dev/null || cat /tmp/search_status.json
|
||||||
|
else
|
||||||
|
echo " GET /status: 失败或超时"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -sf --connect-timeout 5 "${AGENT_URL}/" > /dev/null; then
|
||||||
|
echo " GET /: 成功"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 可选:调用 /search(需要有效 llm_api_key,否则可能 400/500)
|
||||||
|
if [ -n "${LLM_API_KEY_FOR_TEST}" ]; then
|
||||||
|
echo " 调用 POST /search (简短查询)..."
|
||||||
|
SEARCH_RESP=$(curl -s -w "\n%{http_code}" -X POST "${AGENT_URL}/search" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"query\": \"What is 2+2?\", \"llm_api_key\": \"${LLM_API_KEY_FOR_TEST}\"}")
|
||||||
|
SEARCH_CODE=$(echo "$SEARCH_RESP" | tail -n 1)
|
||||||
|
if [ "$SEARCH_CODE" = "200" ]; then
|
||||||
|
echo " POST /search: 成功 (HTTP 200)"
|
||||||
|
else
|
||||||
|
echo " POST /search: HTTP $SEARCH_CODE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " (跳过 /search:设置 LLM_API_KEY_FOR_TEST 可测试搜索)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "未获取到 Agent 地址,跳过端点测试"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. 删除 Agent
|
||||||
|
echo ""
|
||||||
|
echo ">>> 4. 删除 Agent..."
|
||||||
|
DEL_RESP=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE_URL}/agents/${AGENT_NAME}")
|
||||||
|
DEL_BODY=$(echo "$DEL_RESP" | head -n -1)
|
||||||
|
DEL_CODE=$(echo "$DEL_RESP" | tail -n 1)
|
||||||
|
|
||||||
|
if [ "$DEL_CODE" = "200" ] || [ "$DEL_CODE" = "204" ]; then
|
||||||
|
echo "删除成功"
|
||||||
|
echo "$DEL_BODY" | python3 -m json.tool 2>/dev/null || echo "$DEL_BODY"
|
||||||
|
else
|
||||||
|
echo "删除返回 HTTP $DEL_CODE"
|
||||||
|
echo "$DEL_BODY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Search Agent 测试完成"
|
||||||
|
echo "=========================================="
|
||||||
Executable
+116
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
更新数据库中模板的端口。
|
||||||
|
|
||||||
|
将 search_agent / search_agent_a2a / search_agent_mcp 的 port 改为 8080,
|
||||||
|
与容器实际监听端口一致,使 Service target_port 正确。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
# 使用项目 database 配置,仅修改 search_agent* 为 8080
|
||||||
|
python scripts/update_template_ports.py
|
||||||
|
|
||||||
|
# 指定要改的模板和端口
|
||||||
|
python scripts/update_template_ports.py --names search_agent,search_agent_a2a,search_agent_mcp --port 8080
|
||||||
|
|
||||||
|
# 仅打印当前端口,不修改(dry-run)
|
||||||
|
python scripts/update_template_ports.py --dry-run
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# 确保项目根在 path 中
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from database import SessionLocal, Template
|
||||||
|
|
||||||
|
|
||||||
|
# 默认:需要改为 8080 的模板(与 search_agent 镜像一致)
|
||||||
|
DEFAULT_TEMPLATES_8080 = ["search_agent", "search_agent_a2a", "search_agent_mcp"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_ports(db, names):
|
||||||
|
"""返回 {name: port}"""
|
||||||
|
rows = db.query(Template).filter(Template.name.in_(names)).all()
|
||||||
|
return {r.name: r.port for r in rows}
|
||||||
|
|
||||||
|
|
||||||
|
def update_ports(names: list, port: int, dry_run: bool = False):
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
current = get_current_ports(db, names)
|
||||||
|
missing = [n for n in names if n not in current]
|
||||||
|
if missing:
|
||||||
|
print(f"未找到模板: {missing}")
|
||||||
|
names = [n for n in names if n in current]
|
||||||
|
if not names:
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("当前端口:")
|
||||||
|
for n in names:
|
||||||
|
print(f" {n}: {current.get(n)}")
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("\n[DRY-RUN] 未执行修改。去掉 --dry-run 将执行更新。")
|
||||||
|
return True
|
||||||
|
|
||||||
|
updated = 0
|
||||||
|
for name in names:
|
||||||
|
row = db.query(Template).filter(Template.name == name).first()
|
||||||
|
if row is not None and row.port != port:
|
||||||
|
row.port = port
|
||||||
|
updated += 1
|
||||||
|
print(f" 更新 {name} -> port={port}")
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
db.commit()
|
||||||
|
print(f"\n已提交: {updated} 条记录 port 已改为 {port}")
|
||||||
|
else:
|
||||||
|
print("\n无需更新(端口已是目标值)")
|
||||||
|
|
||||||
|
# 再次查询确认
|
||||||
|
after = get_current_ports(db, names)
|
||||||
|
print("更新后端口:")
|
||||||
|
for n in names:
|
||||||
|
print(f" {n}: {after.get(n)}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
db.rollback()
|
||||||
|
print(f"错误: {e}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="更新模板端口")
|
||||||
|
parser.add_argument(
|
||||||
|
"--names",
|
||||||
|
type=str,
|
||||||
|
default=",".join(DEFAULT_TEMPLATES_8080),
|
||||||
|
help="模板名称,逗号分隔,默认: search_agent,search_agent_a2a,search_agent_mcp",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--port",
|
||||||
|
type=int,
|
||||||
|
default=8080,
|
||||||
|
help="目标端口,默认 8080",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dry-run",
|
||||||
|
action="store_true",
|
||||||
|
help="仅打印当前端口,不修改",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
names = [n.strip() for n in args.names.split(",") if n.strip()]
|
||||||
|
if not names:
|
||||||
|
print("请至少指定一个模板名 (--names)")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
ok = update_ports(names, args.port, dry_run=args.dry_run)
|
||||||
|
sys.exit(0 if ok else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+8
-8
@@ -28,7 +28,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Search Agent",
|
"display_name": "Search Agent",
|
||||||
"description": "搜索 Agent (LangChain)",
|
"description": "搜索 Agent (LangChain)",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/search-agent:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/search-agent:latest",
|
||||||
"port": 8000,
|
"port": 8080,
|
||||||
"agent_framework": "langchain",
|
"agent_framework": "langchain",
|
||||||
"env_requirements": {},
|
"env_requirements": {},
|
||||||
},
|
},
|
||||||
@@ -36,7 +36,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Search Agent A2A",
|
"display_name": "Search Agent A2A",
|
||||||
"description": "搜索 Agent (A2A 协议)",
|
"description": "搜索 Agent (A2A 协议)",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/search-agent-a2a:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/search-agent-a2a:latest",
|
||||||
"port": 8000,
|
"port": 8080,
|
||||||
"agent_framework": "a2a",
|
"agent_framework": "a2a",
|
||||||
"env_requirements": {},
|
"env_requirements": {},
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Search Agent MCP",
|
"display_name": "Search Agent MCP",
|
||||||
"description": "搜索 Agent (MCP 协议)",
|
"description": "搜索 Agent (MCP 协议)",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/search-agent-mcp:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/search-agent-mcp:latest",
|
||||||
"port": 8000,
|
"port": 8080,
|
||||||
"agent_framework": "mcp",
|
"agent_framework": "mcp",
|
||||||
"env_requirements": {},
|
"env_requirements": {},
|
||||||
},
|
},
|
||||||
@@ -82,7 +82,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Jina Search Agent",
|
"display_name": "Jina Search Agent",
|
||||||
"description": "Jina AI 搜索 Agent",
|
"description": "Jina AI 搜索 Agent",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/jina-search-agent:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/jina-search-agent:latest",
|
||||||
"port": 8080,
|
"port": 8000,
|
||||||
"agent_framework": "api",
|
"agent_framework": "api",
|
||||||
"env_requirements": {
|
"env_requirements": {
|
||||||
"required": {
|
"required": {
|
||||||
@@ -94,7 +94,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Azure Blob Agent",
|
"display_name": "Azure Blob Agent",
|
||||||
"description": "Azure Blob 存储 Agent",
|
"description": "Azure Blob 存储 Agent",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent:latest",
|
||||||
"port": 8080,
|
"port": 8000,
|
||||||
"agent_framework": "api",
|
"agent_framework": "api",
|
||||||
"env_requirements": {
|
"env_requirements": {
|
||||||
"required": {
|
"required": {
|
||||||
@@ -106,7 +106,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Azure Blob Agent MCP",
|
"display_name": "Azure Blob Agent MCP",
|
||||||
"description": "Azure Blob 存储 Agent (MCP 协议)",
|
"description": "Azure Blob 存储 Agent (MCP 协议)",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent-mcp:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent-mcp:latest",
|
||||||
"port": 8080,
|
"port": 8000,
|
||||||
"agent_framework": "mcp",
|
"agent_framework": "mcp",
|
||||||
"env_requirements": {
|
"env_requirements": {
|
||||||
"required": {
|
"required": {
|
||||||
@@ -118,7 +118,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "Azure Blob Agent A2A",
|
"display_name": "Azure Blob Agent A2A",
|
||||||
"description": "Azure Blob 存储 Agent (A2A 协议)",
|
"description": "Azure Blob 存储 Agent (A2A 协议)",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent-a2a:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/azure-blob-agent-a2a:latest",
|
||||||
"port": 8080,
|
"port": 8000,
|
||||||
"agent_framework": "a2a",
|
"agent_framework": "a2a",
|
||||||
"env_requirements": {
|
"env_requirements": {
|
||||||
"required": {
|
"required": {
|
||||||
@@ -130,7 +130,7 @@ DEFAULT_TEMPLATES = {
|
|||||||
"display_name": "A2A LiteLLM Agent",
|
"display_name": "A2A LiteLLM Agent",
|
||||||
"description": "LiteLLM A2A 协议 Agent",
|
"description": "LiteLLM A2A 协议 Agent",
|
||||||
"image": "agnettaiji.azurecr.io/ai-agents/a2a-litellm-agent:latest",
|
"image": "agnettaiji.azurecr.io/ai-agents/a2a-litellm-agent:latest",
|
||||||
"port": 8080,
|
"port": 8000,
|
||||||
"agent_framework": "a2a",
|
"agent_framework": "a2a",
|
||||||
"env_requirements": {},
|
"env_requirements": {},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from datetime import datetime
|
|||||||
from typing import Dict, List, Optional, Any
|
from typing import Dict, List, Optional, Any
|
||||||
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from k8s_manager import sanitize_k8s_name
|
||||||
|
|
||||||
from gitee_manager import gitee_manager
|
from gitee_manager import gitee_manager
|
||||||
from agent_code_generator import agent_code_generator
|
from agent_code_generator import agent_code_generator
|
||||||
@@ -185,9 +186,9 @@ async def generate_agent(request: GenerateAgentRequest, background_tasks: Backgr
|
|||||||
"timeout": tool.timeout
|
"timeout": tool.timeout
|
||||||
})
|
})
|
||||||
|
|
||||||
# 生成完整项目文件(参考 http://gitee.ath.cx:3000/xiaohei/cicd-AKS)
|
# 生成完整项目文件(k8s_name 必须合规,否则 Service 创建会报 DNS-1035)
|
||||||
project_files = agent_code_generator.generate_full_project(
|
project_files = agent_code_generator.generate_full_project(
|
||||||
agent_name=request.agent_name,
|
agent_name=k8s_name_for_cicd,
|
||||||
description=request.description,
|
description=request.description,
|
||||||
tools_config=tools_config,
|
tools_config=tools_config,
|
||||||
auto_deploy=request.auto_deploy
|
auto_deploy=request.auto_deploy
|
||||||
@@ -261,9 +262,9 @@ async def generate_agent(request: GenerateAgentRequest, background_tasks: Backgr
|
|||||||
"created_at": datetime.utcnow().isoformat(),
|
"created_at": datetime.utcnow().isoformat(),
|
||||||
"status": "building",
|
"status": "building",
|
||||||
"auto_deploy": request.auto_deploy,
|
"auto_deploy": request.auto_deploy,
|
||||||
"image_name": f"agnettaiji.azurecr.io/ai-agents/{repo_name}:latest",
|
"image_name": f"agnettaiji.azurecr.io/ai-agents/{k8s_name_for_cicd}:latest",
|
||||||
"expected_domain": f"{k8s_name}.taijiagnet.com",
|
"expected_domain": f"{k8s_name_for_cicd}.taijiagnet.com",
|
||||||
"expected_namespace": f"agent-{k8s_name}"
|
"expected_namespace": f"agent-{k8s_name_for_cicd}"
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(f"✅ Agent 项目创建成功: {repo_name}")
|
logger.info(f"✅ Agent 项目创建成功: {repo_name}")
|
||||||
@@ -278,12 +279,12 @@ async def generate_agent(request: GenerateAgentRequest, background_tasks: Backgr
|
|||||||
"agent_ref_id": agent_ref_id,
|
"agent_ref_id": agent_ref_id,
|
||||||
"repo_name": repo_name,
|
"repo_name": repo_name,
|
||||||
"repo_url": repo_result.get("html_url"),
|
"repo_url": repo_result.get("html_url"),
|
||||||
"image_name": f"agnettaiji.azurecr.io/ai-agents/{repo_name}:latest",
|
"image_name": f"agnettaiji.azurecr.io/ai-agents/{k8s_name_for_cicd}:latest",
|
||||||
"status": "building",
|
"status": "building",
|
||||||
"files_pushed": len(project_files),
|
"files_pushed": len(project_files),
|
||||||
"tools_count": len(request.tools),
|
"tools_count": len(request.tools),
|
||||||
"expected_domain": expected_domain,
|
"expected_domain": expected_domain,
|
||||||
"expected_namespace": f"agent-{k8s_name}"
|
"expected_namespace": f"agent-{k8s_name_for_cicd}"
|
||||||
},
|
},
|
||||||
"message": f"Agent 项目已创建并推送到 Gitee,CI/CD 正在构建中。部署后访问: http://{expected_domain}"
|
"message": f"Agent 项目已创建并推送到 Gitee,CI/CD 正在构建中。部署后访问: http://{expected_domain}"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user