惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
SegmentFault 最新的问题
博客园 - 聂微东
罗磊的独立博客
W
WeLiveSecurity
博客园_首页
Scott Helme
Scott Helme
V
Visual Studio Blog
T
The Exploit Database - CXSecurity.com
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
L
Lohrmann on Cybersecurity
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
About on SuperTechFans
F
Full Disclosure
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 司徒正美
博客园 - Franky
C
CXSECURITY Database RSS Feed - CXSecurity.com
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
阮一峰的网络日志
阮一峰的网络日志
S
Schneier on Security
雷峰网
雷峰网
博客园 - 【当耐特】
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
T
Tor Project blog
V
V2EX
爱范儿
爱范儿
C
Check Point Blog
T
Threatpost
Project Zero
Project Zero
量子位
V
Vulnerabilities – Threatpost
Know Your Adversary
Know Your Adversary
I
Intezer
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
GbyAI
GbyAI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

V2EX

我用 AI 写代码,但终端管理反而成了累赘——于是我做了 codux - V2EX [调研] 各位在公司都用什么 ide 和 agent 写代码? 老运维 share 一个运维平台 新电脑 brew install node 之后,一个小设置可以提升对供应链投毒的防御 - V2EX GLM-Coding 调用持续报错: z.ai 的 Lite 套餐几乎无法使用,官方 Pro/Max 是否稳定? - V2EX 上海漕河泾内推,本组有 2 个 hc,一个后端,一个前端,预算都是 20k 左右,不打卡,氛围好 如果 V2EX 上有一组不永久保存聊天记录(比如只保存 7 天或者 24 小时)的聊天室,那么会开启哪些有用或者有趣的可能? - V2EX gemini cli 貌似挂了,一直返回 403 - V2EX 第一次在自媒体上赚到钱 收集了最近在使用的低价 GPT, Gemini,邮箱等 AI 会员的小店合集 讨论个大实话:现在企业还在说 AI 编程提效 20%, 30%的,真的太落后,没用懂 AI。因为包括很多前沿公司,已经狂奔到提效 200%-500%的情况 [招聘][远程][币安] 前端/后端/QA/iOS/Android 至少 3 年以上经验 目前有大量 HC 欢迎投递 Chatgpt Pro 用量用不完的可以开这些设置 面试的时候好像遇到钓鱼了,给各位避个坑 cursor 年续费 22 号到期, 自动续费是否还是老的计次套餐呢 - V2EX 被两件破事毁掉的一下午,琐碎的内耗消磨人的精力 使用 Planet 存储 Codex 的会话或者重要信息 - V2EX 如果业务部门领导不要你开发功能,而是要求你教会它用 claude code 开发功能,你会怎么做? 分享一个 MacOS 接绿联 CM818 USB 转 DP 转接器使用感受 - V2EX 我的 HR 朋友 10 年老 Java ,非全大专,大家帮忙看看简历 开源了一个 AI 口语练习工具,音素级发音评分,完全免费可自部署 V2EX 上有哪些你觉得很有趣、印象深刻的妹纸? 字节为啥不出个国内版 Vercel? 有在大马的朋友吗? 问个运营商问题 你们在有领导的公司大群发过的最大胆的消息是什么 公司裁员,目前没有工作。想试试摆摊,做一个移动鲜啤打酒车 我的硬盘 Memblaze Pblaze 5 Linux 下不识别,给 Linux 内核提交了补丁, AI 说有望被合并 - V2EX 只有我一个人觉得 codex 不好用? 做了个 AI + 真人专家监督的广告投放平台 Auxora, 7 个品牌跑出 6x ROAS 如何走出至亲的离世 Claude Web 端貌似 claude-opus-4-7 偷偷上了? 现在 Apple 开发者帳號應該是用哪个地区会更好? - V2EX 用回测筛选因子的一点经验分享 给女儿 vibe 了一个故事类的 app,做完发现,这类应用似乎上线难度极大? - V2EX 手机格式化 bitget 钱包没了,里面开通的银行卡还有机会拿到吗 - V2EX [送码] TransVoice - 我的第一款 App 上架啦!实时转写+翻译+字幕,会议听课好助手! PictureHub 高清摄影作品的画廊 Planet 的第一个使用 macOS 26 SDK 构建的 Insider 版本 20260416-1 - V2EX 成都二手房是不是在涨价,有点坐不住了 - V2EX claude 生态(skill mcp plugin)等 Studio Display XDR VESA 适配器脱落 有在用印度区 applestore 的大哥嘛,请教一下礼品卡去哪里买呢 - V2EX 我好像知道京东家政爆火的原因了 - V2EX 薅了公司的 a 家 api key,用机场 ip 做代理容易被封吗 如何在初期就识别 HR 在刷 KPI,没打算招你? [分享]精心打造一个 AI 编程知识库(算法/设计模式/提示词/Skills),助力程序员转型 港版 iPhone 在国内支持联通 5GA 吗?在广东用 想办港卡 AI 对 it 行业影响太大了 我做了个把照片变成 iOS 小组件贴纸的 App ChatGPT Pro 5x 套餐 量真的很足! I have found a method to directly generate advertising video materials using scripts 在小城市开个店,给人写软件,有前途吗 chrome 最新的 147 版直接卡爆炸了 - V2EX 为什么厂家不在 skill/mcp 这类的工具中塞广告呢?这样不是可以大赚嘛? minimax 真是脸都不要了,工作日下午 14:00 定时开启 529,脸都不要了。训练模型居然占用用户使用时间 外资非核心部门 vs 另一家外资的核心部门,该跳吗? iTad 标签 扩展 加小动作 ? - V2EX 去年 H200 能买,不让买是代替快出来了? - V2EX AI 赛事通 - 2026 年 4 月中国区新增 AI 竞赛和黑客松汇总 - V2EX V2EX › 登录 现在安卓开发都在做啥 - V2EX 浏览器插件 沉浸式翻译 是不支持自定义模型了吗? - V2EX Codex 里的 GPT5.4 也能降智?上午让它改两个问题,改了一个小时了, plus 额度用了一半了还是没改好,和前几天用的体感完全不一样。要它改的问题也不复杂。服了。 目前有使用 claude code 的收到人脸认证的吗 - V2EX 分享一个自己做的 Nginx 管理工具,实时请求动态预览!(无奈市面上实在找不到好用的,自己撸了个) - V2EX claude code 崩了么? 今天在反重力上用 claude 一点都不丝滑,有同样的感受吗? opencode 消息周知插件 今天 claude opus 和前两天比,质的飞跃 - V2EX 999 包月价? - V2EX 一个版本, 50 项更新:我们几乎重做了整个播放页 本地大模型多大显存够用? GOGDNS 一款简易的私人 DNS 服务器 - V2EX API key (GLM) 怎么使用 claude code desktop ? Claude 这样订阅有问题吗 - V2EX 帮我爸找回了一篇赛博兰亭集序 求推荐稳定、高性价比使用 Claude Opus 4.6 的渠道/平台 搞个云端 claude code 防止 封号 - V2EX 用 Claude 要实名了,内地用户怎么办? OpenAI Plus 和 Team 都缩水了吗 海外 Android 手机有什么好用的国内第三方应用市场推荐吗 - V2EX 把电脑伪装成电视,用 DLNA 投屏拿到视频号直播流地址 - V2EX claude 认证莫慌 北京互联网法院有什么攻略么?起诉北京智谱华章科技股份有限公司退款可行么? - V2EX Claude 开始引入身份验证 求 vscode 做笔记软件的插件推荐 - V2EX 讯飞星辰的 Coding Plan 如何? Anthropic 宣布在 Claude 平台推行身份验证机制 科普一下低价 gpt 是怎么来的 有没有长期关注 Claude 的朋友,我建了一个 Channel 自动抓取 Claude Team 的推文 啃了那篇 54 页的 Agent Harness 综述, 给大伙讲个省流版 现在那家的 coding plan 还能买到 是不是最近会有什么更聪明的大模型要发布了呀? 用多了 AI 后,有没有觉得 AI 生成的文章有很强的既视感? 如何 实践 Harness 工程? 今日份 GPT 5.4 笑话 如何建一个自己的号池,让 cursor 真正实现 token 自由 写了三个月 Agent Harness,我终于敢让 Claude Code 全自动写代码了
DAG-chat,让 AI 对话变成思维导图
zmbad · 2026-05-14 · via V2EX
AI 总结

