15 KiB
Agent 域名访问改动计划
版本: 2026-01-14 v1
状态: ✅ 已完成
相关服务: mcp-server, agent-manager 完成时间: 2026-01-14
📋 背景与需求
业务变更说明
- Agent Manager 服务升级:部署好的每个 Pod 现在会自动绑定域名和外网 IP
- 访问方式变更:租户后续将使用域名访问属于自己的平台 Agent 和自定义 Agent
- 数据存储需求:需要记录 Agent Manager 返回的访问信息(domain、external_ip 等)
Agent Manager 返回的 access_info 结构
{
"access_info": {
"external_ip": "135.171.210.24",
"ip_url": "http://135.171.210.24:80",
"domain": "my-agent.taijiagent.com",
"domain_url": "http://my-agent.taijiagent.com",
"recommended": "http://my-agent.taijiagent.com"
}
}
🔍 当前代码分析
1. 数据库模型现状
Agent 模型 (models.py:125)
class Agent(BaseModel, Base):
# ... 已有字段
access_url = Column(String(500)) # 访问 URL(单个字段)
endpoints = Column(JSON, default=dict) # 端点信息
# ❌ 缺少 domain、external_ip 等字段
AgentBillingRecord 模型 (models.py:1157)
class AgentBillingRecord(BaseModel, Base):
# ... 已有字段
agent_name = Column(String(100), nullable=False)
# ❌ 缺少 access_info 相关字段(domain、external_ip、access_url)
2. Agent Manager Client 现状
AgentCreateResult (agent_manager_client.py:97)
@dataclass
class AgentCreateResult:
name: str
namespace: str
status: str
access_info: Optional[Dict[str, Any]] = None # ✅ 已有,但未完整使用
AgentStatusResult (agent_manager_client.py:119)
@dataclass
class AgentStatusResult:
# ❌ 缺少 domain、external_ip 等字段
access_url: Optional[str] = None # 只有单个 access_url
endpoints: Optional[List[str]] = None
3. 创建 Agent 代码现状
平台 Agent 创建 (user.py:1427-1439)
result = await client.create_agent(...)
# 创建 Agent 记录时
agent = Agent(
name=instance_name,
# ❌ 未保存 result.access_info 中的 domain、external_ip
)
自定义 Agent 创建 (user.py:3146-3157)
result = await client.create_custom_agent(...)
# ❌ 响应中只返回了 accessInfo,未持久化 domain 到数据库
return SuccessResponse(
data={
"accessInfo": result.access_info, # 只是透传,未存储
}
)
4. 查询 Agent 列表代码现状
用户 Agent 资源查询 (user.py:3904-3999)
@router.get("/resources/agents")
async def get_user_agents_info(...):
# 从 Agent Manager 获取状态
agent_status = await client.get_agent_status(record.agent_name)
agent_info["accessUrl"] = agent_status.access_url # ❌ 只返回 access_url
# ❌ 缺少 domain、external_ip 等字段
✅ 改动方案
阶段一:数据库模型改动
1.1 修改 AgentBillingRecord 模型
文件: services/mcp-server/models.py
class AgentBillingRecord(BaseModel, Base):
# ... 已有字段
# ========== 新增:访问信息字段 ==========
external_ip = Column(String(45), nullable=True) # 外网 IP 地址
domain = Column(String(255), nullable=True) # 域名
domain_url = Column(String(500), nullable=True) # 域名访问地址
access_url = Column(String(500), nullable=True) # 推荐访问地址
service_port = Column(Integer, nullable=True) # 服务端口
namespace = Column(String(100), nullable=True) # K8s 命名空间
1.2 创建数据库迁移脚本
文件: services/mcp-server/alembic/versions/xxxx_add_agent_access_info.py
"""Add agent access info fields
Revision ID: xxxx
"""
def upgrade():
op.add_column('agent_billing_records',
sa.Column('external_ip', sa.String(45), nullable=True))
op.add_column('agent_billing_records',
sa.Column('domain', sa.String(255), nullable=True))
op.add_column('agent_billing_records',
sa.Column('domain_url', sa.String(500), nullable=True))
op.add_column('agent_billing_records',
sa.Column('access_url', sa.String(500), nullable=True))
op.add_column('agent_billing_records',
sa.Column('service_port', sa.Integer, nullable=True))
op.add_column('agent_billing_records',
sa.Column('namespace', sa.String(100), nullable=True))
# 添加索引(可选,用于按域名查询)
op.create_index('idx_agent_billing_domain', 'agent_billing_records', ['domain'])
def downgrade():
op.drop_index('idx_agent_billing_domain', 'agent_billing_records')
op.drop_column('agent_billing_records', 'namespace')
op.drop_column('agent_billing_records', 'service_port')
op.drop_column('agent_billing_records', 'access_url')
op.drop_column('agent_billing_records', 'domain_url')
op.drop_column('agent_billing_records', 'domain')
op.drop_column('agent_billing_records', 'external_ip')
阶段二:Agent Manager Client 改动
2.1 修改 AgentStatusResult
文件: services/mcp-server/app/agent_manager_client.py
@dataclass
class AgentStatusResult:
# ... 已有字段
# ========== 新增:访问信息字段 ==========
external_ip: Optional[str] = None # 外网 IP
domain: Optional[str] = None # 域名
domain_url: Optional[str] = None # 域名访问地址
2.2 修改 get_agent_status 方法解析逻辑
文件: services/mcp-server/app/agent_manager_client.py
在 get_agent_status 方法中,需要解析 Agent Manager 返回的 access_info:
async def get_agent_status(self, name: str) -> AgentStatusResult:
# ... 现有逻辑
# 解析 access_info
access_info = data.get("access_info", {})
return AgentStatusResult(
# ... 现有字段
external_ip=access_info.get("external_ip"),
domain=access_info.get("domain"),
domain_url=access_info.get("domain_url"),
access_url=access_info.get("recommended") or access_info.get("domain_url"),
)
阶段三:创建 Agent 代码改动
3.1 平台 Agent 创建改动
文件: services/mcp-server/app/routes/user.py
位置: list_platform_agents / deploy_platform_agent 函数
# 在创建 billing_record 时保存 access_info
billing_record = AgentBillingRecord(
# ... 已有字段
# ========== 新增:保存访问信息 ==========
external_ip=result.access_info.get("external_ip") if result.access_info else None,
domain=result.access_info.get("domain") if result.access_info else None,
domain_url=result.access_info.get("domain_url") if result.access_info else None,
access_url=result.access_info.get("recommended") if result.access_info else None,
service_port=result.service_port,
namespace=result.namespace,
)
3.2 自定义 Agent 创建改动
文件: services/mcp-server/app/routes/user.py
位置: create_custom_agent 函数(约第 3146-3213 行)
# 在创建 billing_record 时保存 access_info
billing_record = AgentBillingRecord(
# ... 已有字段
# ========== 新增:保存访问信息 ==========
external_ip=result.access_info.get("external_ip") if result.access_info else None,
domain=result.access_info.get("domain") if result.access_info else None,
domain_url=result.access_info.get("domain_url") if result.access_info else None,
access_url=result.access_info.get("recommended") if result.access_info else None,
service_port=result.service_port,
namespace=result.namespace,
)
阶段四:查询 Agent 列表改动
4.1 用户 Agent 资源查询改动
文件: services/mcp-server/app/routes/user.py
位置: get_user_agents_info 函数(约第 3904-3999 行)
@router.get("/resources/agents", response_model=SuccessResponse)
async def get_user_agents_info(...):
for record in billing_records:
agent_info = {
# ... 已有字段
# ========== 新增:访问信息字段(优先使用数据库存储的值) ==========
"externalIp": record.external_ip,
"domain": record.domain,
"domainUrl": record.domain_url,
"accessUrl": record.access_url, # 推荐访问地址
}
# 从 Agent Manager 获取最新状态(实时更新 IP 等信息)
if agent_manager_available and client:
try:
agent_status = await client.get_agent_status(record.agent_name)
# 更新实时状态
agent_info["status"] = agent_status.status
agent_info["healthStatus"] = agent_status.health_status
agent_info["podIp"] = agent_status.pod_ip
# 更新访问信息(如果 Agent Manager 返回了新的值)
if agent_status.external_ip:
agent_info["externalIp"] = agent_status.external_ip
if agent_status.domain:
agent_info["domain"] = agent_status.domain
if agent_status.domain_url:
agent_info["domainUrl"] = agent_status.domain_url
if agent_status.access_url:
agent_info["accessUrl"] = agent_status.access_url
except Exception as e:
logger.warning(f"获取 Agent {record.agent_name} 状态失败: {e}")
4.2 自定义 Agent 列表查询改动
文件: services/mcp-server/app/routes/user.py
位置: list_my_custom_agents 函数(约第 3462-3516 行)
同样需要添加 domain 等字段的返回。
阶段五:响应模型改动
5.1 添加/修改 Schema
文件: services/mcp-server/app/schemas.py 或 services/mcp-server/schemas.py
class AgentAccessInfo(BaseModel):
"""Agent 访问信息"""
external_ip: Optional[str] = Field(None, description="外网 IP 地址")
domain: Optional[str] = Field(None, description="域名")
domain_url: Optional[str] = Field(None, description="域名访问地址")
ip_url: Optional[str] = Field(None, description="IP 访问地址")
recommended: Optional[str] = Field(None, description="推荐访问地址")
class AgentResourceInfo(BaseModel):
"""用户 Agent 资源信息"""
name: str
template: str
templateName: Optional[str] = None
status: str
healthStatus: str
# Pod 信息
podIp: Optional[str] = None
hostIp: Optional[str] = None
nodeName: Optional[str] = None
# ========== 新增:访问信息 ==========
externalIp: Optional[str] = Field(None, description="外网 IP 地址")
domain: Optional[str] = Field(None, description="域名")
domainUrl: Optional[str] = Field(None, description="域名访问地址")
accessUrl: Optional[str] = Field(None, description="推荐访问地址(域名优先)")
# 资源配置
servicePort: Optional[int] = None
namespace: str = "ai-agents"
cpu: Optional[str] = None
memory: Optional[str] = None
replicas: int = 1
# 运行信息
startTime: Optional[str] = None
runningSeconds: int = 0
endpoints: Optional[List[str]] = None
📄 接口文档更新
GET /api/user/resources/agents 响应更新
{
"success": true,
"data": {
"platformAgents": [
{
"name": "echo-agent-b00a7b8e-fa5a66",
"template": "echo_agent",
"templateName": "echo_agent",
"status": "Running",
"healthStatus": "healthy",
"podIp": "10.244.2.103",
"externalIp": "135.171.210.24",
"domain": "echo-agent-b00a7b8e-fa5a66.taijiagent.com",
"domainUrl": "http://echo-agent-b00a7b8e-fa5a66.taijiagent.com",
"accessUrl": "http://echo-agent-b00a7b8e-fa5a66.taijiagent.com",
"servicePort": 80,
"namespace": "agent-echo-agent-b00a7b8e-fa5a66",
"cpu": "100m",
"memory": "256Mi",
"replicas": 1,
"startTime": "2026-01-11T15:17:17.579421",
"runningSeconds": 227937
}
],
"customAgents": [
{
"name": "my-mysql-agent",
"template": "mysql_agent",
"templateName": "MCP",
"status": "Running",
"healthStatus": "healthy",
"podIp": "10.244.1.61",
"externalIp": "135.171.210.25",
"domain": "my-mysql-agent.taijiagent.com",
"domainUrl": "http://my-mysql-agent.taijiagent.com",
"accessUrl": "http://my-mysql-agent.taijiagent.com",
"servicePort": 80,
"namespace": "agent-my-mysql-agent",
"cpu": "500m",
"memory": "1Gi",
"replicas": 1,
"startTime": "2026-01-13T07:32:52.290231",
"runningSeconds": 83003
}
],
"summary": {
"totalPlatformAgents": 1,
"totalCustomAgents": 1
}
},
"message": "Agent 列表获取成功"
}
📝 改动文件清单
| 序号 | 文件路径 | 改动类型 | 改动说明 |
|---|---|---|---|
| 1 | services/mcp-server/models.py |
修改 | AgentBillingRecord 添加访问信息字段 |
| 2 | services/mcp-server/alembic/versions/xxx.py |
新增 | 数据库迁移脚本 |
| 3 | services/mcp-server/app/agent_manager_client.py |
修改 | AgentStatusResult 添加 domain 等字段 |
| 4 | services/mcp-server/app/routes/user.py |
修改 | 创建 Agent 时保存 access_info |
| 5 | services/mcp-server/app/routes/user.py |
修改 | 查询 Agent 列表返回 domain 等字段 |
| 6 | services/mcp-server/app/schemas.py |
修改 | 添加/修改响应模型 |
| 7 | Docs/用户资源信息查询接口文档.md |
修改 | 更新接口文档 |
| 8 | Docs/数据工具与自定义Agent-前端接口文档.md |
修改 | 更新接口文档 |
🔄 实施步骤
Step 1: 数据库改动(需要停机)
- 备份数据库
- 执行数据库迁移脚本
- 验证迁移结果
Step 2: 代码改动
- 修改
models.py - 修改
agent_manager_client.py - 修改
user.py中的创建 Agent 逻辑 - 修改
user.py中的查询 Agent 逻辑 - 修改响应模型
Step 3: 测试验证
- 单元测试
- 集成测试(创建 Agent → 查询列表 → 访问域名)
- 前端联调
Step 4: 文档更新
- 更新 API 接口文档
- 更新前端接口文档
⚠️ 注意事项
- 向后兼容:新增字段均为可选(nullable=True),不影响现有数据
- 域名生效时间:域名 DNS 解析可能有延迟(通常 1-5 分钟)
- 访问优先级:推荐使用
accessUrl(域名优先),Pod IP 会随重启变化 - 安全考虑:域名访问可能需要配置 HTTPS(后续考虑)
📊 预估工时
| 阶段 | 工时估算 |
|---|---|
| 数据库改动 | 0.5 天 |
| Agent Manager Client 改动 | 0.5 天 |
| 创建 Agent 代码改动 | 1 天 |
| 查询 Agent 列表改动 | 0.5 天 |
| 测试与联调 | 1 天 |
| 文档更新 | 0.5 天 |
| 总计 | 4 天 |
文档编写: AI Assistant
最后更新: 2026-01-14