【Langchian】 一个基础案例手把手带你上线自己的Langchian专属智能体

362 阅读13分钟

🟡 一:任务分解与LangChain思想

image.png

  • 理解用户需求,分解任务。
  • 灌输LangChain的核心思想,明确为何用它。
  • 搭建框架基础,准备工具集。

🔘 步骤1:理解与分解用户需求

你的任务是:“把2025年唐山市税收规模前十的企业做成一个饼状图,数据有异常的需要进行清洗。然后还要生成一个Word报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。”

作为一个非技术背景的用户,你可能习惯用GUI手动操作(打开PDF找数据、复制到Excel、运行ArcGIS工具等)。但这种方式效率低,且无法自动化。AI的目标是把这些步骤变成代码,能动态选择工具、串联任务,让整个流程像“智能助手”一样响应你的自然语言。

任务分解

  1. 数据获取
    • 税收数据:从“Tangshan_2025_Tax_Report.pdf”提取2025年唐山税收前十企业(本地RAG)。
    • 碳排放数据:从MySQL数据库查询这些企业的经纬度与碳排放(Text-to-SQL)。
  2. 数据处理
    • 将数据整合为表格(企业名、税收、经纬度、碳排放)。
    • 清洗异常值(如负值、超出范围的经纬度),排序取前十。
    • 生成税收饼图。
  3. 空间分析
    • arcpy将经纬度转为shp点。
    • 生成碳排放插值图(含图例、指南针)。
  4. 报告生成
    • 创建Word文档,插入饼图和插值图。
    • 用LLM分析空间分布并生成建议。

🔘步骤2:LangChain的核心思想

为什么用LangChain?

  • 单一API的局限
    • arcpy只能做空间分析,无法处理PDF或Word。
    • Excel VBA擅长表格处理,但无法生成插值图。
    • 手动串联这些API需要大量“胶水代码”(如文件读写、格式转换),费时费力。
  • LangChain的优势
    1. 工具集成:将每个API(如PDF解析、arcpy、Word操作)封装为“Tool”,统一调用。
    2. 任务编排:Agent像大脑一样,自动决定调用顺序(如先提取数据、再清洗、再分析)。
    3. 自然语言驱动:你说一句话,Agent自己分解任务,无需写完整脚本。

🔘步骤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报告,并且报告里还要有这前十企业的碳排放点数据做成空间分布插值图,当然之前的饼状图也需要放里面,还要进行分析。"
    }
    
  • 响应:返回报告路径或执行结果。