前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8637
  • Cursor Crane 功能发布
  • AI 智能商品化的循环交易解读
  • Opus 5 在贩卖机模拟中学会欺骗获利
  • GPT-5.6 Sol 修复 Token 消耗缺陷
  • Word Copilot 发现自复制提示注入漏洞
  • Anthropic 倡议顶级 AI 实验室谨慎推进
  • Google Lyria 3.5 音乐生成支持选段编辑
  • PortSwigger Agent 渗透测试的安全隔离设计
  • Cursor 在印度推出本地化定价
  • Claude Opus 5 vs. Fable 5 性能与成本对比
  • 密码学迎接后量子算法过渡时期
  • OpenAI 开发硬件产品线与 AI 交互
  • Google Sheets 支持多轴散点图
  • PwC 报告曝光 AI 生成内容虚假问题
  • Agent 生产部署的安全治理工具包
  • 一键将技术书转化为 Claude Skill
  • 开源模型搭建的低延迟语音 Agent 框架
  • 统一接口访问多个 AI 模型的工具库
  • Claude Code 视频理解插件
  • Pangram 4 推出超高精度 AI 检测器
  • 本地 AI 平台全栈案例:Angular + Spring Boot
  • 多 Agent 协调新方案:Git Refs 与 CRDT
  • MCP 服务器远程代码执行漏洞风险提示
  • AI 生成文本检测技术已成熟
  • OpenAI 公布 AI 前沿风险治理框架
  • Google AI 基础设施成本爆炸式增长
  • AI 代码生成时代,代码审查成为新瓶颈
  • 向量数据库在 Agent 长期记忆中的失效与修复
  • Block 开源 Buzz:AI Agent 工程新范式
  • AI 对话系统的记忆与隐私设计
  • OpenAI 自主 AI 破解 Hugging Face,暴露凭证威胁
  • Claude 破解量子安全算法漏洞
  • AgentShare:MCP 服务器发现平台
  • 移动应用监控工具对比评测
  • Agent 框架的 5 个核心思想(200 行代码)
  • 2026 年 AI 搜索治理:内容去索引与法律应对
  • AWS Bedrock 私钥 JWT 身份认证实现指南
  • Google Lyria 3.5 音乐生成模型发布
  • Anthropic 发布网络安全评估:分析真实攻击场景中的模型防御
  • AI 安全工具 NanoClaw 和 Echo 联手防护数据泄露
  • SGLang 完整支持 Google TPU,LLM 推理框架硬件灵活性升级
  • 2026 年最佳思维导图工具盘点
  • Claude 挖漏洞速度超微软修复
  • Bedrock Agent 和 MCP 驱动无代码商业智能
  • Perplexity 详解 AI Agent 沙箱的有状态系统设计
  • MCP 自动化客户留存工作流,响应时间从天到分
  • 本地推理引擎:M 系列 Mac 仅需 2GB 内存运行 26B 模型
  • GPT-5.6 两个 API 参数设置刷新 ARC-AGI-3 基准
  • GPT-5.6 vs Claude Fable 5 物理 AI 性能对标
  • Copilot 企业版新增全局模型默认启用策略
  • Linux 内核中的 AI 应用探讨
  • 已加载 51 / 8637
6.0
关注
AI SCORE
技术实践2026-07-30 01:11

本地 AI 平台全栈案例:Angular + Spring Boot

dev.to · AI#全栈开发#本地AI#RAG
Editor brief · 编辑速览

Jarvis AI Platform 实战教程,展示后端 RAG 到前端实时 UI 的完整 AI 应用构建流程。对快速上手 AI 应用开发有参考价值。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

从终端到浏览器——Jarvis AI Platform 的第 7 阶段。

在完成六个以后端为核心的阶段后,Jarvis 已经演进为一个功能完备的 local-first AI 平台。

Phase 1 → AI Chat + JWT + CLI
Phase 2 → Long-Term Memory + pgvector
Phase 3 → RAG Document Search
Phase 4 → Tool Engine + MCP Server
Phase 5 → Voice Assistant (Whisper + TTS)
Phase 6 → ReACT Agent System

但所有功能都只能在终端中使用。

第 7 阶段将改变这一点。

目标是在不违背项目理念的前提下,打造一个现代化的浏览器界面:

你的 AI。你的数据。你的机器。

选择前端框架