文章标题:DAG-chat,让 AI 对话变成思维导图

本文介绍了一个名为 DAG-chat 的开源项目,旨在解决传统 AI 对话中线性问答结构带来的痛点。作者指出,当用户围绕多个主题(如旅游规划、技术选型、高考志愿填报)进行发散性、对比性讨论时,线性对话记录会导致信息分散、难以回溯和交叉对比,用户体验碎裂。根本原因在于对话思维是结构化的,而现有 AI 问答 APP(如 DeepSeek、ChatGPT)均采用线性组织方式。

DAG-chat 的核心创新是将对话的数据结构从链表(单链)改为有向无环图(DAG)。具体实现如下:

  1. 核心概念:将每个“用户提问 + AI 回答”定义为原子单元 DagNode。整个对话由多个 DagNode 组成 DAG,每个节点可以有多个父节点(parent_ids)和多个子节点(children),从而支持分支和合并。

  2. 分支功能:用户可以从同一条 AI 回复出发,提出不同问题,形成平行分支。界面通过标签栏实现分支间跳转,原有路径不被覆盖,适合探索性对话。

  3. 合并功能:用户可引用多条不同分支的 AI 回复作为上下文,向 AI 提出新问题。AI 回答时能同时看到所有父分支的内容,实现跨分支对比或汇总。

  4. 多模型对比:对话中可随时切换模型(如 DeepSeek、Qwen、GLM),不同模型的回答各占一条分支,再通过合并功能进行对比总结。

  5. 技术实现:

    • 数据模型:传统消息的 parent_id 改为 parent_ids 数组,支持多父节点;children 数组支持多子节点。
    • 前端展示:扫描 DAG 找出分支点和合并点,构建标签页容器,从根节点沿当前激活路径生成线性展示内容。
    • 后端处理:用户发新消息时,BFS 追溯所有祖先节点构建子图,进行拓扑排序后拉平成线性链喂给大模型。作者改进了 Kahn 算法,确保“干净链”(入度=1、出度=1 的连续问答对)不被其他分支切断,保持语义连贯。
    • 技术栈:前端 React 19 + TypeScript + Vite,后端 Python 3.14 + FastAPI,数据库 MongoDB(存消息和 DAG 关系)+ MySQL(存元数据),支持 Docker Compose 部署和本地 Ollama 模型。
  6. 应用场景:除技术选型外,还适用于学习新知识(分支深入不同方面)、写作构思(分支展开不同章节)、debug 排障(分支分析不同方向)等需要“探索→分支→收敛”模式的场景。

