前段时间,给文章接入了 TianliGPT ,实现了自动生成文章摘要(太长不看)模块。TianliGPT 提供了非常简单快捷的嵌入方式,但是 TianliGPT 专注于摘要生成以及相关文章推荐功能,如果想要对其进行拓展,则有比较大的局限性。所以最近放弃了 TianliGPT 转而使用 Moonshot AI 进行文章摘要的生成和额外功能的拓展。
确定需求
首先,我们想除了给文章生成摘要以外,还能针对文章的内容提出相关问题以及对应的答案,点击问题后会显示对应问题的答案。效果类似于下图:

文章摘要模块预览图
根据上面的需求,需要模型给我们返回类似于下面 JSON 格式的内容,再交给前端进行处理:
进而能设计出下面的 prompt 交给模型:
Noteprompt(提示词)指的是给模型提供的信息或指令,用以引导模型生成特定的响应或输出,它决定了模型如何理解和处理用户输入。一个有效的 prompt 通常包括以下几个要素:明确性、相关性、简洁性、上下文、指令性。
由于 Kimi 和 Moonshot AI 提供的模型是同源的,所以我们可以通过使用 Kimi 测试,在一定程度上预测使用 Moonshot API 时可能获得的结果 (其实是为了省钱) 。为了确认这个 prompt 是否可以实现我们想要的效果,尝试使用它与 Kimi 对话,结果如下图:

模型对话结果
与模型发起对话
在解决了应该与模型交流什么这个问题之后,我们需要解决的是怎么与模型交流的问题。Moonshot AI 的官网文档提供了 Python 和 Node.js 两种版本的实现方法,而这里会使用 PHP 来实现相应的功能。
官方为我们提供了一个 Chat Completions 的 API:https://api.moonshot.cn/v1/chat/completions,同时请求头和请求内容的示例如下:
model为模型名称,Moonshot-v1 目前有moonshot-v1-8k、moonshot-v1-32k、moonshot-v1-128k三个模型。messages数组为对话的消息列表,其中 role 的取值为system、user以及assistan其一:system 代表系统消息,为对话提供上下文或指导,一般填入 prompt;user 代表用户的消息,即用户的提问或输入;assistant 代表模型的回复。temperature为采样温度,推荐0.3。
我们可以构建一个 MoonshotAPI 类来实现这个功能:
[!NOTE] 如果你直接在提示词 prompt 中告诉 Kimi 大模型:“请输出 JSON 格式的内容”,Kimi 大模型能理解你的诉求,也会按要求生成 JSON 文档,但生成的内容通常会有一些瑕疵,例如在 JSON 文档之外,Kimi 还会额外地输出其他文字内容对 JSON 文档进行解释。
所以这里我们需要在构造请求内容时启用 JSON Mode,让模型“按照要求输出一个合法的、可被正确解析的 JSON 文档” ,即给 preparePayload 方法的返回数组内加上 'response_format' => ["type" => "json_object"]。
显而易见,MoonshotAPI 类接受的三个参数中,只有 $messages 对话消息列表这个参数是比较复杂的,所以我们创建一个 getMessages 函数来构建对话消息列表数组。
这里我们把一开始设计好的 prompt 填入 system 消息,把文章内容填入第一个 user 消息中。在实际的 API 请求中,messages 数组将按会照时间顺序排列,通常首先是 system 消息,然后是 user 的提问,最后是 assistant 的回答。这种结构有助于维护对话的上下文和连贯性。
当我们与模型交流时,模型会返回这个样子的 JSON 数据,其中我们主要关注的是 choices 数组。
在我们这种对话模式中,choices 数组中通常只包含一个对象(这也就是为什么下面 Moonshot 函数获取模型回复等信息的时候写死 $result['choices'][0]),这个对象代表模型生成的文本回复。对象内的 finish_reason 指示了生成文本的完成原因,如果模型认为已经给出了一个完整的回答,那么 finish_reason 的值将会为 stop。所以我们可以据此来判断模型生成的内容是否完整。而对象内的 content 则为模型给我们的回复。
接着我们创建 Moonshot 函数来调用 MoonshotAPI 类:
至此,我们就得到了像下面的代码。如果没有意外,直接调用后将会得到模型的回复✌️。前端拿到回复后再渲染到页面即可,这里就不过多赘述。
番外:超长文章的处理
对于某些文章,直接调用上面代码可能会得到下面的错误:
出现这种错误的原因是输入输出上下文的 token 总和超过了模型(这里我们默认使用的是 moonshot-v1-8k 模型)设定的 token 上限,我们需要根据上下文的长度,加上预期的输出 Tokens 长度来选择合适的模型。针对这种情况,文档也给出了 如何根据上下文长度选择恰当的模型 的示例代码,我们只需要将代码转为 PHP 然后接入我们上面的代码即可。
Moonshot 函数下,当模型错误返回类型为 invalid_request_error(即超出该模型最大 token 限制)时,调用 selectModel 函数选择最合适的模型后再重新用合适的模型进行对话。