AutoGen入门-让两个AI自行聊天完成任务 - mingupupup - 博客园

mikel阅读(818)

来源: AutoGen入门-让两个AI自行聊天完成任务 – mingupupup – 博客园

AutoGen介绍

AutoGen 是一个开源编程框架,用于构建 AI 代理并促进多个代理之间的合作以解决问题。AutoGen 旨在提供一个易于使用和灵活的框架,以加速代理型 AI 的开发和研究,就像 PyTorch 之于深度学习。它提供了诸如代理之间可以对话、LLM 和工具使用支持、自主和人机协作工作流以及多代理对话模式等功能。

主要特点

AutoGen使得基于多智能体对话构建下一代LLM应用程序变得非常容易。它简化了复杂LLM工作流的编排、自动化和优化。它最大化了LLM模型的性能并克服了它们的弱点。

它支持复杂工作流的各种对话模式。通过使用可定制和可对话的代理,开发人员可以使用AutoGen构建各种涉及对话自主性、代理数量和代理对话拓扑的对话模式。

它提供了一系列不同复杂度的运行系统。这些系统涵盖了来自不同领域和复杂度的各种应用程序。这展示了AutoGen如何轻松支持各种对话模式。

入门

现在AutoGen有两个版本,一个是0.2,是稳定版本,一个是0.4,是正在开发的版本。

本次入门使用的是开发版本。

首先创建一个Python虚拟环境:

python -m venv myenv

激活虚拟环境:

myenv\Scripts\activate

安装相关包:

pip install "autogen-agentchat==0.4.0.dev13"
pip install "autogen-ext[openai]==0.4.0.dev13"

后面运行时,会显示还缺少几个库,按照报错的信息,继续安装所需的包即可。

入门的例子是创建一个AI团队,一个当任务执行者,一个当评判者,当评判者觉得可以了,就停止对话,完成任务。

Python代码如下:

import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.base import TaskResult
from autogen_agentchat.conditions import ExternalTermination, TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main():

    # Create an OpenAI model client.
    model_client = OpenAIChatCompletionClient(
        model="gpt-4o-2024-08-06",
        api_key="", # Optional if you have an OPENAI_API_KEY env variable set.
        )

    # Create the primary agent.
    primary_agent = AssistantAgent(
        "primary",
        model_client=model_client,
        system_message="You are a helpful AI assistant.",
    )

    # Create the critic agent.
    critic_agent = AssistantAgent(
        "critic",
        model_client=model_client,
        system_message="Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed.",
    )

    # Define a termination condition that stops the task if the critic approves.
    text_termination = TextMentionTermination("APPROVE")


    team = RoundRobinGroupChat(
        [primary_agent, critic_agent],
        termination_condition=text_termination,  # Use the bitwise OR operator to combine conditions.
    )

    await Console(team.run_stream(task="写一首关于秋天的短诗"))

    
if __name__ == "__main__":
    asyncio.run(main())

运行效果:

---------- user ----------
写一首关于秋天的短诗
---------- primary ----------
秋风轻摇叶漫天,  
金黄稻穗笑丰年。  
枫红染尽山川路,  
硕果满枝惹人怜。  

晨霜点缀草间珠,  
夕阳映影湖中船。  
静谧凉月盈满空,  
秋夜温柔如梦甜。  
[Prompt tokens: 28, Completion tokens: 81]
---------- critic ----------
这首关于秋天的短诗运用了丰富的意象生动地描绘了秋天的美丽。以下是一些建议来进一步提升这首诗:

1. 开头的两行已经相当完整,但可以考虑将“轻摇”替换为更具体的动词,比如“飘落”,以增强画面感。
2. 第二节中的“晨霜点缀草间珠”可以更加具体化,比如但不局限于使用“白霜”,进一步富有诗意地描述秋季清晨的细节。
3. 尾句“秋夜温柔如梦甜”可以再结合一个感官描写,比如“如梦”可以结合沁人心脾的“桂香扑鼻”之类的细节来丰富整体体验。

这些建议旨在增加诗歌的生动性和情感深度,整体上已经非常优秀。请进行相应的改动后,我将很高兴地给予批准。
[Prompt tokens: 126, Completion tokens: 215]
---------- primary ----------
非常感谢您的建议!根据您的意见,我对诗歌做了一些修改:

秋风飘落叶漫天,  
金黄稻穗笑丰年。  
枫红染尽山川路,  
硕果满枝惹人怜。  

白霜点缀草间珠,  
夕阳映影湖中船。  
桂香扑鼻月满空,  
秋夜温柔如梦甜。  

希望这些改动能够增强诗歌的生动性,带来更加丰富的秋季体验。
[Prompt tokens: 334, Completion tokens: 120]
---------- critic ----------
改动后的诗歌确实更加生动且富有画面感。使用“飘落”更好地描绘了秋天的特征,而“白霜”和“桂香扑鼻”的加入使得诗歌在感官描述上更加具体和丰富。这 些改动有效地增强了诗歌的生动性和情感深度。因此,我准许该稿件。 

APPROVE
[Prompt tokens: 471, Completion tokens: 92]
---------- Summary ----------
Number of messages: 5
Finish reason: Text 'APPROVE' mentioned
Total prompt tokens: 959
Total completion tokens: 508
Duration: 14.87 seconds

现在试试用一下国内的模型,毕竟使用OpenAI的模型不是很方便。

我以为改一下baseurl就行了,如下所示:

image-20250107163203243

运行时会报错,如下所示:

image-20250107163339701

现在需要解决这个问题。

改成这样:

image-20250107165213070

还是会出现问题:

image-20250107165043167

解决方案:

image-20250107170942735

改成这样就可以了,如下所示:

image-20250107171056791

让Qwen/Qwen2.5-72B-Instruct与deepseek-ai/DeepSeek-V2.5协作完成任务:

image-20250107171506469

image-20250107171534679

---------- user ----------
写一首关于秋天的短诗
---------- primary ----------
秋风轻抚过田野,
黄叶飘零诉离别。
果实累累挂枝头,
丰收的歌在空中回响。

白露凝霜晨光里,
红枫如火映晚晴。
秋水共长天一色,
宁静致远,思绪随风。
[Prompt tokens: 27, Completion tokens: 61]
---------- critic ----------
这首诗以自然意象为载体,描绘了秋天的丰富色彩与情感。秋风、黄叶、果实、白露、红枫等元素,形成了层次分明的秋日图景,表达了丰收与离别交替的复杂情感。诗中“宁静致远”一句,更是点明了秋天带给人们的沉思与感慨。整体语言流畅,意境深远,情感细腻,是一首不错的秋之赞歌。

以下是一些具体的反馈建议:

1. **“黄叶飘零诉离别”**:这一句的表达略显直白,可以考虑用更含蓄或独特的意象来表达离别之情,以增强诗歌的韵味。
   