作者认为,DAG-chat 类似于一个可实时生长的思维导图,将“概念”换为“对话”,支持分支和合并,比静态思维导图更进一步,更接近人真实的非线性思考方式。项目已开源在 GitHub,支持本地部署和免费使用。

最近有一个 idea ,将 AI 对话的问答以 DAG ( Directed Acyclic Graph )的形式重新组织,提高了前端交互的体验。经过数月 Vibe Coding 以后,DAG-chat终于达到了可以公开发布的版本。

场景假设

假设这样一个场景,五一假期来了,我想在杭州,南京,长沙,武汉四个城市挑选一个度假。首先我和 AI 聊了一下杭州的若干知名景点。聊完了以后,我又和 AI 聊了一下南京的美食。聊完南京的美食以后,我又对杭州的交通便利度产生了好奇。

到目前为止,对杭州的讨论和南京的讨论都是独立无关的。但是如果我想回头查看杭州具体某个景点的介绍,就需要滚动屏幕好久才能找到。如果我又开启了长沙的行程攻略讨论,或者对比一下武汉和南京的美食,那么当前的对话就会变得更加混乱:

  1. 进行了多轮对话以后,如果我想查看单独关于杭州的讨论的汇总(美食,景点,交通等),那么需要不停的滚动屏幕进行查找,关于杭州的讨论并没有集中到一处,而是分散在线性的对话内容中;
  2. 在整个讨论中,有四个城市,每个城市又有美食、景点、交通、娱乐、避雷等多个维度;用户可以针对某几个城市、某些维度进行对比或者关联,如:对比武汉、南京、长沙三地的美食;计划去杭州看西湖,然后武汉游长江,最后去长沙吃湘菜,如何安排规划行程。整个对话其实呈现出高度结构化的逻辑,但是在交互上,都被拍扁放到了一个线性的问答记录中,用户的交互体验很碎裂。

