fix: 修复硅基流动接口与 langchain stream event v3 不兼容的问题
This commit is contained in:
parent
7f387fd6e7
commit
e37bd7c808
@ -6,6 +6,10 @@ from yuxi.utils import get_docker_safe_url
|
|||||||
from yuxi.utils.logging_config import logger
|
from yuxi.utils.logging_config import logger
|
||||||
|
|
||||||
|
|
||||||
|
def _requires_non_streaming_tool_calls(provider_id: str, model_id: str) -> bool:
|
||||||
|
return provider_id.startswith("siliconflow")
|
||||||
|
|
||||||
|
|
||||||
def load_chat_model(fully_specified_name: str, **kwargs) -> BaseChatModel:
|
def load_chat_model(fully_specified_name: str, **kwargs) -> BaseChatModel:
|
||||||
if not fully_specified_name:
|
if not fully_specified_name:
|
||||||
raise ValueError("model spec 不能为空")
|
raise ValueError("model spec 不能为空")
|
||||||
@ -47,10 +51,14 @@ def load_chat_model(fully_specified_name: str, **kwargs) -> BaseChatModel:
|
|||||||
|
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
|
|
||||||
|
openai_kwargs = dict(kwargs)
|
||||||
|
if _requires_non_streaming_tool_calls(info.provider_id, info.model_id):
|
||||||
|
openai_kwargs.setdefault("disable_streaming", "tool_calling")
|
||||||
|
|
||||||
return ChatOpenAI(
|
return ChatOpenAI(
|
||||||
model=info.model_id,
|
model=info.model_id,
|
||||||
api_key=SecretStr(api_key),
|
api_key=SecretStr(api_key),
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
stream_usage=True,
|
stream_usage=True,
|
||||||
**kwargs,
|
**openai_kwargs,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -24,12 +24,6 @@ BUILTIN_PROVIDERS: list[dict[str, Any]] = [
|
|||||||
# "api_key_env": "GEMINI_API_KEY",
|
# "api_key_env": "GEMINI_API_KEY",
|
||||||
# "models_endpoint": "https://generativelanguage.googleapis.com/v1beta/models",
|
# "models_endpoint": "https://generativelanguage.googleapis.com/v1beta/models",
|
||||||
# },
|
# },
|
||||||
# {
|
|
||||||
# "provider_id": "lmstudio",
|
|
||||||
# "display_name": "LM Studio",
|
|
||||||
# "base_url": "http://localhost:1234/v1",
|
|
||||||
# "models_endpoint": "http://localhost:1234/v1/models",
|
|
||||||
# },
|
|
||||||
{
|
{
|
||||||
"provider_id": "deepseek",
|
"provider_id": "deepseek",
|
||||||
"display_name": "DeepSeek",
|
"display_name": "DeepSeek",
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class ModelInfo:
|
|||||||
# 运行时配置
|
# 运行时配置
|
||||||
api_key: str
|
api_key: str
|
||||||
base_url: str
|
base_url: str
|
||||||
provider_type: str # openai / anthropic / gemini / openrouter / lmstudio
|
provider_type: str # openai / anthropic / gemini / openrouter
|
||||||
|
|
||||||
# 可选配置
|
# 可选配置
|
||||||
headers: dict[str, str] = field(default_factory=dict)
|
headers: dict[str, str] = field(default_factory=dict)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ from yuxi.storage.postgres.models_business import ModelProvider
|
|||||||
|
|
||||||
VALID_MODEL_TYPES = {"chat", "embedding", "rerank"}
|
VALID_MODEL_TYPES = {"chat", "embedding", "rerank"}
|
||||||
VALID_MODEL_SOURCES = {"manual", "remote"}
|
VALID_MODEL_SOURCES = {"manual", "remote"}
|
||||||
VALID_PROVIDER_TYPES = {"openai", "anthropic", "gemini", "openrouter", "lmstudio"}
|
VALID_PROVIDER_TYPES = {"openai", "anthropic", "gemini", "openrouter"}
|
||||||
_PROVIDER_ID_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_-]{1,99}$")
|
_PROVIDER_ID_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_-]{1,99}$")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -231,7 +231,7 @@ def _message_chunk_yuxi_events(
|
|||||||
"type": "tool_call_delta",
|
"type": "tool_call_delta",
|
||||||
"message_id": message_id,
|
"message_id": message_id,
|
||||||
"tool_call_id": tool_call_chunk.get("id"),
|
"tool_call_id": tool_call_chunk.get("id"),
|
||||||
"name": tool_call_chunk.get("name"),
|
"name": tool_call_chunk.get("name") or None,
|
||||||
"args_delta": args_delta,
|
"args_delta": args_delta,
|
||||||
"index": tool_call_chunk.get("index") if tool_call_chunk.get("index") is not None else 0,
|
"index": tool_call_chunk.get("index") if tool_call_chunk.get("index") is not None else 0,
|
||||||
**route,
|
**route,
|
||||||
@ -377,7 +377,7 @@ async def _save_ai_message(
|
|||||||
for tc in tool_calls_data:
|
for tc in tool_calls_data:
|
||||||
await conv_repo.add_tool_call(
|
await conv_repo.add_tool_call(
|
||||||
message_id=ai_msg.id,
|
message_id=ai_msg.id,
|
||||||
tool_name=tc.get("name", "unknown"),
|
tool_name=tc.get("name") or "unknown",
|
||||||
tool_input=tc.get("args", {}),
|
tool_input=tc.get("args", {}),
|
||||||
status="pending",
|
status="pending",
|
||||||
langgraph_tool_call_id=tc.get("id"),
|
langgraph_tool_call_id=tc.get("id"),
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
- 优化智能体对话页细节:状态面板隐藏空 section,待办名称限制为 20 个中文汉字以内,模型选择器展示供应商名称,并收紧附件状态标签与文件编辑浮动操作样式。
|
- 优化智能体对话页细节:状态面板隐藏空 section,待办名称限制为 20 个中文汉字以内,模型选择器展示供应商名称,并收紧附件状态标签与文件编辑浮动操作样式。
|
||||||
- 标准化 Agent run/SSE 执行链路:run 创建时持久化输入消息并提交后入队,worker 统一写入 Redis Stream envelope,SSE 输出 `event/data/id`、心跳注释、`Last-Event-ID` 回放和终止 `end` 事件;前端强制使用 run API 并支持 ask_user_question 中断后以 resume run 恢复;事件 envelope 构造收敛到统一 helper,前端优先使用 envelope 一级 `thread_id` 路由。
|
- 标准化 Agent run/SSE 执行链路:run 创建时持久化输入消息并提交后入队,worker 统一写入 Redis Stream envelope,SSE 输出 `event/data/id`、心跳注释、`Last-Event-ID` 回放和终止 `end` 事件;前端强制使用 run API 并支持 ask_user_question 中断后以 resume run 恢复;事件 envelope 构造收敛到统一 helper,前端优先使用 envelope 一级 `thread_id` 路由。
|
||||||
- Agent run SSE 新增 `verbose=false` 精简模式:默认仍返回完整事件载荷;精简模式仅在 SSE 输出前重建最小 payload,跳过 `metadata` 和空 `yuxi.agent_state`,将同一 data 内的 `request_id` 外提为单个字段,移除 chunk 中重复的 `meta`、`metadata`、`thread_id`、`response`、空 `namespace` 和图片 base64 等调试字段,保留消息增量、工具调用、工具结果、非空 Agent state、终止状态和 SSE 游标,前端订阅默认使用精简模式。
|
- Agent run SSE 新增 `verbose=false` 精简模式:默认仍返回完整事件载荷;精简模式仅在 SSE 输出前重建最小 payload,跳过 `metadata` 和空 `yuxi.agent_state`,将同一 data 内的 `request_id` 外提为单个字段,移除 chunk 中重复的 `meta`、`metadata`、`thread_id`、`response`、空 `namespace` 和图片 base64 等调试字段,保留消息增量、工具调用、工具结果、非空 Agent state、终止状态和 SSE 游标,前端订阅默认使用精简模式。
|
||||||
|
- 修复 SiliconFlow MiniMax 工具调用流式兼容:MiniMax 在 OpenAI 兼容流中会在参数增量 chunk 返回空 `function.name`,LangGraph v3 event stream 会将空名称写入最终工具调用并导致工具执行失败;该模型默认对工具调用禁用流式模型响应,保留 LangGraph v3 运行事件并避免 agent-chat 中出现空工具名。
|
||||||
- 收敛后端模块边界:文档解析从 `plugins.parser` 移动到 `knowledge.parser`,内容审查从 `plugins.guard` 移动到 `services.guard`。
|
- 收敛后端模块边界:文档解析从 `plugins.parser` 移动到 `knowledge.parser`,内容审查从 `plugins.guard` 移动到 `services.guard`。
|
||||||
- 收敛文件服务边界:文件预览判断抽为独立服务,Viewer 文件系统的 workspace 分支复用用户 workspace 服务,线程运行时上下文解析从泛化 `filesystem_service` 拆出为 agent runtime helper。
|
- 收敛文件服务边界:文件预览判断抽为独立服务,Viewer 文件系统的 workspace 分支复用用户 workspace 服务,线程运行时上下文解析从泛化 `filesystem_service` 拆出为 agent runtime helper。
|
||||||
- 升级 DeepAgents 到 0.6.7 并适配新版文件系统协议:SubAgentMiddleware 改为显式 subagent spec,Skills prompt 补齐新版占位符;sandbox/skills backend 复用新版 `ReadResult`、`GlobResult`、`GrepResult` 等协议类型,文件权限在 backend 层明确区分 skills、uploads、outputs 与 workspace,保留最小 `CustomCompositeBackend` 以避免非 route glob 误扫其他 route;Agent 上下文压缩改为复用 DeepAgents SummarizationMiddleware,历史摘要与大工具结果统一 offload 到 outputs。
|
- 升级 DeepAgents 到 0.6.7 并适配新版文件系统协议:SubAgentMiddleware 改为显式 subagent spec,Skills prompt 补齐新版占位符;sandbox/skills backend 复用新版 `ReadResult`、`GlobResult`、`GrepResult` 等协议类型,文件权限在 backend 层明确区分 skills、uploads、outputs 与 workspace,保留最小 `CustomCompositeBackend` 以避免非 route glob 误扫其他 route;Agent 上下文压缩改为复用 DeepAgents SummarizationMiddleware,历史摘要与大工具结果统一 offload 到 outputs。
|
||||||
|
|||||||
@ -17,29 +17,33 @@
|
|||||||
|
|
||||||
|
|
||||||
**智能体**
|
**智能体**
|
||||||
- [ ] 子智能体缺少异步的机制
|
- [ ] 子智能体缺少异步的机制 <Badge text="v0.7.1" />
|
||||||
- [ ] 子智能体缺少 steer 机制
|
- [ ] 子智能体缺少 steer 机制 <Badge text="v0.7.1" />
|
||||||
- [ ] 子智能体的双向通信,缺少 ask_for_main_agent 的机制
|
- [ ] 子智能体的双向通信,缺少 ask_for_main_agent 的机制 <Badge text="v0.7.1" />
|
||||||
- [ ] 子智能体与子智能体的通信机制
|
- [ ] 子智能体与子智能体的通信机制
|
||||||
- [ ] 如何停掉一个子智能体、查看智能体的进度
|
- [ ] 如何停掉一个子智能体、查看智能体的进度
|
||||||
- [ ] RAG 评估支持 Agent 模式
|
- [ ] RAG 评估支持 Agent 模式
|
||||||
- [ ] 添加 Agent 独立调用接口,方便后续评估使用
|
- [ ] 添加 Agent 独立调用接口,方便后续评估使用
|
||||||
|
- [ ] 任务队列 <Badge text="v0.7.2" />
|
||||||
|
|
||||||
|
**并发与分布式**
|
||||||
|
- [ ] 提高 FastAPI 的并发能力
|
||||||
|
|
||||||
**其他**
|
**其他**
|
||||||
- [ ] 历史对话新增分组(或者叫做项目)
|
- [ ] 历史对话新增分组(或者叫做项目)
|
||||||
- [ ] 集成 Memory,基于 deepagents 的文件后端实现,需要考虑定位
|
- [ ] 集成 Memory,基于 deepagents 的文件后端实现,需要考虑定位
|
||||||
|
- [ ] 模型供应商类型继续补齐非 OpenAI 兼容适配,并清理不再支持的 provider type 字样 <Badge text="v0.7.1" />
|
||||||
|
|
||||||
**仅设想**
|
**仅设想**
|
||||||
- [ ] Yuxi-cli 相关的功能,放在后续版本中实现(不是类似于编程助手,而是管理平台的工,等各个 router 接口优化之后)
|
- [ ] Yuxi-cli 相关的功能,放在后续版本中实现(不是类似于编程助手,而是管理平台的工,等各个 router 接口优化之后)
|
||||||
|
- [ ] Yuxi-cli 支持 `yuxi upload <DIR_NAME>`,将本地文件夹上传到系统中
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
- [ ] 目前的知识库的图片存在公开访问风险
|
- [ ] 目前的知识库的图片存在公开访问风险
|
||||||
- [ ] 点开对话的时候要能够自动定位到尾部,而不是最开始。
|
- [ ] 点开对话的时候要能够自动定位到尾部,而不是最开始。
|
||||||
- [ ] HTML 渲染侧边模式底部有部分无法渲染,全屏情况下下面有白边
|
- [ ] HTML 渲染侧边模式底部有部分无法渲染,全屏情况下下面有白边
|
||||||
|
- [ ] Summary 无法正常触发
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -741,10 +741,9 @@ defineExpose({
|
|||||||
<span>Provider Type</span>
|
<span>Provider Type</span>
|
||||||
<a-select v-model:value="providerForm.provider_type">
|
<a-select v-model:value="providerForm.provider_type">
|
||||||
<a-select-option value="openai">openai</a-select-option>
|
<a-select-option value="openai">openai</a-select-option>
|
||||||
<a-select-option value="anthropic">anthropic</a-select-option>
|
<!-- <a-select-option value="anthropic">anthropic</a-select-option>
|
||||||
<a-select-option value="gemini">gemini</a-select-option>
|
<a-select-option value="gemini">gemini</a-select-option>
|
||||||
<a-select-option value="openrouter">openrouter</a-select-option>
|
<a-select-option value="openrouter">openrouter</a-select-option> -->
|
||||||
<a-select-option value="lmstudio">lmstudio</a-select-option>
|
|
||||||
</a-select>
|
</a-select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -10,7 +10,6 @@ export const modelIcons = {
|
|||||||
dashscope: `${ICON_BASE}/bailian-color.svg`,
|
dashscope: `${ICON_BASE}/bailian-color.svg`,
|
||||||
deepseek: `${ICON_BASE}/deepseek-color.svg`,
|
deepseek: `${ICON_BASE}/deepseek-color.svg`,
|
||||||
google: `${ICON_BASE}/google-color.svg`,
|
google: `${ICON_BASE}/google-color.svg`,
|
||||||
lmstudio: `${ICON_BASE}/lmstudio.svg`,
|
|
||||||
minimax: `${ICON_BASE}/minimax-color.svg`,
|
minimax: `${ICON_BASE}/minimax-color.svg`,
|
||||||
'minimax-cn': `${ICON_BASE}/minimax-color.svg`,
|
'minimax-cn': `${ICON_BASE}/minimax-color.svg`,
|
||||||
modelscope: `${ICON_BASE}/modelscope-color.svg`,
|
modelscope: `${ICON_BASE}/modelscope-color.svg`,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user