首页 / 资料库 / 微软 · 生成式 AI 入门

资料库16 分钟读完MIT文本生成openaiAzure入门

构建文本生成应用(下)

译自《Building Text Generation Applications》 · 查看英文原文

原文出处Building Text Generation Applications 原作者:Microsoft · 许可证:MIT License 中文译本由诸葛AI学院整理,仅供学习参考,版权归原作者与微软所有。

构建文本生成应用(下):菜谱生成器实战与参数调优

(接上篇)上篇装好了 openai 库,配好密钥与端点,跑通了第一个文本生成应用。这篇从这里接着讲:提示词还能玩出哪些花样,怎么做一个真正实用的菜谱生成器,以及密钥、令牌、温度这些工程细节怎么打磨。

不同的提示词,对应不同的用途

你已经见过怎么用一个提示词生成文本,手上也有一个能改能调的程序,可以生成不同类型的文字。

提示词能胜任的任务五花八门。例如:

  • 生成某种类型的文本。比如写一首诗,或者出一套测验题。
  • 查找信息。可以用提示词去找答案,比如问"Web 开发里的 CORS 是什么意思?"
  • 生成代码。可以用提示词生成代码,例如写一个校验邮箱的正则表达式,或者干脆生成一整个程序,比如一个 Web 应用?

更实际的用例:菜谱生成器

假设你家里有些食材,想做点什么菜,这就需要一份菜谱。找菜谱的办法,要么用搜索引擎,要么用大语言模型。

你可以写这样一条提示词:

"给我推荐 5 个菜谱,用料是鸡肉、土豆和胡萝卜。每个菜谱把用到的全部食材列出来"

针对这条提示词,你拿到的回答可能长这样:

```output 1. 烤鸡肉配蔬菜: 食材: - 鸡腿 4 只 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 橄榄油 2 汤匙 - 大蒜 2 瓣,切末 - 干百里香 1 茶匙 - 干牛至 1 茶匙 - 盐、胡椒,适量

  1. 土豆炖鸡: 食材: - 橄榄油 2 汤匙 - 洋葱 1 个,切丁 - 大蒜 2 瓣,切末 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 1 杯 - 盐、胡椒,适量

  2. 焗烤鸡肉土豆: 食材: - 橄榄油 2 汤匙 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 洋葱 1 个,切丁 - 大蒜 2 瓣,切末 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 1 杯 - 盐、胡椒,适量

  3. 鸡肉土豆汤: 食材: - 橄榄油 2 汤匙 - 洋葱 1 个,切丁 - 大蒜 2 瓣,切末 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 4 杯 - 盐、胡椒,适量

  4. 鸡肉土豆杂烩: 食材: - 橄榄油 2 汤匙 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 洋葱 1 个,切丁 - 大蒜 2 瓣,切末 - 干牛至 1 茶匙 ```

结果相当不错,我知道该做什么菜了。到这一步,还有两处可以改进:

  • 把我不喜欢的、或者过敏的食材过滤掉。
  • 生成一份购物清单,万一家里食材不够。

针对这两点,我们再加一条提示词:

"我对大蒜过敏,请把含大蒜的菜谱去掉,换成别的调料。另外帮我列一份购物清单,家里已经有鸡肉、土豆和胡萝卜。"

于是你得到一份新结果:

```output 1. 烤鸡肉配蔬菜: 食材: - 鸡腿 4 只 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 橄榄油 2 汤匙 - 干百里香 1 茶匙 - 干牛至 1 茶匙 - 盐、胡椒,适量

  1. 土豆炖鸡: 食材: - 橄榄油 2 汤匙 - 洋葱 1 个,切丁 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 1 杯 - 盐、胡椒,适量

  2. 焗烤鸡肉土豆: 食材: - 橄榄油 2 汤匙 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 洋葱 1 个,切丁 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 1 杯 - 盐、胡椒,适量

  3. 鸡肉土豆汤: 食材: - 橄榄油 2 汤匙 - 洋葱 1 个,切丁 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 干牛至 1 茶匙 - 干百里香 1 茶匙 - 鸡汤 4 杯 - 盐、胡椒,适量

  4. 鸡肉土豆杂烩: 食材: - 橄榄油 2 汤匙 - 鸡胸肉 2 块,切块 - 土豆 2 个,切块 - 胡萝卜 2 根,切块 - 洋葱 1 个,切丁 - 干牛至 1 茶匙

购物清单: - 橄榄油 - 洋葱 - 百里香 - 牛至 - 盐 - 胡椒 ```

五道菜谱,没有提到大蒜。购物清单也附上了,家里已有的食材都考虑到了。

练习:动手做菜谱生成器

