Agent开发第1步:抽象模型接口 (Model Adapter)

60 阅读3分钟

在开发一个智能 Agent 时,最核心的“大脑”就是大语言模型(LLM)。不同的 LLM 厂商(如 OpenAI、Anthropic、智谱等)提供了各自的 API 格式。为了让我们的 Agent 能够无缝切换和兼容不同的模型,我们需要在第1步引入 模型适配器 (Model Adapter) 的概念。

1. 为什么需要 Model Adapter?

如果没有适配器,我们的核心业务代码将会和具体的 LLM API 强耦合,这会导致后期更换模型成本极高。通过抽象一层 Model Adapter,我们可以将各种大模型的接口统一封装,向上层暴露一致的提问与流式返回接口。

mermaid diagram

2. 两种常见的 API 交互模式

在抽象模型接口时,我们通常需要处理两种主流的交互模式:

模式一:Chat Completion API(手动维护上下文)

这是最基础也最常见的模式。每次请求时,客户端需要将整个对话历史(Context)发送给服务器。

工作流: mermaid diagram

Python 代码示例:

from typing import List, Dict, Generator
import openai

class ChatCompletionAdapter:
    def __init__(self, api_key: str, model: str = "gpt-4o"):
        self.client = openai.Client(api_key=api_key)
        self.model = model

    def chat_stream(self, messages: List[Dict[str, str]]) -> Generator[str, None, None]:
        """
        手动维护上下文模式
        :param messages: 完整的对话历史,例如 [{"role": "user", "content": "你好"}]
        """
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            stream=True
        )
        
        for chunk in response:
            if chunk.choices[0].delta.content is not None:
                yield chunk.choices[0].delta.content

# 使用示例
adapter = ChatCompletionAdapter(api_key="your-api-key")
history = [
    {"role": "system", "content": "你是一个有用的助手。"},
    {"role": "user", "content": "请用Python写一个Hello World。"}
]

print("Assistant: ", end="")
for token in adapter.chat_stream(history):
    print(token, end="", flush=True)

模式二:Responses / Threads API(自动托管上下文)

随着 OpenAI Assistants API 等新型接口的推出,服务端开始支持托管对话状态(Threads)。在这种模式下,我们只需要传入一个 Thread ID,服务器会自动维护历史记录,无需每次传递冗长的上下文。

工作流: mermaid diagram

Python 代码示例:

class ThreadResponseAdapter:
    def __init__(self, api_key: str):
        self.client = openai.Client(api_key=api_key)

    def add_message_and_run(self, thread_id: str, assistant_id: str, new_message: str) -> Generator[str, None, None]:
        """
        托管上下文模式
        :param thread_id: 服务端维护的会话 ID
        :param assistant_id: 关联的 Assistant ID
        :param new_message: 当前用户的最新提问
        """
        # 1. 向 Thread 中追加新消息
        self.client.beta.threads.messages.create(
            thread_id=thread_id,
            role="user",
            content=new_message
        )
        
        # 2. 运行 Assistant 并流式获取结果
        stream = self.client.beta.threads.runs.create_and_stream(
            thread_id=thread_id,
            assistant_id=assistant_id
        )
        
        for event in stream:
            if event.event == 'thread.message.delta':
                yield event.data.delta.content[0].text.value

# 使用示例
adapter = ThreadResponseAdapter(api_key="your-api-key")
# 假设 thread_id 和 assistant_id 已经提前创建好
for token in adapter.add_message_and_run("thread_123", "asst_456", "我刚才问了你什么?"):
    print(token, end="", flush=True)

总结

通过引入 Model Adapter,我们为 Agent 提供了一个干净的文本输入输出层。无论是传统的 Chat Completion 还是先进的 Threads API,都可以被隐藏在统一的接口之后。这是搭建强大 Agent 框架的基石。在下一篇文章中,我们将探讨如何为这个“大脑”装上可以操作外部世界的“双手”——定义工具抽象 (Tools)。