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

相关推荐
uncle_ll13 小时前
RAG 系统性能跃迁:LlamaIndex 索引优化实战指南
llm·rag·检索·llamaindex
孟健15 小时前
吹爆 OpenClaw!一个人 +6 个 AI 助理,我再也不想招人了
openai·agent·ai编程
周末程序猿16 小时前
再谈Agent Loop:大模型 “能做事” 的核心机制
agent·ai编程
七夜zippoe16 小时前
脉向AI|当豆包手机遭遇“全网封杀“:GUI Agent是通向AGI的必经之路吗?
人工智能·ai·智能手机·agent·gui
prog_610317 小时前
【笔记】思路分享:各种大模型免费当agent后台
笔记·大语言模型·agent·cursor
Bruk.Liu18 小时前
(LangChain 实战14):基于 ChatMessageHistory 自定义实现对话记忆功能
人工智能·python·langchain·agent
无名修道院18 小时前
AI大模型微调-LLM、Token、生成与推理详解
llm·token·ai大模型应用开发
玄同76521 小时前
从 0 到 1:用 Python 开发 MCP 工具,让 AI 智能体拥有 “超能力”
开发语言·人工智能·python·agent·ai编程·mcp·trae
Elwin Wong1 天前
浅析OpenClaw:从“贾维斯”梦想看下一代 AI 操作系统的架构演进
人工智能·agent·clawdbot·moltbot·openclaw
猿小羽1 天前
AIGC 应用工程师(3-5 年)面试题精讲:从基础到实战的系统备战清单
面试·大模型·aigc·agent·rag