【山东大学项目实训FinAgent】组合经理阶段怎么做:设计、实现逻辑与报告输出
FinAgent组合经理阶段怎么做:设计、实现逻辑与报告输出
摘要:组合经理(
portfolio_manager)是FinAgent单股分析流水线的倒数第二个业务阶段,位于风控评审之后、组合报告之前。它在Risk Judge终稿与规则风险基线之上,由LLM给出五档投资组合评级(Buy/Overweight/Hold/Underweight/Sell)及执行摘要、投资论点等叙事,并与技术面、情绪、风险等结构化字段合并为final_conclusion(最终结论)。本文说明该节点的设计约定、实现逻辑、兜底策略,以及结果如何进入report_json、Markdown 与前端展示。关键词:FinAgent;LangGraph;组合经理
一、组合经理在流水线中做什么
主图顺序(server/finagent/graph/runner.py):
analyst→research_debate→trader→risk_review→portfolio_manager→build_report
| 阶段 | 职责 | 主要产出 |
|---|---|---|
| risk_review(上游) | 风控辩论+Risk Judge审议交易员方案 | final_trade_decision、risk_section、risk_debate_state |
| portfolio_manager(本文重点) | 在风控结论之上,站在整个组合的角度做五档评级+执行摘要 | portfolio_output→final_conclusion |
| build_report(下游) | 把所有内容打包成网页和PDF | report_json、Markdown |
对照投研分工:交易员提方案,风控审议并给出裁决终稿,组合经理再从资产配置、仓位与执行节奏等角度给出评级与摘要。
二、设计思路:输入、输出与上下游衔接
2.1 设计原则
- 汇总上游,不重复拉数:不再访问行情接口,主要阅读交易员方案、风控裁决与辩论、三份分析师报告。
- 结构化骨架 + LLM 叙事:先用规则字段生成标题、风险摘要等固定结构,AI再往里填评级和长文,避免报告格式混乱。
- 评级必须可解析:Prompt要求AI明确写Buy/Hold/Sell等词,代码用
_extract_rating从正文中抽取,供评分卡与Markdown使用。 - LLM 失败可降级:模型不可用或报错时,自动降级为HOLD+简短说明,保证整条分析线不会卡,进入最终报告。
2.2 输入字段
portfolio_manager_node从共享状态state读取:
| 字段 | 来源 | 用途 |
|---|---|---|
ticker/analysis_date |
用户创建分析任务时传入 | 写入Prompt,标明标的(股票代码)与日期 |
trader_investment_plan |
trader |
交易员方案 |
final_trade_decision/risk_debate_state.judge_decision |
risk_review |
Risk Judge裁决的正文 |
risk_debate_state.history |
risk_review |
风控辩论全文(截断后传入) |
risk_section |
risk_review |
risk_level、risk_score(风险分数、等级)等 |
三份 *_report |
analyst |
证据材料,默认最多12000字符,太长会截断 |
组合经理的输入=交易员方案+风控裁决与辩论+规则风险分+三份分析师报告+部分结构化技术面/情绪字段。
2.3 输出字段
| 字段 | 类型 | 说明 |
|---|---|---|
portfolio_output |
对象 | 本阶段总包裹;含llm(表明是否走通了LLM)、portfolio_narrative(大模型生成的完整文本内容) |
portfolio_output.final_conclusion |
对象 | 写入report_json.final_conclusion的主结构,组合经理输出的核心业务数据结构,是整份研报最终综合结论的数据源 |
final_conclusion.rating |
字符串 | 五档标准:BUY/OVERWEIGHT/HOLD/UNDERWEIGHT/SELL(解析失败默认 HOLD) |
final_conclusion.llm_narrative |
字符串 | 大模型完整投资论述(包含执行摘要、投资逻辑、组合配置建议,全文最长约8000字符),前端组合经理部分的展示 |
final_conclusion.headline 等 |
对象 | 规则自动生成,如:HIGH 风险 | 情绪=… |
memory_log |
字符串列表 | 日志记录,用来排查问题[portfolio_manager] LLM narrative或rule final_conclusion |
2.4 与下游的关系
build_report:若portfolio_output.final_conclusion存在,覆盖/写入report_json["final_conclusion"](最终报告部分);Markdown综合结论一节会展示headline、rating等。trading_signal(交易信号,如买入):仍在build_report中由final_trade_decision(风控阶段的最终裁决) 解析,不由组合经理评级直接映射。- Agent 评分卡:
agent_scorecards.portfolio_manager结合叙事文本、rating与risk_score给出展示分,标注prototype_shell(该模块属于原型壳功能,仅用于前端页面可视化展示,不能用于实盘交易、合规投研归档)。
三、实现逻辑
核心代码位于server/finagent/agents/managers/portfolio_manager.py:
3.1 LLM 主路径
使用深思考档(与Risk Judge同级),Prompt书写以下要点:
- 角色:组合经理,在Risk Judge裁决之后给出最终组合评级;
- 评级需要五选一:Buy/Overweight/Hold/Underweight/Sell;
- 输出结构(固定模块):Rating(评级)、Executive Summary(执行摘要,包含仓位、入场、风控、周期)、Investment Thesis(基于证据的投资论点);
- 输入材料:标的与日期、交易员方案、Judge 裁决(截断 6000)、风险基线、风控辩论(6000)、三份分析师报告(8000)。
调用成功后:
- 调用
generate_final_conclusion(tech, sentiment, risk)得到规则骨架,搭好报告的标准化结构; - 将LLM返回正文写入
fc["llm_narrative"],作为前端组合经理部分的展示正文,并用_extract_rating解析fc["rating"](评级),存入对应的存入final_conclusion.rating字段; - 返回
portfolio_output: { final_conclusion: fc, llm: True, portfolio_narrative: text },将封装阶段结果返回写入流水线状态。
3.2 评级提取(_extract_rating)
在LLM正文中按优先级搜索英文评级词(整词匹配):
UNDERWEIGHT→OVERWEIGHT→BUY→SELL→HOLD
均未命中则默认 HOLD。这样可以避免子串误匹配(例如先匹配OVERWEIGHT再匹配WEIGHT)。
3.3 规则兜底
当get_chat_model(获取模型)返回None,或invoke抛错的时候:
- 仍生成
generate_final_conclusion的报告标准结构骨架; rating固定为HOLD(持有);llm_narrative预填写简短英文模板(说明 LLM 不可用、建议暂缓加仓);portfolio_output.llm为**False**,标识本次结论不是LLM生成,是规则兜底产出;memory_log记[portfolio_manager] rule final_conclusion,日志说明该阶段触发了降级策略,方便排查模型、接口类故障。
流水线可继续执行build_report,不会出现组合经理阶段整段的缺失。
四、接入主图与阶段开关
主图节点_portfolio_node(runner.py)负责:
1.读取环境配置做阶段校验:从环境变量FINAGENT_ENABLED_STAGES读取当前开启的流水线阶段列表,如果列表里没有配置portfolio_manager,直接跳过本阶段,portfolio_output赋值为空对象,不会执行组合经理的 LLM、规则兜底等所有逻辑。
2.标记当前任务进度:调用mark_stage,把前端展示的任务执行进度更新为组合经理,用户可以在页面看到当前运行到哪一步。
3.执行业务核心函数:把全局流转的状态state转为字典传入,调用我们前面讲的portfolio_manager_node,执行LLM研判/规则兜底的逻辑,拿到处理结果portfolio_output。
4.结果回写全局状态:将portfolio_output写回AnalysisGraphState全局状态对象,下游build_report报告生成节点才能读取到组合经理产出的最终结论数据。
.env 完整流水线示例:
FINAGENT_ENABLED_STAGES=analyst,research_debate,trader,risk_review,portfolio_manager,build_report
五、报告输出与前端展示
5.1 写入report_json
build_report阶段逻辑(_build_report_node):
- 调用
generate_report_json(...)生成含技术面、新闻、风险等的基础 JSON(其中已含一份默认final_conclusion); - 若主图state 中存在
portfolio_output.final_conclusion,则用组合经理产出覆盖上面的report_json["final_conclusion"]; - 同时挂载
final_trade_decision、trading_signal、trader_*、risk_debate_state等字段; - 调用
build_agent_scorecards(report_json)生成各Agent评分卡。
| 字段 | 主要来源阶段 | 典型含义 |
|---|---|---|
trader_investment_plan |
交易员 | 交易方案原文 |
final_trade_decision |
风控 Risk Judge | 风控审议后的买/持/卖终稿 |
final_conclusion(含 rating) |
组合经理 | 五档组合评级+执行摘要/论点 |
trading_signal |
对final_trade_decision解析(build_report) |
页面买入/目标价等标签 |
5.2 Markdown导出
generate_report_markdown 在文末综合结论与辅助建议一节输出:
final_conclusion.headline、recommendation_style- 组合经理评级:
final_conclusion.rating - 另附Risk Judge终稿章节与 结构化的交易信号(来自
trading_signal)
5.3 前端展示
(1)组合经理(PortfolioManagerTab)
| 页面区域 | 数据来源 |
|---|---|
| 折叠的组合经理正文 | final_conclusion.llm_narrative或portfolio_narrative |
| 标题旁评级BUY/HOLD/… | final_conclusion.rating |
| 评分等小标签 | agent_scorecards.portfolio_manager |
(2)投资结论(InvestmentConclusion)
汇总展示final_conclusion.headline、风险要点、trading_signal标签,以及交易员/风控/组合经理三张下游评分卡——组合经理在此以评分与评级参与总览,而非重复全文。
5.4 Agent 评分卡
agent_scorecards.py对组合经理:
- 文本来源优先
final_trade_decision,否则llm_narrative; - 按
rating映射基础分(如BUY偏高、SELL偏低),再与风险分等加权; - 标注
prototype_shell:未部署完整组合约束、归因与实盘合规规则,仅展示用。
六、总结
FinAgent的组合经理阶段,在风控Judge终稿与规则风险基线之上,用一次深思考 LLM 调用产出五档评级与组合层叙事,并与规则生成的headline、风险摘要等合并为 final_conclusion。它在流水线中的角色是研究—交易—风控之后的最后一环业务 Agent,再把结果交给build_report统一出报告与评分卡。
往期:
【山东大学项目实训FinAgent】风控评审阶段怎么做:设计、实现逻辑与报告输出
【山东大学项目实训FinAgent】 交易员阶段:设计、实现逻辑与报告输出
更多推荐


所有评论(0)