小智机器人

1.引言 最近有一个很火的开源项目小智机器人-xiaozhi-esp32。 类似于小度音箱和小爱音箱,你可以和小智进行语音沟通,但是小智的服务端对接了大模型(千问、DeepSeek等)。 所以它是一个智能体,可以和用户进行更丰富和有趣的对话。 2.特点 2.1 开源MIT协议,可以用于商用 2.2 支持语音唤醒 需要特定硬件 2.3 基于流式 ASR + LLM + TTS 架构的语音交互 2.4 OLED / LCD 显示屏,支持表情显示 2.5 设备端为ESP32-C3、ESP32-S3、ESP32-P4 芯片平台 价格低廉(最便宜大概50元左右,一般情况小于200元) 立创开发板 立创的这块开发板还带有摄像头,也就是说可以进行图像识别。爱动手的可以买元器件自己装,懒人可以直接在淘宝和京东上买成品。 2.6 后端也有开源实现 xinnan-tech/xiaozhi-esp32-server Python 服务器 joey-zhou/xiaozhi-esp32-server-java Java 服务器 AnimeAIChat/xiaozhi-server-go Golang 服务器 其实虾哥的版本,只开源了客户端和通讯协议,Server的实现都来自第三方 2.7 支持MCP扩展大模型能力 可以实现智能家居控制、PC桌面操作、知识搜索、邮件收发等 小智原生已经带有播放音乐、天气预报、新闻等功能 为了将MCP服务接入小智,萌叔开发了 vearne/xiaozhi-mcp-pipe,欢迎使用。 2.8 有记忆功能 参考 mem0 和 mem0-research 3. 原理&技术 3.1 原理 ESP32芯片的性能非常弱,几百MHz,<1MB的内存,因此几乎所有的功能都是在服务端实现的。 1)【Client】ESP32硬件通过麦克风采集原始音频数据,通过Websocket协议传到Server 2)【Server】对音频数据进行语音识别,转换为文字 3)【Server】使用文字与大模型进行交互,得到回答(文字),回答可能包含指令(控制与之连接的其他外围设备或IoT设备,例如智能灯泡、传感器等) 4)【Server】文字通过TTS转成音频数据,通过Websocket协议再发到ESP32硬件 5)【Client】ESP32硬件通过扬声器播放给用户 3.2 技术 以xinnan-tech/xiaozhi-esp32-server为例说明 LLM 语言模型 使用方式 支持平台 免费平台 openai 接口调用 阿里百炼、火山引擎豆包、深度求索、智谱ChatGLM、Gemini 智谱ChatGLM、Gemini ollama 接口调用 Ollama - dify 接口调用 Dify - fastgpt 接口调用 Fastgpt - coze 接口调用 Coze - 实际上,任何支持 openai 接口调用的 LLM 均可接入使用。 ...

August 13, 2025 · 1 min

玩转MCP(2)-原理篇

