Add MCP Server & function call support fixed #6
This commit is contained in:
parent
f3f3efb862
commit
5350860f78
@ -6,10 +6,9 @@ DIFY_API_KEYS=app-xxxxxxxxxxxxxxxx,app-yyyyyyyyyyyyyyyy,app-zzzzzzzzzzzzzzzz
|
||||
DIFY_API_BASE="https://api.dify.example.com/v1"
|
||||
|
||||
# 会话记忆功能模式
|
||||
# 0: 不开启会话记忆
|
||||
# 1: 构造history_message附加到消息中的模式
|
||||
# 2: 当前的零宽字符模式(默认)
|
||||
CONVERSATION_MEMORY_MODE=2
|
||||
# 1: 构造history_message附加到消息中的模式(默认)
|
||||
# 2: 当前的零宽字符模式
|
||||
CONVERSATION_MEMORY_MODE=1
|
||||
|
||||
# Server Configuration
|
||||
SERVER_HOST="127.0.0.1"
|
||||
|
||||
35
README.md
35
README.md
@ -12,6 +12,7 @@ OpenDify 是一个将 Dify API 转换为 OpenAI API 格式的代理服务器。
|
||||
- 支持流式输出(Streaming)
|
||||
- 智能动态延迟控制,提供流畅的输出体验
|
||||
- 支持多种会话记忆模式,包括零宽字符模式和history_message模式
|
||||
- 支持 OpenAI Function Call 和 MCP Server 功能
|
||||
- 支持多个模型配置
|
||||
- 支持Dify Agent应用,处理高级工具调用(如生成图片等)
|
||||
- 兼容标准的 OpenAI API 客户端
|
||||
@ -19,35 +20,49 @@ OpenDify 是一个将 Dify API 转换为 OpenAI API 格式的代理服务器。
|
||||
|
||||
## 效果展示
|
||||
|
||||
### Function Call 和 MCP Server 支持
|
||||
|
||||
新增对 OpenAI Function Call 和 MCP Server 的支持,即使 Dify 不支持直接设置系统提示词:
|
||||
|
||||
- 自动检测请求中的 `system` 角色消息
|
||||
- 智能将系统提示词插入到用户查询中
|
||||
- 防止重复插入系统提示词
|
||||
- 完美兼容 OpenAI 的 Function Call 格式
|
||||
|
||||

|
||||
|
||||
*上图展示了 OpenDify 对 Function Call 的支持。即使 Dify 应用不支持直接设置系统提示词,通过 OpenDify 的转换,也能正确处理 MCP Server 及 Function Call 的需求。*
|
||||
|
||||
### Dify Agent应用支持
|
||||
|
||||

|
||||
|
||||
*截图展示了OpenDify代理服务支持的Dify Agent应用界面,可以看到Agent成功地处理了用户的Python多线程用法请求,并返回了相关代码示例。*
|
||||
|
||||
### 会话记忆功能
|
||||
|
||||

