当前位置: 首页 > article >正文

基于nodejs中@langchain/langgraph框架实现workflow

代码主要组成部分

  1. 模型初始化

    • 使用ChatOpenAI类初始化一个基于OpenAI的语言模型,该模型用于生成和改进翻译。
    • 模型参数包括模型名称(从环境变量中获取)和温度(设置为0以减少随机性)。
  2. 状态注解定义

    • 定义了一个名为StateAnnotation的状态注解,包含翻译过程中需要的所有字段,如源语言、目标语言、源文本、翻译版本、国家等。
  3. 函数定义

    • initial_translation:执行初始翻译,将源文本从源语言翻译为目标语言。
      • 构建系统提示和用户提示,传递给语言模型进行翻译。
      • 返回包含第一次翻译结果的对象。
    • reflect_on_translation:对初始翻译进行反思和批评,提出改进建议。
      • 构建系统提示和用户提示,传递给语言模型以生成关于如何改进翻译的具体建议。
      • 返回包含反思内容的对象。
    • improve_translation:根据反思的内容改进翻译。
      • 构建系统提示和用户提示,传递给语言模型以生成改进后的翻译。
      • 返回包含第二次翻译结果的对象。
    • print_translation:打印最终的翻译结果。
      • 打印并返回最终翻译结果。
  4. 工作流定义

    • 使用StateGraph定义了一个工作流,依次调用上述函数来完成翻译过程。
    • 工作流的每个节点代表一个步骤,边表示步骤之间的顺序关系。
  5. 编译和运行工作流

    • 编译工作流并调用invoke方法,传入初始状态(源语言、目标语言和源文本),执行整个翻译流程。
    • 该代码实现了一个多步骤的翻译流程,包括初始翻译、反思改进和最终编辑三个主要步骤。
import {ChatOpenAI} from "@langchain/openai";
import {ChatPromptTemplate, PromptTemplate} from "@langchain/core/prompts";
import {StateGraph, MessagesAnnotation, Annotation} from "@langchain/langgraph";


const model = new ChatOpenAI({
    model: String(process.env.MODEL),
    temperature: 0,
});

const StateAnnotation = Annotation.Root({
    source_lang: Annotation<string>(),
    target_lang: Annotation<string>(),
    source_text: Annotation<string>(),
    translation_1: Annotation<string | null>(),
    translation_2: Annotation<string | null>(),
    country: Annotation<string | null>(),
    reflection: Annotation<string | null>(),
});

async function initial_translation(state: typeof StateAnnotation.State) {
    const {source_lang, target_lang, source_text} = state;

    const prompt = ChatPromptTemplate.fromMessages([
        ["system", "You are an expert linguist, specializing in translation from {source_lang} to {target_lang}."],
        ["user", 'This is an {source_lang} to {target_lang} translation, please provide the {target_lang} translation for this text. \\\\ Do not provide any explanations or text apart from the translation. {source_lang}: {source_text} {target_lang}:'],
    ]);

    const formattedPrompt = await prompt.format({source_lang, target_lang, source_text});

    const res = await model.invoke(formattedPrompt);

    return {"translation_1": res.content};
}

async function reflect_on_translation(state: typeof StateAnnotation.State) {
    const {source_lang, target_lang, source_text, country, translation_1} = state;

    const prompt = ChatPromptTemplate.fromMessages([
        [
            "system",
            "You are an expert linguist specializing in translation from {source_lang} to {target_lang}. \\\n" + "You will be provided with a source text and its translation and your goal is to improve the translation."
        ],
        [
            "user", `
Your task is to carefully read a source text and a translation from {source_lang} to {target_lang}, and then give constructive criticism and helpful suggestions to improve the translation. \\
{additional_rule}

The source text and initial translation, delimited by XML tags <SOURCE_TEXT></SOURCE_TEXT> and <TRANSLATION></TRANSLATION>, are as follows:

<SOURCE_TEXT>
{source_text}
</SOURCE_TEXT>

<TRANSLATION>
{translation_1}
</TRANSLATION>

When writing suggestions, pay attention to whether there are ways to improve the translation's \\n\\
(i) accuracy (by correcting errors of addition, mistranslation, omission, or untranslated text),\\n\\
(ii) fluency (by applying {target_lang} grammar, spelling and punctuation rules, and ensuring there are no unnecessary repetitions),\\n\\
(iii) style (by ensuring the translations reflect the style of the source text and takes into account any cultural context),\\n\\
(iv) terminology (by ensuring terminology use is consistent and reflects the source text domain; and by only ensuring you use equivalent idioms {target_lang}).\\n\\

Write a list of specific, helpful and constructive suggestions for improving the translation.
Each suggestion should address one specific part of the translation.
Output only the suggestions and nothing else.`
        ],
    ]);

    const additional_rule = `
        The final style and tone of the translation should match the style of ${target_lang} colloquially spoken in ${country ? country : ''}.
    `;

    const formattedPrompt = await prompt.format({
        source_lang,
        target_lang,
        source_text,
        translation_1,
        additional_rule
    });

    const res = await model.invoke(formattedPrompt);

    console.log(res.content);

    return {"reflection": res.content};
}

