Skip to content

一、工具绑定流程 ​

文件: app/agent/runtime.py, 行 51-69
───────────────────────────────────────────────────────────────────
async def _assemble(servers: list[str] | None = None, 
                    clouds: list[str] | None = None):
    
    # 1. 获取模型配置
    model_cfg = _get_default_model()             # 行 53
    model = build_chat_model(model_cfg)          # 行 54

    # 2. 构建 SSH 工具(根据当前会话的服务器范围)
    allowed = set(servers) if servers else None  # 行 56
    tools = [*make_scoped_ssh_tools(allowed), clarify_tool]  # 行 57
    #                  ↑ SSH 工具          ↑ 澄清工具
    
    # 3. 加载云 MCP 工具
    with SessionLocal() as db:
        q = db.query(CloudAccount).filter(CloudAccount.enabled)
        if clouds:
            q = q.filter(CloudAccount.name.in_(clouds))
        accounts = q.all()
    tools += await load_cloud_tools(accounts)    # 行 66: 动态加载云工具

    # 4. 构建 Agent(绑定所有工具)
    return build_agent(model, tools, checkpointer=_checkpointer, system_suffix=suffix)

二、固定的两个工具 ​

2.1 list_servers - 列出服务器 ​

python
# 文件: app/tools/ssh.py, 行 122-133
def _scoped_list() -> str:
    """列出当前可操作的服务器及标签"""
    with SessionLocal() as db:
        servers = [s for s in db.query(Server).all()
                   if allowed is None or s.name in allowed]
    if not servers:
        return "当前没有可操作的服务器。"
    lines = [f"- {s.name}  {s.username}@{s.host}:{s.port}  tags={s.tags}" for s in servers]
    return "可用服务器:\n" + "\n".join(lines)

list_servers_tool = StructuredTool.from_function(
    func=_scoped_list, 
    name="list_servers",
    description="列出当前可操作的服务器及标签。",
)

作用:让 Agent 知道有哪些服务器可以操作


2.2 ssh_run - 执行 SSH 命令 ​

python
# 文件: app/tools/ssh.py, 行 19-23, 79-87
class SSHRunInput(BaseModel):
    server_name: str = Field(description="目标服务器名称(在后台已登记)")
    command: str = Field(description="要在服务器上执行的 shell 命令")
    intent: str = Field(default="", description="用一句话说明这条命令的目的/作用")
    timeout: int = Field(default=600, description="超时秒数")

ssh_run_tool = StructuredTool.from_function(
    coroutine=_run_on_server,           # 异步 SSH 执行函数
    name="ssh_run",
    description=(
        "在指定服务器上通过 SSH 执行 shell 命令并返回 stdout/stderr/exit code。"
        "用于巡检、诊断、变更等运维操作。先用 list_servers 查看可用服务器。"
    ),
    args_schema=SSHRunInput,
)

作用:在指定服务器上执行 Shell 命令


2.3 clarify - 任务澄清 ​

python
# 文件: app/tools/clarify.py, 行 13-32
class ClarifyInput(BaseModel):
    question: str = Field(description="要向用户澄清的问题(一句话说清歧义点)")
    options: list[str] = Field(default_factory=list,
                               description="可选项列表;用户也可自行补充")

clarify_tool = StructuredTool.from_function(
    coroutine=_clarify,
    name="clarify",
    description=(
        "当任务不明确、存在歧义、或有多种可行方案、需要用户在风险/范围上拍板时,"
        "调用本工具向用户提问并给出候选项,等用户选择后再继续。"
    ),
    args_schema=ClarifyInput,
)

作用:当任务不明确时向用户澄清


三、动态加载的云 MCP 工具 ​

python
# 文件: app/tools/mcp_manager.py, 行 55-75
async def load_cloud_tools(accounts: list[CloudAccount]) -> list[BaseTool]:
    """根据云账号动态加载 MCP 工具"""
    
    # 1. 过滤已启用的账号
    enabled = [a for a in accounts if a.enabled]
    
    # 2. 构建连接配置
    connections = {acc.name: _account_to_server_config(acc) for acc in enabled}
    
    # 3. 创建 MCP 客户端
    client = MultiServerMCPClient(connections)
    
    # 4. 遍历每个云账号加载工具
    tools: list[BaseTool] = []
    for acc in enabled:
        acc_tools = await client.get_tools(server_name=acc.name)
        
        # 5. 工具名加账号前缀避免冲突
        for t in acc_tools:
            t.name = f"{acc.name}__{t.name}"  # 如 aliyun-prod__DescribeInstances
        tools.extend(acc_tools)
    
    return tools

