分析依据:
- 《财顾报告生成智能体后端及算法端功能模块描述及其实现思路.md》
- 《财顾报告Agent-技术架构与选型.md》
- 《财顾报告智能化生成产品MVP版本需求文档.md》
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
| 模块 | 职责边界 | 禁止行为 |
|---|---|---|
| frontend | 用户界面、状态展示、表单提交 | 直接调用Python服务 |
| finrep-web | HTTP接入、参数校验、鉴权 | 业务逻辑 |
| finrep-application | 用例编排、事务控制、状态机 | 直接操作DB |
| finrep-domain | 业务规则、领域模型 | 依赖基础设施 |
| finrep-infrastructure | 技术实现、外部集成 | 包含业务逻辑 |
| Python/api | HTTP接口、参数校验 | 业务持久化 |
| Python/skills | 算法逻辑、Prompt组装 | 状态管理 |
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/
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 # 日志配置
// ==================== 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
@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);
}
# 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
)
┌─────────────────────────────────────────────────────────────────────────────┐
│ 开发里程碑规划 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 第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周: 集成测试与优化 │
│ ├── 端到端测试 │
│ ├── 性能调优 │
│ ├── 行内环境集成 │
│ └── 缺陷修复 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
| 模块 | 任务 | 负责人 | 工期 | 依赖 |
|---|---|---|---|---|
| 前端 | 项目初始化与路由配置 | 前端 | 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 | 业务输入 |
| 难点 | 风险等级 | 应对策略 |
|---|---|---|
| 模型输出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路径隔离 |
# 模型网关降级示例
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)
| 检查项 | 检查点 | 验证方式 |
|---|---|---|
| 基础连通 | 前端→Java | 任务创建API调用成功 |
| Java→Python | 健康检查接口返回200 | |
| Python→模型 | 简单Prompt能返回结果 | |
| Java→行内接口 | Mock数据能正常返回 | |
| 数据流 | 任务创建→落库 | DB中能看到任务记录 |
| 大纲生成→返回 | JSON结构符合契约 | |
| 大纲确认→持久化 | 最终知识单元清单正确保存 | |
| 数据准备→聚合 | 多源数据正确合并 | |
| 报告生成→拼接 | 完整报告段落顺序正确 | |
| 边界场景 | 大纲生成失败 | 错误提示友好,状态正确 |
| 数据获取失败 | 可继续文本补录 | |
| 单段生成失败 | 可重试或跳过 | |
| 并发任务 | 租户隔离正确,无数据串扰 |
## 生产发布检查清单
### 配置检查
- [ ] 模型集群地址与密钥配置正确
- [ ] 行内接口地址、超时、熔断配置
- [ ] OSS桶权限与路径策略
- [ ] 租户默认配置
- [ ] 限流阈值配置
### 数据库检查
- [ ] Flyway脚本已执行
- [ ] 索引已创建
- [ ] 租户列已添加
### 健康检查
- [ ] Java服务 /actuator/health 返回UP
- [ ] Python服务 /health 返回200
- [ ] 数据库连接正常
- [ ] Redis连接正常
### 冒烟测试
- [ ] 完整链路端到端测试通过
- [ ] 大纲生成→确认→数据准备→报告生成
- [ ] 导出功能正常
- [ ] 租户隔离验证通过
# 关键监控指标
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