LangChain快速筑基(带代码)P1-输入控制与输出解析

欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。

引言

在上一篇LangChain入门中,我们已经了解到了可以使用LangChain的langchain_deepseek组件与DeepSeek进行对话。
但DeepSeek并没有提供如OpenAI一样的诸多参数来解决AI使用的问题,如控制随机性的temperature,控制重复(质量和新颖度)的presence_penalty和frequency_penalty。

关于参数在之前常见AI参数讲解有介绍过。

那AI的诸多问题要怎么解决呢?要怎么控制大模型(AI)呢?
常见问题如下:
![[【LangChain】LangChain基础概念-2.png]]

我们应该使用“直接修改大模型本身”之外的方案来解决问题(不现实)。
比如,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()

![[【LangChain】LangChain2-基础概念P1.png]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值