跳转到内容

OBBject 与 LLM 数据管道

学习目标

理解 OBBject 如何通过 to_llm() 方法将异构金融数据转换为 LLM 可消费的 JSON 格式,以及这条数据管线在 AI Agent 场景中的价值。


项目实践

OBBject 的核心定位

OBBject(OpenBB Object)是 OpenBB 平台所有数据操作的统一返回类型。它是一个泛型 Pydantic 模型,承载了:

  • results:序列化的数据结果(类型 T
  • provider:数据来源标识
  • warnings:警告列表
  • chart:图表对象
  • extra:额外元数据
openbb_core/app/model/obbject.py
class OBBject(Tagged, Generic[T]):
"""OpenBB object."""
results: T | None = Field(default=None, description="Serializable results.")
provider: str | None = Field(default=None, description="Provider name.")
warnings: list[Warning_] | None = Field(default=None, description="List of warnings.")
chart: Chart | None = Field(default=None, description="Chart object.")
extra: dict[str, Any] = Field(default_factory=dict, description="Extra info.")

to_llm() 方法解析

OBBject 提供了 to_llm() 方法,专门用于将结果转换为 LLM 友好的格式:

openbb_core/app/model/obbject.py
def to_llm(self) -> dict[Hashable, Any] | list[dict[Hashable, Any]]:
"""Convert results field to an LLM compatible output."""
df = self.to_dataframe(index=None)
results = df.to_json(
orient="records", # [{"col1": val1}, {"col1": val2}, ...]
date_format="iso", # ISO 8601 日期格式
date_unit="s", # 秒级时间戳
)
return results

关键设计决策

参数作用为什么适合 LLM
orient="records"输出为对象数组LLM 天然理解 JSON 对象列表
date_format="iso"ISO 8601 格式标准化日期,LLM 训练数据中常见
date_unit="s"秒级精度避免微秒级冗余信息干扰上下文

完整数据管线

从金融数据查询到 LLM 消费的完整管线:

LLM 场景示例

from openbb import obb
# 1. 获取股票历史数据
output = obb.equity.price.historical("AAPL", provider="yfinance")
# 2. 转换为 LLM 格式
llm_data = output.to_llm()
# 输出: '[{"date":"2025-01-01","open":230.1,"high":232.5,...}, ...]'
# 3. 送入 LLM 分析
prompt = f"""分析以下 AAPL 股票最近 30 天的价格走势,给出投资建议:
{llm_data}"""

问题与规避

大数据量导致上下文溢出

  • to_llm() 默认返回全部记录,超过 LLM 上下文窗口时会截断
  • 对策:先用 to_dataframe() 做聚合/采样,再转 JSON:
    df = output.to_dataframe()
    summary = df[["date", "close", "volume"]].tail(30) # 只取最近 30 天
    llm_data = summary.to_json(orient="records")

嵌套结构丢失语义

  • to_llm() 将复杂对象展平为 JSON,可能丢失字段间的语义关联
  • 对策:在 extra 中附加元数据:
    llm_data = {
    "metadata": {"symbol": "AAPL", "provider": "yfinance"},
    "data": output.to_llm()
    }

设计取舍

为什么选择 orient="records" 而非 orient="columns"

  • records 格式(对象数组)更符合 LLM 对表格数据的理解方式
  • columns 格式(字典的字典)在 LLM prompt 中可读性较差

为什么先转 DataFrame 再转 JSON

  • OBBject.results 可能是 List[BaseModel]DictList[Dict] 等多种格式
  • DataFrame 是统一的中间表示,to_json() 已高度优化

参考来源

  • 源码验证: openbb_core/app/model/obbject.py — OBBject 完整实现
  • 源码验证: openbb_core/provider/abstract/data.py — Data 基类