上面演示了一个场景,现在写代码把它复现出来。按下面步骤来:

  1. 拿上一节的 app.py 文件当起点。

  2. 找到 prompt 变量,把代码改成下面这样:

python prompt = "Show me 5 recipes for a dish with the following ingredients: chicken, potatoes, and carrots. Per recipe, list all the ingredients used"

现在运行代码,你会看到一个大致如下的输出:

```output -土豆胡萝卜炖鸡:油 3 汤匙,洋葱 1 个切丁,大蒜 2 瓣切末,胡萝卜 1 根去皮切块,土豆 1 个去皮切块,月桂叶 1 片,百里香 1 小枝,盐 1/2 茶匙,黑胡椒 1/4 茶匙,鸡汤 1 杯半,干白葡萄酒 1/2 杯,切碎的欧芹 2 汤匙,无盐黄油 2 汤匙,去骨去皮鸡腿 1 磅半切成 1 英寸块

-烤鸡配土豆胡萝卜:特级初榨橄榄油 3 汤匙,第戎芥末酱 1 汤匙,新鲜迷迭香碎 1 汤匙,新鲜百里香碎 1 汤匙,大蒜 4 瓣切末,小红土豆 1 磅半切四瓣,胡萝卜 1 磅半纵向切四瓣,盐 1/2 茶匙,黑胡椒 1/4 茶匙,整鸡 1 只(4 磅)

-鸡肉土豆胡萝卜砂锅:烹饪喷雾,大洋葱 1 个切丁,大蒜 2 瓣切末,胡萝卜 1 根去皮擦丝,土豆 1 个去皮擦丝,干百里香叶 1/2 茶匙,盐 1/4 茶匙,黑胡椒 1/4 茶匙,无脂低钠鸡汤 2 杯,冷冻豌豆 1 杯,中筋面粉 1/4 杯,2% 低脂牛奶 1 杯,帕玛森奶酪碎 1/4 杯

-一锅炖鸡肉土豆:橄榄油 2 汤匙,去骨去皮鸡腿 1 磅切 1 英寸块,大洋葱 1 个切丁,大蒜 3 瓣切末,胡萝卜 1 根去皮切块,土豆 1 个去皮切块,月桂叶 1 片,百里香 1 小枝,盐 1/2 茶匙,黑胡椒 1/4 茶匙,鸡汤 2 杯,干白葡萄酒 1/2 杯

-鸡肉土豆咖喱:植物油 1 汤匙,大洋葱 1 个切丁,大蒜 2 瓣切末,胡萝卜 1 根去皮切块,土豆 1 个去皮切块,芫荽粉 1 茶匙,孜然粉 1 茶匙,姜黄粉 1/2 茶匙,生姜粉 1/2 茶匙,卡宴辣椒粉 1/4 茶匙,鸡汤 2 杯,干白葡萄酒 1/2 杯,鹰嘴豆 1 罐(15 盎司)沥干冲洗,葡萄干 1/2 杯,新鲜香菜碎 1/2 杯 ```

注意:大语言模型的输出是非确定性的(nondeterministic),同一份程序每跑一遍,结果都可能不一样。

好,接下来想想怎么改进。要改进,就得让代码足够灵活,菜谱数量和食材都能随时调整。

  1. 把代码改成下面这样:

```python no_recipes = input("No of recipes (for example, 5): ")

ingredients = input("List of ingredients (for example, chicken, potatoes, and carrots): ")

# 把菜谱数量和食材列表插值进提示词 prompt = f"Show me {no_recipes} recipes for a dish with the following ingredients: {ingredients}. Per recipe, list all the ingredients used" ```

试跑一次,效果可能像这样:

```output No of recipes (for example, 5): 3 List of ingredients (for example, chicken, potatoes, and carrots): milk,strawberries

-草莓奶昔:牛奶、草莓、糖、香草精、冰块 -草莓奶油蛋糕:牛奶、面粉、泡打粉、糖、盐、无盐黄油、草莓、打发奶油 -草莓牛奶:牛奶、草莓、糖、香草精 ```

上面输出里的前两行是程序的提问原文(对应代码里 input() 的英文提示),后面三行才是模型生成的菜谱。

加上过滤和购物清单,继续改进

现在这个应用已经能出菜谱了,也够灵活:做几个菜、用什么食材,都由用户输入决定。

想再好一点,还可以加这两样:

  • 过滤食材。我们不想要的、或者吃了过敏的食材,应该能被排除掉。做到这一点很简单:在现有提示词末尾加一个过滤条件,像这样:

```python filter = input("Filter (for example, vegetarian, vegan, or gluten-free): ")

prompt = f"Show me {no_recipes} recipes for a dish with the following ingredients: {ingredients}. Per recipe, list all the ingredients used, no {filter}" ```