痛点分析

造成这种痛点的根本原因在于:对话沟通的思维是结构化的,有发散和汇总,而绝非单独一问一答。不光是旅游规划,很多场景都如此:

  1. 高考填报志愿。在浙江大学,上海交大,中科大之间抉择。首先要了解这三所学校的专业实力,所在城市发展潜力,保研/出国政策等信息;然后进行交叉对比汇总;
  2. 技术选型。现在要构建一个高性能后端应用,是选择 Rust 还是 Golang ?这两种语言分别从性能,生态,开发难度上进行分析,然后结合团队人员的情况进行选择;

凡是满足:

一个主题 --> 发散思维 --> 对比交叉关联 --> 得出结论

这种沟通范式的,都会存在上述的痛点;

目前市面上几乎所有的 AI 问答 APP ( DeepSeek ,ChatGPT ,Claude ,Gemini ,Qwen ),问答都是以线性的形式进行组织的。如果我想从某个地方开始,往不同的方向探索,再在某一个点上把这些探索汇合起来,以思维导图的形式组织对话内容,这是无法做到的。

那么问题来了,能不能把组织对话的数据结构从链表换成图?

于是做了这个项目:DAG-chat

DAG-chat 效果演示

zh.gif

分支——从同一个回答出发,走不同的路

这是我用得最多的功能。

比如我问 AI “解释一下 Docker 的核心概念”,它给了一段回答。看完之后我脑子里冒出了两个方向:一个是想看看具体的 Dockerfile 怎么写,另一个是想了解 Docker Compose 多容器编排。

在 DAG-chat 里,我可以从同一条 AI 回复出发,分别提两个不同的问题——它们会变成两条平行的分支。界面上会出现一个标签栏,点一下就能在两条分支之间跳转。

switch.gif

操作也很直觉:把鼠标悬停在任何一条用户消息上,左边会出现一个分支图标,点一下,输入框里会自动引用它上面的那条 AI 回复作为上下文。你写上新的问题发出去,一条新分支就出来了。

branch.gif

原来的那条路径不会被覆盖。你开了三条分支,三条都在。想回去看哪条随时切,不丢任何东西。

这在做探索性对话的时候特别有用。比如我在学一个新技术的时候,通常会从概念层面先问一轮,然后针对其中感兴趣的点分别开分支深入——一个分支聊实现细节,一个分支聊最佳实践,一个分支聊常见坑。每个分支都是独立的上下文,互不干扰。最后如果我想对比不同分支里得到的信息,就用下一个功能——合并。

合并——把不同分支的答案汇总到一起

这个功能是我一开始就想做的核心需求,也是最开始的那个痛点——两个分支里的回答想放到一起做对比。

