LLM交互逻辑全面解析
概述
Trae Agent通过模块化的LLM客户端架构与多种大语言模型进行交互。本文档详细解析LLM交互的完整流程和架构设计。
LLM架构概览
scss
┌─────────────────────────────────────────────────────────────────────────────┐
│ LLM交互架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ BaseAgent │ 调用 LLMClient.chat() │
│ │ (agent层) │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ LLMClient │────▶│ LLMProvider │ 工厂模式创建具体客户端 │
│ │ (工厂类) │ │ (Enum) │ │
│ └────────┬────────┘ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ BaseLLMClient │ 抽象基类,定义统一接口 │
│ │ (ABC) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌─────┼─────┬─────────┬─────────┐ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌────┐┌────┐┌────┐ ┌────┐ ┌────┐ │
│ │Anth││Open││Azur│ │Olla│ │Goog│ 具体实现类 │
│ │ropic││AI ││e │ │ma │ │le │ │
│ └────┘└────┘└────┘ └────┘ └────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
核心组件
1. 数据模型
文件 : trae_agent/utils/llm_clients/llm_basics.py
LLMMessage - 消息格式
python
@dataclass
class LLMMessage:
"""标准消息格式"""
role: str # 角色: system, user, assistant
content: str | None = None # 消息内容
tool_call: ToolCall | None = None # 工具调用
tool_result: ToolResult | None = None # 工具执行结果
LLMResponse - 响应格式
python
@dataclass
class LLMResponse:
"""标准LLM响应格式"""
content: str # 响应内容
usage: LLMUsage | None = None # Token使用情况
model: str | None = None # 模型名称
finish_reason: str | None = None # 完成原因
tool_calls: list[ToolCall] | None = None # 工具调用列表
LLMUsage - Token使用统计
python
@dataclass
class LLMUsage:
"""LLM使用统计"""
input_tokens: int # 输入token数
output_tokens: int # 输出token数
cache_creation_input_tokens: int = 0 # 缓存创建token
cache_read_input_tokens: int = 0 # 缓存读取token
reasoning_tokens: int = 0 # 推理token
2. LLMClient - 工厂类
文件 : trae_agent/utils/llm_clients/llm_client.py
python
class LLMProvider(Enum):
"""支持的LLM提供商"""
OPENAI = "openai"
ANTHROPIC = "anthropic"
AZURE = "azure"
OLLAMA = "ollama"
OPENROUTER = "openrouter"
DOUBAO = "doubao"
GOOGLE = "google"
class LLMClient:
"""主LLM客户端,支持多提供商"""
def __init__(self, model_config: ModelConfig):
self.provider = LLMProvider(model_config.model_provider.provider)
# 工厂模式:根据提供商创建对应客户端
match self.provider:
case LLMProvider.OPENAI:
from .openai_client import OpenAIClient
self.client = OpenAIClient(model_config)
case LLMProvider.ANTHROPIC:
from .anthropic_client import AnthropicClient
self.client = AnthropicClient(model_config)
case LLMProvider.AZURE:
from .azure_client import AzureClient
self.client = AzureClient(model_config)
# ... 其他提供商
def chat(
self,
messages: list[LLMMessage],
model_config: ModelConfig,
tools: list[Tool] | None = None,
reuse_history: bool = True,
) -> LLMResponse:
"""发送聊天消息到LLM"""
return self.client.chat(messages, model_config, tools, reuse_history)
3. BaseLLMClient - 抽象基类
文件 : trae_agent/utils/llm_clients/base_client.py
python
class BaseLLMClient(ABC):
"""LLM客户端抽象基类"""
def __init__(self, model_config: ModelConfig):
self.api_key = model_config.model_provider.api_key
self.base_url = model_config.model_provider.base_url
self.api_version = model_config.model_provider.api_version
self.trajectory_recorder = None
@abstractmethod
def chat(
self,
messages: list[LLMMessage],
model_config: ModelConfig,
tools: list[Tool] | None = None,
reuse_history: bool = True,
) -> LLMResponse:
"""发送聊天消息到LLM"""
pass
def supports_tool_calling(self, model_config: ModelConfig) -> bool:
"""检查是否支持工具调用"""
return model_config.supports_tool_calling
LLM交互流程
完整交互流程图
ini
┌─────────────────────────────────────────────────────────────────────────────┐
│ LLM交互完整流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Agent初始化 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ BaseAgent.__init__() │ │
│ │ self._llm_client = LLMClient(agent_config.model) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 2. LLMClient创建(工厂模式) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ LLMClient.__init__() │ │
│ │ match provider: │ │
│ │ case ANTHROPIC: │ │
│ │ self.client = AnthropicClient(model_config) │ │
│ │ case OPENAI: │ │
│ │ self.client = OpenAIClient(model_config) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 3. 执行步骤时调用LLM │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ BaseAgent._run_llm_step() │ │
│ │ llm_response = self._llm_client.chat( │ │
│ │ messages, model_config, tools │ │
│ │ ) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 4. LLMClient转发调用 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ LLMClient.chat() │ │
│ │ return self.client.chat(messages, model_config, tools) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 5. 具体客户端执行(以Anthropic为例) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ AnthropicClient.chat() │ │
│ │ # 1. 转换消息格式 │ │
│ │ anthropic_messages = self.parse_messages(messages) │ │
│ │ │ │
│ │ # 2. 转换工具格式 │ │
│ │ tool_schemas = self._convert_tools(tools) │ │
│ │ │ │
│ │ # 3. 调用API(带重试) │ │
│ │ response = self._create_anthropic_response(...) │ │
│ │ │ │
│ │ # 4. 转换响应格式 │ │
│ │ return self._convert_response(response) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 6. 返回LLMResponse │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ LLMResponse( │ │
│ │ content="我来分析这个问题...", │ │
│ │ usage=LLMUsage(...), │ │
│ │ tool_calls=[ToolCall(...)] # 如果有工具调用 │ │
│ │ ) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
具体客户端实现
AnthropicClient
文件 : trae_agent/utils/llm_clients/anthropic_client.py
python
class AnthropicClient(BaseLLMClient):
"""Anthropic客户端封装"""
def __init__(self, model_config: ModelConfig):
super().__init__(model_config)
self.client = anthropic.Anthropic(
api_key=self.api_key,
base_url=self.base_url
)
self.message_history = []
def chat(self, messages, model_config, tools, reuse_history):
"""发送消息到Anthropic API"""
# 1. 转换消息格式
anthropic_messages = self.parse_messages(messages)
# 2. 更新历史
if reuse_history:
self.message_history.extend(anthropic_messages)
else:
self.message_history = anthropic_messages
# 3. 转换工具格式
tool_schemas = []
if tools:
for tool in tools:
if tool.name == "str_replace_based_edit_tool":
# Anthropic特殊工具
tool_schemas.append(
TextEditor20250429(...)
)
else:
# 普通工具
tool_schemas.append(
anthropic.types.ToolParam(...)
)
# 4. 调用API(带重试)
response = self._create_anthropic_response(
model_config, tool_schemas
)
# 5. 转换响应
return self._convert_response(response)
OpenAICompatibleClient
文件 : trae_agent/utils/llm_clients/openai_compatible_base.py
python
class OpenAICompatibleClient(BaseLLMClient):
"""OpenAI兼容客户端基类"""
def __init__(self, model_config, provider_config):
super().__init__(model_config)
self.provider_config = provider_config
self.client = provider_config.create_client(
self.api_key, self.base_url, self.api_version
)
def chat(self, messages, model_config, tools, reuse_history):
"""发送消息到OpenAI兼容API"""
# 1. 转换消息格式
openai_messages = self.parse_messages(messages)
self.message_history = openai_messages
# 2. 转换工具格式
tool_schemas = None
if tools:
tool_schemas = [
ChatCompletionToolParam(
type="function",
function=FunctionDefinition(...)
)
for tool in tools
]
# 3. 调用API
response = self.client.chat.completions.create(
model=model_config.model,
messages=self.message_history,
tools=tool_schemas,
temperature=model_config.temperature,
max_tokens=model_config.max_tokens,
)
# 4. 转换响应
return self._convert_response(response)
继承OpenAICompatibleClient的客户端:
OpenAIClient- OpenAI官方AzureClient- Azure OpenAIOpenRouterClient- OpenRouterDoubaoClient- 豆包
消息格式转换
消息转换流程
python
# Trae Agent内部格式
llm_messages = [
LLMMessage(role="system", content="You are..."),
LLMMessage(role="user", content="修复这个bug..."),
LLMMessage(role="user", tool_result=ToolResult(...)),
]
# 转换为Anthropic格式
anthropic_messages = [
{"role": "user", "content": "修复这个bug..."},
{"role": "user", "content": [{"type": "tool_result", ...}]},
]
# 转换为OpenAI格式
openai_messages = [
{"role": "system", "content": "You are..."},
{"role": "user", "content": "修复这个bug..."},
{"role": "tool", "content": "...", "tool_call_id": "..."},
]
工具调用支持
工具格式转换
python
# Trae Agent工具格式
class Tool:
name: str
description: str
def get_parameters(self) -> list[ToolParameter]: ...
# Anthropic工具格式
anthropic.types.ToolParam(
name=tool.name,
description=tool.description,
input_schema=tool.get_input_schema(),
)
# OpenAI工具格式
ChatCompletionToolParam(
type="function",
function=FunctionDefinition(
name=tool.name,
description=tool.description,
parameters=tool.get_input_schema(),
),
)
重试机制
文件 : trae_agent/utils/llm_clients/retry_utils.py
python
def retry_with(func, provider_name, max_retries):
"""为API调用添加重试逻辑"""
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except APIError as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # 指数退避
time.sleep(wait_time)
else:
raise
return wrapper
Agent中的LLM调用
BaseAgent._run_llm_step
文件 : trae_agent/agent/base_agent.py (第210-236行)
python
async def _run_llm_step(
self,
step: AgentStep,
messages: list[LLMMessage],
execution: AgentExecution
) -> list[LLMMessage]:
"""执行一步LLM交互"""
# 1. 设置状态为思考中
step.state = AgentStepState.THINKING
self._update_cli_console(step, execution)
# 2. 调用LLM
llm_response = self._llm_client.chat(
messages,
self._model_config,
self._tools
)
step.llm_response = llm_response
# 3. 更新显示
self._update_cli_console(step, execution)
# 4. 更新token使用统计
self._update_llm_usage(llm_response, execution)
# 5. 检查是否完成
if self.llm_indicates_task_completed(llm_response):
if self._is_task_completed(llm_response):
execution.agent_state = AgentState.COMPLETED
execution.final_result = llm_response.content
execution.success = True
return messages
# 6. 处理工具调用
tool_calls = llm_response.tool_calls
return await self._tool_call_handler(tool_calls, step)
核心文件索引
| 文件 | 职责 | 重要性 |
|---|---|---|
llm_clients/llm_basics.py |
数据模型定义 | ⭐⭐⭐ |
llm_clients/llm_client.py |
工厂类,创建客户端 | ⭐⭐⭐ |
llm_clients/base_client.py |
抽象基类 | ⭐⭐⭐ |
llm_clients/anthropic_client.py |
Anthropic实现 | ⭐⭐⭐ |
llm_clients/openai_compatible_base.py |
OpenAI兼容基类 | ⭐⭐⭐ |
llm_clients/openai_client.py |
OpenAI实现 | ⭐⭐ |
llm_clients/azure_client.py |
Azure实现 | ⭐⭐ |
llm_clients/retry_utils.py |
重试逻辑 | ⭐⭐ |
agent/base_agent.py |
Agent调用LLM | ⭐⭐⭐ |
设计模式总结
1. 工厂模式 (Factory Pattern)
python
# LLMClient根据配置创建对应客户端
match self.provider:
case LLMProvider.ANTHROPIC:
self.client = AnthropicClient(model_config)
case LLMProvider.OPENAI:
self.client = OpenAIClient(model_config)
2. 策略模式 (Strategy Pattern)
python
# 不同提供商实现相同的chat接口
class AnthropicClient(BaseLLMClient):
def chat(self, ...): ... # Anthropic实现
class OpenAIClient(BaseLLMClient):
def chat(self, ...): ... # OpenAI实现
3. 适配器模式 (Adapter Pattern)
python
# 将内部LLMMessage转换为各提供商格式
anthropic_messages = self.parse_messages(messages)
openai_messages = self.parse_messages(messages)
总结
Trae Agent的LLM交互架构设计清晰:
- 统一接口 - BaseLLMClient定义统一接口
- 工厂创建 - LLMClient根据配置创建对应客户端
- 格式转换 - 自动转换消息和工具格式
- 重试机制 - 内置指数退避重试
- 多提供商支持 - 支持7+种LLM提供商
这种设计使得添加新的LLM提供商变得简单,只需实现BaseLLMClient接口即可。
最后更新: 2026-03-16