在了解Agent之前,我们先了解一下LLM;
我们都知道22年11月30日,OpenAI发布了ChatGPT,而ChatGPT就是LLM的典型的应用实例之一,包括后面发布的文心一言、通义千问等大模型。
LLM全称Large Language Model,中文为大语言模型,是人工智能领域中自然语言处理(NLP)方向的核心技术,也是当前生成式AI的底层支撑。它的本质是基于海量文本数据训练、具备强大语言理解与生成能力的深度学习模型。
我们从以上的概念中很容易就能看到LLM的一些局限,比如:
这两个局限使得LLM更像是一个建议者、开车时的副驾驶,无法执行具体的动作。
而在AI的发展中,我们更需要AI去做一个执行者,去做司机,去实际参与物理世界,由此,Agent发展出来了。
现在我们常常用这样的一个智能体架构公式去理解Agent:
有了 LLM(大语言模型)、Perception(感知)、Planning(规划)、Memory(记忆) 、Tools(工具),Agent真正具备了五官与手脚,去理解、操作我们的物理世界:
Agent的大脑
Agent与外部沟通的桥梁,通过多种渠道感知环境信息,类似于人的感官
Agent的决策执行引擎,负责将LLM拆解的目标转化为可执行的分布计划,并根据反馈动态调整策略
Agent的长期知识库,解决LLM上下文窗口有限的问题,为Agent提供长期学习和经验积累的能力
Agent的双手,让Agent突破纯文本能力限制,实现"知行合一"的任务执行
API调用,控制智能家居、工业机器人等物理设备Excel、Photoshop等了解了上面的概念,我们来实操一下,搭建一个本地的Agent;
实现的Agent的功能点包括:
Python 函数(如获取时间、数学计算求和)基于ReAct结构,用通义千问大模型作为AI基座,Python3作为开发语言:
OpenAI 兼容模式Python 3.8+我这里用的是阿里云的大模型:
API Key创建 requirements.txt 文件:
openai
python-dotenv
安装依赖:
pip3 install -r requirements.txt
创建 .env 文件:
DASHSCOPE_API_KEY=你的API_KEY
创建utils.py文件,利用Python 的 inspect 模块,读取函数的函数名、参数列表和类型注解,生成大模型可理解的JSON Schema,让大模型去了解工具的功能和参数
import inspect
def function_to_json(func) -> dict:
"""
通过 Python 反射机制,自动将一个 Python 函数转换为 OpenAI/DashScope 兼容的工具定义 (JSON Schema)。
这使得我们只需要编写普通的 Python 函数,就能直接被 Agent 识别和调用。
"""
# 获取函数的签名信息(包含参数名、参数类型注解、默认值等)
sig = inspect.signature(func)
parameters = {}
required = []
# 遍历函数的所有参数
for name, param in sig.parameters.items():
# 根据 Python 的类型注解推断 JSON Schema 的类型
if param.annotation == float:
param_type = "number"
elif param.annotation == int:
param_type = "integer"
elif param.annotation == str:
param_type = "string"
elif param.annotation == bool:
param_type = "boolean"
else:
# 默认设为 string
param_type = "string"
# 构造单个参数的 schema 定义
parameters[name] = {"type": param_type}
# 如果参数没有设定默认值,则在 Schema 中标记为必填项 (required)
if param.default is inspect.Parameter.empty:
required.append(name)
# 返回符合 OpenAI Tool 定义规范的字典结构
return {
"type": "function",
"function": {
"name": func.__name__, # 函数名
"description": inspect.getdoc(func) or "", # 使用函数的 docstring 作为工具描述
"parameters": {
"type": "object",
"properties": parameters, # 参数列表
"required": required, # 必填参数列表
},
},
}
关键点:
from datetime import datetime
def get_current_datetime() -> str:
"""
获取当前日期和时间的工具。
Agent 可以调用此工具来了解当前的实时时间。
:return: 格式化后的日期时间字符串,例如 "2024-01-05 12:00:00"。
"""
current_datetime = datetime.now()
formatted_datetime = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
return formatted_datetime
def add(a: int, b: int) -> int:
"""
计算两个整数的和。
Agent 会在需要进行加法运算时自动调用此工具。
"""
return a + b
Memory - 短期记忆)LLM)Planning - 任务规划)Tools - 工具执行)初始化系统提示词,创建工具映射
import json
from typing import List, Dict, Any
from openai import OpenAI
from utils import function_to_json
SYSTEM_PROMPT = """
你是一个人工智能助手。你的输出应该与用户的语言保持一致。
当用户的问题需要调用工具时,你可以从提供的工具列表中调用适当的工具函数。
"""
class Agent:
def __init__(self, client: OpenAI, model: str = "qwen-plus",
tools: List = None, verbose: bool = True):
self.client = client
self.tools = tools or []
self.model = model
# Memory: 初始化对话历史,包含系统提示词
self.messages = [{"role": "system", "content": SYSTEM_PROMPT}]
self.verbose = verbose
# Tools: 创建工具映射:函数名 -> 函数对象
self.tool_map = {tool.__name__: tool for tool in self.tools}
将时间工具和数学工具转换为模型可识别的JSON Schema
def get_tool_schema(self) -> List[Dict[str, Any]]:
"""将 Python 函数列表转换为模型可识别的 JSON Schema"""
return [function_to_json(tool) for tool in self.tools]
处理模型发出的单个工具调用逻辑
def handle_tool_call(self, tool_call):
"""处理模型发出的单个工具调用请求"""
function_name = tool_call.function.name
function_args_str = tool_call.function.arguments
function_id = tool_call.id
try:
# 解析 JSON 字符串参数
function_args = json.loads(function_args_str)
# 从映射表中查找并执行函数
if function_name in self.tool_map:
if self.verbose:
print(f">>> 正在执行工具: {function_name}, 参数: {function_args}")
func = self.tool_map[function_name]
result = func(**function_args)
else:
result = f"错误: 找不到名为 {function_name} 的工具"
except Exception as e:
result = f"工具执行过程中出错: {str(e)}"
return {
"role": "tool",
"content": str(result),
"tool_call_id": function_id,
}
处理用户输入的核心方法,实现 ReAct 循环:
实现 Planning(规划)的核心思想:
def get_completion(self, prompt: str) -> str:
# Memory: 添加用户问题到历史
self.messages.append({"role": "user", "content": prompt})
# Planning: 第一次请求 - LLM 判断是否需要工具
response = self.client.chat.completions.create(
model=self.model,
messages=self.messages,
tools=self.get_tool_schema() if self.tools else None,
stream=False,
)
message = response.choices[0].message
# Planning: 循环处理工具调用(支持多次调用或链式调用)
while message.tool_calls:
# Memory: 将模型的工具调用请求加入历史
self.messages.append(message)
# Tools: 执行所有请求的工具
for tool_call in message.tool_calls:
tool_result_message = self.handle_tool_call(tool_call)
# Memory: 将工具执行结果加入历史
self.messages.append(tool_result_message)
# Planning: 带着工具结果再次请求模型,进行动态调整
response = self.client.chat.completions.create(
model=self.model,
messages=self.messages,
tools=self.get_tool_schema() if self.tools else None,
stream=False,
)
message = response.choices[0].message
# Memory: 模型不再调用工具,返回最终回复,存入历史并返回
self.messages.append({"role": "assistant", "content": message.content})
return message.content or ""
OpenAIAgent实例,并注入工具import os
from dotenv import load_dotenv
from openai import OpenAI
from agent import Agent
from tools.time_tool import get_current_datetime
from tools.math_tools import add, compare, count_letter_in_string
load_dotenv()
API_KEY = os.getenv("DASHSCOPE_API_KEY")
if __name__ == "__main__":
if not API_KEY:
print("错误: 请在 .env 文件中配置 DASHSCOPE_API_KEY")
exit(1)
# 初始化 OpenAI 客户端(使用阿里云百炼的兼容接口)
client = OpenAI(
api_key=API_KEY,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 创建 Agent 实例,注入工具
agent = Agent(
client=client,
model="qwen-plus",
tools=[get_current_datetime, add, compare, count_letter_in_string],
verbose=True,
)
print("JUN 人工智能助手已启动!(输入 'exit' 退出)")
# 交互式对话循环
while True:
try:
prompt = input(" 33[94mUser: 33[0m")
if prompt.lower() in ["exit", "quit", "退出"]:
print("再见!")
break
if not prompt.strip():
continue
response = agent.get_completion(prompt)
print(" 33[92mAssistant: 33[0m", response, "n")
except KeyboardInterrupt:
print("n程序终止")
break
except Exception as e:
print(f" 33[91m发生错误: {e}