智能体(Agent)开发入门:基于通义千问1.5-1.8B构建你的第一个AI助手

你是不是经常看到“智能体”这个词,感觉它很酷,但又觉得离自己很远?觉得那是大公司或者顶尖工程师才能玩转的东西?其实,搭建一个能理解你、帮你干活儿的AI助手,并没有想象中那么复杂。

今天,我们就来亲手做一个。不用复杂的框架,就用你熟悉的Python,加上一个轻量又好用的模型——通义千问1.5-1.8B,来构建一个能查天气、能算账、能给你出行建议的智能小助手。整个过程就像搭积木,我会一步步带你走完,保证你看完就能自己动手做一个。

1. 智能体到底是什么?先别被概念吓到

咱们先抛开那些高大上的定义。你可以把智能体想象成一个“有脑子、会动手”的虚拟小管家。

  • “有脑子”:就是它的核心,一个能理解你说话的大语言模型。比如,你跟它说“明天上海天气怎么样?”,它能明白你想问的是“上海”、“明天”的“天气”。
  • “会动手”:光理解还不够,它得能干活。比如,理解了你要查天气,它得能去调用一个真正的天气查询接口,把结果拿回来。
  • “有记性”:好的管家得记得之前的事。你问完“上海天气”,接着说“那需要带伞吗?”,它得记得刚才聊的是上海,才能给出合理的建议。

所以,一个简单的智能体 = 大模型(大脑) + 工具调用(手脚) + 记忆(记事本)。我们今天要做的,就是把这三样东西拼装起来。

为什么选通义千问1.5-1.8B这个模型呢?因为它足够“轻”。参数少,意味着我们在自己的电脑上就能比较容易地跑起来,做实验、学原理非常合适,效果对于入门来说也完全够用。

2. 动手之前:准备好你的“工具箱”

工欲善其事,必先利其器。我们不需要太多东西,一个Python环境,几个常用的库就够了。

2.1 基础环境搭建

首先,确保你的电脑上有Python(建议3.8或以上版本)。然后,我们打开命令行,安装几个核心的库:

pip install transformers  # 这是Hugging Face的模型库,我们用它来加载和运行通义千问模型
pip install torch         # 深度学习框架,transformers的依赖
pip install requests      # 用来发送网络请求,比如调用天气API

如果你的网络环境下载模型比较慢,可能需要一点耐心,或者寻找一些国内镜像源来加速。

2.2 获取天气数据的能力

智能体要查天气,得有个信息来源。我们可以找一个免费的天气API。这里我以和风天气(HeWeather)为例,因为它有免费的开发版,足够我们学习使用。

  1. 去和风天气官网注册一个账号。
  2. 在控制台创建一个项目,获取你的API Key。这个Key就像一把钥匙,有了它,你才能问天气数据。
  3. 他们提供的免费套餐通常足够我们做测试用了。

记住这个API Key,我们等会儿写代码的时候会用到。

3. 核心模块搭建:给智能体装上“大脑”和“手脚”

现在,我们来一块块地拼装我们的智能体。我们会创建三个主要的Python文件,让结构更清晰。

3.1 第一步:启动“大脑”(模型加载与对话)

我们创建一个文件叫 qianwen_brain.py,专门负责和通义千问模型对话。

# qianwen_brain.py
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

class QianwenBrain:
    def __init__(self, model_name="Qwen/Qwen1.5-1.8B"):
        """
        初始化大脑:加载通义千问模型和分词器。
        注意:首次运行会自动从网上下载模型,请确保网络通畅。
        """
        print(f"正在加载模型 {model_name},首次加载可能需要几分钟,请耐心等待...")
        self.tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
        self.model = AutoModelForCausalLM.from_pretrained(
            model_name,
            torch_dtype=torch.float16, # 使用半精度减少内存占用
            device_map="auto", # 自动选择GPU或CPU
            trust_remote_code=True
        )
        print("模型加载完成!")

    def think(self, prompt):
        """
        让大脑思考:根据输入的提示词(prompt)生成回复。
        """
        # 将输入文本转换为模型能理解的数字ID
        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        # 让模型生成文本,这里设置一些生成参数
        with torch.no_grad(): # 推理阶段,不计算梯度以节省内存
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=256,  # 最多生成256个新token
                do_sample=True,      # 使用采样,让输出更有创造性
                temperature=0.7,     # 温度参数,控制随机性
            )
        
        # 将生成的数字ID解码回我们能看懂的文本
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        # 只返回新生成的部分,去掉原始的prompt
        return response[len(prompt):].strip()