上面这段往提示词末尾加了 {filter},过滤条件由用户输入。现在跑一遍程序,输入可能是这样:

```output No of recipes (for example, 5): 3 List of ingredients (for example, chicken, potatoes, and carrots): onion,milk Filter (for example, vegetarian, vegan, or gluten-free): no milk

  1. 法式洋葱汤

食材:

-大洋葱 1 个,切片 -牛肉高汤 3 杯 -牛奶 1 杯 -法式面包片 6 片 -帕玛森奶酪碎 1/4 杯 -黄油 1 汤匙 -干百里香 1 茶匙 -盐 1/4 茶匙 -黑胡椒 1/4 茶匙

做法:

  1. 大锅烧热,黄油炒洋葱至金黄。
  2. 加入牛肉高汤、牛奶、百里香、盐、胡椒,煮开。
  3. 转小火炖 10 分钟。
  4. 面包片铺在汤碗底。
  5. 把汤浇在面包上。
  6. 撒上帕玛森奶酪。

  7. 洋葱土豆汤

食材:

-大洋葱 1 个,切丁 -土豆 2 杯,切丁 -蔬菜高汤 3 杯 -牛奶 1 杯 -黑胡椒 1/4 茶匙

做法:

  1. 大锅烧热,黄油炒洋葱至金黄。
  2. 加入土豆、蔬菜高汤、牛奶、胡椒,煮开。
  3. 转小火炖 10 分钟。
  4. 趁热上桌。

  5. 奶油洋葱汤

食材:

-大洋葱 1 个,切丁 -蔬菜高汤 3 杯 -牛奶 1 杯 -黑胡椒 1/4 茶匙 -中筋面粉 1/4 杯 -帕玛森奶酪碎 1/2 杯

做法:

  1. 大锅烧热,黄油炒洋葱至金黄。
  2. 加入蔬菜高汤、牛奶、胡椒,煮开。
  3. 转小火炖 10 分钟。
  4. 小碗里把面粉和帕玛森奶酪搅匀。
  5. 倒进汤里再炖 5 分钟,直到汤变浓稠。 ```

可以看到,含牛奶的菜谱被过滤掉了。不过如果你是乳糖不耐受,含奶酪的菜谱最好也排除掉,所以过滤条件要说得足够明确。

  • 生成购物清单。我们想要一份购物清单,并且考虑家里已有的食材。

实现这个功能有两条路:一条提示词解决所有问题,或者拆成两条提示词。我们试后面这种。这里要再加一条提示词,但前提是把第一条提示词的结果作为上下文喂给第二条。

找到代码里打印第一条提示词结果的位置,在它下面加上这段代码:

```python old_prompt_result = response.output_text prompt = "Produce a shopping list for the generated recipes and please don't include ingredients that I already have."

new_prompt = f"{old_prompt_result} {prompt}" response = client.responses.create(model=deployment_name, input=new_prompt, max_output_tokens=1200, store=False)

# 打印响应 print("Shopping list:") print(response.output_text) ```

留意两个地方:

  1. 新提示词是拼出来的:第一条提示词的结果加上新问题。

    python new_prompt = f"{old_prompt_result} {prompt}"

  2. 又发了一次请求,同时考虑了上一条请求已经占掉的令牌数,所以这次把 max_output_tokens 定为 1200。

    python response = client.responses.create(model=deployment_name, input=new_prompt, max_output_tokens=1200, store=False)

    这段代码跑起来,输出大概是这样:

    ```output No of recipes (for example, 5): 2 List of ingredients (for example, chicken, potatoes, and carrots): apple,flour Filter (for example, vegetarian, vegan, or gluten-free): sugar

    -苹果面粉煎饼:面粉 1 杯,泡打粉 1/2 茶匙,小苏打 1/2 茶匙,盐 1/4 茶匙,糖 1 汤匙,鸡蛋 1 个,酪乳(或酸牛奶)1 杯,融化黄油 1/4 杯,澳洲青苹果 1 个去皮擦丝 -炸苹果面团:面粉 1 杯半,泡打粉 1 茶匙,盐 1/4 茶匙,小苏打 1/4 茶匙,肉豆蔻粉 1/4 茶匙,肉桂粉 1/4 茶匙,多香果粉 1/4 茶匙,糖 1/4 杯,起酥油 1/4 杯,牛奶 1/4 杯,鸡蛋 1 个,擦丝去皮苹果 2 杯 Shopping list: -面粉、泡打粉、小苏打、盐、糖、鸡蛋、酪乳、黄油、苹果、肉豆蔻、肉桂、多香果 ```

