ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FinReportAgent 实战:基于 HelloAgents 框架构建金融研报智能体

FinReportAgent 实战:基于 HelloAgents 框架构建金融研报智能体 FinReportAgent 实战基于 HelloAgents 框架构建金融研报智能体【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents导读FinReportAgent 是 HelloAgents 开源社区中一个典型的垂直领域智能体项目它演示了如何基于ReActAgent 工具注册机制把「股价查询、金融新闻搜索、多源信息检索」封装成三个可执行工具让大模型自主完成收集数据 → 推理分析 → 生成研报的完整链路最终输出带看涨/看跌/中性情绪判断的 Markdown 投资分析报告。读完本文你将掌握在 HelloAgents 框架下自定义工具、重写 ReAct 循环解析逻辑以兼容中文 LLM 输出、以及用规则方法做报告格式化与情绪识别的完整实战方案。一、项目定位与技术栈FinReportAgent 是一个基于 HelloAgents 框架构建的金融研报生成智能体核心能力如下自动收集数据通过 DuckDuckGo 搜索、Yahoo Finance API 获取实时行情和新闻智能分析推理基于 ReActReasoning and Acting范式进行多步推理生成专业的投资分析结构化报告自动生成带情绪判断的 Markdown 格式研报。项目声明的核心功能包括 股票价格查询Yahoo Finance 实时行情、 金融新闻搜索DuckDuckGo 新闻抓取、 多源信息检索DuckDuckGo 网络搜索、 Markdown 报告生成自动生成结构化投资分析报告、 情绪判断自动识别看涨/看跌/中性情绪。技术栈可概括为下表组件技术智能体框架HelloAgents智能体范式ReAct (Reasoning and Acting)搜索工具DuckDuckGo Search金融数据Yahoo Finance API (yfinance)LLMDeepSeek / OpenAI 兼容 API二、快速开始2.1 环境要求Python 3.10项目主程序在 Python 3.13.9 内核下运行验证Jupyter Notebook / JupyterLab2.2 安装依赖项目的依赖清单位于 Co-creation-projects/kkkano-FinReportAgent/requirements.txt一条命令即可完成安装pip install -r requirements.txt依赖的构成也说明了本项目每一层能力的来源hello-agents0.2.8核心智能体框架ReActAgent、HelloAgentsLLM、ToolRegistry 等openai1.0.0LLM 客户端底层HelloAgentsLLM 封装的是 OpenAI 兼容接口yfinance0.2.0Yahoo Finance 行情数据duckduckgo-search4.0.0网络搜索与新闻抓取pandas2.0.0、numpy1.24.0数据处理ipython8.0.0Jupyter 运行环境python-dotenv1.0.0.env 环境配置加载。2.3 配置 API 密钥方式一使用 .env 文件推荐# 复制配置模板 cp .env.example .env # 编辑 .env 文件填入你的 API 密钥方式二直接在 Notebook 中配置打开main.ipynb在第一个代码 Cell 中修改os.environ[LLM_API_KEY] your-api-key-here # 替换为你的 API Key从 main.ipynb 第 1 部分的实现可以看到完整的环境配置逻辑先用load_dotenv()加载.env如果LLM_API_KEY尚未设置则在代码内直接补充LLM_MODEL_ID默认deepseek-chat、LLM_API_KEY、LLM_BASE_URL默认https://api.deepseek.com/v1。这套命名约定LLM_MODEL_ID/LLM_API_KEY/LLM_BASE_URL与本书框架的 LLM 客户端读取逻辑完全一致——在 code/chapter4/llm_client.py 中HelloAgentsLLM初始化时正是通过os.getenv(LLM_MODEL_ID)、os.getenv(LLM_API_KEY)、os.getenv(LLM_BASE_URL)依次兜底并支持LLM_TIMEOUT默认 60 秒控制请求超时。也就是说只要把三个环境变量配置正确DeepSeek、通义、OpenAI 等任何 OpenAI 兼容服务都可以直接切换。2.4 运行项目# 启动 Jupyter jupyter lab # 打开 main.ipynb 并按顺序运行所有 Cell2.5 项目结构kkkano-FinReportAgent/ ├── main.ipynb # 主程序 ├── README.md # 项目说明 ├── requirements.txt # 依赖列表 └── .env.example # 环境变量示例三、HelloAgents 框架组件与设计思想本项目对 HelloAgents 框架的使用非常聚焦仅依赖四个核心组件可以在后续各节中一一对照源码理解组件用途ReActAgentReAct 循环框架推理-行动-观察HelloAgentsLLM统一的 LLM 调用接口ToolRegistry工具注册和管理Tool/ToolParameter工具定义基类要理解这四个组件的协作方式可以对照本书在 code/chapter7/my_react_agent.py 中对框架的典型用法MyReActAgent在run()中循环执行用tool_registry.get_tools_description()组装工具描述 → 将 tools/question/history 填入提示词模板 →self.llm.invoke(messages)调用 LLM →_parse_output解析 Thought/Action → 命中Finish即结束、否则tool_registry.execute_tool执行工具并把结果追加进current_history直到max_steps步数耗尽。FinReportAgent 正是沿着这一骨架把通用 ReAct 智能体改造成了金融领域专用智能体。四、工具层三个金融工具的定义与实现工具定义位于main.ipynb第 2 部分三个工具分别对应行情、新闻、搜索三类数据源。它们的写法遵循 HelloAgents 的Tool基类约定构造函数传入name与descriptionget_parameters()声明参数ToolParameter(name, type, description, required)run(parameters)执行业务逻辑并返回字符串给 LLM 观察。4.1 SearchTool网络搜索class SearchTool(Tool): 搜索工具 def __init__(self): super().__init__(namesearch, description搜索网络信息) def get_parameters(self) - List[ToolParameter]: return [ToolParameter(nameinput, typestring, description搜索关键词, requiredTrue)] def run(self, parameters: Dict[str, Any]) - str: query parameters.get(input, ) try: from duckduckgo_search import DDGS with DDGS() as ddgs: results list(ddgs.text(query, max_results5)) if not results: return f未找到 {query} 的相关结果 output [] for i, r in enumerate(results, 1): output.append(f[{i}] {r.get(title, 无标题)}) output.append(f 链接: {r.get(href, N/A)}) output.append(f 摘要: {r.get(body, )[:150]}...) return \n.join(output) except Exception as e: return f搜索出错: {str(e)}要点解析ddgs.text(query, max_results5)限制每次搜索最多返回 5 条结果控制上下文体积输出固定拼装标题 链接 摘要且摘要截断到 150 字符既给足信息又不撑爆上下文窗口全函数用 try/except 包裹任何异常都返回人类可读的错误串如搜索出错: ...而不是抛异常打断 ReAct 循环。4.2 NewsTool金融新闻获取class NewsTool(Tool): 新闻工具 def __init__(self): super().__init__(nameget_news, description获取股票相关新闻) def get_parameters(self) - List[ToolParameter]: return [ToolParameter(nameinput, typestring, description股票代码, requiredTrue)] def run(self, parameters: Dict[str, Any]) - str: ticker parameters.get(input, ) try: from duckduckgo_search import DDGS with DDGS() as ddgs: results list(ddgs.news(f{ticker} stock news, max_results5)) if not results: return f未找到 {ticker} 的相关新闻 output [f{ticker} 最新新闻:, ] for i, r in enumerate(results, 1): output.append(f[{i}] {r.get(title, 无标题)}) output.append(f 来源: {r.get(source, 未知)}) output.append(f 日期: {r.get(date, N/A)}) return \n.join(output) except Exception as e: return f新闻获取出错: {str(e)}与搜索工具不同新闻工具固定以{ticker} stock news为查询串并使用ddgs.news()的新闻专用接口返回结构包含title、source、date便于 LLM 在报告中引用新闻来源和时间。4.3 PriceToolYahoo Finance 实时行情class PriceTool(Tool): 价格工具 (Yahoo Finance) def __init__(self): super().__init__(nameget_price, description获取股票实时价格) def get_parameters(self) - List[ToolParameter]: return [ToolParameter(nameinput, typestring, description股票代码如AAPL, requiredTrue)] def run(self, parameters: Dict[str, Any]) - str: ticker parameters.get(input, ).upper() try: import yfinance as yf stock yf.Ticker(ticker) info stock.info price info.get(currentPrice) or info.get(regularMarketPrice, N/A) prev info.get(previousClose, N/A) cap info.get(marketCap, 0) pe info.get(trailingPE, N/A) # 计算涨跌幅 change N/A if isinstance(price, (int, float)) and isinstance(prev, (int, float)): change f{((price - prev) / prev) * 100:.2f}% # 格式化市值 if cap 1e12: cap_str f${cap/1e12:.2f}T elif cap 1e9: cap_str f${cap/1e9:.2f}B else: cap_str f${cap/1e6:.2f}M return f{ticker} 行情数据: 当前价格: ${price} 涨跌幅: {change} 昨收: ${prev} 市值: {cap_str} 市盈率: {pe} except Exception as e: return f价格获取出错: {str(e)}要点解析入参.upper()归一化避免aapl与AAPL混用导致的查询失败优先取currentPrice缺失时回退到regularMarketPrice兼容不同市场的字段差异涨跌幅在数值类型校验后才计算防止N/A参与运算市值按 T万亿/ B十亿/ M百万分级格式化输出更易读一次工具调用即返回现价、涨跌幅、昨收、市值、市盈率五个关键指标足以支撑报告中的股票概况章节。五、智能体层继承 ReActAgent 并增强中文解析鲁棒性工具注册与智能体构建位于main.ipynb第 3 部分是全项目最核心的工程实践# 初始化 LLM llm HelloAgentsLLM() # 注册工具 tool_registry ToolRegistry() tool_registry.register_tool(SearchTool()) tool_registry.register_tool(NewsTool()) tool_registry.register_tool(PriceTool()) class FinReportAgent(ReActAgent): 金融研报智能体 继承自 HelloAgents 框架的 ReActAgent覆盖解析方法以支持多种 LLM 输出格式。 ...5.1 为什么要重写_parse_output这是本项目最值得借鉴的设计决策。注释中明确说明了动机框架原版只认严格的Thought: 和Action: 格式DeepSeek 等模型经常输出中文标签思考/行动或全角冒号覆盖后可以兼容多种格式提高鲁棒性。对比本书 code/chapter4/ReAct.py 中基础版ReActAgent._parse_output的正则只匹配Thought:\s*与Action:\s*FinReportAgent 的解析器做了三层强化def _parse_output(self, text: str) - Tuple[Optional[str], Optional[str]]: if not text: return None, None text text.strip() # 提取 Thought支持中英文、全角冒号 thought None for pattern in [rThought[:]\s*(.?)(?Action|行动|$), r思考[:]\s*(.?)(?Action|行动|$)]: match re.search(pattern, text, re.IGNORECASE | re.DOTALL) if match: thought match.group(1).strip() break # 提取 Action支持中英文、全角冒号- 使用贪婪匹配获取完整内容 action None for pattern in [rAction[:]\s*(.), r行动[:]\s*(.)]: match re.search(pattern, text, re.IGNORECASE | re.DOTALL) if match: action match.group(1).strip() break return thought, action对应_parse_action也做了中英文括号的兼容def _parse_action(self, action_text: str) - Tuple[Optional[str], Optional[str]]: if not action_text: return None, None match re.match(r(\w)\s*[\[【](https://link.gitcode.com/i/beb3cb0ea121a4045f022b39df74f8d7)[\]】], action_text, re.DOTALL) return (match.group(1), match.group(2)) if match else (None, None)5.2 自定义 ReAct 循环FinReportAgent.run()重写了整个循环逻辑与框架标准实现一脉相承可对照 code/chapter7/my_react_agent.py 的MyReActAgent.run()用tool_registry.get_tools_description()生成工具描述、拼接历史格式化进prompt_templateself.llm.invoke(messages, **kwargs)调用 LLM 得到响应_parse_output解析出 thought / action若只有 thought 没有 action则把请按格式输出 Action作为 Observation 追加进历史逼模型纠正格式action 以Finish开头时调用_extract_finish_content贪婪提取完整报告并返回否则_parse_action拆出工具名与参数tool_registry.execute_tool执行并记录Action/Observation历史超过max_steps本项目设为 6仍未完成则返回无法在限定步数内完成分析。5.3 用提示词模板约束报告结构PROMPT_TEMPLATE是让 LLM 输出专业研报的关键它明确规定了工作流与格式PROMPT_TEMPLATE 你是一位资深金融分析师请使用工具分析股票。 可用工具: {tools} 回复格式: Thought: 简短说明下一步计划 Action: 工具调用或最终报告 工作流程: 1. 先调用 get_price[股票代码] 获取价格 2. 再调用 get_news[股票代码] 获取新闻 3. 最后用 Finish[完整报告] 输出分析报告 重要要求: - Finish[] 括号内必须包含完整的中文分析报告 - 报告字数必须超过300字 - 报告必须包含股票概况、新闻解读、投资建议、风险提示 ... 问题: {question} 历史: {history} 请回复:提示词工程上有三个值得复用的技巧固定调用顺序先价格、再新闻、最后报告减少 LLM 决策的不确定性硬性结构约束强制报告包含股票概况、新闻解读、投资建议、风险提示四个章节保证输出结构稳定few-shot 示例模板内置了一个 AAPL 的完整Finish[...]示例示范章节格式与行文风格。创建智能体时将这些参数注入agent FinReportAgent( nameFinReportAgent, llmllm, tool_registrytool_registry, max_steps6, custom_promptPROMPT_TEMPLATE )六、报告层Markdown 格式化与情绪判断第 4 部分提供三个报告处理函数把 LLM 返回的分析正文包装成规范研报。format_report的核心是基于关键词规则的情绪判断def format_report(ticker: str, analysis: str) - str: now datetime.now().strftime(%Y-%m-%d %H:%M) # 判断情绪倾向 if any(w in analysis for w in [看涨, 买入, 增持, 上涨, 建议买入]): sentiment 看涨 (Bullish) elif any(w in analysis for w in [看跌, 卖出, 减持, 下跌, 建议卖出]): sentiment 看跌 (Bearish) else: sentiment ➖ 中性 (Neutral) ...判断顺序是先看涨、再看跌、否则中性只要正文中出现看涨/买入/增持/上涨/建议买入任一关键词即判定 Bullish出现看跌/卖出/减持/下跌/建议卖出判定 Bearish两者都不命中则为 Neutral。这是一种轻量、可解释、零成本的规则方案适合对输出稳定性要求不高的场景。最终报告模板统一包含标题# {ticker} 投资分析报告、生成时间、情绪判断、分析正文以及固定的免责声明 ⚠️ **免责声明**: 本报告由 AI 自动生成仅供参考不构成投资建议。配套的两个函数负责展示与落盘show_report(ticker, analysis)调用display(Markdown(report))在 Jupyter 内直接渲染save_report(ticker, analysis, filenameNone)默认按report_{ticker}_{YYYYMMDD_HHMM}.md命名写入本地文件如演示中的report_AAPL_20260125_1842.md指定filename可自定义输出路径。七、端到端演示从提问到研报第 5 部分先用PriceTool().run({input: AAPL})单独验证工具可用性再以agent.run(Analyze AAPL stock price and news)驱动完整流程。运行日志清晰地展示了 ReAct 的三步循环第 1 步LLM 输出Thought: 我将按照工作流程先获取AAPL的实时价格...→Action: get_price[AAPL]→ 工具返回现价 248.04 美元、涨跌幅 -0.12%、市值 3.67T、市盈率 33.2第 2 步Action: get_news[AAPL]获取新闻演示中曾出现 DuckDuckGo 请求异常但模型在第 3 步依据已获得的信息继续生成报告第 3 步Action: Finish[...]输出完整报告经format_report包装后渲染情绪判断为中性。最终报告包含股票概况、新闻解读、投资建议谨慎持有逢低分批布局、风险提示监管、竞争、创新周期、估值、宏观五大类四个完整章节并通过save_report保存为 Markdown 文件。第二个演示NVDA同样跑通且其报告被判为看涨。这个演示还暴露出两个真实的工程边界值得读者注意工具链不稳定是常态duckduckgo_search包已改名为ddgs运行时出现RuntimeWarningDuckDuckGo 与 Yahoo Finance 都可能因网络/反爬返回异常。本项目的应对策略是工具层 try/except 返回错误串、智能体层把错误当作 Observation 继续循环、LLM 依据既有信息兜底成文——这种容错设计恰恰是生产级 Agent 与玩具 Demo 的分水岭解析格式漂移从 NVDA 的运行日志可见LLM 偶尔会输出不带换行的THOUGHT:/ACTION:大写串或一次性输出多步内容_parse_output的多模式正则正是为此设计的兜底。八、源码级原理ReAct 循环与 HelloAgents 组件如何协作要深入理解 FinReportAgent 的每一层可以把本项目与本书框架源码对照阅读ReAct 循环骨架基础版的推理-行动-观察循环见 code/chapter4/ReAct.py 的ReActAgent.run()其_parse_output/_parse_action只支持严格的英文格式这正是 FinReportAgent 需要重写的根源LLM 统一调用code/chapter4/llm_client.py 的HelloAgentsLLM展示了框架如何统一管理LLM_MODEL_ID/LLM_API_KEY/LLM_BASE_URL/LLM_TIMEOUT环境变量并基于 OpenAI 兼容客户端做流式调用框架内标准用法code/chapter7/my_react_agent.py 的MyReActAgent展示了ReActAgentToolRegistrycustom_promptmax_steps的规范组合方式FinReportAgent 的run()结构几乎与其一一对应只是针对金融场景定制了提示词与输出解析工具抽象Tool/ToolParameter的声明参数 run 执行契约让ToolRegistry能够统一完成注册、描述生成get_tools_description与执行execute_toolLLM 无需感知任何实现细节。从整个 HelloAgents 教程的知识脉络看见 docs/chapter7/Chapter7-Building-Your-Agent-Framework.mdFinReportAgent 是框架学完之后做领域应用的典型范例它没有引入新的框架概念而是通过定制工具集 定制提示词 增强解析器三个抓手把通用 Agent 快速改造成金融垂直智能体。九、总结与可复用清单FinReportAgent 在 HelloAgents 社区项目中示范了一条可复制的领域智能体落地路径核心经验可归纳为数据源工具化把每个外部数据源行情、新闻、搜索封装为带参数声明的Tool统一由ToolRegistry管理鲁棒解析针对中文/全角符号/大小写漂移重写_parse_output与_parse_action这是对接国产大模型如 DeepSeek的必备改造提示词即产品通过固定工作流、章节约束与 few-shot 示例让 LLM 输出结构稳定的专业报告规则兜底情绪判断、报告格式化用确定性规则实现成本低、可解释、易测试容错设计工具层异常不外抛、智能体层把错误当 Observation 继续循环保证演示流程不中断。如需复现或改造直接运行 Co-creation-projects/kkkano-FinReportAgent/main.ipynb 即可将该智能体扩展为其他领域如舆情分析、行业研究只需替换工具集与提示词模板框架层代码无需改动。⚠️ 提示本项目的报告由 AI 自动生成仅供技术学习与演示不构成任何投资建议。金融市场存在风险投资决策前请咨询专业顾问。【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表