AI原生应用架构设计深度解析从意图理解到工具编排与多轮对话管理的工程实践
AI原生应用架构设计深度解析从意图理解到工具编排与多轮对话管理的工程实践
一、引言:AI原生应用的架构范式革新
传统软件应用以确定性逻辑为核心,每个功能模块通过预先编写的代码路径实现,输入与输出的映射是确定的、可预测的。AI原生应用(AI-Native Application)彻底改变了这一范式——应用的核心业务逻辑由大语言模型(LLM)动态生成,而非硬编码的规则引擎。这种范式转变使得应用能够处理模糊、多义、非结构化的用户意图,极大扩展了软件系统的能力边界。AI原生应用的典型特征包括:自然语言作为主要交互界面、LLM作为推理引擎驱动业务逻辑、意图理解作为请求入口、工具编排作为执行手段、多轮对话管理上下文状态、检索增强提供外部知识。这些特征使得传统Web应用的MVC架构不再完全适用,需要新的架构模式来管理不确定性、优化延迟、控制成本。AI原生应用架构的核心挑战包括:意图理解的不确定性(用户表达可能模糊、多义、不完整)、工具编排的复杂性(多个工具的选择、组合、依赖管理)、多轮对话的状态管理(上下文窗口限制、会话持久化、话题切换)、延迟优化(LLM推理慢于传统API数个量级)、成本控制(每次LLM调用都有Token费用)、安全防护(防止越狱和有害内容生成)。一个成熟的AI原生应用架构通常包含以下核心层次:意图理解层(请求分类、槽位填充、意图路由)、对话管理层(上下文维护、话题跟踪、状态机)、工具编排层(工具注册、选择、执行、结果聚合)、推理引擎层(LLM调用、Prompt管理、响应解析)、知识检索层(RAG、向量数据库、知识图谱)、以及产品架构层(用户画像、个性化、反馈闭环)。本文将从这些层次出发,完整解析AI原生应用的架构设计,并提供可运行的Python代码实现。
二、意图理解层:从自然语言到结构化意图
2.1 意图识别与分类
意图理解是AI原生应用的入口层,负责将用户的自然语言输入转化为结构化的意图表示。与传统的NLP意图分类不同,AI原生应用的意图理解需要处理开放域的、多轮递进的、上下文依赖的用户表达。意图识别的核心任务包括:意图分类(确定用户想做什么)、槽位填充(提取任务所需的关键参数)、意图路由(将请求分发给对应的处理模块)、置信度评估(判断理解是否可靠)。
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any, Tuple, Callable, Awaitable
from enum import Enum
import json
import re
import time
import hashlib
import asyncio
from collections import defaultdict, deque
class IntentCategory(Enum):
"""意图类别枚举"""
SEARCH = "search"
CHAT = "chat"
TOOL_USE = "tool_use"
CODE_GEN = "code_gen"
DATA_ANALYSIS = "data_analysis"
TRANSLATION = "translation"
SUMMARIZATION = "summarization"
UNKNOWN = "unknown"
@dataclass
class Slot:
"""槽位定义"""
name: str
value: Any
required: bool = True
confidence: float = 1.0
source: str = "current"
@dataclass
class Intent:
"""结构化意图"""
category: IntentCategory
raw_text: str
slots: Dict[str, Slot] = field(default_factory=dict)
confidence: float = 0.0
sub_intent: Optional[str] = None
requires_clarification: bool = False
clarification_question: Optional[str] = None
def get_slot(self, name: str, default: Any = None) -> Any:
slot = self.slots.get(name)
return slot.value if slot else default
def is_complete(self) -> bool:
"""检查必填槽位是否都已填充"""
for slot in self.slots.values():
if slot.required and slot.value is None:
return False
return True
def missing_slots(self) -> List[str]:
"""获取缺失的必填槽位"""
missing = []
for name, slot in self.slots.items():
if slot.required and slot.value is None:
missing.append(name)
return missing
class IntentRecognizer:
"""意图识别器:基于规则+LLM的混合意图识别"""
def __init__(self):
self.rule_patterns: Dict[IntentCategory, List[str]] = {
IntentCategory.SEARCH: [r"搜索|查找|查询|搜索一下|帮我找"],
IntentCategory.CODE_GEN: [r"写代码|生成代码|实现.*函数|编写.*脚本"],
IntentCategory.TRANSLATION: [r"翻译|translate|译成"],
IntentCategory.SUMMARIZATION: [r"总结|摘要|概括|summarize"],
IntentCategory.DATA_ANALYSIS: [r"分析|统计|报表|数据"],
IntentCategory.TOOL_USE: [r"调用|执行|运行|使用.*工具"],
}
self.confidence_threshold = 0.6
self.llm_classifier = None
def recognize(self, text: str, context: Optional[Dict] = None) -> Intent:
"""识别用户意图"""
scores = defaultdict(float)
for category, patterns in self.rule_patterns.items():
for pattern in patterns:
if re.search(pattern, text, re.IGNORECASE):
scores[category] += 0.3
if context and "last_intent" in context:
last_cat = context["last_intent"]
if last_cat in scores:
scores[last_cat] += 0.2
if not scores:
return Intent(
category=IntentCategory.CHAT,
raw_text=text,
confidence=0.5
)
best_category = max(scores, key=scores.get)
best_score = scores[best_category]
slots = self._extract_slots(text, best_category)
return Intent(
category=best_category,
raw_text=text,
slots=slots,
confidence=min(best_score, 1.0)
)
def _extract_slots(self, text: str, category: IntentCategory) -> Dict[str, Slot]:
"""提取槽位"""
slots: Dict[str, Slot] = {}
if category == IntentCategory.SEARCH:
query = re.sub(r"搜索|查找|查询|搜索一下|帮我找", "", text).strip()
slots["query"] = Slot(name="query", value=query if query else None)
if "最新" in text or "最近" in text:
slots["time_range"] = Slot(name="time_range", value="recent", required=False)
elif category == IntentCategory.TRANSLATION:
lang_match = re.search(r"译成(中文|英文|日文|韩文|法文)", text)
target_lang = lang_match.group(1) if lang_match else None
slots["target_lang"] = Slot(name="target_lang", value=target_lang)
slots["source_text"] = Slot(name="source_text", value=text)
elif category == IntentCategory.CODE_GEN:
lang_match = re.search(r"(Python|Java|Go|Rust|JavaScript|C\+\+)", text, re.IGNORECASE)
slots["language"] = Slot(name="language", value=lang_match.group(1) if lang_match else "python", required=False)
slots["task"] = Slot(name="task", value=text)
return slots
recognizer = IntentRecognizer()
intent = recognizer.recognize("帮我搜索Python异步编程的最新资料")
print(f"意图: {intent.category.value}, 置信度: {intent.confidence:.2f}")
print(f"槽位: {[f'{k}={v.value}' for k, v in intent.slots.items()]}")
print(f"是否完整: {intent.is_complete()}, 缺失: {intent.missing_slots()}")
2.2 基于LLM的深度意图理解
规则匹配在简单场景下高效,但面对复杂多义的自然语言表达时能力有限。基于LLM的意图理解通过精心设计的Prompt,让模型直接输出结构化意图,能够处理隐式意图、多意图叠加、上下文继承等复杂场景。
INTENT_CLASSIFICATION_PROMPT = """你是一个意图识别专家。分析用户的输入,输出JSON格式的意图分析结果。
意图类别:search(搜索)、chat(闲聊)、tool_use(工具调用)、code_gen(代码生成)、data_analysis(数据分析)、translation(翻译)、summarization(摘要)
输出格式:
{{
"category": "意图类别",
"confidence": 0.0-1.0,
"slots": {{"参数名": "参数值"}},
"requires_clarification": false,
"clarification_question": "如果需要澄清则为问题,否则为null",
"reasoning": "简要分析"
}}
用户输入: {user_input}
上下文: {context}
请分析意图并输出JSON:"""
class LLMIntentRecognizer:
"""基于LLM的意图识别器"""
def __init__(self, llm_client):
self.llm = llm_client
self.prompt_template = INTENT_CLASSIFICATION_PROMPT
self.few_shot_examples = [
{"input": "今天天气怎么样", "output": {"category": "tool_use", "confidence": 0.9, "slots": {"tool": "weather"}, "requires_clarification": False}},
{"input": "帮我写个排序算法", "output": {"category": "code_gen", "confidence": 0.95, "slots": {"task": "排序算法", "language": "python"}, "requires_clarification": False}},
{"input": "这个什么意思", "output": {"category": "chat", "confidence": 0.4, "slots": {}, "requires_clarification": True, "clarification_question": "您指的是哪个内容需要解释?"}},
]
async def recognize(self, text: str, context: Optional[Dict] = None) -> Intent:
"""使用LLM进行深度意图识别"""
prompt = self.prompt_template.format(
user_input=text,
context=json.dumps(context or {}, ensure_ascii=False)
)
response = await self.llm.chat(
messages=[{"role": "user", "content": prompt}],
temperature=0.1,
response_format={"type": "json_object"}
)
try:
result = json.loads(response)
category = IntentCategory(result.get("category", "unknown"))
raw_slots = result.get("slots", {})
slots = {
k: Slot(name=k, value=v, confidence=result.get("confidence", 0.8))
for k, v in raw_slots.items()
}
return Intent(
category=category,
raw_text=text,
slots=slots,
confidence=result.get("confidence", 0.5),
requires_clarification=result.get("requires_clarification", False),
clarification_question=result.get("clarification_question")
)
except (json.JSONDecodeError, ValueError) as e:
return Intent(
category=IntentCategory.UNKNOWN,
raw_text=text,
confidence=0.3,
requires_clarification=True,
clarification_question="抱歉,我不太理解您的意思,能换个方式表达吗?"
)
三、对话管理层:上下文维护与状态机
3.1 对话上下文管理器
对话管理是AI原生应用的核心组件,负责维护对话历史、跟踪话题状态、管理上下文窗口、处理话题切换。与简单的消息列表不同,对话管理器需要智能地压缩历史、提取关键信息、在有限上下文窗口内保持对话连贯性。
@dataclass
class Message:
"""对话消息"""
role: str # user, assistant, system, tool
content: str
timestamp: float = field(default_factory=time.time)
metadata: Dict[str, Any] = field(default_factory=dict)
token_count: int = 0
@dataclass
class ConversationState:
"""对话状态"""
topic: Optional[str] = None
active_intent: Optional[Intent] = None
pending_clarification: Optional[str] = None
user_preferences: Dict[str, Any] = field(default_factory=dict)
tool_results: Dict[str, Any] = field(default_factory=dict)
turn_count: int = 0
class ConversationManager:
"""对话管理器"""
def __init__(self, max_context_tokens: int = 8000, max_messages: int = 50):
self.max_context_tokens = max_context_tokens
self.max_messages = max_messages
self.messages: deque = deque(maxlen=max_messages)
self.state = ConversationState()
self.topic_history: List[Dict] = []
self.summary_cache: Dict[str, str] = {}
def add_message(self, role: str, content: str, **metadata) -> Message:
"""添加消息到对话历史"""
msg = Message(
role=role,
content=content,
metadata=metadata,
token_count=self._estimate_tokens(content)
)
self.messages.append(msg)
self.state.turn_count += 1
if role == "user":
self._update_topic(content)
return msg
def _estimate_tokens(self, text: str) -> int:
"""粗略估算Token数量(中文约1.5字/token,英文约4字符/token)"""
chinese_chars = len(re.findall(r'[\u4e00-\u9fff]', text))
english_chars = len(text) - chinese_chars
return int(chinese_chars / 1.5 + english_chars / 4)
def _update_topic(self, text: str):
"""更新当前话题"""
new_topic = self._detect_topic(text)
if new_topic and new_topic != self.state.topic:
if self.state.topic:
self.topic_history.append({
"topic": self.state.topic,
"ended_at": time.time(),
"message_count": len(self.messages)
})
self.state.topic = new_topic
def _detect_topic(self, text: str) -> Optional[str]:
"""简单话题检测"""
topics = {
"编程": ["代码", "函数", "编程", "程序", "bug", "调试"],
"数据": ["数据", "分析", "统计", "报表", "数据库"],
"翻译": ["翻译", "translate", "语言"],
"搜索": ["搜索", "查找", "查询"],
}
for topic, keywords in topics.items():
if any(kw in text.lower() for kw in keywords):
return topic
return None
def get_context_window(self, system_prompt: str = "") -> List[Dict[str, str]]:
"""获取适合LLM的上下文窗口"""
system_msg = [{"role": "system", "content": system_prompt}] if system_prompt else []
total_tokens = self._estimate_tokens(system_prompt)
selected_messages = []
for msg in reversed(self.messages):
if total_tokens + msg.token_count > self.max_context_tokens:
break
selected_messages.insert(0, {
"role": msg.role,
"content": msg.content
})
total_tokens += msg.token_count
if len(selected_messages) < len(self.messages):
summary = self._summarize_old_messages()
if summary:
selected_messages.insert(0, {
"role": "system",
"content": f"[之前对话摘要] {summary}"
})
return system_msg + selected_messages
def _summarize_old_messages(self) -> str:
"""摘要旧消息(简化版)"""
if not self.messages:
return ""
old_msgs = list(self.messages)[:10]
topics = set()
for msg in old_msgs:
if msg.role == "user":
topic = self._detect_topic(msg.content)
if topic:
topics.add(topic)
return f"之前讨论了: {', '.join(topics)}" if topics else ""
def get_state(self) -> ConversationState:
return self.state
def reset(self):
"""重置对话"""
self.messages.clear()
self.state = ConversationState()
self.topic_history.clear()
3.2 对话状态机
对于有明确业务流程的AI应用(如订单处理、预约系统),使用状态机管理对话流程能够确保业务逻辑的完整性和可控性。状态机定义了对话的合法状态和状态间的转换规则,防止对话偏离预期流程。
from enum import Enum, auto
class OrderState(Enum):
"""订单处理状态"""
INIT = auto()
COLLECTING_ITEMS = auto()
CONFIRMING_ORDER = auto()
COLLECTING_ADDRESS = auto()
COLLECTING_PAYMENT = auto()
ORDER_CONFIRMED = auto()
CANCELLED = auto()
class OrderStateMachine:
"""订单对话状态机"""
TRANSITIONS = {
OrderState.INIT: [OrderState.COLLECTING_ITEMS],
OrderState.COLLECTING_ITEMS: [OrderState.CONFIRMING_ORDER, OrderState.COLLECTING_ITEMS],
OrderState.CONFIRMING_ORDER: [OrderState.COLLECTING_ADDRESS, OrderState.COLLECTING_ITEMS],
OrderState.COLLECTING_ADDRESS: [OrderState.COLLECTING_PAYMENT, OrderState.CONFIRMING_ORDER],
OrderState.COLLECTING_PAYMENT: [OrderState.ORDER_CONFIRMED, OrderState.COLLECTING_PAYMENT],
OrderState.ORDER_CONFIRMED: [],
OrderState.CANCELLED: [],
}
STATE_PROMPTS = {
OrderState.INIT: "您好!请问您想购买什么商品?",
OrderState.COLLECTING_ITEMS: "还有其他需要购买的商品吗?",
OrderState.CONFIRMING_ORDER: "您的订单包含: {items},确认下单吗?",
OrderState.COLLECTING_ADDRESS: "请提供收货地址。",
OrderState.COLLECTING_PAYMENT: "请选择支付方式: 1.微信支付 2.支付宝 3.银行卡",
OrderState.ORDER_CONFIRMED: "订单已确认!订单号: {order_id},感谢您的购买。",
}
def __init__(self):
self.state = OrderState.INIT
self.data: Dict[str, Any] = {"items": [], "address": None, "payment": None}
def transition(self, user_input: str) -> str:
"""处理用户输入并进行状态转换"""
if self.state == OrderState.INIT:
self.data["items"].append(user_input)
self._move_to(OrderState.COLLECTING_ITEMS)
elif self.state == OrderState.COLLECTING_ITEMS:
if user_input in ["确认", "没有了", "下单"]:
self._move_to(OrderState.CONFIRMING_ORDER)
else:
self.data["items"].append(user_input)
elif self.state == OrderState.CONFIRMING_ORDER:
if user_input in ["确认", "是的", "确定"]:
self._move_to(OrderState.COLLECTING_ADDRESS)
else:
self._move_to(OrderState.COLLECTING_ITEMS)
elif self.state == OrderState.COLLECTING_ADDRESS:
self.data["address"] = user_input
self._move_to(OrderState.COLLECTING_PAYMENT)
elif self.state == OrderState.COLLECTING_PAYMENT:
self.data["payment"] = user_input
self.data["order_id"] = f"ORD{int(time.time())}"
self._move_to(OrderState.ORDER_CONFIRMED)
return self._get_prompt()
def _move_to(self, new_state: OrderState):
if new_state in self.TRANSITIONS.get(self.state, []):
self.state = new_state
else:
raise ValueError(f"非法状态转换: {self.state.name} -> {new_state.name}")
def _get_prompt(self) -> str:
prompt = self.STATE_PROMPTS.get(self.state, "")
return prompt.format(**self.data) if "{" in prompt else prompt
四、工具编排层:注册、选择与执行
4.1 工具注册中心
工具编排是AI原生应用的核心能力之一。LLM通过调用外部工具(API、数据库、搜索引擎、代码执行器等)来扩展自身能力,实现实时信息获取、复杂计算、外部系统操作。工具编排层需要管理工具的注册、描述、选择、执行和结果处理。
@dataclass
class ToolParameter:
"""工具参数定义"""
name: str
type: str
description: str
required: bool = True
default: Any = None
enum: Optional[List[str]] = None
@dataclass
class ToolDefinition:
"""工具定义"""
name: str
description: str
parameters: List[ToolParameter]
handler: Callable
category: str = "general"
timeout: float = 30.0
def to_openai_schema(self) -> Dict:
"""转换为OpenAI Function Calling格式"""
properties = {}
required = []
for param in self.parameters:
prop = {"type": param.type, "description": param.description}
if param.enum:
prop["enum"] = param.enum
properties[param.name] = prop
if param.required:
required.append(param.name)
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": {
"type": "object",
"properties": properties,
"required": required
}
}
}
class ToolRegistry:
"""工具注册中心"""
def __init__(self):
self._tools: Dict[str, ToolDefinition] = {}
self._categories: Dict[str, List[str]] = defaultdict(list)
def register(self, tool: ToolDefinition):
"""注册工具"""
self._tools[tool.name] = tool
self._categories[tool.category].append(tool.name)
def unregister(self, name: str):
"""注销工具"""
tool = self._tools.pop(name, None)
if tool:
self._categories[tool.category].remove(name)
def get(self, name: str) -> Optional[ToolDefinition]:
return self._tools.get(name)
def list_tools(self, category: Optional[str] = None) -> List[ToolDefinition]:
if category:
names = self._categories.get(category, [])
return [self._tools[n] for n in names]
return list(self._tools.values())
def get_openai_schemas(self) -> List[Dict]:
"""获取所有工具的OpenAI格式描述"""
return [tool.to_openai_schema() for tool in self._tools.values()]
async def execute(self, name: str, arguments: Dict[str, Any]) -> Any:
"""执行工具"""
tool = self._tools.get(name)
if not tool:
raise ValueError(f"工具不存在: {name}")
try:
if asyncio.iscoroutinefunction(tool.handler):
result = await asyncio.wait_for(
tool.handler(**arguments),
timeout=tool.timeout
)
else:
result = await asyncio.wait_for(
asyncio.to_thread(tool.handler, **arguments),
timeout=tool.timeout
)
return {"success": True, "result": result}
except asyncio.TimeoutError:
return {"success": False, "error": f"工具执行超时: {tool.timeout}秒"}
except Exception as e:
return {"success": False, "error": str(e)}
# 示例工具实现
async def search_web(query: str, max_results: int = 5) -> List[Dict]:
"""网页搜索工具"""
await asyncio.sleep(0.5)
return [
{"title": f"搜索结果-{i}: {query}", "url": f"https://example.com/{i}", "snippet": f"这是关于{query}的搜索结果..."}
for i in range(min(max_results, 3))
]
async def get_weather(city: str, unit: str = "celsius") -> Dict:
"""天气查询工具"""
await asyncio.sleep(0.3)
return {"city": city, "temperature": 25, "unit": unit, "condition": "晴", "humidity": 60}
def calculate(expression: str) -> float:
"""计算器工具"""
allowed = re.match(r'^[\d+\-*/.()\s]+$', expression)
if not allowed:
raise ValueError("表达式包含非法字符")
return eval(expression)
# 注册工具
registry = ToolRegistry()
registry.register(ToolDefinition(
name="search_web",
description="搜索互联网获取信息",
parameters=[
ToolParameter(name="query", type="string", description="搜索关键词"),
ToolParameter(name="max_results", type="integer", description="最大返回结果数", required=False, default=5),
],
handler=search_web,
category="information"
))
registry.register(ToolDefinition(
name="get_weather",
description="查询指定城市的天气",
parameters=[
ToolParameter(name="city", type="string", description="城市名称"),
ToolParameter(name="unit", type="string", description="温度单位", required=False, default="celsius", enum=["celsius", "fahrenheit"]),
],
handler=get_weather,
category="information"
))
registry.register(ToolDefinition(
name="calculate",
description="数学计算器,支持四则运算",
parameters=[
ToolParameter(name="expression", type="string", description="数学表达式,如 2+3*4"),
],
handler=calculate,
category="utility"
))
4.2 工具选择与编排引擎
工具选择是工具编排的核心问题。当有多个可用工具时,LLM需要根据用户意图选择正确的工具,并按正确的顺序调用。对于复杂任务,可能需要多步工具调用——前一个工具的输出作为后一个工具的输入。
TOOL_SELECTION_PROMPT = """你是一个工具选择专家。根据用户请求,从可用工具列表中选择合适的工具并生成调用参数。
可用工具:
{tools}
用户请求: {user_request}
对话上下文: {context}
请输出JSON:
{{
"tool_calls": [
{{
"tool": "工具名",
"arguments": {{"参数名": "参数值"}},
"reasoning": "选择此工具的原因"
}}
],
"response": "如果不需要工具调用,直接回答用户"
}}
"""
class ToolOrchestrator:
"""工具编排引擎"""
def __init__(self, registry: ToolRegistry, llm_client):
self.registry = registry
self.llm = llm_client
self.max_tool_calls = 5 # 单次请求最大工具调用次数
async def orchestrate(self, user_input: str, context: Optional[Dict] = None) -> Dict[str, Any]:
"""编排工具调用"""
tools = self.registry.get_openai_schemas()
prompt = TOOL_SELECTION_PROMPT.format(
tools=json.dumps(tools, ensure_ascii=False, indent=2),
user_request=user_input,
context=json.dumps(context or {}, ensure_ascii=False)
)
response = await self.llm.chat(
messages=[{"role": "user", "content": prompt}],
temperature=0.1,
tools=tools
)
if response.get("tool_calls"):
results = []
for call in response["tool_calls"][:self.max_tool_calls]:
tool_name = call["function"]["name"]
arguments = json.loads(call["function"]["arguments"])
result = await self.registry.execute(tool_name, arguments)
results.append({
"tool": tool_name,
"arguments": arguments,
"result": result
})
synthesis = await self._synthesize_response(user_input, results, context)
return {
"tool_results": results,
"response": synthesis
}
return {
"tool_results": [],
"response": response.get("content", "我无法处理您的请求。")
}
async def _synthesize_response(self, user_input: str, tool_results: List[Dict], context: Optional[Dict]) -> str:
"""综合工具结果生成自然语言响应"""
results_str = json.dumps(tool_results, ensure_ascii=False, indent=2)
prompt = f"""根据以下工具调用结果,回答用户的问题。
用户问题: {user_input}
工具结果:
{results_str}
请用自然语言回答用户:"""
response = await self.llm.chat(
messages=[{"role": "user", "content": prompt}],
temperature=0.7
)
return response.get("content", "处理完成")
class MultiStepPlanner:
"""多步工具调用规划器"""
def __init__(self, orchestrator: ToolOrchestrator):
self.orchestrator = orchestrator
async def plan_and_execute(self, user_input: str, max_steps: int = 5) -> Dict[str, Any]:
"""规划并执行多步工具调用"""
plan = await self._create_plan(user_input)
results = []
for i, step in enumerate(plan[:max_steps]):
step_input = step["input_template"]
for prev_result in results:
placeholder = f"${{{prev_result['step']}}}"
step_input = step_input.replace(placeholder, str(prev_result["result"]))
step_result = await self.orchestrator.orchestrate(step_input)
results.append({
"step": step["name"],
"input": step_input,
"result": step_result.get("response", ""),
"tool_results": step_result.get("tool_results", [])
})
if step.get("condition") and not self._check_condition(step["condition"], step_result):
break
return {"plan": plan, "results": results}
async def _create_plan(self, user_input: str) -> List[Dict]:
"""创建执行计划"""
plan_prompt = f"""分析用户请求,制定工具调用计划。
用户请求: {user_input}
可用工具: {json.dumps([t.name for t in self.orchestrator.registry.list_tools()])}
输出JSON格式的执行计划:
{{
"steps": [
{{"name": "步骤名", "tool": "工具名", "input_template": "输入模板,可用${{上一步名}}引用上一步结果", "condition": "可选的继续条件"}}
]
}}"""
response = await self.orchestrator.llm.chat(
messages=[{"role": "user", "content": plan_prompt}],
temperature=0.2
)
try:
return json.loads(response).get("steps", [])
except json.JSONDecodeError:
return [{"name": "direct", "tool": "any", "input_template": user_input}]
def _check_condition(self, condition: str, result: Dict) -> bool:
"""检查执行条件"""
return True
五、推理引擎层:Prompt管理与LLM调用
5.1 Prompt模板引擎
Prompt是AI原生应用中最重要的"代码"之一。好的Prompt管理系统能够支持模板化、变量注入、版本控制、A/B测试和动态优化。
class PromptTemplate:
"""Prompt模板"""
def __init__(self, template: str, variables: Optional[List[str]] = None):
self.template = template
self.variables = variables or self._extract_variables(template)
self.version = "1.0"
self.metadata: Dict[str, Any] = {}
def _extract_variables(self, template: str) -> List[str]:
return re.findall(r'\{(\w+)\}', template)
def render(self, **kwargs) -> str:
"""渲染模板"""
missing = [v for v in self.variables if v not in kwargs]
if missing:
raise ValueError(f"缺少模板变量: {missing}")
return self.template.format(**kwargs)
class PromptManager:
"""Prompt管理器"""
def __init__(self):
self.templates: Dict[str, PromptTemplate] = {}
self.versions: Dict[str, List[Dict]] = defaultdict(list)
self._init_default_templates()
def _init_default_templates(self):
"""初始化默认模板"""
self.register("rag_answer", """基于以下检索到的上下文信息回答用户问题。
上下文信息:
{context}
用户问题: {question}
要求:
1. 只基于上下文信息回答
2. 如果上下文不足以回答,明确说明
3. 引用信息来源
回答:""")
self.register("summarize", """请总结以下文本的要点。
文本:
{text}
要求:
1. 不超过{max_points}个要点
2. 每个要点一行
3. 保持原文关键信息
总结:""")
self.register("tool_describe", """你是一个AI助手,可以使用以下工具:
{tools_description}
用户请求: {user_request}
判断是否需要使用工具。如果需要,选择合适的工具并提供参数。如果不需要,直接回答。""")
def register(self, name: str, template: str, version: str = "1.0"):
"""注册Prompt模板"""
self.templates[name] = PromptTemplate(template)
self.templates[name].version = version
self.versions[name].append({
"version": version,
"template": template,
"timestamp": time.time()
})
def render(self, name: str, **kwargs) -> str:
"""渲染指定模板"""
template = self.templates.get(name)
if not template:
raise KeyError(f"模板不存在: {name}")
return template.render(**kwargs)
def get_versions(self, name: str) -> List[Dict]:
"""获取模板的所有版本"""
return self.versions.get(name, [])
5.2 LLM客户端封装
class LLMClient:
"""LLM客户端封装"""
def __init__(self, model: str = "gpt-4", api_key: str = "", base_url: str = ""):
self.model = model
self.api_key = api_key
self.base_url = base_url
self.token_usage = {"input": 0, "output": 0, "total_cost": 0.0}
self.retry_config = {"max_retries": 3, "base_delay": 1.0, "max_delay": 30.0}
async def chat(self, messages: List[Dict], temperature: float = 0.7,
tools: Optional[List[Dict]] = None,
response_format: Optional[Dict] = None,
max_tokens: int = 4096) -> Dict[str, Any]:
"""调用LLM聊天接口"""
for attempt in range(self.retry_config["max_retries"]):
try:
request = {
"model": self.model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
}
if tools:
request["tools"] = tools
if response_format:
request["response_format"] = response_format
response = await self._call_api(request)
self._track_usage(response.get("usage", {}))
return self._parse_response(response)
except Exception as e:
if attempt == self.retry_config["max_retries"] - 1:
raise
delay = min(self.retry_config["base_delay"] * (2 ** attempt),
self.retry_config["max_delay"])
await asyncio.sleep(delay)
return {}
async def _call_api(self, request: Dict) -> Dict:
"""调用底层API(模拟)"""
await asyncio.sleep(0.5)
return {
"content": f"这是对'{request["messages"][-1]["content"][:50]}'的模拟回复",
"usage": {"prompt_tokens": 100, "completion_tokens": 50}
}
def _parse_response(self, response: Dict) -> Dict[str, Any]:
"""解析API响应"""
return {
"content": response.get("content", ""),
"tool_calls": response.get("tool_calls"),
"usage": response.get("usage", {})
}
def _track_usage(self, usage: Dict):
"""追踪Token使用量"""
self.token_usage["input"] += usage.get("prompt_tokens", 0)
self.token_usage["output"] += usage.get("completion_tokens", 0)
cost = usage.get("prompt_tokens", 0) * 0.00001 + usage.get("completion_tokens", 0) * 0.00003
self.token_usage["total_cost"] += cost
def get_usage_stats(self) -> Dict[str, Any]:
return dict(self.token_usage)
六、知识检索层:RAG集成
6.1 向量检索增强
class SimpleVectorStore:
"""简易向量存储(用于演示)"""
def __init__(self):
self.documents: List[Dict[str, Any]] = []
self.embeddings: List[List[float]] = []
def add_documents(self, docs: List[Dict[str, Any]], embeddings: List[List[float]]):
self.documents.extend(docs)
self.embeddings.extend(embeddings)
def search(self, query_embedding: List[float], top_k: int = 3) -> List[Dict[str, Any]]:
"""余弦相似度搜索"""
if not self.embeddings:
return []
scores = []
for i, emb in enumerate(self.embeddings):
score = self._cosine_similarity(query_embedding, emb)
scores.append((i, score))
scores.sort(key=lambda x: x[1], reverse=True)
results = []
for idx, score in scores[:top_k]:
doc = dict(self.documents[idx])
doc["score"] = score
results.append(doc)
return results
def _cosine_similarity(self, a: List[float], b: List[float]) -> float:
import math
dot = sum(x * y for x, y in zip(a, b))
norm_a = math.sqrt(sum(x * x for x in a))
norm_b = math.sqrt(sum(x * x for x in b))
return dot / (norm_a * norm_b + 1e-8)
class RAGEngine:
"""RAG检索增强引擎"""
def __init__(self, llm_client: LLMClient, vector_store: SimpleVectorStore):
self.llm = llm_client
self.store = vector_store
self.prompt_manager = PromptManager()
async def answer_with_rag(self, question: str, top_k: int = 3) -> Dict[str, Any]:
"""使用RAG回答问题"""
query_embedding = await self._get_embedding(question)
retrieved = self.store.search(query_embedding, top_k=top_k)
if not retrieved:
return {
"answer": "未找到相关资料。",
"sources": [],
"retrieved_count": 0
}
context = "\n\n".join([
f"[来源{i+1}] (相关度: {doc['score']:.2f})\n{doc.get('content', '')}"
for i, doc in enumerate(retrieved)
])
prompt = self.prompt_manager.render("rag_answer", context=context, question=question)
response = await self.llm.chat(
messages=[{"role": "user", "content": prompt}],
temperature=0.3
)
return {
"answer": response.get("content", ""),
"sources": [{"content": d.get("content", "")[:100], "score": d["score"]} for d in retrieved],
"retrieved_count": len(retrieved)
}
async def _get_embedding(self, text: str) -> List[float]:
"""获取文本embedding(模拟)"""
import hashlib
hash_val = hashlib.md5(text.encode()).hexdigest()
return [int(hash_val[i:i+2], 16) / 255 for i in range(0, 32, 2)]
七、AI原生应用完整架构
7.1 应用编排器
将所有组件整合为一个完整的AI原生应用框架:
class AINativeApplication:
"""AI原生应用主类"""
def __init__(self, config: Optional[Dict] = None):
self.config = config or {}
self.llm = LLMClient(
model=self.config.get("model", "gpt-4"),
api_key=self.config.get("api_key", "")
)
self.intent_recognizer = IntentRecognizer()
self.conversation = ConversationManager(
max_context_tokens=self.config.get("max_context_tokens", 8000)
)
self.tool_registry = ToolRegistry()
self._init_tools()
self.orchestrator = ToolOrchestrator(self.tool_registry, self.llm)
self.vector_store = SimpleVectorStore()
self.rag = RAGEngine(self.llm, self.vector_store)
self.prompt_manager = PromptManager()
self.response_filters: List[Callable] = []
self.metrics = {
"total_requests": 0,
"tool_calls": 0,
"rag_queries": 0,
"avg_latency": 0.0
}
def _init_tools(self):
"""初始化内置工具"""
self.tool_registry.register(ToolDefinition(
name="search_web",
description="搜索互联网",
parameters=[ToolParameter(name="query", type="string", description="搜索关键词")],
handler=search_web,
category="information"
))
self.tool_registry.register(ToolDefinition(
name="get_weather",
description="查询天气",
parameters=[ToolParameter(name="city", type="string", description="城市名")],
handler=get_weather,
category="information"
))
self.tool_registry.register(ToolDefinition(
name="calculate",
description="数学计算",
parameters=[ToolParameter(name="expression", type="string", description="数学表达式")],
handler=calculate,
category="utility"
))
async def chat(self, user_input: str, session_id: Optional[str] = None) -> Dict[str, Any]:
"""处理用户输入并返回响应"""
start_time = time.time()
self.metrics["total_requests"] += 1
context = {
"last_intent": self.conversation.state.active_intent.category.value
if self.conversation.state.active_intent else None,
"topic": self.conversation.state.topic,
"turn_count": self.conversation.state.turn_count
}
intent = self.intent_recognizer.recognize(user_input, context)
if intent.requires_clarification:
response = intent.clarification_question or "请澄清您的问题。"
self.conversation.add_message("user", user_input)
self.conversation.add_message("assistant", response)
return {"response": response, "intent": intent.category.value, "clarified": True}
self.conversation.state.active_intent = intent
self.conversation.add_message("user", user_input)
if intent.confidence < self.intent_recognizer.confidence_threshold:
tool_result = await self.orchestrator.orchestrate(user_input, context)
self.metrics["tool_calls"] += len(tool_result.get("tool_results", []))
response = tool_result.get("response", "")
tool_results = tool_result.get("tool_results", [])
elif intent.category == IntentCategory.SEARCH:
query = intent.get_slot("query", user_input)
rag_result = await self.rag.answer_with_rag(query)
self.metrics["rag_queries"] += 1
response = rag_result["answer"]
tool_results = []
else:
messages = self.conversation.get_context_window(
system_prompt="你是一个专业的AI助手,请友好、准确地回答用户问题。"
)
llm_response = await self.llm.chat(messages=messages, temperature=0.7)
response = llm_response.get("content", "抱歉,我无法处理您的请求。")
tool_results = []
for filter_fn in self.response_filters:
response = filter_fn(response)
self.conversation.add_message("assistant", response)
latency = time.time() - start_time
self._update_avg_latency(latency)
return {
"response": response,
"intent": intent.category.value,
"confidence": intent.confidence,
"latency": round(latency, 3),
"tool_results": tool_results,
"session_id": session_id
}
def _update_avg_latency(self, latency: float):
"""更新平均延迟"""
total = self.metrics["total_requests"]
self.metrics["avg_latency"] = (
self.metrics["avg_latency"] * (total - 1) + latency
) / total
def get_metrics(self) -> Dict[str, Any]:
"""获取应用指标"""
return {
**self.metrics,
"llm_usage": self.llm.get_usage_stats(),
"conversation_turns": self.conversation.state.turn_count,
"current_topic": self.conversation.state.topic
}
def add_response_filter(self, filter_fn: Callable[[str], str]):
"""添加响应过滤器"""
self.response_filters.append(filter_fn)
async def demo():
"""演示AI原生应用"""
app = AINativeApplication(config={"model": "gpt-4"})
app.vector_store.add_documents(
docs=[
{"content": "Python是一种广泛使用的高级编程语言,由Guido van Rossum于1991年创建。"},
{"content": "异步编程是Python中处理IO密集型任务的重要模式,使用async/await语法。"},
{"content": "GIL(全局解释器锁)是CPython的实现限制,影响多线程性能。"},
],
embeddings=[
[0.1, 0.5, 0.3, 0.8, 0.2, 0.7, 0.4, 0.6, 0.1, 0.9, 0.3, 0.5, 0.7, 0.2, 0.8, 0.4],
[0.3, 0.7, 0.5, 0.6, 0.4, 0.8, 0.2, 0.9, 0.1, 0.6, 0.5, 0.3, 0.8, 0.4, 0.7, 0.2],
[0.5, 0.3, 0.8, 0.2, 0.7, 0.4, 0.6, 0.1, 0.9, 0.3, 0.7, 0.5, 0.2, 0.8, 0.4, 0.6],
]
)
queries = [
"搜索Python异步编程",
"计算 128 * 45 + 37",
"Python是什么语言",
]
for q in queries:
print(f"\n{'='*60}")
print(f"用户: {q}")
result = await app.chat(q, session_id="demo-001")
print(f"意图: {result['intent']} (置信度: {result['confidence']:.2f})")
print(f"延迟: {result['latency']}秒")
print(f"回复: {result['response'][:200]}")
if result.get("tool_results"):
for tr in result["tool_results"]:
print(f" 工具[{tr['tool']}]: {tr['result']}")
print(f"\n{'='*60}")
print(f"应用指标: {json.dumps(app.get_metrics(), indent=2, ensure_ascii=False)}")
if __name__ == "__main__":
asyncio.run(demo())
八、总结
AI原生应用架构是软件工程的一次范式转变。本文从意图理解层、对话管理层、工具编排层、推理引擎层、知识检索层五个核心层次,完整解析了AI原生应用的架构设计。意图理解层通过规则匹配与LLM结合实现精准的意图分类和槽位填充;对话管理层通过上下文窗口管理和状态机确保对话连贯性;工具编排层通过工具注册中心和编排引擎实现LLM与外部系统的交互;推理引擎层通过Prompt模板管理和LLM客户端封装提供稳定的推理能力;知识检索层通过RAG引擎为应用注入外部知识。这些层次协同工作,共同构成了一个完整的AI原生应用框架。随着大模型能力的持续提升和成本的下降,AI原生应用将成为下一代软件应用的主流形态,掌握其架构设计方法将成为每个工程师的核心竞争力。
- 点赞
- 收藏
- 关注作者
评论(0)