Trae-Agent中LLM Client深度分析

引言

在之前的文章,我们分析了Trae Agent整体执行思路和LLM是如何调用内置工具的一些细节。还有一块内容我觉得是有必要了解到,就是Agent对于LLM客户端的封装,毕竟每个供应商提供的LLM使用方式都有些差异,Agent需要将差异性封装起来,使我们使用LLM时使用一个统一的LLM Client对象就可以和LLM进行交互了。

Agent 如何使用 LLMClient

LLMClient在使用上十分的简介,重点的就是初始化、设置轨迹记录器、chat。屏蔽了LLM供应商的细节。

LLMClient下的内容

这里需要用一个类图来展示llm_client.py中的内容了,它是一个工厂模式,根据我们允许命令时指定要使用的LLM供应商,来决定是实例化某一个对象,比如我们执行"trae-cli run "写一个最简单的网页" --provider doubao",会实例化DouBaoClient。可以看到LLMClient下包含了各种供应商Client。

DouBaoClient实现分析

基于 doubao_client.py 的代码,我们来分析一下实现一个 LLM 供应商客户端需要的关键细节。

初始化配置

python 复制代码
def __init__(self, model_parameters: ModelParameters):
    super().__init__(model_parameters)
    
    # 1. API Key 获取(环境变量 + 配置文件)
    if self.api_key == "":
        self.api_key: str = os.getenv("DOUBAO_API_KEY", "")
    
    # 2. Base URL 配置
    if self.base_url is None or self.base_url == "":
        self.base_url: str | None = os.getenv("DOUBAO_API_BASE_URL")
    
    # 3. 创建底层客户端
    self.client: openai.OpenAI = openai.OpenAI(
        base_url=self.base_url, api_key=self.api_key
    )
    
    # 4. 初始化消息历史
    self.message_history: list[ChatCompletionMessageParam] = []

核心实现的方法

ini 复制代码
@override
def chat(
    self,
    messages: list[LLMMessage],
    model_parameters: ModelParameters,
    tools: list[Tool] | None = None,
    reuse_history: bool = True,
) -> LLMResponse:
    # 1. 消息格式转换
    doubao_messages = self.parse_messages(messages)
    
    # 2. 历史消息管理
    if reuse_history:
        self.message_history = self.message_history + doubao_messages
    else:
        self.message_history = doubao_messages
    
    # 3. 工具模式转换
    tool_schemas = None
    if tools:
        tool_schemas = [
            ChatCompletionToolParam(
                function=FunctionDefinition(
                    name=tool.get_name(),
                    description=tool.get_description(),
                    parameters=tool.get_input_schema(),
                ),
                type="function",
            )
            for tool in tools
        ]
    
    # 4. API 调用(带重试机制)
    response = None
    for i in range(model_parameters.max_retries):
        try:
            response = self.client.chat.completions.create(
                model=model_parameters.model,
                messages=self.message_history,
                tools=tool_schemas if tool_schemas else openai.NOT_GIVEN,
                temperature=model_parameters.temperature,
                top_p=model_parameters.top_p,
                max_tokens=model_parameters.max_tokens,
                n=1,
            )
            break
        except Exception as e:
            # 重试逻辑
            time.sleep(random.randint(3, 30))
            continue
    
    # 5. 响应解析和格式转换
    choice = response.choices[0]
    
    # 6. 工具调用解析
    tool_calls: list[ToolCall] | None = None
    if choice.message.tool_calls:
        tool_calls = [
            ToolCall(
                name=tool_call.function.name,
                call_id=tool_call.id,
                arguments=json.loads(tool_call.function.arguments)
            )
            for tool_call in choice.message.tool_calls
        ]
    
    # 7. 构建标准响应
    llm_response = LLMResponse(
        content=choice.message.content or "",
        tool_calls=tool_calls,
        finish_reason=choice.finish_reason,
        model=response.model,
        usage=LLMUsage(
            input_tokens=response.usage.prompt_tokens,
            output_tokens=response.usage.completion_tokens,
        )
    )
    
    # 8. 更新消息历史
    # ... 历史更新逻辑
    
    # 9. 轨迹记录
    if self.trajectory_recorder:
        self.trajectory_recorder.record_llm_interaction(
            messages=messages,
            response=llm_response,
            provider="doubao",
            model=model_parameters.model,
            tools=tools,
        )
    
    return llm_response

细节:豆包客户端使用了OpenAI兼容的API格式,可以直接使用OpenAI 的 Python SDK 作为底层实现。

具体Client之间的差异

每个Client实现类都略微有些差异。比如DoubaoClient和OpenAIClient底层SDK都是用openai Python SDK,AnthropicClient使用原生 anthropic Python SDK。

在消息处理上,DoubaoClient & OpenAIClient都使用相同的 OpenAI 消息格式,AnthropicClient会是用 Anthropic 特有格式。

还有在工具调用、响应处理等方面,不同的Client都会有些差异。

OpenRouterClient分析

我注意到有一个openai_client.py。它的特别指出在于不是一个具体的 LLM 供应商 ,而是一个 LLM 聚合服务平台 。它的作用类似于一个"中介"或"代理",提供统一的 API 接口来访问多个不同的 LLM 提供商。

OpenRouter 的优势

  1. 统一接口 : 通过一个 API 访问多个 LLM 提供商
  2. 模型选择 : 可以在不同模型间轻松切换
  3. 成本优化 : 可以根据价格和性能选择最合适的模型
  4. 简化集成 : 不需要为每个 LLM 提供商单独集成
  5. OpenAI 兼容 : 使用熟悉的 OpenAI API 格式

总结

这篇文章,我们对Agent中LLM Client的封装也有了一定的了解。这让我们学习到一个程序如何调用LLM的诸多细节。接下来会持续关注Trae Agent开源库的发展,会给我们带来什么新的思路和创意。

相关推荐
AI大模型2 小时前
【保姆级教程】开源 Qwen3 本地部署实操详细教程
程序员·llm·agent
AI大模型2 小时前
【保姆级教程】有手就行,字节Coze开源版本地部署完整指南,只需6步!
llm·agent·coze
hayson3 小时前
langchaingo用法详解及源码解析(二)
langchain·llm
高克莱3 小时前
【macOS操作系统部署开源DeepSeek大模型,搭建Agent平台,构建私有化RAG知识库完整流程】
macos·llm·agent·知识库·anythingllm·ollama·deepseek
聚客AI4 小时前
📰多智能体才是未来:深度解析多Agent架构带你从零到生产级部署
人工智能·llm·agent
袁庭新8 小时前
五大提示词撰写原则
llm·aigc·deepseek
哔哩哔哩技术9 小时前
ICML25 视频问答中以语言为中心的结构化推理
llm
ai2things10 小时前
OpenAI 模型命名(GPT-5)
llm
Baihai_IDP10 小时前
AI 智能体记忆机制详解
人工智能·面试·llm
七超AI落地实操11 小时前
从 Coze 到 Dify:一个 智能体开发者的趟坑与顿悟
人工智能·agent