第六练:基于 LLM 的"叙事经济学"量化分析系统
课程目标:从零构建一个能够读取金融新闻、量化市场叙事、并支持结构化数据输出的 AI 系统。 适用人群:金融科技开发者、量化研究员、数据分析师。 核心代码库:
sentiment.py(基于 LangChain)
1. 背景与痛点
1.1 什么是叙事经济学?
核心理论:引用诺奖得主 Robert Shiller 的《叙事经济学》。他认为市场波动不仅源于数据(如利率、财报),更源于**"故事(Narrative)"**在社会中的传播。
量化难题:
- K 线是"结果":价格波动是果,叙事是因。
- 传统 NLP 的局限:基于词频统计(Bag of Words)的方法无法理解语境。例如,"利空出尽是利好"这句话,传统模型看到"利空"会判负面,而 LLM 能理解这是正面信号。
1.2 我们的解决方案
- 输入:非结构化的每日财经新闻流。
- 核心引擎:利用 LLM(Large Language Model)的语义理解能力 + 结构化输出技术。
- 输出:结构化数据(JSON) —— 这是本练重点。只有将模糊的文字转化为结构化的表格数据,才能存入数据库,才能进行回测。
2. 数据契约与提示词工程
2.1 定义"模具":Pydantic Data Model
在让 AI 工作前,必须先定义"输出长什么样"。我们使用 Python 的 Pydantic 库充当数据契约。这不仅是定义数据,更是对 AI 的一种约束。
from pydantic import BaseModel, Field
from typing import List
class IndustrySignalSummary(BaseModel):
"""单个行业的每日信号摘要"""
industry_name: str = Field(description="行业名称")
# 强制要求列表格式,且必须提取实质性内容
positive_signals: List[str] = Field(description="实质性利好信号(如补贴、增长),忽略空话")
negative_signals: List[str] = Field(description="实质性利空信号(如处罚、下滑)")
daily_signal_bullet_points: List[str] = Field(description="3-5条核心要点摘要")
class PolicyAttribution(BaseModel):
"""政策归因:解决可解释性问题"""
key_event: str
quote_text: str = Field(description="必须引用原文,作为证据")
class ReportRiskAnalysis(BaseModel):
"""最终输出的完整报告结构"""
industry_signal_summaries: List[IndustrySignalSummary]
# 强制约束分数在 0-100 之间,防止 AI 产生幻觉数值
daily_macro_sentiment_score: int = Field(ge=0, le=100, description="0-100分,50为中性")
# 关键:要求 AI 提供原文证据
key_policy_attributions: List[PolicyAttribution]
2.2 提示词工程(Prompt Engineering)
- Role(角色):Quantitative Financial Analyst(激活模型的金融领域权重,让它像分析师一样思考)。
- Constraints(约束):明确要求 "Ignore generic slogans"(过滤噪音)。
- Evidence(证据):要求 "Quote specific wording"(引用原文)。这是解决大模型幻觉的核心手段——没有证据,就不准打分。
3. 核心技术深度解析——三种输出策略
这是本系统的核心架构。我们在 sentiment.py 中实现了三种不同的 Agent,代表了 LLM 应用开发的三个阶段。我们将从 API 原理、稳定性和适用场景三个维度进行对比。
3.1 策略一:ProviderAgent(Native Structured Output)
【推荐方案】 利用模型厂商(OpenAI/Anthropic)底层的原生 JSON 模式。
# 直接将 Pydantic 类传给 response_format
self.agent = create_agent(
model=self.model,
response_format=ReportRiskAnalysis
)
- 技术原理:LangChain 将 Pydantic 类转换为 JSON Schema,通过 API 的
response_format参数传递给模型。 - 底层约束:模型在推理层(Inference Layer)被强制约束。如果模型想生成一个不符合格式的字符(例如在
int字段生成字母),会被底层引擎直接屏蔽。
3.2 策略二:ToolAgent(Tool/Function Calling)
【通用/兼容方案】 利用 LLM 的"工具调用"能力来"截获"结构化数据。
from langchain.agents.structured_output import ToolStrategy
# 将 Schema 包装为一个"工具策略"
self.agent = create_agent(
model=self.model,
response_format=ToolStrategy(ReportRiskAnalysis)
)
- 技术原理(核心:参数截获 Intercept):我们告诉 LLM 有一个函数叫
submit_report(score, signals...),必须填对参数才能提交分析报告。LLM 分析完文本后,为了"调用"这个工具,它会生成一段标准的 JSON 参数(例如{"score": 80, "signals": [...]})。
3.3 策略三:UnstructuredAgent(Freeform Text)
【对照组方案】 传统的聊天模式。
response_format=None # 不限制格式
3.4 三种策略对比
| 维度 | ProviderAgent | ToolAgent | UnstructuredAgent |
|---|---|---|---|
| 格式控制 | response_format=Pydantic模型 | response_format=ToolStrategy(schema) | response_format=None |
| 格式准确率 | 最高,输出与 Schema 严格一致 | 较高,跨模型兼容性更好 | 最低,输出格式完全自由 |
| 依赖 | 依赖模型原生支持 | 独立于特定 Provider | 无依赖 |
| 灵活性 | 较低 | 中等,需要更多提示工程 | 最高 |
| 后处理 | 无需 | 少量 | 需要后处理解析 |
结构化输出与模型能力的权衡
- 约束导致能力下降:与自由文本生成相比,强制模型生成结构化输出(尤其是 JSON)会导致推理能力显著下降。
- 约束越强,下降越多:格式限制越严格(如必须符合特定的 JSON Schema),模型的任务表现通常越差。
- 原因:格式约束限制了模型的"生成空间",使得模型不得不分配注意力去满足格式要求,从而挤压了进行深度推理(Chain-of-Thought)的空间。
4. 应用场景与扩展方向
4.1 量化策略集成
-
行业轮动(Industry Rotation):统计 JSON 中
positive_signals频次。- 策略:做多"利好叙事"最强的行业,做空"利空叙事"最强的行业。
-
风险预警(Risk Alert):当
sentiment_score < 40且negative_signals激增时。- 策略:触发风控系统的自动减仓逻辑,或发送邮件给交易员。
4.2 扩展方向
- 多模态(Multimodal):不仅读文字,还要用 GPT-4o 读新闻配图(如会议现场图)、K 线图。
- 实时流(Streaming):接入 Kafka/News API,将
batch_process改为实时事件驱动。实现毫秒级信号推送:新闻发出 → LLM 分析 → 交易信号。 - 知识图谱(Knowledge Graph):将提取的 Policy → Industry 关系存入图数据库。挖掘隐形的政策传导链(例如:A 行业的补贴如何传导至 B 行业)。
📋 小结
| 步骤 | 内容 | 关键技术 |
|---|---|---|
| 1 | 叙事经济学背景 | LLM 语义理解 vs 传统 NLP |
| 2 | 数据契约定义 | Pydantic BaseModel + Field 约束 |
| 3 | 三种输出策略 | Provider / Tool / Unstructured |
| 4 | 应用与扩展 | 行业轮动、风险预警、多模态 |
掌握结构化输出技术后,你就能将 LLM 的分析能力转化为可量化、可回测的数据资产!🚀