# 财顾报告Agent MVP 工程实现分析文档 > 分析依据: > - 《财顾报告生成智能体后端及算法端功能模块描述及其实现思路.md》 > - 《财顾报告Agent-技术架构与选型.md》 > - 《财顾报告智能化生成产品MVP版本需求文档.md》 --- ## 1. 实施范围与代码边界 ### 1.1 代码仓库结构 ``` finrep-report/ # 统一代码目录 ├── frontend/ # Web前端 (React 18+) │ ├── src/ │ │ ├── pages/ # 页面组件 │ │ │ ├── TaskCreate/ # 任务创建 │ │ │ ├── OutlineConfirm/ # 大纲确认 │ │ │ ├── DataPrepare/ # 数据准备 │ │ │ └── ReportView/ # 报告查看 │ │ ├── components/ # 公共组件 │ │ │ ├── OutlineTree/ # 大纲树组件 │ │ │ ├── DataDisplay/ # 数据展示 │ │ │ └── ProgressBar/ # 进度条 │ │ ├── services/ # API服务 │ │ └── utils/ # 工具函数 │ ├── public/ │ └── package.json │ ├── backend/ # Java业务后端 (Spring Boot 3) │ ├── finrep-web/ # Web接入层 │ ├── finrep-application/ # 应用服务层 │ │ ├── orchestration/ # 任务编排 │ │ ├── hitl/ # 人工卡点 │ │ └── service/ # 领域服务 │ ├── finrep-domain/ # 领域层 │ │ ├── model/ # 领域模型 │ │ └── repository/ # 仓库接口 │ ├── finrep-infrastructure/ # 基础设施层 │ │ ├── persistence/ # 持久化 │ │ ├── integration/ # 外部集成 │ │ │ ├── pythonagent/ # Python算法适配 │ │ │ ├── datasource/ # 行内数据源 │ │ │ └── oss/ # OSS集成 │ │ └── config/ # 配置 │ ├── finrep-contract/ # 契约定义 (DTO/API) │ └── pom.xml │ └── algo/ # Python算法服务 (FastAPI) ├── src/finrep_algo_agent/ │ ├── api/ # API路由 │ │ ├── outline.py # 大纲接口 │ │ └── section.py # 段落接口 │ ├── skills/ # 技能实现 │ │ ├── outline_l1.py # 一级大纲生成 │ │ ├── outline_l2.py # 二级大纲生成 │ │ └── section_gen.py # 段落生成 │ ├── llm/ # LLM相关 │ │ ├── model_wrapper.py # 模型网关 │ │ └── router.py # 多模型路由 │ ├── rag/ # RAG检索 │ │ ├── parser.py # 文档解析 │ │ ├── indexer.py # 索引构建 │ │ └── retriever.py # 检索器 │ ├── prompts/ # 提示词模板 │ │ ├── templates/ # Jinja模板 │ │ └── builders.py # Prompt构建器 │ ├── models/ # 数据模型 (Pydantic) │ └── core/ # 核心配置 ├── tests/ ├── requirements.txt └── Dockerfile ``` ### 1.2 模块职责边界 | 模块 | 职责边界 | 禁止行为 | |------|----------|----------| | frontend | 用户界面、状态展示、表单提交 | 直接调用Python服务 | | finrep-web | HTTP接入、参数校验、鉴权 | 业务逻辑 | | finrep-application | 用例编排、事务控制、状态机 | 直接操作DB | | finrep-domain | 业务规则、领域模型 | 依赖基础设施 | | finrep-infrastructure | 技术实现、外部集成 | 包含业务逻辑 | | Python/api | HTTP接口、参数校验 | 业务持久化 | | Python/skills | 算法逻辑、Prompt组装 | 状态管理 | --- ## 2. 模块拆分与目录建议 ### 2.1 Java后端模块详细拆分 ``` finrep-web/src/main/java/com/yuxin/finrep/web/ ├── controller/ # 控制器层 │ ├── TaskController.java # 任务管理 │ ├── OutlineController.java # 大纲生成与确认 │ ├── DataController.java # 数据准备 │ └── ReportController.java # 报告生成与导出 ├── dto/ # 请求/响应DTO │ ├── request/ │ └── response/ ├── filter/ # 过滤器 │ ├── AuthFilter.java # 认证 │ ├── TenantFilter.java # 租户注入 │ └── AuditFilter.java # 审计 └── exception/ # 全局异常处理 finrep-application/src/main/java/com/yuxin/finrep/application/ ├── orchestration/ # 任务编排 │ ├── TaskOrchestrator.java # 任务编排器 │ ├── TaskStateMachine.java # 状态机 │ └── StageHandler.java # 阶段处理器 ├── hitl/ # 人工卡点 │ ├── OutlineConfirmationService.java # 大纲确认 │ └── DataConfirmationService.java # 数据确认 ├── service/ # 领域服务 │ ├── TaskService.java │ ├── OutlineService.java │ └── ReportService.java └── event/ # 领域事件 finrep-infrastructure/src/main/java/com/yuxin/finrep/infrastructure/ ├── persistence/ # 持久化 │ ├── mybatis/mapper/ │ └── entity/ ├── integration/ │ ├── pythonagent/ # Python算法适配 │ │ ├── PythonAgentClient.java │ │ ├── PythonAgentAdapter.java │ │ └── dto/ │ ├── datasource/ # 行内数据源 │ │ ├── BusinessDataClient.java # 工商 │ │ ├── RiskDataClient.java # 风险 │ │ └── MetricPlatformClient.java # 指标平台 │ └── oss/ # OSS │ └── OssClient.java └── config/ ``` ### 2.2 Python算法模块详细拆分 ``` src/finrep_algo_agent/ ├── api/ │ ├── __init__.py │ ├── deps.py # 依赖注入 │ ├── outline.py # 大纲路由 │ │ ├── generate_l1 # POST /v1/outline/l1 │ │ └── generate_l2 # POST /v1/outline/l2 │ └── section.py # 段落路由 │ └── generate # POST /v1/section ├── skills/ │ ├── __init__.py │ ├── outline_l1.py # 一级大纲Skill │ ├── outline_l2.py # 二级大纲Skill │ ├── section_gen.py # 段落生成Skill │ └── base.py # Skill基类 ├── llm/ │ ├── __init__.py │ ├── model_wrapper.py # 模型网关MW │ ├── router.py # 多模型路由 │ ├── retry.py # 重试机制 │ └── schemas.py # 输出Schema ├── rag/ │ ├── __init__.py │ ├── parser.py # 文档解析 │ ├── indexer.py # 索引管理 │ ├── retriever.py # 检索器 │ └── chunker.py # 分块策略 ├── prompts/ │ ├── templates/ # Jinja2模板 │ │ ├── outline_l1.jinja2 │ │ ├── outline_l2.jinja2 │ │ ├── section_info.jinja2 # 信息陈述型 │ │ ├── section_analysis.jinja2 # 对象分析型 │ │ ├── section_metric.jinja2 # 指标数据描述型 │ │ └── section_judgment.jinja2 # 综合判断型 │ └── builders.py # Prompt构建器 ├── models/ │ ├── __init__.py │ ├── outline.py # 大纲模型 │ ├── section.py # 段落模型 │ └── common.py # 通用模型 └── core/ ├── config.py # 配置管理 ├── exceptions.py # 异常定义 └── logging.py # 日志配置 ``` --- ## 3. 接口/模型实现要点 ### 3.1 核心数据模型 ```java // ==================== Java 领域模型 ==================== // 报告任务 public class ReportTask { private String taskId; private String tenantId; private ReportType reportType; // 报告类型 private TaskStatus status; // 任务状态 private TaskInput input; // 任务输入 private LocalDateTime createdAt; private LocalDateTime updatedAt; } // 任务状态枚举 (与需求文档一致) public enum TaskStatus { PENDING_OUTLINE, // 待生成大纲 OUTLINE_CONFIRMING, // 待确认大纲 PENDING_DATA_PREPARE, // 待准备数据 DATA_CONFIRMING, // 待确认数据 PENDING_GENERATE, // 待生成报告 GENERATING, // 报告生成中 COMPLETED, // 待查看结果 FINISHED, // 已完成 FAILED // 执行失败 } // 一级大纲结果 public class OutlineL1Result { private String taskId; private List chapterResults; private String overallLogic; private String rawOutput; private LocalDateTime generatedAt; } // 最终知识单元清单 (经确认) public class FinalKnowledgeUnitList { private String taskId; private String version; // 确认版本 private List nodes; // 树状节点 private String confirmedBy; private LocalDateTime confirmedAt; } // 知识单元节点 public class KnowledgeUnitNode { private String nodeId; private String nodeName; private String nodeNo; // 章节编号 private Integer nodeLevel; private String parentNodeId; private String sourceType; // single/batch private Boolean modelSelected; // 模型默认选中 private Boolean manualAdjusted; // 是否人工调整 } // 知识单元数据包 public class KnowledgeUnitDataPackage { private String taskId; private String knowledgeUnitId; private JsonNode autoData; // 自动获取结果 private String manualSupplement; // 人工补录 private JsonNode finalData; // 合并后最终数据 private DataStatus status; } // 单段生成结果 public class SectionResult { private String taskId; private String knowledgeUnitId; private String prompt; // 实际使用的prompt private String generatedText; // 生成内容 private TokenUsage usage; private LocalDateTime generatedAt; } ``` ```python # ==================== Python Pydantic 模型 ==================== class OutlineL1Request(BaseModel): """一级大纲生成请求""" task_id: str tenant_id: str report_type: str agreement_amount: Decimal enterprise_type: str group_business_segments: List[str] industry_type: str has_independent_report: bool independent_report_types: List[str] candidate_financing_tools: List[str] recommended_financing_tools: List[str] other_requirements: Optional[str] chapter_candidates: List[ChapterCandidate] class ChapterL1Result(BaseModel): """一级章节结果""" chapter_id: str chapter_name: str paragraph_count_enum: str # P0/P1/P2/P3/P4 reason: str class OutlineL1Response(BaseModel): """一级大纲生成响应""" chapter_results: List[ChapterL1Result] overall_logic: str class SectionRequest(BaseModel): """段落生成请求""" task_id: str tenant_id: str knowledge_unit_id: str report_type: str template_type: str # info/analysis/metric/judgment paragraph_logic: str paragraph_position: str overall_logic: str chapter_logic: str task_input: Dict[str, Any] data_package: Dict[str, Any] class SectionResponse(BaseModel): """段落生成响应""" generated_text: str prompt_tokens: int completion_tokens: int ``` ### 3.2 关键接口实现要点 #### Java侧:Python调用适配层 ```java @Component public class PythonAgentAdapter { @Autowired private PythonAgentClient client; // 生成一级大纲 public OutlineL1Result generateOutlineL1(Task task, List candidates) { OutlineL1Request request = buildL1Request(task, candidates); // 调用Python服务,超时120秒 OutlineL1Response response = client.callOutlineL1(request, Duration.ofSeconds(120)); // 校验响应完整性 validateL1Response(response); return convertToL1Result(response); } // 生成段落 (逐段调用) public SectionResult generateSection(Task task, KnowledgeUnit ku, DataPackage data) { SectionRequest request = buildSectionRequest(task, ku, data); // 单段生成超时30秒 SectionResponse response = client.callSection(request, Duration.ofSeconds(30)); return convertToSectionResult(response); } } // Python客户端 (Resilience4j熔断) @FeignClient( name = "python-agent", url = "${python.agent.url}", configuration = PythonClientConfig.class ) public interface PythonAgentClient { @PostMapping("/v1/outline/l1") OutlineL1Response callOutlineL1(@RequestBody OutlineL1Request request); @PostMapping("/v1/outline/l2") OutlineL2Response callOutlineL2(@RequestBody OutlineL2Request request); @PostMapping("/v1/section") SectionResponse callSection(@RequestBody SectionRequest request); } ``` #### Python侧:Skill实现 ```python # skills/outline_l1.py class OutlineL1Skill: """一级大纲生成Skill""" def __init__(self, model_wrapper: ModelWrapper, prompt_builder: PromptBuilder): self.model = model_wrapper self.prompt_builder = prompt_builder async def execute(self, request: OutlineL1Request) -> OutlineL1Response: # 构建Prompt prompt = self.prompt_builder.build_outline_l1_prompt( report_type=request.report_type, agreement_amount=request.agreement_amount, chapter_candidates=request.chapter_candidates, # ... 其他参数 ) # 调用模型 response_text = await self.model.generate( prompt=prompt, temperature=0.3, # 低温度,提高稳定性 response_format={"type": "json_object"} # 强制JSON输出 ) # 解析并校验 try: data = json.loads(response_text) validated = OutlineL1Response(**data) # Pydantic校验 return validated except (json.JSONDecodeError, ValidationError) as e: # 解析失败,触发重试或返回错误 raise OutlineParseError(f"Failed to parse outline: {e}") # skills/section_gen.py class SectionGenerationSkill: """段落生成Skill""" async def execute(self, request: SectionRequest) -> SectionResponse: # 根据模板类型选择Prompt模板 template = self.get_template(request.template_type) # 构建完整Prompt prompt = template.render( report_type=request.report_type, overall_logic=request.overall_logic, chapter_logic=request.chapter_logic, paragraph_logic=request.paragraph_logic, task_input=request.task_input, data_package=request.data_package ) # 调用模型生成 response = await self.model.generate(prompt=prompt) return SectionResponse( generated_text=response.text, prompt_tokens=response.usage.prompt_tokens, completion_tokens=response.usage.completion_tokens ) ``` --- ## 4. 任务拆分与里程碑 ### 4.1 开发阶段划分 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 开发里程碑规划 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ 第1周: 基础设施搭建 │ │ ├── [前端] 项目初始化,路由配置,基础组件 │ │ ├── [Java] 多模块项目搭建,数据库设计,CI/CD │ │ ├── [Python] FastAPI项目搭建,模型网关MW初版 │ │ └── [联调] 打通前后端、Java-Python基础调用 │ │ │ │ 第2-3周: 核心链路开发 │ │ ├── [前端] 任务创建页,大纲确认树组件,数据展示页 │ │ ├── [Java] 任务管理,状态机,大纲确认持久化 │ │ ├── [Python] 大纲生成Skills(L1/L2),段落生成Skill │ │ ├── [Java] 行内数据源集成(工商/指标) │ │ └── [Python] RAG基础能力(解析/索引/检索) │ │ │ │ 第4周: 报告生成与导出 │ │ ├── [前端] 报告查看页,导出功能 │ │ ├── [Java] 逐段生成编排,报告拼接,DOCX导出 │ │ ├── [Python] 四类Prompt模板完善,模型路由优化 │ │ └── [集成] 完整链路联调 │ │ │ │ 第5周: 集成测试与优化 │ │ ├── 端到端测试 │ │ ├── 性能调优 │ │ ├── 行内环境集成 │ │ └── 缺陷修复 │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### 4.2 详细任务清单 | 模块 | 任务 | 负责人 | 工期 | 依赖 | |------|------|--------|------|------| | **前端** | 项目初始化与路由配置 | 前端 | 1d | - | | | 任务创建页面 | 前端 | 2d | API契约 | | | 大纲树组件(展示/勾选/排序) | 前端 | 3d | API契约 | | | 数据准备展示页面 | 前端 | 2d | API契约 | | | 报告查看与导出页面 | 前端 | 2d | API契约 | | | SSE进度推送集成 | 前端 | 1d | 后端SSE | | **Java** | 多模块项目搭建 | 后端 | 1d | - | | | 数据库设计与Flyway脚本 | 后端 | 2d | - | | | 任务管理API | 后端 | 2d | DB | | | 状态机实现 | 后端 | 2d | - | | | 大纲确认持久化 | 后端 | 2d | DB | | | Python适配层(ADAPTER) | 后端 | 2d | Python服务 | | | 行内数据源集成 | 后端 | 3d | 接口文档 | | | 报告生成编排 | 后端 | 2d | Python适配 | | | DOCX导出 | 后端 | 2d | - | | **Python** | FastAPI项目搭建 | 算法 | 1d | - | | | 模型网关MW | 算法 | 2d | 模型访问权限 | | | L1大纲生成Skill | 算法 | 2d | Prompt模板 | | | L2大纲生成Skill | 算法 | 2d | Prompt模板 | | | 段落生成Skill | 算法 | 2d | Prompt模板 | | | RAG解析/索引 | 算法 | 2d | 向量库 | | | RAG检索 | 算法 | 1d | 向量库 | | | 四类Prompt模板 | 算法 | 3d | 业务输入 | --- ## 5. 关键技术难点与规避策略 ### 5.1 难点清单与应对 | 难点 | 风险等级 | 应对策略 | |------|----------|----------| | **模型输出JSON解析失败** | 高 | 1. 强制JSON输出格式
2. Pydantic服务端校验
3. 失败时重试(最多3次)
4. 仍失败则返回明确错误,人工介入 | | **大纲树状结构展示性能** | 中 | 1. 虚拟滚动(大量节点时)
2. 后端返回扁平结构,前端组装树
3. 懒加载子节点 | | **多数据源数据格式不统一** | 中 | 1. 每个数据源独立适配器
2. 转换为知识单元数据包统一格式
3. 前端只展示文本,不编辑结构化数据 | | **段落间风格不一致** | 中 | 1. 整篇报告撰写逻辑贯穿各段落Prompt
2. 当前章节撰写逻辑保持一致
3. 统一系统角色定义 | | **长文本RAG召回质量** | 中 | 1. 按章节/段落切分
2. 带metadata(文件名/页码)
3. Top-K重排序 | | **模型调用超时** | 中 | 1. 分级超时配置(大纲120s/段落30s)
2. 异步化+进度推送
3. 可中断重试 | | **租户数据隔离** | 高 | 1. ORM层拦截注入tenant_id
2. 所有查询强制带租户条件
3. OSS路径隔离 | ### 5.2 降级策略 ```python # 模型网关降级示例 class ModelRouter: async def generate_with_fallback(self, prompt: str, primary_model: str) -> str: try: # 首选模型 return await self.call_model(primary_model, prompt) except ModelTimeoutError: logger.warning(f"Primary model {primary_model} timeout, trying fallback") # 降级到备用模型 return await self.call_model(self.fallback_model, prompt) except ModelRateLimitError: # 指数退避重试 await asyncio.sleep(self.backoff_time) return await self.generate_with_fallback(prompt, primary_model) ``` --- ## 6. 联调与发布注意事项 ### 6.1 联调检查清单 | 检查项 | 检查点 | 验证方式 | |--------|--------|----------| | **基础连通** | 前端→Java | 任务创建API调用成功 | | | Java→Python | 健康检查接口返回200 | | | Python→模型 | 简单Prompt能返回结果 | | | Java→行内接口 | Mock数据能正常返回 | | **数据流** | 任务创建→落库 | DB中能看到任务记录 | | | 大纲生成→返回 | JSON结构符合契约 | | | 大纲确认→持久化 | 最终知识单元清单正确保存 | | | 数据准备→聚合 | 多源数据正确合并 | | | 报告生成→拼接 | 完整报告段落顺序正确 | | **边界场景** | 大纲生成失败 | 错误提示友好,状态正确 | | | 数据获取失败 | 可继续文本补录 | | | 单段生成失败 | 可重试或跳过 | | | 并发任务 | 租户隔离正确,无数据串扰 | ### 6.2 发布 checklist ```markdown ## 生产发布检查清单 ### 配置检查 - [ ] 模型集群地址与密钥配置正确 - [ ] 行内接口地址、超时、熔断配置 - [ ] OSS桶权限与路径策略 - [ ] 租户默认配置 - [ ] 限流阈值配置 ### 数据库检查 - [ ] Flyway脚本已执行 - [ ] 索引已创建 - [ ] 租户列已添加 ### 健康检查 - [ ] Java服务 /actuator/health 返回UP - [ ] Python服务 /health 返回200 - [ ] 数据库连接正常 - [ ] Redis连接正常 ### 冒烟测试 - [ ] 完整链路端到端测试通过 - [ ] 大纲生成→确认→数据准备→报告生成 - [ ] 导出功能正常 - [ ] 租户隔离验证通过 ``` ### 6.3 监控与告警配置 ```yaml # 关键监控指标 metrics: java: - http_requests_total # HTTP请求总量 - http_request_duration_seconds # 请求延迟 - task_stage_duration_seconds # 各阶段耗时 - python_client_calls_total # Python调用次数 - python_client_errors_total # Python调用错误 python: - llm_requests_total # LLM调用次数 - llm_request_duration_seconds # LLM延迟 - llm_tokens_total # Token消耗 - rag_retrieve_latency # RAG检索延迟 # 告警规则 alerts: - name: HighErrorRate condition: error_rate > 5% for 5m severity: critical - name: LLMLatencyHigh condition: llm_p99 > 60s for 10m severity: warning - name: TaskStuck condition: task_in_stage > 30m severity: warning ``` --- *文档版本:MVP阶段* *最后更新:2026-03-31*