# 简单测试一下大脑是否工作
if __name__ == "__main__":
    brain = QianwenBrain()
    test_prompt = "你好,请介绍一下你自己。"
    print(f"用户: {test_prompt}")
    print(f"AI: {brain.think(test_prompt)}")

运行这个文件,如果看到模型开始加载并最终能和你打招呼,恭喜你,“大脑”激活成功!

3.2 第二步:打造“手脚”(工具调用)

光有大脑会思考,还得有手脚去执行。我们创建 agent_tools.py,定义智能体能用的工具。

# agent_tools.py
import requests
import json
import math

class AgentTools:
    def __init__(self, weather_api_key):
        # 初始化时传入天气API的密钥
        self.weather_api_key = weather_api_key
        self.weather_base_url = "https://devapi.qweather.com/v7/weather/now"

    def get_weather(self, city):
        """
        工具1:查询城市实时天气。
        调用和风天气API,返回天气信息。
        """
        try:
            # 首先,需要根据城市名获取该城市的Location ID
            geo_url = f"https://geoapi.qweather.com/v2/city/lookup?location={city}&key={self.weather_api_key}"
            geo_resp = requests.get(geo_url, timeout=10)
            geo_data = geo_resp.json()
            
            if geo_data['code'] != '200' or not geo_data['location']:
                return f"抱歉,找不到城市'{city}'的天气信息。"
            
            location_id = geo_data['location'][0]['id']
            
            # 用Location ID查询实时天气
            weather_url = f"{self.weather_base_url}?location={location_id}&key={self.weather_api_key}"
            weather_resp = requests.get(weather_url, timeout=10)
            weather_data = weather_resp.json()
            
            if weather_data['code'] == '200':
                now = weather_data['now']
                result = (
                    f"{city}的当前天气:{now['text']},"
                    f"温度{now['temp']}摄氏度,"
                    f"体感温度{now['feelsLike']}摄氏度,"
                    f"湿度{now['humidity']}%,"
                    f"风向{now['windDir']},风力{now['windScale']}级。"
                )
                return result
            else:
                return "天气查询失败,请稍后再试。"
                
        except requests.exceptions.RequestException as e:
            return f"网络请求出错:{e}"
        except Exception as e:
            return f"查询天气时发生未知错误:{e}"

    def calculate(self, expression):
        """
        工具2:简单数学计算。
        注意:这里使用eval有安全风险,仅用于演示。生产环境务必使用更安全的方式(如ast.literal_eval或专门库)。
        """
        try:
            # 非常简单的安全过滤,仅允许数字和基本运算符
            allowed_chars = set("0123456789+-*/(). ")
            if not all(c in allowed_chars for c in expression):
                return "计算表达式包含不安全字符。"
            # 使用math模块中的函数,避免直接eval不可控内容
            result = eval(expression, {"__builtins__": None}, {"math": math})
            return f"计算结果:{expression} = {result}"
        except Exception as e:
            return f"计算失败:{e}"

    def get_tools_description(self):
        """
        返回工具的描述,用于告诉大脑(模型)现在有哪些工具可用。
        这个描述很重要,模型需要知道它能用什么、怎么用。
        """
        tools_desc = [
            {
                "name": "get_weather",
                "description": "查询指定城市的实时天气信息。需要提供城市名称,例如:'上海'、'北京'。",
                "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
            },
            {
                "name": "calculate",
                "description": "执行一个简单的数学计算。需要提供一个数学表达式字符串,例如:'3 + 5 * 2'、'sqrt(16)'。",
                "parameters": {"type": "object", "properties": {"expression": {"type": "string"}}}
            }
        ]
        return json.dumps(tools_desc, ensure_ascii=False)

这里我们定义了两个工具:查天气和做计算。注意看get_tools_description函数,它用结构化的方式描述了工具,这是后面让模型知道该调用哪个工具的关键。

3.3 第三步:连接大脑与手脚(智能体核心逻辑)

现在到了最有趣的部分,我们要创建一个“调度中心”,让大脑能根据我们的指令,决定什么时候思考,什么时候使用工具。创建 my_first_agent.py

