前言:这几天学习理论知识较少,跟着网上的视频做了一些代码试写,从开始的调用大模型逐渐进阶到搭建简单的agent,实现提示词工程、agent工具开发、简单agent开发
轻松一刻:我最讨厌的两件事:一是写注释,二是别人不写注释。程序员最怕听到的三个字不是“有Bug”,而是……“你注释呢?”
知识点学习
工具调用与Agent类知识点
知识点1:什么是Function Calling(工具调用)?它在Agent系统中起什么作用?
Function Calling 是让大模型在对话中识别需要调用外部工具或函数,并生成结构化调用参数的能力。它在 Agent 系统中起到连接模型与外部世界的作用,让模型能获取实时数据、执行操作,从而完成单靠模型本身无法完成的任务。
知识点2:什么是ReAct模式?它与单纯的工具调用有什么不同?
ReAct 模式是让模型交替进行「推理」和「行动」:先思考下一步该做什么,再调用工具获取结果,然后根据结果继续推理。与单纯工具调用相比,ReAct 多了推理环节,能根据中间结果动态调整策略,处理更复杂的多步任务。
知识点3:什么是工具(Tool)描述?如何正确编写工具描述以提高模型调用的准确性?
工具描述是告诉模型「这个工具是做什么的、什么时候该用、参数怎么填」的说明文字。编写时要写清楚工具的功能、适用场景、参数含义和格式要求,语言要简洁明确,避免歧义,这样模型才能准确判断何时调用以及如何传参。
知识点4:多工具场景下,模型如何决定调用哪个工具?优先级如何设定?
模型会根据用户意图和各个工具的描述,选择最匹配的那个工具来调用。优先级可以通过在工具描述中明确使用条件、适用场景和重要程度来设定,描述越清晰、条件越明确,模型就越容易做出正确选择。
知识点5:什么是工具调用循环(Tool Call Loop)?如何防止无限循环?
工具调用循环是指模型反复调用工具、获取结果、再继续调用的过程,直到完成任务。防止无限循环可以设置最大调用次数、增加超时机制,或在结果中检测到无进展时主动终止循环。
LangChain与框架类知识点
知识点6:LangChain的核心组件有哪些?它们分别解决什么问题?
LangChain 的核心组件包括模型(Model)、提示词(Prompt)、记忆(Memory)、工具(Tool)和链(Chain)。模型负责与大模型交互,提示词负责组织输入,记忆负责保存对话历史,工具负责连接外部能力,链负责把多个步骤串联起来完成复杂任务。
知识点7:什么是LCEL(LangChain Expression Language)?它的优势是什么?
LCEL 是 LangChain 提供的一种声明式表达式语言,用简洁的管道语法把组件串联成执行流程。它的优势是代码简洁、易于组合和复用,支持流式输出、并行执行和异步调用,还能自动处理重试和回退,让复杂流程的构建和维护更高效。
知识点8:什么是Chain?Chain和Agent有什么区别?
Chain 是把多个处理步骤按固定顺序串联起来的执行流程,每一步做什么是预先定义好的。Agent 则更灵活,它能根据用户意图动态决定调用哪些工具、按什么顺序执行。简单说,Chain 是固定流程,Agent 是自主决策流程。
知识点9:什么是Vector Store?在RAG系统中它扮演什么角色?
Vector Store 是专门存储和检索向量数据的数据库,把文本等内容转换成向量后存入其中,并支持按相似度快速检索。在 RAG 系统中,它负责保存知识库的向量索引,当用户提问时,系统先从 Vector Store 中检索出最相关的片段,再交给大模型生成回答,从而提升回答的准确性和时效性。
知识点10:什么是Embedding?如何选择Embedding模型?
Embedding 是把文本、图片等内容转换成高维向量表示的过程,让语义相近的内容在向量空间中距离更近。选择 Embedding 模型时,要考虑模型的语义理解能力、支持的语言、向量维度、推理速度和成本,并结合实际业务场景和检索效果进行测试对比。
实战代码
1、天气查询工具开发
import os
import json
import requests
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, AIMessage, ToolMessage
from dotenv import load_dotenv
import ssl
from requests.adapters import HTTPAdapter
import gradio as gr
load_dotenv()
class TLSAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
kwargs['ssl_version'] = ssl.PROTOCOL_TLSv1_2 # 强制 TLS 1.2
return super().init_poolmanager(*args, **kwargs)
@tool
def get_weather(city: str) -> str:
"""查询指定城市的当前天气信息,包括温度、天气状况、湿度、风速。
当用户询问某个城市或地区的天气、气温、冷不冷、热不热、下不下雨时,使用此工具。
Args:
city: 要查询天气的城市名称,例如"北京"、"上海"、"长沙"、"广州"
"""
print("需要查询的城市:", city)
try:
url = f"https://wttr.in/{city}?format=j1&lang=zh"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
""
}
# 使用自定义适配器
session = requests.Session()
session.mount('https://', TLSAdapter())
resp = session.get(url, timeout=10, headers=headers)
# resp = requests.get(url, timeout=10, headers=headers)
print("爬取成功")
resp.raise_for_status()
data = resp.json()
# print(data)
current = data["current_condition"][0]
area = data["nearest_area"][0]
return (
f"{area['areaName'][0]['value']}天气\n"
f"天气:{current['weatherDesc'][0]['value']}\n"
f"温度:{current['temp_C']}°C(体感{current['FeelsLikeC']}°C)\n"
f"湿度:{current['humidity']}%\n"
f"风速:{current['windspeedKmph']}km/h"
)
except Exception as e:
print(f"请求失败,错误信息:{e}")
return (
f"{city}天气(模拟数据,网络不通时显示)\n"
"天气:晴,温度:28°C(体感30°C),湿度:65%,风速:12km/h"
)
tools = [get_weather]
tool_map = {t.name: t for t in tools}
# --- 初始化 LLM 并绑定工具 ---
llm = ChatOpenAI(
model=os.getenv("DATA_MODEL"),
base_url=os.getenv("DATA_BASE_URL"),
api_key=os.getenv("DATA_API_KEY"),
temperature=0,
)
llm_with_tools = llm.bind_tools(tools)
# --------------ReAct 循环(核心!)-------------------
def run_agent(user_input: str, verbose: bool = True) -> str:
"""
Args:
user_input(用户的提问)
verbose:是否记录每一步,此处默认为True
"""
messages = [HumanMessage(content=user_input)]
# 此处记录用户问题以及每一步循环的ai回答
for step in range(5):
response: AIMessage = llm_with_tools.invoke(messages)
messages.append(response)
if not response.tool_calls:
return response.content
# 此处判断,如果大模型没有调用任何工具,说明大模型觉得获得的信息已经够了,可以直接回答用户了,返回结果
if verbose:
for tc in response.tool_calls:
print(f"【步骤{step+1}】调用工具:{tc['name']},参数:{json.dumps(tc['args'], ensure_ascii=False)}")
for tc in response.tool_calls:
tool_result = tool_map[tc["name"]].invoke(tc["args"])
if verbose:
print(f"【步骤{step+1}】工具返回:{str(tool_result)[:60]}...")
messages.append(ToolMessage(content=str(tool_result), tool_call_id=tc["id"]))
return "处理次数超限,请换个问题。"
demo = gr.Interface(fn=run_agent, inputs="text", outputs="text")
if __name__ == "__main__":
demo.launch()
其中核心代码如下:
封装了一个工具用@tool装饰,在函数定义里写清楚工具描述,避免歧义(这一步很重要)
在工具get_weather里用requests爬取天气网站信息,让大模型有了能获取天气的能力
@tool
def get_weather(city: str) -> str:
"""查询指定城市的当前天气信息,包括温度、天气状况、湿度、风速。
当用户询问某个城市或地区的天气、气温、冷不冷、热不热、下不下雨时,使用此工具。
Args:
city: 要查询天气的城市名称,例如"北京"、"上海"、"长沙"、"广州"
"""
print("需要查询的城市:", city)
try:
url = f"https://wttr.in/{city}?format=j1&lang=zh"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
""
}
# 使用自定义适配器
session = requests.Session()
session.mount('https://', TLSAdapter())
resp = session.get(url, timeout=10, headers=headers)
# resp = requests.get(url, timeout=10, headers=headers)
print("爬取成功")
resp.raise_for_status()
data = resp.json()
# print(data)
current = data["current_condition"][0]
area = data["nearest_area"][0]
return (
f"{area['areaName'][0]['value']}天气\n"
f"天气:{current['weatherDesc'][0]['value']}\n"
f"温度:{current['temp_C']}°C(体感{current['FeelsLikeC']}°C)\n"
f"湿度:{current['humidity']}%\n"
f"风速:{current['windspeedKmph']}km/h"
)
except Exception as e:
print(f"请求失败,错误信息:{e}")
return (
f"{city}天气(模拟数据,网络不通时显示)\n"
"天气:晴,温度:28°C(体感30°C),湿度:65%,风速:12km/h"
)
tools = [get_weather]
tool_map = {t.name: t for t in tools}
2、天气查询工具进阶(agent开发,让大模型有短期记忆,能记住用户前面所说的话)
在1的基础上调用改为如下方代码
这段代码在1的基础上,定义了一个agent,并通过定义类WeatherChat的办法,实现循环调用和清空记忆,其中self.messages里会存储着每一次的对话,让大模型在每次调用时都知道之前说了什么,在每轮循环里用agent.invoke的方式存储每一轮对话。
# 在001的基础上创建1个带记忆的agent:
# create_agent 是langchain给的官方agent创建工具
agent = create_agent(
model= llm,
tools = tools,
system_prompt = """
你是天气小助手,专业友好。
1、问天气必须调用get_wheather工具,不要编造
2、问答简洁自然,根据温度给穿衣建议(<10度保暖,>30度防暑)
3、用户没说城市时礼貌询问
4、非天气问题礼貌说明你主要提供天气服务
""",
)
class WeatherChat:
"""多轮对话会话:自己维护消息历史"""
def __init__(self):
self.messages = [] # 消息列表,存所有历史
def send(self, user_input: str) -> str:
"""发送用户消息,返回助手回答"""
# 1. 把用户消息加入历史
self.messages.append(HumanMessage(content=user_input))
# 2. 调用agent(传入完整历史)
result = agent.invoke({"messages": self.messages})
# 3. 用agent返回的完整消息列表更新历史(包含工具调用过程)
self.messages = result["messages"]
# 4. 最后一条就是最终回答
return self.messages[-1].content
def clear(self):
"""清空对话"""
self.messages = []
if __name__ == "__main__":
print("=" * 50)
print("天气助手 进阶版(多轮对话版)")
print("命令:quit 退出 | clear 清空对话")
print("=" * 50)
chat = WeatherChat()
while True:
user_input = input("\n你: ").strip()
if not user_input:
continue
if user_input.lower() in ("quit", "exit", "q"):
print("再见!")
break
if user_input.lower() == "clear":
chat.clear()
print("对话已清空,重新开始~")
continue
answer = chat.send(user_input)
print(f"助手: {answer}")
结果截图:

写到这里,谢谢!

1170

被折叠的 条评论
为什么被折叠?