还是技术选型的例子。我在分支 A 里让 AI 分析了 Rust 的优势,在分支 B 里分析了 Go 的优势。现在我想让它做一个综合对比。

在 DAG-chat 里,我把鼠标悬停在两条 AI 回复上,分别点右边的合并图标,它们就被引用到了输入框里。然后我写上”Rust 和 Go 哪个学起来更容易?”——两条分支的上下文会一起作为这条新问题的 parent 。

compare.gif

合并的妙处在于:AI 在回答的时候,能同时看到不同分支的内容。它不是只看了一个片面,而是看到了你探索的全貌。此时,AI 回答的上下文,是沿着所有的 parent 一直向上到最初的提问,所形成的 sub DAG.

多模型对比

对话中间可以随时切模型。比如同一个问题,我先让 DeepSeek 回答,再切到 Qwen 回一个,两条回答各占一条分支。然后再用合并功能让 GLM 做个对比总结。

这个用法在做方案评估的时候特别好使。不同模型的知识储备和推理风格不一样——DeepSeek 可能更擅长逻辑推理,Qwen 在中文理解上有优势,Kimi 的长上下文能力比较强。把多个模型放在同一张图里对比,能比只用一个模型看到更全面的分析。

我试过拿三个模型分别 review 同一段代码,然后合并到一个节点让第四个模型做总结。这种用法在线性对话里,要么开多个对话,手动复制上下文;要么在一个对话里面,但是信息需要来回滚动查看。

除了技术选型,还能怎么用

上面举的例子偏技术开发场景,但其实 DAG 对话结构适用的范围比我想象的要广。

学习新知识。 比如你在学机器学习,问了一个”什么是梯度下降”的基础问题。AI 给了回答之后,你可以在一个分支里追问数学推导,另一个分支里要看代码实现,第三个分支里聊实际应用场景。每个分支独立深入,不会互相污染上下文。学到后面想回顾某个分支的内容,点标签就跳回去了,不用在长长的对话历史里翻找。

写作和内容创作。 我试过用它来构思文章大纲。先让 AI 给一个初始结构,然后在大纲的每个章节上开分支,分别让它展开写。不同章节的构思互不干扰,最后再用合并把几个章节的要点汇聚到一起做统一审阅。

debug 和排障。 遇到一个报错,可以让 AI 从不同方向分析:一个分支走”看日志定位问题”的路线,另一个分支走”检查配置文件”的路线,第三个分支走”搜索已知 issue”的路线。哪条路走通了就沿着哪条继续,走不通的切回去换一条,不浪费之前已经聊过的内容。

本质上,只要你的思考过程是”探索→分支→收敛”这种模式,DAG-chat 都能派上用场。

技术实现

问答对——核心概念

大模型的回答不同于即时通讯,在没有异常中断的情况下,是严格的一问一答节奏,用户提问和大模型的回答,在逻辑上构成了一个原子的,不可分割的问答对。

将这样一个问答对,定义为 DagNode ,整个对话就是由很多个 DagNode 组成的 DAG 。

每次在对话中新增提问内容,实际上就是在向这个 DAG 中,新增一个 DagNode 节点。而整个 DAG ,有且仅有一个 root 节点,即对话开始,最早的那个问答对。从任何一个 dagNode 开始向上遍历,寻找 parnet_ids ,最后都会遍历到最初的 dagNode 。

从链表到图

传统聊天的每条消息只有一个 parent_id ,指向前一条消息。我把这个字段改成了 parent_ids——一个数组。一个节点可以有零个、一个或多个父节点。

传统聊天:
  Message { id, content, role, parent_id }

DAG-chat:
  DagNode { id, content, role, parent_ids[], children[] }

parent_ids 是数组,所以一个用户问题可以引用多条 AI 回复作为上下文——这就是合并。children 也是数组,所以一条 AI 回复可以派生出多个追问——这就是分支。

