Trae Agent Tools 核心逻辑详解
概述
Trae Agent 的 Tools 模块采用插件化架构 ,通过抽象基类 Tool 定义统一接口,支持内置工具和 MCP(Model Context Protocol)外部工具。Tools 是 Agent 与外部环境交互的核心机制。
核心架构
yaml
┌─────────────────────────────────────────────────────────────────┐
│ Tools 核心架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Tool 抽象基类 (base.py) │ │
│ │ ├── name: 工具名称 │ │
│ │ ├── description: 工具描述 │ │
│ │ ├── parameters: 参数定义 │ │
│ │ └── execute(): 执行逻辑 │ │
│ └────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 内置工具 │ │ MCP工具 │ │ 注册表 │ │
│ │ │ │ │ │ │ │
│ │ • BashTool │ │ MCPTool │ │ tools_ │ │
│ │ • EditTool │ │ (动态) │ │ registry │ │
│ │ • TaskDone │ │ │ │ │ │
│ └────────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
核心类详解
1. Tool 抽象基类
文件 : trae_agent/tools/base.py
python
class Tool(ABC):
"""所有工具的抽象基类"""
def __init__(self, model_provider: str | None = None):
self._model_provider = model_provider
@abstractmethod
def get_name(self) -> str:
"""获取工具名称"""
pass
@abstractmethod
def get_description(self) -> str:
"""获取工具描述"""
pass
@abstractmethod
def get_parameters(self) -> list[ToolParameter]:
"""获取工具参数定义"""
pass
@abstractmethod
async def execute(self, arguments: ToolCallArguments) -> ToolExecResult:
"""执行工具"""
pass
def json_definition(self) -> dict[str, object]:
"""获取工具的 JSON 定义(用于 LLM API)"""
return {
"name": self.name,
"description": self.description,
"parameters": self.get_input_schema(),
}
核心属性:
| 属性 | 类型 | 说明 |
|---|---|---|
name |
str |
工具唯一标识 |
description |
str |
工具功能描述 |
parameters |
list[ToolParameter] |
参数定义列表 |
model_provider |
`str | None` |
2. ToolParameter 参数定义
python
@dataclass
class ToolParameter:
"""工具参数定义"""
name: str # 参数名
type: str | list[str] # 参数类型
description: str # 参数描述
enum: list[str] | None = None # 枚举值
items: dict[str, object] | None = None # 数组项定义
required: bool = True # 是否必填
3. ToolCall 工具调用请求
python
@dataclass
class ToolCall:
"""LLM 返回的工具调用请求"""
name: str # 工具名称
call_id: str # 调用唯一标识
arguments: ToolCallArguments = field(default_factory=dict) # 参数值
id: str | None = None # OpenAI 特有字段
4. ToolResult 工具执行结果
python
@dataclass
class ToolResult:
"""工具执行结果"""
call_id: str # 对应调用的 ID
name: str # 工具名称
success: bool # 是否成功
result: str | None = None # 成功时的输出
error: str | None = None # 失败时的错误信息
id: str | None = None # OpenAI 特有字段
5. ToolExecutor 工具执行器
python
class ToolExecutor:
"""工具执行器,管理工具的执行"""
def __init__(self, tools: list[Tool]):
self._tools = tools
self._tool_map: dict[str, Tool] | None = None
@property
def tools(self) -> dict[str, Tool]:
"""获取工具映射表(懒加载)"""
if self._tool_map is None:
self._tool_map = {
self._normalize_name(tool.name): tool
for tool in self._tools
}
return self._tool_map
async def execute_tool_call(self, tool_call: ToolCall) -> ToolResult:
"""执行单个工具调用"""
normalized_name = self._normalize_name(tool_call.name)
# 查找工具
if normalized_name not in self.tools:
return ToolResult(
name=tool_call.name,
success=False,
error=f"Tool '{tool_call.name}' not found",
call_id=tool_call.call_id,
)
tool = self.tools[normalized_name]
# 执行工具
try:
exec_result = await tool.execute(tool_call.arguments)
return ToolResult(
name=tool_call.name,
success=exec_result.error_code == 0,
result=exec_result.output,
error=exec_result.error,
call_id=tool_call.call_id,
)
except Exception as e:
return ToolResult(
name=tool_call.name,
success=False,
error=f"Error: {str(e)}",
call_id=tool_call.call_id,
)
async def parallel_tool_call(self, tool_calls: list[ToolCall]) -> list[ToolResult]:
"""并行执行多个工具调用"""
return await asyncio.gather(*[
self.execute_tool_call(call) for call in tool_calls
])
async def sequential_tool_call(self, tool_calls: list[ToolCall]) -> list[ToolResult]:
"""串行执行多个工具调用"""
return [await self.execute_tool_call(call) for call in tool_calls]
内置工具列表
1. BashTool - Bash 命令执行
文件 : trae_agent/tools/bash_tool.py
python
class BashTool(Tool):
"""执行 Bash 命令的工具"""
def get_name(self) -> str:
return "bash"
def get_description(self) -> str:
return "Execute bash commands"
def get_parameters(self) -> list[ToolParameter]:
return [
ToolParameter(
name="command",
type="string",
description="The bash command to execute",
required=True,
),
]
async def execute(self, arguments: ToolCallArguments) -> ToolExecResult:
command = arguments.get("command", "")
# 使用 _BashSession 执行命令
result = await self._session.run(command)
return result
特点:
- 维护持久的 Bash 会话
- 支持超时控制(默认 120 秒)
- 跨平台支持(Unix/Windows)
2. TextEditorTool - 文本编辑器
文件 : trae_agent/tools/edit_tool.py
python
class TextEditorTool(Tool):
"""文件编辑工具"""
def get_name(self) -> str:
return "str_replace_based_edit_tool"
def get_description(self) -> str:
return """Custom editing tool for viewing, creating and editing files
* State is persistent across command calls
* Commands: view, create, str_replace, insert
* ...
"""
def get_parameters(self) -> list[ToolParameter]:
return [
ToolParameter(
name="command",
type="string",
description="The commands to run",
required=True,
enum=["view", "create", "str_replace", "insert"],
),
ToolParameter(name="path", type="string", description="File path", required=True),
ToolParameter(name="old_str", type="string", description="String to replace"),
ToolParameter(name="new_str", type="string", description="Replacement string"),
# ... 更多参数
]
支持的命令:
| 命令 | 功能 |
|---|---|
view |
查看文件内容 |
create |
创建新文件 |
str_replace |
字符串替换 |
insert |
在指定行后插入 |
3. TaskDoneTool - 任务完成标记
文件 : trae_agent/tools/task_done_tool.py
python
class TaskDoneTool(Tool):
"""标记任务完成的工具"""
def get_name(self) -> str:
return "task_done"
def get_description(self) -> str:
return "Report the completion of the task"
def get_parameters(self) -> list[ToolParameter]:
return [] # 无参数
async def execute(self, arguments: ToolCallArguments) -> ToolExecResult:
return ToolExecResult(output="Task done.")
用途: 通知 Agent 任务已完成。
4. JSONEditTool - JSON 编辑器
文件 : trae_agent/tools/json_edit_tool.py
python
class JSONEditTool(Tool):
"""JSON 文件编辑工具"""
def get_name(self) -> str:
return "json_edit_tool"
def get_parameters(self) -> list[ToolParameter]:
return [
ToolParameter(name="path", type="string", required=True),
ToolParameter(name="json_path", type="string", required=True),
ToolParameter(name="value", type="object", required=True),
]
5. SequentialThinkingTool - 顺序思考
文件 : trae_agent/tools/sequential_thinking_tool.py
python
class SequentialThinkingTool(Tool):
"""顺序思考工具,用于复杂推理"""
def get_name(self) -> str:
return "sequentialthinking"
6. CKGTool - 代码知识图谱
文件 : trae_agent/tools/ckg_tool.py
python
class CKGTool(Tool):
"""代码知识图谱工具"""
def get_name(self) -> str:
return "ckg"
工具注册表
文件 : trae_agent/tools/__init__.py
python
# 工具注册表:名称 -> 工具类
tools_registry: dict[str, type[Tool]] = {
"bash": BashTool,
"str_replace_based_edit_tool": TextEditorTool,
"json_edit_tool": JSONEditTool,
"sequentialthinking": SequentialThinkingTool,
"task_done": TaskDoneTool,
"ckg": CKGTool,
}
使用方式:
python
from trae_agent.tools import tools_registry
# 通过名称动态创建工具实例
tool = tools_registry["bash"](model_provider="anthropic")
MCP 工具集成
MCPTool 类
文件 : trae_agent/tools/mcp_tool.py
python
class MCPTool(Tool):
"""MCP 外部工具包装器"""
def __init__(self, client, tool: mcp.types.Tool, model_provider: str | None = None):
super().__init__(model_provider)
self.client = client # MCP 客户端
self.tool = tool # MCP 工具定义
def get_name(self) -> str:
return self.tool.name
def get_description(self) -> str:
return self.tool.description
def get_parameters(self) -> list[ToolParameter]:
"""将 MCP 参数定义转换为 ToolParameter"""
parameters = []
input_schema = self.tool.inputSchema
required = input_schema.get("required", [])
properties = input_schema.get("properties", {})
for name, prop in properties.items():
parameters.append(ToolParameter(
name=name,
type=prop["type"],
description=prop["description"],
required=name in required,
))
return parameters
async def execute(self, arguments: ToolCallArguments) -> ToolExecResult:
"""通过 MCP 客户端调用工具"""
try:
output = await self.client.call_tool(self.get_name(), arguments)
if output.isError:
return ToolExecResult(error=output.content[0].text)
else:
return ToolExecResult(output=output.content[0].text)
except Exception as e:
return ToolExecResult(error=f"Error: {e}", error_code=-1)
与其他模块的交互
1. 与 Agent 模块的交互
文件 : trae_agent/agent/base_agent.py
工具初始化
python
class BaseAgent:
def __init__(self, agent_config: AgentConfig, ...):
# 1. 从配置创建工具实例
self._tools: list[Tool] = [
tools_registry[tool_name](
model_provider=self._model_config.model_provider.provider
)
for tool_name in agent_config.tools
]
# 2. 创建工具执行器
self._tool_caller = ToolExecutor(self._tools)
工具调用处理
python
async def _tool_call_handler(
self,
tool_calls: list[ToolCall] | None,
step: AgentStep
) -> list[LLMMessage]:
"""处理 LLM 返回的工具调用"""
messages: list[LLMMessage] = []
# 1. 更新状态为 CALLING_TOOL
step.state = AgentStepState.CALLING_TOOL
step.tool_calls = tool_calls
self._update_cli_console(step)
# 2. 执行工具调用(并行或串行)
if self._model_config.parallel_tool_calls:
tool_results = await self._tool_caller.parallel_tool_call(tool_calls)
else:
tool_results = await self._tool_caller.sequential_tool_call(tool_calls)
step.tool_results = tool_results
self._update_cli_console(step)
# 3. 将结果转换为消息
for tool_result in tool_results:
message = LLMMessage(role="user", tool_result=tool_result)
messages.append(message)
# 4. 反思结果
reflection = self.reflect_on_result(tool_results)
if reflection:
step.state = AgentStepState.REFLECTING
step.reflection = reflection
messages.append(LLMMessage(role="assistant", content=reflection))
return messages
交互流程:
markdown
┌─────────────┐ tool_calls ┌─────────────────┐
│ Agent │ ──────────────────▶ │ _tool_call_ │
│ │ │ handler │
│ │ ◀────────────────── │ │
└─────────────┘ messages └────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐
│ ToolExe-│ │ 状态更新 │ │ 反思 │
│ cutor │ │ │ │ │
└─────────┘ └──────────┘ └──────────┘
2. 与 LLM Client 模块的交互
文件 : trae_agent/utils/llm_clients/anthropic_client.py
工具定义传递
python
class AnthropicClient(BaseLLMClient):
def chat(self, messages, model_config, tools):
# 1. 将 Tool 对象转换为 Anthropic 格式
tool_schemas = []
for tool in tools:
if tool.name == "str_replace_based_edit_tool":
# Anthropic 原生工具
tool_schemas.append(
anthropic.types.ToolTextEditor20250429Param(...)
)
elif tool.name == "bash":
tool_schemas.append(
anthropic.types.ToolBash20250124Param(...)
)
else:
# 通用工具
tool_schemas.append(
anthropic.types.ToolParam(
name=tool.name,
description=tool.description,
input_schema=tool.get_input_schema(), # ← 关键调用
)
)
# 2. 调用 API
response = self._create_anthropic_response(model_config, tool_schemas)
# 3. 解析工具调用
tool_calls = []
for block in response.content:
if block.type == "tool_use":
tool_calls.append(ToolCall(
call_id=block.id,
name=block.name,
arguments=block.input,
))
return LLMResponse(content=text, tool_calls=tool_calls)
交互流程:
scss
┌─────────────┐ get_input_schema() ┌─────────────┐
│ Tool │ ───────────────────────▶ │ Anthropic │
│ │ │ Client │
│ │ ◀─────────────────────── │ │
└─────────────┘ JSON Schema └──────┬──────┘
│
▼
┌─────────────┐
│ Anthropic │
│ API │
└──────┬──────┘
│
▼
┌─────────────┐
│ ToolCall │
│ 对象 │
└─────────────┘
3. 与配置模块的交互
文件 : trae_agent/utils/config.py
python
@dataclass
class AgentConfig:
"""Agent 配置包含工具列表"""
tools: list[str] # 工具名称列表
allow_mcp_servers: list[str] # 允许的 MCP 服务器
mcp_servers_config: dict[str, MCPServerConfig] # MCP 配置
配置示例:
yaml
agents:
trae_agent:
tools:
- bash
- str_replace_based_edit_tool
- sequentialthinking
- task_done
allow_mcp_servers:
- playwright
mcp_servers:
playwright:
command: npx
args: ["@playwright/mcp@0.0.27"]
4. 与 CLI 模块的交互
文件 : trae_agent/cli.py
python
from trae_agent.tools import tools_registry
# 列出所有可用工具
for tool_name in tools_registry:
tool = tools_registry[tool_name]()
print(f"- {tool_name}: {tool.description}")
工具 Schema 生成
OpenAI 兼容格式
python
def get_input_schema(self) -> dict[str, object]:
"""生成 OpenAI Function Calling 格式的 Schema"""
schema: dict[str, object] = {
"type": "object",
"properties": {},
"required": [],
}
for param in self.parameters:
param_schema = {
"type": param.type,
"description": param.description,
}
# OpenAI strict mode: 所有参数必须 required
if self.model_provider == "openai":
schema["required"].append(param.name)
# 可选参数标记为 nullable
if not param.required:
param_schema["type"] = [param.type, "null"]
elif param.required:
schema["required"].append(param.name)
if param.enum:
param_schema["enum"] = param.enum
schema["properties"][param.name] = param_schema
# OpenAI strict mode 需要 additionalProperties: false
if self.model_provider == "openai":
schema["additionalProperties"] = False
return schema
生成的 Schema 示例:
json
{
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to execute"
},
"timeout": {
"type": ["integer", "null"],
"description": "Timeout in seconds"
}
},
"required": ["command", "timeout"],
"additionalProperties": false
}
Docker 工具执行器
文件 : trae_agent/tools/docker_tool_executor.py
python
class DockerToolExecutor:
"""在 Docker 容器中执行工具"""
def __init__(self, original_executor, docker_manager, ...):
self._original_executor = original_executor
self._docker_manager = docker_manager
self._docker_tools = ["bash", "str_replace_based_edit_tool", "json_edit_tool"]
async def sequential_tool_call(self, tool_calls: list[ToolCall]) -> list[ToolResult]:
"""在 Docker 中串行执行工具"""
results = []
for tool_call in tool_calls:
if tool_call.name in self._docker_tools:
# 在 Docker 中执行
result = await self._execute_in_docker(tool_call)
else:
# 在宿主机执行
result = await self._original_executor.execute_tool_call(tool_call)
results.append(result)
return results
核心文件索引
| 文件 | 职责 | 重要性 |
|---|---|---|
tools/base.py |
Tool 抽象基类和 ToolExecutor | ⭐⭐⭐ |
tools/__init__.py |
工具注册表 | ⭐⭐⭐ |
tools/bash_tool.py |
Bash 命令执行 | ⭐⭐⭐ |
tools/edit_tool.py |
文件编辑 | ⭐⭐⭐ |
tools/task_done_tool.py |
任务完成标记 | ⭐⭐⭐ |
tools/mcp_tool.py |
MCP 工具包装 | ⭐⭐⭐ |
tools/docker_tool_executor.py |
Docker 执行环境 | ⭐⭐ |
agent/base_agent.py |
工具调用处理 | ⭐⭐⭐ |
总结
| 特性 | 说明 |
|---|---|
| 架构 | 插件化、抽象基类 + 具体实现 |
| 注册机制 | 全局注册表,支持动态加载 |
| MCP 支持 | 原生支持外部工具服务 |
| 执行模式 | 并行/串行可选 |
| Schema 适配 | 自动适配不同 LLM 提供商的格式 |
| 环境隔离 | 支持 Docker 容器执行 |
核心设计原则:
- 统一接口 : 所有工具继承
Tool基类 - 声明式定义 : 通过
ToolParameter声明参数 - 自动转换: Schema 自动生成,适配不同 LLM
- 灵活扩展: 注册表模式支持动态添加工具
最后更新: 2026-03-16