Phoenix0531-sudo/BondLens

GitHub: Phoenix0531-sudo/BondLens

BondLens AI 是一个基于证据的中国债券市场分析智能体,通过实时数据、确定性工具链和 LLM 护栏,提供可解释、可审计的固定收益分析。

Stars: 3 | Forks: 1

# BondLens AI **可解释债券分析 Agent** [English](README.md) | [中文](README.zh-CN.md) ![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg) BondLens AI 是一个针对中国债券市场数据的轻量级、基于证据的分析 Agent。它默认使用 AkShare 实时债券市场数据,当无法访问实时数据时,会回退到最新缓存的实时快照;如果没有可用的快照,则回退到保留的本地 Excel 样本。每次回答都会返回一个结构化追踪记录,包含证据账本、回答评判器、风险概况、护栏状态和局限性说明。 项目主页:[https://phoenix0531-sudo.github.io/BondLens/](https://phoenix0531-sudo.github.io/BondLens/) ## 截图
BondLens AI agent workbench
Agent Workbench
Agent answer and evidence view
Answer, Tool Trace, and Evidence
Risk profile and answer judge
Risk Profile and Answer Judge
Agent replay dashboard
Replay Dashboard
GitHub Pages project page
GitHub Pages Project Page
Live-first data, deterministic tools, optional LLM enhancement, guardrails, replay, Docker, and CI in one portfolio-ready project.
## 背景 本项目最初是 2024 年的一个本科毕业设计项目:一个基于 Flask 的债券数据分析系统。原始的论文版本被保留下来,不应被重写: - 原始论文分支:`undergraduate-thesis-2024` - 当前分支:`main` 当前分支将毕业设计项目升级为 AI Agent / LLM 应用 / AI 工程师作品集项目,同时保留其历史渊源可见。 ## 仓库结构 本仓库有意保留了两个长期分支: - `main`:现代化的 BondLens AI 作品集项目 - `undergraduate-thesis-2024`:原始的本科毕业设计版本 没有保留发布标签,因为原始论文分支已是保留的历史版本。 ## 为什么这是一个 Agent,而不是 Chatbot BondLens AI 不会让 LLM 去猜测金融问题的答案。该 Agent 遵循一个小型的确定性循环: 1. **数据解析器** 优先加载 AkShare 实时债券数据,然后是缓存的实时快照,最后在需要时使用 `data/testdata.xlsx`。 2. **规划器** 对用户意图进行分类并选择工具。 3. **工具** 在活动数据帧上运行本地 Python 分析。 4. **证据** 作为结构化数据附加到响应中,并呈现为审查者可读的声明。 5. **报告** 基于证据生成,包含风险和局限性。 6. **可选 LLM** 只有在存在本地证据后才能润色回答。它支持 OpenAI 和兼容 OpenAI 的本地 endpoint(例如 Ollama)。 7. **LLM 护栏** 根据结构化证据检查数字声明和不安全的投资用语模式,如果 LLM 输出不安全,则回退到确定性报告。 8. **回答评判器** 记录模型输出是被接受、被护栏拒绝还是被绕过。 9. **证据账本、风险概况和重放存储** 使回答可审计,且无需在作品集 UI 中展示原始 JSON。 10. **Schema 契约** 在返回最终 API 响应之前,使用 Pydantic 对其进行验证。 如果未设置 `OPENAI_API_KEY`,项目仍可运行并使用确定性回退输出。 ## 核心功能 - 意图规划:市场概览、债券搜索、排名、异常值检测、完整债券报告 - 工具追踪:每个规划器/工具步骤在 Web 页面和 API 响应中均可见 - 按名称、期限和收益率范围搜索债券 - 实时数据模式:AkShare `bond_spot_deal` 当前债券成交数据 - 证券主数据核对:由于 `bond_spot_deal` 不提供原生期限数据,匹配到的债券会从本地静态样本中进行数据丰富,并标记期限覆盖率元数据 - 缓存实时快照模式:当实时 endpoint 暂时失败时,重用最近成功的 AkShare 抓取结果 - 本地回退模式:`data/testdata.xlsx` 仍可用于离线演示和确定性测试 - 市场摘要:样本计数、收益率分布、成交量统计 - 按收益率、成交量、期限或价格排名 - 使用 z-score 进行收益率异常值检测 - 债券与市场对比:收益率百分位、成交量百分位、期限百分位、异常值状态 - 数据源概况:请求模式、实际 runtime 模式、提供商、抓取时间、回退原因以及遗留爬虫边界 - 针对固定收益概念的检索增强风险解释 - 带有置信度和新鲜度标签的证据质量评分 - 用于数字证据检查、不安全投资用语检查和安全回退的 LLM 忠实度护栏 - 证据账本:将工具输出转化为声明/证据/来源/置信度记录以供审查 - 回答评判器:解释 LLM 回答为何被接受、拒绝或绕过 - 结构化风险概况:数据质量、信用背景、流动性、久期、异常值和模型输出风险 - 重放仪表板:`/replay` 汇总最近的 Agent 运行情况,默认不暴露原始 JSON - 使用 `/api/agent/schema` 的 Pydantic 响应 schema - 用于容器和部署平台的轻量级 `/healthz` endpoint - 用于可重复行为和安全检查的 Agent 评估和红队评估套件 - 使用 gunicorn 进行 Docker 部署 ## Agent 工作流 ``` flowchart TD A[User Question] --> B[Data Source Resolver] B --> C[Planner] C --> D{Intent} D -->|market_overview| E[describe_market] D -->|bond_search| F[search_bonds] D -->|ranking| G[rank_bonds] D -->|outlier_detection| H[detect_yield_outliers] D -->|bond_report| I[search_bonds + compare_bond_to_market + market/ranking/outlier tools] E --> J[Structured Evidence] F --> J G --> J H --> J I --> J J --> K[generate_bond_report] K --> L[Risk explanation retrieval] L --> M[Evidence quality assessment] M --> N{OPENAI_API_KEY or OPENAI_BASE_URL} N -->|missing| O[Deterministic fallback] N -->|set| P[OpenAI or local LLM enhancement] P --> Q[LLM numeric and language guardrail] Q -->|passed| R[LLM final answer] Q -->|numeric or language failure| S[Deterministic fallback answer] R --> T[Answer Judge + Evidence Ledger + Risk Profile] S --> T O --> T T --> U[Replay Dashboard] ``` ## 工具追踪示例 ``` User question: 搜索23附息国债26并给出收益率分析 -> data_source(mode=live, source=akshare_bond_spot_deal) -> planner(intent=bond_report) -> search_bonds(name=23附息国债26) -> compare_bond_to_market() -> describe_market() -> rank_bonds(by=yield, top_n=5) -> detect_yield_outliers(method=zscore, threshold=3.0) -> generate_bond_report() -> llm_guardrail(skipped: llm_disabled) -> final answer ``` ## 技术栈 - Python 3.11 - Flask - AkShare - Pandas / NumPy - OpenPyXL - OpenAI Python SDK(可选) - Pytest + 本地 Agent 评估 - Docker Compose + gunicorn - GitHub Actions CI ## 架构 ``` . ├── app.py # Flask app entry ├── bond_agent/ │ ├── agent.py # Agent orchestration and LLM fallback status │ ├── planner.py # Rule-based intent planner │ ├── data_loader.py # AkShare live loading, snapshot cache, Excel fallback │ ├── evidence_ledger.py # Claim/evidence/source/confidence ledger │ ├── answer_judge.py # Deterministic judge for LLM acceptance/fallback │ ├── risk_profile.py # Structured risk profile cards │ ├── replay_store.py # Sanitized local run replay summaries │ ├── risk_knowledge.py # Local fixed-income risk explanation retrieval │ ├── evidence_quality.py # Evidence scoring, freshness, and confidence labels │ ├── llm_guardrail.py # Numeric and risk-language checks for LLM answers │ ├── schemas.py # Pydantic API request/response contracts │ └── tools.py # Local bond analysis tools ├── data/testdata.xlsx # Static bond sample data ├── docs/index.html # GitHub Pages project page ├── docs/deployment.md # Docker, health check, and platform deployment notes ├── evals/ │ ├── agent_eval_cases.yml # Behavior cases │ ├── red_team_eval_cases.yml # Safety boundary cases │ ├── run_agent_evals.py # Local eval runner │ └── run_red_team_evals.py # Red-team eval runner ├── templates/agent.html # Agent UI ├── templates/replay.html # Recent run replay dashboard ├── tests/ # Unit and smoke tests ├── LICENSE ├── Dockerfile └── docker-compose.yml ``` ## 使用 Docker 快速开始 ``` docker compose up --build ``` 打开: ``` http://localhost:5000/agent ``` 容器运行 gunicorn: ``` gunicorn -b 0.0.0.0:5000 app:app ``` Compose 服务命名为 `bondlens-ai`,并使用 `/healthz` 进行轻量级的平台和容器健康检查。 ## 本地开发 ``` python -m pip install -r requirements-dev.txt python app.py ``` 打开: ``` http://localhost:5000/agent ``` ## 环境变量 ``` FLASK_ENV=production SECRET_KEY=change-me-in-production OPENAI_API_KEY= OPENAI_MODEL=gpt-5.4-mini OPENAI_BASE_URL= OPENAI_API_STYLE=auto OPENAI_TIMEOUT_SECONDS=20 BOND_DATA_MODE=auto BOND_LIVE_CACHE_PATH= BOND_LIVE_CACHE_MAX_AGE_HOURS=24 BOND_REPLAY_ENABLED=true BOND_REPLAY_DIR= ``` - `SECRET_KEY`:Flask session 密钥。 - `OPENAI_API_KEY`:可选。如果为空,则使用确定性回退。 - `OPENAI_MODEL`:用于受证据约束的回答增强的可配置模型。 - `OPENAI_BASE_URL`:可选的兼容 OpenAI 的 endpoint。对于本地 Ollama,请使用 `http://127.0.0.1:11434/v1`。 - `OPENAI_API_STYLE`:`auto`、`responses` 或 `chat`。正常使用时保持 `auto`;本地 endpoint 通常使用 chat completions。 - `OPENAI_TIMEOUT_SECONDS`:可选的 LLM 请求超时时间。默认为 `20`,以便缓慢的本地模型能够安全回退,而不是导致 Web 服务器超时。 - `BOND_DATA_MODE`:`auto`、`live` 或 `static`。`auto` 会先尝试 AkShare,然后是缓存的实时快照,最后是本地 Excel 回退。 - `BOND_LIVE_CACHE_PATH`:AkShare 快照 CSV 的可选路径。默认为 `.tmp/bond_spot_deal_snapshot.csv`。 - `BOND_LIVE_CACHE_MAX_AGE_HOURS`:在使用静态回退之前接受的最大快照时效(小时)。默认为 `24`。 - `BOND_REPLAY_ENABLED`:设置为 `false` 以禁用本地运行重放摘要。默认为 `true`。 - `BOND_REPLAY_DIR`:可选的重放目录。默认为 `.tmp/replays`,该目录会被 Git 忽略。 本地 Ollama 冒烟测试示例: ``` set OPENAI_BASE_URL=http://127.0.0.1:11434/v1 set OPENAI_MODEL=qwen2.5:1.5b set OPENAI_API_STYLE=chat python app.py ``` 对于不需要身份验证的本地兼容 OpenAI 的 endpoint,`OPENAI_API_KEY` 可以保留为空。 小型本地模型对于验证 LLM 路径是否能够端到端运行非常有用,但确定性证据字段仍然是审查和调试的真理来源。 在 Windows 或 macOS 上使用 Docker 时,请将容器指向宿主机的 Ollama 服务: ``` set OPENAI_BASE_URL=http://host.docker.internal:11434/v1 docker compose up --build ``` API 响应会暴露安全的 LLM 状态: ``` { "used_llm": false, "used_llm_in_final": false, "llm_status": "disabled", "llm_error": null, "llm_guardrail": { "status": "not_run", "numeric_status": "not_run", "language_status": "not_run" } } ``` ## 示例问题 ``` 当前样本收益率分布是什么样? 搜索23附息国债26并给出收益率分析 按收益率列出最高的前5只债券 按成交量列出最活跃的前5只债券 按期限列出最长的前5只债券 有没有收益率异常的债券? 筛选收益率大于 3 的债券 ``` ## API ``` POST /api/agent/query Content-Type: application/json { "question": "搜索23附息国债26并给出收益率分析", "data_mode": "auto" } ``` 关键响应字段: - `plan`:规划器意图、选定工具、排名/搜索参数 - `tools_used`:实际用于该回答的工具 - `tool_trace`:人类可读的步骤追踪 - `data_evidence`:机器可读的市场/搜索/排名/异常值/对比证据 - `data_source`:活动数据源概况,包括请求模式、runtime 模式、提供商、抓取时间、行数和回退原因 - `risk_explanations`:检索到的固定收益风险解释 - `evidence_quality`:评分、置信度标签、覆盖率、新鲜度和惩罚项 - `evidence_ledger`:审查者可读的声明、证据、来源、工具和置信度记录 - `answer_judge`:LLM 输出的最终回答接受/拒绝状态 - `risk_profile`:结构化的数据质量、信用、流动性、久期、异常值和模型风险卡片 - `final_answer`:通过护栏的 LLM 回答,或确定性报告 - `final_answer_source`:`llm` 或 `deterministic_fallback` - `llm_enhanced_answer`:可用时保留用于调试的原始 LLM 回答 - `llm_guardrail`:数字忠实度状态、不安全风险用语状态、评分、不支持的数字声明以及被阻止的短语 - `llm_status`:`disabled`、`success` 或 `failed` 其他操作 endpoint: ``` GET /healthz GET /api/agent/schema GET /replay ``` `/api/agent/schema` 返回请求、响应、健康检查和错误 payload 的 Pydantic JSON schema。 `/replay` 显示经过脱敏处理的最近运行摘要,用于面试演示和调试重放。 部署说明可在 [docs/deployment.md](docs/deployment.md) 中查看。 ## 数据源边界 当前 Agent 路径采用实时优先的数据策略: ``` Primary: AkShare bond_spot_deal Snapshot: .tmp/bond_spot_deal_snapshot.csv Final fallback: data/testdata.xlsx ``` AkShare 将 `bond_spot_deal` 记录为 ChinaMoney 的当前债券成交市场接口。BondLens AI 使用的原生字段包括债券名称、净价、最新收益率、BP 变化、加权收益率和成交量。实时 endpoint 不提供期限数据,因此 BondLens AI 从本地静态样本中丰富匹配的债券名称,并在 `data_source` 中报告 `maturity_coverage`。 默认 runtime 模式是 `auto`:首先抓取实时数据,将归一化结果写入本地 CSV 快照,并在后续实时请求失败时使用该快照。如果实时抓取和快照回退均不可用或已过期,Agent 将回退到本地工作簿。`/agent` 页面和 API 还支持: ``` auto -> live first, cached snapshot second, local fallback third live -> live source requested; fallback reason is shown if it degrades static -> local Excel only ``` 本地回退仍然是: ``` data/testdata.xlsx ``` 该工作簿包含 3000 多条债券样本数据,字段包括债券名称、期限、净价、收盘收益率、加权收益率和成交量。它用于离线演示、确定性 CI 和回退行为。 实时快照默认有意存储在 `.tmp/` 下,并且不提交到 Git。这样既能保持仓库整洁,又能在公共 endpoint 暂时不可用时使本地演示具有弹性。 遗留爬虫作为毕业设计时期的历史代码保留在 `undergraduate-thesis-2024` 中。它针对旧的 CNSTOCK 新闻页面,依赖 MongoDB 和毕业设计时期的文本分析模块,不存在于当前 `main` 的 runtime 中。在 2026 年 5 月 26 日的仓库验证期间,旧的 CNSTOCK HTTP endpoint 对自动请求返回 `403 Forbidden`,因此本项目不将它们作为活跃或可靠的实时数据源呈现。 ## 风险解释层 BondLens AI 包含一个针对固定收益风险概念的本地检索增强解释层。在 Python 工具生成证据后,Agent 会从精选的本地知识库中检索相关片段,涵盖: - 收益率解释 - 流动性风险 - 期限和久期敏感性 - 收益率异常值审查 - 信用背景局限性 - 实时/静态数据边界 这使得解释有理有据且可重复,无需外部向量数据库或实时 LLM 调用。 ## 证据质量 每次 Agent 回答都包含一个 `evidence_quality` 对象,具有: - `score`:当前回答的 0-100 证据质量评分 - `level`:当前活动证据集的低、中或高置信度 - `analysis_confidence`:对描述性分析的置信度 - `decision_confidence`:故意设为低,因为未附加发行人评级、信用事件、宏观曲线和完整的证券主数据 - `data_freshness`:`live_fetch`、`cached_live_snapshot` 或 `static_snapshot` - `coverage`:哪些证据块可用 - `penalties`:限制结论的缺失上下文 ## 证据账本、回答评判器和重放 默认 Web UI 避免使用原始 JSON/类似代码的诊断面板。相反,它呈现: - **证据账本**:从活动工具输出派生的声明/证据/来源/置信度记录。 - **回答评判器**:一个确定性接受层,显示 LLM 文本是被接受、被护栏拒绝还是被绕过。 - **概况**:用于数据质量、信用背景、流动性、久期、收益率异常值和模型输出风险的结构化卡片。 - **重放仪表板**:`/replay` 默认将脱敏后的运行摘要存储在 `.tmp/replays` 下。 原始的机器可读契约仍可通过 `/api/agent/query` 和 `/api/agent/schema` 获取。 ## Agent 评估 运行确定性行为检查: ``` python evals/run_agent_evals.py ``` 运行红队安全检查: ``` python evals/run_red_team_evals.py ``` 评估套件检查: - 预期的规划器意图 - 预期的工具 - 必需的回答关键词 - 可选的禁止回答关键词 - 投资建议和保证收益边界案例 它不会调用 OpenAI。 ## 测试 ``` python -m pytest -q ``` 覆盖范围包括: - 规划器意图分类 - 感知意图的工具路由 - 数据源元数据 - 风险解释检索 - 证据质量评估 - 市场统计 - 排名工具 - 收益率异常值检测 - 债券与市场对比 - 具体债券报告行为 - 带有 mock 的 LLM 禁用/成功/失败状态 - LLM 数字和不安全风险用语护栏 - 证据账本、回答评判器、风险概况和重放存储 - Pydantic Agent 响应 schema - 健康检查和 schema endpoint - 实时快照缓存回退 - Flask 页面/API 冒烟测试 - 评估案例加载 ## 仓库策略 公共仓库有意保持紧凑:源代码、测试、评估、Docker、文档、截图、CI 和许可证。通用的社区模板已被移除,因为这是一个个人作品集项目,而不是开源协作中心。 推荐的分支策略是保护 `main`,并要求在合并之前通过 CI 工作流。原始论文分支仍作为历史参考,不应接收现代功能开发。 ## 数据边界 所有金融结论均根据每个响应中显示的活动数据源计算得出: ``` AkShare bond_spot_deal, the cached AkShare snapshot, or data/testdata.xlsx when static/fallback mode is active ``` Agent 不会捏造发行人评级、信用事件、宏观观点或投资建议。遗留爬虫代码仅保留在论文分支中;当前 `main` 分支使用 AkShare 实时数据加上本地 Excel 回退。 ## 现代项目清理 `main` 分支移除了遗留的登录/数据库代码、过时的爬虫代码、旧的论文 UI 页面、IDE 元数据和未引用的静态数据转储。这是安全的,因为: - `undergraduate-thesis-2024` 保留了原始仓库状态。 - 当前 Flask 路由仅服务于 BondLens AI 及其 API。 - 核心债券样本数据、Agent 代码、测试、Docker 和 README 文档均予保留。 ## 面试讨论点 - **工具调用设计**:确定性规划器将用户意图映射到本地 Python 工具。 - **实时优先源设计**:AkShare 实时数据为默认设置,具有缓存的实时快照和静态回退层以保障可靠性。 - **证据约束**:最终回答基于 `data_evidence` 生成,而非自由形式的金融猜测。 - **证据账本**:UI 将数据证据转化为可审计的声明,而不是倾倒原始 JSON。 - **本地 LLM 兼容性**:兼容 OpenAI 的 endpoint 无需付费 API 密钥即可执行 LLM 路径。 - **LLM 护栏**:在 LLM 回答成为最终回答之前,会检查数字声明和不安全的投资用语。 - **回答评判器和重放**:被接受/拒绝的模型输出可见,并且可以审查最近的运行。 - **回退设计**:无需 API 密钥;OpenAI/本地 LLM 路径是可选且可观察的。 - **风险边界**:输出始终包含局限性和非投资建议语言。 - **评估方法**:本地行为评估和红队评估测试意图、工具选择、回答约束和安全边界。 - **Docker 化**:gunicorn runtime、健康检查和可重现的依赖安装。 - **遗留迁移**:保留原始论文版本,清理现代分支以供作品集使用。 ## 路线图 - 在实时市场 Feed 周围添加发行人评级、债券主数据和收益率曲线背景 - 将 RAG 从本地片段扩展到文档支持的检索 - 添加 PDF/Markdown 报告导出 - 在实时快照和静态回退之间添加更丰富的证据一致性评估 - 添加久期、凸性、信用利差和流动性分桶 - 在有稳定的债券详细信息数据源时,添加后台证券主数据刷新任务 ## 许可证 MIT。在使用本项目进行学习、作品集审查或面试讨论时,请保持论文来源和作者背景可见。 ## 免责声明 BondLens AI 不提供投资建议、交易建议、评级意见或收益保证。输出仅供学习、研究和工程演示使用。
标签:AI智能体, DLL 劫持, Flask, 债券分析, 大语言模型, 版权保护, 请求拦截, 逆向工具, 金融科技