Skip to content

AI 交互架构

1. RAG(检索增强生成)

题目:什么是 RAG(检索增强生成)?前端在 RAG 应用中需要承担哪些工作?

答案要点:

RAG 通过检索外部知识库来弥补模型时效性不足,前端主要负责知识溯源的展示和交互。

  • 引用标注: 在 AI 回复中高亮显示引用来源,点击可跳转到原始文档片段
  • 文档切片预览: 展示向量数据库检索出的 Top-K 片段,并支持用户反馈相关性
  • 预处理: 在上传文档时,前端可进行初步的格式清洗或分段预览
  • 交互链路: 处理"检索中 -> 思考中 -> 生成中"的复杂状态流转

前端架构设计:

typescript
interface RAGResponse {
  answer: string
  sources: {
    id: string
    content: string
    document: string
    page?: number
    relevance: number
  }[]
}

// 引用高亮组件
function CitationHighlight({ text, citations }: { text: string; citations: Citation[] }) {
  return (
    <div className="rag-answer">
      {parseTextWithCitations(text).map((part, idx) =>
        part.type === 'citation' ? (
          <sup key={idx} className="citation">
            [{part.id}]
          </sup>
        ) : (
          <span key={idx}>{part.text}</span>
        ),
      )}
    </div>
  )
}

常见坑:

  • 引用链接失效或索引偏移导致的标注错误

题目:谈谈 RAG(检索增强生成)在前端侧可以做哪些优化?

答案要点:

  • 检索结果预览: 在发送问题前,展示可能相关的文档片段
  • 引用交互: 支持点击引用跳转到原文,悬浮显示上下文
  • 相关性反馈: 让用户标记检索结果的相关性,用于优化向量模型
  • 文档预处理: 上传时进行 OCR、格式转换、自动分段

2. Prompt Engineering

题目:谈谈你对 Prompt Engineering(提示工程)在前端业务代码中封装的理解?

答案要点:

在前端侧封装 Prompt 主要是为了屏蔽模型差异,并根据用户交互动态构建上下文。

  • 模板化: 将 Prompt 定义为模板字符串,通过占位符注入变量(如用户输入、历史记录)
  • 角色隔离: 明确 System Prompt(约束行为)、User Prompt(具体指令)和 Few-shot(示例)
  • 结构化输出: 在 Prompt 中强制要求模型返回特定格式(如 JSON),方便前端解析
  • 版本管理: 将 Prompt 逻辑从业务代码中抽离,支持根据模型版本动态切换

代码示例:

typescript
// Prompt 模板管理
class PromptTemplate {
  private templates: Map<string, string> = new Map()

  register(name: string, template: string) {
    this.templates.set(name, template)
  }

  render(name: string, variables: Record<string, any>): string {
    const template = this.templates.get(name)
    if (!template) throw new Error(`Template ${name} not found`)

    return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
      return variables[key] ?? match
    })
  }
}

// 使用
const promptManager = new PromptTemplate()
promptManager.register(
  'code-review',
  `
你是一位资深前端工程师,请对以下代码进行审查:

文件:{{filename}}
代码:
\`\`\`{{language}}
{{code}}
\`\`\`

请从以下方面给出建议:
1. 代码规范
2. 性能优化
3. 潜在 Bug
`,
)

const prompt = promptManager.render('code-review', {
  filename: 'utils.ts',
  language: 'typescript',
  code: 'function add(a, b) { return a + b; }',
})

常见坑:

  • Prompt 过长导致 Token 浪费和响应延迟

题目:在前端如何实现 Prompt 的版本管理和动态替换变量?

答案要点:

  • 配置化存储: 将 Prompt 存储在 JSON/YAML 配置文件中
  • 版本控制: 使用 Git 管理 Prompt 变更,支持 A/B 测试
  • 热更新: 支持不重启服务更新 Prompt
  • 变量注入: 使用模板引擎(如 Handlebars、Mustache)进行变量替换

3. AI Agent 架构

题目:谈谈 AI Agent 的基本架构,以及前端如何实现一个简单的 Agent 闭环?

答案要点:

AI Agent 是能够自主决策并执行任务的智能体,通常包含感知、思考、行动三个模块。

基本架构:

┌─────────┐    ┌─────────┐    ┌─────────┐
│  感知层  │ -> │  思考层  │ -> │  行动层  │
│ (Input) │    │  (LLM)  │    │ (Tools) │
└─────────┘    └─────────┘    └─────────┘
      ↑                            │
      └────────────┬───────────────┘

              ┌─────────┐
              │  记忆层  │
              │(Memory) │
              └─────────┘

前端实现:

typescript
interface Agent {
  perceive(input: string): Observation
  think(observation: Observation): Action
  act(action: Action): Result
  remember(interaction: Interaction): void
}

class SimpleAgent implements Agent {
  private memory: Interaction[] = []
  private tools: Map<string, Tool> = new Map()

  async run(input: string): Promise<string> {
    // 1. 感知
    const observation = this.perceive(input)

    // 2. 思考(调用 LLM)
    const action = await this.think(observation)

    // 3. 行动
    const result = await this.act(action)

    // 4. 记忆
    this.remember({ input, action, result })

    return result
  }