1. 引言 这篇文章萌叔来谈谈MCP的协议的一些重要概念,以及它是如何和大模型进行交互的。 2. MCP架构 2.1 Host Host进程充当容器和协调器,它要负责启动MCP-Client,使用Client与对应的MCP-Server进行交互。 通常而言Host with Client就是第一个AI Agent,在其中必然会涉及与大模型的交互。 2.2 Client Client由Host创建,每个Client与特定的Server具有一对一的关系 2.3 Server 通过 MCP 原语暴露resource、tool和prompt, Server可以运行在本地或者是远程服务 3. MCP协议的内容 MCP协议的核心诉求是对外说明Server具有什么能力,Client该如何使用这种能力,每种能力其实都被抽象成了某个tool,类似于函数。 为了更好的使用tool,MCP引入了resource和prompt, 3.1 resource resource一般是可访问的静态或动态数据源,笔者的理解,resource是领域相关的知识库 3.2 prompt 用户或系统提供给模型的指令或上下文输入,用于引导模型行为。 大部分情况下,只提供tool即可,注意: 一个server通过会提供多个tool。 Client和Server采用JSON-RPC 2.0协议。 3.3 Client要获取tool信息通常会发起 ListTools 指令 Request { "method": "tools/list", "params": { "_meta": { "progressToken": 3 } }, "jsonrpc": "2.0", "id": 3 } Response { "jsonrpc": "2.0", "id": 3, "result": { "tools": [{ "name": "remember", "description": "Retrieve historical chat records between users and LLM.", "inputSchema": { "properties": { "keyword": { "description": "key word", "title": "Keyword", "type": "string" }, "start_date": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "Start date in &#039;YYYYMMDD&#039; format.When empty, automatically uses the date 3 months before today", "examples": ["20250620"], "title": "Start Date" }, "end_date": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "End date in &#039;YYYYMMDD&#039; format.When empty, automatically uses today&#039;s date", "examples": ["20250710"], "title": "End Date" }, "max_message_count": { "default": 200, "description": "The maximum number of messages that can be returned", "minimum": 1, "title": "Max Message Count", "type": "integer" } }, "required": ["keyword"], "type": "object" }, "outputSchema": { "properties": { "result": { "title": "Result", "type": "string" } }, "required": ["result"], "title": "_WrappedResult", "type": "object", "x-fastmcp-wrap-result": true } }] } } 3.4 Client使用某个tool时,会使用 callTool 指令 Request { "jsonrpc": "2.0", "method": "tools/call", "id": "tool-call-1754015372815", "params": { "name": "get_datetime", "arguments": { "format": "date_jp" }, "_meta": { "progressToken": 0 } } } Response { "jsonrpc": "2.0", "id": "tool-call-1754015372815", "result": { "content": [{ "type": "text", "text": "2025年08月01日" }], "isError": false } } 4.与大模型的交互 我们已经通过MCP协议获知了MCP Server所能提供的能力,现在需要把这些信息告诉大模型, 让大模型依据上下文以及MCP Server提供的能力,做出决策,发出指令。 ...

August 5, 2025 · 5 min

玩转MCP(1)-使用篇

1. 引言 MCP可以说是function calling的升级版,它使得大语言模型可以方便的整合和具有工具能力。 简单而言,LLM只是一个大脑,它只能思考。 但是当我们给它提供了MCP之后,它可以轻易的获得各种能力, 宛如给他安上了手和腿,它可以行走了,并对外部世界施加影响。 2. 一些MCP 聊天App 萌叔使用的是 daodao97/chatmcp chatmcp可以很方便的集成其它mcp工具,这里介绍几个MCP 2.1 mcp-searxng ihor-sokoliuk/mcp-searxng SearXNG 是一款免费的互联网元搜索引擎,它聚合了来自各种搜索引擎和服务的结果。 用户既不会被追踪,也不会被画像。传送门 使用mcp-searxng,使得大模型可以通过搜索引擎获取信息。 配置方式 { "mcpServers": { "searxng": { "command": "npx", "args": [ "-y", "mcp-searxng" ], "env": { "SEARXNG_URL": "YOUR_SEARXNG_INSTANCE_URL" } } } } Tools searxng_web_search 利用搜索引擎进行检索 web_url_read 从某个URL读取内容 2.2 mcp-datetime ZeparHyfar/mcp-datetime 很多大模型没有时间概念,这会导致他在处理问题时,出现时间错误,mcp-datetime可以 以各种格式获取当前日期和时间。 配置方式 { "mcpServers": { "mcp-datetime": { "command": "uvx", "args": ["mcp-datetime"] } } } Tools get_datetime 2.3 mcp-server-chart antvis/mcp-server-chart antvis/mcp-server-chart是蚂蚁集团出品的图表工具。 mcp-server-chart生成的图片已经使用CDN加速,与大模型交互只传递URL,可以极大的减少token开销。 配置方式 { "mcpServers": { "mcp-server-chart": { "command": "npx", "args": [ "-y", "@antv/mcp-server-chart" ] } } } Tools 可以画25种图表 ...