# my_first_agent.py
import re
import json
from qianwen_brain import QianwenBrain
from agent_tools import AgentTools

class MyFirstAgent:
    def __init__(self, weather_api_key):
        """
        初始化智能体:组装大脑和工具。
        """
        self.brain = QianwenBrain()
        self.tools = AgentTools(weather_api_key)
        # 一个简单的列表,用来记录对话历史,充当短期记忆
        self.conversation_history = []
        
        # 给大脑一个系统提示,告诉它你是谁以及它能做什么
        self.system_prompt = f"""你是一个有用的AI助手,可以调用工具来帮助用户。
        你可以使用的工具如下:
        {self.tools.get_tools_description()}
        
        当用户的问题需要调用工具时,请严格按照以下JSON格式回复:
        {{"action": "tool_call", "tool_name": "工具名", "parameters": {{"参数名": "参数值"}}}}
        
        例如,用户问“北京天气怎么样?”,你应该回复:
        {{"action": "tool_call", "tool_name": "get_weather", "parameters": {{"city": "北京"}}}}
        
        如果不需要调用工具,就像平常一样用自然语言回复。
        请保持对话友好且有帮助。
        """
        self.conversation_history.append({"role": "system", "content": self.system_prompt})

    def _parse_model_response(self, response):
        """
        解析模型的回复,判断是普通对话还是工具调用指令。
        """
        # 尝试查找JSON格式的工具调用指令
        try:
            # 使用正则表达式匹配可能被包裹在文本中的JSON
            json_match = re.search(r'\{.*"action".*"tool_name".*\}', response, re.DOTALL)
            if json_match:
                tool_call = json.loads(json_match.group())
                if tool_call.get("action") == "tool_call":
                    return tool_call
        except json.JSONDecodeError:
            pass
        # 如果不是工具调用,就当作普通文本回复
        return {"action": "reply", "content": response}

    def run_tool(self, tool_name, parameters):
        """
        根据工具名和参数,实际调用工具。
        """
        if tool_name == "get_weather":
            return self.tools.get_weather(parameters.get("city"))
        elif tool_name == "calculate":
            return self.tools.calculate(parameters.get("expression"))
        else:
            return f"未知的工具:{tool_name}"

    def chat(self, user_input):
        """
        智能体的主要聊天循环。
        """
        print(f"\n[用户] {user_input}")
        # 将用户输入加入历史
        self.conversation_history.append({"role": "user", "content": user_input})
        
        # 构建给模型的完整提示,包含历史对话
        # 这里简单地将历史拼接起来,更复杂的系统会做更精细的处理
        prompt_parts = []
        for msg in self.conversation_history[-6:]: # 只保留最近几轮对话作为上下文,防止太长
            role = msg["role"]
            content = msg["content"]
            if role == "system":
                prompt_parts.append(content)
            elif role == "user":
                prompt_parts.append(f"用户: {content}")
            elif role == "assistant":
                prompt_parts.append(f"助手: {content}")
        prompt_parts.append("助手:") # 提示模型该它说话了
        full_prompt = "\n\n".join(prompt_parts)
        
        # 让大脑思考
        raw_response = self.brain.think(full_prompt)
        print(f"[模型原始回复] {raw_response}")
        
        # 解析大脑的回复
        parsed = self._parse_model_response(raw_response)
        
        if parsed["action"] == "tool_call":
            # 如果需要调用工具
            tool_name = parsed["tool_name"]
            tool_params = parsed["parameters"]
            print(f"[智能体] 检测到工具调用指令:{tool_name},参数:{tool_params}")
            
            # 执行工具
            tool_result = self.run_tool(tool_name, tool_params)
            print(f"[工具执行结果] {tool_result}")
            
            # 把工具执行结果也加入历史,并让大脑基于结果生成最终回复
            self.conversation_history.append({"role": "assistant", "content": raw_response})
            # 这里我们构造一个简单的提示,告诉模型工具执行的结果
            follow_up_prompt = f"{full_prompt}\n助手:{raw_response}\n(工具调用返回结果:{tool_result})\n请根据以上结果回复用户:"
            final_response = self.brain.think(follow_up_prompt)
            
            # 将最终回复加入历史
            self.conversation_history.append({"role": "assistant", "content": final_response})
            print(f"[智能体最终回复] {final_response}")
            return final_response
            
        else:
            # 如果是普通回复,直接返回
            self.conversation_history.append({"role": "assistant", "content": parsed['content']})
            print(f"[智能体回复] {parsed['content']}")
            return parsed['content']

