Agent层与CLI层对接机制详解
📊 整体架构
用户命令 (trae-cli run "...")
↓
CLI层 (cli.py)
├── 参数解析
├── 配置加载
├── 创建Agent实例
└── 调用Agent.run()
↓
Agent层 (agent.py + base_agent.py)
├── 接收任务
├── 执行循环
├── 通过CLIConsole输出
└── 返回AgentExecution
↓
CLI层
├── 显示结果
└── 保存轨迹
🎯 对接流程详解
步骤1:CLI层创建Agent实例
文件位置: trae_agent/cli.py (第325-352行)
# CLI层创建Agent
agent = Agent(
agent_type, # Agent类型 (如"trae_agent")
config, # 配置对象
trajectory_file, # 轨迹文件路径
cli_console, # CLI控制台接口 ⭐ 关键对接点
docker_config, # Docker配置
docker_keep, # 是否保持容器
)
关键点:
- cli_console 是CLI层与Agent层的主要通信桥梁
- CLI层创建
CLIConsole实例并传递给Agent - Agent通过这个接口向CLI层发送输出
步骤2:Agent层接收CLIConsole
文件位置: trae_agent/agent/agent.py (第30-50行)
class Agent:
def __init__(
self,
agent_type: AgentType | str,
config: Config,
trajectory_file: str | None,
cli_console: CLIConsole | None, # ⭐ 接收CLI控制台
docker_config: dict | None,
docker_keep: bool = True,
):
# 保存CLI控制台引用
self._cli_console = cli_console
# 创建具体Agent (如TraeAgent)
match self.agent_type:
case AgentType.TraeAgent:
self.agent = TraeAgent(...)
# 设置CLI控制台到具体Agent
self.agent.set_cli_console(cli_console)
关键点:
- Agent保存
cli_console引用 - 将CLI控制台传递给具体的Agent实现
- Agent通过这个接口向用户输出信息
步骤3:CLI层调用Agent.run()
文件位置: trae_agent/cli.py (第352-357行)
# CLI层调用Agent执行
try:
execution = await agent.run(task, task_args)
# task_args = {
# "project_path": working_dir,
# "issue": task,
# "must_patch": "true"|"false",
# "patch_path": patch_path,
# }
finally:
console.print(f"\n[green]Trajectory saved to: {agent.trajectory_file}[/green]")
关键点:
- CLI调用
agent.run()是异步调用 (await) - 传递任务参数给Agent
- Agent返回
AgentExecution对象 - CLI处理最终结果和错误
步骤4:Agent层通过CLIConsole输出
文件位置: trae_agent/agent/agent.py (第70-80行)
async def run(
self,
task: str,
extra_args: dict[str, str] | None,
tool_names: list[str] | None,
):
# 1. 通过CLIConsole显示任务详情 ⭐
if self.agent.cli_console:
task_details = {
"Task": task,
"Model Provider": self.agent_config.model.model_provider.provider,
"Model": self.agent_config.model.model,
"Max Steps": str(self.agent_config.max_steps),
"Trajectory File": self.trajectory_file,
"Tools": ", ".join([tool.name for tool in self.agent.tools]),
}
self.agent.cli_console.print_task_details(task_details)
# 2. 调用Agent执行
execution = await self.agent.execute_task()
# 3. 启动CLI控制台任务
cli_console_task = (
asyncio.create_task(self.agent.cli_console.start())
if self.agent.cli_console else None
)
关键点:
- Agent通过
cli_console.print_task_details()显示任务信息 - Agent通过
cli_console.start()启动交互式输出 - CLIConsole负责实际的终端输出
步骤5:BaseAgent执行循环与CLI通信
文件位置: trae_agent/agent/base_agent.py (第100-180行)
async def execute_task(self) -> AgentExecution:
messages = self._initial_messages
step_number = 1
while step_number <= self._max_steps:
# 1. 创建步骤
step = AgentStep(step_number=step_number, state=AgentStepState.THINKING)
# 2. 调用LLM
messages = await self._run_llm_step(step, messages, execution)
# 3. 完成步骤,通过CLI输出 ⭐
await self._finalize_step(step, messages, execution)
# 4. 检查是否完成
if execution.agent_state == AgentState.COMPLETED:
break
step_number += 1
finalize_step方法:
async def _finalize_step(
self,
step: AgentStep,
messages: list[LLMMessage],
execution: AgentExecution,
):
# 1. 记录轨迹
if self._trajectory_recorder:
self._trajectory_recorder.record_step(...)
# 2. 通过CLIConsole输出 ⭐
if self._cli_console:
self._cli_console.update_step(step, messages, execution)
关键点:
- 每个步骤完成后,通过
_cli_console.update_step()更新CLI显示 - CLIConsole负责格式化和显示Agent的每个步骤
- 实时更新用户界面
🔌 CLIConsole接口
接口定义
文件位置: trae_agent/utils/cli/cli_console.py
class CLIConsole(ABC):
@abstractmethod
def print_task_details(self, task_details: dict) -> None:
"""打印任务详情"""
pass
@abstractmethod
def update_step(self, step: AgentStep, messages: list, execution: AgentExecution) -> None:
"""更新步骤显示"""
pass
@abstractmethod
def start(self) -> None:
"""启动控制台(交互模式)"""
pass
@abstractmethod
def finalize(self, execution: AgentExecution) -> None:
"""完成执行"""
pass
实现类
RichConsole - 丰富的终端输出
- 使用Rich库美化输出
- 支持进度条、表格、面板
- 交互式界面
SimpleConsole - 简单终端输出
- 基础的print输出
- 适合脚本和CI/CD
📊 数据流转图
┌─────────────────────────────────────────────────────────────┐
│ CLI层 (cli.py) │
│ │
│ 1. 解析参数: trae-cli run "task" │
│ 2. 加载配置: Config.create() │
│ 3. 创建CLIConsole: ConsoleFactory.create() │
│ 4. 创建Agent: Agent(agent_type, config, ...) │
└─────────────────────────────────────────────────────────────┘
↓
传递 (cli_console)
┌─────────────────────────────────────────────────────────────┐
│ Agent层 (agent.py) │
│ │
│ 1. 接收CLIConsole: self._cli_console │
│ 2. 显示任务: cli_console.print_task_details() │
│ 3. 执行任务: execute_task() │
│ 4. 更新步骤: cli_console.update_step() │
│ 5. 返回结果: AgentExecution │
└─────────────────────────────────────────────────────────────┘
↓
返回 (execution)
┌─────────────────────────────────────────────────────────────┐
│ CLI层 (cli.py) │
│ │
│ 1. 接收结果: execution = await agent.run() │
│ 2. 显示轨迹: console.print(...) │
│ 3. 保存文件: 轨迹文件 │
│ 4. 退出程序: sys.exit(0) │
└─────────────────────────────────────────────────────────────┘
🎯 核心对接机制总结
1. 依赖注入模式
CLI层通过构造函数将依赖注入到Agent层:
agent = Agent(
agent_type,
config, # 依赖注入
cli_console, # 依赖注入 ⭐
docker_config, # 依赖注入
)
2. 接口隔离
CLI层和Agent层通过抽象接口通信:
CLIConsole抽象基类- Agent不直接操作终端
- 通过接口方法输出信息
3. 异步协作
CLI层和Agent层使用异步协作:
# CLI层
execution = await agent.run(task, task_args)
# Agent层
async def run(self, task, extra_args) -> AgentExecution:
# 异步执行
execution = await self.agent.execute_task()
return execution
4. 状态管理
Agent层管理执行状态,通过CLIConsole更新显示:
# Agent层
execution.agent_state = AgentState.RUNNING
self._cli_console.update_step(step, messages, execution)
💡 学习要点
- CLIConsole是关键 - 它是两层之间的通信桥梁
- 依赖注入 - CLI层将配置和控制台注入到Agent
- 接口抽象 - 使用抽象类实现解耦
- 异步协作 - 两层都使用async/await
- 单向通信 - CLI → Agent → CLI(主要流程)
🔗 关键文件索引
| 文件 | 行数 | 职责 | 重要性 |
|---|---|---|---|
cli.py | 325-357 | CLI入口,创建Agent | ⭐⭐⭐ |
agent/agent.py | 30-80 | Agent包装,接收CLIConsole | ⭐⭐⭐ |
agent/base_agent.py | 100-180 | 核心执行,调用CLIConsole | ⭐⭐⭐ |
utils/cli/cli_console.py | 全部 | CLIConsole抽象接口 | ⭐⭐⭐ |
utils/cli/rich_console.py | 全部 | Rich实现 | ⭐⭐ |
utils/cli/simple_console.py | 全部 | Simple实现 | ⭐⭐ |
最后更新: 2025-03-10