以下教程介绍如何在单机环境(CPU或1~2张GPU)上,使用 LLM-Agent 框架搭建并训练一个混合数据源查询智能体。该智能体可同时处理结构化数据(如SQL数据库、Pandas DataFrame)和非结构化数据(如网页、PDF文档等),通过检索与工具调用回答用户问题。训练目标包括:构建高效的检索模块(如FAISS向量检索、RAG、混合检索),训练策略决策模块(监督学习或强化学习来决定何时调用检索/工具并生成答案),以及使用合适的Agent框架(如LangChain、LlamaIndex、CrewAI、Semantic Kernel等)进行整合。以下内容将分步骤详细说明安装、数据准备、模型与工具选择、训练与评估等环节,附以示例代码模板和最小可运行示例(MWE),帮助工程人员快速实现。
faiss-cpu
(或 GPU版faiss-gpu
)、sentence-transformers(用于生成文本向量);transformers
、accelerate
、trl
(HuggingFace的RL包)等;pandas
、sqlalchemy
(或sqlite3
)处理结构化数据,PyPDF2
/textract
等处理文档;stable-baselines3
、trl
(PPO)等。通过pip一次性安装示例(根据需要可加入GPU选项、安装长文本库等):
pip install langchain llama-index faiss-cpu sentence-transformers transformers accelerate trl torch pandas sqlalchemy
import sqlite3, pandas as pd
conn = sqlite3.connect("example.db")
df = pd.DataFrame({
"city": ["Beijing", "Shanghai", "Guangzhou"],
"population": [21540000, 24240000, 14000000]
})
df.to_sql("cities", conn, if_exists="replace", index=False)
conn.close()
或者直接使用pandas.DataFrame
进行查询。
with open("documents.txt", "r", encoding="utf-8") as f:
raw_text = f.read()
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
docs = [ {"page_content": chunk} for chunk in splitter.split_text(raw_text) ]
可使用langchain.document_loaders
模块加载PDF/HTML等。准备完数据后,对非结构化数据提取文本、分段以进行向量化检索;结构化数据则直接保留表结构,通过SQL查询或DataFrame操作访问。
检索模块负责从混合数据源中找到与用户问题最相关的信息(SQL查询结果或文本片段)。常用方法包括基于向量的检索(FAISS)、RAG(检索增强生成)、以及混合检索。
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.schema import Document
# 构造示例文档列表
documents = [Document(page_content=d) for d in docs_text_list]
# 选择预训练文本嵌入模型(支持中文模型或多语言模型)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
# 构建FAISS索引
vector_store = FAISS.from_documents(documents, embeddings)
# 创建检索器
retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 3})
# 示例检索
query = "北京市人口是多少?"
results = retriever.get_relevant_documents(query)
for doc in results:
print(doc.page_content)
上例中,FAISS.from_documents
将文本列表转换为向量索引,as_retriever
用于检索相关文档。引擎返回前k个相似段落,可用于后续生成答案或执行工具调用。文档检索可进一步结合**Maximal Marginal Relevance (MMR)**等策略提升结果多样性。
LangChain可使用RetrievalQA
链快速实现RAG,例如:
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
# 假设使用OpenAI或其他支持问答的模型
llm = OpenAI(model_name="gpt-3.5-turbo")
qa_chain = RetrievalQA(llm=llm, retriever=retriever)
answer = qa_chain.run("北京的人口是多少?")
print(answer)
MultiRetrievalQA
之类的自定义链,或先用关键字检索定位相关表/文档,再用向量检索细化内容。策略模块决定智能体在回答过程中的行动序列,如调用何种工具(检索、数据库查询、API调用等)以及何时生成回答。常用训练方法包括模仿学习和强化学习(RL)。
“在模仿学习(IL)中,我们通过观察人类专家或更熟练的智能体来生成轨迹,然后导出训练序列以微调LLM”。
实现时,可用Hugging Face Trainer
对语言模型进行微调,训练数据示例结构如:
用户: 北京市人口是多少?
Agent: [SQL] SELECT population FROM cities WHERE city='Beijing';
结果: 21540000
Agent: 北京市的人口约为2154万。
将以上串联为单个输入输出序列供模型学习。微调时可采用流式生成(teacher forcing)计算交叉熵损失,仅监督Action和回答部分。
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import PPOTrainer, PPOConfig
model = AutoModelForCausalLM.from_pretrained("gpt2")
tokenizer = AutoTokenizer.from_pretrained("gpt2", use_fast=False)
ppo_config = PPOConfig(batch_size=1, learning_rate=1e-5, log_with=None)
ppo_trainer = PPOTrainer(model, tokenizer, **ppo_config)
# 简单示例:使用固定问答对训练
prompts = ["北京市人口是多少?"]
for epoch in range(10):
responses = [tokenizer.decode(model.generate(tokenizer(prompt, return_tensors="pt")["input_ids"])[0], skip_special_tokens=True) for prompt in prompts]
# 计算奖励(这里假设知道正确答案)
rewards = [1.0 if "2154" in resp else 0.0 for resp in responses]
# 更新策略
ppo_trainer.step(prompts, responses, rewards)
该过程较为复杂,通常先用监督学习初始化模型,再用RL微调以优化特定任务目标。
市面上已有多种用于构建智能体的框架,常见包括 LangChain (含LangGraph)、LlamaIndex (原GPT Index)、CrewAI、Microsoft Semantic Kernel、Microsoft AutoGen 等。每种框架优劣不同,根据项目需求选择合适方案:
推荐组合:对于数据查询场景,常见的选择是LangChain + LlamaIndex。LangChain负责流程编排与工具调用,LlamaIndex负责底层检索和索引。CrewAI可在需要多Agent协作时引入。Semantic Kernel适合企业级或混合语言环境。AutoGen适用于构建复杂多轮Agent对话。总体而言,LangChain/LangGraph生态最成熟,文档丰富,能快速实现SQL工具调用和文本检索。
示例:使用LangChain创建SQL与文本检索Agent的代码结构大致为:
from langchain.agents import initialize_agent, AgentType
from langchain.tools import QuerySQLDatabaseTool
from langchain_community.sql import SQLDatabase
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
# 1. 初始化数据源和工具
db = SQLDatabase.from_uri("sqlite:///example.db")
sql_tool = QuerySQLDatabaseTool(db=db)
# 文本检索工具:使用FAISS向量检索
documents = [Document(page_content=d) for d in docs_text_list]
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
vector_store = FAISS.from_documents(documents, embeddings)
text_tool = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 3})
# 2. 定义LLM模型(可替换为本地模型)
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(model_name="gpt-3.5-turbo")
# 3. 初始化Agent(使用LangGraph的ReAct代理器)
agent = initialize_agent(
tools=[sql_tool, text_tool],
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# 4. 运行示例查询
response = agent.run("北京市人口是多少?")
print(response)
该示例将SQL查询工具和文本检索工具作为Agent的可调用工具,LLM负责决定何时调用哪个工具并生成回答。
用于训练的数据集通常包含问-工具调用-回答的完整轨迹。格式可以是类似对话的文本,其中标记不同角色和动作。例如:
用户: 北京市人口是多少?
Agent思考: 需要查询数据库
Agent调用工具[SQL]: SELECT population FROM cities WHERE city='Beijing';
工具返回: 21540000
Agent回答: 北京的人口约为2154万。
上述轨迹示例中,用[SQL]
标记表示Agent调用了SQL查询工具。也可以将检索工具调用用类似[检索]
标记。这样的标记序列可以拼接成一段训练文本供语言模型学习。
组织训练集时,可将上述示例转换为如下对(以逗号分隔prompt和response):
[
{
"prompt": "用户: 北京市人口是多少?\nAgent: [SQL]",
"response": "SELECT population FROM cities WHERE city='Beijing'; 工具返回: 21540000 Agent回答: 北京的人口约为2154万。"
},
...
]
在微调时,模型学习从提示的环境中推断动作和答案。LangChain社区和OpenAI Fine-tuning指南都采用类似格式。行为轨迹数据也可通过现有QA对、系统日志或者人工编写示例构造。如果缺乏标注数据,可借助现有LLM生成(如模拟GPT-4生成SQL和答案),再用人类审校。
transformers
。引入微调工具,例如HuggingFace 的Trainer进行监督微调,或trl
库进行RL微调。注意内存/显存限制:可使用LoRA/8-bit优化来降低显存占用。from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
model = AutoModelForCausalLM.from_pretrained("gpt2")
tokenizer = AutoTokenizer.from_pretrained("gpt2", use_fast=False)
# 构建训练集
train_texts = ["用户: ... Agent: ..."]
encodings = tokenizer(train_texts, padding=True, truncation=True, return_tensors="pt")
dataset = torch.utils.data.TensorDataset(encodings["input_ids"])
args = TrainingArguments(
output_dir="sft_output",
num_train_epochs=3,
per_device_train_batch_size=1,
logging_steps=10,
save_total_limit=1
)
trainer = Trainer(model=model, args=args, train_dataset=dataset)
trainer.train()
这样模型会学习在遇到“用户: ... Agent:
”时输出对应SQL和回答。
trl.PPOTrainer
可以处理对话式样本,例子参见前文。训练时需要注意:奖励设计和tokenizer兼容性(常用token化器需与模型一致)。监控PPO训练的平均奖励变化,确保策略朝正确方向优化。verbose=True
可以看到每一步LLM输出及工具调用,便于排查思路错误。下面给出一个整合上述组件的简单示例框架,可在单机环境下运行。注意,该示例仅说明结构,不包含实际大规模训练。
# 安装依赖(需联网)
!pip install langchain llama-index faiss-cpu sentence-transformers transformers accelerate torch pandas sqlalchemy
# 1. 数据源准备:示例SQLite表
import sqlite3, pandas as pd
conn = sqlite3.connect("example.db")
pd.DataFrame({"city": ["Beijing","Shanghai"], "pop": [21540000,24240000]}) \
.to_sql("cities", conn, if_exists="replace", index=False)
# 2. 构建向量检索器(示例文本)
docs = ["Beijing is the capital of China.", "Shanghai has the largest population."]
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.schema import Document
emb = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vector_store = FAISS.from_documents([Document(page_content=d) for d in docs], emb)
# 3. 定义工具
from langchain_community.sql import SQLDatabase, QuerySQLDatabaseTool
db = SQLDatabase.from_uri("sqlite:///example.db")
sql_tool = QuerySQLDatabaseTool(db=db)
from langchain.vectorstores import VectorStoreRetriever
text_tool = vector_store.as_retriever()
# 4. 初始化LLM-Agent
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
llm = ChatOpenAI(model_name="gpt-3.5-turbo")
agent = initialize_agent([sql_tool, text_tool], llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# 5. 示例运行
query = "北京的人口是多少?"
answer = agent.run(query)
print("Answer:", answer)
以上示例在单机上运行,无需额外服务器,只要有Python环境及上述依赖即可。正式部署时,可将模型换为本地加载的开源LLM(改用ChatModel.from_pretrained
),并替换向量检索为GPU版FAISS以加速。
sentence-transformers/all-MiniLM-L6-v2
(轻量、支持多语言),或中文嵌入模型如hkunlp/instructor-large
。API可选用OpenAI Embedding。trl
(PPOTrainer),stable-baselines3
;如需RLHF可使用OpenAI的TRLX或其他RLHF库。本文综述了在单机环境下训练一个基于LLM-Agent的数据查询智能体所需的各环节:包括检索模块构建(FAISS向量检索、RAG、混合检索)、策略模块训练(模仿学习与强化学习)、Agent框架选择(LangChain、LlamaIndex、CrewAI等)、训练数据组织、环境配置及调试监控等。核心步骤分为安装依赖、准备结构化与非结构化数据、构建检索/工具调用组件、选择合适的模型及Agent框架、组织训练样本并执行微调,最后进行评估与部署。上述示例和模板代码可据此修改,并替换为具体数据集和模型。通过遵循本文所示的体系结构和方法,工程师可复现一个从数据到智能体端到端的可训练流水线,将LLM与外部知识源和工具有效结合。
参考资料: LangChain官方教程、GoPenAI RAG+RL博客、AGILE框架论文、Turing框架比较报告。以上文献介绍了LLM Agent的基本概念、RAG检索以及主流框架特性,为本文内容提供了理论依据。