2025年的春天用三行代码就能创建第一个代理

春天来了,让我们一起打造一个超级智能聊天机器人!🌸

如果你一直在关注AI社区的动态,你可能已经注意到Nvidia最近宣布了一个价值数十亿美元的人工智能代理项目,或者听说过Zark提到他们未来一年内不会招聘中级工程师的消息。这些新闻让我思考:这一切是如何发生的?在我开发AI代理系统时,我花费了数天的时间来完成这项任务。构建智能代理一直是一项复杂且技术要求极高的工作,涉及许多繁琐的步骤,如API集成、环境配置和依赖管理。

想象一下,在喝一杯咖啡的时间里就能搭建一个AI代理------这正是 Smolagents 带来的可能性。这是一个由Hugging Face团队打造的新一代代理框架,它让构建AI变得简单而强大。对于开发者来说,这就像是一份礼物------既简洁又功能强大。

接下来展示如何使用 **Smolagents**、Web Scraper 和 DeepSeek R1 来创建一个强大的多代理聊天机器人。无论是用于商业还是个人用途,这个聊天机器人都能成为你的得力助手。

Smolagents 旨在找到复杂性和简易性之间的完美平衡。编写代码是 Smolagents 的最大亮点之一。最令人印象深刻的是,只需三行代码就能创建你的第一个代理,并且它还能构建 Agent-Retrieval-Generation (Agent-RAG) 系统。与 Crew AI 和 Autogen 相比,虽然它们功能丰富但复杂度较高。

在新的一年伊始,DeepSeek 推出了其最新的大规模语言模型 DeepSeek R1,这是一个拥有671B参数的混合专家(MoE)语言模型。DeepSeek R1 最吸引人的一点是它的价格非常亲民。不要以为"便宜就不好"!事实上,DeepSeek R1 在保持高精度自然语言处理能力的同时,价格却远低于竞争对手如 GPT-4 和 Claude。

用户可以自由定制 DeepSeek R1,使其适用于特定行业和应用的AI模型变得简单易行。这种灵活性是它区别于其他竞争产品的关键所在。

接下来,我将通过一个实时聊天机器人的演示来展示我的意思。我访问了一个房地产网站,抓取了代理的名字、电话号码和公司名称,并使用了一些精心设计的输入和工具以获得更好的结果。我们知道 DeepSeek R1 在编码能力和基于链式思维及工具化方法方面表现优异。

在视频结束时,你将了解 Smolagents 是什么,它的特点是什么,为什么它值得我们关注,它是如何工作的,以及如何利用 Smolagents 创建一个超级智能代理。

免责声明:本文仅用于教育目的。我们不鼓励任何人抓取网站内容,尤其是那些有条款和条件禁止此类行为的网站。

SmolAgents 是什么?

SmolAgents 是一个轻量级的 Python 库,它让开发者能够用极简的方式构建高效的代理。这个库解决了代理开发中的常见痛点:代码臃肿、流程低效以及工具集成困难。它支持安全地"编写行动代码"的代理,并且与 Hugging Face Hub 集成。此外,它还为你处理了许多非例行的复杂性问题,比如确保系统提示、解析器和执行链接中代码格式的一致性。

为什么值得关注?

SmolAgents 致力于简洁性和对 LLM 无关的设计,专注于支持安全的代码编写代理,并且与 Hugging Face Hub 集成。这个代理系统打破了传统工作流程对于狭窄任务的限制,扩展了处理更复杂现实问题的可能性。Hugging Face 的工程师们表示,代理为 LLM 提供了访问外部世界的能力。

在这个万物复苏的春天,让我们一起探索 SmolAgents 如何帮助我们构建更加智能和高效的代理吧!

Smolagents 采用代码而非 JSON 来描述动作,这种方式带来了更多的组合性、数据管理和灵活性。构建代理时面临的挑战包括解析代理的输出和基于前几轮迭代合成提示词,这些正是 Smolagents 提供的关键功能。