July 27, 2025 · 2 min

一文了解RAG(检索增强型生成)

在这篇文章中,萌叔将介绍RAG技术。 将它与传统的搜索引擎进行对比,并介绍一个完整的RAG实现–lightRAG,详述其技术细节。 1. 传统搜索 传统搜索通常基于倒排索引来进行搜索 1.1 倒排索引 倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案, 是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。 倒排索引是Term到DocID的映射。 1.2 搜索语句示例 Lucene针对某个字段进行搜索样例 title:hello world 就意味着,搜索title为hello,或者包含title关键字的文档 伪代码形如 doc.title contains &quot;hello&quot; OR doc.title contains &quot;world&quot; 假定 “hello”-> [1, 5, 8] “world”-> [5, 8, 10, 12] 然后搜索引擎对2个doc ID集合的求并集,并对所有文档进行打分,选出分数最高的前N个文档。 2. RAG RAG (检索增强生成) 是一种人工智能技术,它结合了信息检索和生成式模型的功能, 以提高生成文本的准确性和相关性。 RAG 先从外部知识库中检索相关信息,然后结合这些信息,使用生成式模型, 生成更准确、更有上下文相关的文本。 提到RAG,需要先聊一聊Embedding models 2.1 Embedding models 2.1.1 高维向量表征文本 嵌入式模型,可以把一段文本转换为纯数值的高维向量 通过嵌入模型(如bge-m3)将文本转换为1024维的数值向量,这个向量包含了文本的语义特征 curl --location &#039;http://192.168.100.2:21434/api/embed&#039; \ --header &#039;Content-Type: application/json&#039; \ --data &#039;{ &quot;model&quot;: &quot;bge-m3:latest&quot;, &quot;input&quot;: &quot;这个故事的主题是什么?&quot; }&#039; 2.1.2 向量距离反映语义相似度 当两个向量在向量空间中的距离越近(通常用余弦相似度或欧氏距离衡量) 说明它们对应的文本在语义上越相似 例如"猫"和"猫咪"的向量会比"猫"和"汽车"的向量更接近 ...

June 27, 2025 · 2 min

gomock简明教程

