工程化 LLM 交互协议与 Agent 系统设计实践

62 阅读3分钟

本文不是概念介绍,而是一套 可落地、可实现、可扩展 的实践方案,覆盖 Prompt DSL 设计、Agent Router 架构,以及前端渲染落地。

你现在做的,其实已经进入 「LLM 交互协议 + Agent 系统设计」 这一层级。

一、统一的 LLM Prompt DSL 设计(@ / # / ::)

这是一套 业界可行 + 工程友好 的 DSL(Domain Specific Language)规范,用于降低 Prompt 的歧义,并让系统具备可解析、可路由、可扩展的能力。

1️⃣ 设计目标

  • 人类可读:用户可以自然输入

  • 机器可解析:系统可以稳定结构化解析

  • 不污染 Markdown:Markdown 仍然是最终输出格式

  • 可映射 Agent / Tool / Prompt Template

二、三种符号的明确职责

✅ @ —— 上下文 / 资源绑定(Context Binding)

把「外部对象」喂给模型

适用场景

  • 文件(Code / Shader)

  • 3D 场景 / 模型

  • 文档

  • 历史记忆

  • 工具实例

语法规范

@type[:name][(options)]

示例

@file:App.tsx
@scene:planet.glb
@mesh:earth
@shader:atmosphere.glsl
@doc:design.md
@memory:last-session

解析后的内部结构

{
  kind: "context",
  type: "file",
  name: "App.tsx"
}

✅ # —— 意图 / 能力 / 输出约束(Intent / Capability)

告诉系统「你要模型怎么做」

适用场景

  • 动作:analyze / refactor / optimize

  • 能力:code / vision / math / 3d

  • 输出结构:json / markdown / table

  • Agent 路由依据

语法规范

#intent[(options)]

示例

#analyze
#refactor
#optimize(perf)
#json
#steps

解析后的内部结构

{
  kind: "intent",
  name: "refactor",
  options: { target: "perf" }
}

✅ :: —— Markdown 结构化块 / 自定义组件

在 Markdown 中声明「非纯文本块」

适用场景

  • 富媒体(audio / video)

  • 3D 预览

  • 结构化输出块

语法规范

::component-name
content
::

示例

::audio
https://example.com/a.mp3
::

::model-viewer
planet.glb
::

三、完整 DSL 示例

@scene:planet.glb
@shader:atmosphere.glsl

#analyze
#markdown

请分析这个星球场景的性能瓶颈

四、Agent Router 设计(系统核心)

Agent Router 是整个系统的「大脑」,负责把 DSL 转换为具体的模型调用策略。

1️⃣ 职责链路

用户输入
 ↓
DSL 解析
 ↓
意图识别 (#)
 ↓
上下文装配 (@)
 ↓
Agent 选择
 ↓
Prompt 生成
 ↓
模型调用

2️⃣ Agent 分类建议

type AgentType =
  | "chat"
  | "code"
  | "vision"
  | "3d"
  | "data"
  | "doc";

3️⃣ 路由规则示例

function routeAgent(intents, contexts) {
  if (contexts.some(c => c.type === "scene")) return "3d";
  if (intents.includes("refactor")) return "code";
  if (intents.includes("json")) return "data";
  return "chat";
}

4️⃣ Prompt Template 示例

const promptTemplates = {
  refactor: ({ context }) => `
You are a senior engineer.
Please refactor the following code:

${context.files.join("\n")}
`,
  analyze3d: ({ context }) => `
Analyze this 3D scene for performance:

${context.scene}
`
};

5️⃣ 内部统一数据结构

{
  agent: "3d",
  intent: ["analyze"],
  output: "markdown",
  context: {
    scene: "planet.glb",
    shader: "atmosphere.glsl"
  }
}

五、React + ReactMarkdown + unist AST 落地

前端的核心任务是:把 Markdown 还原为“有语义的 UI”

1️⃣ 消息数据结构

type Message =
  | { type: "markdown"; content: string }
  | { type: "image"; url: string }
  | { type: "audio"; url: string };

⚠️ 只要是 LLM 输出 Markdown,本质上就是 text / markdown

2️⃣ ReactMarkdown 渲染配置

<ReactMarkdown
  remarkPlugins={[
    remarkGfm,
    remarkDirective,
    directiveFromMarkdown,
    remarkCustomBlocks
  ]}
  components={{
    audio: AudioBlock,
    modelViewer: ModelViewerBlock
  }}
>
  {message.content}
</ReactMarkdown>

3️⃣ 使用 unist-util-visit 解析自定义块

import { visit } from "unist-util-visit";

export function remarkCustomBlocks() {
  return (tree) => {
    visit(tree, "containerDirective", (node) => {
      if (node.name === "audio") node.type = "audio";
      if (node.name === "model-viewer") node.type = "modelViewer";
    });
  };
}

4️⃣ 自定义组件渲染

function AudioBlock({ node }) {
  return <audio controls src={node.children[0].value} />;
}

function ModelViewerBlock({ node }) {
  return <ModelViewer src={node.children[0].value} />;
}

六、整体架构示意

[User Input]
   |
   |-- @context
   |-- #intent
   v
[DSL Parser]
   |
[Agent Router]
   |
[Prompt Builder]
   |
[LLM]
   |
[Markdown Output]
   |
[ReactMarkdown + AST]
   |
[Custom Components Render]

七、架构级总结

@ 决定「喂什么」
# 决定「怎么做」
:: 决定「怎么展示」

三者组合在一起,就形成了一套:

  • 可扩展

  • 可路由

  • 可演进

工程化 LLM 交互系统

八、下一步演进方向

  • DSL 的 EBNF 形式化定义

  • 对接 OpenAI Tool / Structured Output

  • Agent 多模型协同(Planner / Executor)

  • Prompt 版本化与可观测性