async function improve_translation(state: typeof StateAnnotation.State) {
    const {source_lang, target_lang, source_text, translation_1, reflection} = state;

    const prompt = ChatPromptTemplate.fromMessages([
        [
            "system",
            "You are an expert linguist, specializing in translation editing from {source_lang} to {target_lang}."
        ],
        [
            "user", `
Your task is to carefully read, then edit, a translation from {source_lang} to {target_lang}, taking into
account a list of expert suggestions and constructive criticisms.

The source text, the initial translation, and the expert linguist suggestions are delimited by XML tags <SOURCE_TEXT></SOURCE_TEXT>, <TRANSLATION></TRANSLATION> and <EXPERT_SUGGESTIONS></EXPERT_SUGGESTIONS> \\
as follows:

<SOURCE_TEXT>
{source_text}
</SOURCE_TEXT>

<TRANSLATION>
{translation_1}
</TRANSLATION>

<EXPERT_SUGGESTIONS>
{reflection}
</EXPERT_SUGGESTIONS>

Please take into account the expert suggestions when editing the translation. Edit the translation by ensuring:

(i) accuracy (by correcting errors of addition, mistranslation, omission, or untranslated text),
(ii) fluency (by applying {target_lang} grammar, spelling and punctuation rules and ensuring there are no unnecessary repetitions), \\
(iii) style (by ensuring the translations reflect the style of the source text)
(iv) terminology (inappropriate for context, inconsistent use), or
(v) other errors.

Output only the new translation and nothing else.`
        ],
    ]);

    const formattedPrompt = await prompt.format({
        source_lang,
        target_lang,
        source_text,
        translation_1,
        reflection
    });

    const res = await model.invoke(formattedPrompt);

    console.log(res.content);

    return {"translation_2": res.content};
}

async function print_translation(state: typeof StateAnnotation.State) {
    const {translation_2} = state;

    console.log('翻译结果', translation_2);

    return {"translation_2": translation_2};
}

const workflow = new StateGraph(StateAnnotation)
    .addNode("initial_translation", initial_translation)
    .addNode("reflect_on_translation", reflect_on_translation)
    .addNode("improve_translation", improve_translation)
    // .addNode("improve_translation", toolNode)
    .addNode("print_translation", print_translation)

workflow
    .addEdge("__start__", "initial_translation")
    .addEdge("initial_translation", "reflect_on_translation")
    .addEdge("reflect_on_translation", "improve_translation")
    .addEdge("improve_translation", "print_translation")

const app = workflow.compile();

// Use the agent
const finalState = await app.invoke({
    "source_lang": "English",
    "target_lang": "中文",
    "source_text": `
Ideas for extensions
Here are ideas we haven’t had time to experiment with but that we hope the open-source community will:

Try other LLMs. We prototyped this primarily using gpt-4-turbo. We would love for others to experiment with other LLMs as well as other hyperparameter choices and see if some do better than others for particular language pairs.
Glossary Creation. What’s the best way to efficiently build a glossary -- perhaps using an LLM -- of the most important terms that we want translated consistently? For example, many businesses use specialized terms that are not widely used on the internet and that LLMs thus don’t know about, and there are also many terms that can be translated in multiple ways. For example, ”open source” in Spanish can be “Código abierto” or “Fuente abierta”; both are fine, but it’d better to pick one and stick with it for a single document.
`
});

console.log(finalState);


http://www.kler.cn/a/587865.html

相关文章:

  • QT中的线程同步机制
  • 视觉slam十四讲(四)——相机与图像
  • Vue3 + Vite + Yarn + Fabricjs构建的开源演示系统
  • 基于 Verilog 的时序设计:从理论到实践的深度探索
  • 蓝桥杯每日一题01背包拔高·小A点菜
  • Navicat SqlServer 设置自增主键
  • 【人工智能】大语言模型学习大纲
  • 使用 Django 的 `FileResponse` 实现文件下载与在线预览
  • 【虚幻C++笔记】枚举UENUM、结构体USTRUCT
  • 基于CPU使用paddlex OCR识别图片内容
  • 《 线程池项目:线程池背景知识与整体架构梳理》
  • Postman中Authorization和Headers的区别
  • 【软考网工-实践篇】DHCP 动态主机配置协议
  • 【Vue列表渲染中key与数据绑定的核心问题解析】
  • 小程序渲染之谜:如何解决“加载中...”不消失的 Bug(glass-easel)
  • SpringMVC (二)请求处理
  • docker Mysql主从配置
  • 【设计模式】《设计模式:可复用面向对象软件的基础》:设计模式怎样解决设计问题?
  • Vue 系列之:ref、reactive、toRef、toRefs
  • 合并pull request的过程