|
||||
|
||||
*上图展示了OpenDify的会话记忆功能。当用户提问"今天是什么天气?"时,AI能够记住之前对话中提到"今天是晴天"的上下文信息,并给出相应回复。*
|
||||
|
||||
## 特性
|
||||
|
||||
### 会话记忆功能
|
||||
|
||||
该代理支持自动记忆会话上下文,无需客户端进行额外处理。提供了三种会话记忆模式:
|
||||
该代理支持自动记忆会话上下文,无需客户端进行额外处理。提供了两种会话记忆模式:
|
||||
|
||||
1. **不开启会话记忆**:每次对话都是独立的,无上下文关联
|
||||
2. **history_message模式**:将历史消息直接附加到当前消息中,支持客户端编辑历史消息
|
||||
3. **零宽字符模式**:在每个新会话的第一条回复中,会自动嵌入不可见的会话ID,后续消息自动继承上下文
|
||||
1. **history_message模式**:将历史消息直接附加到当前消息中,支持客户端编辑历史消息(默认)
|
||||
2. **零宽字符模式**:在每个新会话的第一条回复中,会自动嵌入不可见的会话ID,后续消息自动继承上下文
|
||||
|
||||
可以通过环境变量控制此功能:
|
||||
|
||||
```shell
|
||||
# 在 .env 文件中设置会话记忆模式
|
||||
# 0: 不开启会话记忆
|
||||
# 1: 构造history_message附加到消息中的模式
|
||||
# 2: 当前的零宽字符模式(默认)
|
||||
CONVERSATION_MEMORY_MODE=2
|
||||
# 1: 构造history_message附加到消息中的模式(默认)
|
||||
# 2: 零宽字符模式
|
||||
CONVERSATION_MEMORY_MODE=1
|
||||
```
|
||||
|
||||
默认情况下使用零宽字符模式。对于需要支持客户端编辑历史消息的场景,推荐使用history_message模式。
|
||||
默认情况下使用history_message模式,这种模式更灵活,支持客户端编辑历史消息,并能更好地处理系统提示词。
|
||||
|
||||
> 注意:history_message模式会将所有历史消息追加到当前消息中,可能会消耗更多的token。
|
||||
|
||||
|
||||
22
README_EN.md
22
README_EN.md
@ -12,23 +12,43 @@ OpenDify is a proxy server that transforms the Dify API into OpenAI API format.
|
||||
- Streaming output support
|
||||
- Intelligent dynamic delay control for smooth output experience
|
||||
- Multiple conversation memory modes, including zero-width character mode and history_message mode
|
||||
- Support for OpenAI Function Call and MCP Server functionality
|
||||
- Support for multiple model configurations
|
||||
- Support for Dify Agent applications with advanced tool calls (like image generation)
|
||||
- Compatible with standard OpenAI API clients
|
||||
- Automatic fetching of Dify application information
|
||||
|
||||
## Screenshot
|
||||
## Screenshots
|
||||
|
||||
### Function Call and MCP Server Support
|
||||
|
||||

|
||||
|
||||
*The above image demonstrates OpenDify's support for Function Call. Even though Dify applications don't support setting system prompts directly, through OpenDify's conversion, it can correctly handle MCP Server and Function Call requirements.*
|
||||
|
||||
### Dify Agent Application Support
|
||||
|
||||

|
||||
|
||||
*The screenshot shows the Dify Agent application interface supported by the OpenDify proxy service. It demonstrates how the Agent successfully processes a user's request about Python multithreading usage and returns relevant code examples.*
|
||||
|
||||
### Conversation Memory Feature
|
||||
|
||||