支持的云平台:

云平台工具名前缀示例工具
阿里云aliyun-账号名__aliyun-prod__DescribeInstances
Cloudflarecloudflare-账号名__cloudflare-main__ListZones

四、完整工具列表 ​

┌─────────────────────────────────────────────────────────────────┐
│                    绑定到模型的工具                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  【固定工具】(始终绑定)                                        │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  1. list_servers                                        │   │
│  │     - 列出当前可操作的服务器                             │   │
│  │     - 参数: 无                                          │   │
│  │     - 返回: 服务器列表字符串                             │   │
│  ├─────────────────────────────────────────────────────────┤   │
│  │  2. ssh_run                                             │   │
│  │     - 在服务器上执行 SSH 命令                           │   │
│  │     - 参数: server_name, command, intent, timeout       │   │
│  │     - 返回: stdout/stderr/exit_code                     │   │
│  ├─────────────────────────────────────────────────────────┤   │
│  │  3. clarify                                             │   │
│  │     - 向用户澄清任务歧义                                 │   │
│  │     - 参数: question, options                           │   │
│  │     - 返回: 用户的选择/补充                              │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  【动态工具】(根据配置的云账号加载)                             │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  4. aliyun-prod__DescribeInstances                     │   │
│  │     5. aliyun-prod__RunInstances                        │   │
│  │     6. aliyun-prod__StopInstances                       │   │
│  │     ...                                                 │   │
│  ├─────────────────────────────────────────────────────────┤   │
│  │  7. cloudflare-main__ListZones                         │   │
│  │     8. cloudflare-main__GetZone                         │   │
│  │     ...                                                 │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

五、工具 Schema 传递给 LLM 的方式 ​

┌─────────────────────────────────────────────────────────────────┐
│              工具 Schema → LLM Function Calling                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  当 model.bind_tools([list_servers, ssh_run, clarify, ...]) 时 │
│                                                                 │
│  LLM 会收到类似这样的工具定义(不同模型格式略有差异):            │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │ {                                                         │  │
│  │   "name": "ssh_run",                                      │  │
│  │   "description": "在指定服务器上通过 SSH 执行 shell 命令", │  │
│  │   "parameters": {                                         │  │
│  │     "type": "object",                                     │  │
│  │     "properties": {                                       │  │
│  │       "server_name": {"type": "string", ...},            │  │
│  │       "command": {"type": "string", ...},                │  │
│  │       "intent": {"type": "string", ...},                 │  │
│  │       "timeout": {"type": "integer", ...}                │  │
│  │     },                                                    │  │
│  │     "required": ["server_name", "command"]               │  │
│  │   }                                                       │  │
│  │ }                                                         │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  LLM 根据这些定义决定是否/如何调用工具                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

六、工具绑定代码位置 ​

python
# 文件: app/agent/graph.py, 行 38-42
def build_agent(model: BaseChatModel, tools: list[BaseTool], 
                checkpointer=None, system_suffix: str = ""):
    tools_by_name = {t.name: t for t in tools}           # 行 40: 工具名映射
    model_with_tools = model.bind_tools(tools)           # 行 41: ⚠️ 关键绑定点
python
# 文件: app/agent/runtime.py, 行 57
tools = [*make_scoped_ssh_tools(allowed), clarify_tool]
python
# 文件: app/agent/runtime.py, 行 66
tools += await load_cloud_tools(accounts)

七、总结 ​

工具名称类型来源用途
list_servers固定ssh.py列出可用服务器
ssh_run固定ssh.pySSH 执行命令
clarify固定clarify.py任务澄清
aliyun-xxx__*动态mcp_manager.py阿里云操作
cloudflare-xxx__*动态mcp_manager.pyCloudflare 操作

绑定数量:

  • 固定工具:3 个
  • 动态工具:根据配置的云账号数量动态增减
  • 总计:3 + (云账号数 × 该账号的 MCP 工具数)

Released under the MIT License.