一、升级概览
2025 年 10 月 29 日,TradingAgents-CN 完成了一次重要的 系统功能完善 工作。
本次更新通过 21 个提交,完成了 数据源优先级统一、报告多格式导出、系统日志管理、数据同步进度优化 等多项功能,显著提升了系统的 数据一致性、功能完整性、可维护性和用户体验。
核心改进
- 数据源优先级统一:所有
stock_basic_info查询统一使用数据源优先级。 - 报告多格式导出:支持 Markdown、JSON、DOCX、PDF 四种格式。
- 系统日志模块:支持日志查看、过滤、统计、下载和批量导出。
- 日志配置统一:日志配置迁移到 TOML 文件,支持 Docker 环境。
- 数据同步进度优化:增加多数据源同步详细进度日志。
- 前端体验优化:报告下载改为下拉菜单,日志管理新增可视化页面。
二、数据源优先级统一
2.1 问题背景
相关提交:
be56c32:所有stock_basic_info查询统一使用 数据源优先级。
此前系统中多个地方会查询股票基本信息,但没有统一遵循数据源优先级配置,导致不同接口返回的数据可能来自不同数据源。
主要问题
数据不一致
同一股票代码在不同接口中可能返回不同数据源的数据,用户看到的信息可能不一致。
优先级配置被忽视
用户在系统设置中配置的数据源优先级没有被完全应用,部分接口仍然使用硬编码数据源。
影响范围广
受影响的接口和模块包括:
- 股票搜索接口。
- 股票列表接口。
- 股票筛选接口。
- 自选股接口。
- 股票行情接口。
- MongoDB 缓存适配器。
2.2 解决方案
统一数据源查询逻辑
async def search_stocks(q: str, limit: int = 10):
"""搜索股票,使用数据源优先级"""
configs = await UnifiedConfigManager.get_data_source_configs_async()
sorted_configs = sorted(configs, key=lambda x: x.priority, reverse=True)
if sorted_configs:
primary_source = sorted_configs[0].source
return await get_stock_list(q, source=primary_source, limit=limit)
修改所有查询接口
本次统一改造了以下模块:
app/routers/stock_data.py:search_stocks接口。app/routers/stocks.py:get_quote接口。app/services/stock_data_service.py:get_stock_list方法。app/services/database_screening_service.py:screen方法。app/services/favorites_service.py:get_user_favorites方法。tradingagents/dataflows/cache/mongodb_cache_adapter.py:get_stock_basic_info方法。
兼容旧数据
对于没有 source 字段的旧数据,系统会补充默认数据源。
if not record.get('source'):
record['source'] = primary_source
2.3 优化效果
- 所有查询都遵循数据源优先级。
- 用户在系统设置中的配置可以完整生效。
- 不同接口返回的数据更加一致。
- 数据来源更加清晰可控。
三、报告多格式导出功能
3.1 功能背景
相关提交:
62126b6:添加 PDF 和 Word 格式报告导出 功能。264d7b0:增加 PDF 打包能力。6532b5a:Dockerfile 添加wkhtmltopdf支持 PDF 导出。ee78839:使用 GitHub 直接下载pandoc和wkhtmltopdf。
此前报告主要支持原始格式下载,无法满足不同场景下的分享、归档和编辑需求。
3.2 支持的导出格式
本次新增后,报告支持 4 种导出格式:
| 格式 | 用途 |
|---|---|
| Markdown | 原始文本格式,便于编辑和版本管理 |
| JSON | 数据格式,适合系统集成和二次处理 |
| DOCX | Word 文档,适合编辑、归档和分享 |
| 便携式文档,适合正式分发和阅读 |
3.3 后端实现
新增 ReportExporter 报告导出工具类。
class ReportExporter:
"""报告导出工具类"""
@staticmethod
async def export_markdown(report: Report) -> bytes:
"""导出为 Markdown 格式"""
content = f"# {report.title}\n\n{report.content}"
return content.encode('utf-8')
@staticmethod
async def export_json(report: Report) -> bytes:
"""导出为 JSON 格式"""
data = {
"title": report.title,
"content": report.content,
"created_at": report.created_at.isoformat(),
"analysts": report.analysts,
"model": report.model
}
return json.dumps(data, ensure_ascii=False, indent=2).encode('utf-8')
@staticmethod
async def export_docx(report: Report) -> bytes:
"""导出为 DOCX 格式"""
md_content = await ReportExporter.export_markdown(report)
docx_content = subprocess.run(
['pandoc', '-f', 'markdown', '-t', 'docx'],
input=md_content,
capture_output=True
).stdout
return docx_content
@staticmethod
async def export_pdf(report: Report) -> bytes:
"""导出为 PDF 格式"""
html_content = markdown.markdown(report.content)
pdf_content = subprocess.run(
['wkhtmltopdf', '-', '-'],
input=html_content.encode('utf-8'),
capture_output=True
).stdout
return pdf_content
3.4 下载接口改造
@router.get("/reports/{report_id}/download")
async def download_report(report_id: str, format: str = "markdown"):
"""下载报告,支持多种格式"""
report = await get_report(report_id)
exporter = ReportExporter()
if format == "markdown":
content = await exporter.export_markdown(report)
media_type = "text/markdown"
filename = f"{report.title}.md"
elif format == "json":
content = await exporter.export_json(report)
media_type = "application/json"
filename = f"{report.title}.json"
elif format == "docx":
content = await exporter.export_docx(report)
media_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
filename = f"{report.title}.docx"
elif format == "pdf":
content = await exporter.export_pdf(report)
media_type = "application/pdf"
filename = f"{report.title}.pdf"
return StreamingResponse(
iter([content]),
media_type=media_type,
headers={"Content-Disposition": f"attachment; filename={filename}"}
)
3.5 前端下拉菜单
报告详情页将下载按钮改为下拉菜单。
<el-dropdown @command="handleDownload">
<el-button type="primary">
下载报告
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="markdown">Markdown</el-dropdown-item>
<el-dropdown-item command="json">JSON</el-dropdown-item>
<el-dropdown-item command="docx">Word (DOCX)</el-dropdown-item>
<el-dropdown-item command="pdf">PDF</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
3.6 Docker 镜像配置
Docker 后端镜像中加入导出依赖。
RUN apt-get update && apt-get install -y \
pandoc \
wkhtmltopdf \
fonts-noto-cjk \
&& rm -rf /var/lib/apt/lists/*
3.7 优化效果
- 支持 4 种报告导出格式。
- 用户可根据场景选择适合格式。
- Word 和 PDF 适合正式分享与归档。
- Docker 镜像内置导出依赖,部署后即可使用。
四、系统日志导出功能
4.1 功能背景
相关提交:
98d173b:添加 系统日志导出功能。7205e52:统一日志配置到 TOML,支持 Docker 环境生成tradingagents.log。c93c20c:修复 Docker 环境下日志导出服务找不到日志文件的问题。
用户反馈问题时,往往不方便查看和导出日志。为提升问题定位效率,本次新增 系统日志管理模块。
4.2 后端日志服务
新增 LogExportService,支持日志文件列表、内容读取、导出和统计。
class LogExportService:
"""日志导出服务"""
async def get_log_files(self) -> List[Dict]:
"""获取日志文件列表"""
log_dir = Path(self.log_directory)
files = []
for log_file in log_dir.glob("*.log"):
stat = log_file.stat()
files.append({
"filename": log_file.name,
"size": stat.st_size,
"modified": stat.st_mtime,
"lines": self._count_lines(log_file)
})
return files
async def read_logs(
self,
filename: str,
level: Optional[str] = None,
keyword: Optional[str] = None,
lines: int = 100
) -> str:
"""读取日志内容,支持过滤"""
log_file = self.log_directory / filename
with open(log_file, 'r', encoding='utf-8') as f:
all_lines = f.readlines()
filtered_lines = all_lines
if level:
filtered_lines = [l for l in filtered_lines if level in l]
if keyword:
filtered_lines = [l for l in filtered_lines if keyword in l]
return ''.join(filtered_lines[-lines:])
日志统计支持:
- 日志文件数量。
- 日志总大小。
- ERROR 数量。
- WARNING 数量。
- INFO 数量。
4.3 后端 API
新增日志相关 API:
@router.get("/api/system/logs/files")
async def get_log_files():
"""获取日志文件列表"""
@router.post("/api/system/logs/read")
async def read_logs(request: ReadLogsRequest):
"""读取日志内容"""
@router.post("/api/system/logs/export")
async def export_logs(request: ExportLogsRequest):
"""导出日志文件"""
@router.get("/api/system/logs/statistics")
async def get_statistics():
"""获取日志统计"""
4.4 前端日志管理页面
新增 LogManagement.vue 页面,提供:
- 日志统计信息展示
- 日志文件列表
- 在线查看日志内容
- 按日志级别过滤
- 按关键词搜索
- 按行数限制读取
- 单个日志下载
- 批量日志导出
前端筛选项包括:
- 日志级别:全部、ERROR、WARNING、INFO。
- 关键词。
- 行数限制。
- 刷新按钮。
4.5 日志配置统一到 TOML
日志配置迁移到 TOML 文件,方便在本地与 Docker 环境中统一管理。
[handlers.file_main]
class = "logging.handlers.RotatingFileHandler"
filename = "/app/logs/tradingagents.log"
maxBytes = 10485760
backupCount = 5
formatter = "standard"
[handlers.file_webapi]
class = "logging.handlers.RotatingFileHandler" filename = "/app/logs/webapi.log" maxBytes = 10485760 backupCount = 5 formatter = "standard"
[handlers.file_error]
class = "logging.handlers.RotatingFileHandler" filename = "/app/logs/error.log" maxBytes = 10485760 backupCount = 5 formatter = "standard"
[loggers.tradingagents]
level = "INFO" handlers = ["console", "file_main"] propagate = false
4.6 优化效果
- 用户可以在界面查看日志。
- 支持多种过滤条件。
- 支持日志导出和下载。
- 日志配置统一管理。
- Docker 环境完整支持。
- 问题反馈和远程排查更方便。
五、数据同步进度优化
5.1 问题背景
相关提交:
49f2d39:增加 多数据源同步详细进度日志。
此前数据同步过程中缺少清晰的进度反馈:
- 用户不知道同步进行到哪里。
- 无法估算还需要等待多久。
- 同步失败位置难以定位。
- 错误统计不清楚。
5.2 BaoStock 适配器增加进度日志
def sync_stock_data(self, symbols: List[str]):
"""同步股票数据,添加进度日志"""
total = len(symbols)
success_count = 0
fail_count = 0
for i, symbol in enumerate(symbols):
try:
data = self._fetch_data(symbol)
success_count += 1
except Exception as e:
fail_count += 1
if fail_count % 50 == 0:
logger.warning(f"已失败 {fail_count} 次")
if (i + 1) % 50 == 0:
progress = (i + 1) / total * 100
logger.info(f"同步进度: {progress:.1f}% ({i + 1}/{total}), 最新: {symbol}")
logger.info(f"同步完成: 成功 {success_count}, 失败 {fail_count}")
5.3 多数据源同步服务增加进度日志
async def sync_all_sources(self, symbols: List[str]):
"""同步所有数据源,添加进度日志"""
logger.info(f"开始同步 {len(symbols)} 只股票")
for source in self.sources:
logger.info(f"处理数据源: {source.name}")
for i in range(0, len(symbols), 100):
batch = symbols[i:i+100]
progress = (i + 100) / len(symbols) * 100
logger.info(f"批量写入进度: {progress:.1f}%")
await self.write_batch(batch)
logger.info(f"{source.name} 同步完成")
5.4 前端超时调整
同步接口超时时间从 2 分钟增加到 10 分钟。
const syncRequest = axios.create({
timeout: 10 * 60 * 1000
})
5.5 优化效果
- 同步过程有更详细的进度反馈。
- 用户等待体验更好。
- 同步失败位置更容易定位。
- 错误统计更加清晰。
- 长时间同步任务不容易被前端误判为超时失败。
六、统计数据
6.1 提交统计
| 指标 | 数量 |
|---|---|
| 总提交数 | 21 |
| 修改文件数 | 40+ |
| 新增代码 | 2500+ 行 |
| 删除代码 | 300+ 行 |
| 净增代码 | 2200+ 行 |
6.2 功能分类
| 类型 | 数量 |
|---|---|
| 数据源统一 | 1 项 |
| 报告导出 | 4 项 |
| 系统日志 | 3 项 |
| 数据同步 | 1 项 |
| 其他优化 | 12 项 |
6.3 代码行数分布
| 模块 | 新增代码量 |
|---|---|
| 系统日志功能 | 约 1100 行 |
| 报告导出功能 | 约 900 行 |
| 数据源统一 | 约 160 行 |
| 数据同步进度 | 约 250 行 |
| 其他优化 | 约 400 行 |
七、技术亮点
7.1 数据源优先级设计
特点:
- 统一的数据源查询接口。
- 灵活的数据源优先级配置。
- 向后兼容旧数据。
- 查询结果更加一致。
7.2 多格式导出架构
特点:
- 模块化导出工具类。
- 支持 Markdown、JSON、DOCX、PDF 多格式转换。
- Docker 完整集成。
- 适配不同报告使用场景。
7.3 系统日志管理
特点:
- 完整的日志查看和导出功能。
- 灵活的日志过滤:级别、关键词、行数。
- 日志统计和分析。
- 安全的文件操作,防止路径遍历。
- 支持大文件分页读取。
- 支持 ZIP 压缩导出。
7.4 日志配置统一
特点:
- 日志配置从代码迁移到 TOML 文件。
- 支持主日志、WebAPI、Worker、错误日志等多个日志文件。
- Docker 环境完整支持。
- 日志级别和处理器配置更灵活。
7.5 进度反馈机制
特点:
- 同步进度日志更详细。
- 错误统计更清楚。
- 用户等待体验更好。
- 问题诊断更容易。
八、总结
本次更新通过 21 个提交,完成了 报告导出、系统日志、数据同步进度和数据源优先级统一 等多项系统功能完善。
主要成果包括:
- 数据一致性提升:所有
stock_basic_info查询统一使用数据源优先级,用户配置完整生效。 - 报告导出增强:支持 Markdown、JSON、DOCX、PDF 四种格式。
- 系统日志管理:新增日志查看、过滤、统计、下载和批量导出功能。
- 日志配置统一:迁移到 TOML 配置,并支持 Docker 环境生成主日志文件。
- 数据同步进度优化:增加详细同步进度日志,前端同步超时提升到 10 分钟。
- 用户体验改善:报告下载更灵活,问题排查更方便,同步过程更透明。
这些改进显著提升了 TradingAgents-CN 的 数据一致性、功能完整性、可维护性和用户体验,也让系统在实际使用和问题诊断场景中更加顺手。
✅ 官方唯一渠道:📦 GitHub 仓库:https://github.com/hsliuping/TradingAgents-CN
Aekor AI-API 中转站,让全球顶尖 AI 大模型“触手可及”!你是否曾为这些烦恼头疼?
🔹 人在国内,却总被海外官网 API 的高延迟、掉线、甚至无法访问困扰?
🔹 想用最强的 GPT、Claude 等模型,却卡在海外信用卡、支付审核等重重阻碍?
🔹 官方 API 太贵?Aekor 为你打通“网络-支付-成本”的任督二脉!
💡 Aekor 核心价值:好用、便宜、快 💡
🚀 高速稳定,告别掉线国内专线加速,API 响应低延迟,告别「转圈圈」的焦虑,开发效率瞬间拉满!
🧠 顶尖模型,随需而调涵盖 GPT 系列、Claude 系列等全球主流大厂模型,一次接入,轻松调用!
🎁 免费白嫖,诚意拉满!
注册即送 20 美元体验额度,够你狠狠测试一轮模型质量与线路稳定性了!
⚠️ 温馨提示:API 中转市场虽多但良莠不齐(甚至有些会偷工减料换小模型糊弄事儿)。Aekor 坚持提供正版稳定的服务,但还是建议:先用免费的 20 刀测试是否契合自身需求,满意了再小额充值上车,理性消费不盲目。
文章评论