Hugging Face 还与其他模型进行了基准测试,发现开放模型在减少步骤和 API 调用方面比传统解决方案减少了 30%,同时在困难的基准测试中表现更佳。除了 Smolagents,还有其他公司如 OpenAI 的 Swarm 和微软的 Magentic-One 等也在这一领域有所作为。SmolAgents 在安全上也下了功夫,内置了沙箱模式以确保代码的安全执行,并且通过与 Hugging Face Hub 的集成,只需一行代码即可轻松分享。

Smolagents 工作原理

Smolagents 旨在实现易用性和效率的完美结合。其直观的 API 让开发者能够轻松构建智能代理来完成任务,如命令理解、外部数据源连接、动态代码生成与执行等。具体功能包括:

语言理解: 利用先进的自然语言处理(NLP)模型,Smolagents 能够理解和解析命令及查询。

智能搜索: 连接外部数据源以提供快速准确的搜索结果。

动态代码执行: 代理可以根据需要生成并执行代码来解决特定问题。

SmolAgents 的模块化设计使其适用于多种场景,无论是快速原型制作还是全规模生产环境应用。通过利用预训练模型,开发者可以节省大量时间和精力,并获得强大的性能,而无需从头开始定制模型。

动手编码

现在让我们一步步探索如何创建 SmolAgents。首先,我们需要安装支持该模型的库。这一步我们使用 pip install requirements 命令来完成。

复制代码
pip install -r requirements.txt

接下来是导入相关库的步骤,随着我们的深入,这些库的重要性将逐渐显现。

  • CodeAgent:这是默认代理,它会在每一步编写并执行 Python 代码片段。
  • LiteLLM Model:让你能够调用超过100种不同的模型。
  • tool :一个列表 Tools,代理可以使用这个列表中的工具来解决问题。

一旦你有了这两个参数 toolsmodel,就可以创建代理并运行它了。你可以使用任何你喜欢的 LLM,无论是通过 Hugging Face APItransformersollama 还是 LiteLLM

python 复制代码
from typing import Optional, Dict
from smolagents import CodeAgent, tool, LiteLLMModel , GradioUI
import requests
import os
import time
from bs4 import BeautifulSoup
import pandas as pd

首先,我创建了一个抓取函数来从realtor.com网站上搜集房地产代理的信息。我们的目标是获取名字、电话号码和公司名称。

你可以指定州(例如,"CA"代表加利福尼亚)和城市(例如,"Angeles"),以及你想要抓取的页面数量。初始化列表用于存储数据,并使用头部信息来模仿浏览器请求,动态地为每个页面URL设置请求头。

接着,我创建了一个循环从第一页到指定的页数进行迭代。对于第一页,链接很简单;而对于后续页面,则在链接中添加了页码。

我利用requests库下载网页内容。如果HTTP响应状态码不是200(表示成功),抓取器将停止并返回错误信息。

我们通过搜索HTML中的类名为agent-name的元素来查找代理的名字。找到后,去除多余的空格并将名字添加到列表中。同样地,我们也检查所有可能的位置以获取电话号码和公司名称。如果找到了这些信息,我们会清理数据并将其加入各自的列表中。如果没有找到任何代理信息,则返回错误消息。否则,将整理好的数据组织成字典形式并返回。

python 复制代码
@tool
def scrape_realtor(state: str, city_name: str, num_pages: Optional[int] = 2) -> Dict[str, any]:
    """从realtor.com抓取指定城市和州的代理信息
    
    参数:
        state: 州缩写(例如,'CA', 'NY')
        city_name: 城市名称,用连字符代替空格(例如,'buffalo')
        num_pages: 要抓取的页面数量(默认:2)
    """
    try:
        # 初始化结果列表
        results = []         # 名字
        phone_results = []   # 电话号码
        office_results = []  # 办公室名称
        pages_scraped = 0
        
        # 设置请求头信息
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
            "Accept-Language": "en-US,en;q=0.5",
