
LangChain的create_agent函数基于LangGraph构建了图形化的智能体运行时。在这个架构中,智能体被构建为一个由节点(步骤)和边(连接)组成的图,定义了信息处理的流程。
那么,背后的实现原理和执行过程究竟是怎样的呢?
这里,我将为您实现一个原生版本的 create_agent 功能,使用 Python 和通用的 LLM MaaS API。这个实现将模拟 LangChain 的代理功能,但使用原生 API 调用。
python
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)
- 工具管理(定义工具结构与调用逻辑)
- 决策引导(通过提示词让模型判断是否使用工具)
- 流程控制(循环处理工具调用与结果整合)
完整代码实现
python
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地址)。