439 - 《笔记:从前端到 AI:LangChain.js 入门和实战(1)》

发布于 2024年5月10日

本文是掘金课程的阅读笔记,看了感觉还不错,查漏补缺吧。课程链接见: https://s.juejin.cn/ds/i2531au3/

1、用 Deno + Jupyter Notebook 调参数和 prompt,相比 Node 程序每次改完后要重头跑会简单不少,示例。而用 Deno 的好处是不需要安装依赖,Deno 运行时会自动安装。VSCode 下用 Jupyter 安装个 Jupyter VSCode 插件 会有高亮。

2、如果没有 OpenAI 官方的 API,其他可选服务包括 Azure OpenAI、第三方中转、本地大模型。本地大模型作者推荐了 ollama,可以下载 7B 的版本,本地测试够用。

OpenAI 示例。

import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";

let chatModel = new ChatOpenAI({
  configuration: {
    // 使用三方中转时需要制定
    baseURL: '',
  },
});
await chatModel.invoke([
  new HumanMessage("Tell me a joke"),
]);

本地 ollama 大模型。

import { Ollama } from "@langchain/community/llms/ollama";

let ollama = new Ollama({
  baseUrl: "http://localhost:11434", 
  model: "llama2", 
});
let res = await ollama.invoke("讲个笑话");

3、langchain 由于历史原因,有多套设计,导致用户写法也会不同。其中 LCEL(LangChain Expression Language)是
langchain 主推的新设计,其好处是从原型到生产的完整流程不需要修改任何代码就能支持生产级别的各种特性,比如并行、自动的重试和 fallback、对 chain 中间结果的访问、LangSimith 可视化、steaming 等。

一条 Chain 上的每个模块都继承自 Runnable,常用有 invoke、batch、stream 和 streamLog 四个方法。Runnable 之间可通过 .pipe() 串起来。

let chatModel = new ChatOpenAI();
let outputPrase = new StringOutputParser();
let chain = chatModel.pipe(outputPrase);
// invoke
await chain.invoke([
  new HumanMessage("Tell me a joke")
]);
// batch
await chain.batch([
  [new HumanMessage("Tell me a joke")],
  [new HumanMessage("Hi, Who are you?")],
]);
// stream
let stream = await simpleChain.stream([ new HumanMessage("Tell me a joke") ]);
for await (let chunk of stream) {
  console.log(chunk);
}
// fallback
chain = chain.withFallbacks({
  fallbacks: [new ChatOpenAI()],
});

4、RAG 全称 Retrieval(检索) Augmented(增强) Generation(生成)。RAG 解两个问题,1)幻觉(hallucination),2)领域知识的欠缺。RAG 的基本流程是加载、切分、嵌入、检索、prompt,我去年搞过的 285 - 《minicc 和 OpenAI embedding》 就是这种。

5、PromptTemplate 可以让我们以工程化的方式管理和构建 prompt。除了 PromptTemplate,还有 ChatPromptTemplate、SystemMessagePromptTemplate、AIMessagePromptTemplate 和 HumanMessagePromptTemplate,后三个分别对应 system、assistant 和 user 三个角色。还有个更高级的 PipelinePromptTemplate,感觉没啥必要。

import { PromptTemplate } from "@langchain/core/prompts";

// create
let tpl = new PromptTemplate({
  inputVariables: ["world", "name"],
  template: "hello {world},{name}",
});
// or
let tpl = PromptTemplate.fromTemplate("hello {world}, {name}");

// use
let prompt = await tpl.format({
  name: "Kai",
  world: "WORLD",
});
// or
let prompt1 = await tpl.partial({
  name: "Kai",
});
let prompt = await prompt1.format({
  world: "WORLD",
});

来个翻译的例子。

let chatModel = new ChatOpenAI();
let outputPraser = new StringOutputParser();

const systemTemplate = "你是一个专业的翻译员,你的任务是将文本从{source_lang}翻译成{target_lang}。";
const humanTemplate = "请翻译这句话:{

内容预览已结束

此内容需要会员权限。请先登录以查看完整内容。