# 一键生成研究方案 - 开发计划 > **版本**: v2.0 > **创建日期**: 2026-01-24 > **最后更新**: 2026-01-25 > **负责人**: AI Assistant > **状态**: 开发中 --- ## 一、功能概述 ### 目标 基于 Protocol Agent 收集的 5 个核心要素,一键生成完整的临床研究方案文档,支持对话式修改和 Word 导出。 ### 核心价值 - 将 5-10 小时的方案撰写工作缩短至 30 分钟 - AI 生成 + 对话式修改 + Word 精修,保证专业性和个性化 - 输出符合伦理委员会审查要求的标准文档 ### 技术策略:No-Editor First(无编辑器优先) **核心洞察**: > 用户最终会在 Word 中精修,我们的价值是 **"AI 生成高质量初稿"**,而不是 **"提供一个编辑器"**。 --- ## 二、交互设计:对话流生成 ### 用户流程 ``` 用户完成 5 阶段要素收集 ↓ 点击"一键生成研究方案" ↓ AI 在对话框中流式输出完整方案(Markdown) ↓ 用户对话修改:"把样本量部分改一下..." ↓ AI 流式输出修改后的章节 ↓ 用户满意 → 点击"导出 Word" ↓ 下载符合伦理委员会格式的 Word 文档 ``` ### 交互示意 ``` ┌─────────────────────────────────────────────────────────────┐ │ ← 返回 全流程研究方案制定 │ ├────────────────────────────────────────┬────────────────────┤ │ │ 📋 研究方案状态 │ │ [AI] 根据您确认的信息,我已生成研究方案: │ │ │ │ ✅ 科学问题 │ │ # 1. 研究题目 │ ✅ PICO要素 │ │ 糖尿病患者使用二甲双胍与格列美脲... │ ✅ 研究设计 │ │ │ ✅ 样本量 │ │ # 2. 研究背景 │ ✅ 观察指标 │ │ 2型糖尿病是全球性公共卫生问题... │ │ │ │ ──────────────── │ │ ... │ │ │ │ [📥 导出 Word] │ │ ┌────────────────────────────────┐ │ [🔄 重新生成] │ │ │ 📥 导出Word │ 🔄 修改本章节 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ [用户] 把样本量从200改成300,并说明原因 │ │ │ │ │ │ [AI] 好的,我已修改样本量部分: │ │ │ ## 6. 样本量估算 │ │ │ 根据前期预实验数据...样本量调整为300例 │ │ │ │ │ ├────────────────────────────────────────┴────────────────────┤ │ [输入消息...] [发送] │ └─────────────────────────────────────────────────────────────┘ ``` --- ## 三、研究方案结构 ```markdown # 临床研究方案 ## 1. 研究题目 ## 2. 研究背景与立题依据 ## 3. 研究目的 ## 4. 研究设计 ## 5. 研究对象(纳入/排除标准) ## 6. 样本量估算 ## 7. 研究实施步骤与技术路线 ## 8. 观察指标 ## 9. 数据管理与质量控制 ## 10. 安全性评价 ## 11. 统计分析计划 ## 12. 伦理与知情同意 ## 13. 研究时间表 ## 14. 参考文献 ``` --- ## 四、技术方案 ### 架构概览 ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 前端 │ │ Node.js │ │ Python │ │ ChatArea │ ──▶ │ Backend │ ──▶ │ Service │ │ │ │ │ │ (Pandoc) │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ 流式输出 │ 调用 LLM │ Markdown→Word │ Markdown │ 生成方案 │ 格式转换 ▼ ▼ ▼ ┌─────────────────────────────────────────────────────┐ │ 用户下载 Word │ └─────────────────────────────────────────────────────┘ ``` ### 技术栈 ``` 前端:复用现有 ChatArea + useAIStream ├── 增加"导出 Word"按钮 ├── 增加"修改本章节"交互 │ 后端 (Node.js): ├── POST /api/v1/aia/protocol-agent/generate/full # 生成完整方案 ├── POST /api/v1/aia/protocol-agent/regenerate # 重新生成指定章节 ├── POST /api/v1/aia/protocol-agent/export/docx # 导出 Word │ 后端 (Python): ├── Pandoc 集成 ├── Reference Doc 模板控制样式 ``` ### 数据模型 ```sql -- 方案生成记录表(复用现有 protocol_generations) ALTER TABLE protocol_schema.protocol_generations ADD COLUMN IF NOT EXISTS sections JSONB; -- 分章节存储,支持局部修改 -- sections 结构示例 { "title": "糖尿病患者使用二甲双胍...", "background": "2型糖尿病是全球性...", "objectives": "...", "design": "...", "subjects": "...", "sample_size": "...", "implementation": "...", "endpoints": "...", "data_management": "...", "safety": "...", "statistics": "...", "ethics": "...", "timeline": "...", "references": "..." } ``` ### API 设计 ```typescript // 生成完整方案(流式) POST /api/v1/aia/protocol-agent/generate/full Request: { conversationId: string } Response: SSE 流式输出完整 Markdown // 重新生成指定章节(流式) POST /api/v1/aia/protocol-agent/regenerate Request: { conversationId: string, section: 'sample_size' | 'background' | ..., instruction: "把样本量从200改成300" } Response: SSE 流式输出该章节 // 导出 Word POST /api/v1/aia/protocol-agent/export/docx Request: { conversationId: string } Response: Binary (application/vnd.openxmlformats-officedocument.wordprocessingml.document) // 获取当前方案内容 GET /api/v1/aia/protocol-agent/generation/:conversationId Response: { sections: {...}, fullMarkdown: "...", version: 3 } ``` --- ## 五、核心实现 ### 5.1 Python 微服务:Pandoc 转换器 **Dockerfile 增加依赖:** ```dockerfile RUN apt-get update && apt-get install -y pandoc RUN pip install pypandoc ``` **Service 代码:** ```python # python-service/app/services/doc_service.py import pypandoc import os def convert_md_to_docx(markdown_text: str, output_path: str): # 使用参考文档控制样式(字体、字号、页眉) reference_doc = os.path.join( os.path.dirname(__file__), 'assets/protocol_template.docx' ) pypandoc.convert_text( markdown_text, 'docx', format='markdown', outputfile=output_path, extra_args=[f'--reference-doc={reference_doc}'] ) return output_path ``` **API 端点:** ```python # python-service/app/routers/doc_router.py from fastapi import APIRouter, Response from ..services.doc_service import convert_md_to_docx import tempfile router = APIRouter() @router.post("/convert/docx") async def convert_to_docx(request: dict): markdown = request.get("content", "") with tempfile.NamedTemporaryFile(suffix='.docx', delete=False) as f: output_path = f.name convert_md_to_docx(markdown, output_path) with open(output_path, 'rb') as f: content = f.read() return Response( content=content, media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) ``` ### 5.2 Node.js 后端:导出 API ```typescript // backend/src/modules/agent/protocol/controllers/ProtocolGenerateController.ts export class ProtocolGenerateController { // 生成完整方案 async generateFull(request: FastifyRequest, reply: FastifyReply) { const { conversationId } = request.body as { conversationId: string }; // 获取 Protocol Context(5 阶段数据) const context = await this.contextService.getContext(conversationId); // 构建生成 Prompt const prompt = this.buildGeneratePrompt(context); // 流式生成 const streamingService = createStreamingService(reply, { onChunk: async (chunk) => { // 保存到数据库 await this.saveChunk(conversationId, chunk); } }); await streamingService.streamGenerate([ { role: 'system', content: this.getSystemPrompt() }, { role: 'user', content: prompt } ]); } // 重新生成指定章节 async regenerateSection(request: FastifyRequest, reply: FastifyReply) { const { conversationId, section, instruction } = request.body; const context = await this.contextService.getContext(conversationId); const currentGeneration = await this.getGeneration(conversationId); const prompt = ` 请根据以下指令修改"${section}"章节: 用户指令:${instruction} 当前章节内容: ${currentGeneration.sections[section]} 研究背景信息: ${JSON.stringify(context)} 请输出修改后的完整章节内容(Markdown 格式): `; // 流式输出修改后的章节 const streamingService = createStreamingService(reply); await streamingService.streamGenerate([ { role: 'system', content: '你是临床研究方案撰写专家...' }, { role: 'user', content: prompt } ]); } // 导出 Word async exportDocx(request: FastifyRequest, reply: FastifyReply) { const { conversationId } = request.body as { conversationId: string }; // 获取完整 Markdown const generation = await this.getGeneration(conversationId); const markdown = this.sectionsToMarkdown(generation.sections); // 调用 Python 微服务转换 const response = await axios.post( `${PYTHON_SERVICE_URL}/convert/docx`, { content: markdown }, { responseType: 'arraybuffer' } ); reply.header('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); reply.header('Content-Disposition', 'attachment; filename="research_protocol.docx"'); return reply.send(response.data); } } ``` ### 5.3 前端:ChatArea 增强 ```tsx // frontend-v2/src/modules/aia/protocol-agent/components/ChatArea.tsx // 在消息气泡中增加导出按钮 const ProtocolMessageActions = ({ content, conversationId }) => { const [exporting, setExporting] = useState(false); const handleExport = async () => { setExporting(true); try { const response = await fetch('/api/v1/aia/protocol-agent/export/docx', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ conversationId }) }); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '研究方案.docx'; a.click(); } finally { setExporting(false); } }; return (
); }; ``` --- ## 六、开发计划 ### Phase 1:MVP 核心功能(2 天) | 天数 | 任务 | 交付物 | |------|------|--------| | Day 1 | Python 微服务集成 Pandoc | `/convert/docx` API 可用 | | Day 1 | Node.js 导出 API | `/export/docx` 端点完成 | | Day 2 | 前端导出按钮 | ChatArea 增加导出功能 | | Day 2 | 完整方案生成 Prompt | 生成质量优化 | **Phase 1 交付**: - ✅ 一键生成完整研究方案(Markdown) - ✅ 导出符合格式的 Word 文档 - ✅ 基础对话式修改 ### Phase 2:分章节修改(2 天) | 天数 | 任务 | 交付物 | |------|------|--------| | Day 3 | 分章节存储模型 | sections JSONB 字段 | | Day 3 | 章节重新生成 API | `/regenerate` 端点 | | Day 4 | 前端章节选择器 | 点击章节触发修改对话 | | Day 4 | 版本历史 | 修改记录存储 | **Phase 2 交付**: - ✅ 分章节存储和修改 - ✅ 智能识别修改章节 - ✅ 版本历史追踪 ### Phase 3:体验优化(1 天) | 天数 | 任务 | 交付物 | |------|------|--------| | Day 5 | Word 模板优化 | 符合伦理委员会格式 | | Day 5 | UI 美化 | 导出进度、预览 | | Day 5 | 测试与修复 | 完整功能测试 | --- ## 七、与编辑器方案对比 | 维度 | 无编辑器方案(当前) | 编辑器方案(备选) | |------|---------------------|-------------------| | **开发周期** | 5 天 | 10 天 | | **维护成本** | 低(复用现有组件) | 高(Fork Novel) | | **格式控制** | ⭐⭐⭐⭐⭐ Pandoc 精确控制 | ⭐⭐⭐ 需自己处理 | | **修改体验** | 对话式(稍慢) | 直接编辑(更快) | | **用户习惯** | 符合(Word 精修) | 需适应新界面 | | **适用场景** | MVP / 快速验证 | 高频编辑场景 | ### 何时考虑上编辑器? 如果用户反馈以下问题,再考虑引入编辑器: 1. "对话修改太慢,我想直接改某个字" 2. "我需要频繁调整段落顺序" 3. "我想同时看到多个章节并对比" --- ## 八、验收标准 ### 功能验收 - [ ] 点击"一键生成",对话框流式输出完整方案 - [ ] 点击"导出 Word",下载格式正确的 docx 文件 - [ ] 输入"修改样本量",AI 只重新生成该章节 - [ ] Word 文档符合伦理委员会格式要求 ### 性能指标 | 指标 | 目标 | |------|------| | 完整方案生成时间 | < 2 分钟 | | Word 导出时间 | < 5 秒 | | 章节修改响应时间 | < 30 秒 | --- ## 九、Word 模板设计 ### 格式要求(伦理委员会标准) ``` 字体:正文宋体小四,标题黑体三号 行距:1.5 倍 页边距:上下 2.54cm,左右 3.17cm 页眉:研究方案 + 版本号 页脚:页码 ``` ### Reference Doc 制作 1. 在 Word 中创建符合格式的模板文档 2. 定义样式:标题1、标题2、正文、表格等 3. 保存为 `protocol_template.docx` 4. 放置到 `python-service/app/services/assets/` --- ## 十、后续迭代 ### v1.1:编辑器增强(可选) 如果用户反馈需要更直接的编辑体验: - 引入 Novel/Tiptap 编辑器 - 支持实时编辑 + AI 辅助 ### v1.2:模板库 - 不同研究类型的方案模板 - RCT、队列研究、病例对照等 ### v1.3:协作与审核 - 多人协作编辑 - 方案审核流程 - 与伦理系统对接 --- ## 十一、参考文档 - [基于对话流的文档生成技术方案](./基于对话流的文档生成与导出技术方案.md) - [编辑器选型深度评估](./编辑器选型深度评估与落地建议.md)(备选方案) - [Novel vs BlockNote 对比分析](./Novel_vs_BlockNote_深度对比分析.md)(备选方案) --- **文档更新记录**: - 2026-01-24 v1.0: 初始版本(技术选型:Tiptap/BlockNote) - 2026-01-24 v1.1: 技术选型改为 Novel (Fork) - 2026-01-25 v2.0: **重大调整:采用无编辑器方案**,优先实现对话流生成 + Word 导出