Trae Agent 设计模式分析
概述
Trae Agent 项目广泛运用了多种经典设计模式,使代码具有良好的扩展性、可维护性和灵活性。本文档详细分析项目中使用的主要设计模式。
一、工厂模式 (Factory Pattern)
1.1 LLMClient 工厂
文件 : trae_agent/utils/llm_clients/llm_client.py
python
class LLMClient:
"""LLM 客户端工厂类"""
@staticmethod
def create(model_config: ModelConfig) -> BaseLLMClient:
"""根据配置创建对应的 LLM 客户端"""
provider = model_config.model_provider.provider
match provider:
case "anthropic":
return AnthropicClient(
api_key=model_config.model_provider.api_key,
base_url=model_config.model_provider.base_url,
)
case "openai":
return OpenAIClient(
api_key=model_config.model_provider.api_key,
base_url=model_config.model_provider.base_url,
)
case "azure":
return AzureOpenAIClient(
api_key=model_config.model_provider.api_key,
base_url=model_config.model_provider.base_url,
api_version=model_config.model_provider.api_version,
)
case "google":
return GoogleClient(
api_key=model_config.model_provider.api_key,
)
case "ollama":
return OllamaClient(
base_url=model_config.model_provider.base_url,
)
case _:
raise ValueError(f"Unknown provider: {provider}")
优点:
- 客户端代码无需知道具体类名
- 新增提供商只需添加 case 分支
- 集中管理对象创建逻辑
1.2 CLIConsole 工厂
文件 : trae_agent/utils/cli/console_factory.py
python
class ConsoleFactory:
"""CLI 控制台工厂"""
@staticmethod
def create_console(
console_type: ConsoleType,
mode: ConsoleMode = ConsoleMode.RUN,
lakeview_config: LakeviewConfig | None = None,
) -> CLIConsole:
"""创建对应类型的控制台"""
match console_type:
case ConsoleType.SIMPLE:
return SimpleConsole(mode=mode, lakeview_config=lakeview_config)
case ConsoleType.RICH:
return RichConsole(mode=mode, lakeview_config=lakeview_config)
case _:
raise ValueError(f"Unknown console type: {console_type}")
二、抽象工厂模式 (Abstract Factory)
2.1 BaseLLMClient 抽象接口
文件 : trae_agent/utils/llm_clients/base.py
python
class BaseLLMClient(ABC):
"""LLM 客户端抽象基类"""
@abstractmethod
def chat(
self,
messages: list[LLMMessage],
model_config: ModelConfig,
tools: list[Tool] | None,
) -> LLMResponse:
"""与 LLM 进行对话"""
pass
@abstractmethod
def convert_messages(
self, messages: list[LLMMessage]
) -> list[dict[str, object]]:
"""转换消息格式"""
pass
@abstractmethod
def convert_tools(self, tools: list[Tool]) -> list[dict[str, object]]:
"""转换工具定义格式"""
pass
具体实现:
AnthropicClient- Anthropic API 实现OpenAIClient- OpenAI API 实现AzureOpenAIClient- Azure OpenAI 实现GoogleClient- Google Gemini 实现OllamaClient- Ollama 本地模型实现
优点:
- 统一接口,不同实现
- 客户端代码与具体实现解耦
- 易于扩展新的 LLM 提供商
三、策略模式 (Strategy Pattern)
3.1 工具执行策略
文件 : trae_agent/tools/base.py
python
class ToolExecutor:
"""工具执行器,支持并行和串行策略"""
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]
使用:
python
# 根据配置选择策略
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)
3.2 Docker 执行策略
文件 : trae_agent/tools/docker_tool_executor.py
python
class DockerToolExecutor:
"""Docker 执行策略包装器"""
def __init__(self, original_executor: ToolExecutor, ...):
self._original_executor = original_executor
async def execute_tool_call(self, tool_call: ToolCall) -> ToolResult:
"""选择在 Docker 或宿主机执行"""
if tool_call.name in self._docker_tools:
# Docker 执行策略
return await self._execute_in_docker(tool_call)
else:
# 宿主机执行策略(委托给原始执行器)
return await self._original_executor.execute_tool_call(tool_call)
四、注册表模式 (Registry Pattern)
4.1 工具注册表
文件 : 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,
}
# 使用
from trae_agent.tools import tools_registry
tool_class = tools_registry["bash"]
tool_instance = tool_class(model_provider="anthropic")
优点:
- 运行时动态查找
- 解耦工具定义和使用
- 便于扩展新工具
4.2 Agent 类型注册
文件 : trae_agent/agent/agent.py
python
# Agent 类型注册表
AGENT_TYPES: dict[str, type[BaseAgent]] = {
"trae": TraeAgent,
"code_review": CodeReviewAgent,
# ...
}
def create_agent(agent_type: str, config: Config) -> BaseAgent:
"""根据类型创建 Agent"""
if agent_type not in AGENT_TYPES:
raise ValueError(f"Unknown agent type: {agent_type}")
return AGENT_TYPES[agent_type](config)
五、模板方法模式 (Template Method Pattern)
5.1 BaseAgent 执行模板
文件 : trae_agent/agent/base_agent.py
python
class BaseAgent(ABC):
"""Agent 抽象基类,定义执行模板"""
async def execute_task(self) -> AgentExecution:
"""模板方法:定义执行流程"""
# 1. 初始化(固定步骤)
execution = AgentExecution(task=self._task, steps=[])
# 2. 主循环(固定流程)
while step_number <= self._max_steps:
# 3. 执行单步(可定制)
messages = await self._run_llm_step(step, messages, execution)
# 4. 步骤收尾(固定步骤)
await self._finalize_step(step, messages, execution)
# 5. 检查完成(可定制)
if execution.agent_state == AgentState.COMPLETED:
break
# 6. 清理(固定步骤)
await self._close_tools()
return execution
@abstractmethod
async def cleanup_mcp_clients(self) -> None:
"""抽象方法:子类必须实现"""
pass
def reflect_on_result(self, tool_results: list[ToolResult]) -> str | None:
"""钩子方法:子类可重写"""
# 默认实现
...
具体实现:
python
class TraeAgent(BaseAgent):
async def cleanup_mcp_clients(self) -> None:
"""实现抽象方法"""
for client in self._mcp_clients.values():
await client.cleanup()
def reflect_on_result(self, tool_results: list[ToolResult]) -> str | None:
"""重写钩子方法"""
# 自定义反思逻辑
...
六、装饰器模式 (Decorator Pattern)
6.1 重试装饰器
文件 : trae_agent/utils/llm_clients/retry_decorator.py
python
def retry_with(max_retries: int = 3, exceptions: tuple = (Exception,)):
"""重试装饰器工厂"""
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return await func(*args, **kwargs)
except exceptions as e:
if attempt == max_retries - 1:
raise
await asyncio.sleep(2 ** attempt) # 指数退避
return None
return wrapper
return decorator
# 使用
@retry_with(max_retries=10, exceptions=(APIError,))
async def chat_with_llm(self, messages, tools):
...
6.2 属性缓存装饰器
文件 : trae_agent/tools/base.py
python
class Tool(ABC):
"""工具基类,使用 @cached_property 缓存属性"""
@cached_property
def name(self) -> str:
"""缓存工具名称,避免重复计算"""
return self.get_name()
@cached_property
def description(self) -> str:
"""缓存工具描述"""
return self.get_description()
@cached_property
def parameters(self) -> list[ToolParameter]:
"""缓存工具参数"""
return self.get_parameters()
七、代理模式 (Proxy Pattern)
7.1 DockerToolExecutor 代理
文件 : trae_agent/tools/docker_tool_executor.py
python
class DockerToolExecutor:
"""Docker 执行代理,控制对真实执行器的访问"""
def __init__(self, original_executor: ToolExecutor, ...):
self._original_executor = original_executor # 真实执行器
self._docker_manager = docker_manager
async def execute_tool_call(self, tool_call: ToolCall) -> ToolResult:
"""代理方法:决定在哪里执行"""
if self._should_execute_in_docker(tool_call):
# 代理到 Docker
return await self._execute_in_docker(tool_call)
else:
# 委托给真实执行器
return await self._original_executor.execute_tool_call(tool_call)
async def sequential_tool_call(self, tool_calls: list[ToolCall]) -> list[ToolResult]:
"""代理批量执行"""
results = []
for tool_call in tool_calls:
result = await self.execute_tool_call(tool_call)
results.append(result)
return results
优点:
- 透明地添加 Docker 执行层
- 无需修改原有 ToolExecutor 代码
- 灵活控制执行环境
八、观察者模式 (Observer Pattern)
8.1 CLIConsole 状态更新
文件 : trae_agent/agent/base_agent.py
python
class BaseAgent:
def __init__(self, ...):
self._cli_console: CLIConsole | None = None
def set_cli_console(self, cli_console: CLIConsole | None) -> None:
"""注册观察者"""
self._cli_console = cli_console
def _update_cli_console(
self,
step: AgentStep | None = None,
agent_execution: AgentExecution | None = None
) -> None:
"""通知观察者状态变化"""
if self._cli_console:
self._cli_console.update_status(step, agent_execution)
观察者实现:
python
class SimpleConsole(CLIConsole):
def update_status(
self,
agent_step: AgentStep | None = None,
agent_execution: AgentExecution | None = None
):
"""响应状态更新"""
if agent_step:
self._print_step(agent_step)
if agent_execution:
self._print_execution_summary(agent_execution)
8.2 TrajectoryRecorder 轨迹记录
python
class BaseAgent:
def set_trajectory_recorder(self, recorder: TrajectoryRecorder | None) -> None:
"""注册轨迹记录观察者"""
self._trajectory_recorder = recorder
def _record_handler(self, step: AgentStep, messages: list[LLMMessage]) -> None:
"""通知轨迹记录器"""
if self._trajectory_recorder:
self._trajectory_recorder.record_agent_step(...)
九、建造者模式 (Builder Pattern)
9.1 配置构建
文件 : trae_agent/utils/config.py
python
class Config:
"""配置建造者"""
@classmethod
def create(cls, config_file: str | None = None) -> "Config":
"""建造方法:从文件构建配置对象"""
config = cls()
# 1. 构建 model_providers
config.model_providers = cls._build_model_providers(yaml_config)
# 2. 构建 models
config.models = cls._build_models(yaml_config, config.model_providers)
# 3. 构建 agents
config.trae_agent = cls._build_agent(yaml_config, config.models)
return config
@classmethod
def create_from_legacy_config(cls, config_file: str) -> "Config":
"""另一种建造方法:从旧版配置构建"""
legacy_config = LegacyConfig(config_file)
config = cls()
config.model_providers = {...}
config.models = {...}
config.trae_agent = {...}
return config
十、单例模式 (Singleton Pattern)
10.1 BashSession 管理
文件 : trae_agent/tools/bash_tool.py
python
class BashTool(Tool):
"""Bash 工具,维护单一会话"""
def __init__(self, ...):
self._session: _BashSession | None = None
@property
def session(self) -> _BashSession:
"""懒加载单例会话"""
if self._session is None:
self._session = _BashSession()
asyncio.create_task(self._session.start())
return self._session
十一、适配器模式 (Adapter Pattern)
11.1 MCP 工具适配
文件 : trae_agent/tools/mcp_tool.py
python
class MCPTool(Tool):
"""MCP 工具适配器,将 MCP 工具适配为内部 Tool 接口"""
def __init__(self, client, tool: mcp.types.Tool, ...):
self.client = client
self.tool = tool # MCP 工具定义
def get_name(self) -> str:
"""适配:MCP name -> 内部 name"""
return self.tool.name
def get_parameters(self) -> list[ToolParameter]:
"""适配:MCP inputSchema -> 内部 ToolParameter"""
parameters = []
input_schema = self.tool.inputSchema
for name, prop in input_schema.get("properties", {}).items():
parameters.append(ToolParameter(
name=name,
type=prop["type"],
description=prop["description"],
required=name in input_schema.get("required", []),
))
return parameters
async def execute(self, arguments: ToolCallArguments) -> ToolExecResult:
"""适配:内部 execute -> MCP call_tool"""
output = await self.client.call_tool(self.get_name(), arguments)
return ToolExecResult(output=output.content[0].text)
11.2 消息格式适配
文件 : trae_agent/utils/llm_clients/anthropic_client.py
python
class AnthropicClient(BaseLLMClient):
"""将内部消息格式适配为 Anthropic 格式"""
def convert_messages(self, messages: list[LLMMessage]) -> list[MessageParam]:
"""适配消息格式"""
anthropic_messages = []
for msg in messages:
if msg.role == "system":
anthropic_messages.append({
"role": "system",
"content": msg.content
})
elif msg.role == "user":
if msg.tool_result:
# 适配工具结果格式
anthropic_messages.append({
"role": "user",
"content": [{"type": "tool_result", ...}]
})
else:
anthropic_messages.append({
"role": "user",
"content": msg.content
})
return anthropic_messages
十二、命令模式 (Command Pattern)
12.1 工具调用命令
文件 : trae_agent/tools/base.py
python
@dataclass
class ToolCall:
"""命令对象:封装工具调用请求"""
name: str # 命令类型
call_id: str # 命令唯一标识
arguments: dict # 命令参数
class ToolExecutor:
"""命令执行器"""
async def execute_tool_call(self, tool_call: ToolCall) -> ToolResult:
"""执行命令"""
tool = self.tools[tool_call.name]
return await tool.execute(tool_call.arguments)
十三、责任链模式 (Chain of Responsibility)
13.1 配置解析链
文件 : trae_agent/utils/config.py
python
class Config:
"""配置解析责任链"""
@classmethod
def create(cls, config_file: str) -> "Config":
"""按顺序解析配置各部分"""
yaml_config = yaml.safe_load(open(config_file))
# 责任链:必须按顺序解析
# 1. 先解析 providers(基础)
model_providers = cls._parse_providers(yaml_config)
# 2. 再解析 models(依赖 providers)
models = cls._parse_models(yaml_config, model_providers)
# 3. 最后解析 agents(依赖 models)
agents = cls._parse_agents(yaml_config, models)
return Config(
model_providers=model_providers,
models=models,
agents=agents
)
设计模式总结表
| 设计模式 | 应用场景 | 关键文件 | 优点 |
|---|---|---|---|
| 工厂模式 | LLMClient、CLIConsole 创建 | llm_client.py, console_factory.py |
解耦创建逻辑 |
| 抽象工厂 | BaseLLMClient 接口 | base.py |
统一接口,多实现 |
| 策略模式 | 并行/串行工具执行 | base.py |
运行时切换策略 |
| 注册表模式 | 工具、Agent 类型管理 | __init__.py |
动态查找扩展 |
| 模板方法 | BaseAgent 执行流程 | base_agent.py |
复用流程,定制细节 |
| 装饰器模式 | 重试、缓存 | retry_decorator.py |
透明添加功能 |
| 代理模式 | Docker 执行代理 | docker_tool_executor.py |
控制访问 |
| 观察者模式 | CLI 更新、轨迹记录 | base_agent.py |
松耦合通信 |
| 建造者模式 | 配置构建 | config.py |
分步构建复杂对象 |
| 单例模式 | BashSession | bash_tool.py |
全局唯一实例 |
| 适配器模式 | MCP 工具、消息格式 | mcp_tool.py |
接口兼容 |
| 命令模式 | ToolCall 封装 | base.py |
解耦请求和执行 |
| 责任链模式 | 配置解析顺序 | config.py |
按序处理 |
学习建议
- 从简单模式开始 - 先理解工厂、单例等基础模式
- 结合实际场景 - 理解为什么在这个场景使用这个模式
- 关注接口设计 - 模式的核心是良好的接口抽象
- 避免过度设计 - 不要为了用模式而用模式
- 阅读源码注释 - 很多设计意图都在注释中体现
最后更新: 2026-03-16