2. **“秋水共长天一色”**:这一句虽然取自王勃的《滕王阁序》,但使用在此处稍显突兀,可能会让读者感受到某种经典符号的重复。可以考虑替换为更个性化的表达,与前文的自然意象形成更好 的呼应。

如果你能根据这些建议进行调整,这首诗将会更加出色。期待看到你的进一步修改!
[Prompt tokens: 103, Completion tokens: 239]
---------- primary ----------
非常感谢你的详细反馈和建议!根据你的意见,我将对这首诗进行一些调整,以增强其含蓄性和个性化表达。

---

秋风轻抚过田野,
黄叶轻舞似鸿羽。
果实累累挂枝头,
丰收的歌在空中回响。

白露凝霜晨光里,
红枫如火映晚晴。
秋水清澈连天际,
宁静致远,思绪随风。

---

1. **“黄叶轻舞似鸿羽”**:用“鸿羽”这一意象来表达黄叶的轻盈,增强视觉和情感的层次感。
2. **“秋水清澈连天际”**:替换“秋水共长天一色”为更个性化的表达,使意境更加独特和自然。

希望这些调整能更好地传达秋天的美好与复杂情感。感谢你的指导!
[Prompt tokens: 332, Completion tokens: 182]
---------- critic ----------
调整后的诗句更显细腻与含蓄,黄叶与秋水的意象都更加个性化,情感表达也更加丰富。以下是具体反馈:

1. **“黄叶轻舞似鸿羽”**:这一修改非常成功,“鸿羽”不仅增添了轻盈之感,还赋予了黄叶一种飘逸的动态美,增强了诗歌的视觉与情感张力。

2. **“秋水清澈连天际”**:这一改写避免了经典句式的重复,同时营造了秋水澄澈、连通天际的广阔意境,使整体氛围更加宁静致远。

3. **情感表达**:诗歌整体情感更加内敛,通过自然意象的细腻描绘,既表达了丰收的喜悦,又蕴含了秋天的宁静与思索,尤其最后一句“宁静致远,思绪随风”更是将情感推向了深远的境界。     

总体来说,这首诗的意境已经非常成熟,语言流畅,情感细腻,具有很高的艺术表现力。如果后续没有更多的修改需求,我认为可以定稿。

**APPROVE**
[Prompt tokens: 547, Completion tokens: 239]
---------- Summary ----------
Number of messages: 5
Finish reason: Text 'APPROVE' mentioned
Total prompt tokens: 1009
Total completion tokens: 721
Duration: 75.84 seconds

DeepSeekV3+Roo Code,智能编码好助手 - mingupupup - 博客园

mikel阅读(768)

来源: DeepSeekV3+Roo Code,智能编码好助手 – mingupupup – 博客园

前言

硅基流动最近上线了deepseek-ai/DeepSeek-R1与deepseek-ai/DeepSeek-V3,感兴趣快来试试吧!

邀请注册得14元不过期额度:https://cloud.siliconflow.cn/i/Ia3zOSCU。

image-20250202084545172

实践

最近VS Code中的自动编程插件Cline很火爆,Roo Code也是Cline的一个fork版本。

Cline

自主编码代理直接集成在您的 IDE 中,能够创建/编辑文件,执行命令,使用浏览器等,每一步都需您的许可。

image-20250202081003394

首先在Cline中接入SiliconCloud可以使用OpenAI Compatible这种方式,配置如下所示:

image-20250202081241737

以创建一个使用ts的next.js项目todo-demo为例,查看效果。

之前使用Cline还好好的,但是最近遇到了这个问题:

image-20250202081507401

因此开始尝试使用Roo Code。

Roo Code

Roo Code(原名 Roo Cline)是 VS Code 插件,通过 AI 驱动的自动化、多模型支持和实验性功能增强编码。

image-20250202081802147

安装Roo Code:

image-20250202081858277

配置方式与Cline相同:

image-20250202081933858

开始测试使用DeepSeek-V3的效果:

image-20250202082142598

运行的每一个命令,都需要你同意。

安装next.js模板:

image-20250202082239724

安装antd:

image-20250202082357679

自动编写代码:

image-20250202082455957

写完的代码还有一个报错,但是显示任务已完成:

image-20250202082754213

如果自己解决不了,继续让Roo Code解决:

image-20250202083305520

查看效果:

image-20250202083551586

感觉还可以。

推荐给大家,可以提升自己的编码效率。

image-20250202084031409

token消耗量也还可以,只花了12万多,只用了0.13元。

AI工具推荐——open-interpreter - mingupupup - 博客园

mikel阅读(280)

来源: AI工具推荐——open-interpreter – mingupupup – 博客园

前言

Open Interpreter 是一个能让大型语言模型在你本地电脑上运行代码的工具。 简单来说:

它提供了一个类似于 ChatGPT 的自然语言界面,让你能通过代码与电脑互动。 你可以用它来:

  • 创建和编辑各种类型的文件(照片、视频、PDF 等)。
  • 控制 Chrome 浏览器进行研究。
  • 分析数据集。

工作原理: Open Interpreter 为语言模型配备了一个函数,该函数可以在 Python、JavaScript 和 Shell 等各种语言中执行代码。 然后,它会将模型的消息、正在运行的代码和系统的输出流式传输到你的终端。

主要特点:

  • 它在本地运行,无需担心网络限制或文件大小限制。
  • 它通过自然语言界面简化了复杂的任务。

该项目目前已经收获了58.2kstars,GitHub地址:https://github.com/OpenInterpreter/open-interpreter

image-20250208094027464

我在体验之后,觉得是一个很棒的项目,因此推荐给大家。它的思路很好,我之前想的是创建很多工具,然后根据用户的意图,选择工具调用,但是用户需求是多变的,创建的工具不可能全部涵盖到,但是通过open-interpreter这种方式,就可以应对用户多变的需求了。

实践

首先创建一个python虚拟环境,安装open-interpreter:

pip install open-interpreter

虽然官方推荐使用gpt-40,但是为了在国内更多感兴趣的朋友能够方便体验,这里我以硅基流动提供的模型为例。现在硅基流动也有DeepSeek-R1并且邀请注册可得14元不过期额度,邀请链接:https://cloud.siliconflow.cn/i/Ia3zOSCU。

由于我硅基流动还有很多额度,接下来演示如何接入硅基流动的模型。

from interpreter import interpreter

interpreter.llm.model = "openai/deepseek-ai/DeepSeek-V3"
interpreter.llm.api_key = "sk-xxx"
interpreter.llm.api_base = "https://api.siliconflow.cn/v1"
interpreter.llm.context_window = 64000

# Start an interactive chat session
interpreter.chat()

第一个踩坑点,注意要加上openai表示是openai兼容的,不然报错如下:

image-20250208095153912

现在我以一个简单的办公需求来演示open-interpreter的效果。

我在项目目录,放入了一个excel,该excel中的数据,如下所示:

