DeerFlow 前端工程开发指南:基于 `frontend/AGENTS.md` 的架构、命令体系与 AI Agent 协作规范
导读:DeerFlow 的前端是一个基于 Next.js 16 构建的 Agent 系统 Web 界面,通过 LangGraph SDK 与后端进行线程化对话、流式响应与制品(artifact)交互。本文以 frontend/AGENTS.md 为骨架,系统梳理其架构分层、源码目录约定、完整命令体系、Rstest/Playwright 双轨测试策略、环境变量与代理配置,以及为 AI 编码助手(Claude Code、Codex 等)设计的协作规范。读完你不仅能快速上手
pnpm dev,还能理解每个目录、每条命令、每个测试文件背后的设计意图,具备独立向该工程提交高质量改动、或为其他 Agent 工程撰写同类开发指引的能力。
一、AGENTS.md 是什么:AI 协作的唯一事实来源
在 DeerFlow 仓库中,frontend/AGENTS.md 并不仅是一份人类开发者阅读的 README。它的核心定位在文档首段即被点明:
它为 AI 编码 Agent(Claude Code、Codex 及其他)在操作 DeerFlow 前端时提供指引,是"唯一事实来源"(source of truth);同目录的 frontend/CLAUDE.md 仅通过
@AGENTS.md将其导入。
这一设计解决了多 Agent 协作场景下的文档同步难题:指引只维护一份,Claude Code 用 CLAUDE.md 作为入口、Codex 与通用 Agent 直接读取 AGENTS.md,二者指向同一份内容,避免多份文档漂移失同步。若你以 AI Agent 身份在本工程内开发,第一件事就是完整通读该文件;若你是维护者,也应遵循其"贡献规范"一节的约定,在架构、命令或约定变化时同步更新它(详见后文)。
从仓库结构看,这一"分层指引"思路被延续到了更深一层:frontend/AGENTS.md 明确写到 src/ 下存在更细粒度的 frontend/src/AGENTS.md,将本文件中的前端各分区再行拆分,供聚焦某目录开发时按需查阅。
二、项目概览:一个"有状态对话"式 Agent Web 界面
2.1 它在整个系统中扮演的角色
DeerFlow 前端是一个面向 AI Agent 系统的 Web 界面,它并不自行驱动 Agent,而是通过 LangGraph SDK 与基于 LangGraph 的后端通信,对外提供:
- 基于线程(thread)的 AI 对话:创建会话、发送消息、接收流式响应;
- 线程级
/goal完成条件:用户可为单个线程设定完成目标并跟踪其状态; - 制品(artifacts):后端 Agent 产出的文件/代码等,前端负责展示与管理;
- 技能与工具(skills/tools)系统 的交互入口。
文档给出了一幅非常凝练的架构图:
Frontend (Next.js) ──▶ LangGraph SDK ──▶ LangGraph Backend (lead_agent)
├── Sub-Agents
└── Tools & Skills
即前端是"瘦客户端":它只负责编排对话、渲染流式结果;真正的 Agent 编排、工具调用、技能执行都发生在后端的 lead_agent 及其子 Agent 中。这也解释了为什么前端核心代码(src/core/)里大量模块都与"如何调用后端 API、如何解析流式事件、如何恢复线程状态"相关。
2.2 技术栈与版本要求
文档明确列出了当前栈及运行前提,这些信息与 frontend/package.json 中的声明相互印证:
| 类别 | 版本 / 要求 | 说明 |
|---|---|---|
| 框架 | Next.js 16(package.json 中为 next@^16.2.11) |
App Router 架构,含 i18n 与 rewrites |
| UI 框架 | React 19(react@^19.0.0) |
服务端组件与客户端组件混用 |
| 语言 | TypeScript 5.8(typescript@^5.8.2) |
tsc --noEmit 做类型检查 |
| 样式 | Tailwind CSS 4(tailwindcss@^4.0.15) |
v4 @import 语法 + CSS 变量主题 |
| 包管理 | pnpm 10.26.2(packageManager 字段锁定) |
workspace 内安装使用 pnpm |
| 运行时 | Node.js 22+、pnpm 10.26.2+ | 低于该版本可能无法正常构建 |
2.3 核心依赖及其分工
frontend/AGENTS.md 强调的四组核心依赖,构成了应用的能力底座:
| 依赖 | 版本 | 职责 |
|---|---|---|
@langchain/langgraph-sdk |
^1.5.3 | Agent 编排与流式通信的唯一通道(连接后端) |
@langchain/core |
^1.1.15 | LangChain/LangGraph 的基础类型与构建块 |
@tanstack/react-query |
^5.90.17 | 服务端状态管理(请求缓存、失效、重试) |
| UI 体系 | Shadcn UI、MagicUI、React Bits、Vercel AI SDK | 组件全部由 registry 自动生成,禁止手改 |
结合 frontend/src/core/api/index.ts(重新导出 api-client)以及 frontend/src/core/api 目录下的 api-client.ts、stream-mode.ts、fetcher.ts 等文件可以看出,"LangGraph 客户端单例"是被 core/ 各业务域(threads、artifacts、memory…)共享的底层设施;core/api 之上才是一个个业务领域模块。
三、源码布局(src/):按领域组织而非按类型组织
这是整个工程最值得学习的部分。frontend/AGENTS.md 给出的目录约定打破了常见"全部放 components/ 下"的写法,改用领域化 + 少量共享层结构:
| 顶层目录 | 内容与职责 |
|---|---|
app/ |
Next.js App Router 页面与 API Route Handlers |
components/ |
React 组件,其中 ui/(Shadcn)与 ai-elements/(Vercel AI SDK)自动生成、ESLint 忽略、禁止手改;workspace/(聊天页组件)、landing/(落地页)、docs/(MDX 渲染组件)为手写 |
core/ |
业务逻辑核心。文档列举了大量领域:threads/(创建/流式/状态)、api/(LangGraph 客户端单例)、agents/(自定义 Agent)、subagents/(运行时 worker 目录与管理变更)、auth/、artifacts/、channels/(IM 连接)、integrations/(Lark CLI 等托管三方集成)、i18n/(en-US、zh-CN)、memory/、skills/、messages/、mcp/、models/、input-polish/(发送前草稿改写 API)、voice-input/(浏览器语音识别)、suggestions/、tasks/、todos/、tools/、workspace-changes/(run 级变更文件摘要与 diff 拉取)、config/、notification/、blog/ 等,另有 rehype/、streamdown/ 渲染助手与 utils/ |
hooks/ |
共享 React Hooks |
lib/ |
工具函数,如由 clsx + tailwind-merge 实现的 cn() |
content/ |
MDX 内容(博客、文档),由应用渲染 |
styles/ |
全局 CSS:Tailwind v4 @import + CSS 变量主题 |
typings/ |
环境(ambient)TypeScript 声明 |
根级还有两个关键文件:frontend/src/env.js(环境变量校验,详见第六节)与 mdx-components.ts(MDX 组件映射)。
从实际目录看(如 frontend/src/core 下存在 threads/、channels/、memory/、skills/、mcp/、scheduled-tasks/、subagent-batches/ 等),文档所述与仓库实现一致。这种"核心代码与页面解耦"的布局,使单元测试可以纯粹针对 core/ 逻辑运行而无需渲染 DOM(对应下文 Rstest 的 node 环境设计)。
3.1 app/ 下的主要路由
文档详列了 App Router 中的关键路由,据此可快速定位页面代码:
/—— 落地页(landing);/showcase/[thread_id]—— 白名单公开的只读演示页;/workspace/chats/[thread_id]—— 需要认证的聊天工作台(实际路径见 frontend/src/app/workspace/chats);/workspace/agents/[agent_name]与/workspace/agents/new—— 自定义 Agent 的查看与新建;/artifacts/view—— 无浏览器镶边(chrome-free)的窗口,用面板自带渲染器渲染单个 Markdown 制品;/blog/…与/[lang]/docs/…—— 博客与多语言文档站;(auth)/{login,setup,auth/callback}—— 登录、初始化与 OAuth 回调流;/api/…Route Handlers(例如/api/memory)。
四、命令体系:从开发到发布的完整脚本
frontend/AGENTS.md 的 Commands 表与 frontend/package.json 的 scripts 一一对应,是前端开发最常用的操作入口:
| 命令 | 作用 | 备注 |
|---|---|---|
pnpm dev |
启动开发服务器 | 默认使用 Webpack 打包 |
pnpm build |
生产构建(next build) |
文档额外指出可用 NEXT_CONFIG_BUILD_OUTPUT=standalone 产出 standalone 产物 |
pnpm check |
Lint + 类型检查(eslint . && tsc --noEmit) |
提交前必跑 |
pnpm lint |
仅 ESLint | |
pnpm lint:fix |
ESLint 自动修复 | |
pnpm format |
Prettier 检查 | 实际应用用 pnpm format:write |
pnpm test |
Rstest 单元测试 | |
pnpm test:e2e |
Playwright E2E(Chromium) | |
pnpm typecheck |
tsc --noEmit |
|
pnpm start |
启动生产服务器 |
两个值得注意的工程化细节:
- 开发期默认用 Webpack。当需要诊断本地 Next.js 打包器问题时,可通过环境变量
DEER_FLOW_DEV_BUNDLER=turbo搭配pnpm dev临时切到 Turbopack。这避免了"默认开启 Turbopack 导致难以复现 Webpack 场景问题"的调试困境——把非默认打包器当作诊断手段而非默认值。 pnpm check是提交闸门。它把 ESLint 与全量类型检查串成一条命令,配合贡献规范中"提交前运行"的要求,保证任何 Agent 改动在进入仓库前先过静态检查。
五、双轨测试策略:Rstest 单元测试 + Playwright E2E
DeerFlow 前端的测试体系设计得很克制:能用纯逻辑测试就不渲染 DOM,能 mock 后端就不起真服务。理解这一原则,才能正确地把测试写进正确的轨道。
5.1 Rstest:按环境拆分两个 project
单元测试位于 tests/unit/,目录结构镜像 src/(例如 tests/unit/core/api/stream-mode.test.ts 测试 src/core/api/stream-mode.ts),通过 @/ 路径别名导入被测源码。
Rstest 在 frontend/rstest.config.ts 中定义了两个 project,这是理解整个单测体系的关键:
| project | 环境 | 匹配文件 | 适用对象 |
|---|---|---|---|
node |
纯 node | *.test.ts / *.test.tsx |
纯逻辑测试,几乎覆盖全量套件 |
dom |
happy-dom | *.dom.test.ts / *.dom.test.tsx |
需要 document 的测试 |
两类文件的命名规则本身就是一种声明:
- 需要真实 React 行为(effect 顺序、卸载清理、store 变化触发重渲染)的 Hook,通过
@testing-library/react的renderHook驱动,必须放入.dom.test.*文件,而不是在 node 测试里 mockreact; - 需要渲染组件的测试同理。
设计动机在文档与配置注释中都写得很直白:DOM 环境的运行开销约为 node 套件的 3 倍,因此凡不渲染的测试都不应"升舱"到 DOM 环境。把测试成本显式写进工程文档,能让后续贡献者自动形成"默认纯逻辑、按需 DOM"的成本意识。
配置中还有一个值得借鉴的细节:bundleDependencies: ["streamdown", "katex"] —— 因为 Streamdown 会以副作用形式引入 KaTeX CSS,打包这两个依赖可让 Rsbuild 处理该 CSS 导入,而不是让 Node 直接加载它。
5.2 Playwright E2E:全量 mock 后端
E2E 测试位于 tests/e2e/,由 frontend/playwright.config.ts 驱动:
- 仅 Chromium 桌面浏览器 project;
- 通过
page.route()网络拦截 mock 全部后端 API,测试真实页面交互(导航、聊天输入、流式响应),因此 E2E 无需真实后端即可稳定运行; - webServer 默认执行
next build && next start,并注入SKIP_ENV_VALIDATION=1与DEER_FLOW_AUTH_DISABLED=1环境变量(跳过环境变量校验、关闭认证,专为测试铺路); - 支持
PLAYWRIGHT_BASE_URL指向已运行服务,以及PLAYWRIGHT_SKIP_WEB_SERVER=1跳过内置启动; - CI 下
workers=1、失败重试 2 次、使用 github reporter;本地默认 html reporter,trace: "on-first-retry"便于诊断。
这条"E2E 也 mock 后端"的路线与架构一致:前端真正需要自证的是"页面逻辑与流式渲染正确",而不是后端的真实行为——后者属于后端 E2E 的职责边界。
六、环境变量与网络配置:nginx 优先、直连兜底
前端环境配置体现了"生产默认走反代、开发可直连"的哲学,是排查"页面不响应"类问题时的必读内容。
6.1 两个可选的 API 地址
NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:8001
NEXT_PUBLIC_LANGGRAPH_BASE_URL=http://localhost:8001/api
文档明确指出这两个变量可以留空:标准 make dev / Docker 流程中,nginx 对外提供 /api/langgraph/* 公共前缀并改写转发到 Gateway 的原生 /api/* 路由,因此本地开发无须手工配置。从 frontend/next.config.js 的 rewrites() 实现可以印证这一设计:
- 当
NEXT_PUBLIC_LANGGRAPH_BASE_URL未设置时,把/api/langgraph与/api/langgraph/:path*重写到内部网关地址; - 当
NEXT_PUBLIC_BACKEND_BASE_URL未设置时,把/api/agents、/api/skills以及其余全部网关 API(models、threads、memory、mcp、artifacts、uploads、suggestions、runs 等)通过/api/:path*兜底重写; - 内部网关默认取
DEER_FLOW_INTERNAL_GATEWAY_BASE_URL,缺省回退到http://127.0.0.1:8001; - 注释特别提醒:LangGraph 兼容路由的 rewrite 必须排在网关原生
/api/:path*兜底之前,以保持其公共前缀。
也就是说:变量一旦显式设置,前端便绕过 nginx/rewrite 直连指定后端;否则全部请求收敛到 Next 的 rewrites 层。排查"登录后无响应"等联通问题时,先分清请求走的是反代还是直连。
6.2 环境变量校验(t3-env + zod)
frontend/src/env.js 基于 @t3-oss/env-nextjs 与 zod 对服务端、客户端变量做 schema 校验:
- 服务端:
GITHUB_OAUTH_TOKEN、NODE_ENV(枚举 development/test/production); - 客户端(
NEXT_PUBLIC_*前缀才能暴露给浏览器):NEXT_PUBLIC_BACKEND_BASE_URL、NEXT_PUBLIC_LANGGRAPH_BASE_URL、NEXT_PUBLIC_STATIC_WEBSITE_ONLY; - 通过
SKIP_ENV_VALIDATION可跳过校验(Docker 构建场景); emptyStringAsUndefined: true—— 空字符串按未定义处理,避免''误触发必填校验。
6.3 DEER_FLOW_DEV_ALLOWED_ORIGINS:非 localhost 开发的关键
当开发服务器需通过局域网地址或反向代理主机名访问(而非 localhost)时,必须设置:
DEER_FLOW_DEV_ALLOWED_ORIGINS=192.168.1.20,my-proxy.internal
(逗号分隔;填写完整 URL 也会被自动规约为纯 host。)它喂给 Next 的 allowedDevOrigins,用于门控 /_next/*、字体与 HMR 资源。缺少它会发生什么? 这些资源请求返回 403,页面虽完成 SSR 但永远无法水合(hydrate)——页面看起来渲染了,但包括登录表单在内的所有交互都无响应。
其解析逻辑在 frontend/src/dev-origins.js 中实现得相当细致:normalizeHost() 会剥离 scheme、去掉 /? 后的路径段、单独处理 IPv6 括号字面量,且只在恰好一个冒号(host:port)时剥离端口,避免误伤裸 IPv6。注释点明了陷阱:Next 只按 host 匹配,带 scheme/端口/路径的条目无法命中任何请求。同时该配置仅开发期生效,生产构建会忽略它——这是一个应当写进任何 Agent 工程"常见坑"清单的配置。
七、代码风格约定:让 AI Agent 产出可预测的代码
frontend/AGENTS.md 的 Code Style 一节短小但对 Agent 极其关键——它把审美问题转化为可执行的机械规则:
| 约定 | 规则 |
|---|---|
| 导入顺序 | builtin → external → internal → parent → sibling,组内按字母序,组间空行 |
| 类型导入 | 使用内联类型导入:import { type Foo } |
| 未使用变量 | 前缀 _ 显式声明"有意不用" |
| 条件类名 | 用 cn()(来自 @/lib/utils,封装 clsx + tailwind-merge) |
| 路径别名 | @/* 映射 src/* |
| 生成组件 | ui/ 与 ai-elements/ 由 Shadcn、MagicUI、React Bits、Vercel AI SDK 的 registry 生成,不要手改(二者也被 ESLint 忽略) |
对 AI 编码助手而言,这些规则直接决定了 diff 是否可被人类审查者接受;尤其"生成组件不改、导入分组有序"两条,能显著减少 Agent 改动带来的无谓冲突。
八、贡献规范与前端资源预算门禁(pnpm perf:check)
文档给出了向 DeerFlow 前端添加功能的标准动作序列,这本质上也是 AI Agent 的"开发流程 checklist":
- 遵循既有的
src/结构(新业务逻辑进core/对应领域); - 补充 TypeScript 类型与完善的错误处理;
- 在
tests/unit/写单测(pnpm test),在tests/e2e/写 E2E(pnpm test:e2e); - 提交前运行
pnpm check; - 当架构、命令或约定变化时同步更新本文档(AGENTS.md 自身处于版本管理之下)。
一个容易被忽视的高价值命令是 pnpm perf:check(对应 package.json 中 node scripts/measure-route-assets.mjs --check)。文档说明了它的完整机制:
- 从一个正常生产构建开始测量
/login; - 再以 static-demo 模式构建由 fixture 支撑的 workspace 路由;
- 在临时本地端口启动生产服务器,测量代表性路由实际引用的唯一 JavaScript 与 CSS 文件;
- 详细结果写入
.next/performance-results.json; - 将总计与 frontend/performance-budgets.json 中的预算(例如
/login的 CSS 170KB / JS 850KB,/workspace/chats的 CSS 190KB / JS 1750KB,deep chat 页 JS 上限 4100KB)比对,失败即告警。
文档给出的处置原则是:预算失败时应修复路由归属或代码拆分点,而不是上调上限;确需提高上限,必须记录并评审被实测出的劣化回归。这种"预算文件 + 归因命令 + 升级审批"的组合,比单纯口头要求"注意包体积"可靠得多,是值得在文章里单独强调的工程实践。
九、为贡献者与 Agent 提炼的实用清单
综合 frontend/AGENTS.md 全篇,可沉淀出四条在 DeerFlow 前端高效工作的实用结论:
- 先读文档再动手:AGENTS.md 是唯一事实来源,
src/AGENTS.md提供分区细节;架构演进时这些文档会被要求同步更新。 - 按域落代码、按需选测试环境:业务逻辑进
core/对应领域;不渲染的测试写*.test.ts(node),涉及真实 React 行为的 Hook/组件才写*.dom.test.ts(happy-dom),E2E 一律 mock 后端。 - 提交前跑
pnpm check,预算靠pnpm perf:check:前者拦静态错误,后者拦路由体积劣化。 - 联通问题先查环境:默认反代路径下不需要设置任何
NEXT_PUBLIC_*;一旦页面 SSR 成功却无法交互,优先检查是否为非 localhost 访问且缺少DEER_FLOW_DEV_ALLOWED_ORIGINS所致(403 水合失败);相关校验入口见 frontend/src/env.js 与 frontend/src/dev-origins.js。
若需进一步理解后端侧能力,可继续阅读 backend/docs/API.md 与 backend/docs/ARCHITECTURE.md,结合本仓库根目录 frontend/README.md 与本篇共同构成 DeerFlow 前端的完整认知地图。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00