但是每一个 role=user 的 dagNode ,children 只有一个元素;每个 role=assistant 的 dagNode ,parent_ids 也只有一个元素,这是问答对的定义决定的。

前端怎么把图展示成线性

DAG 在数据库里很自然,但屏幕是一条线。用户一次只能看到从根到叶的一条路径——就像在思维导图里,你虽然能展开所有节点,但目光的焦点在同一时刻也只能沿着一条路径走。

所以前端做的事情是:扫描 DAG 找出所有的分支点和合并点,给每个点建一个标签页容器,tabsContainer 。然后从根节点出发,沿着每个分支点当前激活的标签往下走,生成一条线性路径——这就是屏幕上展示的内容。

根据分支以及合并的特性,有两种 tabsContainer ,一种是 ChildrenTabsContainer ,用于管理分支问里面不同的分支,点击切换的时候,会改变整个渲染 path 中,到 leaf 方向的节点路径;

另一种是 ParentTabsContainer ,用于管理合并提问里面,不同的来源。点击切换的时候,会改变整个渲染 path 中,到 root 方向的途径节点;

用户点击 tab ,实际上就是在 DAG 中所有分支节点和合并节点中,选择一条 path ,从而让前端构建一条从 root 到某个 leaf 的 path 。

后端怎么把图喂给大模型

大模型的 API 只接受线性的对话历史,比如 :

[{role: "user", content: "..."}, {role: "assistant", content: "..."}, ...]

但 DAG 是图结构,不能直接丢过去。

所以后端做了一件事:当用户发新消息时,从这条消息的 parent_ids 出发,BFS 往上追溯所有祖先节点,构建出一个子图( SubDAG )。然后对这个子图做拓扑排序,把它拉平成一条链。

这里有个坑:经典的 Kahn 拓扑排序只保证拓扑序合法(每个节点都在父节点后面),但不保证连贯性——一条干净的链可能被别的分支的节点从中间插断。

前面提过,问答对是原子单元。后端做拓扑排序时以问答对为单位,下面用字母代表:a=(Q₁,A₁), b=(Q₂,A₂),以此类推。先说清楚什么叫”干净的链”。如果一段连续的问答对序列中,每一对都恰好只有一个父、一个子(入度=1 、出度=1 ),中间没有任何分支点(出度>1 )和合并点(入度>1 ),这就是一条干净链。

下图中 b → c → d → e → f 和 h → i → j → k → l ,就是两条“干净的链“。

    ┌── b → c → d → e → f ──┐
    │                       │
a ──┤                       ├── g
    │                       │
    └── h → i → j → k → l ──┘

节点类型:
a              分支点  (出度=2 ,子节点是 b 和 h)
b → c → d → e → f    干净链  (每个节点入度=1, 出度=1)
h → i → j → k → l    干净链  (每个节点入度=1, 出度=1)
g              合并点  (入度=2 ,父节点是 f 和 l)

干净链里的问答在语义上连贯——同一分支上的连续对话。排序时如果别的分支插进来,大模型看到的上下文就会出现话题跳跃。

普通 Kahn 算法处理完 a 之后,b 和 h 同时可用。算法不区分先后,可能先选 h ,走完旁支再回来:

普通 Kahn 排序结果:

a → b → h → i → j → k → l → c → d → e → f → g
       ╰── b→c→d→e→f 这段干净链被旁支切断了 ──╯

拓扑序合法——每个节点都在父节点后面,没有任何违规。但 b→c→d→e→f 这段干净链被 h→i→j→k→l 从中间切断了:b 后面接的不是 c ,而是 h 。大模型看到的对话,聊完 b 突然跳到 h 的分支,绕一圈再回来接 c——连贯线索被切碎了。

我的做法是改进 Kahn 算法,核心保证:干净链不被切断。有三条策略,按优先级依次尝试:

  1. 延续链:刚处理完一个节点,优先选它的子节点继续(前提是子节点原始入度=1 ,确认是链上节点而非合并点)
  2. 开新链:没有可延续的链时,选一个入度=1 、出度=1 的候选节点开新链
  3. 兜底:以上都不满足,选任意可用节点(按 ID 排序保证确定性)