改进你的配置

到这一步,代码能跑了,但还有几处值得打磨。该做的事有这么几件:

  • 密钥和代码分开,比如 API 密钥。密钥不该出现在代码里,要存到安全的地方。分开存放的办法:用环境变量(environment variable),再配合 python-dotenv 这类库从文件里加载。代码里是这样:
  1. 建一个 .env 文件,内容如下:

    bash OPENAI_API_KEY=sk-...

    注意,如果用 Microsoft Foundry 里的 Azure OpenAI,要设置的是这几个环境变量:

    bash AZURE_OPENAI_API_KEY=<replace> AZURE_OPENAI_ENDPOINT=<replace> AZURE_OPENAI_API_VERSION=2024-10-21

    在代码里,这样加载环境变量:

    ```python import os from dotenv import load_dotenv from openai import OpenAI

    load_dotenv()

    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"]) ```

  • 说说令牌长度。要生成目标文本需要多少令牌(token),得心里有数。令牌是要花钱的,能省就省。比如:同样的意思,提示词能不能写得更短?

想控制令牌用量,用 max_output_tokens 参数。例如只想用 100 个令牌:

python response = client.responses.create(model=deployment, input=prompt, max_output_tokens=100, store=False)

  • 拿温度做做实验。温度(temperature)我们一直没提,但它对程序表现影响很大。温度值越高,输出越随机;越低,输出越可预测。你的应用要不要多样化输出,要想清楚。

调温度用 temperature 参数。例如想用 0.5:

python response = client.responses.create(model=deployment, input=prompt, temperature=0.5, store=False)

注意,越接近 1.0,输出越多样。

  • 推理模型不支持 temperature。这是 2026 年的一个重要变化。Microsoft Foundry 上当前未被弃用的模型是推理模型(reasoning model,GPT-5 系列和 o 系列),它们不支持 temperaturetop_p(也不支持 max_tokens,请用 max_output_tokens)。给 gpt-5-minitemperature,会收到一个"parameter not supported"错误。所以想试上面的温度例子,就换一个仍支持采样控制的模型,比如 Microsoft Foundry 模型目录里的开源 Llama 模型(如 Llama-3.3-70B-Instruct),通过 Foundry Models / Azure AI Inference 端点调用(和 githubmodels-* 示例的调用方式相同)。对 GPT-5 这类推理模型,控制输出的思路不一样:
  • 提示工程:清晰的指令、示例、结构化输出,这些活儿以前是采样参数干的,现在交给提示工程(参见第 4 课:提示工程基础)。
  • 推理控制:像 reasoning effort(推理投入)、verbosity(详尽度)这类参数,用来在推理深度、延迟和成本之间做取舍。

一句话总结:temperature/top_p 在很多模型上仍然有效(Llama、Mistral、Phi,以及 GPT-4.x 家族,尽管 GPT-4.x 正在弃用),但行业方向是在推理模型(如 GPT-5)上做提示工程加推理控制。

作业

这次作业,做什么由你定。

给几个建议:

  • 继续打磨菜谱生成器。调一调温度值,改一改提示词,看看能玩出什么花样。
  • 做一个"学习伙伴"。这个应用要能回答某个主题的问题,比如 Python:你可以问"Python 里的某个主题是什么?",也可以让它展示某个主题的代码。
  • 做一个历史人物机器人,让历史活过来。让机器人扮演某位历史人物,问它生平年代的问题。

参考答案

学习伙伴

下面是一条起步提示词,看你怎么用,按自己的喜好改。

```text - "You're an expert on the Python language

Suggest a beginner lesson for Python in the following format:

Format:
- concepts:
- brief explanation of the lesson:
- exercise in code with solutions"

```

历史人物机器人

你可以用这样的提示词:

```text - "You are Abe Lincoln, tell me about yourself in 3 sentences, and respond using grammar and words like Abe would have used" - "You are Abe Lincoln, respond using grammar and words like Abe would have used:

Tell me about your greatest accomplishments, in 300 words" ```

知识检验

温度这个概念是干什么的?

  1. 控制输出的随机程度。
  2. 控制回答的长度。
  3. 控制使用多少令牌。

挑战

做作业的时候,试着改变温度值,分别设成 0、0.5 和 1。记住,0 是最不变的,1 是最多样的。哪个值最适合你的应用?

做得好!继续学习

学完这节课,去看看生成式 AI 学习合集,继续精进你的生成式 AI 知识。

然后前往第 7 课,学习怎么构建聊天应用

这篇在讲什么,跟咱们的课怎么对?

资料库是大厂公开教材的中文译本,偏原理和工程做法。想看面向中小企业的白话版本,去入门课场景课