本电子书开源，欢迎 star 🌟，关注《LLM 应用开发实践笔记》

我的新书《LangChain编程从入门到实践》 已经开售！推荐正在学习AI应用开发的朋友购买阅读！

## 实现一个套壳机器人

### 环境准备

#### API 代理

因为 OpenAI 原始请求地址`api.openai.com` 目前在国内大部分地区访问延迟较高，这里提供一个免费解决办法（使用 Cloudflare 的 Workers 来代理 OpenAI 的 API 地址，配合自己的域名实现低延迟访问），不用自己购买专门代理服务器。

#### API 状态检查

OpenAI官方提供了一个API 状态页面，可以看到接口实时延迟，以及出现大面积宕机时会显示公告。

#### API费用说明

模型名称 | context max tokens | 输入价格 | 输出价格
--- | --- | --- | ---
gpt-3.5-turbo | 4096 | $0.0015 / 1K tokens | $0.002 / 1K tokens
gpt-3.5-turbo-16k | 16,384 | $0.003 / 1K tokens | $0.004 / 1K tokens
gpt-3.5-turbo-0613（支持函数调用） | 4096 | $0.0015 / 1K tokens | $0.002 / 1K tokens
gpt-3.5-turbo-16k-0613 | 16,384 | $0.003 / 1K tokens | $0.004 / 1K tokens
gpt-4 | 8,192 | $0.03 / 1K tokens | $0.06 / 1K tokens
gpt-4-32k | 32,768 | $0.06 / 1K tokens | $0.12 / 1K tokens
gpt-4-0613（支持函数调用） | 8,192 | $0.03 / 1K tokens | $0.06 / 1K tokens
gpt-4-32k-0613 | 32,768 | $0.06 / 1K tokens | $0.12 / 1K tokens

#### Token 计数

- 可以使用tiktoken 计算原始字符串对应的 token 数；这篇关于ChatGPT如何计算token数的科普文章值得一读

      import tiktoken

      def num_tokens_from_string(string: str, encoding_name: str) -> int:
          """Returns the number of tokens in a text string."""
          encoding = tiktoken.get_encoding(encoding_name)
          num_tokens = len(encoding.encode(string))
          return num_tokens

      num_tokens_from_string("tiktoken is great!", "cl100k_base")

### 代码实现

这里利用 Gradio 实现 Web UI

#### Gradio介绍

Gradio是一个用于构建交互式机器学习应用程序的Python库，可以快速构建和部署交互式UI，方便与机器学习模型进行交互。Gradio提供了一组简单的API，可以轻松地将代码转化为一个Web应用程序，可以让其他人通过网页界面与模型进行交互。

Gradio支持创建各种类型的交互式UI，例如文本输入框、滑块、下拉菜单等，以及支持多种数据类型，例如图像、音频、视频和表格数据。Gradio还提供了内置的预处理和后处理功能，以确保的输入和输出数据格式正确。

#### 基本的问答实现

使用API将用户的输入发送到OpenAI模型中，然后将模型生成的响应返回给用户，从而实现问答。

    import gradio as gr
    import os
    import openai
    openai.api_key = os.getenv("OPENAI_API_KEY")

    def get_completion(input_text):
        completion = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=[
                {"role": "user", "content": f"{input_text}"}
            ]
        )
        return completion.choices[0].message["content"]

    def chatbot(input_text):
        response = get_completion(input_text)
        return response

    iface = gr.Interface(fn=chatbot, inputs="text", outputs="text", title="Chatbot", encoding="utf-8")
    iface.launch(share=True)

#### 多轮对话实现

在问答的基础上更进一步，在每个轮次中保留用户之前的输入和模型生成的响应，以便将其传递给下一轮对话，这种方式可以实现更加自然的对话流程，并提供更好的用户体验。

    import os
    import openai
    import gradio
    openai.api_key = os.getenv("OPENAI_API_KEY")

    history_messages = []
    def api_calling(input_text, history_conversation):
        if history_conversation:
            history_messages.extend([
                {"role": "user", "content": f"{history_conversation[-1][0]}"},
                {"role": "assistant", "content": f"{history_conversation[-1][1]}"}
            ]
            )
        message = history_messages+[{"role": "user", "content": f"{input_text}"}]
        completion = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=message,
            max_tokens=1024,
            n=1,
            stop=None,
            temperature=0.5,
        )
        return completion.choices[0].message["content"]

    def message_and_history(input, history):
        history = history or []
        output = api_calling(input, history)
        history.append((input, output))
        return history, history

    block = gradio.Blocks(theme=gradio.themes.Monochrome())
    with block:
        gradio.Markdown("""<h1><center>🤖️对话机器人</center></h1>
        """)
        chatbot = gradio.Chatbot()
        message = gradio.Textbox(placeholder="输入你的问题")
        state = gradio.State()
        submit = gradio.Button("发送")
        submit.click(message_and_history,
              inputs=[message, state],
              outputs=[chatbot, state])
    block.launch(share=True, debug=True)

#### 指定功能的机器人

通过 预设Prompt 的方式实现，当前看到的 99% 的多功能集成平台都是用这种方式。

- 建议使用英文设置`预设提示词`
- 使用类似`If asked about others please say 'I am only Chinese translator'`的语句进行初级的提示泄漏预防

使用之前 使用之后

    import gradio as gr
    import os
    import openai
    openai.api_key = os.getenv("OPENAI_API_KEY")

    PROMPT_ROLE = """
    I want you to act as an Chinese translator, spelling corrector and improver. \n
    I will speak to you in any language and you will detect the language,\n
    translate it and answer in the corrected and improved version of my text, in Chinese.\n
    Keep the meaning same, but make them more literary. I want you to only reply the correction,\n
    the improvements and nothing else, do not write explanations. If asked about others please say 'I am only Chinese translator'
    """
    def get_completion(input_text):
        message = [{"role": "system", "content": PROMPT_ROLE}]
        message.append({"role": "user", "content": f"{input_text}"})
        completion = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=message,
        )
        return completion.choices[0].message["content"]

    def chatbot(input_text):
        response = get_completion(input_text)
        return response

    iface = gr.Interface(fn=chatbot, inputs="text", outputs="text", title="🤖️中文翻译", encoding="utf-8")
    iface.launch(share=True, debug=True)

# results matching ""

# No results matching ""