# 让我们运行起来看看!
if __name__ == "__main__":
    # 替换成你在和风天气获取的真实API Key
    YOUR_WEATHER_API_KEY = "你的和风天气API Key"
    
    if YOUR_WEATHER_API_KEY == "你的和风天气API Key":
        print("请先在 agent_tools.py 中配置你的和风天气API Key!")
        exit()
    
    agent = MyFirstAgent(YOUR_WEATHER_API_KEY)
    print("智能体已启动!输入 '退出' 或 'quit' 结束对话。")
    
    while True:
        try:
            user_input = input("\n请输入你的问题:").strip()
            if user_input.lower() in ['退出', 'quit', 'exit']:
                print("再见!")
                break
            if user_input:
                agent.chat(user_input)
        except KeyboardInterrupt:
            print("\n程序被中断。")
            break
        except Exception as e:
            print(f"出错了:{e}")

这个文件是智能体的“总控”。它做了几件关键事:

  1. 管理记忆:用conversation_history列表记住对话。
  2. 指挥大脑:把用户的问题和对话历史整理好,送给模型(大脑)去思考。
  3. 解析指令:判断大脑的回复是普通聊天,还是命令它去调用工具(比如查天气)。
  4. 执行工具:如果大脑说要调用工具,它就指挥AgentTools去干活。
  5. 整合结果:拿到工具的结果(比如天气数据)后,再让大脑组织成一句人话回复给我们。

4. 看看效果:和你的智能体对话

现在,在命令行运行 python my_first_agent.py,并确保你的API Key已填好。让我们试试几个场景:

场景一:简单查询

你:北京今天天气怎么样?
智能体:[模型原始回复] {"action": "tool_call", "tool_name": "get_weather", "parameters": {"city": "北京"}}
智能体:[工具执行结果] 北京的当前天气:晴,温度22摄氏度,体感温度21摄氏度,湿度35%,风向西北,风力2级。
智能体:[智能体最终回复] 北京今天天气晴朗,气温22度,体感比较舒适,湿度较低,西北风2级。是个出门的好天气。

场景二:多轮对话(利用记忆)

你:上海明天天气呢?
智能体:(调用工具查询上海天气...)
你:需要带伞吗?
智能体:(它需要结合上一轮“上海天气”的结果来推理。因为我们的记忆机制保留了上下文,它能做到。)

场景三:使用计算工具

你:计算一下 15 乘以 28 加上 17 等于多少
智能体:[模型原始回复] {"action": "tool_call", "tool_name": "calculate", "parameters": {"expression": "15 * 28 + 17"}}
智能体:[工具执行结果] 计算结果:15 * 28 + 17 = 437
智能体:[智能体最终回复] 15乘以28等于420,再加上17,结果是437。

看,它真的像一个有逻辑的小助手了!它能理解你的意图,选择正确的工具,执行任务,并把结果用自然语言告诉你。

5. 总结与下一步

跟着走完这一趟,你应该已经亲手搭建了一个具备基础能力的AI智能体。它虽然简单,但包含了智能体最核心的三大件:模型、工具和记忆。通义千问1.5-1.8B作为“大脑”负责理解和规划,我们写的工具类就是它的“手脚”,而那个不断增长的对话历史列表就是它的“短期记忆”。

实际用起来,你可能会发现这个简易版智能体有些地方可以做得更好。比如,模型有时候可能不会严格按照我们规定的JSON格式返回,导致工具调用失败;记忆管理也比较粗糙,对话长了就会失效。这些都是后续可以优化的方向,比如使用更成熟的框架(如LangChain、Semantic Kernel)来提供更稳定的工具调用解析和更强大的记忆管理。

但最重要的是,通过这个实践,你拆解了智能体的黑盒,知道了它内部是如何流转的。下次你再听到“Agent”这个词,脑子里浮现的不再是一个模糊的概念,而是一个清晰的、由代码构成的协作系统。不妨就以这个“天气助手”为起点,试着给它添加更多工具,比如查新闻、定日历、翻译句子,或者优化它的对话逻辑,让它变得更聪明、更可靠。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