掘金 人工智能 05月09日 17:04
typedoc助力组件AI知识库文档搭建
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了如何利用现有代码注释,低成本构建企业或部门的AI知识库。针对个人用户对大模型私有化部署和知识库的需求不强烈的情况,文章提出对于企业和开发者,通过TypeDoc等工具将代码注释转化为Markdown文档,再导入Dify等平台,搭建问答工作流,从而高效检索和利用知识。这种方法尤其适用于组件库、SDK、API等场景,能有效解决知识体量大、查询者不熟悉知识结构的问题,提升开发效率和知识管理水平。

💡 **知识库构建关键**:对企业而言,知识积累是构建AI知识库的核心。手动编写文档适用于复杂业务知识,而组件库、SDK等场景,可利用代码注释自动生成文档。

🛠️ **TypeDoc生成文档**:利用TypeDoc工具,特别是结合typedoc-plugin-markdown插件,可以将TypeScript项目的代码注释转化为Markdown文档,实现知识文档的低成本生成。

🧩 **Dify知识库导入与工作流搭建**:使用Dify等平台,将生成的Markdown文档导入知识库,并搭建问答工作流。当用户提问时,系统会从知识库检索相关知识,并结合大模型给出答案,否则提示未检索到。

🔍 **实际效果展示**:通过提问“输入框支持哪些属性”、“如何设置输入框禁用”、“如何给输入框设置前缀图标”等问题,展示了AI知识库的检索效果。结果表明,该方案能够有效回答用户关于组件属性和使用方法的问题。

一、前言

当前AI、大模型、知识库等词条随处可见,随处翻翻就是一大片的大模型私有化部署+私有知识库相关帖子。

但个人认为对于个人来说,完全没有大模型私有化部署的需求,而且费了许多资源部署落地的可能也只是一个鸡肋;对于知识库而言,首先个人知识很难说有没有安全隐私的保护需求,另外又有多少人能够写出大量的篇幅文档需要借助ai搜索而常规的检索(如分目录+ctrl + f)不可靠呢。就目前观察一些文档管理工具对知识的管理已经足够满足个人的知识存储了。

不过对于企业、部门或者软件开发者,知识库还是存在一定的价值,一方面知识体量可能非常巨大,常规检索效率低下;另一方面知识查询者对知识可能不了解,常规检索无从下手或者找不到知识在何处。

大模型+知识库最重要的个人认为是知识,没有知识的知识库是空中楼阁,一定是先有的知识,才有的ai知识库的需求。因此知识的积累是这里的关键,对于复杂业务、复杂知识,可能手动编写知识文档更为合适,而如果是一些组件库、sdkapi等,知识的重点在于输入输出、属性、方法等等,完全可以通过代码注释生成的文档满足知识的积累需要,本文将提供一种思路。

二、typedoc生成文档

几乎每一种语言都有相应的工具能够生成项目文档,这里使用基于typescripttypedoc工具,原先已经有大量官方静态站点可能已经由它生成,进一步生成知识文档可以说是0成本,typedoc+typedoc-plugin-markdown就能够生成markdown文档。

对于以下目录结构的组件库,每一个组件的propsemitsslots等定义在了props.ts文件中,组件使用者一般也只需要关注着一些信息。

input/src/props.ts

