欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。
引言
在上一篇LangChain入门中,我们已经了解到了可以使用LangChain的langchain_deepseek组件与DeepSeek进行对话。
但DeepSeek并没有提供如OpenAI一样的诸多参数来解决AI使用的问题,如控制随机性的temperature,控制重复(质量和新颖度)的presence_penalty和frequency_penalty。
关于参数在之前常见AI参数讲解有介绍过。
那AI的诸多问题要怎么解决呢?要怎么控制大模型(AI)呢?
常见问题如下:
我们应该使用“直接修改大模型本身”之外的方案来解决问题(不现实)。
比如,LangChain。
LangChain不仅仅通过简单传递参数给 LLM API来解决问题,它还抽象了一系列组件来提供问题的解决方案。使用LangChain,可以讲不同大模型API封装成统一、易于调用的形式。
需要快速回顾和看懂Python的Java程序员可以看一下我之前写的Python快速入门
基础代码
上一篇入门中有与DeepSeek联网搜索对话的代码,这里放一个对话基础代码。
我本地是没有问题的(狗头)。有问题随时交流。
在DeepSeek官网购买获取API-KEY后替换到代码中。
import os
# 基础对话所需
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import SystemMessage, HumanMessage
# 环境key
os.environ["DEEPSEEK_API_KEY"] = 'sk-xx'
def get_deepseek_key():
key = os.getenv('DEEPSEEK_API_KEY')
if key is None:
raise ValueError("DEEPSEEK_API_KEY not found in environment variables.")
return key
# --- LLM 初始化 ---
def create_deepseek_llm():
api_key = get_deepseek_key()
if not api_key:
raise ValueError("没有ds key")
return ChatDeepSeek(
model = "deepseek-chat",
temperature=0.1, # 低温度,更具备确定性
max_tokens=1024,
timeout=None,
max_retries=2,
api_key=api_key
)
def test_simple_llm_call():
llm = create_deepseek_llm()
# 封装消息
# LangChain 支持的消息类型如下:
# - 'human': 人类消息
# - 'user': 用户消息
# - 'ai': AI 消息
# - 'assistant': 助手消息
# - 'function': 函数消息
# - 'tool': 工具消息
# - 'system': 系统消息
# - 'developer': 开发者消息
messages = [
("system","你是一个乐于助人的LangChain专家。"),
("human","你好,请用一句话介绍LangChain。")
]
# 流式响应
for chunk in llm.stream(messages):
print(chunk.text(), end="")
print("\n AI回答完了")
# 单词响应
# response = llm.invoke(messages)
# print("AI:", response.content)
if __name__ == '__main__':
test_simple_llm_call()
LangChain python官方文档
https://python.langchain.com/docs/how_to/#prompt-templates
输出可控性
结构化输入输出:提示模板Prompt Templates
LangChain提供了组件 Prompt Templates(提示模板)用来"让你的指令更规范、灵活,并且可以动态地根据用户输入或上下文调整"。
# 导入提示模板
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
场景:我们创建一个LangChain专家的提示模板
import os
# 基础对话所需
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import SystemMessage, HumanMessage
# 提示模板
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
# 环境key
os.environ["DEEPSEEK_API_KEY"] = 'sk-xx'
def get_deepseek_key():
key = os.getenv('DEEPSEEK_API_KEY')
if key is None:
raise ValueError("DEEPSEEK_API_KEY not found in environment variables.")
return key
# --- LLM 初始化 ---
def create_deepseek_llm():
api_key = get_deepseek_key()
if not api_key:
raise ValueError("没有ds key")
return ChatDeepSeek(
model = "deepseek-chat",
temperature=0.1, # 低温度,更具备确定性
max_tokens=1024,
timeout=None,
max_retries=2,
api_key=api_key
)
# --- 使用模板对话限定输入输出 ---
def create_langchain_teacher_template():
# 创建基础对话模板
"""
我们能在一些消息的构建上看到这种使用消息对象的写法。
但是实际上这不是推荐的简洁写法,应该直接使用元组。
是的,这个写法不会被视为一个s-string模板,而是一个string
return ChatPromptTemplate.from_messages([
SystemMessage(content="你是一个乐于助人的LangChain专家。"),
HumanMessage(content="你好,我想问一个关于LangChain的问题: {actual_user_input}")
])
"""
return ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的LangChain专家。"),
("human", "你好,我想问一个关于LangChain的问题: {actual_user_input}") # 确保这里是占位符
])
def test_simple_template_call():
llm = create_deepseek_llm()
user_question = "你好,请问LangChain组件Prompt Templates可以做什么?"
prompt_template = create_langchain_teacher_template()
messages = prompt_template.format_messages(actual_user_input=user_question)
print("最终发送给 LLM 的消息:")
for msg in messages:
print(f"- 类型: {msg.type}, 内容: {msg.content}")
print("\nAI开始回答")
for chunk in llm.stream(messages):
print(chunk.content, end="")
print("\nAI回答完了")
if __name__ == '__main__':
test_simple_template_call()
Prompt Templates可以告诉LLM它应该扮演什么角色、提供上下文、引导输出。
这里需要注意的是,在使用ChatPromptTemplate.from_messages()方法创建ChatPromptTemplate实例时,使用元组消息而是不是使用消息对象。
(“human”, “…”) 语法糖在幕后为你做了更多的工作,将字符串自动识别和处理为模板。而直接使用 HumanMessage(content=“…”) 时,content 被视为最终内容,而不是一个待格式化的模板。
输出解析器 Output Parsers(输出解析器)
现在,我们已经了解了基本对话和使用提示词模板Prompt Templates来限制输出。有时候我们需要结构化的输出数据,比如JSON、列表等…
LangChain提供了Output Parsers(输出解析器)来解析大模型返回文本。
以Prompt Templates的代码为基础,我们导入类库,询问LangChain的3个优点
import os
# 基础对话所需
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import SystemMessage, HumanMessage
# 提示模板
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
# 输出解析器
from langchain.output_parsers import CommaSeparatedListOutputParser
# 链条
from langchain.chains import LLMChain, SimpleSequentialChain, SequentialChain
# 环境key
os.environ["DEEPSEEK_API_KEY"] = 'sk-xx'
def get_deepseek_key():
key = os.getenv('DEEPSEEK_API_KEY')
if key is None:
raise ValueError("DEEPSEEK_API_KEY not found in environment variables.")
return key
# --- LLM 初始化 ---
def create_deepseek_llm():
api_key = get_deepseek_key()
if not api_key:
raise ValueError("没有ds key")
return ChatDeepSeek(
model = "deepseek-chat",
temperature=0.1, # 低温度,更具备确定性
max_tokens=1024,
timeout=None,
max_retries=2,
api_key=api_key
)
# --- 使用模板对话限定输入输出 ---
def create_langchain_teacher_template():
return ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的LangChain专家。"),
("human", "你好,我想问一个关于LangChain的问题: {actual_user_input} \n\n {format_instructions}") # 确保这里是占位符
])
# --- 使用输出解析器解析输出 ---
def create_output_parser():
return CommaSeparatedListOutputParser()
def test_output_parser_with_template():
llm = create_deepseek_llm()
output_parser = create_output_parser()
"""
1.获取格式化指令
对于 CommaSeparatedListOutputParser,它会是类似 "Your response should be a list of comma separated values, eg: `foo, bar, baz`"
"""
format_instructions = output_parser.get_format_instructions()
print(f"输出解析器的格式化指令: {format_instructions}")
prompt_template = create_langchain_teacher_template()
user_task = "请列出 LangChain 的3个主要优点。"
# 2.格式化完整提示,包含用户任务和格式指令
messages_for_llm = prompt_template.format_messages(
actual_user_input=user_task,
format_instructions=format_instructions
)
print("\n最终发送给 LLM 的消息 (包含格式指令):")
for msg in messages_for_llm:
print(f"- 类型: {msg.type}, 内容: {msg.content}")
# 3. 调用LLM并获取原始文本输出
print("\nAI开始生成原始文本 (等待 LLM 响应)...")
ai_response_message = llm.invoke(messages_for_llm)
raw_llm_output = ai_response_message.content # AIMessage对象的content属性是字符串
print(f"LLM 返回的原始文本: '{raw_llm_output}'")
# 4. 解析原始文本输出
try:
parsed_output = output_parser.parse(raw_llm_output)
print("\n解析后的输出 (Python列表):")
print(parsed_output)
if isinstance(parsed_output, list):
print("LangChain 的3个优点是:")
for i,advantage in enumerate(parsed_output):
print(f"{i}. {advantage.strip()}")
except Exception as e:
print(f"解析输出时出错: {e}")
print("这通常意味着 LLM 的输出没有严格遵循格式化指令。")
print("你可以尝试调整提示,或者使用更鲁棒的解析器/重试机制。")
print("--- 结束测试:带输出解析器的模板调用 ---\n")
if __name__ == '__main__':
test_output_parser_with_template()