image-20250208095524855

现在根据这个excel随机提需求。

问题1:读取test.xlsx内容,商品A的累计销量是多少?

image-20250208095743329

给出计划,命令行操作与运行代码需要你的同意。

image-20250208095955211

模型假设列名是Product A,失败之后,请求获取列名。

image-20250208100052033

image-20250208100144833

答案是82正确!!

问题2:读取test.xlsx内容,以月份为横坐标,商品B为纵坐标,画一个折线图,需要能显示中文。

image-20250208100313341

模型列出了计划。

image-20250208100450196

模型给出代码。

image-20250208100524122

绘图结果正确。

对比硅基流动平台不同模型的效果。

deepseek-ai/DeepSeek-V3:

meta-llama/Llama-3.3-70B-Instruct:

Qwen/Qwen2.5-72B-Instruct:

视频效果在AI工具推荐——open-interpreter

最后

open-interpreter这个项目非常有意思,可玩性非常高,感兴趣的朋友快去试试吧!!!

将它与自己的日常需求结合看看能不能提高自己的效率。

浏览器自动化与AI Agent结合项目browser-use初探 - mingupupup - 博客园

mikel阅读(749)

来源: 浏览器自动化与AI Agent结合项目browser-use初探 – mingupupup – 博客园

browser-use介绍

browser-use是将您的 AI 代理连接到浏览器的最简单方式。它通过提供一个强大且简单的接口来实现 AI 代理访问网站的自动化。

GitHub地址:https://github.com/browser-use/browser-use。目前已经获得了27.3k颗stars,2.7kforks,看得出来是一个比较热门的项目。我在上手体验了之后,发现确实是一个很有趣的项目,因此推荐给大家。

实践

上手也非常简单,创建一个python虚拟环境,pip install browser-use,再playwright install即可。

现在需要进行LLM的配置,官方推荐使用gpt-4o,但是为了降低成本,方便让看了教程感兴趣的人能够方便上手,这里我使用的是硅基流动提供的模型。目前硅基流动注册送14元不过期额度,够用一段时间的了,邀请链接:https://cloud.siliconflow.cn/i/Ia3zOSCU。如果你的额度不够了,但是也想体验一下,可以私聊我,我可以提供一个api key暂时供你快速上手体验,额度用差不多了,我就停止了。

创建一个.env文件,这样写:

Silicon_Cloud_API_KEY=xxx
Base_URL=https://api.siliconflow.cn
Model=Qwen/Qwen2.5-72B-Instruct

创建一个test脚本,这样写:

from langchain_openai import ChatOpenAI
from browser_use import Agent
from dotenv import load_dotenv
import os
load_dotenv()

import asyncio

api_key = os.getenv('Silicon_Cloud_API_KEY')
base_url = os.getenv('Base_URL')
model = os.getenv('Model')

llm = ChatOpenAI(model=model, api_key=api_key, base_url=base_url)

async def main():
    agent = Agent(
        task="获取https://github.com/OpenInterpreter/open-interpreter仓库的前五个问题",
        llm=llm,
        use_vision=False,
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

查看效果:

image-20250212085716642

image-20250212085758634

image-20250212085834372

还生成了一个agent_history.gif可以查看流程:

将结果与实际对比:

image-20250212090403603

可以发现browser-use非常准确的获取了。

再使用一个更普遍的例子,就是获取当前微博前十的热搜。

from langchain_openai import ChatOpenAI
from browser_use import Agent
from dotenv import load_dotenv
import os
load_dotenv()

import asyncio

api_key = os.getenv('Silicon_Cloud_API_KEY')
base_url = os.getenv('Base_URL')
model = os.getenv('Model')

llm = ChatOpenAI(model=model, api_key=api_key, base_url=base_url)

async def main():
    agent = Agent(
        task="获取当前微博前十的热搜",
        llm=llm,
        use_vision=False,
    )
    result = await agent.run()
    print(result)

asyncio.run(main())

image-20250212090822384

image-20250212090907000

最后

以上就是使用硅基流动中的Qwen/Qwen2.5-72B-Instruct快速体验browser-use的效果。初步体验感觉是一个很有潜力的项目,将AI Agent与浏览器自动化结合确实可以做很多事情。

如何让大模型安全地自动生成代码并执行? - mingupupup - 博客园

mikel阅读(409)

来源: 如何让大模型安全地自动生成代码并执行? – mingupupup – 博客园

前言

本文带来的分享是在crewai中使用代码解释器,为了安全,代码在docker中运行。

为什么要使用代码解释器呢?

之前的文章中使用的是function call + 各种工具 来完成一个任务,比如文件读取工具、文件保存工具等。

但是用户的需求是多变的,你很难提前写好所有的工具。

读取文件内容,使用代码解释器的效果如下所示:

image-20250224100624862

实践

首先需要看下crewai中提供的代码解释器工具代码,学习一下。

代码在:https://github.com/crewAIInc/crewAI-tools/tree/main/crewai_tools/tools/code_interpreter_tool

文件如下:

image-20250224100921024

先来看一下Dockerfile:

FROM python:3.12-alpine

RUN pip install requests beautifulsoup4 

# Set the working directory
WORKDIR /workspace

这是一个Dockerfile的片段,用于构建一个Python环境的Docker镜像。解释如下:

FROM python:3.12-alpine:这行指定了基础镜像为Python 3.12版本的Alpine Linux镜像。Alpine Linux是一种轻量级的Linux发行版,非常适合作为Docker镜像的基础。
RUN pip install requests beautifulsoup4:这行使用pip安装两个Python包:requests和beautifulsoup4。requests是一个用于发送HTTP请求的库,而beautifulsoup4是一个用于解析HTML和XML文档的库。
WORKDIR /workspace:这行设置了容器中的工作目录为/workspace。当容器启动时,会自动进入这个目录。
总的来说,这个Dockerfile构建了一个Python环境,安装了两个常用的库,并将工作目录设置为/workspace。这个镜像可以用于运行Python应用程序,尤其是那些需要解析HTML和发送HTTP请求的应用程序。

再来看一下code_interpreter_tool.py的代码:

import importlib.util
import os
from typing import List, Optional, Type
from crewai.tools import BaseTool
from docker import from_env as docker_from_env
from docker import DockerClient
from docker.models.containers import Container
from docker.errors import ImageNotFound, NotFound
from docker.models.containers import Container
from pydantic import BaseModel, Field


class CodeInterpreterSchema(BaseModel):
    """
    Input for CodeInterpreterTool.
    供代码解释工具输入。
    """

    code: str = Field(
        ...,
        # Python3代码原来是在Docker容器中被解释的。始终打印最终结果和代码的输出。
        description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code",
    )

    libraries_used: Optional[List[str]] = Field(
        None,
        # 代码中使用的库列表,带有适当的安装名称,以逗号分隔。例如: numpy,pandas,beautifulsoup4
        description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4",
    )


class CodeInterpreterTool(BaseTool):
    name: str = "Code Interpreter"
    description: str = "Interprets Python3 code strings with a final print statement."
    args_schema: Type[BaseModel] = CodeInterpreterSchema
    default_image_tag: str = "code-interpreter:latest"
    code: Optional[str] = None
    user_dockerfile_path: Optional[str] = None
    user_docker_base_url: Optional[str] = None
    unsafe_mode: bool = False

    @staticmethod
    def _get_installed_package_path():
        spec = importlib.util.find_spec("crewai_tools")
        return os.path.dirname(spec.origin)

    def _verify_docker_image(self) -> None:
        """
        Verify if the Docker image is available. Optionally use a user-provided Dockerfile.
        验证Docker镜像是否可用。可选地使用用户提供的Dockerfile。
        """

        client = (
            docker_from_env()
            if self.user_docker_base_url == None
            else DockerClient(base_url=self.user_docker_base_url)
        )

        try:
            client.images.get(self.default_image_tag)

        except ImageNotFound:
            if self.user_dockerfile_path and os.path.exists(self.user_dockerfile_path):
                dockerfile_path = self.user_dockerfile_path
            else:
                package_path = self._get_installed_package_path()
                dockerfile_path = os.path.join(
                    package_path, "tools/code_interpreter_tool"
                )
                if not os.path.exists(dockerfile_path):
                    raise FileNotFoundError(
                        f"Dockerfile not found in {dockerfile_path}"
                    )

            client.images.build(
                path=dockerfile_path,
                tag=self.default_image_tag,
                rm=True,
            )

    def _run(self, **kwargs) -> str:
        code = kwargs.get("code", self.code)
        libraries_used = kwargs.get("libraries_used", [])

        if self.unsafe_mode:
            return self.run_code_unsafe(code, libraries_used)
        else:
            return self.run_code_in_docker(code, libraries_used)

    def _install_libraries(self, container: Container, libraries: List[str]) -> None:
        """
        Install missing libraries in the Docker container
        """
        for library in libraries:
            container.exec_run(["pip", "install", library])

    def _init_docker_container(self) -> Container:
        container_name = "code-interpreter"
        client = docker_from_env()
        current_path = os.getcwd()

        # Check if the container is already running
        try:
            existing_container = client.containers.get(container_name)
            existing_container.stop()
            existing_container.remove()
        except NotFound:
            pass  # Container does not exist, no need to remove

        return client.containers.run(
            self.default_image_tag,
            detach=True,
            tty=True,
            working_dir="/workspace",
            name=container_name,
            volumes={current_path: {"bind": "/workspace", "mode": "rw"}},  # type: ignore
        )

    def run_code_in_docker(self, code: str, libraries_used: List[str]) -> str:
        self._verify_docker_image()
        container = self._init_docker_container()
        self._install_libraries(container, libraries_used)

        exec_result = container.exec_run(["python3", "-c", code])

        container.stop()
        container.remove()

        if exec_result.exit_code != 0:
            return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}"
        return exec_result.output.decode("utf-8")

    def run_code_unsafe(self, code: str, libraries_used: List[str]) -> str:
        """
        Run the code directly on the host machine (unsafe mode).
        """
        # Install libraries on the host machine
        for library in libraries_used:
            os.system(f"pip install {library}")

        # Execute the code
        try:
            exec_locals = {}
            exec(code, {}, exec_locals)
            return exec_locals.get("result", "No result variable found.")
        except Exception as e:
            return f"An error occurred: {str(e)}"

