🟡 一:任务分解与LangChain思想
- 理解用户需求,分解任务。
- 灌输LangChain的核心思想,明确为何用它。
- 搭建框架基础,准备工具集。
🔘 步骤1:理解与分解用户需求
你的任务是:“把2025年唐山市税收规模前十的企业做成一个饼状图,数据有异常的需要进行清洗。然后还要生成一个Word报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。”
作为一个非技术背景的用户,你可能习惯用GUI手动操作(打开PDF找数据、复制到Excel、运行ArcGIS工具等)。但这种方式效率低,且无法自动化。AI的目标是把这些步骤变成代码,能动态选择工具、串联任务,让整个流程像“智能助手”一样响应你的自然语言。
任务分解:
- 数据获取:
- 税收数据:从“Tangshan_2025_Tax_Report.pdf”提取2025年唐山税收前十企业(本地RAG)。
- 碳排放数据:从MySQL数据库查询这些企业的经纬度与碳排放(Text-to-SQL)。
- 数据处理:
- 将数据整合为表格(企业名、税收、经纬度、碳排放)。
- 清洗异常值(如负值、超出范围的经纬度),排序取前十。
- 生成税收饼图。
- 空间分析:
- 用
arcpy将经纬度转为shp点。 - 生成碳排放插值图(含图例、指南针)。
- 用
- 报告生成:
- 创建Word文档,插入饼图和插值图。
- 用LLM分析空间分布并生成建议。
🔘步骤2:LangChain的核心思想
为什么用LangChain?
- 单一API的局限:
arcpy只能做空间分析,无法处理PDF或Word。- Excel VBA擅长表格处理,但无法生成插值图。
- 手动串联这些API需要大量“胶水代码”(如文件读写、格式转换),费时费力。
- LangChain的优势:
- 工具集成:将每个API(如PDF解析、
arcpy、Word操作)封装为“Tool”,统一调用。 - 任务编排:Agent像大脑一样,自动决定调用顺序(如先提取数据、再清洗、再分析)。
- 自然语言驱动:你说一句话,Agent自己分解任务,无需写完整脚本。
- 工具集成:将每个API(如PDF解析、
🔘步骤3:搭建LangChain框架
from langchain.agents import Tool, initialize_agent (基本不用了)
from langchain.llms import OpenAI
# 初始化大语言模型
llm = OpenAI(temperature=0, api_key="YOUR_API_KEY")
# 定义工具集(后续详细实现)
tools = [
# Tool 1: 从PDF提取税收数据
# Tool 2: 从数据库查询碳排放
# Tool 3: 清洗数据并生成饼图
# Tool 4: 生成插值图
# Tool 5: 生成Word报告
]
# 初始化Agent(管家)
agent = initialize_agent(
tools=tools,
llm=llm,
agent="zero-shot-react-description", # 一种Agent参数
verbose=True # 打印执行过程,方便学习
)
# 用户指令
response = agent.run("帮我把2025年唐山市税收规模前十的企业做成一个饼状图,数据有异常的需要进行清洗。然后还要生成一个Word报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。")
print(response)
🔘initialize_agent 与 create_xxx_agent
initialize_agent 方法(早期/传统方式)
- 高级封装:提供了一个简单的入口点,通过字符串参数选择Agent类型
- 使用方式:通过
agent="zero-shot-react-description"这样的参数指定Agent类型 - 内部操作:在底层,它实际上创建了相应的Agent并包装在AgentExecutor中
- 便利性:适合快速开发,不需要了解底层实现细节
agent = initialize_agent(
tools=tools,
llm=llm,
agent="zero-shot-react-description",
verbose=True
)
create_xxx_agent + AgentExecutor 方法(新方式)
- 更明确的类型:类型直接体现在函数名中(如
create_react_agent) - 更灵活:允许您自定义提示模板(prompt),调整语气、逻辑等
- 分离关注点:先创建Agent,再用AgentExecutor执行
- 代码更清晰:明确表明使用的是哪种Agent策略
from langchain.agents import create_react_agent, AgentExecutor
# 创建Agent
agent = create_react_agent(
llm=llm,
tools=tools,
prompt=custom_prompt # 可以自定义prompt,这也是最关键的地方
)
# 创建执行器
agent_executor = AgentExecutor(agent=agent, tools=tools)
initialize_agent是一个便捷封装,返回的实际上也是一个AgentExecutor。新的create_xxx_agent方法更符合现代编程风格,将Agent创建和执行分开,更清晰。从功能上讲,两种方式都能实现相同的结果,但新方式提供了更多的自定义能力
🟡 二:数据获取与清洗
- 实现从PDF提取税收数据(本地RAG)。
- 从MySQL查询碳排放数据(Text-to-SQL)。
- 清洗数据并生成饼状图。
- 灌输工具设计与调试的思想。
🔘步骤1:从PDF提取税收前十企业(本地RAG)
从“Tangshan_2025_Tax_Report.pdf”提取2025年唐山税收前十企业。需要用RAG先检索内容,再让LLM提取关键信息。
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import RetrievalQA
def extract_top10_from_pdf(query):
# 私域知识导入
loader = PyPDFLoader("Tangshan_2025_Tax_Report.pdf")
documents = loader.load() # 读取PDF每一页为一个Document对象
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0) # 分割策略
texts = text_splitter.split_documents(documents) # 开始分割对象
# 创建向量数据库
embeddings = OpenAIEmbeddings(api_key="YOUR_API_KEY") #嵌入模型
vectorstore = FAISS.from_documents(texts, embeddings) #文本转为向量入向量库
# 用RetrievalQA检索并提取
qa = RetrievalQA.from_chain_type( #Langchian自带的RAG链
llm=OpenAI(temperature=0, api_key="YOUR_API_KEY"),
chain_type="stuff",
retriever=vectorstore.as_retriever()
)
result = qa.run("Extract the top 10 enterprises by tax revenue in Tangshan 2025")
# 假设返回格式:企业名,税收\n企业名,税收...
top10 = [line.split(',')[0] for line in result.split('\n') if line] # 提取企业名
return top10[:10] # 确保返回10个
# 测试
# print(extract_top10_from_pdf("test"))
🔘步骤2:从MySQL查询碳排放数据(Text-to-SQL)
根据前十企业名,从MySQL查询经纬度和碳排放数据。因为数据库是结构化数据,AI无法直接读。我们用Text-to-SQL让LLM生成SQL语句,自动查询。
from langchain.sql_database import SQLDatabase
from langchain.chains import SQLDatabaseChain
def query_carbon_emissions(top10_companies):
# 连接数据库
db = SQLDatabase.from_uri("mysql+pymysql://user:password@localhost/tangshan_db")
# 创建SQL查询链
sql_chain = SQLDatabaseChain.from_llm(
llm=OpenAI(temperature=0, api_key="YOUR_API_KEY"),
database=db,
verbose=True # 打印生成的SQL,方便调试
)
# 生成查询(这是我手动写上了,其实LLM的Text2SQL就是自动生成这一句,下面就展示)
query = f"SELECT company_name, longitude, latitude, carbon_emission FROM enterprises WHERE company_name IN {tuple(top10_companies)}"
result = sql_chain.run(query)
# 转为DataFrame(假设返回列表套列表格式)
import pandas as pd
df = pd.DataFrame(result, columns=["company_name", "longitude", "latitude", "carbon_emission"])
return df
将其从“手动编写 SQL”改为真正的 Text-to-SQL 实现。
from langchain.sql_database import SQLDatabase # 导入用于连接数据库的模块
from langchain.chains import SQLDatabaseChain # 导入SQL查询链,用于将自然语言转为SQL
import pandas as pd # 导入pandas,用于处理查询结果为DataFrame
def query_carbon_emissions(top10_companies):
...前面不变
sql_chain = SQLDatabaseChain.from_llm( # SQLDatabaseChain 是 LangChain 提供的工具,将自然语言转为SQ
llm=OpenAI(temperature=0, api_key="YOUR_API_KEY"), # 建议温度为0,数据库不需要发散思维
database=db, # 数据库连接对象,提供数据库结构信息,LLM 根据此生成SQL
verbose=True # 会打印生成的SQL和执行过程,便于调试
)
# 用自然语言描述需求,LLM 会根据这句话和数据库结构生成对应的SQL语句
natural_language_query = (
f"Query the company_name, longitude, latitude, and carbon_emission "
f"from the enterprises table for these companies: {', '.join(top10_companies)}"
)
# 执行查询,sql_chain.run() 会将自然语言转为SQL,执行查询并返回结果
result = sql_chain.run(natural_language_query)
🔘步骤3:纯Py清洗数据并生成饼图
整合数据,清洗异常值如负值、无效经纬,按税收排序,生成饼状图。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def clean_and_pie_chart(df):
# 清洗异常值
df["carbon_emission"] = df["carbon_emission"].apply(lambda x: np.nan if x < 0 else x)
df["longitude"] = df["longitude"].apply(lambda x: np.nan if x < 0 or x > 180 else x)
df["latitude"] = df["latitude"].apply(lambda x: np.nan if x < -90 or x > 90 else x)
df.dropna(inplace=True) # 删除空值行
# 模拟税收数据(实际应从PDF提取,此处随机生成)
df["tax_revenue"] = np.random.rand(len(df)) * 1000
# 按税收排序,取前十
df = df.sort_values("tax_revenue", ascending=False).head(10)
# 生成饼图
plt.pie(df["tax_revenue"], labels=df["company_name"], autopct='%1.1f%%')
plt.title("Tangshan 2025 Top 10 Tax Revenue")
plt.savefig("tax_pie_chart.png")
plt.close() # 关闭图,避免内存占用
return df # 返回清洗后的数据框
# 测试
# df = pd.DataFrame({"company_name": ["A", "B"], "longitude": [114, 115], "latitude": [39, 40], "carbon_emission": [100, -5]})
# print(clean_and_pie_chart(df)) # 调试时取消注释
🔘步骤4:全部封装为LangChain工具
from langchain.agents import Tool
tools = [
Tool(
name="ExtractTop10",
func=extract_top10_from_pdf,
description="Extract the top 10 enterprises by tax revenue from a PDF report"
),
Tool(
name="QueryCarbon",
func=query_carbon_emissions,
description="Query carbon emission and location data for given companies from MySQL"
),
Tool(
name="CleanAndChart",
func=clean_and_pie_chart,
description="Clean data and generate a pie chart of tax revenue"
)
]
🟡 三:空间分析、报告生成与完整流程整合**
- 实现碳排放空间插值图(用
arcpy)。 - 生成Word报告(整合饼图、插值图和分析)。
- 整合所有工具,运行完整Agent。
- 灌输调试与优化的思想。
🔘步骤1:生成碳排放空间插值图(用arcpy)**
将企业经纬度转为shp点,生成碳排放插值图,包含图例和指南针。arcpy是ArcGIS Pro的Python接口,能在无GUI情况下运行空间分析。我们要把表格数据变成地图,就像手工画图,但全自动化。(Arcpy是闭源的哦,需要确保ArcGIS Pro已安装并激活,Python环境指向C:\Program Files\ArcGIS\Pro\bin\Python。)
import arcpy
def create_interpolation_map(df):
# 设置工作空间
arcpy.env.workspace = "C:/gis_data"
arcpy.env.overwriteOutput = True # 允许覆盖输出
# 将DataFrame的经纬度转为shp点
shp_path = "carbon_points.shp"
arcpy.management.XYTableToPoint( #把表格的经纬度转为shp点
in_table=df[["company_name", "longitude", "latitude", "carbon_emission"]],
out_feature_class=shp_path,
x_field="longitude",
y_field="latitude"
)
# 生成插值图(克里金法)
interpolation_path = "carbon_interpolation.tif"
arcpy.Kriging_3d(
in_point_features=shp_path,
z_field="carbon_emission",
out_surface_raster=interpolation_path,
cell_size=0.01 # 格网大小,可调整
)
# 制图并导出(假设有模板mxd)
mxd = arcpy.mapping.MapDocument("C:/gis_data/template.mxd") # 需准备带图例和指南针的模板
df_layer = arcpy.mapping.Layer(interpolation_path)
arcpy.mapping.AddLayer(mxd.activeDataFrame, df_layer, "TOP")
arcpy.mapping.ExportToPNG(mxd, "carbon_map.png")
del mxd # 释放资源
return "carbon_map.png"
# 测试
# import pandas as pd
# df = pd.DataFrame({"company_name": ["A", "B"], "longitude": [114, 115], "latitude": [39, 40], "carbon_emission": [100, 200]})
# print(create_interpolation_map(df)) # 调试时取消注释
🔘步骤2:生成Word报告(整合图表与分析)
创建Word文档,插入饼图和插值图,用LLM生成分析。我们用win32com控制Word。
import win32com.client
from langchain.llms import OpenAI
def generate_word_report(df, pie_chart_path, map_path):
# 初始化Word
word = win32com.client.Dispatch("Word.Application")
word.Visible = False # 后台运行,避免弹出窗口
doc = word.Documents.Add()
# 写入标题和内容
doc.Content.Text = "2025年唐山市税收前十企业分析报告\n\n"
doc.Content.InsertAfter("税收规模饼图:\n")
doc.InlineShapes.AddPicture(pie_chart_path) # 插入饼图
doc.Content.InsertAfter("\n\n碳排放空间分布插值图:\n")
doc.InlineShapes.AddPicture(map_path) # 插入插值图
# LLM分析
llm = OpenAI(temperature=0, api_key="YOUR_API_KEY")
analysis_prompt = f"Analyze the spatial distribution of carbon emissions for these companies: {df.to_dict()}"
analysis = llm(analysis_prompt + " Provide suggestions for reducing emissions.")
doc.Content.InsertAfter(f"\n\n分析与建议:\n{analysis}")
# 保存并关闭
doc.SaveAs("C:/gis_data/Tangshan_Report.docx")
word.Quit()
# 测试
# df = pd.DataFrame({"company_name": ["A", "B"], "carbon_emission": [100, 200]})
# generate_word_report(df, "tax_pie_chart.png", "carbon_map.png") # 调试时取消注释
🔘步骤3:整合所有工具并运行Agent**
完整代码:
from langchain.agents import Tool, initialize_agent
from langchain.llms import OpenAI
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.chains import RetrievalQA, SQLDatabaseChain
from langchain.sql_database import SQLDatabase
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import arcpy
import win32com.client
# 初始化LLM
llm = OpenAI(temperature=0, api_key="YOUR_API_KEY")
# 工具1:PDF提取
def extract_top10_from_pdf(query):
loader = PyPDFLoader("Tangshan_2025_Tax_Report.pdf")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings(api_key="YOUR_API_KEY")
vectorstore = FAISS.from_documents(texts, embeddings)
qa = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=vectorstore.as_retriever())
result = qa.run("Extract the top 10 enterprises by tax revenue in Tangshan 2025")
return [line.split(',')[0] for line in result.split('\n') if line][:10]
# 工具2:SQL查询
def query_carbon_emissions(top10_companies):
db = SQLDatabase.from_uri("mysql+pymysql://user:password@localhost/tangshan_db")
sql_chain = SQLDatabaseChain.from_llm(llm=llm, database=db, verbose=True)
query = f"SELECT company_name, longitude, latitude, carbon_emission FROM enterprises WHERE company_name IN {tuple(top10_companies)}"
result = sql_chain.run(query)
return pd.DataFrame(result, columns=["company_name", "longitude", "latitude", "carbon_emission"])
# 工具3:清洗与饼图
def clean_and_pie_chart(df):
df["carbon_emission"] = df["carbon_emission"].apply(lambda x: np.nan if x < 0 else x)
df["longitude"] = df["longitude"].apply(lambda x: np.nan if x < 0 or x > 180 else x)
df["latitude"] = df["latitude"].apply(lambda x: np.nan if x < -90 or x > 90 else x)
df.dropna(inplace=True)
df["tax_revenue"] = np.random.rand(len(df)) * 1000 # 模拟税收
df = df.sort_values("tax_revenue", ascending=False).head(10)
plt.pie(df["tax_revenue"], labels=df["company_name"], autopct='%1.1f%%')
plt.title("Tangshan 2025 Top 10 Tax Revenue")
plt.savefig("tax_pie_chart.png")
plt.close()
return df
# 工具4:插值图
def create_interpolation_map(df):
arcpy.env.workspace = "C:/gis_data"
arcpy.env.overwriteOutput = True
arcpy.management.XYTableToPoint(df[["company_name", "longitude", "latitude", "carbon_emission"]], "carbon_points.shp", "longitude", "latitude")
arcpy.Kriging_3d("carbon_points.shp", "carbon_emission", "carbon_interpolation.tif", cell_size=0.01)
mxd = arcpy.mapping.MapDocument("C:/gis_data/template.mxd")
df_layer = arcpy.mapping.Layer("carbon_interpolation.tif")
arcpy.mapping.AddLayer(mxd.activeDataFrame, df_layer, "TOP")
arcpy.mapping.ExportToPNG(mxd, "carbon_map.png")
del mxd
return "carbon_map.png"
# 工具5:Word报告
def generate_word_report(df, pie_chart_path, map_path):
word = win32com.client.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Add()
doc.Content.Text = "2025年唐山市税收前十企业分析报告\n\n"
doc.Content.InsertAfter("税收规模饼图:\n")
doc.InlineShapes.AddPicture(pie_chart_path)
doc.Content.InsertAfter("\n\n碳排放空间分布插值图:\n")
doc.InlineShapes.AddPicture(map_path)
analysis = llm(f"Analyze the spatial distribution of carbon emissions for these companies: {df.to_dict()} Provide suggestions.")
doc.Content.InsertAfter(f"\n\n分析与建议:\n{analysis}")
doc.SaveAs("C:/gis_data/Tangshan_Report.docx")
word.Quit()
# 定义工具集
tools = [
Tool(name="ExtractTop10", func=extract_top10_from_pdf, description="Extract top 10 enterprises by tax revenue from PDF"),
Tool(name="QueryCarbon", func=query_carbon_emissions, description="Query carbon emission and location data from MySQL"),
Tool(name="CleanAndChart", func=clean_and_pie_chart, description="Clean data and generate a pie chart"),
Tool(name="CreateInterpolation", func=create_interpolation_map, description="Generate carbon emission interpolation map"),
Tool(name="GenerateReport", func=generate_word_report, description="Generate Word report with charts and analysis")
]
# 初始化Agent
agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
# 运行用户指令
response = agent.run("帮我把2025年唐山市税收规模前十的企业做成一个饼状图,数据有异常的需要进行清洗。然后还要生成一个Word报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。")
print(response)
🟡 四:使用 LangServe 发布为 API
🔘 步骤 1:安装 LangServe
pip install langserve fastapi uvicorn
🔘 步骤 2:修改代码为可服务化
# app.py
from langchain.agents import create_react_agent, AgentExecutor
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langserve import add_routes
from fastapi import FastAPI
# 初始化 LLM(略)
llm = OpenAI(temperature=0, api_key="YOUR_API_KEY")
# 工具定义(略)
# extract_top10_from_pdf, query_carbon_emissions, clean_and_pie_chart,
# create_interpolation_map, generate_word_report 保持不变
tools = [ 略 ]
# 创建 Agent(修改为 create_react_agent)
prompt = PromptTemplate.from_template(
"任务:{task}。按步骤执行:1.提取税收数据;2.查询碳排放;3.清洗并生成饼图;4.生成插值图;5.生成报告并返回报告路径。"
)
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 创建 FastAPI 应用并添加路由
app = FastAPI(title="Tangshan Tax and Carbon Analysis API")
add_routes(app, agent_executor, path="/analyze")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
🔘 步骤 3:运行服务
python app.py
- 服务启动后,可通过
http://localhost:8000/analyze访问。
🔘 步骤 4:测试 API
- 端点:
POST /analyze - 请求示例:
{ "input": "帮我把2025年唐山市税收规模前十的企业做成一个饼状图,数据有异常的需要进行清洗。然后还要生成一个Word报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。" } - 响应:返回报告路径或执行结果。