/** @module Input */import { InferVueDefaults } from '@/shared';import type Input from './input.vue';/** * 输入框组件的属性如下*/export interface InputProps {  /**   * 输入值,支持 v-model 双向绑定   * @default ''   */  modelValue?: string | number | null | undefined;  /**   * 类型,与原生input一致   * @default 'text'   */  type?: string;  /**   * 是否禁用   * @default false   */  disabled?: boolean;  /**   * 是否只读,只读时一定为禁用   * @default false   */  readonly?: boolean;  /**   * 最大输入长度   * @default ''   */  maxlength?: string | number  /**   * 最小输入长度   * @default ''   */  minlength?: string | number  /**   * 统计数值   * @default false   */  showCount?: boolean  /**   * 占位文本   * @default ''   */  placeholder?: string  /**   * 是否可清除   * @default false   */  clearable?: boolean  /**   * 是否显示密码显隐按钮   * @default false   */  showPassword?: false  /**   * 尺寸   * @default 'medium'   */  size?: string  /**   * 前缀图标   * @default ''   */  prefixIcon?: string  /**   * 前缀图标是否不响应事件   * @default: true   */  prefixIconSilent?: boolean  /**   * 后缀图标   * @default ''   */  suffixIcon?: string  /**   * 后缀图标是否不响应事件   * @default: true   */  suffixIconSilent?: boolean  /**   * 后缀内容,如单位等   * @default ''   */  suffixText?: string  /**   * 是否自动补全   * @default ''   */  autocomplete?: string  /**   * 原生属性   * @default ''   */  name?: string  /**   * 原生属性   * @default false   */  autofocus?: boolean  /**   * 原生属性   */  form?: string  /**   * 原生aria-label属性   */  label?: string  /**   * 原生属性   */  tabindex?: string | number  /**   * 是否触发表单验证   * @default true   */  validateEvent?: boolean  /**   * 原生属性   */  max?: string  /**   * 原生属性   */  min?: string  /**   * 原生属性   */  step?: string}/** @hidden */export function defaultInputProps(): Required<InferVueDefaults<InputProps>> {  return {    modelValue: '',    type: 'text',    disabled: false,    readonly: false,    maxlength: '',    minlength: '',    showCount: false,    placeholder: '',    clearable: false,    showPassword: false,    size: 'medium',    prefixIcon: '',    prefixIconSilent: true,    suffixIcon: '',    suffixIconSilent: true,    suffixText: '',    autocomplete: '',    name: '',    autofocus: false,    form: '',    label: '',    tabindex: '',    validateEvent: true,    min: '',    max: '',    step: '',  };}/** * 输入框组件的事件 * @interface * */export type InputEmits = {  'update:modelValue': [value: string];  /**   * input事件   * @param value 输入值   */  input: [value: string];  /**   * change事件   * @param value 输入值   */  change: [value: string];  /**   * 输入框失去焦点   * @param e 事件对象   */  focus: [e: FocusEvent];  /**   * 输入框获取焦点   * @param e 事件对象   */  blur: [e: FocusEvent];  /**   * 输入框键盘按下   * @param e 事件对象   */  keydown: [e: KeyboardEvent];  /**   * 前缀图标点击事件   * @param e 事件对象   */  prefixIconClick: [e: MouseEvent];  /**   * 后缀图标点击事件   * @param e 事件对象   */  suffixIconClick: [e: MouseEvent];};/** 输入框组件对外暴露的方法 */export interface InputExpose {  /**   * 清空输入框   * @returns void  */  clear: () => void  /**   * 聚焦输入框   * @returns void   */  focus: () => void}/** 按钮组件的插槽信息 */export interface InputSlots {  /**   * 前缀插槽,使用:v-slot:prefix   */  prefix: any;  /**   * 后缀插槽,使用:v-slot:suffix   */  suffix: any;}/** @hidden */export type InputInstance = InstanceType<typeof Input>;

下面是typedoc简单生成markdown的配置:

import { join, dirname } from "node:path";import { fileURLToPath } from "node:url";import { readFile, writeFile } from "node:fs/promises";import {  Application,  TSConfigReader,  ReflectionKind} from "typedoc";import defaultLocaleJson from "../locale/default.json" assert { type: "json" };const __filename = fileURLToPath(import.meta.url);const __dirname = dirname(__filename);const fromRoot = (...paths) => join(  __dirname,  "..",  "..",  ...paths);const tsConfigPath = fromRoot("tsconfig.src.json");const OUT_DIR = join(__dirname, "..", "api");const CONFIGS_DIR = join(__dirname, "..", "configs");async function main() {  const app = await Application.bootstrapWithPlugins({    entryPoints: [fromRoot("packages", "**", "props.ts").replace(/\\/g, "/")],    tsconfig: tsConfigPath,    // 启用 markdown 转化插件    plugin: ["typedoc-plugin-markdown"],    disableSources: true,    readme: "none",    skipErrorChecking: true,    // 这里配置了因此页首、面包屑等    hidePageHeader: true,    hideBreadcrumbs: true,    useCodeBlocks: true,    // 这一步转换标题 如 InputProps ——> 输入框属性    pageTitleTemplates: {      member: (args) => `${splitByUpperCase(args.name).map((item) => defaultLocaleJson[item]).join("")}`    },    interfacePropertiesFormat: "table",    out: OUT_DIR,    lang: "zh"  }, [    new TSConfigReader()  ]);  const project = await app.convert();  if (project) {    await app.generateDocs(project, OUT_DIR);    await app.generateOutputs(project);    const jsonDir = join(OUT_DIR, "documentation.json");    await app.generateJson(project, jsonDir);  }}main().catch(console.error);

需要注意的是不能够使用 tsx 执行这一脚本,因为typedoc自身模块导入的问题会使得插件失效,建议直接使用nodejs运行.mjs脚本

生成效果如下:

3.导入知识库与工作流

这里使用的是dify,导入过程非常简单不赘述。实践中由于各文件体积较小且基本一个文件就是一块内容,因此chunk的分割按文件分割效果较好。

下面需要搭建一条问答的工作流,如下:

当能够从知识库中检索到相关知识时,就会结合大模型输出相关知识,否则会告知未检索到相关内容。

4.效果

1.提问输入框支持哪些属性

2.提问如何设置输入框禁用

3.提问如何给输入框设置前缀图标

可以看到效果还是比较不错的,不过后面的代码示例中出现了el-element的标签,这一部分应该可以通过提示词的调整来优化,但不影响总体的可行性判定。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

AI知识库 TypeDoc Dify 代码注释 知识管理
相关文章