Files
cloudpods/pkg/apis/llm/mcp_agent.go
Zexi Li 3fd882452b feat(llm): route MCP agent via aiproxy virtual key and routing id (#25667)
Support X-Ai-Routing-Id to pin ai_routing, treat empty model_pattern as non-wildcard, and wire MCP agent to aiproxy credentials instead of direct LLM api_key.
2026-09-11 10:14:08 +08:00

154 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package llm
import (
"yunion.io/x/pkg/util/sets"
"yunion.io/x/onecloud/pkg/apis"
)
// LLMClientType 定义 LLM 驱动类型
type LLMClientType string
const (
LLM_CLIENT_OLLAMA LLMClientType = "ollama"
LLM_CLIENT_OPENAI LLMClientType = "openai"
MCP_AGENT_SYSTEM_PROMPT = `你是一个 %s 云平台管理助手。你可以使用提供的工具来帮助用户管理云资源。
## 你的能力
- 查询云平台资源(虚拟机、镜像、网络、存储、区域、套餐等)
- 管理虚拟机(创建、启动、停止、重启、删除、重置密码)
- 获取虚拟机监控信息和实时统计数据
## 重要规则(必须严格遵守)
**如果用户的问题涉及查询、创建、修改或删除云资源,你必须先调用相应的工具,而不是直接回答。**
- 严禁空口编造:在未真正调用工具并拿到返回结果前,禁止声称“已查到区域/镜像/网络”“正在创建成功”等。
- 对于需要查询资源的问题(如"列出虚拟机"、"查询状态"等),必须调用工具获取数据后再回答
- 对于需要操作资源的问题(如"创建"、"启动"、"停止"等),必须调用工具执行操作后再回答
- 只有在以下情况才可以直接回复:
1. 用户只是询问一般性问题(如"你能做什么"、"如何使用"等)
2. 没有合适的工具可以解决用户的问题
3. 工具调用失败后需要向用户说明错误原因
## 创建虚拟机标准流程(同一轮对话中连续调用工具,不要只说不做;查询可并行以节省轮次)
1. climc_cloud_region_list公有云必须 provider=["Aliyun"] 等;创建时 usable=true
2. climc_cloud_region_capabilityID=区域 id从 storage_types2 取系统盘 backend
3. climc_cached_image_list公有云或 climc_image_listKVM公有云必须带 provider + region=区域 id不要重复调用
4. climc_server_sku_list公有云带 provider+cloudregion用户说 2c2g/2核2G 时传 spec="2c2g"
5. climc_server_createname、disk 须含 image+backend、instance-type 或 ncpu/mem-spec公有云 hypervisor=aliyun、prefer-region=区域 id。net 可省略:未指定时自动 randomnets:[{exit:false}])调度,默认不要先 network-list/vpc-list
查询工具的返回不等于任务完成;必须最终调用 climc_server_create。创建失败时根据工具错误向用户说明原因。
## 工作流程
1. 理解用户的需求
2. **优先检查是否有合适的工具可以完成任务,如果有则必须调用工具(发 tool_calls不要只输出计划文字**
3. 分析工具返回的结果
4. 如果需要更多信息,继续调用其他工具
5. 最后用自然语言总结结果给用户
## 注意事项
- 认证信息已由系统自动处理,调用工具时无需提供认证参数
- 如果工具调用失败,尝试分析错误原因并告知用户
- 回复时使用中文,语言简洁明了
- **不要在没有调用工具的情况下直接回答需要查询或操作资源的问题**
`
)
var (
LLM_CLIENT_TYPES = sets.NewString(
string(LLM_CLIENT_OLLAMA),
string(LLM_CLIENT_OPENAI),
)
)
// IsLLMClientType 检查给定的字符串是否是有效的 LLM 驱动类型
func IsLLMClientType(t string) bool {
return LLM_CLIENT_TYPES.Has(t)
}
// MCP Agent 配置相关的 API 定义
type MCPAgentListInput struct {
apis.SharableVirtualResourceListInput
LLMDriver string `json:"llm_driver"`
DefaultAgent *bool `json:"default_agent,omitempty" help:"filter by default agent (true to get the default one)"`
}
type MCPAgentCreateInput struct {
apis.SharableVirtualResourceCreateInput
LLMId string `json:"llm_id" help:"deprecated; ignored"`
LLMUrl string `json:"llm_url" help:"AI 网关 OpenAI 兼容 base 请求地址"`
LLMDriver string `json:"llm_driver" help:"使用的大模型驱动,固定为 openai"`
Model string `json:"model" help:"使用的模型名称"`
ApiKey string `json:"api_key" help:"deprecated; ignored"`
McpServer string `json:"mcp_server" help:"mcp 服务器的后端地址"`
AiProxyRoutingId string `json:"aiproxy_routing_id" help:"关联的 AI 网关路由规则 ID"`
AiproxyVirtualKeyId string `json:"aiproxy_virtual_key_id" help:"关联的 AI 网关 API Key ID"`
DefaultAgent *bool `json:"default_agent,omitempty" help:"set as default MCP agent (only one can be true globally)"`
}
type MCPAgentUpdateInput struct {
apis.SharableVirtualResourceCreateInput
LLMId *string `json:"llm_id,omitempty" help:"deprecated; ignored"`
LLMUrl *string `json:"llm_url,omitempty" help:"AI 网关 OpenAI 兼容 base 请求地址"`
LLMDriver *string `json:"llm_driver,omitempty" help:"使用的大模型驱动,固定为 openai"`
Model *string `json:"model,omitempty" help:"使用的模型名称"`
ApiKey *string `json:"api_key,omitempty" help:"deprecated; ignored"`
McpServer *string `json:"mcp_server,omitempty" help:"mcp 服务器的后端地址"`
AiProxyRoutingId *string `json:"aiproxy_routing_id,omitempty" help:"关联的 AI 网关路由规则 ID"`
AiproxyVirtualKeyId *string `json:"aiproxy_virtual_key_id,omitempty" help:"关联的 AI 网关 API Key ID"`
DefaultAgent *bool `json:"default_agent,omitempty" help:"set as default MCP agent (only one can be true globally)"`
}
type MCPAgentDetails struct {
apis.SharableVirtualResourceDetails
LLMId string `json:"llm_id"`
LLMName string `json:"llm_name"`
AiProxyRoutingId string `json:"aiproxy_routing_id"`
AiproxyVirtualKeyId string `json:"aiproxy_virtual_key_id"`
DefaultAgent bool `json:"default_agent"`
}
type LLMToolRequestInput struct {
ToolName string `json:"tool_name"`
Arguments map[string]interface{} `json:"arguments"`
}
type LLMMCPAgentRequestInput struct {
Message string `json:"message" help:"message to send to MCP agent"`
History []MCPAgentChatMessage `json:"history" help:"chat history"`
}
type MCPAgentChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
// ToolCalls []MCPAgentToolCallRecord `json:"tool_calls,omitempty"`
}
// MCPAgentResponse 表示 Agent 响应
type MCPAgentResponse struct {
// Success 是否成功
Success bool `json:"success"`
// Answer 自然语言回答
Answer string `json:"answer"`
// Error 错误信息
Error string `json:"error,omitempty"`
// ToolCalls 工具调用记录
ToolCalls []MCPAgentToolCallRecord `json:"tool_calls,omitempty"`
}
// MCPAgentToolCallRecord 记录工具调用
type MCPAgentToolCallRecord struct {
Id string `json:"id,omitempty"`
ToolName string `json:"tool_name"`
Arguments map[string]interface{} `json:"arguments"`
Result string `json:"result"`
}
const (
// MCPAgentMaxIterations 最大迭代次数,防止无限循环
MCPAgentMaxIterations = 10
)