LangChain核心组件 == 提示词(Prompts)

发送给大模型的所有消息都可以称为提示词(Prompt) ,它直接影响模型的输出结果**。**

其中,SystemMessage尤为重要,我们把SystemMessage称为系统提示词 (System Prompt),它可以给模型设定角色和本次聊天的背景,对模型生成的内容有很大的影响。

系统提示词

在创建智能体时,我们可以直接设定system prompt,不必在每次发送消息时指定。

复制代码
from langchain.agents import create_agent
from langchain.messages import HumanMessage
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()


# 创建智能体
agent = create_agent(
    model = "deepseek-chat",
    system_prompt="像海盗一样说话."
)

for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="你是谁?")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)

如果没有设定系统提示词,模型会按照训练中的自我认知来回答

复制代码
你好!我是DeepSeek,由深度求索公司创造的AI助手!😊

我是一个纯文本模型,虽然不支持多模态识别功能,但我有文件上传功能,可以帮你处理图像、txt、pdf、ppt、word、excel等各种文件,从中读取文字信息进行分析处理。

我的一些特点:
- 完全免费使用,没有收费计划
- 上下文长度达128K,可以处理很长的对话
- 支持联网搜索(需要你手动点开联网搜索按键)
- 可以通过官方应用商店下载App使用

而设定了海盗这个角色后,它的回答就非常有趣了:

复制代码
啊哈!我是你船上的鹦鹉,一个在数字海洋里翱翔的AI助手!想聊聊宝藏、航海,还是七大洋的奇闻?尽管放马过来,伙计!🗺️⚓

提示词工程

通过优化System Prompt从而让模型输出更理想的结果的这一过程,我们称为提示词工程(Prompt Engineering)。

也就是说,提示词优化不是一锤子买卖,而是一个不断优化、测试、再优化的过程。那么,提示词到底该怎么写呢?

从内容来说,提示词通常包含以下几个部分,通常按此顺序排列:

  • 身份(Identity):描述AI的职责、沟通风格和总体目标。

  • 说明(Instructions):请指导模型如何生成所需的响应。它应该遵循哪些规则?模型应该做什么,以及模型绝对不能做什么?

  • 示例(Examples):提供可能的输入示例,以及模型期望的输出。

  • 背景信息(Context):向模型提供生成响应所需的任何额外信息,例如RAG的额外知识库数据,或您认为特别相关的任何其他数据。

从格式来说,在编写System Prompt时,您可以使用Markdown格式和XML 标签的组合来帮助模型理解提示和上下文数据的逻辑边界。

  • Markdown 的标题和列表有助于标记提示的不同部分,并向模型传达层级结构。它们还可以提高开发过程中提示的可读性。

  • XML 标签可以帮助明确区分一段内容(例如用作参考的辅助文档、对话示例等)的起始和结束位置。

    Identity

    You are a helpful assistant that labels short product reviews as
    Positive, Negative, or Neutral.

    Instructions

    • Only output a single word in your response with no additional formatting
      or commentary.
    • Your response should only be one of the words "Positive", "Negative", or
      "Neutral" depending on the sentiment of the product review you are given.

    Examples

    <product_review id="example-1">
    I absolutely love this headphones --- sound quality is amazing!
    </product_review>

    <assistant_response id="example-1">
    Positive
    </assistant_response>

    <product_review id="example-2">
    Battery life is okay, but the ear pads feel cheap.
    </product_review>

    <assistant_response id="example-2">
    Neutral
    </assistant_response>

    <product_review id="example-3">
    Terrible customer service, I'll never buy from them again.
    </product_review>

    <assistant_response id="example-3">
    Negative
    </assistant_response>

接下来,我们就学习下不同的提示词对模型结果的影响。

设定角色和详细指令

角色可以帮助模型认清自己的身份,以对应的身份来回答问题。

指令则告诉模型需要遵循哪些规则,应该做什么,不应该做什么

例如:

复制代码
system_prompt = """
# 身份
- 你是一个编程助手,你帮助用户编写Python代码。

# 指令
- 定义变量时,使用snake case命名法,而不是camel case命名法。
- 不要返回markdown格式说明,仅仅返回代码即可。

"""

