基础概念

给LLM提示

Prompt 是一种在自然语言处理(NLP)中用于引导语言模型生成特定类型文本的技术。它的基本原理是通过向语言模型提供一个包含任务相关信息的输入文本片段(即 Prompt),利用语言模型在预训练阶段学到的语言知识和模式,引导模型生成符合预期的输出。

你可以通过简单的提示词(Prompts)获得大量结果,但结果的质量与你提供的信息数量和完善度有关。一个提示词可以包含你传递到模型的指令问题等信息,也可以包含其他详细信息,如上下文输入示例等。你可以通过这些元素来更好地指导模型,并因此获得更好的结果。

提示词要素

提示词可以包含以下任意要素:

  • 指令:想要模型执行的特定任务或指令。
  • 上下文:包含外部信息或额外的上下文信息,引导语言模型更好地响应。
  • 输入数据:用户输入的内容或问题。
  • 输出指示:指定输出的类型或格式。

设计提示

  • 从简单开始:

        你可以从简单的提示词开始,并逐渐添加更多元素和上下文(因为你想要更好的结果)。因此,在这个过程中不断迭代你的提示词是至关重要的。

        当你有一个涉及许多不同子任务的大任务时,可以尝试将任务分解为更简单的子任务,并随着结果的改善逐步构建。这避免了在提示设计过程中一开始就添加过多的复杂性。

  • 指令

        你可以使用命令来指示模型执行各种简单任务,例如“写入”、“分类”、“总结”、“翻译”、“排序”等,从而为各种简单任务设计有效的提示。

  • 具体性

        要非常具体地说明你希望模型执行的指令和任务。提示越具描述性和详细,结果越好。特别是当你对生成的结果或风格有要求时,这一点尤为重要。不存在什么特定的词元(tokens)或关键词(tokens)能确定带来更好的结果。更重要的是要有一个具有良好格式和描述性的提示词。

  • 避免不明确

        通常来说,具体和直接会更好。这里的类比非常类似于有效沟通——越直接,信息传达得越有效。

  • 做什么还是不做什么

        设计提示时的另一个常见技巧是避免说不要做什么,而应该说要做什么。这样(说要做什么)更加的具体,并且聚焦于(有利于模型生成良好回复的)细节上。

提示工程指南:https://www.promptingguide.ai/zh

需要注意的是,当使用 OpenAI 的 gpt-4 或者 gpt-3.5-turbo 等聊天模型时,你可以使用三个不同的角色来构建 prompt: systemuser 和 assistant。其中 system 不是必需的,但有助于设定 assistant 的整体行为,帮助模型了解用户的需求,并根据这些需求提供相应的响应。你可以使用 user 消息直接作为 prompt。你还可以定义 assistant 消息来传递模型所需行为的示例。

提示工程实践

零样本提示

零样本提示(Zero-shot) 是指在没有向模型提供任何示例的情况下完成任务。模型必须依靠其预训练知识和提示来生成答案。

这种方法的优势是任务通用性高,可以快速应用于各种新任务,而且能够节省训练资源和时间,也不会消耗特别多的Token。但由于没有针对特定任务进行训练,所以生成内容的准确性可能不如经过特定任务训练的模型。

Java示例

public class ZeroShotPromptingDemo {

    public static void main(String[] args) {
        String input = "将文本分类为中性、负面或正面。" +
                "文本:我认为这次假期还可以。" +
                "情感:";
        String output = DeepSeekModelUtils.textModelExecution("deepseek-chat",input);
        System.out.println(output);
    }

}

Utils方法:

public class DeepSeekModelUtils {

    private static final String BASE_URL = "https://api.deepseek.com";

    private static final String COMPLETIONS_URL = BASE_URL + "/chat/completions";

    private static final String API_KEY = "yourself-api-key";