|
||||
|
||||
*The above image demonstrates the conversation memory feature of OpenDify. When the user asks "What's the weather today?", the AI remembers the context from previous conversations that "today is sunny" and provides an appropriate response.*
|
||||
|
||||
## Detailed Features
|
||||
|
||||
### Function Call and MCP Server Support
|
||||
|
||||
Added support for OpenAI Function Call and MCP Server, even though Dify doesn't support setting system prompts directly:
|
||||
|
||||
- Automatically detects `system` role messages in requests
|
||||
- Intelligently inserts system prompts into user queries
|
||||
- Prevents duplicate insertion of system prompts
|
||||
- Perfectly compatible with OpenAI Function Call format
|
||||
|
||||
### Conversation Memory
|
||||
|
||||
The proxy supports automatic remembering of conversation context without requiring additional processing by the client. It provides three conversation memory modes:
|
||||
|
||||
BIN
images/3.png
Normal file
BIN
images/3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 285 KiB |
79
main.py
79
main.py
@ -25,10 +25,9 @@ load_dotenv()
|
||||
VALID_API_KEYS = [key.strip() for key in os.getenv("VALID_API_KEYS", "").split(",") if key]
|
||||
|
||||
# 获取会话记忆功能模式配置
|
||||
# 0: 不开启会话记忆
|
||||
# 1: 构造history_message附加到消息中的模式
|
||||
# 2: 当前的零宽字符模式(默认)
|
||||
CONVERSATION_MEMORY_MODE = int(os.getenv('CONVERSATION_MEMORY_MODE', '2'))
|
||||
# 1: 构造history_message附加到消息中的模式(默认)
|
||||
# 2: 零宽字符模式
|
||||
CONVERSATION_MEMORY_MODE = int(os.getenv('CONVERSATION_MEMORY_MODE', '1'))
|
||||
|
||||
class DifyModelManager:
|
||||
def __init__(self):
|
||||
@ -121,6 +120,14 @@ def transform_openai_to_dify(openai_request, endpoint):
|
||||
# 尝试从历史消息中提取conversation_id
|
||||
conversation_id = None
|
||||
|
||||
# 提取system消息内容
|
||||
system_content = ""
|
||||
system_messages = [msg for msg in messages if msg.get("role") == "system"]
|
||||
if system_messages:
|
||||
system_content = system_messages[0].get("content", "")
|
||||
# 记录找到的system消息
|
||||
logger.info(f"Found system message: {system_content[:100]}{'...' if len(system_content) > 100 else ''}")
|
||||
|
||||
if CONVERSATION_MEMORY_MODE == 2: # 零宽字符模式
|
||||
if len(messages) > 1:
|
||||
# 遍历历史消息,找到最近的assistant消息
|
||||
@ -132,41 +139,55 @@ def transform_openai_to_dify(openai_request, endpoint):
|
||||
if conversation_id:
|
||||
break
|
||||
|
||||
dify_request = {
|
||||
"inputs": {},
|
||||
"query": messages[-1]["content"] if messages else "",
|
||||
"response_mode": "streaming" if stream else "blocking",
|
||||
"conversation_id": conversation_id,
|
||||
"user": openai_request.get("user", "default_user")
|
||||
}
|
||||
elif CONVERSATION_MEMORY_MODE == 1: # history_message模式
|
||||
# 使用history_messages直接作为上下文
|
||||
user_query = messages[-1]["content"] if messages else ""
|
||||
# 获取最后一条用户消息
|
||||
user_query = messages[-1]["content"] if messages and messages[-1].get("role") != "system" else ""
|
||||
|
||||
if len(messages) > 1:
|
||||
# 构造历史消息
|
||||
history_messages = []
|
||||
for msg in messages[:-1]: # 除了最后一条消息
|
||||
role = msg.get("role", "")
|
||||
content = msg.get("content", "")
|
||||
if role and content:
|
||||
history_messages.append(f"{role}: {content}")
|
||||
|
||||
# 将历史消息添加到查询中
|
||||
if history_messages:
|
||||
history_context = "\n\n".join(history_messages)
|
||||
user_query = f"<history>\n{history_context}\n</history>\n\n用户当前问题: {user_query}"
|
||||
# 如果有system消息且是首次对话(没有conversation_id),则将system内容添加到用户查询前
|
||||
if system_content and not conversation_id:
|
||||
user_query = f"系统指令: {system_content}\n\n用户问题: {user_query}"
|
||||
logger.info(f"[零宽字符模式] 首次对话,添加system内容到查询前")
|
||||
|
||||
dify_request = {
|
||||
"inputs": {},
|
||||
"query": user_query,
|
||||
"response_mode": "streaming" if stream else "blocking",
|
||||
"conversation_id": conversation_id,
|
||||
"user": openai_request.get("user", "default_user")
|
||||
}
|
||||
else: # 不开启会话记忆
|
||||
else: # history_message模式(默认)
|
||||
# 获取最后一条用户消息
|
||||
user_query = messages[-1]["content"] if messages and messages[-1].get("role") != "system" else ""
|
||||
|
||||
# 构造历史消息
|
||||
if len(messages) > 1:
|
||||
history_messages = []
|
||||
has_system_in_history = False
|
||||
|
||||
# 检查历史消息中是否已经包含system消息
|
||||
for msg in messages[:-1]: # 除了最后一条消息
|
||||
role = msg.get("role", "")
|
||||
content = msg.get("content", "")
|
||||
if role and content:
|
||||
if role == "system":
|
||||
has_system_in_history = True
|
||||
history_messages.append(f"{role}: {content}")
|
||||
|
||||
# 如果历史中没有system消息但现在有system消息,则添加到历史的最前面
|
||||
if system_content and not has_system_in_history:
|
||||
history_messages.insert(0, f"system: {system_content}")
|
||||
logger.info(f"[history_message模式] 添加system内容到历史消息前")
|
||||
|
||||
# 将历史消息添加到查询中
|
||||
if history_messages:
|
||||
history_context = "\n\n".join(history_messages)
|
||||
user_query = f"<history>\n{history_context}\n</history>\n\n用户当前问题: {user_query}"
|
||||
elif system_content: # 没有历史消息但有system消息
|
||||
user_query = f"系统指令: {system_content}\n\n用户问题: {user_query}"
|
||||
logger.info(f"[history_message模式] 首次对话,添加system内容到查询前")
|
||||
|
||||
dify_request = {
|
||||
"inputs": {},
|
||||
"query": messages[-1]["content"] if messages else "",
|
||||
"query": user_query,
|
||||
"response_mode": "streaming" if stream else "blocking",
|
||||
"user": openai_request.get("user", "default_user")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user