1.定义 gomock是一个用于Go语言的Mock框架, 它可以帮助开发者在单元测试中模拟(Mock)接口的行为, 从而隔离被测试代码与外部依赖,使测试更加独立、稳定和高效。 项目原地址为 golang/mock 2023年6月之后,代码库已经归档,官方推荐使用go.uber.org/mock 2.安装 go install go.uber.org/mock/mockgen@latest 3.生成Mock代码 有文件itf.go mockgen -source=./itf.go -destination=./mock.go -package=mymock -source:指定包含接口定义的源文件。 -destination:用于写入结果源代码的文件。 -package:指定生成的Mock代码所在的包名。 4.单元测试 预设的请求,可以按照顺序调用或非顺序调用 4.1 非顺序调用 import ( &quot;fmt&quot; &quot;go.uber.org/mock/gomock&quot; &quot;testing&quot; ) func TestFoo(t *testing.T) { // 创建Mock控制器 ctrl := gomock.NewController(t) defer ctrl.Finish() m := NewMockFoo(ctrl) m.EXPECT().Bar(1).Return(1) m.EXPECT().Bar(2).Return(2) fmt.Println(&quot;--1--&quot;, m.Bar(2)) fmt.Println(&quot;--2--&quot;, m.Bar(1)) } output: --1-- 2 --2-- 1 可以按照任意顺序调用Bar() 4.2 顺序调用 func TestFoo2(t *testing.T) { // 创建Mock控制器 ctrl := gomock.NewController(t) defer ctrl.Finish() m := NewMockFoo(ctrl) gomock.InOrder( // 必须按照指定顺序调用Bar() m.EXPECT().Bar(1).Return(1), m.EXPECT().Bar(2).Return(2), ) fmt.Println(&quot;--1--&quot;, m.Bar(2)) fmt.Println(&quot;--2--&quot;, m.Bar(1)) } 单元测试运行错误 ...

May 29, 2025 · 3 min

推荐一个AI的代理服务(收费)

引言 国内这两年崛起的AI大模型,Kimi和Deepseek,已经足够满足日常的使用需要。 但如果你想体验OpenAI,或者想调用dall-e-3模型画图,或者使用国外的其它音频和视频模型。 你可能需要科学上网,并且可能需要使用信用卡进行注册。其实还是非常不方便。 这里推荐一个AI的反向代理服务: openai-hk 这个服务应该是国人开发的,有QQ客服支持 优势 1.支付方便 使用微信支付,不用包月,按照对接口的实际调用量收费。 从个人使用看,计费即时且精准。 2.不需要科学上网,国内可以随意使用 3. 无限速 因为采用账号池多账号轮询的方案,所以没有API的调用频率限速 4. 支持广泛 以下只列出部分 4.1 文字 gpt-3.5 gpt-4o o1-mini o1-preview gemini claude 4.2 图像 dall-e-3 Midjourney 4.3 音乐 suno udio 4.4 视频 kling 可灵 pika 参考 模型定价列表 5. 文档清晰 openai-hk 文档更新比较快, 新的模型也能很快接入。 另外文档中也介绍了社区一些常用的AI软件,可以作为借鉴和参考。 总结 使用openai-hk 减少了对接的烦恼, 支付更方便,计费合理。适合AI研究人员以及想体验OpenAI等产品的用户。 有兴趣的朋友可以试一下。 作者: vearne 文章标题: 推荐一个AI的代理服务(收费) 发表时间: 2025年2月12日 文章链接: https://vearne.cc/archives/40263 版权说明: CC BY-NC-ND 4.0 DEED

February 12, 2025 · 1 min

介绍OpenAI新发布的Operator

前言 2025年1月23日 OpenAI发布了新的Agent: Operator。 这篇文章将分为2个部分 第1部分,萌叔全文翻译OpenAI的官方介绍资料 第2部分,会基于萌叔自己的理解,介绍一下Operator功能要点和可能的实现思路 废话不多说,进入正题 第1部分 针对新的Agent预览版的研究概述,此Agent可以使用它自己的浏览器来执行用户提出的任务。 今天,我们发布了Operator(在新窗口中打开),一个可以访问网页并为你执行任务的智能代理。 它使用自己的浏览器查看网页,并通过输入、点击和滚动与页面交互。 目前,它是一个研究预览版,这意味着它仍有限制,并将根据用户反馈不断改进。 Operator 是我们推出的首批代理之一,这类 AI 能够自主为你完成任务——你只需指定任务,它就会执行。 Operator 可以处理各种重复性的浏览器任务,例如填写表单、订购杂货,甚至创建梗图。 它能够使用人们日常交互的界面和工具,这不仅拓宽了 AI 的应用范围,还能帮助用户节省日常任务的时间,同时为企业提供新的互动机会。 为了确保安全并逐步推广,我们将从小范围开始。 从今天起,Operator 向美国的 Pro 用户开放, 用户可以在 [operator.chatgpt.com](opens in a new window) 访问。 这个研究预览版让我们能够从用户和更广泛的生态系统中学习,不断优化和改进。 我们计划未来将其扩展到 Plus、Team 和 Enterprise 用户,并将这些能力集成到 ChatGPT 中。 Operator 的工作原理 Operator 由一种名为 Computer-Using Agent (CUA) 的新模型驱动。CUA 结合了 GPT-4o 的视觉能力, 并通过强化学习增强推理能力,使其能够与图形用户界面(GUI)交互——即用户在屏幕上看到的按钮、菜单和文本框。 Operator 可以“看见”(通过截图)并“交互”(使用鼠标和键盘能执行的所有操作)网页,因此无需定制 API 集成,就能在网页上执行任务。 如果遇到挑战或出现错误,Operator 能利用其推理能力进行自我纠正。而当它陷入困境并需要帮助时,会将控制权交还给用户,确保流畅且协作的体验。 尽管 CUA 仍处于早期阶段并存在一些限制,但它在 WebArena 和 WebVoyager 这两个关键的浏览器使用基准测试中创造了新的最先进基准成绩。 你可以在我们的研究博客文章中了解更多关于评估方法及 Operator 背后的研究。 ...

February 6, 2025 · 2 min

开源密码管理小工具 vearne/mypwbox

1. 引子 日常总有很多的密码需要存储,除了使用chrome浏览器的密码管理工具,还有一些其它场景,比如二次密码验证。 2019年萌叔开发了一款纯命令行管理工具 vearne/passwordbox 2024年底,我又在AI的帮助下开发了跨平台的App。vearne/mypwbox 2. 特征和用法 Flutter编写,支持跨平台(需要自己build) 支持国际化,当前支持 中文 或 English 支持使用对象存储(S3协议)进行在线同步&备份(可选,默认为离线) 支持一次性密码 任何支持S3协议的对象存储都可以被使用 AWS S3 Aliyun OSS Tencent COS MinIO 如果密码被用于二次验证且形如 otpauth://totp/ut:vearne?algorithm=SHA1&amp;digits=6&amp;issuer=ut&amp;period=30&amp;secret=XXXXXXXXXXXXXXXXXXXXXXXX 则可以显示对应的基于时间的一次性密码 警告: 关键密码不宜存储于电子文档中,最安全的方式是牢记于心。 作者: vearne 文章标题: 开源密码管理小工具 vearne/mypwbox 发表时间: 2025年01月17日 文章链接: https://vearne.cc/archives/40249 版权说明: CC BY-NC-ND 4.0 DEED

January 17, 2025 · 1 min

给大语言模型插上翅膀

1.引言 有人说,智慧是 知识 + 运用知识的能力。从这个角度来看,大语言模型(如ChatGPT) 在某种程度上可以被认为具有一定形式的智慧。然而现在针对大语言模型的使用有一个问题, 就是模型所具有的知识无法保持实时更新。比如某个API文档发生变化,大语言模型仍然只能基于历史知识进行回答。 有没有办法让大语言模型获取最新的知识,而不至于stale。 显然如果它能够调用搜索引擎,获取最新知识,就可以解决这个问题。 事实上,现在kimi的联网搜索和ChatGPT的搜索网页都是为了解决这个问题。 下面让我们看看如何利用function calling来实现大语言模型从搜索引擎获取数据,继而回答用户的提问。 2. 大语言模型通过搜索引擎获取数据 首先,我们来看一个问题:“今天武汉和上海的气温,哪一个更高?” 对于人类而言,我们要解决这个问题,必须经过以下步骤 1)获取武汉和上海的气温数据 2)比较武汉和上海的最高气温,得出结论 下面萌叔提供一个完整的Python程序,看看如何使用function calling来回答这个提问 import json from email.policy import strict from openai import OpenAI import requests from openai._utils import maybe_transform from openai.types.chat import ChatCompletion base_url = &quot;{此处请自行替换}&quot; api_key = &quot;{此处请自行替换}&quot; google_search_key = &quot;{此处请自行替换}&quot; google_search_engine = &quot;{此处请自行替换}&quot; # 定义 google_search 函数(示例) def google_search(query: str) -&gt; str: url = &quot;https://www.googleapis.com/customsearch/v1&quot; query_params = { &quot;key&quot;: google_search_key, &quot;cx&quot;: google_search_engine, &quot;q&quot;: query, &quot;num&quot;: 5, } response = requests.get(url, params=query_params) print(response.url) return response.text # 调用大模型 def send_messages(messages): # 函数信息,用于 Function Calling tools = [ { &quot;type&quot;: &quot;function&quot;, &quot;function&quot;: { &quot;name&quot;: &quot;google_search&quot;, &quot;description&quot;: &quot;通过 Google 搜索获取信息&quot;, &quot;parameters&quot;: { # 参数类型必须是object &quot;type&quot;: &quot;object&quot;, &quot;properties&quot;: { &quot;query&quot;: { &quot;type&quot;: &quot;string&quot;, &quot;description&quot;: &quot;需要搜索的关键词或短语&quot;, } }, &quot;required&quot;: [&quot;query&quot;], &quot;additionalProperties&quot;: False, }, &quot;strict&quot;: True } }, ] client = OpenAI(api_key=api_key, base_url=base_url) response = client.chat.completions.create( model=&quot;gpt-4o-mini&quot;, # 确保使用支持 Function Calling 的模型 messages=messages, tools=tools, max_tokens=4096, parallel_tool_calls=True, ) dd = maybe_transform(response, ChatCompletion) data = json.dumps(dd, ensure_ascii=False) print(data) return response.choices[0].message if __name__ == &quot;__main__&quot;: # 示例对话 # input_text = input(&quot;请输入您的问题:&quot;) messages = [ {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;你是一个智能搜索机器人。你根据用户提出的问题,利用google_search函数,获取额外信息,然后回答用户的提问&quot;}, {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;今天武汉和上海的气温,哪一个更高?&quot;}, ] # 1. **第1次调用AI接口** message = send_messages(messages) call_cout = len(message.tool_calls) print(f&quot;将会发起{call_cout}次调用...&quot;) # 2. **在client端调用google_search()** messages.append(message) for tool in message.tool_calls: if tool.function.name == &quot;google_search&quot;: parsed_arguments = json.loads(tool.function.arguments) query = parsed_arguments.get(&quot;query&quot;, None) # 获取 query 值 print(&quot;query:&quot;, query) content = google_search(query) messages.append({&quot;role&quot;: &quot;tool&quot;, &quot;tool_call_id&quot;: tool.id, &quot;content&quot;: content}) # 3. **第2次调用AI接口** message = send_messages(messages) print(f&quot;Model&gt;\t {message.content}&quot;) 0) 函数说明 这里我们给出了函数google_search()说明, 并把它传递给大模型, 告诉它在处理问题的时候,可以考虑使用上我们提供的函数。 ...

