类低代码平台的Agent开发实践(上)——文档助手

最近在开发仿真平台的Agent,其场景和开发思路和大多数低代码平台都是一样的。我将Agent功能分为两大块:文档助手和智能生成。

本文介绍文档助手agent的开发。

文档助手

低码类平台常常有非常多的配置,也具有复杂的操作手册和各式案例,是智能文档助手的最佳应用场景。

技术选型

项目中rag部分的关键技术选型是chromadb。

ts 复制代码
import { Chroma } from "@langchain/community/vectorstores/chroma";

function getVectorStore(): Promise<Chroma> {
  if (vectorStore) {
    return vectorStore;
  }

  vectorStore = new Chroma(embeddings, {
    collectionName: COLLECTION_NAME,
    url: `http://${config.chromaHost}:${config.chromaPort}`,
  });

  return vectorStore;
}

chromadb有内置的embedding模型(all-MiniLM-L6-v2),不过我选择Qwen3-Embedding-8B,该处理中文更好。

另外如果知识库中有大量图片的,建议使用Qwen3-VL-Embedding-8B。(这个模型跑起来比较难,要么调阿里云的api,要么就得找个好点的机子本地部署。ollama是没有办法运行这种多模态模型的。)

typescript 复制代码
import { OpenAIEmbeddings } from "@langchain/openai";
import { config } from "../config/index.js";

export const embeddings = new OpenAIEmbeddings({
  model: config.embeddingModel,
  batchSize: 8,
  timeout: 300_000,
  configuration: {
    baseURL: config.embeddingBaseUrl,
  },
});

rag流程

rag的标准流程是载入文档 → 分词 → 嵌入 → 向量存储 → 检索

载入文档

typescript 复制代码
function loadDocuments(): Promise<Document[]> {
  const files = await getFiles(DOCS_PATH);
  const documents: Document[] = [];

  for (const file of files) {
    const rawContent = await readFile(file, 'utf-8');


    //如果不是纯文本,比如excel/html,需要将其转为纯文本
    const text = convert(rawContent);

    documents.push(
      new Document({
        pageContent: text,
        metadata: {
          source: file,
          title,
        },
      })
    );
  }

  return documents;
}

分词

分词工具建议使用RecursiveCharacterTextSplitter(@langchain/textsplitters)。

其代码实现很简单:

typescript 复制代码
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
import type { Document } from '@langchain/core/documents';

const CHUNK_SIZE = 1000;
const CHUNK_OVERLAP = 200;

export function createSplitter(): RecursiveCharacterTextSplitter {
  return new RecursiveCharacterTextSplitter({
    chunkSize: CHUNK_SIZE,
    chunkOverlap: CHUNK_OVERLAP,
  });
}

export async function splitDocuments(docs: Document[]): Promise<Document[]> {
  const splitter = createSplitter();
  return splitter.splitDocuments(docs);
}

这里简单介绍下它的原理------分级降级,尽力而为

  1. 按优先级切分 :它首先会尝试用一个较高的分隔符(比如段落分隔符 \n\n)来切分文本,希望保持段落完整。
  2. 检查块大小 :如果切分出来的某个块仍然超过了预设的 chunk_size,它不会强行保留这个超长的块,而是进入下一步。
  3. 递归降级处理 :如果高优先级的分隔符切出的块过长,它会自动"降级",对这个过长的块使用优先级次之的分隔符(比如句号 .)再次尝试切分。
  4. 循环直至完成 :这个过程会一直递归下去,直到所有的块都符合大小要求。如果到最后使用最小分隔符(如单个字符 "")切分后块还是过大,它最终也只能产生一个超长块,并给出警告

基于以上原理,我们可以额外添加中文标点

typescript 复制代码
export function createSplitter(): RecursiveCharacterTextSplitter {
  return new RecursiveCharacterTextSplitter({
    separators: [
      "\n\n", // 段落
      "\n", // 换行
      "。",
      "!",
      "?",
      ";", // 中文句子结束符
      ",",
      "、", // 中文逗号/顿号
      " ", // 空格
      "", // 字符
    ],
    chunkSize: CHUNK_SIZE,
    chunkOverlap: CHUNK_OVERLAP,
  });
}

嵌入和存储

Chroma.from_documents() 方法是一个将向量化(Embedding)存储(Storage) 两个核心步骤合二为一的便捷方法。 调用它时,会在内部自动执行以下步骤:

  1. 调用嵌入模型 :它会调用你通过 embedding 参数传入的嵌入模型,将 documents 列表中的每一个 Document 的文本内容转换成对应的向量(Embeddings)。
  2. 存储到数据库 :它会创建一个 Chroma 数据库的连接,并将上一步生成的 向量 与对应的 文档原文、元数据 一起,存储到 Chroma 中,形成一个完整的向量数据库。
typescript 复制代码
 const store = await Chroma.fromDocuments(docs, embeddings, {
    collectionName: COLLECTION_NAME,
    url: `http://${config.chromaHost}:${config.chromaPort}`,
  }).catch((error) => {
    console.error("Error creating vector store:", error);
    throw error;
  });

这一步根据材料和模型的不同,耗时可能会很长。文档更新,最好能够增量embedding。

查询

查询时也需要将原始字符串转为向量才行,不过similaritySearch会自动完成这一步。

ts 复制代码
   const llm = createLLM(0.3);

  const docs: Document[] = await vectorStore.similaritySearch(query, 5);
  const contextDocs: string[] = docs.map((doc: Document) => doc.pageContent);
  // 源文档,可以用作连接
  const sources: string[] = [
    ...new Set(docs.map((doc: Document) => doc.metadata.source as string)),
  ];
  // 向量数据库查找出来的内容塞到llm的promot中 
  const prompt = buildPrompt(
    query,
    contextDocs,
    projectContext,
    conversationHistory,
  );

  const response = await llm.invoke(prompt);
相关推荐
格桑阿sir2 小时前
13-大模型智能体开发工程师:工具使用(Tool Use)范式
ai·大模型·agent·工具·智能体·tool·tool use
canonical_entropy2 小时前
为什么 Attractor Guided Engineering 不能被降级为 AI Agent Skill
架构·agent·ai编程
DreamWear2 小时前
用本地 LLM 写 commit,不消耗云端 token:git-courer 是怎么做到的
agent·ai编程
weiwin1233 小时前
MAF入门(3 下):多轮对话进阶——清除历史、注入 System、截断策略
人工智能·agent
XLYcmy3 小时前
面向Agent权限系统的快速审计工具
python·网络安全·ai·llm·飞书·agent·字节跳动
guyoung3 小时前
BoxAgnts 运行时(1)——运行时工程决定 Agent 未来
agent·ai编程
Artech3 小时前
[MAF的Agent管道详解-06]ChatClientAgent对IChatClient和输入输出增强管道的整合
ai·agent·maf·agent管道
武雄(小星Ai)5 小时前
Gemini CLI 免费用户6月18日停服,Google Antigravity 2.0 深度解读
运维·人工智能·agent
HIT_Weston5 小时前
102、【Agent】【OpenCode】task 工具提示词(examples)
人工智能·agent·opencode