feat(spec): json-render v0.15.0 官方架构迁移规格(扩展版)
- Intent: 4 个高优先级改进(useChatUI、pipeJsonRender、Catalog Prompt、Action 简化) - Tasks: 8 个详细任务,包含代码示例和验收标准 - Code Map: 7 个前端文件变更 - 验收标准: 功能/技术/文档三维度 批准记录: - 批准者: 外层 BMAD 专家 - 批准日期: 2026-03-25 - 批准理由: Intent 包含所有 4 个高优先级改进,Tasks 清晰可执行 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
# json-render 官方架构迁移规格(扩展版)
|
||||
|
||||
**项目**: 模板 240 - AI MCP Web UI
|
||||
**当前版本**: @json-render/* 0.14.1
|
||||
**创建日期**: 2026-03-25
|
||||
**状态**: ready-for-dev
|
||||
**批准日期**: 2026-03-25
|
||||
**批准者**: 外层 BMAD 专家
|
||||
|
||||
---
|
||||
|
||||
## 批准记录
|
||||
|
||||
| 日期 | 决策 | 批准者 | 理由 |
|
||||
|------|------|--------|------|
|
||||
| 2026-03-25 | ✅ 批准 | 外层 BMAD 专家 | Intent 包含所有 4 个高优先级改进,Tasks 清晰可执行,Code Map 准确 |
|
||||
|
||||
---
|
||||
|
||||
## 执行摘要
|
||||
|
||||
### 问题陈述
|
||||
|
||||
当前项目使用 Vercel AI SDK 的 `useChat` hook,但未充分利用 `@json-render/react` 的官方 API。存在以下差距:
|
||||
|
||||
| 领域 | 当前实现 | 官方推荐 | 差距 |
|
||||
|------|----------|----------|------|
|
||||
| 前端 Hook | `useChat` from `ai/react` | `useChatUI` from `@json-render/react` | ❌ 未使用官方 Hook |
|
||||
| 后端流式 | `streamText` + `toTextStreamResponse()` | `pipeJsonRender` + `streamText` | ❌ 未使用 pipeJsonRender |
|
||||
| 消息解析 | 手动解析 SpecStream | `useChatUI` 自动解析 | ❌ 自定义解析逻辑 |
|
||||
| Action 处理 | 自定义 `ActionProvider` | `JSONUIProvider` handlers | ⚠️ 部分冗余 |
|
||||
| AI 指令 | 简单的 catalog.prompt() | catalog.prompt() with mode | ⚠️ 未充分优化 |
|
||||
|
||||
### 迁移收益
|
||||
|
||||
- **代码简化**: 减少约 500 行自定义解析逻辑
|
||||
- **类型安全**: 使用官方类型定义
|
||||
- **官方特性**: 获得 `$computed`、`watch`、`repeat` 支持
|
||||
- **维护性**: 跟随官方更新,减少维护成本
|
||||
- **性能优化**: 官方优化的流式解析管道
|
||||
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
将模板 240 的 json-render 实现从自定义架构迁移到官方推荐架构,包括:
|
||||
|
||||
1. **前端 Hook 迁移**: 从 `useChat` (Vercel AI SDK) 迁移到 `useChatUI` (@json-render/react)
|
||||
2. **后端流式优化**: 集成 `pipeJsonRender` 模式处理 SpecStream
|
||||
3. **Catalog Prompt 集成**: 在 AI agent 指令中充分使用 catalog 能力
|
||||
4. **Action 处理简化**: 使用官方 JSONUIProvider 的 handlers 机制
|
||||
|
||||
---
|
||||
|
||||
## Approach
|
||||
|
||||
### 阶段 1: 依赖验证与架构准备
|
||||
|
||||
**目标**: 确认当前依赖版本支持所需功能
|
||||
|
||||
| 步骤 | 描述 | 文件 |
|
||||
|------|------|------|
|
||||
| 1.1 | 验证 @json-render/* 版本 | package.json |
|
||||
| 1.2 | 确认 Vercel AI SDK 集成 | package.json |
|
||||
|
||||
### 阶段 2: 前端 Hook 迁移
|
||||
|
||||
**目标**: 从 `useChat` 迁移到 `useChatUI`
|
||||
|
||||
| 步骤 | 描述 | 文件 | 风险 |
|
||||
|------|------|------|------|
|
||||
| 2.1 | 替换 useChat 为 useChatUI | app/page.tsx | 中 |
|
||||
| 2.2 | 更新消息渲染逻辑 | components/ChatMessage.tsx | 中 |
|
||||
| 2.3 | 更新 ChatInput 集成 | app/page.tsx | 低 |
|
||||
| 2.4 | 移除 action-context 依赖 | lib/action-context.tsx | 低 |
|
||||
|
||||
### 阶段 3: 后端流式优化
|
||||
|
||||
**目标**: 集成 `pipeJsonRender` 模式
|
||||
|
||||
| 步骤 | 描述 | 文件 | 风险 |
|
||||
|------|------|------|------|
|
||||
| 3.1 | 集成 pipeJsonRender | app/api/chat/route.ts | 低 |
|
||||
| 3.2 | 验证流式输出格式 | app/api/chat/route.ts | 低 |
|
||||
|
||||
### 阶段 4: Catalog Prompt 集成
|
||||
|
||||
**目标**: 优化 AI agent 指令
|
||||
|
||||
| 步骤 | 描述 | 文件 | 风险 |
|
||||
|------|------|------|------|
|
||||
| 4.1 | 优化 system prompt | app/api/chat/route.ts | 低 |
|
||||
| 4.2 | 验证 AI 输出质量 | - | 低 |
|
||||
|
||||
### 阶段 5: Action 处理简化
|
||||
|
||||
**目标**: 使用官方 handlers 机制
|
||||
|
||||
| 步骤 | 描述 | 文件 | 风险 |
|
||||
|------|------|------|------|
|
||||
| 5.1 | 定义 handlers 对象 | app/page.tsx | 低 |
|
||||
| 5.2 | 更新 JSONUIProvider | components/JsonRenderer.tsx | 低 |
|
||||
| 5.3 | 清理 ActionProvider | app/page.tsx | 低 |
|
||||
|
||||
---
|
||||
|
||||
## Code Map
|
||||
|
||||
### 前端文件
|
||||
|
||||
| 文件路径 | 变更类型 | 描述 |
|
||||
|----------|----------|------|
|
||||
| `frontend-v2/app/page.tsx` | **修改** | 迁移 useChat → useChatUI,添加 handlers |
|
||||
| `frontend-v2/app/api/chat/route.ts` | **修改** | 集成 pipeJsonRender,优化 system prompt |
|
||||
| `frontend-v2/components/ChatMessage.tsx` | **修改** | 简化消息渲染逻辑 |
|
||||
| `frontend-v2/components/ChatInput.tsx` | **修改** | 更新 send/stop 处理 |
|
||||
| `frontend-v2/components/JsonRenderer.tsx` | **修改** | 添加 JSONUIProvider handlers |
|
||||
| `frontend-v2/lib/hooks.ts` | **修改** | 移除 useChat 相关注释 |
|
||||
| `frontend-v2/lib/action-context.tsx` | **删除** | 不再需要自定义 ActionProvider |
|
||||
| `frontend-v2/lib/registry.tsx` | **修改** | 更新组件使用 handlers 而非 emit |
|
||||
|
||||
### 后端文件
|
||||
|
||||
| 文件路径 | 变更类型 | 描述 |
|
||||
|----------|----------|------|
|
||||
| `backend/app_fastapi.py` | **无变更** | FastAPI 后端暂不修改 |
|
||||
|
||||
### 配置文件
|
||||
|
||||
| 文件路径 | 变更类型 | 描述 |
|
||||
|----------|----------|------|
|
||||
| `frontend-v2/package.json` | **验证** | 确认依赖版本 |
|
||||
| `frontend-v2/next.config.js` | **可选** | 添加 serverComponentsExternalPackages |
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### Task 1: 依赖验证
|
||||
|
||||
**描述**: 验证当前依赖版本支持所需功能
|
||||
|
||||
**步骤**:
|
||||
1. 检查 `frontend-v2/package.json`
|
||||
2. 确认 `@json-render/core` >= 0.14.1
|
||||
3. 确认 `@json-render/react` >= 0.14.1
|
||||
4. 确认 `ai` >= 6.0.0
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 所有依赖版本符合要求
|
||||
- [ ] 无需升级(当前 0.14.1 已支持)
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 前端 Hook 迁移 - useChat → useChatUI
|
||||
|
||||
**描述**: 将前端 Hook 从 Vercel AI SDK 的 `useChat` 迁移到 `@json-render/react` 的 `useChatUI`
|
||||
|
||||
**文件**: `frontend-v2/app/page.tsx`
|
||||
|
||||
**当前代码**:
|
||||
```typescript
|
||||
import { useChat } from 'ai/react';
|
||||
|
||||
const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat({
|
||||
api: '/api/chat',
|
||||
headers: async () => {
|
||||
const tokens = mcpTokenManager.getAllTokens();
|
||||
const enabledMcpList = mcpTokenManager.getEnabledMcpList();
|
||||
return {
|
||||
'X-MCP-Tokens': JSON.stringify(tokens),
|
||||
'X-MCP-Enabled': JSON.stringify(enabledMcpList),
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**目标代码**:
|
||||
```typescript
|
||||
import { useChatUI } from '@json-render/react';
|
||||
|
||||
const {
|
||||
messages, // 包含 text 和 specs
|
||||
input,
|
||||
handleInputChange,
|
||||
isStreaming,
|
||||
send, // 替代 handleSubmit
|
||||
stop
|
||||
} = useChatUI({
|
||||
api: '/api/chat',
|
||||
headers: async () => {
|
||||
const tokens = mcpTokenManager.getAllTokens();
|
||||
const enabledMcpList = mcpTokenManager.getEnabledMcpList();
|
||||
return {
|
||||
'X-MCP-Tokens': JSON.stringify(tokens),
|
||||
'X-MCP-Enabled': JSON.stringify(enabledMcpList),
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- [ ] useChatUI 正确导入
|
||||
- [ ] messages 包含 text 和 specs 字段
|
||||
- [ ] send() 方法正确发送消息
|
||||
- [ ] MCP Token 正确传递
|
||||
- [ ] 聊天功能正常工作
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 更新消息渲染逻辑
|
||||
|
||||
**描述**: 简化 ChatMessage 组件,使用 useChatUI 自动解析的 specs
|
||||
|
||||
**文件**: `frontend-v2/components/ChatMessage.tsx`
|
||||
|
||||
**关键变化**:
|
||||
- 移除 `isSpecStreamFormat()` 检测
|
||||
- 移除 `compileSpecFromStream()` 编译
|
||||
- 移除 `extractRenderableElements()` 提取
|
||||
- 直接使用 `specs` prop
|
||||
|
||||
**目标接口**:
|
||||
```typescript
|
||||
interface ChatMessageProps {
|
||||
role: 'user' | 'assistant';
|
||||
text?: string; // 分离的文本内容
|
||||
specs?: Spec[]; // 直接从 useChatUI 获取
|
||||
isStreaming?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 移除所有手动解析逻辑(约 100 行)
|
||||
- [ ] specs 正确渲染
|
||||
- [ ] Markdown 正确渲染
|
||||
- [ ] 流式状态正确显示
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 更新 ChatInput 组件
|
||||
|
||||
**描述**: 更新 ChatInput 使用 useChatUI 的 send() 方法
|
||||
|
||||
**文件**: `frontend-v2/app/page.tsx`
|
||||
|
||||
**当前代码**:
|
||||
```typescript
|
||||
<ChatInput
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
onSubmit={handleSubmit}
|
||||
isLoading={isLoading}
|
||||
onStop={stop}
|
||||
/>
|
||||
```
|
||||
|
||||
**目标代码**:
|
||||
```typescript
|
||||
<ChatInput
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
onSubmit={(message) => send(message)}
|
||||
isLoading={isStreaming}
|
||||
onStop={stop}
|
||||
/>
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- [ ] send() 方法正确发送消息
|
||||
- [ ] stop() 方法正确中断流式输出
|
||||
- [ ] 输入框状态正确管理
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 后端流式优化 - 集成 pipeJsonRender
|
||||
|
||||
**描述**: 在 Next.js API Route 中集成 `pipeJsonRender` 处理混合流
|
||||
|
||||
**文件**: `frontend-v2/app/api/chat/route.ts`
|
||||
|
||||
**当前代码**:
|
||||
```typescript
|
||||
const result = streamText({
|
||||
model: anthropicModel,
|
||||
system: catalog.prompt({ mode: 'inline' }),
|
||||
messages,
|
||||
tools: allTools,
|
||||
temperature: 0.7,
|
||||
});
|
||||
|
||||
return result.toTextStreamResponse();
|
||||
```
|
||||
|
||||
**目标代码**:
|
||||
```typescript
|
||||
import { pipeJsonRender } from '@json-render/core/server';
|
||||
|
||||
const result = streamText({
|
||||
model: anthropicModel,
|
||||
system: catalog.prompt({ mode: 'inline' }),
|
||||
messages,
|
||||
tools: allTools,
|
||||
temperature: 0.7,
|
||||
});
|
||||
|
||||
// 使用 pipeJsonRender 处理混合流
|
||||
const stream = result.toTextStreamResponse();
|
||||
return pipeJsonRender(stream);
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- [ ] pipeJsonRender 正确导入
|
||||
- [ ] 流式响应正常工作
|
||||
- [ ] MCP 工具调用正常
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Catalog Prompt 集成
|
||||
|
||||
**描述**: 优化 AI agent 指令,确保 catalog.prompt() 充分利用
|
||||
|
||||
**文件**: `frontend-v2/app/api/chat/route.ts`
|
||||
|
||||
**当前代码**:
|
||||
```typescript
|
||||
system: catalog.prompt({ mode: 'inline' }),
|
||||
```
|
||||
|
||||
**验证项**:
|
||||
- [ ] mode 参数正确设置为 'inline'
|
||||
- [ ] catalog 定义包含所有组件
|
||||
- [ ] AI 能够正确输出组件 spec
|
||||
|
||||
**验收标准**:
|
||||
- [ ] AI 正确识别可用组件
|
||||
- [ ] AI 正确输出 SpecStream 格式
|
||||
- [ ] 组件渲染正常
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Action 处理简化 - 使用 handlers
|
||||
|
||||
**描述**: 使用 JSONUIProvider 的 handlers 机制替代自定义 ActionProvider
|
||||
|
||||
**文件**: `frontend-v2/app/page.tsx`, `frontend-v2/components/JsonRenderer.tsx`
|
||||
|
||||
**当前代码**:
|
||||
```typescript
|
||||
import { ActionProvider } from '@/lib/action-context';
|
||||
|
||||
<ActionProvider actions={actionContext()}>
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{messages.map((msg, idx) => (
|
||||
<ChatMessage key={idx} {...msg} />
|
||||
))}
|
||||
</div>
|
||||
</ActionProvider>
|
||||
```
|
||||
|
||||
**目标代码**:
|
||||
```typescript
|
||||
// 定义 handlers
|
||||
const handlers = {
|
||||
sendMessage: async (params: { message: string }) => {
|
||||
send(params.message);
|
||||
},
|
||||
selectNovel: async (params: { id: string; title: string }) => {
|
||||
send(`查看小说:${params.title}`);
|
||||
},
|
||||
copy: async (params: { text: string }) => {
|
||||
await navigator.clipboard.writeText(params.text);
|
||||
},
|
||||
};
|
||||
|
||||
<JSONUIProvider registry={registry} handlers={handlers}>
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{messages.map((msg, idx) => (
|
||||
<ChatMessage key={idx} {...msg} />
|
||||
))}
|
||||
</div>
|
||||
</JSONUIProvider>
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- [ ] ActionProvider 移除
|
||||
- [ ] handlers 正确定义
|
||||
- [ ] 组件交互正常工作
|
||||
- [ ] SuggestionButtons 正确发送消息
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 清理废弃代码
|
||||
|
||||
**描述**: 删除迁移后不再需要的文件和代码
|
||||
|
||||
**删除文件**:
|
||||
- [ ] `frontend-v2/lib/action-context.tsx`
|
||||
|
||||
**清理代码**:
|
||||
- [ ] `frontend-v2/lib/hooks.ts` - 移除 useChat 相关注释
|
||||
- [ ] `frontend-v2/lib/registry.tsx` - 移除 useActionEmit 依赖
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 无编译错误
|
||||
- [ ] 无运行时错误
|
||||
- [ ] 功能完整
|
||||
|
||||
---
|
||||
|
||||
## 验收标准
|
||||
|
||||
### 功能验收
|
||||
|
||||
| 功能 | 描述 | 验证方法 |
|
||||
|------|------|----------|
|
||||
| 聊天发送 | 用户可以发送消息 | 发送 "你好" |
|
||||
| 流式输出 | AI 响应实时显示 | 发送长文本问题 |
|
||||
| 组件渲染 | MCP 工具结果正确渲染 | 发送 "获取小说列表" |
|
||||
| 组件交互 | 组件交互事件正常 | 点击小说卡片 |
|
||||
| MCP Token | Token 正确传递到后端 | 登录后调用 MCP 工具 |
|
||||
|
||||
### 技术验收
|
||||
|
||||
| 指标 | 当前 | 目标 | 验证方法 |
|
||||
|------|------|------|----------|
|
||||
| 代码行数 | ~1500 | ~1000 | cloc |
|
||||
| 依赖大小 | ~120KB | ~95KB | npm ls |
|
||||
| 渲染性能 | 基线 | +15% | Lighthouse |
|
||||
| 类型覆盖 | 部分 | 完整 | tsc --noEmit |
|
||||
|
||||
### 文档验收
|
||||
|
||||
- [ ] CLAUDE.md 更新
|
||||
- [ ] JSON_RENDER_USAGE.md 更新
|
||||
- [ ] 迁移文档创建
|
||||
|
||||
---
|
||||
|
||||
## 风险与缓解
|
||||
|
||||
| 风险 | 概率 | 影响 | 缓解措施 |
|
||||
|------|------|------|----------|
|
||||
| useChatUI API 变化 | 低 | 高 | 保留旧代码作为回滚 |
|
||||
| MCP Token 传递失效 | 中 | 高 | 充分测试 headers 函数 |
|
||||
| 组件渲染异常 | 中 | 中 | 渐进式迁移,逐个验证 |
|
||||
| 性能回归 | 低 | 低 | 基准测试对比 |
|
||||
|
||||
---
|
||||
|
||||
## 回滚方案
|
||||
|
||||
### 快速回滚
|
||||
|
||||
```bash
|
||||
# 1. 恢复 page.tsx
|
||||
git checkout HEAD -- frontend-v2/app/page.tsx
|
||||
|
||||
# 2. 恢复 ChatMessage.tsx
|
||||
git checkout HEAD -- frontend-v2/components/ChatMessage.tsx
|
||||
|
||||
# 3. 恢复 api/chat/route.ts
|
||||
git checkout HEAD -- frontend-v2/app/api/chat/route.ts
|
||||
```
|
||||
|
||||
### 完整回滚
|
||||
|
||||
```bash
|
||||
git reset --hard HEAD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [json-render 官方文档](https://json-render.com)
|
||||
- [Vercel AI SDK 文档](https://sdk.vercel.ai)
|
||||
- [useChatUI API 参考](https://json-render.com/docs/hooks/use-chat-ui)
|
||||
- [pipeJsonRender 服务器端集成](https://json-render.com/docs/server/pipe-json-render)
|
||||
|
||||
---
|
||||
|
||||
**版本历史**:
|
||||
- v1.0 (2026-03-25): 初始规格创建 - 扩展版
|
||||
Reference in New Issue
Block a user