这是一个车载智能助手云端 Agent 平台演示项目,当前已跑通文字、流式、事件和多模态交互闭环:
前端交互面板 -> Java Spring Boot 后端 -> Python FastAPI Agent -> 模拟车辆工具/视觉模型 -> 返回回答
car-agent-platform/
├── backend-java/ Java Spring Boot 后端,负责 HTTP、WebSocket 和调用 Agent
├── agent-python/ Python FastAPI Agent 服务,负责意图识别和车辆工具调用
├── vehicle-event-simulator/ Kafka 车辆事件模拟器
├── frontend/ Vite + React 前端聊天页面
├── docker-compose.yml 后续一键启动多服务
└── README.md
| 服务 | 地址 |
|---|---|
| 前端 | http://localhost:5173 |
| Java 后端 | http://localhost:8080 |
| Python Agent | http://localhost:8000 |
| MySQL | localhost:3306 |
| Redis | localhost:6379 |
| Kafka | localhost:9092 |
| Ollama | http://localhost:11434 |
项目 Dockerfile 默认使用 docker.m.daocloud.io/library/... 作为基础镜像来源,原因是部分网络环境下 Docker Hub 直连可能失败。
项目默认使用 Docker Compose 内的 Ollama,不需要任何云端 API Key:文本问答使用 qwen2.5:3b,图片理解使用 qwen2.5vl:3b。仓库只提交 .env.example,真实的 .env 和本地密码记录不会提交。
克隆仓库后,先在项目根目录创建本地配置:
Copy-Item .env.example .env
$passwordChars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789'.ToCharArray()
$rootPassword = -join (1..32 | ForEach-Object { $passwordChars | Get-Random })
$appPassword = -join (1..32 | ForEach-Object { $passwordChars | Get-Random })
while ($appPassword -eq $rootPassword) { $appPassword = -join (1..32 | ForEach-Object { $passwordChars | Get-Random }) }
(Get-Content .env) -replace '^MYSQL_ROOT_PASSWORD=.*$', "MYSQL_ROOT_PASSWORD=$rootPassword" -replace '^MYSQL_PASSWORD=.*$', "MYSQL_PASSWORD=$appPassword" | Set-Content .env也可以手动编辑 .env,为 MYSQL_ROOT_PASSWORD 和 MYSQL_PASSWORD 填入两组不同的随机密码。不要把 .env 或 LOCAL_PASSWORDS.txt 上传到 GitHub。
上传仓库时建议在项目根目录初始化 Git,再执行 git add .;.gitignore 会自动排除本地密码和构建缓存。GitHub 网页的“上传文件”不会替你执行 .gitignore,手动上传时必须确认没有选中 .env 和 LOCAL_PASSWORDS.txt。
首次启动 Ollama 后,需要一次性拉取两个模型:
docker compose up -d ollama
docker compose exec ollama ollama pull qwen2.5:3b
docker compose exec ollama ollama pull qwen2.5vl:3b模型文件保存在 ollama-data volume 中,后续重启无需重复下载。完成后启动整套服务:
docker compose up --build -dAgent 健康检查会显示 llmConfigured、llmProvider、llmModel、visionConfigured 和 visionModel:
curl http://localhost:8000/healthdocker compose up --build -d查看容器:
docker compose ps停止服务:
docker compose downMySQL 数据库名和用户名默认为 car_agent,密码由本机 .env 提供。首次启动会创建数据卷;已有数据卷不会因为修改 .env 自动改密码,需要按数据库迁移方式更新账号密码。
cd agent-python
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
python -m uvicorn app.main:app --reload --port 8000健康检查:
curl http://localhost:8000/healthcd backend-java
mvn spring-boot:run健康检查:
curl http://localhost:8080/api/healthcd frontend
npm install
npm run dev打开:
http://localhost:5173
curl -X POST http://localhost:8080/api/chat ^
-H "Content-Type: application/json" ^
-d "{\"sessionId\":\"session-001\",\"vehicleId\":\"car-001\",\"content\":\"我的车还有多少电?\"}"PowerShell 推荐用下面这种写法:
$body = @{ sessionId = 'session-001'; vehicleId = 'car-001'; content = '我的车还有多少电?' } | ConvertTo-Json -Compress
Invoke-RestMethod -Uri 'http://localhost:8080/api/chat' -Method Post -ContentType 'application/json; charset=utf-8' -Body $body创建或获取会话:
$body = @{ sessionId = 'session-001'; vehicleId = 'car-001'; title = '默认车载助手会话' } | ConvertTo-Json -Compress
Invoke-RestMethod -Uri 'http://localhost:8080/api/sessions' -Method Post -ContentType 'application/json; charset=utf-8' -Body $body查询历史消息:
Invoke-RestMethod -Uri 'http://localhost:8080/api/sessions/session-001/messages' -Method Get查询车辆状态:
Invoke-RestMethod -Uri 'http://localhost:8080/api/vehicles/car-001/state' -Method GetRedis key 设计:
vehicle:car-001:state
session:session-001:context
Compose 会启动 Kafka 和 vehicle-event-simulator。模拟器每 15 秒向 vehicle-events topic 写入一条事件,包括低电量、胎压异常、充电完成、车门未锁。Java 后端通过 Kafka consumer 消费事件,合并更新 Redis 中的 vehicle:{vehicleId}:state;需要提醒用户的事件会通过 /ws/chat 主动推送到前端事件提醒列表。
查看 Kafka 事件模拟器日志:
docker compose logs -f vehicle-event-simulator查看 Java 后端消费日志:
docker compose logs -f backend-java查看车辆状态是否被事件更新:
Invoke-RestMethod -Uri 'http://localhost:8080/api/vehicles/car-001/state' -Method Get查看 Redis 缓存:
docker compose exec redis redis-cli keys '*'
docker compose exec redis redis-cli get vehicle:car-001:state
docker compose exec redis redis-cli lrange session:session-001:context 0 -1- 结构化工具路由:车辆状态查询、车辆控制、最近事件查询、说明书检索
- 本地车辆说明知识库检索,返回匹配的说明书章节来源
- Kafka 事件写入 Redis 最近事件列表,Agent 可以回答“最近有什么异常/提醒”
- 本地 Ollama 文本模型同步和流式调用,支持超时、重试及不可用时规则降级
- Java Agent Client 通过 SSE 接收增量内容,再经 WebSocket 推送到前端
- Redis 上下文保留最近会话消息,车辆事件作为额外上下文注入 Agent
- Java 后端健康检查
- Java 后端 HTTP 聊天接口
- Java 后端 WebSocket 聊天入口
- MySQL 保存会话和聊天消息
- 查询指定会话的历史消息
- Redis 缓存车辆状态和最近上下文
- Kafka 车辆事件消费和 Redis 状态更新
- WebSocket 主动车辆事件提醒
- 查询车辆最近事件:
GET /api/vehicles/{vehicleId}/events - Python Agent 健康检查
- Python Agent 简单规则意图识别
- Ollama 本地模型接入,无需 API Key,调用失败时自动降级
- OpenAI 兼容文本模型流式回复、超时和重试
- 车辆说明书检索和事件上下文问答
- 模拟车辆状态查询和控制
- React 前端聊天界面和历史消息加载
- 图片上传链路:前端 -> Java multipart 校验/转发 -> Python
/agent/vision - Ollama
qwen2.5vl:3b视觉模型可执行图片理解;模型未下载或调用失败时返回明确降级原因 - 浏览器 Web Speech API 语音识别,识别结果复用现有聊天链路
- 浏览器 SpeechSynthesis 语音播报,支持手动播报和自动播报开关
- 轻量 WebRTC 音频演示:浏览器内双 PeerConnection、SDP/ICE 协商和麦克风音轨状态
- 前端展示当前 Agent 工具、知识来源、模型状态和降级状态
启动后可以依次发送:
我的车还有多少电?
胎压异常时应该怎么处理?
最近有什么车辆提醒?
打开空调
其中说明书问题会走 manual_search,事件问题会走 recent_event_query,车辆控制会走 vehicle_control。如果本地语言模型不可用,Agent 仍会返回规则工具结果。
视觉接口默认连接 Compose 中的本地 Ollama。首次拉取 qwen2.5vl:3b 后即可执行图片理解,不需要 API Key:
VISION_PROVIDER=ollama
VISION_API_KEY=
VISION_BASE_URL=http://ollama:11434/v1
VISION_MODEL=qwen2.5vl:3b
VISION_MAX_ATTEMPTS=2
VISION_TIMEOUT_SECONDS=120
当前视觉链路按 JPG、PNG、WebP 校验,单张图片最大 8 MB。若 Ollama 未启动或视觉模型尚未拉取,接口会返回明确降级状态,不会伪造识别结果。浏览器语音识别和麦克风演示需要用户授权,并取决于浏览器能力;未支持时界面会显示明确状态。
本地模型首次加载通常比热请求慢。Java 到 Agent 的同步聊天、流式聊天和视觉请求超时可分别通过 AGENT_CHAT_TIMEOUT_SECONDS、AGENT_STREAM_TIMEOUT_SECONDS、AGENT_VISION_TIMEOUT_SECONDS 调整,Compose 默认值为 90、150、150 秒。
项目目录包含 frontend、backend-java、agent-python 和 vehicle-event-simulator 四个模块,可从仓库根目录按本文档启动。
- Kafka 消费以
eventId做 Redis 原子幂等,重复事件不会重复改状态、写历史或推送。 - Kafka 无效消息和消费异常使用固定间隔重试,超过次数投递到
vehicle-events.DLT,并保留消费日志。 - 车辆事件同时写入 MySQL
vehicle_event表,eventId唯一;Redis 仍保留 24 小时最近事件缓存。 - 事件持久化查询:
GET /api/vehicles/{vehicleId}/events/history?eventType=LOW_BATTERY&from=...&to=...&limit=20。 - Agent 服务增加 IP 窗口限流、并发上限和文本/视觉模型调用短路熔断;健康检查返回治理阈值和熔断状态。
- WebSocket 增加应用层心跳
ping/pong;前端断线指数退避重连,最多 5 次,并展示连接状态。 - Actuator 指标:
/actuator/health、/actuator/metrics,包含 Agent 调用耗时/结果/降级、Kafka 消费结果和 WebSocket 在线数。
浏览器 React 面板
├─ HTTP /api/chat、/api/vision/analyze
├─ WebSocket /ws/chat(assistant_start/delta/done、vehicle_event、ping/pong)
├─ Web Speech API / SpeechSynthesis
└─ 本地双 PeerConnection WebRTC 音频演示
│
▼
Java Spring Boot
├─ MySQL:会话、消息、车辆事件历史
├─ Redis:车辆状态、上下文、近期事件、eventId 幂等键
├─ Kafka:车辆事件消费、重试、DLT
└─ HTTP multipart / SSE client
│
▼
Python FastAPI Agent
├─ 规则工具:车辆状态、控制、近期事件、说明书检索
├─ Ollama qwen2.5:3b:同步/流式问答,超时/重试/熔断/降级
└─ Ollama qwen2.5vl:3b:图片理解,模型不可用时明确降级
- 打开前端,展示车辆状态、事件提醒和 Agent 运行状态面板。
- 发送“我的车还有多少电?”,说明
vehicle_state_query和规则降级链路。 - 发送“胎压异常时应该怎么处理?”,展示
manual_search和知识来源。 - 发送“最近有什么车辆提醒?”,展示 Redis 事件上下文和事件去重。
- 点击“语音”,说“打开空调”,确认语音转文字后沿用 WebSocket 流式回复。
- 上传仪表盘或故障灯图片:展示
qwen2.5vl:3b的实际识别结果;若模型未拉取则展示视觉调用失败的降级状态。 - 打开“回复自动播报”,点击任意回复的“播放”,展示浏览器 TTS。
- 点击 WebRTC“启动链路”,授权麦克风后展示
音频链路已建立;说明这是本地信令演示,不是生产级音视频平台。 - 查看
/actuator/metrics和 Kafka 日志,说明限流、熔断、重试、DLT、幂等和指标设计。
- 支持大模型流式响应
- 增加车辆说明书 RAG 问答
- 增加更完整的前端演示面板
车载智能助手 Vehicle Agent 智能汽车 车载 Agent 多模态交互 视觉理解 语音交互 Spring Boot FastAPI React Kafka Redis MySQL WebSocket