🔥🔥🔥Retrieval-Augmented Tool Selector 工具已开源!!! 求 Star ⭐️⭐️⭐️ :github.com/xiaoyesoso/...
在大型语言模型(LLM)应用中,工具调用能力已成为连接AI与真实世界的桥梁。然而,传统方法存在工具选择不准确、参数匹配错误等问题。本文将深入探讨检索增强工具选择器(Retrieval-Augmented Tool Selector) 如何通过语义嵌入技术解决这些挑战。
引言:大模型工具调用的挑战
当前LLM工具调用面临三大核心问题:
-
幻觉问题:模型可能调用不存在的工具
-
参数歧义:对枚举型参数理解不准确
-
上下文缺失:无法有效利用历史交互信息
graph TD
A[用户查询] --> B[传统工具调用]
B --> C{问题}
C --> D[工具选择错误]
C --> E[参数匹配错误]
C --> F[枚举值误解]
1. 检索增强工具选择器架构
1.1 系统整体架构
graph LR
A[用户查询] --> B[语义嵌入引擎]
B --> C[工具选择器]
C --> D[参数过滤器]
D --> E[增强的API调用]
E --> F[大模型执行]
subgraph 预处理
G[工具库] --> H[工具嵌入]
I[枚举值] --> J[枚举嵌入]
end
H --> C
J --> D
1.2 核心组件交互
sequenceDiagram
participant User
participant API_Gateway
participant Tool_Selector
participant OpenAI_API
User->>API_Gateway: 发送查询请求
API_Gateway->>Tool_Selector: 提取用户查询
Tool_Selector->>Tool_Selector: 计算语义相似度
Tool_Selector->>API_Gateway: 返回增强工具集
API_Gateway->>OpenAI_API: 转发增强请求
OpenAI_API->>API_Gateway: 返回执行结果
API_Gateway->>User: 返回最终响应
2. 核心实现解析
2.1 语义嵌入引擎
python
class RetrievalAugmentedToolSelector:
def __init__(self, tools, api_key, base_url, embedding_model="text-embedding-ada-002"):
# 初始化OpenAI客户端
self.client = openai.Client(api_key=api_key, base_url=base_url)
# 存储工具定义和嵌入模型
self.embedding_model = embedding_model
self.tools = tools
# 预计算工具嵌入向量
self.tool_embeddings = []
self.tool_names = []
self.tool_definitions = []
for tool in tools:
# 构建工具语义文本:名称+描述
tool_name = tool["function"]["name"]
tool_description = tool["function"]["description"]
tool_text = f"{tool_name}: {tool_description}"
# 计算嵌入向量
embedding = self._get_embedding(tool_text)
self.tool_embeddings.append(embedding)
self.tool_names.append(tool_name)
# 存储工具定义副本
self.tool_definitions.append({
"type": "function",
"function": {
"name": tool_name,
"description": tool_description,
"parameters": tool["function"]["parameters"]
})
# 转换为NumPy数组便于计算
self.tool_embeddings = np.array(self.tool_embeddings)
# 预计算枚举值嵌入
self.enum_embeddings_cache = {}
all_enum_values = set()
# 收集所有枚举值
for tool in tools:
parameters = tool["function"]["parameters"]
if "properties" in parameters:
for prop in parameters["properties"].values():
if "enum" in prop:
for value in prop["enum"]:
str_value = str(value).strip()
all_enum_values.add(str_value)
# 批量计算枚举值嵌入
if all_enum_values:
enum_values_list = list(all_enum_values)
embeddings = self._get_embeddings(enum_values_list)
# 创建枚举值到嵌入的映射
for value, embedding in zip(enum_values_list, embeddings):
self.enum_embeddings_cache[value] = embedding
2.2 工具选择算法
python
def select_tools(self, query, tool_threshold=0.7, tool_top_k=1,
enum_threshold=0.6, enum_top_k=3):
"""
基于语义相似度选择最相关的工具和参数
参数:
query: 用户查询文本
tool_threshold: 工具相似度阈值(0-1)
tool_top_k: 返回的最大工具数量
enum_threshold: 枚举值相似度阈值
enum_top_k: 每个参数保留的最大枚举值数
"""
# 计算查询的嵌入向量
query_embedding = self._get_embedding(query)
# 计算工具相似度
similarities = cosine_similarity([query_embedding], self.tool_embeddings)[0]
# 按相似度排序工具
tool_scores = list(enumerate(similarities))
tool_scores.sort(key=lambda x: x[1], reverse=True)
selected_tools = []
for idx, score in tool_scores:
# 应用阈值和top_k过滤
if score >= tool_threshold and len(selected_tools) < tool_top_k:
# 深拷贝工具定义
tool_copy = json.loads(json.dumps(self.tool_definitions[idx]))
# 过滤枚举参数
parameters = tool_copy["function"]["parameters"]
if "properties" in parameters:
for prop_name, prop in parameters["properties"].items():
if "enum" in prop:
# 转换枚举值为字符串
enum_values = [str(v).strip() for v in prop["enum"]]
# 应用语义过滤
prop["enum"] = self._filter_enum_values(
query_embedding,
enum_values,
threshold=enum_threshold,
top_k=enum_top_k
)
selected_tools.append(tool_copy)
return selected_tools
2.3 枚举值过滤算法
python
def _filter_enum_values(self, query_embedding, enum_values, threshold, top_k):
"""
基于语义相似度过滤枚举值
参数:
query_embedding: 查询的嵌入向量
enum_values: 枚举值列表
threshold: 相似度阈值
top_k: 保留的最大值数量
"""
if not enum_values:
return enum_values
# 获取预计算的枚举值嵌入
enum_embeddings = [self.enum_embeddings_cache[value] for value in enum_values]
enum_embeddings = np.array(enum_embeddings)
# 计算相似度
similarities = cosine_similarity([query_embedding], enum_embeddings)[0]
# 创建(索引, 相似度, 值)元组
enum_scores = [(i, sim, value) for i, (sim, value)
in enumerate(zip(similarities, enum_values))]
# 按相似度降序排序
enum_scores.sort(key=lambda x: x[1], reverse=True)
# 应用阈值过滤
filtered_enum = []
for i, sim, value in enum_scores:
if sim >= threshold and len(filtered_enum) < top_k:
filtered_enum.append(value)
return filtered_enum
3. 语义匹配过程详解
3.1 工具选择原理
graph TD
A[用户查询] --> B[计算查询嵌入]
C[预计算工具嵌入] --> D[余弦相似度计算]
B --> D
D --> E[相似度排序]
E --> F[应用阈值过滤]
F --> G[返回Top-K工具]
3.2 枚举值过滤原理
graph LR
A[用户查询] --> B[查询嵌入]
C[枚举值嵌入缓存] --> D[相似度计算]
B --> D
D --> E[排序枚举值]
E --> F[应用阈值和Top-K]
F --> G[返回过滤后枚举值]
3.3 参数调优指南
参数 | 默认值 | 适用场景 | 调整建议 |
---|---|---|---|
tool_threshold | 0.7 | 工具匹配 | 工具数量多时提高,工具少时降低 |
tool_top_k | 1 | 多工具场景 | 根据实际工具数量调整 |
enum_threshold | 0.6 | 参数过滤 | 枚举值语义明确时提高 |
enum_top_k | 3 | 多值参数 | 根据参数复杂度调整 |
4. API服务集成实现
4.1 Flask API架构
python
@app.route('/v1/chat/completions', methods=['POST'])
def chat_completion():
"""
OpenAI兼容的聊天补全端点,带语义工具选择
请求格式: https://platform.openai.com/docs/api-reference/chat/create
响应格式: https://platform.openai.com/docs/api-reference/chat/object
"""
try:
# 获取并验证请求负载
payload = request.get_json()
if not payload or "messages" not in payload:
return jsonify({
"error": {
"message": "Invalid request: missing 'messages' parameter",
"type": "invalid_request_error"
}), 400
# 增强请求:添加工具选择
enhanced_payload = enhance_request(payload)
# 调用OpenAI API
response = openai_client.chat.completions.create(enhanced_payload)
# 返回OpenAI兼容响应
return jsonify(response.to_dict())
except Exception as e:
return jsonify({
"error": {
"message": f"Processing error: {str(e)}",
"type": "server_error"
}), 500
4.2 请求增强过程
python
def enhance_request(payload: Dict[str, Any]) -> Dict[str, Any]:
"""
通过工具选择增强OpenAI请求负载
保留所有原始参数
"""
# 创建负载副本
payload = payload.copy()
# 获取最新的用户消息
user_query = process_message(payload.get("messages", []))
if not user_query:
return payload
# 基于用户查询选择工具
selected_tools = tool_selector.select_tools(
user_query,
tool_threshold=Config.TOOL_THRESHOLD,
tool_top_k=Config.TOOL_TOP_K,
enum_threshold=Config.ENUM_THRESHOLD,
enum_top_k=Config.ENUM_TOP_K
)
# 添加选择的工具到请求负载
payload["tools"] = selected_tools
# 设置工具选择策略
if "tool_choice" not in payload:
payload["tool_choice"] = "auto"
return payload
5. 部署与实践指南
5.1 部署架构
graph TB
subgraph 云环境
A[Docker容器] --> B[API服务]
C[负载均衡] --> A
D[自动扩缩容] --> A
end
subgraph 客户端
E[Web应用] --> C
F[移动应用] --> C
G[CLI工具] --> C
end
B --> H[(向量数据库)]
B --> I[OpenAI API]
5.2 Docker部署示例
Dockerfile
# 使用Python 3.10精简镜像
FROM python:3.10-slim
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 设置环境变量
ENV OPENAI_API_KEY=your_api_key
ENV PORT=5000
# 暴露端口
EXPOSE 5000
# 启动命令
CMD ["python", "app.py"]