forked from xiaohei/taiji-AI-PAD
16 KiB
16 KiB
数据工具与自定义Agent - 功能修复文档
创建日期: 2026-01-13
状态: 待修复
优先级: 高
1. 问题概述
当前实现与预期业务逻辑不一致
预期业务逻辑:
- 前端获取
dataTemplates(Agent 模板列表,如mysql_agent、postgresql_agent) - 用户选择模板,根据模板的
env_info填写配置值(如 MySQL 连接信息),保存为工具 - 用户创建自定义 Agent 时选择已创建的工具
- MCP-Server 从工具中获取模板类型和配置,传递给 Agent Manager 创建对应的 Agent
当前实现问题:
- Tool 模型设计为通用 API 调用配置(endpoint、method、schema)
- 缺少
template字段:无法关联 Agent 模板 - 缺少
env_config字段:无法存储模板所需的环境变量配置 - 创建 Agent 时,工具只作为附加的 API 能力,而不是决定 Agent 类型的关键信息
2. 正确的业务流程
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 正确的业务流程 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ① 获取模板列表 ② 创建工具(基于模板) ③ 创建Agent(选择工具) │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ GET │ │ POST │ │ POST │ │
│ │ /templates │──────→│ /tools/create │───────────→│ /custom-agents│ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │ │ │ │
│ ↓ ↓ ↓ │
│ 返回 dataTemplates 保存到 Tool 表 从工具获取 template │
│ [mysql_agent, - template: mysql_agent 和 envConfig, │
│ postgresql_agent] - envConfig: { 传递给 Agent Manager │
│ MYSQL_HOST: "...", │
│ 含 env_info: MYSQL_USER: "...", │
│ - required ... │
│ - optional } │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
关键概念
| 概念 | 说明 |
|---|---|
| 模板 (template) | Agent Manager 提供的镜像类型,如 mysql_agent,包含 env_info 定义所需配置 |
| 工具 (Tool) | 用户基于模板创建的配置实例,包含 template + 填写好的 envConfig |
| 自定义 Agent | 根据工具的模板类型和配置创建的 K8s Pod |
3. 需要修改的内容
3.1 数据库模型修改
文件: services/mcp-server/models.py
修改 Tool 模型,添加字段:
class Tool(BaseModel, Base):
"""工具模型"""
__tablename__ = "tools"
name = Column(String(100), nullable=False)
description = Column(Text)
category = Column(String(50)) # database, api, function 等
# ========== 新增:模板相关字段 ==========
template = Column(String(100)) # 模板名称,如 "mysql_agent", "postgresql_agent"
env_config = Column(JSON, default=dict) # 环境变量配置,根据模板 env_info 填写
# =========================================
# 工具定义(保留,用于自定义 API 工具)
schema = Column(JSON) # 改为可空,模板工具不需要
endpoint = Column(String(500))
method = Column(String(10), default="POST")
# ... 其他字段保持不变
3.2 创建工具接口修改
文件: services/mcp-server/app/routes/user.py
修改 POST /api/user/tools/create 接口:
@router.post("/tools/create", response_model=SuccessResponse)
async def create_tool(
req: dict,
principal: dict = Depends(require_auth),
db: AsyncSession = Depends(get_db)
):
"""
创建工具(基于模板)
请求体示例(MySQL 工具):
{
"name": "my-mysql-tool",
"description": "我的MySQL数据库连接工具",
"template": "mysql_agent",
"envConfig": {
"MYSQL_HOST": "mysql.example.com",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "password123",
"MYSQL_DATABASE": "mydb",
"MYSQL_PORT": "3306",
"OPENAI_API_KEY": "sk-xxx"
}
}
"""
user_id = principal.get("user_id")
# 验证模板名称
template_name = req.get("template")
if template_name:
# 从 Agent Manager 获取模板列表并验证
try:
from app.agent_manager_client import get_agent_manager_client, AgentManagerError
client = get_agent_manager_client()
custom_templates = await client.list_custom_templates()
template_names = [t.template for t in custom_templates]
if template_name not in template_names:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"无效的模板名称: {template_name}。支持的模板: {', '.join(template_names)}"
)
except AgentManagerError:
pass # Agent Manager 不可用时跳过验证
# 检查工具名称是否已存在
result = await db.execute(
select(Tool).where(
and_(
Tool.owner_id == user_id,
Tool.name == req.get("name")
)
)
)
existing_tool = result.scalar_one_or_none()
if existing_tool:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"工具名称 '{req.get('name')}' 已存在"
)
# 创建工具
tool = Tool(
name=req.get("name"),
description=req.get("description"),
category="database" if template_name else req.get("type", "api"),
template=template_name, # 新增
env_config=req.get("envConfig", {}), # 新增
schema=req.get("config", {}).get("schema") if not template_name else None,
endpoint=req.get("config", {}).get("endpoint") if not template_name else None,
method=req.get("config", {}).get("method", "GET") if not template_name else None,
auth_config={"apiKey": req.get("config", {}).get("apiKey")} if req.get("config", {}).get("apiKey") else {},
owner_id=user_id,
is_active=True,
is_public=False,
)
db.add(tool)
await db.commit()
await db.refresh(tool)
return SuccessResponse(
data={
"id": str(tool.id),
"name": tool.name,
"template": tool.template,
},
message="工具创建成功"
)
3.3 创建自定义 Agent 接口修改
文件: services/mcp-server/app/routes/user.py
修改 POST /api/user/custom-agents 接口的工具处理逻辑:
@router.post("/custom-agents", response_model=SuccessResponse)
async def create_custom_agent(
req: CreateCustomAgentRequest,
principal: dict = Depends(require_auth),
db: AsyncSession = Depends(get_db)
):
"""
创建自定义 Agent
新逻辑:从选中的工具获取模板类型和环境变量配置
"""
# ... 配额检查等代码保持不变 ...
# ========== 新增:从工具获取模板和配置 ==========
template_name = req.template # 默认使用请求中的 template
env_vars = req.envConfig or {}
if req.tools and len(req.tools) > 0:
# 查询第一个工具(主工具,决定 Agent 类型)
primary_tool_id = req.tools[0]
try:
tool_result = await db.execute(
select(Tool).where(
Tool.id == PyUUID(primary_tool_id),
or_(
Tool.is_public == True,
Tool.owner_id == PyUUID(user_id)
)
)
)
primary_tool = tool_result.scalar_one_or_none()
if primary_tool and primary_tool.template:
# 使用工具的模板类型
template_name = primary_tool.template
# 合并工具的环境变量配置
if primary_tool.env_config:
env_vars = {**primary_tool.env_config, **env_vars}
logger.info(
f"从工具获取配置: tool_id={primary_tool_id}, "
f"template={template_name}, env_keys={list(env_vars.keys())}"
)
except Exception as e:
logger.warning(f"查询工具失败: {str(e)}")
# ================================================
# 验证模板
try:
client = get_agent_manager_client()
custom_templates = await client.list_custom_templates()
template_names = [t.template for t in custom_templates]
if template_name not in template_names:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"无效的模板名称: {template_name}。支持的模板: {', '.join(template_names)}"
)
except AgentManagerError as e:
logger.warning(f"无法获取模板列表,跳过验证: {str(e)}")
# ... 后续代码使用 template_name 和 env_vars 创建 Agent ...
3.4 获取用户工具列表接口修改
文件: services/mcp-server/app/routes/user.py
修改 GET /api/user/tools 响应格式:
@router.get("/tools", response_model=SuccessResponse)
async def get_user_tools(
principal: dict = Depends(require_auth),
db: AsyncSession = Depends(get_db)
):
"""获取用户创建的所有工具"""
user_id = principal.get("user_id")
result = await db.execute(
select(Tool)
.where(Tool.owner_id == user_id)
.order_by(desc(Tool.created_at))
)
tools = result.scalars().all()
tools_data = []
for tool in tools:
tools_data.append({
"id": str(tool.id),
"name": tool.name,
"description": tool.description,
"template": tool.template, # 新增
"category": tool.category,
"envConfig": tool.env_config, # 新增(注意:敏感信息如密码应脱敏)
"created_at": tool.created_at.isoformat() if tool.created_at else None,
"updated_at": tool.updated_at.isoformat() if tool.updated_at else None,
"is_active": tool.is_active,
})
return SuccessResponse(data={"tools": tools_data})
3.5 数据库迁移
需要创建数据库迁移脚本,添加新字段:
-- 添加 template 字段
ALTER TABLE tools ADD COLUMN template VARCHAR(100);
-- 添加 env_config 字段
ALTER TABLE tools ADD COLUMN env_config JSON DEFAULT '{}';
-- 创建索引
CREATE INDEX idx_tool_template ON tools(template);
4. 更新后的接口文档
4.1 创建工具(基于模板)
接口: POST /api/user/tools/create
请求参数:
interface CreateToolRequest {
name: string; // 工具名称(必填)
description?: string; // 工具描述
template: string; // 模板名称(必填,来自 dataTemplates[].template)
envConfig: Record<string, string>; // 环境变量配置(必填,根据模板 env_info 填写)
}
请求示例(MySQL 工具):
{
"name": "my-mysql-tool",
"description": "我的MySQL数据库连接工具",
"template": "mysql_agent",
"envConfig": {
"MYSQL_HOST": "mysql.example.com",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "password123",
"MYSQL_DATABASE": "mydb",
"MYSQL_PORT": "3306",
"OPENAI_API_KEY": "sk-xxx"
}
}
请求示例(PostgreSQL 工具):
{
"name": "my-pgsql-tool",
"description": "我的PostgreSQL数据库连接工具",
"template": "postgresql_agent",
"envConfig": {
"POSTGRES_HOST": "postgres.example.com",
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "password123",
"POSTGRES_DATABASE": "mydb",
"POSTGRES_PORT": "5432",
"OPENAI_API_KEY": "sk-xxx"
}
}
响应示例:
{
"success": true,
"data": {
"id": "d14cd898-e2cf-4150-a7f9-53b962c1c9a2",
"name": "my-mysql-tool",
"template": "mysql_agent"
},
"message": "工具创建成功"
}
4.2 创建自定义 Agent(选择工具)
接口: POST /api/user/custom-agents
请求参数变化:
interface CreateCustomAgentRequest {
name: string; // Agent名称(必填)
tools: string[]; // 工具ID列表(必填,第一个工具决定 Agent 类型)
// 以下参数变为可选(可从工具自动获取)
template?: string; // 模板名称(可选,默认从工具获取)
envConfig?: Record<string, string>; // 额外环境变量(可选,会与工具配置合并)
// 资源配置
cpuRequest?: string; // 默认 "100m"
memoryRequest?: string; // 默认 "128Mi"
// 其他可选参数
frameworkTemplate?: string; // 默认 "MCP"
model?: string;
}
请求示例:
{
"name": "my-mysql-agent",
"tools": ["d14cd898-e2cf-4150-a7f9-53b962c1c9a2"],
"cpuRequest": "500m",
"memoryRequest": "1Gi",
"model": "gpt-4"
}
说明:
template和envConfig从工具自动获取- 请求中的
envConfig会与工具配置合并(请求中的优先)
5. 修改检查清单
- models.py: 添加
template和env_config字段到 Tool 模型 - 数据库迁移: 创建迁移脚本添加新字段
- user.py - create_tool: 修改创建工具接口,支持 template 和 envConfig
- user.py - create_custom_agent: 修改创建 Agent 接口,从工具获取模板和配置
- user.py - get_user_tools: 修改响应格式,包含 template 和 envConfig
- schemas.py: 更新请求/响应模型定义
- 接口文档: 更新前端接口文档
6. 测试用例
6.1 创建工具
# 创建 MySQL 工具
curl -X POST /api/user/tools/create \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-mysql-tool",
"template": "mysql_agent",
"envConfig": {
"MYSQL_HOST": "mysql.example.com",
"MYSQL_USER": "root",
"MYSQL_PASSWORD": "password123",
"MYSQL_DATABASE": "mydb"
}
}'
6.2 创建 Agent(选择工具)
# 创建 Agent,选择已创建的工具
curl -X POST /api/user/custom-agents \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-mysql-agent",
"tools": ["d14cd898-e2cf-4150-a7f9-53b962c1c9a2"],
"cpuRequest": "500m",
"memoryRequest": "1Gi"
}'
如有问题,请联系大智开发团队。