在编写第一个组件之前,我们先在社区发起了投票。

选择 Angular 有三个原因。

1. 响应式编程与 Spring WebFlux 非常契合

Jarvis 基于 Spring WebFlux 构建。

后端已经通过响应式流和 Server-Sent Events(SSE)进行通信。

Angular 通过 RxJS 原生拥抱这种模型,因此实现流式 API 非常自然。

与手动协调 React hooks 相比,管理订阅、取消、清理和流组合要简洁得多。

2. 维护者已经熟悉 Angular

开源项目的推进速度取决于维护者。

使用一个我已经深入掌握的框架意味着:

更容易为贡献者提供支持。

贡献者随时都可以学习 Angular。

但维护者不应该在审查每一个 pull request 的同时,还要学习一套全新的生态系统。

3. 使用 Angular Material,但不做成 Angular Material 的样子

Angular Material 提供了非常出色的基础:

但整体外观是定制的。

所有布局、间距规则、字体排印选择和配色方案,都是通过 SCSS 实现的。

最终呈现出来的是 Jarvis 的感觉,而不是又一个千篇一律的 Material 应用。

第一个意外:EventSource 行不通

对于 Server-Sent Events,最显而易见的选择是 EventSource。

// ❌ Doesn't work

const source = new EventSource('/api/v1/chat/stream');

遗憾的是,它有三个主要限制:

无法发送 request body

无法发送 Authorization headers

而 Jarvis 三者都需要。

每个聊天请求都需要:

使用 JWT 进行身份认证

因此,EventSource 根本不是一个可行的选项。

解决方案:fetch() + ReadableStream

因此,每一个流式 endpoint 都改用 fetch()。

