forked from xiaohei/taiji-AI-PAD
更新爆改前的备份
This commit is contained in:
+16
-6
@@ -7,7 +7,7 @@ metadata:
|
||||
labels:
|
||||
app: data-ingestion
|
||||
spec:
|
||||
replicas: 2
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: data-ingestion
|
||||
@@ -24,6 +24,9 @@ spec:
|
||||
- containerPort: 8000
|
||||
name: http
|
||||
env:
|
||||
# 环境标识
|
||||
- name: ENVIRONMENT
|
||||
value: "production"
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -85,15 +88,22 @@ spec:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 5
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 5
|
||||
|
||||
# ACR 镜像拉取凭据
|
||||
imagePullSecrets:
|
||||
- name: acr-secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
+2
-1
@@ -22,8 +22,9 @@ stringData:
|
||||
# ===========================================
|
||||
# Redis配置 (Azure Cache for Redis with SSL)
|
||||
# 端口 10000 使用 SSL 连接
|
||||
# 注意:Redis 已迁移到 taiji2026 实例
|
||||
# ===========================================
|
||||
redis-url: "rediss://:nkJgt1ERFpdeYrEFNyFtsc5K4ycvx2jIeAzCaGGf1OQ%3D@taiji.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
redis-url: "rediss://:PzmWkM6CwfRrJTB1d2xLRxE9pzT7JKgvVAzCaEehmFE=@taiji2026.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
|
||||
# ===========================================
|
||||
# JWT配置
|
||||
|
||||
@@ -33,6 +33,7 @@ def register_lifecycle_events(app: FastAPI) -> None:
|
||||
state = get_state()
|
||||
settings = state.settings
|
||||
|
||||
# Redis 连接(允许失败,服务继续运行)
|
||||
try:
|
||||
state.redis_client = redis.from_url(
|
||||
settings.redis_url,
|
||||
@@ -42,11 +43,23 @@ def register_lifecycle_events(app: FastAPI) -> None:
|
||||
await state.redis_client.ping()
|
||||
redis_connections.set(1)
|
||||
logger.info("Redis连接成功")
|
||||
except Exception as redis_exc:
|
||||
logger.warning("Redis连接失败,服务将继续运行(无缓存功能)", error=str(redis_exc))
|
||||
state.redis_client = None
|
||||
redis_connections.set(0)
|
||||
|
||||
# NATS 连接(允许失败)
|
||||
try:
|
||||
state.nats_client = await nats.connect(settings.nats_url)
|
||||
nats_connections.set(1)
|
||||
logger.info("NATS连接成功")
|
||||
except Exception as nats_exc:
|
||||
logger.warning("NATS连接失败,消息功能不可用", error=str(nats_exc))
|
||||
state.nats_client = None
|
||||
nats_connections.set(0)
|
||||
|
||||
# 初始化其他组件
|
||||
try:
|
||||
state.rapidapi_client = RapidAPIClient(
|
||||
api_key=settings.rapidapi_key,
|
||||
host=settings.rapidapi_host,
|
||||
|
||||
@@ -1495,6 +1495,22 @@ class AgentManagerClient:
|
||||
|
||||
data = await self._request("POST", "/external-tools/agents/create-with-tools", json=payload)
|
||||
|
||||
# 检查业务逻辑是否成功(agent-manager 可能返回 HTTP 200 但 success=false)
|
||||
if isinstance(data, dict) and data.get("success") is False:
|
||||
error_code = data.get("error", "unknown_error")
|
||||
error_message = data.get("message", "创建 Agent 失败")
|
||||
logger.error(
|
||||
"create_agent_with_tools_failed",
|
||||
name=name,
|
||||
error_code=error_code,
|
||||
error_message=error_message
|
||||
)
|
||||
raise AgentManagerError(
|
||||
message=error_message,
|
||||
status_code=400,
|
||||
detail={"error": error_code, "message": error_message}
|
||||
)
|
||||
|
||||
return AgentCreateResult(
|
||||
name=data["name"],
|
||||
namespace=data["namespace"],
|
||||
|
||||
@@ -2238,6 +2238,21 @@ async def get_available_platform_agents(
|
||||
template_configs_result = await db.execute(select(PlatformAgentTemplateConfig))
|
||||
template_configs = {config.template_name: config for config in template_configs_result.scalars().all()}
|
||||
|
||||
# 查询实际运行的agent数量(基于计费记录)
|
||||
running_count_result = await db.execute(
|
||||
select(
|
||||
AgentBillingRecord.agent_type,
|
||||
func.count().label("count")
|
||||
).where(
|
||||
and_(
|
||||
AgentBillingRecord.user_id == user_id,
|
||||
AgentBillingRecord.is_platform_agent == True,
|
||||
AgentBillingRecord.end_time.is_(None) # 正在运行
|
||||
)
|
||||
).group_by(AgentBillingRecord.agent_type)
|
||||
)
|
||||
running_counts = {row.agent_type: row.count for row in running_count_result.all()}
|
||||
|
||||
agents = []
|
||||
for quota in quotas:
|
||||
# 从模板配置中获取管理员设置的CPU和内存限制
|
||||
@@ -2245,20 +2260,35 @@ async def get_available_platform_agents(
|
||||
cpu_limit = template_config.cpu_limit if template_config and template_config.cpu_limit else "100m"
|
||||
memory_limit = template_config.memory_limit if template_config and template_config.memory_limit else "256Mi"
|
||||
|
||||
# 使用实际运行的agent数量,而不是数据库中的pod_used
|
||||
actual_used = running_counts.get(quota.template_name, 0)
|
||||
|
||||
# 如果数据库中的pod_used与实际不符,同步更新
|
||||
if quota.pod_used != actual_used:
|
||||
quota.pod_used = actual_used
|
||||
logger.warning(
|
||||
f"同步配额使用数: {quota.template_name} {quota.pod_used} -> {actual_used}",
|
||||
user_id=user_id,
|
||||
template=quota.template_name
|
||||
)
|
||||
|
||||
agents.append({
|
||||
"id": str(quota.id),
|
||||
"templateName": quota.template_name,
|
||||
"displayName": quota.template_name.replace("-", " ").replace("_", " ").title(),
|
||||
"description": f"Platform Agent: {quota.template_name}",
|
||||
"podQuota": quota.pod_quota,
|
||||
"podUsed": quota.pod_used,
|
||||
"podRemaining": quota.pod_quota - quota.pod_used,
|
||||
"podUsed": actual_used, # 使用实际运行数量
|
||||
"podRemaining": quota.pod_quota - actual_used,
|
||||
"cpuLimit": cpu_limit,
|
||||
"memoryLimit": memory_limit,
|
||||
"category": "platform",
|
||||
"allocatedAt": quota.allocated_at.isoformat() if quota.allocated_at else None,
|
||||
})
|
||||
|
||||
# 提交配额同步更新
|
||||
await db.commit()
|
||||
|
||||
return SuccessResponse(data={"agents": agents})
|
||||
|
||||
|
||||
@@ -3169,44 +3199,44 @@ async def create_custom_agent(
|
||||
client = get_agent_manager_client()
|
||||
|
||||
# ========== 自定义 Agent:使用外部数据工具创建 ==========
|
||||
# 工具已在 Agent Manager 生成(有 tool_ref_id),直接使用 tool_refs 创建 Agent
|
||||
# 工具已在 Agent Manager 生成(有 tool_ref_id),直接使用 tool_refs 创建 Agent
|
||||
# =======================================================
|
||||
|
||||
if not external_tool_refs:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="没有可用的外部数据工具(需要 tool_ref_id)"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
|
||||
if not external_tool_refs:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="没有可用的外部数据工具(需要 tool_ref_id)"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"创建自定义 Agent: name={req.name}, tool_refs={external_tool_refs}"
|
||||
)
|
||||
|
||||
# 创建 Agent 配置
|
||||
agent_config = AgentConfig(
|
||||
user_id=str(user_id),
|
||||
cpu_request=req.cpuRequest,
|
||||
)
|
||||
|
||||
# 创建 Agent 配置
|
||||
agent_config = AgentConfig(
|
||||
user_id=str(user_id),
|
||||
cpu_request=req.cpuRequest,
|
||||
cpu_limit=req.cpuRequest, # limit 默认和 request 一致
|
||||
memory_request=req.memoryRequest,
|
||||
memory_request=req.memoryRequest,
|
||||
memory_limit=req.memoryRequest, # limit 默认和 request 一致
|
||||
replicas=1,
|
||||
)
|
||||
|
||||
# 调用 create_agent_with_tools(使用 /external-tools/agents/create-with-tools 接口)
|
||||
replicas=1,
|
||||
)
|
||||
|
||||
# 调用 create_agent_with_tools(使用 /external-tools/agents/create-with-tools 接口)
|
||||
# template 默认和 name 一致
|
||||
template_name = req.name
|
||||
result = await client.create_agent_with_tools(
|
||||
name=req.name,
|
||||
result = await client.create_agent_with_tools(
|
||||
name=req.name,
|
||||
template=template_name,
|
||||
tool_refs=external_tool_refs,
|
||||
config=agent_config,
|
||||
env=env_vars
|
||||
)
|
||||
|
||||
logger.info(
|
||||
tool_refs=external_tool_refs,
|
||||
config=agent_config,
|
||||
env=env_vars
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"自定义 Agent 创建成功: name={req.name}, "
|
||||
f"status={result.status}, tool_count={len(external_tool_refs)}"
|
||||
)
|
||||
f"status={result.status}, tool_count={len(external_tool_refs)}"
|
||||
)
|
||||
|
||||
try:
|
||||
# 更新配额使用量
|
||||
|
||||
@@ -34,7 +34,8 @@ class Settings(BaseSettings):
|
||||
)
|
||||
|
||||
# Redis设置(Azure Cache for Redis)
|
||||
redis_url: str = "rediss://:nkJgt1ERFpdeYrEFNyFtsc5K4ycvx2jIeAzCaGGf1OQ%3D@taiji.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
# 注意:Redis 已迁移到 taiji2026 实例
|
||||
redis_url: str = "rediss://:PzmWkM6CwfRrJTB1d2xLRxE9pzT7JKgvVAzCaEehmFE=@taiji2026.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
redis_max_connections: int = 20
|
||||
redis_retry_on_timeout: bool = True
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ stringData:
|
||||
# 数据库连接字符串 - 使用 taiji 数据库
|
||||
database-url: "postgresql+asyncpg://taiji:PASSWORD@taijipda.postgres.database.azure.com:5432/taiji?sslmode=require"
|
||||
|
||||
# Redis连接字符串
|
||||
redis-url: "rediss://:REDIS_PASSWORD@taiji.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
# Redis连接字符串(Redis 已迁移到 taiji2026 实例)
|
||||
redis-url: "rediss://:PzmWkM6CwfRrJTB1d2xLRxE9pzT7JKgvVAzCaEehmFE=@taiji2026.southeastasia.redis.azure.net:10000/0?ssl_cert_reqs=none"
|
||||
|
||||
# JWT密钥
|
||||
jwt-secret: "CHANGE_THIS_SECRET_KEY_IN_PRODUCTION"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
-- 018: 修复 agent_billing_records 表 agent_type 字段长度
|
||||
-- 问题: microsoft_learn_agent (22字符) 超出 VARCHAR(20) 限制
|
||||
-- 解决: 将 agent_type 字段从 VARCHAR(20) 扩展到 VARCHAR(100)
|
||||
|
||||
ALTER TABLE agent_billing_records ALTER COLUMN agent_type TYPE VARCHAR(100);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
运行 018 迁移:修复 agent_billing_records 表 agent_type 字段长度
|
||||
问题: microsoft_learn_agent (22字符) 超出 VARCHAR(20) 限制
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到 Python 路径
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
import asyncpg
|
||||
|
||||
|
||||
async def run_migration():
|
||||
"""执行迁移"""
|
||||
# 获取数据库连接信息
|
||||
database_url = os.getenv(
|
||||
"DATABASE_URL",
|
||||
"postgresql://postgres:postgres@localhost:5432/mcp_server"
|
||||
)
|
||||
|
||||
# 解析连接字符串
|
||||
if database_url.startswith("postgresql://"):
|
||||
# 转换为 asyncpg 格式
|
||||
database_url = database_url.replace("postgresql://", "postgres://")
|
||||
|
||||
print(f"连接数据库: {database_url.split('@')[1] if '@' in database_url else database_url}")
|
||||
|
||||
try:
|
||||
conn = await asyncpg.connect(database_url)
|
||||
print("数据库连接成功")
|
||||
|
||||
# 读取 SQL 文件
|
||||
sql_file = Path(__file__).parent / "018_fix_agent_type_length.sql"
|
||||
with open(sql_file, "r", encoding="utf-8") as f:
|
||||
sql = f.read()
|
||||
|
||||
print("执行迁移 SQL...")
|
||||
print(f"SQL: {sql}")
|
||||
await conn.execute(sql)
|
||||
print("迁移执行成功!")
|
||||
|
||||
# 验证字段类型
|
||||
result = await conn.fetchrow(
|
||||
"""
|
||||
SELECT character_maximum_length
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'agent_billing_records'
|
||||
AND column_name = 'agent_type'
|
||||
"""
|
||||
)
|
||||
if result and result['character_maximum_length'] == 100:
|
||||
print("✅ agent_type 字段已扩展到 VARCHAR(100)")
|
||||
else:
|
||||
print(f"❌ 字段验证失败: {result}")
|
||||
|
||||
await conn.close()
|
||||
|
||||
except Exception as e:
|
||||
print(f"迁移失败: {e}")
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_migration())
|
||||
|
||||
Reference in New Issue
Block a user