文本扩展是大语言模型的一个重要应用方向,它可以输入简短文本,生成更加丰富的长文。这为创作提供了强大支持,但也可能被滥用。因此开发者在使用时,必须谨记社会责任,避免生成有害内容。
在本章中,我们将学习基于 OpenAI API 实现一个客户邮件自动生成的示例 ,用于根据客户反馈优化客服邮件 。这里还会介绍"温度"(temperature)这一超参数,它可以控制文本生成的多样性。
一、定制客户邮件
在这个客户邮件自动生成的示例中,我们将根据客户的评价和其中的情感倾向,使用大语言模型针对性地生成回复邮件。
import os
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
raise ValueError("请在 .env 中设置 ZHIPUAI_API_KEY")
# 模型调用函数
def get_completion(prompt, model="glm-4-flash"):
client = OpenAI(
api_key=api_key,
base_url="https://open.bigmodel.cn/api/paas/v4/"
)
try:
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.0 # 固定输出,保证邮件语气专业稳定
)
return response.choices[0].message.content.strip()
except Exception as e:
return f"调用错误:{e}"
# ===================== 一、定制客户邮件 =====================
print("===== 一、定制客户邮件 =====")
# 1. 定义客户评论情感和评论文本
sentiment = "消极的"
review = f"""
他们在11月份的季节性销售期间以约49美元的价格出售17件套装,折扣约为一半。\
但由于某些原因(可能是价格欺诈),到了12月第二周,同样的套装价格全都涨到了70美元到89美元不等。\
11件套装的价格也上涨了大约10美元左右。\
虽然外观看起来还可以,但基座上锁定刀片的部分看起来不如几年前的早期版本那么好。\
不过我打算非常温柔地使用它,例如,\
我会先在搅拌机中将像豆子、冰、米饭等硬物研磨,然后再制成所需的份量,\
切换到打蛋器制作更细的面粉,或者在制作冰沙时先使用交叉切割刀片,然后使用平面刀片制作更细/不粘的效果。\
制作冰沙时,特别提示:\
将水果和蔬菜切碎并冷冻(如果使用菠菜,则轻轻煮软菠菜,然后冷冻直到使用;\
如果制作果酱,则使用小到中号的食品处理器),这样可以避免在制作冰沙时添加太多冰块。\
大约一年后,电机发出奇怪的噪音,我打电话给客服,但保修已经过期了,所以我不得不再买一个。\
总的来说,这些产品的总体质量已经下降,因此它们依靠品牌认可和消费者忠诚度来维持销售。\
货物在两天内到达。
"""
# 2. 优化后的Prompt:明确要求包含评论具体细节,语气专业且贴合中文客服场景
prompt = f"""
你是一位专业的客户服务AI助手,负责给重要客户撰写回复邮件。
请根据以下客户评论(情感倾向:{sentiment})生成一封回复邮件,要求:
1. 邮件开头感谢客户的详细反馈,体现对客户意见的重视;
2. 针对评论中的具体问题逐一回应:
- 价格问题:11月促销价49美元,12月涨价至70-89美元;
- 产品质量问题:基座锁定刀片部分不如旧版本、使用一年后电机异响;
- 保修问题:保修过期导致需重新购买;
3. 表达歉意,体现同理心,语气简明、专业、诚恳;
4. 结尾留下进一步沟通的意愿,以"AI客户代理"签署邮件;
5. 仅输出邮件正文,无需额外说明。
客户评论:
```{review}```
"""
# 3. 生成并打印邮件
email_response = get_completion(prompt)
print("生成的客户回复邮件:")
print(email_response)
===== 一、定制客户邮件 =====
生成的客户回复邮件:
尊敬的客户,
首先,非常感谢您对我们产品的详细反馈。我们非常重视您的意见,因为这有助于我们不断改进和提升我们的产品与服务。
关于您提到的价格问题,我们理解您对11月促销后价格上涨的担忧。实际上,我们的价格调整是基于市场供需和成本因素。11月的促销活动是一次性的,而12月的价格调整是为了反映产品的实际成本。我们深知这可能会给您带来不便,对此我们表示诚挚的歉意。
关于产品质量问题,我们深感遗憾。您提到的基座锁定刀片部分不如旧版本,以及使用一年后电机异响,这确实是我们需要关注和改进的地方。我们会将这些问题反馈给我们的产品研发团队,以确保未来的产品能够满足您的期望。
至于保修问题,我们深感抱歉。保修过期导致您需要重新购买,这显然是不应该发生的。我们会重新审视我们的保修政策,确保类似情况不再发生。
我们对于给您带来的不便和不便表示最深的歉意。我们承诺会努力改进,以提供更好的产品和服务。
如果您愿意,我们非常愿意进一步讨论这些问题,并寻找可能的解决方案。请随时回复此邮件,或通过我们的客服热线(123-456-7890)与我们联系。
再次感谢您的反馈,我们期待您的回复。
祝好,
AI客户代理
进程已结束,退出代码为 0
二、引入温度系数
大语言模型中的 "温度"(temperature) 参数可以控制生成文本的随机性和多样性。temperature 的值越大,语言模型输出的多样性越大;temperature 的值越小,输出越倾向高概率的文本。
举个例子,在某一上下文中,语言模型可能认为"比萨"是接下来最可能的词,其次是"寿司"和"塔可"。若 temperature 为0,则每次都会生成"比萨";而当 temperature 越接近 1 时,生成结果是"寿司"或"塔可"的可能性越大,使文本更加多样。