fetch('/api/v1/chat/stream', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${token}`,
    Accept: 'text/event-stream'
  },
  body: JSON.stringify(request)
})
.then(response => response.body!.getReader())
.then(reader => readStream(reader));

这种方式支持:

完全相同的实现还驱动着:

只需一套流式实现。

“Done”事件触发了两次

后端会发送这样的事件:

event: token
data: {"t":"Hello"}

event: token
data: {"t":" world"}

event: done
data: [DONE]

前端正确处理了 done 事件。

但随后发生了一件奇怪的事。

当浏览器读取完流之后,reader.read() 还会返回:

done === true

于是 onDone() 被执行了两次。

每一条 AI 回复的末尾,都会多出一条空白的 assistant 消息。

只需要一个 guard 就能解决这个问题。

let finished = false;

const finish = () => {
    if (finished) return;

    finished = true;
    onDone();
};

现在,两条代码路径都会调用 finish()。

无论流以何种方式结束,onDone() 都只会执行一次。

设计主题系统

Dark mode 并不是后来才补上的功能。

它从一开始就在设计之中。

每一种颜色都是 CSS custom property。

:root {
  --bg-primary: #0f1117;
  --bg-secondary: #1a1d27;

  --accent-primary: #6366f1;

  --success: #10b981;
  --error: #ef4444;

  --error-surface: rgba(239,68,68,.12);
}

Light mode 只需覆盖这些变量。

.light-theme {
  --bg-primary: white;
  --bg-secondary: #f8f9fc;
}

组件中绝不硬编码颜色。

background: var(--bg-primary);
color: var(--text-primary);

切换主题时,无需修改任何组件,就能重新绘制整个应用。

到处使用 Angular Signals

每个页面都使用 Signals 管理 UI 状态。

readonly messages = signal<Message[]>([]);
readonly streamingContent = signal('');
readonly isStreaming = signal(false);

计算状态也可以保持简单。

readonly canSend = computed(() =>
    this.input().trim().length > 0 &&
    !this.isStreaming()
);
Signals
↓
Everything the template displays

Observables
↓
HTTP calls
SSE streams
Background work

这样的职责划分让组件小得出乎意料。

在流式传输期间,Send 按钮会变成 Stop 按钮。

最初的实现复用了同一个按钮。

<button [disabled]="!canSend()">

流式传输期间,canSend() 会变成 false。

所以 Stop 按钮虽然出现了……

但实际上什么也停止不了。

解决方案是把它拆成两个按钮。

@if (isStreaming()) {
    <button (click)="stopStreaming()">
        stop_circle
    </button>
} @else {
    <button
        [disabled]="!canSend()"
        (click)="sendMessage()">
        send
    </button>
}

停止操作只需中止 fetch 请求。

private abortController: AbortController | null = null;

stopStreaming() {
    this.abortController?.abort();
}

CORS 其实并没有修好

添加 CorsWebFilter 看起来是正确的做法。

但 Spring Security 会在该 filter 执行之前拦截 OPTIONS 请求。

真正的解决方案位于 ServerHttpSecurity 中。

@Bean
SecurityWebFilterChain security(ServerHttpSecurity http) {

    return http
            .cors(cors -> cors.configurationSource(
                    corsConfigurationSource()))
            .csrf(ServerHttpSecurity.CsrfSpec::disable)
            .build();
}

如果没有这项配置,浏览器会拒绝每一个经过身份认证的流式请求,甚至不会让它到达 controller。

✅ Login
    Register/Login tabs
    JWT authentication

✅ App Shell
    Sidebar
    Topbar
    Lazy routing

✅ Chat
    Real-time SSE
    Markdown rendering
    Stop streaming

✅ Settings
    Provider health
    Voice configuration

✅ Memory
    CRUD
    Type badges
    Confirmation dialogs
📋 Documents
📋 Agents
📋 Voice

这些都是当前开放给贡献者的 issue。

可访问性很重要

CodeRabbit 在用户遇到问题之前,发现了多个可访问性缺陷。

不再使用普通的 div,而是:

<div role="status"
     aria-live="polite">
<div role="alert"
     aria-live="assertive">

现在,screen reader 会自动播报消息。

仅仅调整 opacity 是不够的。

键盘用户仍然可能通过 Tab 键聚焦到一个不可见的按钮上。

.memory-card:focus-within .memory-card__delete {
    opacity: 1;
}

.memory-card__delete:focus-visible {
    outline: 2px solid var(--accent-primary);
}

现在,键盘导航的行为已经正确了。

dialog 也获得了正确的语义。

<div
    role="dialog"
    aria-modal="true"
    aria-labelledby="clear-confirm-title">

可访问性得到了大幅改善。

EventSource 并不足够

如果你的 API 有以下要求:

从一开始就使用 fetch() 和 ReadableStream。

硬编码颜色最终一定会破坏 dark mode。

所有可复用的颜色都被定义成了 design token。

随着新页面不断加入,这个决定仍在持续带来收益。

Signals 简化了模板

手动执行 change detection

模板中的订阅

模板变得更容易阅读。

自动化审查能发现真实的 Bug

自动化审查发现了多个足以影响生产质量的 Bug:

onDone() 执行两次

无法访问的删除按钮

错误的 CORS 配置

这些 Bug 最终都没有触达用户。

Lazy Loading 值得投入

每项功能都可以独立加载。

{
  path: 'memory',
  loadComponent: () =>
      import('./features/memory/memory')
          .then(m => m.MemoryPage)
}

贡献者可以添加全新的页面,而不会增大初始 bundle 的体积。

目前还剩下三个主要页面:

📄 Documents
    File upload
    Status polling

🤖 Agents
    Live ReACT execution
    Step-by-step streaming

🎙 Voice
    MediaRecorder
    SSE AI responses

之后就是打磨工作:

后端已经完成了六个阶段。

第 7 阶段的目标,是通过精心打磨的浏览器体验,让用户能够使用这些功能。

Jarvis AI Platform 采用 Apache 2.0 License 开源。

当前开放给贡献者的 issue:

Documents Page → Good First Issue

Agents Page → Intermediate

Voice Page → Advanced

https://github.com/sujankim/jarvis-ai-platform

Jarvis AI Platform 系列文章

第 1 部分——使用 Spring Boot 4 构建 Local-First AI Assistant

第 2 部分——使用 pgvector 实现 Long-Term Memory

第 3 部分——Semantic Memory Retrieval

第 4 部分——使用 Spring AI 构建 Tool Engine

第 5 部分——使用 Whisper 与 Text-to-Speech 构建 Voice Assistant

第 6 部分——使用 ReACT Pattern 构建 AI Agent System

第 7 部分——使用 Angular 22 构建实时 Web UI(本文)

你的 AI。你的数据。你的机器。

如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
Pangram 4 推出超高精度 AI 检测器
下一篇
多 Agent 协调新方案:Git Refs 与 CRDT