python 复制代码
            "Connection": "keep-alive"
        }

        # 处理页面
        for page in range(1, num_pages + 1):
            # 构造URL
            if page == 1:
                url = f'https://www.realtor.com/realestateagents/{city_name}_{state}/'
            else:
                url = f'https://www.realtor.com/realestateagents/{city_name}_{state}/pg-{page}'
            
            print(f"正在抓取第 {page} 页...")
            
            # 获取页面内容
            r = requests.get(url, headers=headers)
            if r.status_code != 200:
                return {"error": f"无法访问第 {page} 页: 状态码 {r.status_code}"}

            soup = BeautifulSoup(r.text, features="html.parser")
            
            # 查找所有经纪人卡片
            agent_cards = soup.find_all('div', class_='agent-list-card')
            
            for card in agent_cards:
                # 找到姓名
                name_elem = card.find('div', class_='agent-name')
                if name_elem:
                    name = name_elem.text.strip()
                    if name and name not in results:
                        results.append(name)
                        print(f"找到经纪人: {name}")

                # 找到电话号码
                phone_elem = card.find('a', {'data-testid': 'agent-phone'}) or \
                            card.find(class_='btn-contact-me-call') or \
                            card.find('a', href=lambda x: x and x.startswith('tel:'))
                
                if phone_elem:
                    phone = phone_elem.get('href', '').replace('tel:', '').strip()
                    if phone:
                        phone_results.append(phone)
                        print(f"找到电话号码: {phone}")

                # 获取办公室/公司名称
                office_elem = card.find('div', class_='agent-group') or \
                            card.find('div', class_='text-semibold')
                if office_elem:
                    office = office_elem.text.strip()
                    office_results.append(office)
                    print(f"找到办公室: {office}")
                else:
                    office_results.append("")
            
            pages_scraped += 1
            time.sleep(2)  # 控制抓取速度

        if not results:
            return {"error": "未找到经纪人。可能是网站结构发生了变化,或者该地区没有结果。"}

        # 返回结构化数据
        return {
            "names": results,
            "phones": phone_results,
            "offices": office_results,
            "total_agents": len(results),
            "pages_scraped": pages_scraped,
            "city": city_name,
            "state": state
        }
        
    except Exception as e:
        return {"error": f"抓取错误: {s

接下来,我创建了一个函数,用于将抓取到的房地产数据保存为CSV文件。这个函数接受一个字典data作为参数,里面包含了抓取的信息,并且可以选填一个文件名。如果data中包含错误信息,则直接返回该错误消息。

如果没有错误,它会确保所有列表(names, phones, offices)的长度相等,通过在较短的列表末尾填充空字符串来实现这一点。然后,从这些列表创建一个DataFrame,并使用UTF-8编码将其写入CSV文件中。如果操作成功,则返回一条包含保存文件名和条目总数的成功消息;否则,返回错误信息。

python 复制代码
@tool
def save_to_csv(data: Dict[str, any], filename: Optional[str] = None) -> str:
    """将抓取的房地产数据保存到CSV文件
    
    参数:
        data: 包含抓取结果的字典
        filename: 可选的文件名(默认:cityname.csv)
    """
    try:
        if "error" in data:
            return f"错误: {data['error']}"
            
        if not filename:
            filename = f"{data['city'].replace('-', '')}.csv"
            
        # 确保所有列表长度相等
        max_length = max(len(data['names']), len(data['phones']), len(data['offices']))
        
        # 在较短的列表末尾填充空字符串
        data['names'].extend([""] * (max_length - len(data['names'])))
        data['phones'].extend([""] * (max_length - len(data['phones'])))
        data['offices'].extend([""] * (max_length - len(data['offices'])))
        
        # 创建只包含名字、电话和办公室的DataFrame
        df = pd.DataFrame({
            'Names': data['names'],
            'Phone': data['phones'],
            'Office': data['offices']
        })
        
        df.to_csv(filename, index=False, encoding='utf-8')
        return f"数据已保存到 {filename}。总条目数: {len(df)}"
        
    except Exception as e:
        return f"保存CSV时出错: {str(e)}"

要使用 LiteLLMModel,你需要设置环境变量 ANTHROPIC_API_KEYOPENAI_API_KEY,或者在初始化时传递 api_key 变量。默认情况下,我们使用 CodeAgent 来执行 Python 代码。这应该是安全的,因为唯一可以调用的是你提供的工具和一组预定义的安全函数或来自 math 模块的函数,所以你的执行范围已经受到了限制。

Python 解释器默认不允许从一个安全列表之外导入模块,因此最常见的攻击方式不会构成威胁。你可以通过传递授权模块列表来允许额外的导入:

python 复制代码
deepseek_model = LiteLLMModel(
        model_id="ollama/nezahatkorkmaz/deepseek-R1"
    )

# 创建带有工具的代理
agent = CodeAgent(
        tools=[scrape_realtor, save_to_csv],
        model=deepseek_model,
        additional_authorized_imports=["pandas", "bs4", "time"]
    )

最后,让我们运行代理,启动 Gradio 界面,并测试聊天机器人。请记住,你的提示越精确,得到的结果就越好:

python 复制代码
result = agent.run("""
Thought: 让我们来抓取房地产数据吧!
Code:
```python
# 抓取房地产数据
data = scrape_realtor(state="NY", city_name="buffalo", num_pages=2)

# 保存到 CSV 文件
if "error" not in data:
    result = save_to_csv(data)
    print(result)
else:
    print(f"Error: {data['error']}")

""")

结论 :

Hugging Face 对开发者用户有着深刻的理解。再加上其社区的优势,它发布的许多框架都获得了良好的反响。

这个框架可能是过去两年整个AI社区思考和积累的结果。

这提醒我们,有时候,小巧而精致才是最好的选择。

2025年春天来了,随着代理技术的蓬勃发展,SmolAgents以最简洁的方式解决了最关键的问题。

在这个AIGC时代,找到知己不易,自我修炼更难。抓住前沿科技的机会,与我们一起成为创新超个体(掌握个人力量)。

结论 :

通过今天的分享,我们不仅深入了解了SmolAgents的工作原理及其重要性,还动手实践了一次实际的代码编写过程。在这个过程中,你学会了如何初始化结果、设置请求头以及处理页面内容等关键步骤。希望这些知识能帮助你在未来的项目中更加得心应手。

随着春天的到来,技术领域也迎来了新的生机与活力。不妨将今天学到的知识应用到你的下一个项目中,看看能否带来意想不到的惊喜!

相关推荐
Leinwin6 分钟前
Microsoft Azure 服务4月更新告示
人工智能·azure
胡耀超9 分钟前
霍夫圆变换全面解析(OpenCV)
人工智能·python·opencv·算法·计算机视觉·数据挖掘·数据安全
jndingxin17 分钟前
OpenCV CUDA 模块中用于在 GPU 上计算两个数组对应元素差值的绝对值函数absdiff(
人工智能·opencv·计算机视觉
jerry60917 分钟前
LLM笔记(五)概率论
人工智能·笔记·学习·概率论
硅谷秋水19 分钟前
学习以任务为中心的潜动作,随地采取行动
人工智能·深度学习·计算机视觉·语言模型·机器人
Tiny番茄1 小时前
Multimodal models —— CLIP,LLava,QWen
人工智能
Wnq100721 小时前
工业场景轮式巡检机器人纯视觉识别导航的优势剖析与前景展望
人工智能·算法·计算机视觉·激光雷达·视觉导航·人形机器人·巡检机器人
无心水2 小时前
【程序员AI入门:模型】19.开源模型工程化全攻略:从选型部署到高效集成,LangChain与One-API双剑合璧
人工智能·langchain·开源·ai入门·程序员ai开发入门·程序员的 ai 开发第一课·程序员ai入门
有梦想的攻城狮2 小时前
大语言模型与多模态模型比较
人工智能·语言模型·自然语言处理·llm·大语言模型
九章云极AladdinEdu3 小时前
GPU与NPU异构计算任务划分算法研究:基于强化学习的Transformer负载均衡实践
java·开发语言·人工智能·深度学习·测试工具·负载均衡·transformer