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开源库的发展,会给我们带来什么新的思路和创意。

相关推荐
聚客AI1 小时前
🔥 大模型开发进阶:基于LangChain的异步流式响应与性能优化
人工智能·langchain·agent
堆栈future2 小时前
大模型时代的三巨头—Grok、ChatGPT与Gemini深度解析
llm·aigc·openai
大千AI助手2 小时前
BERT:双向Transformer革命 | 重塑自然语言理解的预训练范式
人工智能·深度学习·机器学习·自然语言处理·llm·bert·transformer
后端小肥肠3 小时前
效率革命!10分钟用Dify+Spring Boot打造AI热点雷达,自媒体选赛道再不难!(附保姆级教程)
人工智能·spring boot·agent
静Yu3 小时前
蚂蚁百宝箱|快速搭建会讲故事、读新闻的智能体
前端·agent
ai2things4 小时前
Generative agents 编译运行
agent
在努力的韩小豪16 小时前
如何从0开始构建自己的第一个AI应用?(Prompt工程、Agent自定义、Tuning)
人工智能·python·llm·prompt·agent·ai应用·mcp
weikuo05061 天前
【手搓大模型】从零手写GPT2 — Attention
llm
weikuo05061 天前
【手搓大模型】从零手写GPT2 — Embedding
llm