    public static String textModelExecution(String model, String prompt) {
        if (model == null || model.isEmpty()) {
            model = "deepseek-chat";
        }
        OkHttpClient client = new OkHttpClient().newBuilder()
                .readTimeout(20, TimeUnit.SECONDS)
                .connectTimeout(20, TimeUnit.SECONDS)
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        String json = String.format("{" +
                "  \"messages\": [" +
                "    {" +
                "      \"content\": \"You are a helpful assistant\"," +
                "      \"role\": \"system\"" +
                "    }," +
                "    {" +
                "      \"content\": \"%s\"," +
                "      \"role\": \"user\"" +
                "    }" +
                "  ]," +
                "  \"model\": \"%s\"," +
                "  \"thinking\": {" +
                "    \"type\": \"disabled\"" +
                "  }," +
                "  \"frequency_penalty\": 0," +
                "  \"max_tokens\": 4096," +
                "  \"presence_penalty\": 0," +
                "  \"response_format\": {" +
                "    \"type\": \"text\"" +
                "  }," +
                "  \"stop\": null," +
                "  \"stream\": false," +
                "  \"stream_options\": null," +
                "  \"temperature\": 1," +
                "  \"top_p\": 1," +
                "  \"tools\": null," +
                "  \"tool_choice\": \"none\"," +
                "  \"logprobs\": false," +
                "  \"top_logprobs\": null" +
                "}", prompt, model);
        RequestBody body = RequestBody.create(mediaType, json);
        try {
            Request request = new Request.Builder()
                    .url(COMPLETIONS_URL)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .addHeader("Authorization", "Bearer " + API_KEY)
                    .build();
            Response response = client.newCall(request).execute();
            return response.body().string();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

返回结果:

{
    "id": "ae444da8-8a9f-4b66-86d4-62184941ba70",
    "object": "chat.completion",
    "created": 1775628118,
    "model": "deepseek-chat",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "中性"
            },
            "logprobs": null,
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 28,
        "completion_tokens": 1,
        "total_tokens": 29,
        "prompt_tokens_details": {
            "cached_tokens": 0
        },
        "prompt_cache_hit_tokens": 0,
        "prompt_cache_miss_tokens": 28
    },
    "system_fingerprint": "fp_eaab8d114b_prod0820_fp8_kvcache_new_kvcache"
}

优化返回结果

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ChatCompletionResponse {
    @JsonProperty("id")
    public String id;

    @JsonProperty("object")
    public String object;

    @JsonProperty("created")
    public Long created;

    @JsonProperty("model")
    public String model;

    @JsonProperty("choices")
    public List<Choice> choices;

    @JsonProperty("usage")
    public Usage usage;

    @JsonProperty("system_fingerprint")
    public String systemFingerprint;
}

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Choice {
    @JsonProperty("index")
    public Integer index;

    @JsonProperty("message")
    public Message message;

    @JsonProperty("logprobs")
    public Object logprobs; // null,可设为 Object 或自定义类

    @JsonProperty("finish_reason")
    public String finishReason;
}

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Message {
    @JsonProperty("role")
    public String role;

    @JsonProperty("content")
    public String content;
}

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Usage {
    @JsonProperty("prompt_tokens")
    public Integer promptTokens;

    @JsonProperty("completion_tokens")
    public Integer completionTokens;

    @JsonProperty("total_tokens")
    public Integer totalTokens;

    @JsonProperty("prompt_tokens_details")
    public PromptTokensDetails promptTokensDetails;

    @JsonProperty("prompt_cache_hit_tokens")
    public Integer promptCacheHitTokens;

    @JsonProperty("prompt_cache_miss_tokens")
    public Integer promptCacheMissTokens;
}

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class PromptTokensDetails {
    @JsonProperty("cached_tokens")
    public Integer cachedTokens;

}

在Utils中添加

ObjectMapper mapper = new ObjectMapper();
String responseBody = response.body().string();
// 使用 Jackson 将 JSON 字符串转换为 ChatCompletionResponse 对象
ChatCompletionResponse completionResponse = mapper.readValue(responseBody, ChatCompletionResponse.class);
String content = completionResponse.getChoices().get(0).getMessage().getContent();

少样本提示

在使用零样本设置时,它们在更复杂的任务上仍然表现不佳。少样本提示(Few-shot) 可以作为一种技术,以启用上下文学习,我们在提示中提供演示以引导模型实现更好的性能。

Java示例

没有添加示例

public class FewShotPromptingDemo {

    public static void main(String[] args) {
        String input = "“farduddle”是指快速跳上跳下。一个使用farduddle这个词的句子的例子是:";
        String output = DeepSeekModelUtils.textModelExecution("deepseek-chat",input);
        System.out.println(output);
    }

}

输出是

The children began to **farduddle** on the trampoline, laughing each time they bounced up and down.

添加示例

public class FewShotPromptingDemo {

    public static void main(String[] args) {
        String input = "“whatpu”是坦桑尼亚的一种小型毛茸茸的动物。一个使用whatpu这个词的句子的例子是:" +
                "我们在非洲旅行时看到了这些非常可爱的whatpus。" +
                "“farduddle”是指快速跳上跳下。一个使用farduddle这个词的句子的例子是:";
        String output = DeepSeekModelUtils.textModelExecution("deepseek-chat",input);
        System.out.println(output);
    }

}

输出是

“farduddle”是指快速跳上跳下。一个使用farduddle这个词的句子的例子是:孩子们在蹦床上兴奋地farduddle,玩得不亦乐乎。
少样本提示的限制

标准的少样本提示对许多任务都有效,但仍然不是一种完美的技术,特别是在处理更复杂的推理任务时。少样本提示不足以获得推理类型问题的可靠响应。

这组数字中的奇数加起来是一个偶数:15、32、5、13、82、7、1。A:

如果我们再试一次,模型输出如下:

是的,这组数字中的奇数加起来是107,是一个偶数。

这不是正确的答案,这不仅突显了这些系统的局限性,而且需要更高级的提示工程。

让我们尝试添加一些示例,看看少样本提示是否可以改善结果。

提示:

这组数字中的奇数加起来是一个偶数:4、8、9、15、12、2、1。A:答案是False。这组数字中的奇数加起来是一个偶数:17、10、19、4、8、12、24。A:答案是True。这组数字中的奇数加起来是一个偶数:16、11、14、4、8、13、24。A:答案是True。这组数字中的奇数加起来是一个偶数:17、9、10、12、13、4、2。A:答案是False。这组数字中的奇数加起来是一个偶数:15、32、5、13、82、7、1。A:

输出:

答案是True。

备注:这是提示工程指南中少样本提示对于推理类型任务的限制示例,在当前deepseek的 API请求中对于该示例的响应已经可以正确识别,但是不影响接下来对于思维链(CoT)提示
的思考。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