图胜千言·懒人版
近半年如果你关注 AI 客户端、MCP、Agent Memory、Computer Use 这些关键词就会发现很多 AI 工具正在从“聊天窗口”变成更完整的 Agent 工作台。这也是今天要聊的开源项目——DeepChat 演变的路线。一开始它是一个 Chatbot后来逐步演进成一个 Local First 的 Agent 客户端对话、文件、记忆、模型配置都尽量放在本地也支持 MCP、Skills、Computer Use、Agent Memory 等能力。在本文 DeepChat 的两位作者会和我们聊了聊这个项目的起点、产品演进、技术实现以及他们最近在探索的 Agent Memory。DeepChat 是一款本地优先 Agent 桌面客户端GitHub github.com/ThinkInAIXYZ/deepchat本次专访嘉宾夕阳针DeepChat 最早的开发者之一有多年跨端和全栈开发经验做过移动端、桌面端 App也接触过前端、后端等不同方向。工作之外喜欢骑车和拍照。灰灰DeepChat 核心贡献者早期主要负责模型接入最近主要在 DeepChat 实现 Tape]和 Agent Memory。作为开源爱好者陆续给 DB-GPT、NewAPI 等项目提交过 PR。平时喜欢折腾 AI 相关项目和网络代理工具。Tape 是一种将 Agent 的上下文、记忆、运行轨迹trace和可观测性统一在同一个“只追加、不可变的事实记录带”上的底层抽象架构。由于这次专访聊得比较长如果你想先快速了解可以先看下面的“懒人版”。一图胜千言·懒人版1DeepChat 的诞生DeepChat 是什么小七先来和大家介绍下 DeepChat 是什么你想开发者怎么使用它夕阳针DeepChat 现在定位是一个 Local First 的 Agent 客户端。它原来可能是一个 Chatbot这样一路发展过来有一点一直没有变就是我们坚持本地优先。不管是更好地支持你本地的模型部署还是你的数据和交互我们都尽量往本地客户端放把数据留在本地并且做加密。粗浅地说现在的状态可能就是一个不限制模型和供应商的“ChatGPT Codex”合起来的形态。对开发者来说我更希望他们把 DeepChat 当成一个客制化键盘。你直接拿它当工具当然没有问题但我更希望你把它拆掉自己在上面折腾客制化出一个顺手的 Agent或者任何你想要的形态。灰灰我从重度用户的角度补充一下。对我来说DeepChat 首先就是针哥刚刚说的本地优先的 Agent 平台。它没有非常多限制这点我非常喜欢。所有对话、文件、记忆等等都是在自己电脑上。这会带来一个比较长远的思考当我们越用越多把内容拼得越来越多的时候它应该要能越来越懂你。当然这个“越来越懂你”DeepChat 现在还处在探索阶段因为 Memory 没那么好做。这个苗头其实也是从把 Tape 接进来之后才开始比较明显。做 DeepChat 的初衷小七那你们一开始为什么想做 DeepChat夕阳针这个我之前写过一篇博客「2024 VueConf」讲过这个事情。最早是 2025 年 1 月份那个时候 DeepSeek 开始火了网页大家都登不上去于是大家就拿 API 去调。当时我比较喜欢用 Cherry Studio而且我是 Cherry Studio 的重度用户。那时候工作上有一个事情我要调 Prompt。Cherry Studio 当时有个问题它不支持多个会话一起弄。比如老板让我调三个不同的 Prompt我必须等一个调完再发下一条。这就很难受。我一开始想给他们提个 PR 修这个问题结果发现它是 React 写的我又特别不会写 React折腾半天没搞定。后来一怒之下想自己造个轮子。刚好遇到了 Golang 社区的谢孟军他在做一个新的 AI 社区说想做一个商业化、比较友好、全新的 Chatbot问我有没有兴趣一起弄。我觉得这个思路挺好而且我自己很喜欢写 Vue。我看了一圈好像没有人用 Vue 写 Chatbot那我就写一个。当时 DeepChat 就这么开始了。其实一开始就是一个很“一怒之下”的想法莫名其妙就开始写了。灰灰这个其实我跟针哥有一点点类似。因为我一开始也是 Cherry Studio 的重度用户。它一开始挺稳定但后来赶上 DeepSeek 那波热潮Cherry 狠狠火了一把。但是当时它对 PR 的审核机制还没有现在这么标准化。它越更新我发现问题越多。我当时也想过给 Cherry 提 PR但热度实在太高了有时候我 idea 刚想出来别人已经提 PR 上去了。我就想着要不我找一下 Cherry Studio 平替吧。其实我找了非常多 Chatbot基本都那时候市面上的 Chatbot 都逛了一圈。最后社区朋友给我推了 DeepChat。我发现这个项目跟我当时用的 Cherry 版本对比好像更稳定而且界面风格我也更喜欢就干脆切过来了。2在使用的过程中我发现它还有一些小瑕疵。于是我干脆提 PR 一起把 DeepChat 做得越来越好一点。一开始我和针哥是通过邮件联系的从第一个 PR「#636」开始慢慢一起开发。一开始的那一批 PR 都是比较用户视角的东西。哪里不好用我就修哪里。后面越做投入越多几乎每天都会看一眼 issue 或 PR看看还有哪些功能点可以加上去再跟针哥探讨一下。如果他也觉得没啥问题我就开始搞。整体大概就是这么一个过程。Local First 的设计初衷小七刚刚夕阳针提到了 Local First。我想问一下你们为什么把产品设定成 Local First夕阳针这里有几点考虑。第一个点是我自己本身算是一个隐私爱好者。我希望尽可能把很多东西保护起来。虽然我在社交网络上是一个很透明的人但我觉得人应该有这样保护好自己隐私的权利。第二个点是AI 刚出来的时候我们觉得好的上下文才能得到好的结果。你给它的 context 越贴近你自己它出来的结果一定越符合你想达到的目标。我们当时调研了各种平台觉得个人电脑应该是拥有你最多上下文、也是最准确上下文的地方。尤其是工作类场景和创作类场景大部分数据都在你的个人电脑上。虽然你可能在云盘有备份但你最完整的 workspace 一定是在电脑上。所以我们当时就觉得不管后面形态怎么迭代Local First 会很重要。因为它能够接触到你最核心、最懂你的那些数据。另外Local First 做隐私和安全相对更好做也能够打消很多人对 AI 滥用后个人信息泄露的担忧。小七好奇问一句你们接触下来的用户对隐私这一块在意程度如何会有人在便利和隐私之间选择便利吗夕阳针其实还是有不少在意的。DeepChat 其实有不少海外用户我们经常会遇到一些欧洲的学校和未知国籍的程序员发英文邮件给我们咨询隐私问题。之前有个学校教授给我们发邮件说他给学生做 AI 演示和实验的时候用了 DeepChat 项目。由于 DeepChat 有自动更新机制一旦有新版本就会自动去我们官网请求更新。这个教授发现了这个请求他有些不理解这个请求和 AI 模型连接无关为什么会有存在这样的的连接。所以保护隐私这块还是很有意义的。最近有一个国内用户和我说你们所有模型的 key 都存在本地我拿别的 Agent 可以直接去读这些 key再上传到互联网刷你的模型额度、用你的 Token。为此他给我们提了一系列规避 API 被盗刷的技术方案。在他的建议下DeepChat 做了和系统 Keychain 的结合。现阶段DeepChat 应该是现在几个主流 Agent 客户端中比较早做了强数据加密的客户端。它的整个 SQLite 都是加密的。之前还被人开玩笑说DeepChat 能导入别家的数据但导不出我们的数据给别的 Agent。自然这是个玩笑。如果你想把 DeepChat 里的数据导到其他 Agent其实有一个开关。用户授权后把密钥打开就能导出 DeepChat 的数据给其他 Agent 用。不过确实大部分用户觉得在便利上可以让渡一些隐私这是更常见的情况。DeepChat 的升级之路从 Chatbot 到 Agent 客户端小七DeepChat 从早期版本到现在有哪些关键性的功能迭代夕阳针最大的一个迭代应该是在 2025 年下半年到今年初这个阶段。去年 9 月份的时候我去拜访了 Cherry Studio 的办公室和他们当时的团队聊了很多关于 Agent 后续的想法和畅想。也是那个时候Claude Code 这些 Agent 开始火了。Cherry Studio 成立公司之后会开始考虑产品商业化的事情。和 DeepChat 这种纯开源、为爱发电的社区不大一样。他们有很多见解和他们聊完之后我觉得很有意思。回来之后我写了一篇文章写「在 DeepChat 停止开发前」说我要停止开发一下。其实是当时我们决定把整个 DeepChat 从 Chatbot 改成 Agent 客户端。就是这次几乎是把原来的 DeepChat包括模型层、界面全部推翻重做了。这个过程大概花了三、四个月的时间。这是 DeepChat 开发过程中一个非常关键的迭代。DeepChat 从 Chatbot 变成了现在这种有点像 Coding Agent或者说通用 Agent 的形态。现在回想当时还是做了一个蛮大的决心因为很多东西和去年那时候的版本相比真的全部不一样了。灰灰针哥讲的是整个项目的视角我补一个我的开发视角。我第一个 PR 是在 2025 年下半年去年七、八月份那会儿。那是非常疯狂的一个时期每周都有新模型。GPT-5、GLM-4.5、千问、豆包、Grok感觉上这些模型几乎每天都在发新版本。模型发版变频繁之后就有用户来问为什么 DeepChat 现在还用不了某个版本的模型那两个月我光模型接入提交的 PR可能就有三、四十个。平均算下来差不多两天一个的频率。其实接模型不是只接一个名字那么简单。举个例子模型要不要开启思考Thinking这个功能各家模型的表达方式都不一样。当时每次千问发模型我就会喊俊旸哥快点让你的小伙伴们更新一下 API 接口。Qwen 发版经常是模型发得热火朝天结果自己的 API 接口没跟上。不过后面 API 同步更新的速度是慢慢跟上来了。可惜现在俊旸哥走了没有地方吐槽了。再后来我跟针哥商量我们是不是应该把模型配置做成外置化。于是就做「PublicProviderConf 」这个Repo针对这些模型单独衍生了一个庞大的数据库。它实际上是通过上游 「models.dev 」的数据再加上我们对 OpenRouter 等一系列 provider 做全量模型 DB。维护这样一个 DB 会有一个好处当上游更新不及时的时候我们可以主动往这个 DB 里加新的模型调整有问题的参数等非常方便。同时我们会把基础参数及能力等都放在这份 DB 中后续 DeepChat 只需要写一个简易的解析层就能完成所有的适配工作而不需要写很多客制化的代码。比如要不要针对 gpt-5.5 多放一个 xhigh 的参数等等。然后就到了 2025 年底、2026 年初整个 DeepChat 开始转成 Agent 客户端。最近我的开发重心就是把 Tape 接进来之后的 Memory 开发。一个月发版 10 在迭代什么小七我看了一下5 月底到现在DeepChat 发了包括 「v1.0.5」、「v1.0.6」、「v1.0.7」 在内的 10 多个版本。这个发版本速度算是很快了。迭代得这么快可以简单介绍下这几个版本的重点是什么吗夕阳针先补充一下其实我们不止这三个版本。DeepChat 的 Beta 版基本上是一到两天发一个。如果有完整功能合进去我们就会发一个 Beta。针对这三个大版本我们其实有自己的规划。v1.0.5 主要是一些用户交互、细节打磨还有灰灰做的一些东西。v1.0.6 可能是灰灰工作量最重的一版他加了非常多 Tape System 相关的东西。我在 v1.0.6 做得主要功能是 Computer Use。我们跟 Codex 差不多同一时间做了 Computer Use。开源社区里有一个项目叫 「Cua」做得非常好它把 Computer Use 的基础能力都暴露出来了。我一直在追这个项目的更新然后把它集成进了 DeepChat。不过DeepChat 只集成了 Cua 很小一部分毕竟 Cua 是一套完整的 Computer Use 解决方案我只集成了它的驱动部分。然后按照 DeepChat 的实际需求进行修改、适配看客户端需要哪些 Computer Use 能力。上个月六月中旬左右Cua 支持了 Windows 和 Linux 的 Computer Use我又做了一次比较大的集成工作。这是 v1.0.6 中我的主要开发工作。v1.0.7 当时的规划是把闲聊 Chat 模式加回来。因为很多用户跟我们说他们还是想要 Chatbot。DeepChat 最后的 Chatbot 版本停留在了 「v0.5.8」有不少用户 fork v0.5.8 后自己迭代 Chatbot。所以在 DeepChat 的 v1.0.7 中单独划了一块区域让用户可以像之前版本一样当它是个 Chatbot或者是当个 Agent 用。灰灰我从 v1.0.5 开始说吧。我第一次了解到 Tape 其实非常早。当时 PsiACEBub 作者把 Tape 引入 Bub 之后我一直在留意它。我觉得 PsiACE 的实现思路非常有意思。他觉得我们跟大模型探讨的任何东西都应该像一条无休止的纸带一直记录下来。当然在一些关键点位需要有额外的记录。这个跟现在整个 Agent 领域的一些想法很接近就要把完整的用户对话记录尽可能延长下来让 Agent 工作流更持久。用户在做一件事情的时候一般会在一个会话里和 Agent 交流。这个会话里有很多关键点位比如什么时候需要 handoff什么时候要 compact什么时候有 tool use。这些信息记录下来后对后面的 Memory 非常有用。现在 DeepChat 的 Memory 基本上也是依赖 Tape 中的事件记录。它会把所有对话信息、关键点位、工具调用都记下来。这样后面我已经完成了一次完整上下文之后如果往下对话还需要上文的某些内容我就可以通过 Tape 的关键点位找到那个关键点上下的上下文。这是 Tape 真正吸引我的地方。所以v1.0.5 中我做的第一个大工程就是先把 Tape 接进来。而后 v1.0.6Tape 接进来之后开始做 Memory 这块工作。因为我觉得 Tape 很适合往 Memory 方向转。后来DeepChat 社区另一个核心开发者 「zhangmo」提了一个人格记忆的 「PR#1770」。我虽然 review 了那个 PR但它合得很快一下进了主分支。这 PR 和我想基于 Tape 做的 Memory 还有一段差距。既然 Memory 这个事情被人提起来了我就想赶紧把这部分内容完整实现了。于是这一、两个月我投入最多时间的工作就是先把 Tape 这条线补上完整校验和溯源。这有点像给 Agent 执行过程装上一个类似飞机黑匣子的东西。有了它之后再参考市面上一些 Memory 工具和平台造一个属于 DeepChat 的 Memory System。此外v1.0.6 还集成了 「OpenDAL」一个数据访问层。因为之前有用户提过 S3 存储、数据上云这些数据需求。「zhangmo」先实现了一版基于 aws-sdk 实现的同步方案但我之前「xuanwo」 那刚好看到 OpenDAL 这个项目只需要写一下简单范式就能把很多存储接进来项目中因此就将同步方案改成 OpenDAL 了。v1.0.7 这个版本主要是把 Memory System 进一步加强。契机是我在推特上转发了针哥的文章私下去请教了 PsiACE了解他对 Memory 的看法以及为什么 Bub 到现在还没把 Memory 放进来。同时 PsiACE 还将 yihong 大哥之前在 Bub 实现的初版 Memory「PR#33」 让我参考。请教过后自己整合了一部分优点加到了 DeepChat v1.0.7 里。现在我有不少研究生朋友他们整个实验室都在用 DeepChat。他们在读论文、写论文、写实验代码的时候就会用到记忆功能。我做了 DeepChat 的记忆系统之后他们就说“为什么你不早点做这个东西”。因为很多研究员会有一套相对固定的方式去写论文和实验代码。只要 DeepChat 的 Memory 记住了后面他们要 Agent 干活就可以快速从记忆中拉出这个方法论去读写论文或者是编写实验代码甚至他们现在觉得以前写的一些 Skills 都可以删掉了。这里还有一个 todo怎么进行 Memory 的自我更新。在后面的 DeepChat 版本中我应该会实现这个需求。DeepChat 中的技术细节模型接入怎么做抽象小七模型接入这块DeepChat 在架构上是怎么做抽象的夕阳针这个比较有意思。一开始我们维护了一整套API请求。因为 OpenAI、Claude、Gemini 这几个模型的 API 彼此都很不一样所以 2025 年上半年我们做适配做得很痛苦。不止如此第三方模型平台会魔改模型 API往里面加很多奇怪的参数。我们当时对每个模型供应商都写了一个对应的 provider。比如七牛 provider会针对七牛模型接口做一系列适配OpenAI provider 就是接 OpenAI。我个人很喜欢读文档会很认真地把各家文档都看完之后再实现一个接入版本。当时这些 provider 我维护了很久也加了很多小的“黑科技”。比如DeepChat 从很久之前就能看到一些供应商的账户余额。像国内的硅基流动、PPIO还有国外的 OpenRouter你都能在 DeepChat 中看到它们的余额。除了模型 API我还看了 AI 公司能被 DeepChat 用上的相关 API再针对这家厂商封装一个小 SDK。比如 Vercel 出的包括流式渲染、请求在内的一系列 AI SDK我都第一时间去尝试接入。但 Vercel 有个毛病他们很喜欢把半成品先扔出来。所以DeepChat 适配这些就会出很多问题。不过Vercel 迭代得快过一段时间这些问题都解决了。现在 DeepChat 最底层包括 OpenAI、Claude、Gemini 在内的这些模型全部都换成了 AI SDK 接入。此外DeepChat 保留了对每个厂商的二次封装。如果厂商的余额、token 用量、模型参数有自己的配置DeepChat 就会结合 public provider config 那边配置后给出更准确的版本。这样设计provider 配置可以做很多细致的工作。比如有些厂商是聚合站既有 Anthropic 接口也有 OpenAI 接口而且二者是互通的。你可以用 OpenAI 接口去调 Claude 模型也可以用 Anthropic 的接口去调 GPT 模型。这时候如果上下文组织没做好按 OpenAI 最普通的方式去组织上下文就会丢失缓存让模型使用费用变高。所以DeepChat 中某些 provider 会做模型路由。因为中转站一般会有前缀用来区分这个模型来自哪个供应商。这样我就可以根据供应商分配最适合这个模型的接入端点。用 Claude 模型时就自动切到 Anthropic API 的 SDK用 GPT 时再切回 OpenAI。这样所有 cache、缓存命中基本能符合预期不会出现缓存突然飘走的情况。这就是我们之前手动维护一整套 provider 后得到的经验。虽然现在最底层换成了开源社区都在用的 AI SDK但上面还是做了一层封装保障定制化能力、缓存命中率以及对上下文更好的掌控。灰灰我补充模型元数据这一块。刚刚提到 public provider config立项初衷就是因为客户端适配来适配去都是这些模型。但模型的上下文长度、是否支持视觉等这些功能都不同我们决定还是要维护一套属于 DeepChat 的 repo。有了 public provider config 之后DeepChat 只要写一个接入层信息去说明模型有哪些能力有没有思考能力DeepChat 这边只需要解析上游给到的配置信息就能解决这个模型是否展示这个按钮不需要再有对某些模型去做额外的代码适配工作。例如 minimax 的模型配置就可以用这个 json 来表达{“id”: “MiniMax-M2.7-highspeed”,“name”: “MiniMax-M2.7-highspeed”,“family”: “minimax”,“display_name”: “MiniMax-M2.7-highspeed”,“type”: “chat”,“attachment”: false,“reasoning”: {“supported”: true,“default”: true},“temperature”: true,“tool_call”: true,“structured_output”: false,“release_date”: “2026-03-18”,“last_updated”: “2026-03-18”,“open_weights”: true,“modalities”: {“input”: [“text”],“output”: [“text”]},“cost”: {“input”: 0.6,“output”: 2.4,“cache_read”: 0.06,“cache_write”: 0.375},“limit”: {“context”: 204800,“output”: 131072},“metadata”: {“selection”: [“latest”,“fast”,“coding”],“lifecycle”: “active”,“sourceProvider”: “minimax”,“sourceProviderName”: “MiniMax”,“sourceDocs”: [“https://platform.minimax.io/docs/guides/models-intro”,“https://platform.minimax.io/docs/api-reference/api-overview”,“https://platform.minimax.io/docs/guides/text-ai-coding-tools”],“sourceStatus”: “seed”,“apiListed”: false,“source”: “public-provider-conf”},“vision”: false,“extra_capabilities”: {“reasoning”: {“supported”: true,“interleaved”: true,“summaries”: true,“visibility”: “summary”,“continuation”: [“thinking_blocks”],“default_enabled”: true}}}这样就不需要每次有新模型都要单独为这个模型做个适配单独处理开关。补充说明这里的开关指的是一些特殊设定比如模型要不要打开视觉支持、是否支持温度等基础参数配置夕阳针我加一个补充点。public provider config 这个项目目前基本上是 AI 在自主维护了。我们把结构定义好之后后面需要增加新东西可以直接给 Agent 发一下需求。我们有一个 Agent 的打工时间是 7×24 小时每半个小时就去检测几个大厂有没有发新模型。如果发了新模型它会自动把配置写进去。虽然上游的models.dev 是一个很大的项目有很多人给他们提 PR 但不一定及时被合并。比如 Kimi 今天发新模型models.dev 不一定几分钟或几个小时内合进去可能要等第二天早上才会合并 PR 有新的模型配置。所以DeepChat 如果有自己的配置机制可以非常及时地同步模型的更新。一检测到模型厂商发新模型就立刻把 patch 打进 DeepChat。用户在几分钟内就能拉到这个模型配置正常使用。这个体验对用户会非常友好。 当然如果后面上游 models.dev 有了新配置这边会把自己写的配置删掉以上游的配置为准。灰灰这个体验确实好。我的很多研究生朋友有时候新模型一出来就想第一时间用上。早期 DeepChat 没做好配置时需要我们人肉发版、打包发给用户。现在用户只要在设置里刷新模型元数据就能直接用上最新模型。DeepChat 中的 MCP小七MCP 在 DeepChat 里是怎么落地的夕阳针这个是我写的第一个比较让我开心的功能。DeepChat 的 MCP 最早的版本不是我写的。社区里有一个写 Golang 的小伙伴给 DeepChat 写了一整套 MCP demo。但由于他对 Electron 没那么熟这个实现有一点小问题会乱弹进程。虽然有些小 bug但它跑通了 MCP。我觉得它很厉害。拿到那个 「PR#121」后我就基于他的版本去看实现代码对比 MCP 官方文档去优化。但说实话当时 MCP 官方文档写得特别差好像没人维护一样。我就去翻他们 TypeScript SDK 的源码。让我发现他们正在开发一个叫 in-memory 的 MCP 协议。当时 MCP Server 的连接方式主要是 SSE 和 stdio大部分应用也是接入了这两种方式。DeepChat 也实现了这两个版本然后发现 MCP 团队在做 in-memory 协议可以把当前客户端的能力封装成一个 MCP 暴露出来。这样 tool call 就会变成一个非常好编排的方式。当时还没有现在这种 Computer Use 的概念。如果把 in-memory MCP 协议做好再封装一套文件增删查改工具就可以做出一个很像现在 Computer Use 的东西。所以DeepChat 把这个 MCP 协议集成到了内部调用 DeepChat 的代码去操作本地文件。为此我还发了一个小视频「DeepChat MCP 超级功能」展示如何把 DeepChat 开着让它去帮我整理文件夹DeepChat 会按照文件类型、后缀名、尺寸大小帮你整理好文件在当时看来非常酷炫。当 DeepChat 的 MCP 功能终于调通之后又遇到一个新问题用户本地没有 Node 和 Python 环境的话用 MCP 就会很麻烦。我研究了下 Cherry Studio 是如何解决这个问题的。发现他们的做法是写了一篇特别友好的文章教大家怎么安装 Node.js 和 Python。那篇文章确实写得很好一开始我也把那篇文章发给用户说你按这个装就能用 MCP 了。但后来想了想丢教程文档不是长久之计。于是我就开始研究如何更优雅地解决这个问题。这让我发现了一个方案将 Node.js 和 Python 运行环境内置到应用中并用 uv 管理依赖注入到项目。「uv」 是一个很小的工具可以帮你下载依赖、Python 这些东西。这样用户装完 DeepChat 之后本地的开发环境就已经搭好了。他不用去考虑本地 Node.js 配置得对不对要不要 sudo 权限安装包。MCP 配置里只要发现你填的是 npm、npx 这些命令DeepChat 就自动转换成内部 Node.js 环境去跑命令。这就相当于集成了一套 Shell 环境到 DeepChat 中。