  private async think(observation: Observation): Promise<Action> {
    const response = await llm.chat({
      messages: [
        { role: 'system', content: '你是一个助手,可以使用以下工具...' },
        ...this.memoryToContext(),
        { role: 'user', content: observation.text },
      ],
      tools: Array.from(this.tools.values()),
    })

    return this.parseAction(response)
  }
}

4. 低代码 AI Agent 编排

题目:设计一个低代码 AI Agent 编排画布(类似 LangFlow),你会如何选型和设计架构?

答案要点:

  • 节点设计: 定义各种节点类型(输入、LLM、工具、条件、输出)
  • 数据流: 基于 DAG(有向无环图)的数据流转
  • 状态管理: 使用 Redux/MobX 管理画布状态
  • 执行引擎: 前端负责编排,后端负责实际执行
  • 可视化: 使用 React Flow、X6 等库实现节点拖拽和连线

架构设计:

typescript
// 节点定义
interface Node {
  id: string
  type: 'input' | 'llm' | 'tool' | 'condition' | 'output'
  position: { x: number; y: number }
  data: Record<string, any>
  inputs: Port[]
  outputs: Port[]
}

// 边定义
interface Edge {
  id: string
  source: string
  target: string
  sourcePort: string
  targetPort: string
}

// 工作流定义
interface Workflow {
  nodes: Node[]
  edges: Edge[]
}

// 执行引擎
class WorkflowEngine {
  async execute(workflow: Workflow, input: any): Promise<any> {
    const graph = this.buildGraph(workflow)
    const executionOrder = this.topologicalSort(graph)

    const context = new ExecutionContext()
    context.set('input', input)

    for (const nodeId of executionOrder) {
      const node = graph.getNode(nodeId)
      const result = await this.executeNode(node, context)
      context.set(nodeId, result)
    }

    return context.get('output')
  }
}

5. 上下文管理

题目:如何处理大模型对话中的上下文管理(Context Window)?

答案要点:

上下文窗口有限,需要智能地管理历史对话。

  • 滑动窗口: 只保留最近的 N 轮对话
  • 摘要压缩: 对早期对话进行摘要,减少 Token 占用
  • 关键信息提取: 提取用户偏好、重要事实存储在记忆库中
  • 向量化检索: 将历史对话向量化,按需检索相关上下文

代码示例:

typescript
class ContextManager {
  private maxTokens: number = 4000
  private messages: Message[] = []

  addMessage(message: Message) {
    this.messages.push(message)
    this.optimizeContext()
  }

  private optimizeContext() {
    const totalTokens = this.estimateTokens(this.messages)

    if (totalTokens > this.maxTokens) {
      // 策略1:删除最早的对话
      // this.messages = this.messages.slice(-10);

      // 策略2:摘要早期对话
      const toSummarize = this.messages.slice(0, -5)
      const summary = this.summarize(toSummarize)
      this.messages = [
        { role: 'system', content: `历史摘要:${summary}` },
        ...this.messages.slice(-5),
      ]
    }
  }

  private estimateTokens(messages: Message[]): number {
    // 简单估算:1 token ≈ 4 个字符
    return messages.reduce((acc, msg) => acc + Math.ceil(msg.content.length / 4), 0)
  }
}

6. 多模态输入

题目:前端如何实现多模态输入(图片、语音)的预处理?

答案要点:

  • 图片处理: 压缩、格式转换、Base64 编码
  • 语音处理: 录音、降噪、转文字(ASR)
  • 文件上传: 分片上传、断点续传
  • 预览展示: 图片预览、音频播放

代码示例:

typescript
class MultimodalPreprocessor {
  // 图片压缩
  async compressImage(file: File, maxSize: number): Promise<string> {
    return new Promise((resolve) => {
      const reader = new FileReader()
      reader.onload = (e) => {
        const img = new Image()
        img.onload = () => {
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')!

          // 计算压缩后的尺寸
          let { width, height } = img
          if (width > height && width > maxSize) {
            height *= maxSize / width
            width = maxSize
          } else if (height > maxSize) {
            width *= maxSize / height
            height = maxSize
          }

          canvas.width = width
          canvas.height = height
          ctx.drawImage(img, 0, 0, width, height)

          resolve(canvas.toDataURL('image/jpeg', 0.8))
        }
        img.src = e.target!.result as string
      }
      reader.readAsDataURL(file)
    })
  }

  // 语音转文字(使用 Web Speech API)
  async speechToText(): Promise<string> {
    return new Promise((resolve, reject) => {
      const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)()
      recognition.lang = 'zh-CN'
      recognition.onresult = (event) => {
        resolve(event.results[0][0].transcript)
      }
      recognition.onerror = reject
      recognition.start()
    })
  }
}

7. AI 组件库设计

题目:如果让你从零搭建一个前端 AI 组件库,你会包含哪些核心组件?

答案要点:

核心组件列表:

组件功能
Chat聊天对话容器
Message消息气泡(支持 Markdown)
StreamingText流式文本显示
CodeBlock代码块(支持复制、高亮)
PromptInput提示词输入框
ModelSelector模型选择器
TokenCounterToken 计数器
Citation引用标注
Thinking思考过程展示
FileUploader文件上传(支持多模态)

设计原则:

  • 可组合性: 组件可以灵活组合
  • 可定制性: 支持主题定制
  • 性能优化: 虚拟列表、懒加载
  • 无障碍: ARIA 支持