- 修复前端 componentsPrompt 与后端 availableComponents 字段名不匹配问题
- 清理 conversation_manager.py 中多余的工具指南 (NOVEL_TOOLS_GUIDE, NO_TOOLS_GUIDE)
- 前端统一使用 catalog.prompt({ mode: inline }) 生成组件系统提示
- 后端直接使用前端传来的 componentsPrompt,不再添加额外内容
- 添加 log_error 函数到 debug_logger.py
- 在 app_fastapi.py 所有 except 块中添加 log_error 调用
- 添加 quick-spec-json-render-system-prompt.md 规格文档
Co-Authored-By: Claude <noreply@anthropic.com>
5.0 KiB
5.0 KiB
title, slug, created, status, stepsCompleted, tech_stack, files_modified
| title | slug | created | status | stepsCompleted | tech_stack | files_modified | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| json-render 系统提示统一化 | json-render-system-prompt-unification | 2026-03-20 | completed |
|
|
|
Tech-Spec: json-render 系统提示统一化
Created: 2026-03-20 Completed: 2026-03-20
最终架构
┌─────────────────────────────────────────────────────────┐
│ 前端 │
│ catalog.prompt({ mode: 'inline' }) │
│ → json-render 组件完整说明 (12547 chars) │
│ → 通过 componentsPrompt 字段发送 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 后端 │
│ BASE_SYSTEM_PROMPT (角色 + MCP 状态) │
│ + components_prompt (前端传来的组件说明) │
│ = 完整 system prompt │
└─────────────────────────────────────────────────────────┘
验证结果 (2026-03-20)
后端日志确认
[DEBUG /api/chat/stream] components_prompt: 12547 chars
[DEBUG /api/chat/stream] enabled_mcp_list: ['novel-translator', 'novel-platform-user', 'novel-platform-admin', 'template-241-mcp-app']
前端传来的 componentsPrompt 内容预览
You are a UI generator that outputs JSON.
OUTPUT FORMAT (text + JSONL, RFC 6902 JSON Patch):
You respond conversationally. When generating UI, first write a brief explanation (1-3 sentences), then output JSONL patch lines wrapped in a \`\`\`spec code fence.
The JSONL lines use RFC 6902 JSON Patch operations to build a UI tree...
实施记录
已删除的后端冗余代码
| 删除项 | 原因 |
|---|---|
| `NOVEL_TOOLS_GUIDE` | 引用了不存在的 `novel-detail` 组件,与 catalog 不一致 |
| `NO_TOOLS_GUIDE` | 冗余,AI 可以自己探索工具 |
| `_build_system_prompt()` 中的 `mcp_tools_guide` 逻辑 | 简化后端,让 AI 自己决定 |
简化后的 `_build_system_prompt()` 方法
def _build_system_prompt(self) -> str:
"""构建完整的 system prompt"""
# 构建 MCP 状态部分
if self.enabled_mcp_list is not None and len(self.enabled_mcp_list) == 0:
mcp_status = """当前没有启用任何 MCP 服务器。你只能进行普通对话和返回 json-render 组件。"""
elif self.enabled_mcp_list:
enabled_names = ", ".join(self.enabled_mcp_list)
mcp_status = f"""**已启用的 MCP 服务器**: {enabled_names}
你可以调用这些 MCP 服务器的工具来帮助用户完成任务。"""
else:
mcp_status = """你可以通过调用 MCP 工具来帮助用户完成任务。"""
# 替换占位符并添加组件列表
prompt = BASE_SYSTEM_PROMPT.replace("{MCP_STATUS}", mcp_status)
if self.components_prompt:
return prompt + "\n\n" + self.components_prompt
else:
return prompt
简化后的 `BASE_SYSTEM_PROMPT`
BASE_SYSTEM_PROMPT = """你是一个 AI 助手,可以通过调用 MCP 工具来帮助用户完成任务。
## 当前状态
{MCP_STATUS}
"""
核心原则
- 单一来源: 组件格式由前端 `catalog.prompt({ mode: 'inline' })` 统一定义
- 后端精简: 后端只提供基础角色定义 + MCP 状态
- AI 自主: AI 自己决定用什么工具、返回什么组件
Catalog 组件列表
前端 `catalog.ts` 注册的组件(17 个):
| 组件 | 用途 |
|---|---|
| `card` | 卡片容器组件 |
| `stack` | 布局容器组件 |
| `heading` | 标题组件 |
| `text` | 文本组件 |
| `button` | 按钮组件 |
| `badge` | 徽章组件 |
| `separator` | 分隔线组件 |
| `input` | 输入框组件 |
| `text-area` | 多行文本输入组件 |
| `data-table` | 数据表格组件 |
| `translation-result` | 翻译结果展示组件 |
| `novel-list` | 小说列表组件 |
| `chapter-reader` | 章节阅读器组件 |
| `code-block` | 代码块组件 |
| `tool-call` | MCP 工具调用状态组件 |
| `login-panel` | MCP 登录面板组件 |
| `mcp-status` | MCP 服务器状态组件 |
| `suggestion-buttons` | 建议按钮组组件 |
注意: 没有 `novel-detail` 组件!后端旧代码引用的是不存在的组件。