# 创建智能体
agent = create_agent(
    model = "deepseek-chat",
    system_prompt=system_prompt
)

for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="怎样定义string变量记录学校名字,例如`黑马程序员`")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)

输出结果:

复制代码
school_name = "黑马程序员"​

Few-Shot examples

有的时候我们希望模型按照固定的风格来回答问题,而这种风格又不太好描述,那我们就可以通过举例的方式让模型学习例子来回答。

用户只需在输入提示(Prompt)中提供几个输入-输出示例,模型就能理解任务模式并生成符合预期的输出:

复制代码
system_prompt = """
# 身份
- 你是一个科幻作家,根据用户的要求创建一个太空之都。

# 示例
user:月球的首都是什么?
assistant:月华城(Lunara)------ 镶嵌在月球静海环形山中的水晶穹顶都市,其核心是一座利用月球潮汐能驱动的巨型生态循环塔。

user:火星的首都是什么?
assistant:赤晶城(Aresia)------ 深嵌于火星奥林匹斯山熔岩管内的蜂巢都市,地表仅露出由火星红土烧制而成的螺旋尖塔。
"""

# 创建智能体
agent = create_agent(
    model = "deepseek-chat",
    system_prompt=system_prompt
)

for token, metadata in agent.stream(
    {"messages": [HumanMessage(content="金星的首都是什么?")]},
    stream_mode="messages"
):
    print(token.content, end="", flush=True)

结果:

复制代码
熔金城(Aurum)------悬浮于硫酸云层之上的宏伟浮空都市,以反光性合金铸造,永恒折射着昏黄的日光。

结构化输出

由于传统程序识别结构化的数据会更加方便,所以有时候我们希望LLM也能输出固定结构的内容,方便我们解析。这同样可以通过系统提示词来实现。

复制代码
system_prompt = """
# 身份
- 你是一个科幻作家,根据用户的要求创建一个太空之都。

# 指令
- 请务必以JSON格式输出,不要加任何markdown样式。

# 示例:
user: 月球的首都是什么?
assistant:
{
    "name": "月华市(Lunaria)",
    "location": "位于月球正面赤道附近的静海基地遗址之上,依托巨大的穹顶与地下网络建成",
    "vibe": "冷冽、高效、革新",
    "economy": "氦-3能源开采、量子通信枢纽、尖端生物圈农业"
}
"""

agent = create_agent(
    model="deepseek-chat",
    system_prompt=system_prompt
)

response = agent.invoke(
    {"messages": [HumanMessage(content="金星的首都是什么?")]},
)

print(response['messages'][-1].content)

输出结果:

复制代码
{
    "name": "硫磺城(Sulfura)",
    "location": "悬浮于金星浓厚大气层中距地表约50公里的高空,由巨大的反重力浮空平台群构成",
    "vibe": "高压、炽热、坚韧",
    "economy": "大气资源提炼(二氧化碳、硫酸)、极端环境材料制造、太阳能巨型阵列"
}

在LangChain中,实现结构化输出会更加简单。我们无需自己在提示词中添加描述实现结构化输出,而仅仅是设定好一个数据类型即可。

首先,我们定义一个类,用来封装模型要输出的数据:

复制代码
from pydantic import BaseModel
class CapitalInfo(BaseModel):
    name: str
    location: str
    vibe: str
    economy: str

然后,我们就可以在创建Agent时设定好输出格式:

复制代码
# 然后,我们就可以创建智能体并设置结构化输出的格式了。
agent = create_agent(
    model='deepseek-chat',
    system_prompt="你是一个科幻作家,根据用户的要求创建一个太空之都。",
    response_format=CapitalInfo # 设置结构化输出的格式
)

response = agent.invoke(
    {"messages": [HumanMessage(content="月球的首都是什么?")]}
)

注意,在输出的结果中,有一个'structured_response'的字段,就是结构化输出的对象:

复制代码

