从0开始搭建AI Agent(二)
上节我们基本了解了如何通过LangChain来加载大语言模型并调用,接下来我们接着介绍更多的应用,从而使我们的AI Agent更加完善和健壮。
LangChain 提示词模板
LangChain的提示词模板引擎(Prompt Template Engine)是其核心组件之一,主要用于构建和管理与大语言模型交互的提示词;它的作用是是一套将"写死的 Prompt"变成可复用、可组合的结构化指令系统,从而提升模型输出的准确性和一致性;
例如:我们需要大模型为我们提供旅游建议,为了能够详细表达用户的需求,大概需要对这些方面进行描述:
目的地:{destination} - 出行日期:{travel_date} - 出行天数:{days} - 预算范围(每人):{budget} - 出行人数:{travelers} - 同行人构成:{companions}(如:情侣/亲子/朋友/独行) - 旅行风格偏好:{style}(如:休闲度假/深度文化/户外探险/美食打卡/拍照出片) - 特殊需求:{special_needs}(如:无障碍/素食/带宠物/避开人群);
可以看到,如果每次询问都需要用户输入这么多信息,不仅麻烦,还容易遗漏,这个时候,我们就可以用到提示词模板了,比如以下拉对话框选择的形式,将目的地、 出行天数、旅行风格偏好等,让用户选择好,然后由系统生成最终的会话;这样就方便多了。
编写示例
新建一个“LangChain应用.ipynb”文件,添加一段代码:
key = '你自己的api key'
from langchain_community.chat_models import ChatZhipuAI
import os
os.environ["ZHIPUAI_API_KEY"] = key
chat = ChatZhipuAI(
model="glm-4",
temperature=0.5, #模型温度(0-1之间,值越小,随机性越低,随机性即模型的发散思维)
)
我们使用智谱的模型;点击运行;
注意:这个是单独的代码段,后续代码都是用的这个加载器,如果运行后续代码有出现:NameError: name 'chat' is not defined,那么说明chat没有在内存中,我们需要单独再重新运行一下这段代码;
还有一个问题是:这里将key直接写在了代码里面,这是不对的,这里只是为了方便测试;真实环境需要使用环境变量或配置文件来安全地管理自己的key。
方法1:使用langchain.prompts 的 PromptTemplate
from langchain.prompts import PromptTemplate
# 定义模板
template = '你是一个{role},请用{style}风格回答问题:请给一个详细的旅游建议:冬天,一个人要去{city}旅游,旅游天数:{day}天,大概预算费用:{money}元人民币'
#创建模板对象
prompt_template = PromptTemplate.from_template(template)
#变量填充
#filled_prompt = prompt_template.format(role = '导游助手',style = '中文',city = '中国北京', day='7',money = '5000')
#第二种写法
filled_prompt = prompt_template.invoke({'role':'导游助手', 'style':'中文','city':'中国北京','day':'7','money':'5000'})
#响应
ai_msg = chat.invoke(filled_prompt)
print(ai_msg.content)
点击运行,等待一会儿,模型将输出回答;
方法2:langchain_core.prompts 的 ChatPromptTemplate
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
sys_template = "你是一个{role},请用{style}风格回答问题,请给一个详细的旅游建议"
user_template = "冬天,一个人要去{city}旅游,旅游天数:{day}天,大概预算费用:{money}元人民币"
#创建对话模板
prompt_template = ChatPromptTemplate.from_messages([
('system',sys_template),
('human',user_template)
])
#填充变量
prompt = prompt_template.format_messages(role = '导游助手',style = '中文',city = '中国北京', day='7',money = '5000')
#响应
ai_msg = chat.invoke(prompt)
print(ai_msg.content)
同样可以正常输出。
LangChain 输出格式化
前面的例子我们看到,AI的输出是以文本字符串输出的,很多情况下,我们需要将AI的输出解析为结构化的数据,如:JSON、字典或者自定义的对象,这就要使用LangChain的输出格式化功能。
编写示例
格式化输出Json
from langchain.output_parsers import StructuredOutputParser,ResponseSchema
from langchain.prompts import PromptTemplate
# 定义输出结构
response_schemas = [
ResponseSchema(name="name", description="人的姓名",type='string'),
ResponseSchema(name="age", description="人的年龄",type='integer'),
ResponseSchema(name="city", description="人的城市",type='string')
]
#创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
#创建提示词模板
template = "请根据以下内容,输出一个json格式的结果:\n{content}\n\n输出格式要求:{format_instructions}"
prompt = PromptTemplate(
template=template,
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
#输入
input_content = "一个人,姓名:张三,年龄:30岁,城市:中国北京"
filled_prompt = prompt.format(content=input_content)
#响应
rsp = chat.invoke(filled_prompt)
output = output_parser.parse(rsp.content)
print(output)
点击运行,即可看到输出的Json字符串{'name': '张三', 'age': 30, 'city': '中国北京'}。
格式化输出对象
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
# 定义输出结构
class Person(BaseModel):
name: str = Field(description="人的姓名")
age: int = Field(description="人的年龄")
city: str = Field(description="人的城市")
# 创建输出解析器
output_parser = PydanticOutputParser(pydantic_object=Person)
#创建提示词模板
template = "请根据以下内容,输出一个json格式的结果:\n{content}\n\n输出格式要求:{format_instructions}"
prompt = PromptTemplate(
template=template,
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
#输入
input_content = "一个人,姓名:张三,年龄:30岁,城市:中国北京"
filled_prompt = prompt.format(content=input_content)
#响应
rsp = chat.invoke(filled_prompt)
output = output_parser.parse(rsp.content)
print(output)
点击运行,输出:name='张三' age=30 city='中国北京'。
LangChain 链式调用
在LangChain中,LLMChain是一个核心对象,用于实现基于大语言模型(LLM)的链式调用。它将提示词模板(Prompt Template)、语言模型(LLM)以及可选的输出解析器(Output Parser)组合在一起,形成一个可重复执行的流程,简化了与LLM的交互。
编写示例
#链式调用
from langchain.output_parsers import StructuredOutputParser,ResponseSchema
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
#定义输出结构
response_schemas =[
ResponseSchema(name="answer",description="问题的答案",type="string"),
ResponseSchema(name="confidence", description="答案的置信度",type="float")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
#定义提示模板
template = """你是一名数学老师,请用{style}风格回答以下问题,并以 JSON 格式返回答案和置信度:
问题:{question}
{format_instructions}"""
prompt = PromptTemplate(
template=template,
input_variables=["style", "question"],
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
#创建chain
#llmChain = LLMChain(llm = chat, prompt=prompt, output_parser=output_parser) 方法已过时
llmChain = prompt | chat | output_parser #推荐写法
#运行链
# rsp = llmChain.run({"style":"中文,通俗易懂","question":"请问如何求椭圆的面积?"}) 方法已过时
rsp = llmChain.invoke({"style":"中文,通俗易懂","question":"请问如何求椭圆的面积?"}) #推荐写法
print(rsp)
点击运行即可看到输出结果。
LangChain 响应-流式输出
上面的例子我们看到,程序运行后,一般要等待几秒到几十秒的时间,控制台才会输出大模型的响应结果,但我们在使用豆包、千问的时候看到,系统并不是一次性的输出所有内容,而是不断的向界面输出内容,直到所有响应完成,这个功能就叫做流式输出;
流式输出是指在用户输入问题后,AI模型边生成边显示响应内容,逐步展示AI的"思考"过程,而不是等待所有内容生成完毕后再一次性返回完整答案;与传统非流式输出相比,流式输出的差异如下所示:
普通输出(非流式):用户提交问题等待几秒一次性返回完整答案;
流式输出:用户提交问题Al边生成边显示逐步输出答案;
编写示例
#流式输出
from langchain.output_parsers import StructuredOutputParser,ResponseSchema
from langchain.prompts import PromptTemplate
response_schemas =[
ResponseSchema(name="answer",description="问题的答案",type="string"),
ResponseSchema(name="confidence", description="答案的置信度",type="float")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
#定义提示模板
template = """你是一名数学老师,请用{style}风格回答以下问题,并以 JSON 格式返回答案和置信度:
问题:{question}
{format_instructions}"""
prompt = PromptTemplate(
template=template,
input_variables=["style", "question"],
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
#创建chain
llmChain = prompt | chat
chunks = [] #存储结果
for chunk in llmChain.stream({"style":"中文,通俗易懂","question":"请问如何求椭圆的面积?"}):
print(chunk.content, end="", flush=True)
chunks.append(chunk)
我们只是在链式调用的基础上做了修改,其中:
链式调用时这样写的:llmChain = prompt | chat | output_parser,流式输出我们去掉了output_parser,如果不去掉的化,用户看到的还是过了几秒才会一次性输出,这是因为,虽然现在已经是流式输出了,但是输出的结果被放到格式化器里去执行格式化了,所以,需要等到output_parser全部格式化好了之后,才会输出最终结果;
点击运行即可看到输出效果。
OK,先到这里,后续将会继续介绍Langchain的记忆系统......
更多推荐


所有评论(0)