1. 项目概述
在最近结束的公司年报智能问答系统挑战赛中,我们团队开发了一套基于RAG(检索增强生成)技术的解决方案,成功在2.5小时内完成了100份公司年报的解析和问答任务。这个系统不仅准确回答了各类财务问题,还能提供精确的页码引用作为证据支持。
1.1 核心需求解析
比赛的核心挑战在于:
- 处理海量PDF文档(每份最长1000页)
- 快速构建可查询的知识库
- 确保答案准确且有据可查
- 应对各种财务数据格式(数值、名称、列表等)
我们的解决方案最终在准确率和效率上都取得了优异成绩,关键在于以下几个创新点:
- 双路由器系统实现精准查询分发
- LLM重排序提升检索质量
- 结构化输出保证答案格式规范
- 思维链技术增强推理能力
2. 技术架构详解
2.1 系统整体流程

整个系统的工作流程可分为六个关键阶段:
- 文档解析:将PDF转换为结构化文本
- 数据摄取:构建向量数据库
- 检索增强:多级检索与重排序
- 查询路由:智能分发问题到对应处理模块
- 答案生成:基于检索内容生成准确回答
- 结果验证:确保答案格式和内容正确
2.2 核心技术组件
2.2.1 文档解析引擎
我们选择了Docling作为基础解析器,并进行了深度优化:
- 重写了表格处理模块,保留原始结构
- 添加了Markdown/HTML输出支持
- 实现了GPU加速解析
python复制# 示例:优化后的解析代码片段
def parse_pdf(file_path):
# 初始化解析器
parser = DoclingParser(
table_mode="detailed",
format_output="markdown",
gpu_acceleration=True
)
# 执行解析
result = parser.parse(file_path)
# 后处理
cleaned_result = post_process(result)
return cleaned_result
2.2.2 向量数据库架构
我们为每份年报创建独立的FAISS索引:
- 使用text-embedding-3-large生成嵌入
- 采用Flat索引保证搜索精度
- 分块策略:300token/块,50token重叠
重要提示:独立数据库设计使搜索空间缩小100倍,大幅提升效率
3. 核心技术创新点
3.1 多路由器系统
3.1.1 数据库路由器