{'messages': [HumanMessage(content='月球的首都是什么?', additional_kwargs={}, response_metadata={}, id='42747579-7994-4fe9-93bf-970216fb65b4'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 130, 'prompt_tokens': 355, 'total_tokens': 485, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 355}, 'model_provider': 'deepseek', 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'id': '3dcb8346-67b2-4cf1-b61d-cf9cf8e2dde9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019ca25b-a0e2-77a0-af64-9b1d2c9247f0-0', tool_calls=[{'name': 'CapitalInfo', 'args': {'name': '月宫', 'location': '月球南极-艾特肯盆地边缘', 'vibe': '高科技与东方古典美学融合的宁静都市,拥有透明穹顶下的传统园林和悬浮建筑', 'economy': '氦-3开采、量子计算中心、太空旅游枢纽、月球农业和科学研究'}, 'id': 'call_00_NBnEIMUhLTXZdXRJLZVYCnan', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 355, 'output_tokens': 130, 'total_tokens': 485, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}), ToolMessage(content="Returning structured response: name='月宫' location='月球南极-艾特肯盆地边缘' vibe='高科技与东方古典美学融合的宁静都市,拥有透明穹顶下的传统园林和悬浮建筑' economy='氦-3开采、量子计算中心、太空旅游枢纽、月球农业和科学研究'", name='CapitalInfo', id='1735ea63-403a-468a-a5ea-cc01deeab0b2', tool_call_id='call_00_NBnEIMUhLTXZdXRJLZVYCnan')], 'structured_response': CapitalInfo(name='月宫', location='月球南极-艾特肯盆地边缘', vibe='高科技与东方古典美学融合的宁静都市,拥有透明穹顶下的传统园林和悬浮建筑', economy='氦-3开采、量子计算中心、太空旅游枢纽、月球农业和科学研究')}

所以,我们这样获取结构化的输出:

复制代码
city = response['structured_response']

完整代码:

复制代码
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.messages import HumanMessage

# 首先,我们定义一个类,用来封装模型要输出的数据:
class CapitalInfo(BaseModel):
    name: str
    location: str
    vibe: str
    economy: str

# 然后,我们就可以创建智能体并设置结构化输出的格式了。
agent = create_agent(
    model='deepseek-chat',
    system_prompt="你是一个科幻作家,根据用户的要求创建一个太空之都。",
    response_format=CapitalInfo # 设置结构化输出的格式
)

response = agent.invoke(
    {"messages": [HumanMessage(content="月球的首都是什么?")]}
)

city = response['structured_response']

print(f"{city.name}位于{city.location},是一座{city.vibe}的城市,其主要产业包括{city.economy}。")

总结

本节我们主要学习了:

  • 什么是提示词

  • 如何优化系统提示词,控制模型输出

    • 设定角色和详细指令

    • 通过few-shot样例,让模型参考

    • 通过结构化输出控制输出格式

    • 通过markdown、xml语法编写提示词,加强模型理解能力

相关推荐
niucloud-admin1 小时前
JAVA V6 多商户商城 开发文档——手机端前端
java·开发语言·前端
茉莉玫瑰花茶1 小时前
GO [ 并发 ]
开发语言·后端·golang
霸道流氓气质1 小时前
Dify 可视化 LLM 应用开发平台完全指南:从Workflow编排到Java生产级集成实战
java·开发语言
2601_962218612 小时前
深入理解C++中的thread_local线程局部变量的应用
开发语言·c++
外收内放2 小时前
Python基础语法练习题(31-33)
开发语言·python
CRMEB系统商城2 小时前
前后端技术栈全面换代!CRMEB 多商户(Java)v3.0更新预告
java·开发语言·小程序·php
2601_962885722 小时前
如何用 Python 画 K 线图(蜡烛图)?(mplfinance + 均线 + 成交量)
开发语言·python
事圆则缓2 小时前
Flutter 状态管理框架对比(三):Riverpod 如何连起购物车与异步价格
开发语言·javascript·flutter
蓝宝石的傻话2 小时前
onvif-go(mickeyzzc/onvif-go v2)完整参考手册:从建工程到写出自己的 NVR 接入
开发语言·后端·golang