engineering-analysis.md 26 KB

财顾报告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 领域模型 ====================

// 报告任务
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<ChapterL1> chapterResults;
    private String overallLogic;
    private String rawOutput;
    private LocalDateTime generatedAt;
}

// 最终知识单元清单 (经确认)
public class FinalKnowledgeUnitList {
    private String taskId;
    private String version;                 // 确认版本
    private List<KnowledgeUnitNode> 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 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调用适配层

@Component
public class PythonAgentAdapter {
    
    @Autowired
    private PythonAgentClient client;
    
    // 生成一级大纲
    public OutlineL1Result generateOutlineL1(Task task, List<ChapterCandidate> 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实现

# 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 降级策略

# 模型网关降级示例
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

## 生产发布检查清单

### 配置检查
- [ ] 模型集群地址与密钥配置正确
- [ ] 行内接口地址、超时、熔断配置
- [ ] OSS桶权限与路径策略
- [ ] 租户默认配置
- [ ] 限流阈值配置

### 数据库检查  
- [ ] Flyway脚本已执行
- [ ] 索引已创建
- [ ] 租户列已添加

### 健康检查
- [ ] Java服务 /actuator/health 返回UP
- [ ] Python服务 /health 返回200
- [ ] 数据库连接正常
- [ ] Redis连接正常

### 冒烟测试
- [ ] 完整链路端到端测试通过
- [ ] 大纲生成→确认→数据准备→报告生成
- [ ] 导出功能正常
- [ ] 租户隔离验证通过

6.3 监控与告警配置

# 关键监控指标
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