主要的参数与描述如下:

code: str = Field(
        ...,
        # Python3代码原来是在Docker容器中被解释的。始终打印最终结果和代码的输出。
        description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code",
    )

    libraries_used: Optional[List[str]] = Field(
        None,
        # 代码中使用的库列表,带有适当的安装名称,以逗号分隔。例如: numpy,pandas,beautifulsoup4
        description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4",
    )

测试这个工具的代码:

from crewai import LLM, Agent, Crew, Process, Task
# from crewai_tools import CodeInterpreterTool
from code_interpreter_tool import CodeInterpreterTool
import os
from dotenv import load_dotenv
load_dotenv()

api_key = os.getenv('SiliconCloud_API_KEY')
base_url = os.getenv('SiliconCloud_API_BASE')
model = os.getenv('SiliconCloud_MODEL_NAME', 'openai/Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set

agent_llm = LLM(
model=model,
base_url=base_url,
api_key=api_key
	)

# Create an LLM with a temperature of 0 to ensure deterministic outputs
# llm = LLM(model="gpt-4o-mini", temperature=0)

# Create an agent with the knowledge store
agent = Agent(
    role="Tool User",
    goal="You know how to use the tool.",
    backstory="""
    You are a master at using the tool.
    使用代码执行工具时,如果没有使用库,则libraries_used参数为空列表,需要写成libraries_used=[]。
    """,
    verbose=True,
    allow_delegation=False,
    llm=agent_llm,
    tools=[CodeInterpreterTool()],
)
task = Task(
    description="""
    根据用户需求:{question}
    使用相应的工具。
    """,
    expected_output="获取本次工具输出的结果,无需其它内容。",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
    verbose=True,
    process=Process.sequential,
)

result = crew.kickoff(
    inputs={
        "question": "获取test2.txt的内容"
    }
)

在这个地方可以输入你的需求看看代码解释器能不能实现。

先来一个最简单的:

result = crew.kickoff(
    inputs={
        "question": "输出你好世界"
    }
)

image-20250224101613286

再来一个创建文件的:

result = crew.kickoff(
    inputs={
        "question": "创建test3.txt,里面写入我是一只鱼。"
    }
)

image-20250224101933531

image-20250224102041955

再试一下需要使用库的:

result = crew.kickoff(
    inputs={
        "question": "画一个折线图,横坐标为1月、2月、3月,纵坐标为12、15、17,将结果保存到test.png。"
    }
)

image-20250224102742800

image-20250224102759227

中文字体没有正常显示,修改需求:

画一个折线图,横坐标为1月、2月、3月,纵坐标为121517,需要显示中文字体,将结果保存到test.png。

还是没有成功。

在docker环境中没有安装中文字体。

image-20250224103628011

并且使用代码解释器的一个缺点就是你无法保证AI生成的代码就是能用的,稍微复杂一点的需求,就有可能生成无法运行的代码。

image-20250224103800196

这样来看代码解释器的可玩性还是有很大的限制。

但是确实可以替代一些简单的工具了。

使用crewai创建属于你自己的AI团队 - mingupupup - 博客园

mikel阅读(294)

来源: 使用crewai创建属于你自己的AI团队 – mingupupup – 博客园

crewai介绍

CrewAI 是一个用于协调自主 AI 代理的前沿框架。

CrewAI 允许你创建 AI 团队,其中每个代理都有特定的角色、工具和目标,协同工作以完成复杂任务。

把它想象成组建你的梦之队——每个成员(代理)都带来独特的技能和专业知识,无缝协作以实现你的目标。

最近使用了crewai这个框架,我觉得是一个比较好用的AI Agent框架,因此推荐给大家。

在crewai中涵盖了AgentsTasksCrewsFlowsKnowledgeLLMsTools等这些核心概念。

接下来我将以一个具体的例子,介绍一下crewai的使用。

crewai的GitHub地址为:https://github.com/crewAIInc/crewAI

image-20250219164001573

使用crewai构建一个翻译代理

创建一个python虚拟环境,安装crewai与crewai-tools。

运行命令:

crewai create crew translation_agent

会出现一个模板项目。

在config目录下,使用yaml配置agent与task:

image-20250219164418938

先来设置一下代理:

file_reader:
  role: >
    读取文件代理
  goal: >
    根据文件路径,读取文件内容
  backstory: >
    你是一个文件读取代理,你的任务是根据文件路径,读取文件内容
​
translation_agent:
  role: >
    翻译代理
  goal: >
    根据用户需求翻译文本
  backstory: >
    你是一个翻译代理,你的任务是根据用户需求翻译文本
​
file_saver:
  role: >
    文件保存代理
  goal: >
    根据用户需求保存文件
  backstory: >
    你是一个文件保存代理,你的任务是根据用户需求保存文件

在这里设置了三个代理,分别是读取文件代理、翻译代理与文件保存代理。

再来配置一下task:

file_read_task:
  description: >
    根据用户需求:{question}
    获取需要读取的文件路径
    使用工具读取文件内容
  expected_output: >
    返回文件内容
  agent: file_reader
​
translation_task:
  description: >
    根据file_reader获取的文件内容,将文本翻译成英文
  expected_output: >
    返回翻译后的文本内容
  agent: translation_agent
​
file_save_task:
  description: >
   根据用户需求:{question}提取出需要保存到的文件路径及相关信息
   将translation_agent的翻译内容,保存至指定文件
  expected_output: >
    返回保存结果
  agent: file_saver

设置了三个任务,分别是file_read_task、translation_task与file_save_task。

完成这些任务,需要代理能够使用读取文件与保存文件的工具。

在tools目录下可以写工具代码:

image-20250219165027457

file_read_tool工具代码:

from typing import Any, Optional, Type
​
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
​
​
class FileReadToolSchema(BaseModel):
    """Input for FileReadTool."""
​
    # Mandatory file full path to read the file
    # 必须的文件全路径,以读取文件
    file_path: str = Field(..., description="Mandatory file full path to read the file")
​
​
class FileReadTool(BaseTool):
    """A tool for reading file contents.
​
    This tool inherits its schema handling from BaseTool to avoid recursive schema
    definition issues. The args_schema is set to FileReadToolSchema which defines
    the required file_path parameter. The schema should not be overridden in the
    constructor as it would break the inheritance chain and cause infinite loops.
​
    The tool supports two ways of specifying the file path:
    1. At construction time via the file_path parameter
    2. At runtime via the file_path parameter in the tool's input
​
    Args:
        file_path (Optional[str]): Path to the file to be read. If provided,
            this becomes the default file path for the tool.
        **kwargs: Additional keyword arguments passed to BaseTool.
​
    Example:
        >>> tool = FileReadTool(file_path="/path/to/file.txt")
        >>> content = tool.run()  # Reads /path/to/file.txt
        >>> content = tool.run(file_path="/path/to/other.txt")  # Reads other.txt
​
    用于读取文件内容的工具。
​
    该工具继承自 BaseTool 的 schema 处理,以避免递归 schema 定义问题。args_schema 设置为 FileReadToolSchema,定义了必需的 file_path 参数。构造函数中不应该覆盖 schema,否则会破坏继承链并导致无限循环。
​
    该工具支持两种指定文件路径的方法:
​
    在构造时通过 file_path 参数
    在运行时通过工具的输入参数 file_path
​
    参数:
    file_path (可选[str]): 要读取的文件路径。如果提供,则成为工具的默认文件路径。
    **kwargs: 传递给 BaseTool 的其他关键字参数。
​
    示例:
    >>> tool = FileReadTool(file_path="/path/to/file.txt")
    >>> content = tool.run()  # 读取 /path/to/file.txt
    >>> content = tool.run(file_path="/path/to/other.txt")  # 读取 other.txt
    """
​
    name: str = "Read a file's content"
    description: str = "A tool that reads the content of a file. To use this tool, provide a 'file_path' parameter with the path to the file you want to read."
    args_schema: Type[BaseModel] = FileReadToolSchema
    file_path: Optional[str] = None
​
    def __init__(self, file_path: Optional[str] = None, **kwargs: Any) -> None:
        """
        Initialize the FileReadTool.
​
        Args:
            file_path (Optional[str]): Path to the file to be read. If provided,
                this becomes the default file path for the tool.
            **kwargs: Additional keyword arguments passed to BaseTool.
​
        初始化 FileReadTool。
​
        参数:
        file_path(可选[str]):要读取的文件路径。如果提供,则此路径成为工具的默认文件路径。
        **kwargs:传递给 BaseTool 的其他关键字参数。
        """
​
        if file_path is not None:
            kwargs['description'] = f"A tool that reads file content. The default file is {file_path}, but you can provide a different 'file_path' parameter to read another file."
​
        super().__init__(**kwargs)
        self.file_path = file_path
​
    def _run(
        self,
        **kwargs: Any,
    ) -> str:
        file_path = kwargs.get("file_path", self.file_path)
        if file_path is None:
            return "Error: No file path provided. Please provide a file path either in the constructor or as an argument."
​
        try:
            with open(file_path, "r",encoding='utf-8') as file:
                return file.read()
        except FileNotFoundError:
            return f"Error: File not found at path: {file_path}"
        except PermissionError:
            return f"Error: Permission denied when trying to read file: {file_path}"
        except Exception as e:
            return f"Error: Failed to read file {file_path}. {str(e)}"

file_writer_tool工具代码:

import os
from ast import literal_eval
from typing import Any, Optional, Type
​
from crewai.tools import BaseTool
from pydantic import BaseModel
​
​
class FileWriterToolInput(BaseModel):
    filename: str
    directory: Optional[str] = "./"
    overwrite: str = "False"
    content: str
​
​
class FileWriterTool(BaseTool):
    name: str = "File Writer Tool"
    description: str = "A tool to write content to a specified file. Accepts filename, content, and optionally a directory path and overwrite flag as input,overwrite flag is True or False."
    args_schema: Type[BaseModel] = FileWriterToolInput
​
    def _run(self, **kwargs: Any) -> str:
        try:
            # Create the directory if it doesn't exist
            if kwargs.get("directory") and not os.path.exists(kwargs["directory"]):
                os.makedirs(kwargs["directory"])
​
            # Construct the full path
            filepath = os.path.join(kwargs.get("directory") or "", kwargs["filename"])
​
            # Convert overwrite to boolean
            kwargs["overwrite"] = bool(literal_eval(kwargs["overwrite"]))
​
            # Check if file exists and overwrite is not allowed
            if os.path.exists(filepath) and not kwargs["overwrite"]:
                return f"File {filepath} already exists and overwrite option was not passed."
​
            # Write content to the file
            mode = "w" if kwargs["overwrite"] else "x"
            with open(filepath, mode) as file:
                content = kwargs["content"]
                file.write(content)
            return f"Content successfully written to {filepath}"
        except FileExistsError:
            return (
                f"File {filepath} already exists and overwrite option was not passed."
            )
        except KeyError as e:
            return f"An error occurred while accessing key: {str(e)}"
        except Exception as e:
            return f"An error occurred while writing to the file: {str(e)}"

现在需要构建一个团队。

构建团队的代码:

from crewai import Agent, Crew, Process, Task,LLM
from crewai.project import CrewBase, agent, crew, task
from translation_agent.tools.file_read_tool import FileReadTool
from translation_agent.tools.file_writer_tool import FileWriterTool
import os
from dotenv import load_dotenv
load_dotenv()
​
file_read_tool = FileReadTool()
file_writer_tool = FileWriterTool()
​
api_key = os.getenv('OPENAI_API_KEY')
base_url = os.getenv('OPENAI_API_BASE')
model = os.getenv('OPENAI_MODEL_NAME', 'Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set
agent_llm = LLM(
    model=model,
    base_url=base_url,
    api_key=api_key
    )
​
# If you want to run a snippet of code before or after the crew starts, 
# you can use the @before_kickoff and @after_kickoff decorators
# https://docs.crewai.com/concepts/crews#example-crew-class-with-decorators
​
​
@CrewBase
class TranslationAgent():
    """TranslationAgent crew"""
​
    # Learn more about YAML configuration files here:
    # Agents: https://docs.crewai.com/concepts/agents#yaml-configuration-recommended
    # Tasks: https://docs.crewai.com/concepts/tasks#yaml-configuration-recommended
    agents_config = 'config/agents.yaml'
    tasks_config = 'config/tasks.yaml'
    
    # If you would like to add tools to your agents, you can learn more about it here:
    # https://docs.crewai.com/concepts/agents#agent-tools
    # @agent
    # def researcher(self) -> Agent:
    #   return Agent(
    #       config=self.agents_config['researcher'],
    #       verbose=True
    #   )
​
    # @agent
    # def reporting_analyst(self) -> Agent:
    #   return Agent(
    #       config=self.agents_config['reporting_analyst'],
    #       verbose=True
    #   )
    
    @agent
    def file_reader(self) -> Agent:     
        return Agent(
            config=self.agents_config['file_reader'],
            verbose=True,
            llm=agent_llm,
            tools=[file_read_tool],
        )
    
    @agent
    def translation_agent(self) -> Agent:       
        return Agent(
            config=self.agents_config['translation_agent'],
            verbose=True,
            llm=agent_llm,      
        )
    
    @agent
    def file_saver(self) -> Agent:      
        return Agent(
            config=self.agents_config['file_saver'],
            verbose=True,
            llm=agent_llm,
            tools=[file_writer_tool],
        )
    
    # To learn more about structured task outputs, 
    # task dependencies, and task callbacks, check out the documentation:
    # https://docs.crewai.com/concepts/tasks#overview-of-a-task
    @task
    def file_read_task(self) -> Task:
        return Task(
            config=self.tasks_config['file_read_task'],
        )
​
    @task
    def translation_task(self) -> Task:
        return Task(
            config=self.tasks_config['translation_task'],
        )
    
    @task
    def file_save_task(self) -> Task:
        return Task(
            config=self.tasks_config['file_save_task'],
        )
​
    @crew
    def crew(self) -> Crew:
        """Creates the TranslationAgent crew"""
        # To learn how to add knowledge sources to your crew, check out the documentation:
        # https://docs.crewai.com/concepts/knowledge#what-is-knowledge
​
        return Crew(
            agents=self.agents, # Automatically created by the @agent decorator
            tasks=self.tasks, # Automatically created by the @task decorator
            process=Process.sequential,
            verbose=True,
            # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/
        )

其中我想让代理使用硅基流动的模型可以这样写:

image-20250219165445665

需要在模型名称前加上openai才行,不如会报错。

如果你还没注册的话,可以点击邀请链接进行注册:https://cloud.siliconflow.cn/i/Ia3zOSCU

这里我以具有工具调用能力的meta-llama/Llama-3.3-70B-Instruct为例。

然后可以这样使用:

import os
from dotenv import load_dotenv
load_dotenv()
​
file_read_tool = FileReadTool()
file_writer_tool = FileWriterTool()
​
api_key = os.getenv('OPENAI_API_KEY')
base_url = os.getenv('OPENAI_API_BASE')
model = os.getenv('OPENAI_MODEL_NAME', 'Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set
agent_llm = LLM(
    model=model,
    base_url=base_url,
    api_key=api_key
    )

在创建代理时,记得使用这个大模型,并且记得使用工具:

@agent
def file_reader(self) -> Agent:     
        return Agent(
            config=self.agents_config['file_reader'],
            verbose=True,
            llm=agent_llm,
            tools=[file_read_tool],
        )

这样这个团队就构建成功了。

在main.py中这样写:

#!/usr/bin/env python
import sys
import warnings
​
from datetime import datetime
​
from translation_agent.crew import TranslationAgent
​
warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
​
# This main file is intended to be a way for you to run your
# crew locally, so refrain from adding unnecessary logic into this file.
# Replace with inputs you want to test with, it will automatically
# interpolate any tasks and agents information
​
def run():
    """
    Run the crew.
    """
    inputs = {
        'question': '读取test.txt文件内容,将其翻译为英文,然后写入test4.txt文件',
    }
    
    try:
        TranslationAgent().crew().kickoff(inputs=inputs)
    except Exception as e:
        raise Exception(f"An error occurred while running the crew: {e}")
​
​
def train():
    """
    Train the crew for a given number of iterations.
    """
    inputs = {
        "topic": "AI LLMs"
    }
    try:
        TranslationAgent().crew().train(n_iterations=int(sys.argv[1]), filename=sys.argv[2], inputs=inputs)
​
    except Exception as e:
        raise Exception(f"An error occurred while training the crew: {e}")
​
def replay():
    """
    Replay the crew execution from a specific task.
    """
    try:
        TranslationAgent().crew().replay(task_id=sys.argv[1])
​
    except Exception as e:
        raise Exception(f"An error occurred while replaying the crew: {e}")
​
def test():
    """
    Test the crew execution and returns the results.
    """
    inputs = {
        "topic": "AI LLMs"
    }
    try:
        TranslationAgent().crew().test(n_iterations=int(sys.argv[1]), openai_model_name=sys.argv[2], inputs=inputs)
​
    except Exception as e:
        raise Exception(f"An error occurred while testing the crew: {e}")

主要关注这里:

def run():
    """
    Run the crew.
    """
    inputs = {
        'question': '读取test.txt文件内容,将其翻译为英文,然后写入test4.txt文件',
    }
    
    try:
        TranslationAgent().crew().kickoff(inputs=inputs)
    except Exception as e:
        raise Exception(f"An error occurred while running the crew: {e}")

在inputs中输入task中的question占位符的内容。

现在创建一个test.txt,输入内容为:

CrewAI:用于编排复杂 AI 代理系统的生产级框架。从简单的自动化到复杂的现实世界应用,CrewAI 提供精确控制和深度定制。通过灵活的、可投入生产的架构促进协作智能,CrewAI 使代理能够无缝协作,以可预测和一致的结果解决复杂的商业挑战。

现在输入crewai run,看看这个翻译代理的效果。

image-20250219171523468

可以发现读取文件代理做的不够好的地方是多了一些内容。

需要进行改进。

改成这样再试试:

file_reader:
  role: >
    读取文件代理
  goal: >
    根据文件路径,读取文件内容
  backstory: >
    你是一个文件读取代理,你的任务是根据文件路径,读取文件内容,只需返回文件内容即可

现在效果就很好了,如下所示:

image-20250219172033798

翻译代理很好地进行翻译了,如下所示:

image-20250219172055009

文件保存代理将翻译结果进行保存,如下所示:

image-20250219172229853

image-20250219172317889

最后

这就是使用crewai构建一个翻译代理的步骤与效果。在crewai中还有很多很有趣的工具值得探索,下期介绍代码解释器工具的使用。

Manus的开源复刻OpenManus初探 - mingupupup - 博客园

mikel阅读(320)

来源: Manus的开源复刻OpenManus初探 – mingupupup – 博客园

OpenManus介绍

Manus需要邀请码才能体验,目前大部分人都体验不到。

有几个大佬花3个小时就复现了一个简单的原型OpenManus,让我们体验体验吧!!

截至目前,该项目已经获得了25.9k颗星标,是一个非常热门的项目。

GitHub地址:https://github.com/mannaandpoem/OpenManus

image-20250311100212446

实践

话不多说,直接上手实践。

git clone https://github.com/mannaandpoem/OpenManus.git
cd OpenManus
uv venv
.venv\Scripts\activate
uv pip install -r requirements.txt

上手配置:

image-20250311100600763

将config.example.toml复制一份重命名为config.toml。

或者直接运行命令:

cp config/config.example.toml config/config.toml

我先使用硅基流动的Qwen/Qwen2.5-72B-Instruct模型试试水。

image-20250311100938940

直接运行main.py即可。

运行之后如下所示:

image-20250311101034092

需要你输入一个任务。

我就以“导航至https://github.com/mannaandpoem/OpenManus获取star数量”为例。

image-20250311101318649

image-20250311101355429

确实打开了浏览器,但是报错了没有能够完成这个任务。

可能跟模型的能力有关。

我这次使用gemini-2.0-flash再试试。

配置文件如下所示:

image-20250311101838068

再试试刚刚那个任务:

image-20250311102306312

再试试获取这个仓库的前五个问题:

image-20250311102448597

image-20250311102516892

接下来测试一下生成文件的功能,输入“生成一个test.txt文件,里面写入小铭同学AI工具学习记录”。

image-20250311102747068

image-20250311102806589

简单测试了一个OpenManus用Gemini可以跑通了。

还有一个类似的项目叫OWL,目前遇到的一个问题就是一直没有看到浏览器出现。

目前还没有解决,试了Gemini也还是不行。

等等看有没有什么解决方案吧!!

以上就是今天的分享,希望对你有所帮助。

前端订单编辑明细加载速度优化经验总结

mikel阅读(422)

现在有个订单表单布局如下

头部和明细的组合布局,现在出现的问题是明细加载很慢,前端用的是layui实现的,因为form初始化和table都是异步加载,通过谷歌的开发者工具查看页面加载的过程发现明细的异步加载需要10秒以上,尽管后端加了redis缓存,前端的效率还是上不去,开始以为是数据库查询太慢了,不过通过后台执行查询SQL语句,发现并不慢1秒就完成了,那是什么原因呢?!

首先,还是从前端加载开始分析,开始总是盯着明细的异步加载慢的优化,一直改善不了,包括IIS服务器的应用程序池的最大进程数量的调整,提高并发的响应速度,调整了,有效果但是不明显。

然后,开始查看页面的加载顺序,发现了一个比明细加载还慢的异步请求,如图

这个getEntity的异步请求7秒多,比明细加载还慢,于是追查下去发现这个请求了一个跨数据库的查询24万条记录的视图,查询很慢,于是初步分析判断是不是因为这个查询慢的异步请求在明细异步请求getList之前导致,明细的请求被后台数据库处理堵塞在了慢查询的后面等待队列中,导致整个明细查询结果返回慢,于是将慢查询的getEntity放在table明细的异步加载成功后再处理,是不是会提高加载速度?!于是调整了顺序,如上图所示,结果560ms就加载完明细了!尽管getEntiy还是7秒多,但是不影响整体页面呈现效果了!

下一步就是对getEntity整个慢查询的优化了。

总结,现在前端如果响应慢很多时候总是固化的思维模式“哪慢查哪的问题”这么来解决问题,对于常规的问题的确可以找到问题原因,但是特殊情况会如这个问题一样,很多因素导致加载慢的问题出现,这样往往忽略了问题的真正根源在哪?需要跳出固化思维从全局来看待,这才是更好的解决思路!

C#/.NET/.NET Core优秀项目和框架2025年2月简报 - 追逐时光者 - 博客园

mikel阅读(551)

来源: C#/.NET/.NET Core优秀项目和框架2025年2月简报 – 追逐时光者 – 博客园

前言

公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。

eShop

Bulk Crap Uninstaller

  • 项目简介: Bulk Crap Uninstaller 是一款基于 .NET 开源(Apache License)、免费、功能强大的Windows应用卸载工具,旨在帮助用户快速且有效地移除系统中不再需要的大量应用程序。支持批量和强制卸载、清理残留文件、检测隐藏或受保护的已注册应用等功能。虽然面向 IT 专业人员设计,但其简单的默认设置,让任何人都能轻松上手。
  • 项目源码地址: https://github.com/Klocman/Bulk-Crap-Uninstaller
  • 项目详细介绍: https://mp.weixin.qq.com/s/jZCDMcjnpj-_N52jxHgxKw

Netnr.Login

  • 项目简介: Netnr.Login是一个基于 C# 开源(MIT License)的第三方 OAuth2 授权登录整合库,集成了QQ、微信开放平台(Weixin)、微信公众平台(WeixinMP)、微博(Weibo)、淘宝(Taobao)、支付宝(Alipay)、钉钉(DingTalk)、飞书(Feishu)、华为(Huawei)、小米(Xiaomi)、AtomGit、码云(Gitee)、GitHub、GitLab、微软(Microsoft )、StackOverflow等授权登录功能,可以帮助大家快速完成常见的第三方平台的登录授权功能。
  • 项目源码地址: https://gitee.com/netnr/Netnr.Login
  • 项目详细介绍: https://mp.weixin.qq.com/s/XT8WeRxa-_qmrOAs8odj5w

BYSerial

V-Control

Plotly.NET

NetPad

WinformDevFramework

MatBlazor

Cofoundry

mom

  • 项目简介: tmom是一款基于 .NET 开源、通用的生产制造系统,支持多厂区/多项目级的MOM/MES系统,计划排程、工艺路线设计、在线低代码报表、大屏看板、移动端、AOT客户端…… 目标是尽可能打造一款通用的生产制造系统。前端基于最新的vue3、ts、ant design vue, 后端使用.net8、SQLsugar,支持多种数据库切换、数据隔离与聚合。
  • 项目源码地址: https://gitee.com/thgao/tmom
  • 项目详细介绍: https://mp.weixin.qq.com/s/KOxtnNRUngeaSb5vZ86Z-Q

大人的玩具:我用100块做了一个AI眼镜【上篇】

mikel阅读(687)

来源: 大人的玩具:我用100块做了一个AI眼镜【上篇】

自己动手做一个AI 眼镜

5月13日,正好看到Nik Shevchenko分享了一个视频,展示他用20 美元制作了一个外设,挂在眼镜边上,就可以做一个AI智能眼镜,于是我准备复刻一个。

首先是准备工作

项目地址:https://github.com/BasedHardware/OpenGlass

你需要的硬件是一台电脑(我用的是MacPro M2芯片),一个开发板、一个电池、一个3D打印的外壳。

  • Seeed Studio XIAO ESP32 S3 Sense(带蓝牙、摄像头和麦克风)
  • EEMB LP502030 3.7v 250mAH battery
  • 3D printed glasses mount case

这些国内都能买到,需要购买清单的可以滴滴我

(😄我找开发板老板,化缘了一个618粉丝专属福利,备注Rocket)

图片

等硬件都拿到手后,可以开始开发板软件工作了。

01 下载Arduino IDE

Arduino产品地址:https://www.arduino.cc/en/software

这个软件我在整合包里准备好了,大家可以直接回复“Glass”下载

02 设置ESP32S3主板程序

打开Terminal,输入下面代码,把OpenGlass项目代码下载到本地,你也可以手动下载。

git clone <https://github.com/BasedHardware/OpenGlass.git>
然后打开找到OpenGlass文件夹里的 firmware folder 文件夹,并在 Arduino IDE 中打开 .ino 文件。

为ESP32S3 Sense主板设置 Arduino IDE:

图片

将 ESP32S3 板 添加到您的 Arduino IDE

  • 菜单栏,选择“文件”>“首选项”(File > Preferences),然后在“其他 Boards Manager URL”(“Additional Boards Manager URLs” )填写这个链接:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  • 导航到“工具”>“开发板”>“开发板管理器…”(Tools > Board > Boards Manager),在搜索框中输入关键字 esp32 ,选择最新版本的 esp32 并安装它。我这两个都安了一下,但任意选一个就行。图片
  • 最近这个更新到3.0.0版本,但是会引起烧录时报错,建议安装2.0.17版本
  • 选择您的主板和端口:
    • 在 Arduino IDE 顶部,选择开发板和端口。
    • 弹窗中搜索 xiao 并选择 XIAO_ESP32S3 。

图片

“PSRAM:”设置为“PSRAM:”“OPI PSRAM”

在刷机之前,转到Arduino IDE中的“工具”下拉列表,并确保将“PSRAM:”设置为“PSRAM:”“OPI PSRAM”

图片

官方的教程就到这了,但如果你这个时候进行编译,一定会发现哐哐报错。

因为还有一些依赖库没有安装。

我们还需要点击左边菜单的库,搜索并安装 ArduinoBLE、esp_camera

图片安装完后,基本就ok了,如果还有报错,可以看看是否还有依赖库没安上。

现在你可以选一根质量好一点的type c数据线把板子和电脑连接,进行烧录程序。

  • 点击 验证 按钮(对号图标),检查代码是否有错误。
  • 点击 上传 按钮(箭头图标),将代码上传到XIAO ESP32S3开发板。

03 验证功能

  1. 打开Arduino IDE的 串口监视器,检查输出信息。
  2. 确保设备连接到蓝牙。
  3. 检查摄像头是否能够拍照,并通过蓝牙发送数据。

按照这些步骤进行操作,你应该能够成功地将固件上传到XIAO ESP32S3开发板,并实现摄像头和蓝牙的功能。

到这一步,软件工作基本开发结束了,这个时候还有2个步骤需要完成。

04 完善硬件:XIAO ESP32S3开发板连接天线、摄像头、电池

天线的安装

在XIAO ESP32S3的正面左下角,设计了一个独立的“WiFi/BT天线连接器”。

安装天线小窍门:轻轻地将天线连接器的一侧嵌入到连接器块内,从另一侧轻轻下压,就能轻松安装。

同样地,当需要拆卸天线时,也只需在一侧施力,轻轻地提起。图片

安装扩展板

XIAO ESP32S3 Sense,还包括一个扩展板。此扩展板具有1600*1200 OV2640摄像头传感器、板载SD卡插槽和数字麦克风。

安装扩展板非常简单,只需将扩展板上的连接器与XIAO ESP32S3上的B2B连接器对齐,用力按压并听到“咔嗒”一声,即可完成安装。

图片

 

焊接电池

其实如果你不真的戴着这个眼镜出门,可以不用接电池。这块需要用电烙铁焊接,没有焊接技能的人不推荐自己动手,容易把板子搞坏。

焊接电池方法,电池负极焊接到开发板的负极,将正极焊接到开关上,然后再焊接回开发板的正极。这个部分我会在下篇里详细讲到。

05 启动照片的页面程序

烧录完主板,还需要设置一下 Groq 和OpenAI的API。

1. 在位于sources/keys.ts keys.ts 的文件中添加 Groq 和 OpenAI 的 API 密钥。

2. 对于 Ollama,从存储库中自行托管 https://github.com/ollama/ollama 的 REST API,并将 URL 添加到 keys.ts 文件中。

3.启动应用程序:

npm start

如果使用 yarn 启动应用程序


yarn start

启动成功,你在Terminal能看到web页面地址,复制到浏览器可以打开。

图片

目前到这个阶段,我可以通过这个AI设备,实现的功能是可以每隔4秒自动拍照照片,并自动上传记录在本地电脑上。