( 教学 )Agent 构建 Prompt(提示词)5. PandasDataFrameOutPutParser
LLM 的输出以 pd.DataFrame 格式进行控制。
“Pandas”是一个软件包,以表格(即表格数据)的形式存在,深受数据科学家的青睐。它能帮助您进行数据的探索、清理和处理。
若想进一步了解 pd.DataFrame 及其功能,请访问 Pandas 官方教程之一,即 10 分钟学会 Pandas 。
-
这既可以作为将结构化输出转换为 LLM 查询的字符串形式,也可以作为将结构化输入提供给 LLM 查询的形式
-
作为输入,可以使用
pd.DataFrame数据集,使 LLM 与数据进行交互。 “本教程的目标” 了解PandasDataFrameOutputParser是如何用于与pd.DataFrame进行交互的。 数据采集 -
可访问figshare.com网站,可以在该网站上找到各类学术研究的成果,包括从 CSV 格式到 PDF 格式的文件。
定义大模型
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from dotenv import load_dotenv
import os
load_dotenv()
Qwen2_5_7B_Instruct_llm = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
)
定义输出模型
import pandas as pd
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
class DataFrameResponse(BaseModel):
"""期望 LLM 返回表格数据"""
dataframe: list[dict] = Field(..., description="表格数据,每行是一个字典")
model = Qwen2_5_7B_Instruct_llm.with_structured_output(DataFrameResponse)
response = model.invoke("列出前5个最大哺乳动物及其特征")
df = pd.DataFrame(response.dataframe)
不适用模型的情况
format_parser_output函数用于将解析器输出转换为字典格式并格式化输出。- 当输入为
pd.DataFrame或文件时。
def format_parser_output(parser_output: Dict[str, Any]) -> None:
length_val = len(list(parser_output.values()))
if length_val == 1 and isinstance(parser_output.values, (int, float)):
return {"result": parser_output}
# 遍历解析器输出(字典)的"键"
else:
for key in parser_output.keys():
parser_output[key] = parser_output[key].to_dict()
# 美化打印
return pprint.PrettyPrinter(width=4, compact=True).pprint(parser_output)
我们使用模拟数据来演示:
- 由于
titanic.csv数据在类似教程中被反复使用,显得有些单调 - 所以从 figshare.com 获取数据
df = pd.read_csv("./data/Air-Traffic-Passenger-Statistics-csv.csv")
df.head()
输出结构
- 数据框的前五行
- 包含所有列的前五行数据
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
| Activity Period | Activity Period Start Date | Operating Airline | Operating Airline IATA Code | Published Airline | Published Airline IATA Code | GEO Summary | GEO Region | Activity Type Code | Price Category Code | Terminal | Boarding Area | Passenger Count | data_as_of | data_loaded_at | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 199907 | 1999/07/01 | ATA Airlines | TZ | ATA Airlines | TZ | Domestic | US | Deplaned | Low Fare | Terminal 1 | B | 31432 | 2023/11/20 07:01:34 AM | 2023/11/20 07:02:25 AM |
| 1 | 199907 | 1999/07/01 | ATA Airlines | TZ | ATA Airlines | TZ | Domestic | US | Enplaned | Low Fare | Terminal 1 | B | 31353 | 2023/11/20 07:01:34 AM | 2023/11/20 07:02:25 AM |
| 2 | 199907 | 1999/07/01 | ATA Airlines | TZ | ATA Airlines | TZ | Domestic | US | Thru / Transit | Low Fare | Terminal 1 | B | 2518 | 2023/11/20 07:01:34 AM | 2023/11/20 07:02:25 AM |
| 3 | 199907 | 1999/07/01 | Aeroflot Russian International Airlines | NaN | Aeroflot Russian International Airlines | NaN | International | Europe | Deplaned | Other | Terminal 2 | D | 1324 | 2023/11/20 07:01:34 AM | 2023/11/20 07:02:25 AM |
| 4 | 199907 | 1999/07/01 | Aeroflot Russian International Airlines | NaN | Aeroflot Russian International Airlines | NaN | International | Europe | Enplaned | Other | Terminal 2 | D | 1198 | 2023/11/20 07:01:34 AM | 2023/11/20 07:02:25 AM |
import pandas as pd
from typing import Dict, Any
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
class CSVAnalyzer:
def __init__(self, model_name="Qwen2.5-7B-Instruct"):
self.model = Qwen2_5_7B_Instruct_llm
def analyze_csv(self, csv_data: str, question: str) -> Dict[str, Any]:
"""完整CSV分析器"""
df = pd.read_csv(pd.compat.StringIO(csv_data))
prompt = ChatPromptTemplate.from_template("""
CSV数据概览:
- 行数:{row_count}
- 列数:{col_count}
- 列名:{columns}
- 数据预览:
{preview}
完整数据:
{csv_data}
问题:{question}
请提供:
1. 分析结果
2. 可视化建议
3. 业务洞察
""")
result = prompt | self.model | StrOutputParser()
response = result.invoke({
"row_count": len(df),
"col_count": len(df.columns),
"columns": ", ".join(df.columns),
"preview": df.head(3).to_string(),
"csv_data": csv_data,
"question": question
})
return {
"dataframe": df,
"analysis": response,
"summary_stats": df.describe()
}
# 使用
analyzer = CSVAnalyzer()
csv_data = df.to_csv(index=False)
result = analyzer.analyze_csv(csv_data, "分析薪资分布和城市关系")
print(result["analysis"])