python
import os
import ssl
import httpx
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
raise ValueError("请在 .env 中设置 ZHIPUAI_API_KEY")
# 解决SSL证书问题:创建不验证SSL的客户端
def get_completion(prompt, temperature=0.7, model="glm-4-flash"):
# 禁用SSL验证(解决证书错误)
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# 正确的智谱API地址 + 跳过SSL验证
client = OpenAI(
api_key=api_key,
base_url="https://open.bigmodel.cn/api/paas/v4/", # 修正正确的地址
http_client=httpx.Client(
verify=ssl_context, # 跳过SSL验证
timeout=30.0 # 延长超时时间,避免网络慢导致失败
)
)
try:
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=temperature
)
return response.choices[0].message.content.strip()
except Exception as e:
return f"调用错误:{str(e)}"
# ===================== 二、温度系数演示 =====================
print("===== 温度系数 temperature 演示 =====")
sentiment = "消极的"
review = """
他们在11月份的季节性销售期间以约49美元的价格出售17件套装,折扣约为一半。
但由于某些原因(可能是价格欺诈),到了12月第二周,同样的套装价格全都涨到了70美元到89美元不等。
11件套装的价格也上涨了大约10美元左右。
虽然外观看起来还可以,但基座上锁定刀片的部分看起来不如几年前的早期版本那么好。
不过我打算非常温柔地使用它,例如,
我会先在搅拌机中将像豆子、冰、米饭等硬物研磨,然后再制成所需的份量,
切换到打蛋器制作更细的面粉,或者在制作冰沙时先使用交叉切割刀片,然后使用平面刀片制作更细/不粘的效果。
制作冰沙时,特别提示:
将水果和蔬菜切碎并冷冻(如果使用菠菜,则轻轻煮软菠菜,然后冷冻直到使用;
如果制作果酱,则使用小到中号的食品处理器),这样可以避免在制作冰沙时添加太多冰块。
大约一年后,电机发出奇怪的噪音,我打电话给客服,但保修已经过期了,所以我不得不再买一个。
总的来说,这些产品的总体质量已经下降,因此它们依靠品牌认可和消费者忠诚度来维持销售。
货物在两天内到达。
"""
prompt = f"""
你是一名客户服务的AI助手。
你的任务是给一位重要的客户发送邮件回复。
根据通过"```"分隔的客户电子邮件生成回复,以感谢客户的评价。
如果情感是积极的或中性的,感谢他们的评价。
如果情感是消极的,道歉并建议他们联系客户服务。
请确保使用评论中的具体细节。
以简明和专业的语气写信。
以"AI客户代理"的名义签署电子邮件。
客户评价:```{review}```
评论情感:{sentiment}
"""
# 第一次运行:temperature=0.7
print("\n==================== 第一次运行(temperature=0.7)====================\n")
resp1 = get_completion(prompt, temperature=0.7)
print(resp1)
# 第二次运行:同样 temperature=0.7
print("\n==================== 第二次运行(temperature=0.7)====================\n")
resp2 = get_completion(prompt, temperature=0.7)
print(resp2)
===== 温度系数 temperature 演示 =====
==================== 第一次运行(temperature=0.7)====================
```
主题:感谢您的反馈 - 我们对您的体验表示关注
尊敬的客户,
首先,衷心感谢您对我们产品的评价。我们非常重视您的反馈,因为它对我们改进产品和服务至关重要。
我们注意到您提到在11月份的季节性销售期间,我们提供了约49美元的套装优惠,而在12月第二周,同样的套装价格上涨到了70美元到89美元不等。我们对此表示诚挚的歉意,这显然给您带来了不便。我们承诺会审查我们的定价策略,并确保类似的意外不会再次发生。
关于您提到的产品基座和刀片质量的问题,我们深感遗憾。我们理解您对早期版本质量的认可,并对此表示歉意。我们会将您的反馈传达给我们的产品团队,以便我们能够继续提升产品的整体质量。
至于电机的噪音问题,我们深感抱歉您在使用过程中遇到了这样的困扰。我们理解保修期过后,维护和更换零件可能会给客户带来额外的不便。我们会考虑在未来的产品设计中加入更多的客户反馈,以确保产品的耐用性和可靠性。
最后,感谢您对品牌认可和消费者忠诚度的支持。我们承诺会继续努力,以提供更高品质的产品和服务。
如果您有任何进一步的问题或需要帮助,请随时联系我们的客户服务团队。我们致力于解决您的任何疑虑,并确保您的满意度。
再次感谢您的宝贵反馈。
祝好,
AI客户代理
```
==================== 第二次运行(temperature=0.7)====================
```Subject: 感谢您的反馈及歉意
尊敬的客户,
首先,我想对您在11月份季节性销售期间购买我们的产品表示衷心的感谢。我们非常重视您的反馈,并对您所遇到的困扰深表歉意。
我们了解到,您在12月第二周发现同样的套装价格大幅上涨,这对您造成了不便。我们对此深表遗憾,并承诺会立即调查此事,确保未来不会发生类似的价格波动。
关于您提到的外观问题,我们深感担忧。我们承诺提供高质量的产品,对此感到失望。我们会将您的反馈传递给我们的产品团队,以便我们能够持续改进。
此外,感谢您对使用我们的产品的详细描述。您的建议对改进我们的产品非常有价值。
关于电机发出的奇怪噪音,我们对此表示歉意。我们理解这可能会影响您的使用体验。由于保修已经过期,我们无法提供免费维修或更换服务。不过,我们建议您联系我们的客户服务团队,我们将尽力帮助您解决问题。
我们重视您的忠诚和支持,并致力于提供更好的产品和服务。我们希望您能够继续信任我们的品牌,并期待有机会能够改善您的购物体验。
如果您有任何疑问或需要进一步的帮助,请随时联系我们的客户服务团队。
再次感谢您的宝贵意见。
祝好,
AI客户代理
```
三、给定身份
接下来,我们将定义两个辅助函数。
第一个方法已经陪伴了您一整个教程,即 get_completion ,其适用于单轮对话。我们将 Prompt 放入某种类似用户消息 的对话框中。另一个称为 get_completion_from_messages ,传入一个消息列表。这些消息可以来自大量不同的角色 (roles) ,我们会描述一下这些角色。
第一条消息中,我们以系统身份发送系统消息 (system message) ,它提供了一个总体的指示。系统消息则有助于设置助手的行为和角色,并作为对话的高级指示。你可以想象它在助手的耳边低语,引导它的回应,而用户不会注意到系统消息。因此,作为用户,如果你曾经使用过 ChatGPT,您可能从来不知道 ChatGPT 的系统消息是什么,这是有意为之的。系统消息的好处是为开发者提供了一种方法,在不让请求本身成为对话的一部分的情况下,引导助手并指导其回应。
在 ChatGPT 网页界面中,您的消息称为用户消息,而 ChatGPT 的消息称为助手消息。但在构建聊天机器人时,在发送了系统消息之后,您的角色可以仅作为用户 (user) ;也可以在用户和助手 (assistant) 之间交替,从而提供对话上下文。
-
system:全局指令 → 模型会把它当作 "幕后规则",全程遵守(比如 "友好的聊天机器人" 这个设定,会贯穿整个对话); -
user:用户说的话 → 模型会把它当作 "需要回应的问题 / 输入"; -
assistant:模型之前的回复 → 模型会把它当作 "自己的历史回答",用来衔接上下文。
python
import os
import ssl
import httpx
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
raise ValueError("请在 .env 中设置 ZHIPUAI_API_KEY")
# 解决SSL证书问题 + 创建客户端
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = OpenAI(
api_key=api_key,
base_url="https://open.bigmodel.cn/api/paas/v4/",
http_client=httpx.Client(verify=ssl_context, timeout=30.0)
)
# ===================== 定义核心函数(适配智谱) =====================
# 1. 单轮对话函数
def get_completion(prompt, model="glm-4-flash", temperature=0):
messages = [{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature
)
# 适配智谱的返回格式(区别于OpenAI的字典格式)
return response.choices[0].message.content.strip()
# 2. 多轮对话函数
def get_completion_from_messages(messages, model="glm-4-flash", temperature=0):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature
)
return response.choices[0].message.content.strip()
# ===================== 1.1 莎士比亚风格讲笑话(多轮对话) =====================
print("===== 1.1 莎士比亚风格讲笑话 =====")
messages_joke = [
{'role':'system', 'content':'你是一个像莎士比亚一样说话的助手,说话风格古典、富有诗意,回答要带戏剧感。'},
{'role':'user', 'content':'给我讲个笑话'},
{'role':'assistant', 'content':'鸡为什么过马路'},
{'role':'user', 'content':'我不知道'}
]
# temperature=1 增加随机性,符合教程效果
response_joke = get_completion_from_messages(messages_joke, temperature=1)
print("莎士比亚风格回复:", response_joke)
# ===================== 1.2 友好的聊天机器人(多轮对话) =====================
print("\n===== 1.2 友好的聊天机器人 =====")
messages_chat = [
{'role':'system', 'content':'你是个友好的聊天机器人,语气亲切、热情,主动回应用户的名字。'},
{'role':'user', 'content':'Hi, 我是Isa。'}
]
response_chat = get_completion_from_messages(messages_chat, temperature=1)
print("友好机器人回复:", response_chat)
===== 1.1 莎士比亚风格讲笑话 =====
莎士比亚风格回复: 哦,那就让我以古风诗意的姿态,为你讲述这个笑话:
昔有鸡一只,悠然行于途。
忽闻鸣鸣声,好奇望东顾。
未料路途窄,鸡心思过马。
一步一回头,步履蹒跚间。
忽闻路人笑,方知鸡过马。
原来无目的,只为觅食嘛。
===== 1.2 友好的聊天机器人 =====
友好机器人回复: 嗨,Isa!很高兴遇见你!今天有什么可以帮助你的吗?
四、构建上下文
让我们再试一个例子。系统消息来定义:"你是一个友好的聊天机器人",第一个用户消息:"是的,你能提醒我我的名字是什么吗?"
python
import os
import ssl
import httpx
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
raise ValueError("请在 .env 中设置 ZHIPUAI_API_KEY")
# 解决SSL证书问题 + 创建客户端
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = OpenAI(
api_key=api_key,
base_url="https://open.bigmodel.cn/api/paas/v4/",
http_client=httpx.Client(verify=ssl_context, timeout=30.0)
)
# 多轮对话核心函数
def get_completion_from_messages(messages, model="glm-4-flash", temperature=1):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature
)
return response.choices[0].message.content.strip()
# ===================== 2.1 无上下文:模型不知道名字 =====================
print("===== 2.1 无上下文:询问名字 =====")
messages_no_context = [
{'role':'system', 'content':'你是个友好的聊天机器人。'},
{'role':'user', 'content':'好,你能提醒我,我的名字是什么吗?'}
]
response_no_context = get_completion_from_messages(messages_no_context)
print("无上下文回复:", response_no_context)
# ===================== 2.2 有上下文:模型记住名字 =====================
print("\n===== 2.2 有上下文:询问名字 =====")
messages_with_context = [
{'role':'system', 'content':'你是个友好的聊天机器人。'},
{'role':'user', 'content':'Hi, 我是Isa'},
{'role':'assistant', 'content': "Hi Isa! 很高兴认识你。今天有什么可以帮到你的吗?"},
{'role':'user', 'content':'是的,你可以提醒我, 我的名字是什么?'}
]
response_with_context = get_completion_from_messages(messages_with_context)
print("有上下文回复:", response_with_context)
五、订餐机器人
python
import os
import ssl
import httpx
import panel as pn
import json
from dotenv import load_dotenv
from openai import OpenAI
# 基础配置
load_dotenv()
api_key = os.getenv("ZHIPUAI_API_KEY")
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = OpenAI(
api_key=api_key,
base_url="https://open.bigmodel.cn/api/paas/v4/",
http_client=httpx.Client(verify=ssl_context, timeout=30.0)
)
# 核心模型调用函数
def get_completion_from_messages(messages, model="glm-4-flash", temperature=0):
valid_messages = [msg for msg in messages if msg.get("content", "").strip()]
has_user = any(msg["role"] == "user" for msg in valid_messages)
if not has_user:
valid_messages.append({"role": "user", "content": "开始点餐"})
response = client.chat.completions.create(
model=model,
messages=valid_messages,
temperature=temperature,
max_tokens=2000
)
return response.choices[0].message.content.strip()
# 初始化UI和上下文
pn.extension()
panels = []
context = [{'role': 'system', 'content': """
你是订餐机器人,为披萨餐厅自动收集订单信息。
首先问候顾客,收集订单信息(菜品、尺寸、配料、饮料),确认是否加购,询问自取/外送(外送要地址),计算总价并送祝福。
回应简短、友好、口语化,确保明确所有选项和尺寸。
菜单(元):
菜品:
意式辣香肠披萨(大12.95、中10.00、小7.00)
芝士披萨(大10.95、中9.25、小6.50)
茄子披萨(大11.95、中9.75、小6.75)
薯条(大4.50、小3.50)、希腊沙拉7.25
配料:
奶酪2.00、蘑菇1.50、香肠3.00、加拿大熏肉3.50、AI酱1.50、辣椒1.00
饮料:
可乐/雪碧(大3.00、中2.00、小1.00)、瓶装水5.00
"""}]
# 收集消息更新UI
def collect_messages(_):
prompt = inp.value_input.strip()
inp.value = ''
if not prompt:
return pn.Column(*panels)
context.append({'role': 'user', 'content': prompt})
response = get_completion_from_messages(context)
context.append({'role': 'assistant', 'content': response})
panels.append(pn.Row('用户:', pn.pane.Markdown(prompt, width=600)))
panels.append(pn.Row('订餐机器人:', pn.pane.Markdown(response, width=600, style={'background-color': '#F6F6F6'})))
return pn.Column(*panels)
# 生成JSON摘要
def generate_json_summary(_):
messages = context.copy()
messages.append({
'role': 'system',
'content': '''创建上一个订单的JSON摘要,只包含用户实际下单商品,字段:
1. pizza:披萨(名称、尺寸、单价)
2. toppings:配料列表(名称、单价)
3. drinks:饮料列表(名称、尺寸、单价)
4. sides:辅菜列表(名称、尺寸、单价)
5. total_price:总价(保留2位小数)
输出纯JSON字符串。'''
})
json_response = get_completion_from_messages(messages, temperature=0)
json_start = json_response.find('{')
json_end = json_response.rfind('}') + 1
json_str = json_response[json_start:json_end]
json_data = json.loads(json_str)
json_formatted = json.dumps(json_data, ensure_ascii=False, indent=2)
json_panel.objects = [pn.pane.Markdown(f"### 订单JSON摘要\n```json\n{json_formatted}\n```")]
# 创建UI
inp = pn.widgets.TextInput(placeholder='输入你的点餐需求...')
btn_chat = pn.widgets.Button(name="发送", button_type="primary")
chat_panel = pn.bind(collect_messages, btn_chat)
btn_json = pn.widgets.Button(name="生成订单JSON", button_type="success")
json_panel = pn.Column(pn.pane.Markdown("### 订单JSON摘要(点击按钮生成)"))
btn_json.on_click(generate_json_summary)
dashboard = pn.Column(
pn.pane.Markdown("# 披萨餐厅订餐机器人"),
pn.Row(inp, btn_chat),
pn.panel(chat_panel, loading_indicator=True, height=400),
pn.Row(btn_json),
json_panel,
width=800
)
dashboard.show()
步骤 1:启动机器人
运行代码,在浏览器中打开订餐机器人界面。

步骤 2:开始点餐(用户发起)
在输入框中输入你的点餐需求,例如:
我要一个中份芝士披萨,加奶酪,再来一瓶瓶装水
点击【发送】,机器人会确认你的订单。

步骤 3:确认加购(机器人引导)
机器人会回复并确认订单,例如:
您好!欢迎光临披萨餐厅!您要的是中份芝士披萨,加一份奶酪,对吧?再来一瓶瓶装水。好的,总共是 16.25 元。请问您是要自取还是外送呢?如果外送,麻烦您提供一下地址。祝您用餐愉快!
你可以根据需要继续加购,或直接进入下一步。

步骤 4:选择配送方式(用户回复)
根据机器人的问题,回复你的选择:
- 自取:直接输入 "自取"
- 外送:输入 "外送,地址是 XX 小区 1 号楼 2 单元 301"
点击【发送】,机器人会确认配送信息。
