前端使用千帆、通义千问、Ollama的大模型
- markdown解析+代码高亮
- 百度千帆大模型
- 阿里千问大模型
- Ollama
- @langchain/ollama
- 自定义
注:代码举例只使用处理流式数据的。
markdown解析+代码高亮
这里使用的方案是:markdown-it + highlight.js
-
npm install markdown-it github-markdown-css highlight.js
-
引入依赖和配置
import MarkdownIt from 'markdown-it' import hljs from 'highlight.js' import 'github-markdown-css' // 可以根据自己的喜好引入 highlight.js 下的各种代码高亮样式 // import 'highlight.js/styles/github-dark.css'const marked = new MarkdownIt({highlight: (code, lang) => {const language = hljs.getLanguage(lang) ? lang : 'shell'return `<pre><code class="hljs language-${language}">${hljs.highlight(code, { language }).value}</code></pre>`} })
-
编写组件
<template><div v-html="marked.render(content)" class="markdown-body" /> </template><style> // 如果想要修改代码的样式,可以参考: .markdown-body {::v-deep(pre) {background-color: #21252b;line-height: 1.6;} } </style>
百度千帆大模型
base_url:https://qianfan.baidubce.com/v2/chat/completions
该url支持的大模型列表:对话Chat - ModelBuilder (baidu.com)
代码示例:
async (body: QianFanRequestBody, cb: (res: any) => void) => {const resp = await fetch(base_url, {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': `Bearer ${api_key}`},// body里需要有配置:"stream: true"body: JSON.stringify(body)})if (!resp.ok) throw new Error(`状态码:${resp.status},${resp.statusText}`)const reader = resp.body?.getReader()const decoder = new TextDecoder()while (true) {const { done, value } = await reader?.read() as { done: boolean, value: Uint8Array }if (done) break// 数据格式:"data: {...}",具体格式可以看官方文档// 一个value可能有多个data,需要先分割;分割后最后一个元素是空字符串let strs = decoder.decode(value).split('\n\n')for (let i = 0; i < strs.length - 1; i++) {// 最后一个data的格式时:"data: [DONE]"if (strs[i].lastIndexOf('[DONE]') != -1) break// 去掉开头的 "data: ",再转换为js对象const res = JSON.parse(strs[i].slice(6))// 回答内容在:res.choices[0].delta.contentcb(res)}}
}
阿里千问大模型
API文档:阿里云百炼 (aliyun.com)
支持的模型:通义千问大语言模型(商业版、开源版、Qwen-Long)、通义千问VL、数学模型、代码模型
通义千问Audio暂不支持OpenAI兼容模式,仅支持DashScope方式。
- 使用SDK时,需要配置
base_url
:https://dashscope.aliyuncs.com/compatible-mode/v1- 可以使用
openai
的库:npm install openai
,使用方法和接入OpenAI
的API时一样。
- 可以使用
- 使用HTTP方式时,需要配置
endpoint
:POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
使用openai库时的示例:
const qwen = new OpenAI({apiKey: '',baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',dangerouslyAllowBrowser: true // 允许浏览器使用API
})async (callback: (res: string) => void) => {const stream = await qwen.chat.completions.create({model: platform.model.name,messages: msgList,stream: true})for await (const chunk of stream) {callback(chunk.choices[0].delta.content)}
}
Ollama
默认url:http://localhost:11434
获取当前运行的大模型列表:http://localhost:11434/api/ps
获取本地的大模型列表:http://localhost:11434/api/tags
官方API文档:ollama/docs/api.md at main · ollama/ollama (github.com)
@langchain/ollama
可以使用 @langchain/ollama
库来调用Ollama提供的API。
官方Github地址:langchainjs/libs/langchain-ollama at main · langchain-ai/langchainjs (github.com)
-
安装依赖:
npm install @langchain/ollama @langchain/core
-
配置:
import { Ollama } from '@langchain/ollama'const ollama = new Ollama({model: '',baseUrl: 'http://localhost:11434' })
-
使用:
// ollama.client 提供了客户端的相关API // 获取当前运行的所有大模型 await ollama.client.ps()// http://localhost:11434/api/generate // 使用下面的方法可以调用generate接口 const content: string = await ollama.invoke('你好')// 流式处理generate接口返回的数据 let content = '' const resp = await ollama.stream('介绍一下你自己')for await (const chunk of resp) {content += chunk }
自定义
在@langchain/ollama
中我没有找到调用 http://localhost:11434/api/chat 接口的,可以自己写个方法:
async (body: OllamaRequestBody, cb: (res: any) => void) => {const resp = await fetch(ollama.baseUrl + '/api/chat', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(body)})if (!resp.ok) throw new Error(`状态码:${resp.status},${resp.statusText}`)const reader = resp.body?.getReader()const decoder = new TextDecoder()while (true) {const { done, value } = await reader?.read() as { done: boolean, value: Uint8Array }if (done) breaklet strs = decoder.decode(value).split('\n')for (let i = 0; i < strs.length - 1; i++) {// 回答内容在:res.message.contentconst res = JSON.parse(strs[i])cb(res)}}
}// 另一种写法,使用yield
const ollamaChatApi = async function* (body: OllamaRequestBody) {const resp = await fetch(ollama.baseUrl + '/api/chat', {method: 'POST',headers: {'Content-Type': 'Content-Type'},body: JSON.stringify(body)})if (!resp.ok) throw new Error(`状态码:${resp.status},${resp.statusText}`)const reader = resp.body?.getReader()const decoder = new TextDecoder()while (true) {const { done, value } = await reader?.read() as { done: boolean, value: Uint8Array }if (done) breaklet strs = decoder.decode(value).split('\n')for (let i = 0; i < strs.length - 1; i++) {yield JSON.parse(strs[i])}}
}let msg = ''
const resp = ollamaChatApi({model: '',messages: msgList,stream: true
})
for await (const chunk of resp) {msg += chunk.message.content
}