通过简单的正则匹配,将问题路由到对应公司的数据库:
python复制def route_to_database(question, company_names):
for name in company_names:
if re.search(r'\b'+re.escape(name)+r'\b', question, re.I):
return get_database(name)
return None
3.1.2 提示词路由器
根据问题类型选择最适合的提示模板:
| 问题类型 | 处理方式 | 适用提示词 |
|---|---|---|
| 数值问题 | 严格校验单位/格式 | 数字型模板 |
| 名称问题 | 精确匹配原文 | 名称型模板 |
| 列表问题 | 聚合多个结果 | 列表型模板 |
| 比较问题 | 分解为子查询 | 比较型模板 |
3.2 LLM重排序技术
传统向量检索的Top N结果可能包含不相关文档。我们的解决方案:
- 先用向量搜索获取30个候选块
- 提取对应的完整页面
- 使用GPT-4o-mini进行相关性评分
- 按加权分数(向量0.3 + LLM0.7)重新排序
python复制# 重排序提示词设计
rerank_prompt = """
请评估以下文本与问题的相关性:
问题:{question}
文本:{text}
请从0-1打分,并说明理由:
1. 0=完全不相关
2. 0.3=略微相关
3. 0.7=高度相关
4. 1=完美匹配
以JSON格式返回:
{{
"reasoning": "分析理由",
"score": 0.5
}}
"""
3.3 结构化输出与思维链
我们设计了严格的输出schema确保答案质量:
python复制class AnswerSchema(BaseModel):
step_by_step_analysis: str = Field(
description="详细的推理过程"
)
reasoning_summary: str = Field(
description="推理结论摘要"
)
relevant_pages: List[int] = Field(
description="引用的页码"
)
final_answer: Union[str, int, float, bool] = Field(
description="格式化后的最终答案"
)
典型生成过程示例:
- 模型先进行逐步分析
- 然后提炼关键推理点
- 最后生成符合要求的简洁答案
4. 关键实现细节
4.1 表格处理优化
财务报告中的大型表格是主要挑战之一。我们的解决方案:
- HTML转换:将PDF表格转为HTML保留结构
- LLM序列化:拆解为属性-值对
- 双重存储:保留原始表格和序列化版本
python复制# 表格序列化提示词
serialize_prompt = """
将以下HTML表格转换为独立的陈述句:
{table_html}
要求:
1. 每个数据点生成一个独立语句
2. 包含完整上下文
3. 保留原始数值和单位
输出格式:
- 指标名称: 值 (时间范围/条件)
"""
# 示例输出:
# "2021年股东权益为577,782百万日元"
4.2 检索优化技巧
- 父文档检索:先找相关片段,再返回完整页面
- 混合检索:结合语义搜索和关键词匹配
- 分面检索:对不同内容类型采用不同策略
实战经验:父文档检索使准确率提升15%,因为财务信息通常需要完整上下文
4.3 提示工程实践
我们采用模块化提示设计:
python复制# prompts.py
SYSTEM_INSTRUCTIONS = {
"numeric": "当处理数值问题时...",
"name": "当处理名称问题时...",
"list": "当处理列表问题时...",
"comparison": "当处理比较问题时..."
}
EXAMPLES = {
"numeric": [{"question": "...", "answer": "..."}],
"name": [...]
}
def build_prompt(q_type, question, context):
return f"""
{SYSTEM_INSTRUCTIONS[q_type]}
示例:
Q: {EXAMPLES[q_type][0]['question']}
A: {EXAMPLES[q_type][0]['answer']}
现在请回答:
上下文:{context}
问题:{question}
"""
5. 性能优化方案
5.1 解析加速
- GPU加速:使用RTX 4090虚拟机
- 并行处理:多文档同时解析
- 缓存机制:避免重复处理
5.2 检索优化
| 优化措施 | 效果提升 | 实现难度 |
|---|---|---|
| LLM重排序 | +25%准确率 | 中 |
| 查询扩展 | +10%召回率 | 低 |
| 子问题分解 | +15%复杂问题准确率 | 高 |
5.3 成本控制
- 小型模型优先:GPT-4o-mini为主
- 批量处理:多个问题一次API调用
- 缓存结果:相同问题直接返回
6. 实战经验分享
6.1 常见问题解决
问题1:货币单位不一致
- 解决方案:在提示词中添加单位转换规则
- 示例:明确要求"所有金额统一为美元"
问题2:临时职位处理
- 解决方案:区分"现任"和"曾任"
- 规则:只返回当前有效的信息
问题3:负值识别
- 解决方案:特别处理括号表示法
- 提示:"(123)表示-123"
6.2 调试技巧
- 检索检查:先确认检索结果是否包含答案
- 分步验证:隔离各组件测试
- 失败分析:建立错误案例库
6.3 扩展建议
- 添加财务报表自动分析功能
- 集成更多文档类型(招股书、审计报告)
- 开发可视化问答界面
7. 开源资源推荐
项目完整代码已开源:
- GitHub仓库:RAG-Challenge-2
- 包含:解析器优化代码、提示词模板、评估脚本
关键文件说明:
pdf_parser.py:优化后的PDF解析器retriever.py:检索与重排序实现prompts.py:所有提示词模板evaluation.py:性能评估脚本
提示:运行前需准备Python 3.9+环境和必要依赖
8. 总结与展望
通过这次实战,我们验证了几个关键结论:
- 基础技术+精心调优 > 复杂算法:简单方法经过深度优化也能取得顶尖效果
- 提示工程是核心竞争力:好的提示设计可以弥补模型规模不足
- 端到端优化至关重要:每个环节的小改进会累积成显著优势
未来改进方向:
- 更智能的表格理解
- 多模态文档处理
- 自适应分块策略
这套方案不仅适用于财务报告,经过调整也可应用于:
- 法律文档分析
- 医疗记录查询
- 技术文档检索
对于想要复现或改进的开发者,我的建议是:
- 先确保基础RAG流程畅通
- 然后逐个组件优化
- 最后做端到端调优
财务文档问答只是RAG技术的应用场景之一,这套方法论的真正价值在于其可扩展性。通过调整解析器和提示词,同样的架构可以服务于各种专业领域的知识检索需求。