用上面的例子走一遍:

保链排序过程:

  a                                         ← 初始可用
→ b → c → d → e → f                        ← 延续链:a 的子节点 b ,
                                              一路顺着链走到 f
                    ↓
                  h → i → j → k → l          ← 开新链:f 的子节点 g 不可用
                                              (入度=2 ,l 还没处理)
                                              退而选 h (入度=1, 出度=1 )开新链,
                                              一路走到 l
                              ↓
                             g                ← 兜底:l 处理完,g 入度归零

最终结果:

a → b → c → d → e → f → h → i → j → k → l → g
    ╰──── 干净链 ────╯   ╰──── 干净链 ────╯

两条干净链 b→c→d→e→f 和 h→i→j→k→l 都完整保留,没有被切断。不是像普通 Kahn 那样插在 b 和 c 中间。h→l 必须出现在 g 前面,因为 g 是合并点,得等 f 和 l 都处理完才能出场,这是拓扑约束决定的。

两种算法对比:

普通 Kahn:a → b → h → i → j → k → l → c → d → e → f → g
                  ╰── 干净链被旁支切断 ──╯

保链排序:a → b → c → d → e → f → h → i → j → k → l → g
               ╰──── 所有干净链完整 ────╯

技术栈

简单列一下:

  • 前端:React 19 + TypeScript + Vite
  • 后端:Python 3.14 + FastAPI ,模型服务用工厂模式,加新模型只需要继承基类加个注册
  • 数据库:MongoDB 存消息和 DAG 关系(文档结构天然适合图),MySQL 存对话元数据
  • 部署:Docker Compose 一键启动,或者 ./start.sh --all 本地跑
  • 本地模型:支持 Ollama ,没有 API Key 也能用

跟思维导图的关系

回过头来说说为什么我觉得这个项目跟思维导图很像。

思维导图的本质是一个从一个中心出发的树状结构。从一个核心概念开始,发散出几个子话题,每个子话题再继续展开。在这个过程中,你可以同时在好几个方向上思考,互不干扰,但又共享同一个中心。

DAG-chat 做的事情是一样的,只不过把”概念”换成了”对话”,把”发散”变成了”分支”,把”收敛”变成了”合并”。而且比思维导图更进一步的是——DAG 支持合并。在思维导图里,两个分支在某个节点上汇合回来是不太自然的操作,但 DAG 可以。这让整个对话结构更像一张网,而不只是一棵树。

还有一个区别:思维导图是静态的,你画完就定在那了。但 DAG-chat 的对话是活的——你随时可以从任何一个节点开新分支,随时合并,随时切换视角。它更像是一个可以实时生长的思维导图,每次交互都在扩展这张图的结构。

我觉得这种非线性的对话方式,可能更接近人真正思考问题的方式。你在脑子里探索一个问题的时候,不会是线性的——你会同时想好几个方向,然后发现其中两条路其实可以汇合。DAG-chat 就是把这个过程具象化了。

欢迎交流

哔哩哔哩:https://www.bilibili.com/video/BV16D5R6oEck?spm_id_from=333.788.videopod.episodes&vd_source=5a3410516080eb1b6d0a555d39a1ea5f

GitHub 地址:https://github.com/ZM-BAD/DAG-chat

欢迎来 GitHub 看看代码,提提 issue ,或者给个 star 支持一下。

如果你也觉得线性对话这个限制挺烦的,可以试试:

git clone https://github.com/ZM-BAD/DAG-chat.git
cd DAG-chat
cp .env.example .env    # 填入 API Key
./start.sh --all

没有 API Key 也行,装个 Ollama 就能跑本地模型,完全免费:

brew install ollama
ollama pull qwen3:8b
ollama serve
# 然后启动 DAG-chat ,会自动检测本地模型