LangChain的create_agent函数基于LangGraph构建了图形化的智能体运行时。在这个架构中,智能体被构建为一个由节点(步骤)和边(连接)组成的图,定义了信息处理的流程。
那么,背后的实现原理和执行过程究竟是怎样的呢?
这里,我将为您实现一个原生版本的 create_agent 功能,使用 Python 和通用的 LLM MaaS API。这个实现将模拟 LangChain 的代理功能,但使用原生 API 调用。
import json
import requests
from typing import List, Dict, Any, Union, Callable, Optional
from dataclasses import dataclass
import time
@dataclass
class Tool:
"""表示一个可用的工具"""
name: str
description: str
func: Callable
args_schema: Optional[Dict] = None
class LLMModel:
"""LLM 模型的抽象类"""
def __init__(self, model_name: str, **kwargs):
self.model_name = model_name
self.kwargs = kwargs
def invoke(self, messages: List[Dict[str, str]]) -> str:
"""调用模型并返回响应"""
raise NotImplementedError
class OpenAIModel(LLMModel):
"""OpenAI 模型的实现"""
def __init__(self, model: str, api_key: str, temperature: float = 0.7,
max_tokens: int = 1000, timeout: int = 30, **kwargs):
super().__init__(model, **kwargs)
self.api_key = api_key
self.temperature = temperature
self.max_tokens = max_tokens
self.timeout = timeout
self.base_url = kwargs.get("base_url", "https://api.openai.com/v1")
def invoke(self, messages: List[Dict[str, str]]) -> str:
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
data = {
"model": self.model_name,
"messages": messages,
"temperature": self.temperature,
"max_tokens": self.max_tokens
}
try:
response = requests.post(
f"{self.base_url}/chat/completions",
headers=headers,
json=data,
timeout=self.timeout
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except Exception as e:
raise Exception(f"Error calling OpenAI API: {str(e)}")
class Agent:
"""智能代理类"""
def __init__(self, model: LLMModel, tools: List[Tool]):
self.model = model
self.tools = {tool.name: tool for tool in tools}
self.system_prompt = self._build_system_prompt()
def _build_system_prompt(self) -> str:
"""构建系统提示,包含工具信息"""
tools_info = "\n".join([
f"- {tool.name}: {tool.description}"
for tool in self.tools.values()
])
return f"""你是一个智能助手,可以使用以下工具来帮助用户回答问题:
{tools_info}
当需要使用工具时,请使用以下JSON格式:
{
"tool": "工具名称",
"args": {
"参数名": "参数值"
}
}
如果不需要使用工具,请直接回答问题。"""
def _parse_tool_call(self, response: str) -> Optional[Dict[str, Any]]:
"""解析模型响应中的工具调用"""
try:
# 尝试提取JSON格式的工具调用
start_idx = response.find("{")
end_idx = response.rfind("}") + 1
if start_idx != -1 and end_idx != 0:
json_str = response[start_idx:end_idx]
return json.loads(json_str)
except json.JSONDecodeError:
pass
return None
def _execute_tool(self, tool_name: str, args: Dict[str, Any]) -> str:
"""执行指定的工具"""
if tool_name not in self.tools:
return f"错误: 未找到工具 '{tool_name}'"
tool = self.tools[tool_name]
try:
result = tool.func(**args)
return str(result)
except Exception as e:
return f"执行工具 '{tool_name}' 时出错: {str(e)}"
def run(self, query: str) -> str:
"""运行代理,处理用户查询"""
messages = [
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": query}
]
max_iterations = 5 # 防止无限循环
iteration = 0
while iteration < max_iterations:
iteration += 1
# 调用模型
response = self.model.invoke(messages)
# 检查是否需要调用工具
tool_call = self._parse_tool_call(response)
if tool_call and "tool" in tool_call:
tool_name = tool_call["tool"]
tool_args = tool_call.get("args", {})
# 执行工具
tool_result = self._execute_tool(tool_name, tool_args)
# 将工具调用和结果添加到对话历史
messages.append({"role": "assistant", "content": response})
messages.append({
"role": "system",
"content": f"工具 '{tool_name}' 的执行结果: {tool_result}"
})
# 继续对话,让模型基于工具结果回答
continue
else:
# 模型直接回答,不需要工具
return response
return "抱歉,处理您的请求时遇到了问题。"
def create_agent(model: Union[str, LLMModel], tools: List[Tool], **kwargs) -> Agent:
"""
创建一个智能代理
参数:
model: 模型标识符字符串或模型实例
tools: 工具列表
**kwargs: 额外的模型参数
返回:
Agent 实例
"""
# 如果 model 是字符串,创建对应的模型实例
if isinstance(model, str):
# 解析模型标识符,格式如 "provider:model"
if ":" in model:
provider, model_name = model.split(":", 1)
else:
provider = "openai"
model_name = model
# 根据提供商创建模型实例
if provider.lower() == "openai":
api_key = kwargs.get("api_key")
if not api_key:
raise ValueError("OpenAI 模型需要提供 api_key")
model = OpenAIModel(
model=model_name,
api_key=api_key,
temperature=kwargs.get("temperature", 0.7),
max_tokens=kwargs.get("max_tokens", 1000),
timeout=kwargs.get("timeout", 30)
)
else:
raise ValueError(f"不支持的模型提供商: {provider}")
# 创建并返回代理
return Agent(model, tools)
# 示例使用
if __name__ == "__main__":
# 定义一些示例工具
def calculator(expression: str) -> float:
"""计算数学表达式"""
return eval(expression)
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
# 这里只是模拟,实际应用中会调用天气API
return f"{city}今天晴朗,温度25°C"
def search_web(query: str) -> str:
"""在网络上搜索信息"""
# 这里只是模拟,实际应用中会调用搜索API
return f"关于'{query}'的搜索结果:这是一个模拟的搜索结果。"
# 创建工具列表
tools = [
Tool(
name="calculator",
description="用于计算数学表达式",
func=calculator,
args_schema={"expression": "string"}
),
Tool(
name="get_weather",
description="获取指定城市的天气信息",
func=get_weather,
args_schema={"city": "string"}
),
Tool(
name="search_web",
description="在网络上搜索信息",
func=search_web,
args_schema={"query": "string"}
)
]
# 使用模型标识符字符串创建代理
# 注意:这里需要替换为实际的API密钥
api_key = "your-api-key-here"
# 示例1:使用模型标识符字符串
agent1 = create_agent(
"openai:gpt-3.5-turbo",
tools=tools,
api_key=api_key,
temperature=0.1,
max_tokens=1000,
timeout=30
)
# 示例2:使用模型实例
model = OpenAIModel(
model="gpt-3.5-turbo",
api_key=api_key,
temperature=0.1,
max_tokens=1000,
timeout=30
)
agent2 = create_agent(model, tools=tools)
# 测试代理
print("测试代理1:")
response1 = agent1.run("计算 123 * 456 的结果")
print(response1)
print("\n测试代理2:")
response2 = agent2.run("北京今天的天气怎么样?")
print(response2)
这个实现包含以下关键组件:
- Tool 类:表示可用的工具,包含名称、描述和执行函数
- LLMModel 抽象类:定义了模型的接口
- OpenAIModel 类:实现了 OpenAI API 的调用
- Agent 类:核心代理逻辑,能够解析用户请求并选择合适的工具
- create_agent 函数:根据输入创建代理实例,支持字符串标识符或模型实例
这个实现模拟了 LangChain 的代理功能,但使用原生 API 调用。您可以根据需要扩展它,例如添加更多模型提供商的支持或增强工具调用逻辑。
要实现类似LangChain中create_agent的功能,我们需要原生封装LLM调用、工具管理和决策逻辑。以下是基于MaaS API(以OpenAI风格为例)的实现方案:
核心思路
Agent的核心功能是:接收用户输入 → 决定是否调用工具 → 执行工具(如需)→ 整理结果生成回答。实现需包含:
- 模型调用封装(对接MaaS API)
- 工具管理(定义工具结构与调用逻辑)
- 决策引导(通过提示词让模型判断是否使用工具)
- 流程控制(循环处理工具调用与结果整合)
完整代码实现
import json
import requests
from typing import List, Dict, Callable, Any
# 1. 模型调用封装(对接MaaS API)
class LLMChatModel:
"""封装LLM的MaaS API调用,支持模型参数配置"""
def __init__(
self,
model: str,
api_key: str,
base_url: str = "https://api.openai.com/v1/chat/completions", # 可替换为其他MaaS接口
temperature: float = 0.1,
max_tokens: int = 1000,
timeout: int = 30
):
self.model = model
self.api_key = api_key
self.base_url = base_url
self.temperature = temperature
self.max_tokens = max_tokens
self.timeout = timeout
def generate(self, messages: List[Dict[str, str]]) -> str:
"""调用MaaS API生成响应"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
payload = {
"model": self.model,
"messages": messages,
"temperature": self.temperature,
"max_tokens": self.max_tokens
}
try:
response = requests.post(
self.base_url,
headers=headers,
json=payload,
timeout=self.timeout
)
response.raise_for_status() # 抛出HTTP错误
return response.json()["choices"][0]["message"]["content"]
except Exception as e:
raise RuntimeError(f"LLM调用失败: {str(e)}")
# 2. Agent核心逻辑(工具调用与决策)
class Agent:
"""原生实现的Agent,支持工具调用与结果处理"""
def __init__(self, model: LLMChatModel, tools: List[Dict[str, Any]]):
self.model = model
self.tools = tools
self.tool_map = {tool["name"]: tool for tool in tools} # 工具名→工具的映射
self.system_prompt = self._build_system_prompt() # 构建引导模型的系统提示
def _build_system_prompt(self) -> str:
"""生成引导模型使用工具的系统提示词"""
tool_descriptions = "\n".join([
f"- {tool['name']}: {tool['description']}(参数: {list(tool['parameters'].keys())})"
for tool in self.tools
])
return f"""你是一个可以使用工具的智能助手。任务:根据用户问题,判断是否需要调用工具,并生成最终回答。
可用工具:
{tool_descriptions}
工具调用规则:
1. 若需要调用工具,必须输出JSON格式:{{"action": {{"name": "工具名", "parameters": {{参数键值对}}}}}}
2. 若无需调用工具,直接输出自然语言回答。
3. 工具返回结果后,需基于结果整理成最终回答。"""
def _call_tool(self, tool_name: str, parameters: Dict[str, Any]) -> Any:
"""调用指定工具并返回结果"""
if tool_name not in self.tool_map:
raise ValueError(f"工具不存在: {tool_name}")
tool = self.tool_map[tool_name]
try:
return tool["func"](**parameters)
except Exception as e:
return f"工具调用错误: {str(e)}"
def run(self, user_query: str) -> str:
"""处理用户查询,执行Agent流程"""
messages = [
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": user_query}
]
while True:
# 调用LLM获取响应
llm_response = self.model.generate(messages)
# 尝试解析是否为工具调用
try:
action = json.loads(llm_response)
if "action" in action:
tool_name = action["action"]["name"]
params = action["action"]["parameters"]
# 调用工具并获取结果
tool_result = self._call_tool(tool_name, params)
# 将工具结果加入对话上下文,继续循环
messages.append({"role": "assistant", "content": llm_response})
messages.append({"role": "system", "content": f"工具返回: {str(tool_result)}"})
continue
except (json.JSONDecodeError, KeyError):
# 非工具调用格式,直接返回结果
return llm_response
# 3. 创建Agent的工厂函数(类似LangChain的create_agent)
def create_agent(
model_input: str | LLMChatModel,
tools: List[Dict[str, Any]],
**kwargs # 传递模型参数(如api_key、temperature等)
) -> Agent:
"""
创建Agent实例
参数:
model_input: 模型标识符(如"gpt-5")或LLMChatModel实例
tools: 工具列表,每个工具格式:
{
"name": 工具名,
"description": 工具描述(帮助模型判断何时使用),
"parameters": 参数描述(键为参数名,值为说明),
"func": 工具调用函数(接收parameters中定义的参数)
}
**kwargs: 模型参数(当model_input为字符串时)
"""
if isinstance(model_input, str):
# 从字符串创建模型实例(默认使用OpenAI风格API)
model = LLMChatModel(model=model_input,** kwargs)
elif isinstance(model_input, LLMChatModel):
# 直接使用已创建的模型实例
model = model_input
else:
raise TypeError("model_input必须是字符串或LLMChatModel实例")
return Agent(model, tools)
# ------------------------------
# 示例使用
# ------------------------------
if __name__ == "__main__":
# 示例工具1:获取当前时间
def get_current_time() -> str:
import datetime
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 示例工具2:计算加法
def add(a: float, b: float) -> float:
return a + b
# 定义工具列表
tools = [
{
"name": "get_current_time",
"description": "获取当前的日期和时间",
"parameters": {}, # 无参数
"func": get_current_time
},
{
"name": "add",
"description": "计算两个数字的和",
"parameters": {"a": "第一个数字", "b": "第二个数字"},
"func": add
}
]
# 方式1:使用模型标识符创建Agent(需提供api_key)
# agent = create_agent(
# model_input="gpt-5",
# tools=tools,
# api_key="你的MaaS API密钥",
# temperature=0.1
# )
# 方式2:使用模型实例创建Agent(更灵活)
model = LLMChatModel(
model="gpt-5",
api_key="你的MaaS API密钥",
temperature=0.1,
max_tokens=1000
)
agent = create_agent(model, tools)
# 测试Agent
print(agent.run("现在是什么时间?")) # 应调用get_current_time
print(agent.run("100加200等于多少?")) # 应调用add
print(agent.run("介绍一下你自己")) # 无需调用工具,直接回答
关键说明
- 模型封装:
LLMChatModel类对接MaaS API,支持配置温度、最大 tokens 等参数,兼容OpenAI风格接口(可替换为其他平台API)。 - 工具定义:每个工具需包含名称、描述(帮助模型判断是否调用)、参数说明和实际调用函数,便于模型理解和使用。
- 决策逻辑:通过系统提示词严格规定工具调用格式(JSON),Agent循环处理:调用模型→解析是否需工具→执行工具→整合结果,直到生成最终回答。
- 灵活性:
create_agent函数支持通过模型标识符快速创建,或通过模型实例实现更精细的配置(如自定义API地址)。
使用时需替换api_key为实际的MaaS平台密钥,并根据目标平台调整base_url(如Azure OpenAI、Anthropic等的API地址)。