使用 TypeScript 从零搭建自己的 Web 框架:AI 工程化

使用 TypeScript 从零搭建自己的 Web 框架:AI 工程化

随着人工智能技术的快速发展,越来越多的企业开始将其应用到自己的业务中,以提升业务的智能化水平。大名鼎鼎的 Spring 框架最近也新增了 AI 模块,本文主要介绍如何为我们的框架增加 AI 工程化的能力。

挑战

大型语言模型(LLM)的崛起无疑为自然语言处理(NLP)领域带来了巨大的变革。这些模型凭借海量的数据和复杂的神经网络结构,展现出了强大的语言理解和生成能力。然而,尽管大模型在文本生成、问答等任务中表现出色,但其返回的自然语言形式却难以被应用程序直接使用,这成为了 AI 工程化过程中的一大挑战。

模式工程

C#、TypeScript 之父 Anders Hejlsberg 近期开源的 TypeChat 项目,通过使用模式工程代替传统的提示工程给出了一个解决方案。TypeChat 的核心原理在于其模式工程的方法。它允许开发者自由定义类型,以准确表达自然语言应用程序所支持的意图。一旦定义了这些类型,TypeChat 会为 LLM 制定提示,并验证 LLM 的响应是否符合模式。当验证失败时,TypeChat 会进行额外的语言模型交互,以修复不符合要求的输出。这种机制确保了 TypeChat 能够生成符合应用程序需求的响应结果,从而实现了 AI 与应用程序的协同工作。

通俗的来讲就是在每次向大模型提问的时候要求它按照指定的类型返回 JSON 数据,如果返回的数据不符合你给出的类型定义,把错误信息告诉它让他修复之后重新返回,最后将验证通过后的 JSON 数据回给应用程序。

这是一个使用 TypeChat 编写的情感分类器,它将用户输入分类为消极、中性或积极:

typescript 复制代码
// sentimentSchema.ts
export interface SentimentResponse {
  sentiment: '消极的' | '中性的' | '积极的';
}
typescript 复制代码
import assert from 'assert';
import dotenv from 'dotenv';
import findConfig from 'find-config';
import fs from 'fs';
import path from 'path';
import { createJsonTranslator, createLanguageModel } from 'typechat';
import { processRequests } from 'typechat/interactive';
import { createTypeScriptJsonValidator } from 'typechat/ts';
import { SentimentResponse } from './sentimentSchema';

const dotEnvPath = findConfig('.env');
assert(dotEnvPath, '.env file not found!');
dotenv.config({ path: dotEnvPath });

const model = createLanguageModel(process.env);
// 将模式定义的源文件内容用于构建提示词
const schema = fs.readFileSync(path.join(__dirname, 'sentimentSchema.ts'), 'utf8');
const validator = createTypeScriptJsonValidator<SentimentResponse>(schema, 'SentimentResponse');
const translator = createJsonTranslator(model, validator);

processRequests('😀> ', process.argv[2], async request => {
  const response = await translator.translate(request);
  if (!response.success) {
    console.log(response.message);
    return;
  }
  console.log(`用户的情绪是 ${response.data.sentiment}`);
});

// 输入 TypeChat 真棒!

// 输出 用户情绪是 积极的

核心代码逻辑如下:

typescript 复制代码
async function translate(request: string, promptPreamble?: string | PromptSection[]) {
  const preamble: PromptSection[] =
    typeof promptPreamble === 'string' ? [{ role: 'user', content: promptPreamble }] : promptPreamble ?? [];

  let prompt: PromptSection[] = [...preamble, { role: 'user', content: typeChat.createRequestPrompt(request) }];

  let attemptRepair = typeChat.attemptRepair;

  // 进入一个无限循环,直到得到有效的响应或修复失败
  while (true) {
    // 使用模型完成prompt,并等待其响应
    const response = await model.complete(prompt);

    // 如果响应不成功,直接返回响应
    if (!response.success) {
      return response;
    }

    // 获取响应的文本内容
    const responseText = response.data;

    // 查找响应文本中JSON的开始和结束索引
    const startIndex = responseText.indexOf('{');
    const endIndex = responseText.lastIndexOf('}');

    // 如果响应文本不是有效的JSON格式,返回错误
    if (!(startIndex >= 0 && endIndex > startIndex)) {
      return error(`Response is not JSON:\n${responseText}`);
    }

    // 提取JSON文本
    const jsonText = responseText.slice(startIndex, endIndex + 1);

    // 尝试将JSON文本解析为对象
    let jsonObject;
    try {
      jsonObject = JSON.parse(jsonText) as object;
    } catch (e) {
      // 如果解析失败,返回错误
      return error(e instanceof SyntaxError ? e.message : 'JSON parse error');
    }

    // 如果TypeChat设置了stripNulls,则去除jsonObject中的null值
    if (typeChat.stripNulls) {
      stripNulls(jsonObject);
    }

    // 使用validator对jsonObject进行模式验证
    const schemaValidation = validator.validate(jsonObject);

    // 如果模式验证成功,则进一步使用TypeChat进行实例验证
    const validation = schemaValidation.success ? typeChat.validateInstance(schemaValidation.data) : schemaValidation;

    // 如果验证成功,返回验证结果
    if (validation.success) {
      return validation;
    }

    // 如果不允许修复或修复失败,返回错误
    if (!attemptRepair) {
      return error(`JSON validation failed: ${validation.message}\n${jsonText}`);
    }

    // 如果允许修复,将响应文本和修复提示添加到prompt中
    prompt.push({ role: 'assistant', content: responseText });
    prompt.push({ role: 'user', content: typeChat.createRepairPrompt(validation.message) });

    // 禁用下一次的修复尝试
    attemptRepair = false;
  }
}

总结

TypeChat 充当了自然语言、应用模式和 API 之间的桥梁,简化了开发过程并解决了应用程序与大型语言模型(LLM)的集成问题。它使用了一种创新的模式工程方法,取代了传统的提示工程方法。开发者可以自由定义类型,准确表达自然语言应用程序所支持的意图。通过将 TypeChat 包装成一个可依赖注入的组件并为各类大语言模型创建适配器,就可以轻松为我们的框架增加 AI 工程化的能力。

相关推荐
流影ng21 小时前
【HarmonyOS】并发线程间的通信
typescript·harmonyos
duansamve1 天前
TS在Vue3中的使用实例集合
typescript·vue3
FanetheDivine2 天前
ts中如何描述一个复杂函数的类型
前端·typescript
struggle20253 天前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell
执剑、天涯3 天前
通过一个typescript的小游戏,使用单元测试实战(二)
javascript·typescript·单元测试
chéng ௹3 天前
Vue3+Ts+Element Plus 权限菜单控制节点
前端·javascript·vue.js·typescript
武清伯MVP4 天前
阮一峰《TypeScript 教程》学习笔记——基本用法
笔记·学习·typescript
ttod_qzstudio5 天前
解决 Vue 3 + TypeScript 中 v-for 循环类型推断问题
前端·vue.js·typescript
今天头发还在吗5 天前
【React】动态SVG连接线实现:图片与按钮的可视化映射
前端·javascript·react.js·typescript·前端框架
冷冷的菜哥6 天前
react多文件分片上传——支持拖拽与进度展示
前端·react.js·typescript·多文件上传·分片上传