January 14, 2025 · 3 min

JetBrains IDE整合DeepSeek API实现辅助编程:使用篇

1.引言 在前一篇文章《JetBrains IDE整合DeepSeek API实现辅助编程》中, 萌叔介绍了在JetBrains IDE中安装CodeGPT插件来,借助AI来辅助编程。 这篇文章,萌叔将介绍CodeGPT的使用技巧,方便新手直接上手。 2.使用技巧 2.1 找Bug&代码优化&解释 CodeGPT可以帮助你优化代码。选中一段代码,右键 -> “CodeGPT” -> “Optimize”,CodeGPT会提供优化建议。 Find Bugs/Optimize/Explain 实际调用后端的API是相同的,只是提示词有所不同 示例 上图中的代码中的ioutil.Discard已经不再推荐使用了,我们可以直接让AI帮我们修改一下 上图中是AI给出的回答中,已经帮我们重构了一下。 代码框右上角的几个图标都非常有用。 Diff Selection 对边优化前和优化后的代码,你可以根据需要Accept改动 其它我不再赘述,按字面意思理解即可 2.2 对话 这里的技巧是可以使用 @ 提交文件或者某个文件夹下的所有文件给AI 注意: 请保护隐私数据,不要把敏感数据提交给AI 提交文件,将会消耗更多的token,也就意味着更多的money 作者: vearne 文章标题: JetBrains IDE整合DeepSeek API实现辅助编程:使用篇 发表时间: 2025年01月10日 文章链接: https://vearne.cc/archives/40240 版权说明: CC BY-NC-ND 4.0 DEED

January 10, 2025 · 1 min