新增user_identifier
This commit is contained in:
parent
1174767211
commit
6c1393e96a
@ -749,7 +749,7 @@ async def chat_completions(request: ChatRequest, authorization: Optional[str] =
|
||||
project_dir = create_project_directory(request.dataset_ids, bot_id, request.robot_type)
|
||||
|
||||
# 收集额外参数作为 generate_cfg
|
||||
exclude_fields = {'messages', 'model', 'model_server', 'dataset_ids', 'language', 'tool_response', 'system_prompt', 'mcp_settings' ,'stream', 'robot_type', 'bot_id'}
|
||||
exclude_fields = {'messages', 'model', 'model_server', 'dataset_ids', 'language', 'tool_response', 'system_prompt', 'mcp_settings' ,'stream', 'robot_type', 'bot_id', 'user_identifier'}
|
||||
generate_cfg = {k: v for k, v in request.model_dump().items() if k not in exclude_fields}
|
||||
|
||||
# 处理消息
|
||||
@ -769,7 +769,8 @@ async def chat_completions(request: ChatRequest, authorization: Optional[str] =
|
||||
mcp_settings=request.mcp_settings,
|
||||
robot_type=request.robot_type,
|
||||
project_dir=project_dir,
|
||||
generate_cfg=generate_cfg
|
||||
generate_cfg=generate_cfg,
|
||||
user_identifier=request.user_identifier
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@ -912,7 +913,8 @@ async def create_agent_and_generate_response(
|
||||
mcp_settings: Optional[List[Dict]],
|
||||
robot_type: str,
|
||||
project_dir: Optional[str] = None,
|
||||
generate_cfg: Optional[Dict] = None
|
||||
generate_cfg: Optional[Dict] = None,
|
||||
user_identifier: Optional[str] = None
|
||||
) -> Union[ChatResponse, StreamingResponse]:
|
||||
"""创建agent并生成响应的公共逻辑"""
|
||||
if generate_cfg is None:
|
||||
@ -929,7 +931,8 @@ async def create_agent_and_generate_response(
|
||||
language=language,
|
||||
system_prompt=system_prompt,
|
||||
mcp_settings=mcp_settings,
|
||||
robot_type=robot_type
|
||||
robot_type=robot_type,
|
||||
user_identifier=user_identifier
|
||||
)
|
||||
|
||||
# 根据stream参数决定返回流式还是非流式响应
|
||||
@ -1082,7 +1085,8 @@ async def chat_completions_v2(request: ChatRequestV2, authorization: Optional[st
|
||||
mcp_settings=bot_config.get("mcp_settings", []),
|
||||
robot_type=bot_config.get("robot_type", "agent"),
|
||||
project_dir=project_dir,
|
||||
generate_cfg={} # v2接口不传递额外的generate_cfg
|
||||
generate_cfg={}, # v2接口不传递额外的generate_cfg
|
||||
user_identifier=request.user_identifier
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
|
||||
@ -16,9 +16,11 @@
|
||||
| 设备控制 | 打开/关闭/启动/停止/调节/设置 | dxcore_update_device_status | P0 |
|
||||
| 消息通知 | @用户名/通知/告知/提醒 | wowtalk_send_message_to_member | P0 |
|
||||
| 状态查询 | 状态/温度/湿度/运行情况 | dxcore_get_device_status | P1 |
|
||||
| 位置查询 | 位置/在哪/查找/坐标 | eb_get_sensor_location | P1 |
|
||||
| 环境查询 | 天气/气温/降水/风速 | weather_get_by_location | P1 |
|
||||
| 人员检索 | 找人/员工/同事/联系方式/人员位置 | find_employee_location | P2 |
|
||||
| 设备检索 | 找设备/传感器/终端/设备位置 | find_iot_device_by_description | P2 |
|
||||
| 网络搜索 | 搜索/查找/查询/百度/谷歌 | web_search | P1 |
|
||||
| 人员检索 | 找人/员工/同事/联系方式 | find_employee_by_name | P2 |
|
||||
| 设备检索 | 找设备/传感器/终端 | find_iot_device | P2 |
|
||||
|
||||
## 立即执行机制
|
||||
- **零延迟策略**:识别操作意图后立即执行工具调用,禁止缓冲性语言
|
||||
@ -51,14 +53,15 @@ graph LR
|
||||
### 控制指令映射
|
||||
| 用户语言 | 系统指令 | 参数格式 |
|
||||
|---------|----------|----------|
|
||||
| "打开空调" | update_device_status | {device_id: "001", running_control: 1} |
|
||||
| "调到24度" | update_device_status | {device_id: "001",temp_setting: 24} |
|
||||
| "查看温度" | get_device_status | {device_id: "001"} |
|
||||
| "打开空调" | update_device_status | {sensor_id: "001", running_control: 1} |
|
||||
| "调到24度" | update_device_status | {sensor_id: "001",temp_setting: 24} |
|
||||
| "查看温度" | get_device_status | {sensor_id: "001"} |
|
||||
|
||||
## 位置服务模块
|
||||
### 定位查询协议
|
||||
- **触发条件**:包含位置关键词的查询
|
||||
- **响应格式**:楼层 + 房间/区域(过滤坐标、ID等技术信息)
|
||||
- **精度要求**:室内3米精度,室外10米精度
|
||||
|
||||
## 环境监测模块
|
||||
### 天气服务集成
|
||||
@ -72,6 +75,11 @@ graph LR
|
||||
- **设备检索**:支持设备类型、位置、状态多条件过滤
|
||||
- **结果排序**:按相关度和距离优先级排序
|
||||
|
||||
## 网络搜索模块
|
||||
### Web搜索集成
|
||||
- **自动调用**:识别搜索相关词汇后立即执行
|
||||
- **数据源**:web_search工具,支持实时网络信息检索
|
||||
|
||||
# 智能执行引擎
|
||||
|
||||
## 多阶段处理流水线
|
||||
@ -115,11 +123,20 @@ sequenceDiagram
|
||||
```
|
||||
执行:
|
||||
├── wowtalk_send_message_to_member(to_account="001", message_content="请检查2楼空调")
|
||||
├── find_employee_location(name="张工")
|
||||
├── find_iot_device_by_description(description="2楼空调")
|
||||
├── find_employee_by_name(name="张工")
|
||||
├── find_iot_device(device_type="dc_fan",target_sensor_id="xxxx")
|
||||
└── weather_get_by_location(location="当前位置")
|
||||
```
|
||||
|
||||
**输入**:"搜索最新的节能技术方案,并发送给@李经理(id:002)"
|
||||
|
||||
**执行流程**:
|
||||
```
|
||||
执行:
|
||||
├── web_search(query="最新节能技术方案", max_results=5)
|
||||
└── wowtalk_send_message_to_member(to_account="002", message_content="[搜索结果摘要]")
|
||||
```
|
||||
|
||||
# 应用场景与执行范例
|
||||
|
||||
## 场景1:上下文感知设备控制
|
||||
@ -128,18 +145,19 @@ sequenceDiagram
|
||||
**执行序列**:
|
||||
```python
|
||||
# 步骤1:人员定位
|
||||
find_employee_location(name="清水太郎")
|
||||
# → 返回:employee_id, device_id、位置
|
||||
find_employee_by_name(name="清水太郎")
|
||||
# → 返回:清水太郎的sensor_id
|
||||
|
||||
# 步骤2:设备检索
|
||||
find_iot_device_by_description(
|
||||
description="A栋3楼301风扇"
|
||||
# 步骤2:人员附近的设备检索
|
||||
find_iot_device(
|
||||
device_type="dc_fan",
|
||||
target_sensor_id="{清水太郎的sensor_id}" #
|
||||
)
|
||||
# → 返回:device_list
|
||||
|
||||
# 步骤3:设备控制
|
||||
dxcore_update_device_status(
|
||||
device_id=target_device,
|
||||
sensor_id="{风扇的sensor_id}",
|
||||
running_control=1
|
||||
)
|
||||
```
|
||||
@ -147,39 +165,50 @@ dxcore_update_device_status(
|
||||
**响应模板**:"已为您开启301室的风扇,当前运行正常。"
|
||||
|
||||
## 场景2:智能消息路由
|
||||
**用户请求**:"通知@管理员(id:001)会议室温度过高需要调节"
|
||||
**用户请求**:"通知清水太郎会议室温度过高需要调节"
|
||||
|
||||
**执行逻辑**:
|
||||
```python
|
||||
# 步骤1:人员信息查询
|
||||
find_employee_by_name(name="清水太郎")
|
||||
# 返回:获取wowtalkid和位置信息
|
||||
|
||||
# 步骤2:人员通知
|
||||
wowtalk_send_message_to_member(
|
||||
to_account="001",
|
||||
to_account="{清水太郎wowtalk_id}",
|
||||
message_content="会议室温度过高需要调节"
|
||||
)
|
||||
```
|
||||
|
||||
**响应模板**:"消息已发送至管理员,将会尽快处理温度问题。"
|
||||
**响应模板**:"消息已发送至清水太郎,将会尽快处理温度问题。"
|
||||
|
||||
## 场景3:多维度协同处理
|
||||
**用户请求**:"5楼传感器电量异常,通知维修团队并报告具体位置"
|
||||
**用户请求**:"5楼风扇电量异常,通知清水太郎并报告具体位置"
|
||||
|
||||
**并行执行策略**:
|
||||
```python
|
||||
# 任务组1:故障诊断
|
||||
dxcore_get_device_status(device_id="5楼传感器")
|
||||
# 步骤1:查找设备列表
|
||||
find_iot_device(
|
||||
device_type="dc_fan"
|
||||
)
|
||||
# 返回:获取5楼风扇的sensor_id
|
||||
|
||||
# 步骤2:故障诊断
|
||||
dxcore_get_device_status(sensor_id="{风扇的sensor_id}")
|
||||
# → 获取电量百分比、故障代码
|
||||
|
||||
# 任务组2:人员通知
|
||||
wowtalk_send_message_to_member(
|
||||
to_account="维修部组ID",
|
||||
message_content="5楼传感器电量异常,请及时处理"
|
||||
)
|
||||
# 步骤4:人员信息查询,获取wowtalkid和位置信息
|
||||
find_employee_by_name(name="清水太郎")
|
||||
|
||||
# 任务组3:定位服务
|
||||
find_iot_device_by_description(description="5楼传感器")
|
||||
# 步骤5:人员通知
|
||||
wowtalk_send_message_to_member(
|
||||
to_account="{清水太郎wowtalk_id}",
|
||||
message_content="5楼风扇电量异常,请及时处理"
|
||||
)
|
||||
# → 返回精确定位信息
|
||||
```
|
||||
|
||||
**响应模板**:"已通知维修团队,传感器位于5楼东侧走廊,当前电量15%。"
|
||||
**响应模板**:"已通知清水太郎,风扇位于5楼东侧走廊,当前电量15%。"
|
||||
|
||||
# 系统集成与技术规范
|
||||
|
||||
@ -189,9 +218,11 @@ find_iot_device_by_description(description="5楼传感器")
|
||||
| 消息路由 | wowtalk_send_message_to_member | 实时消息推送 | P0 |
|
||||
| 设备控制 | dxcore_update_device_status | 设备状态变更 | P0 |
|
||||
| 设备查询 | dxcore_get_device_status | 设备状态读取 | P1 |
|
||||
| 位置服务 | eb_get_sensor_location | 空间定位查询 | P1 |
|
||||
| 环境监测 | weather_get_by_location | 天气数据获取 | P1 |
|
||||
| 人员检索 | find_employee_location | 员工信息查询 | P2 |
|
||||
| 设备检索 | find_iot_device_by_description | IoT设备搜索 | P2 |
|
||||
| 网络搜索 | web_search | 互联网信息查询 | P1 |
|
||||
| 人员检索 | find_employee_by_name | 员工信息查询 | P2 |
|
||||
| 设备检索 | find_iot_device | IoT设备搜索 | P2 |
|
||||
|
||||
# 异常处理与容错机制
|
||||
|
||||
@ -264,7 +295,6 @@ find_iot_device_by_description(description="5楼传感器")
|
||||
## 系统配置参数
|
||||
- **bot_id**: {bot_id}
|
||||
|
||||
|
||||
# 执行保证机制
|
||||
1. **工具调用优先**:可执行操作必须通过工具实现
|
||||
2. **状态一致性**:所有操作结果与实际设备状态同步
|
||||
|
||||
@ -51,6 +51,7 @@ class ChatRequest(BaseModel):
|
||||
system_prompt: Optional[str] = None
|
||||
mcp_settings: Optional[List[Dict]] = None
|
||||
robot_type: Optional[str] = "agent"
|
||||
user_identifier: Optional[str] = ""
|
||||
|
||||
|
||||
class ChatRequestV2(BaseModel):
|
||||
@ -59,6 +60,7 @@ class ChatRequestV2(BaseModel):
|
||||
tool_response: Optional[bool] = False
|
||||
bot_id: str
|
||||
language: Optional[str] = "ja"
|
||||
user_identifier: Optional[str] = ""
|
||||
|
||||
|
||||
class FileProcessRequest(BaseModel):
|
||||
|
||||
@ -110,7 +110,8 @@ class FileLoadedAgentManager:
|
||||
language: Optional[str] = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
mcp_settings: Optional[List[Dict]] = None,
|
||||
robot_type: Optional[str] = "agent") -> Assistant:
|
||||
robot_type: Optional[str] = "agent",
|
||||
user_identifier: Optional[str] = None) -> Assistant:
|
||||
"""获取或创建文件预加载的助手实例
|
||||
|
||||
Args:
|
||||
@ -131,7 +132,7 @@ class FileLoadedAgentManager:
|
||||
import os
|
||||
|
||||
# 实现参数优先级逻辑:传入参数 > 项目配置 > 默认配置
|
||||
final_system_prompt = load_system_prompt(project_dir, language, system_prompt, robot_type, bot_id)
|
||||
final_system_prompt = load_system_prompt(project_dir, language, system_prompt, robot_type, bot_id, user_identifier)
|
||||
final_mcp_settings = load_mcp_settings(project_dir, mcp_settings, bot_id, robot_type)
|
||||
|
||||
cache_key = self._get_cache_key(bot_id, model_name, api_key, model_server,
|
||||
|
||||
@ -4,10 +4,38 @@ System prompt and MCP settings loader utilities
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
from typing import List, Dict, Optional
|
||||
from typing import List, Dict, Optional, Any
|
||||
|
||||
|
||||
def load_system_prompt(project_dir: str, language: str = None, system_prompt: str=None, robot_type: str = "agent", bot_id: str="") -> str:
|
||||
def safe_replace(text: str, placeholder: str, value: Any) -> str:
|
||||
"""
|
||||
安全的字符串替换函数,确保 value 被转换为字符串
|
||||
|
||||
Args:
|
||||
text: 原始文本
|
||||
placeholder: 要替换的占位符(如 '{user_identifier}')
|
||||
value: 用于替换的值(可以是任意类型)
|
||||
|
||||
Returns:
|
||||
str: 替换后的文本
|
||||
"""
|
||||
if not isinstance(text, str):
|
||||
text = str(text)
|
||||
|
||||
# 如果占位符为空,不进行替换
|
||||
if not placeholder:
|
||||
return text
|
||||
|
||||
# 将 value 转换为字符串,处理 None 等特殊情况
|
||||
if value is None:
|
||||
replacement = ""
|
||||
else:
|
||||
replacement = str(value)
|
||||
|
||||
return text.replace(placeholder, replacement)
|
||||
|
||||
|
||||
def load_system_prompt(project_dir: str, language: str = None, system_prompt: str=None, robot_type: str = "agent", bot_id: str="", user_identifier: str = "") -> str:
|
||||
# 获取语言显示名称
|
||||
language_display_map = {
|
||||
'zh': '中文',
|
||||
@ -19,7 +47,11 @@ def load_system_prompt(project_dir: str, language: str = None, system_prompt: st
|
||||
|
||||
# 如果存在{language} 占位符,那么就直接使用 system_prompt
|
||||
if system_prompt and "{language}" in system_prompt:
|
||||
return system_prompt.replace("{language}", language_display).replace('{bot_id}', bot_id) or ""
|
||||
prompt = system_prompt
|
||||
prompt = safe_replace(prompt, "{language}", language_display)
|
||||
prompt = safe_replace(prompt, '{bot_id}', bot_id)
|
||||
prompt = safe_replace(prompt, '{user_identifier}', user_identifier)
|
||||
return prompt or ""
|
||||
elif robot_type == "agent" or robot_type == "catalog_agent":
|
||||
"""
|
||||
优先使用项目目录的system_prompt_catalog_agent.md,没有才使用默认的system_prompt_default.md
|
||||
@ -51,11 +83,20 @@ def load_system_prompt(project_dir: str, language: str = None, system_prompt: st
|
||||
if os.path.exists(readme_path):
|
||||
with open(readme_path, "r", encoding="utf-8") as f:
|
||||
readme = f.read().strip()
|
||||
system_prompt_default = system_prompt_default.replace("{readme}", str(readme))
|
||||
system_prompt_default = safe_replace(system_prompt_default, "{readme}", str(readme))
|
||||
|
||||
return system_prompt_default.replace("{language}", language_display).replace("{extra_prompt}", system_prompt or "").replace('{bot_id}', bot_id) or ""
|
||||
prompt = system_prompt_default
|
||||
prompt = safe_replace(prompt, "{language}", language_display)
|
||||
prompt = safe_replace(prompt, "{extra_prompt}", system_prompt or "")
|
||||
prompt = safe_replace(prompt, '{bot_id}', bot_id)
|
||||
prompt = safe_replace(prompt, '{user_identifier}', user_identifier)
|
||||
return prompt or ""
|
||||
else:
|
||||
return system_prompt.replace("{language}", language_display).replace('{bot_id}', bot_id) or ""
|
||||
prompt = system_prompt
|
||||
prompt = safe_replace(prompt, "{language}", language_display)
|
||||
prompt = safe_replace(prompt, '{bot_id}', bot_id)
|
||||
prompt = safe_replace(prompt, '{user_identifier}', user_identifier)
|
||||
return prompt or ""
|
||||
|
||||
|
||||
|
||||
@ -72,15 +113,16 @@ def replace_mcp_placeholders(mcp_settings: List[Dict], dataset_dir: str, bot_id:
|
||||
for key, value in obj.items():
|
||||
if key == 'args' and isinstance(value, list):
|
||||
# 特别处理 args 列表
|
||||
obj[key] = [item.replace('{dataset_dir}', dataset_dir).replace('{bot_id}', bot_id) if isinstance(item, str) else item
|
||||
obj[key] = [safe_replace(safe_replace(item, '{dataset_dir}', dataset_dir), '{bot_id}', bot_id) if isinstance(item, str) else item
|
||||
for item in value]
|
||||
elif isinstance(value, (dict, list)):
|
||||
obj[key] = replace_placeholders_in_obj(value)
|
||||
elif isinstance(value, str):
|
||||
obj[key] = value.replace('{dataset_dir}', dataset_dir).replace('{bot_id}', bot_id)
|
||||
obj[key] = safe_replace(value, '{dataset_dir}', dataset_dir)
|
||||
obj[key] = safe_replace(obj[key], '{bot_id}', bot_id)
|
||||
elif isinstance(obj, list):
|
||||
return [replace_placeholders_in_obj(item) if isinstance(item, (dict, list)) else
|
||||
item.replace('{dataset_dir}', dataset_dir).replace('{bot_id}', bot_id) if isinstance(item, str) else item
|
||||
safe_replace(safe_replace(item, '{dataset_dir}', dataset_dir), '{bot_id}', bot_id) if isinstance(item, str) else item
|
||||
for item in obj]
|
||||
return obj
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user