feat: 完成agent功能
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
||||||
|
|
||||||
|
public class AgentToolOutput
|
||||||
|
{
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
|||||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
||||||
using Yi.Framework.AiHub.Domain;
|
using Yi.Framework.AiHub.Domain;
|
||||||
using Yi.Framework.AiHub.Domain.Entities;
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||||
using Yi.Framework.AiHub.Domain.Extensions;
|
using Yi.Framework.AiHub.Domain.Extensions;
|
||||||
using Yi.Framework.AiHub.Domain.Managers;
|
using Yi.Framework.AiHub.Domain.Managers;
|
||||||
@@ -47,13 +48,16 @@ public class AiChatService : ApplicationService
|
|||||||
private readonly ChatManager _chatManager;
|
private readonly ChatManager _chatManager;
|
||||||
private readonly TokenManager _tokenManager;
|
private readonly TokenManager _tokenManager;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
|
private readonly ISqlSugarRepository<AgentStoreAggregateRoot> _agentStoreRepository;
|
||||||
|
|
||||||
public AiChatService(IHttpContextAccessor httpContextAccessor,
|
public AiChatService(IHttpContextAccessor httpContextAccessor,
|
||||||
AiBlacklistManager aiBlacklistManager,
|
AiBlacklistManager aiBlacklistManager,
|
||||||
ISqlSugarRepository<AiModelEntity> aiModelRepository,
|
ISqlSugarRepository<AiModelEntity> aiModelRepository,
|
||||||
ILogger<AiChatService> logger,
|
ILogger<AiChatService> logger,
|
||||||
AiGateWayManager aiGateWayManager,
|
AiGateWayManager aiGateWayManager,
|
||||||
PremiumPackageManager premiumPackageManager,
|
PremiumPackageManager premiumPackageManager,
|
||||||
ChatManager chatManager, TokenManager tokenManager, IAccountService accountService)
|
ChatManager chatManager, TokenManager tokenManager, IAccountService accountService,
|
||||||
|
ISqlSugarRepository<AgentStoreAggregateRoot> agentStoreRepository)
|
||||||
{
|
{
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_aiBlacklistManager = aiBlacklistManager;
|
_aiBlacklistManager = aiBlacklistManager;
|
||||||
@@ -64,6 +68,7 @@ public class AiChatService : ApplicationService
|
|||||||
_chatManager = chatManager;
|
_chatManager = chatManager;
|
||||||
_tokenManager = tokenManager;
|
_tokenManager = tokenManager;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
|
_agentStoreRepository = agentStoreRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -154,50 +159,6 @@ public class AiChatService : ApplicationService
|
|||||||
CurrentUser.Id, sessionId, null, cancellationToken);
|
CurrentUser.Id, sessionId, null, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Agent 发送消息
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("ai-chat/agent/send")]
|
|
||||||
public async Task PostAgentSendAsync([FromBody] AgentSendInput input, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var tokenValidation = await _tokenManager.ValidateTokenAsync(input.Token, input.ModelId);
|
|
||||||
|
|
||||||
await _aiBlacklistManager.VerifiyAiBlacklist(tokenValidation.UserId);
|
|
||||||
// 验证用户是否为VIP
|
|
||||||
var userInfo = await _accountService.GetAsync(null, null, tokenValidation.UserId);
|
|
||||||
if (userInfo == null)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException("用户信息不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否为VIP(使用RoleCodes判断)
|
|
||||||
if (!userInfo.RoleCodes.Contains(AiHubConst.VipRole) && userInfo.User.UserName != "cc")
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException("该接口为尊享服务专用,需要VIP权限才能使用");
|
|
||||||
}
|
|
||||||
|
|
||||||
//如果是尊享包服务,需要校验是是否尊享包足够
|
|
||||||
if (PremiumPackageConst.ModeIds.Contains(input.ModelId))
|
|
||||||
{
|
|
||||||
// 检查尊享token包用量
|
|
||||||
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(tokenValidation.UserId);
|
|
||||||
if (availableTokens <= 0)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await _chatManager.AgentCompleteChatStreamAsync(_httpContextAccessor.HttpContext,
|
|
||||||
input.SessionId,
|
|
||||||
input.Content,
|
|
||||||
input.Token,
|
|
||||||
tokenValidation.TokenId,
|
|
||||||
input.ModelId,
|
|
||||||
tokenValidation.UserId,
|
|
||||||
input.Tools,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送消息
|
/// 发送消息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -234,27 +195,75 @@ public class AiChatService : ApplicationService
|
|||||||
CurrentUser.Id, null, null, cancellationToken);
|
CurrentUser.Id, null, null, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("ai-chat/tool")]
|
|
||||||
public string GetTool()
|
|
||||||
{
|
|
||||||
var toolClasses = typeof(YiFrameworkAiHubDomainModule).Assembly.GetTypes()
|
|
||||||
.Where(x => x.GetCustomAttribute<McpServerToolTypeAttribute>() is not null)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
List<McpServerTool> mcpTools = new List<McpServerTool>();
|
/// <summary>
|
||||||
foreach (var toolClass in toolClasses)
|
/// Agent 发送消息
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("ai-chat/agent/send")]
|
||||||
|
public async Task PostAgentSendAsync([FromBody] AgentSendInput input, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(input.Token, input.ModelId);
|
||||||
|
|
||||||
|
await _aiBlacklistManager.VerifiyAiBlacklist(tokenValidation.UserId);
|
||||||
|
// 验证用户是否为VIP
|
||||||
|
var userInfo = await _accountService.GetAsync(null, null, tokenValidation.UserId);
|
||||||
|
if (userInfo == null)
|
||||||
{
|
{
|
||||||
var instance = LazyServiceProvider.GetRequiredService(toolClass);
|
throw new UserFriendlyException("用户信息不存在");
|
||||||
var toolMethods = toolClass.GetMethods()
|
}
|
||||||
.Where(y => y.GetCustomAttribute<McpServerToolAttribute>() is not null).ToList();
|
|
||||||
foreach (var toolMethod in toolMethods)
|
// 检查是否为VIP(使用RoleCodes判断)
|
||||||
|
if (!userInfo.RoleCodes.Contains(AiHubConst.VipRole) && userInfo.User.UserName != "cc")
|
||||||
|
{
|
||||||
|
throw new UserFriendlyException("该接口为尊享服务专用,需要VIP权限才能使用");
|
||||||
|
}
|
||||||
|
|
||||||
|
//如果是尊享包服务,需要校验是是否尊享包足够
|
||||||
|
if (PremiumPackageConst.ModeIds.Contains(input.ModelId))
|
||||||
|
{
|
||||||
|
// 检查尊享token包用量
|
||||||
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(tokenValidation.UserId);
|
||||||
|
if (availableTokens <= 0)
|
||||||
{
|
{
|
||||||
mcpTools.add(McpServerTool.Create(toolMethod, instance));
|
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = System.Text.Json.JsonSerializer.Serialize(mcpTools.Select(x => x.ProtocolTool).ToList(),
|
await _chatManager.AgentCompleteChatStreamAsync(_httpContextAccessor.HttpContext,
|
||||||
McpJsonUtilities.DefaultOptions);
|
input.SessionId,
|
||||||
return json;
|
input.Content,
|
||||||
|
input.Token,
|
||||||
|
tokenValidation.TokenId,
|
||||||
|
input.ModelId,
|
||||||
|
tokenValidation.UserId,
|
||||||
|
input.Tools,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Agent 工具
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("ai-chat/agent/tool")]
|
||||||
|
public List<AgentToolOutput> GetAgentToolAsync()
|
||||||
|
{
|
||||||
|
var agentTools = _chatManager.GetTools().Select(x => new AgentToolOutput
|
||||||
|
{
|
||||||
|
Code = x.Code,
|
||||||
|
Name = x.Name
|
||||||
|
}).ToList();
|
||||||
|
return agentTools;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 Agent 上下文
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("ai-chat/agent/context/{sessionId}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<string?> GetAgentContextAsync([FromRoute] Guid sessionId)
|
||||||
|
{
|
||||||
|
var data = await _agentStoreRepository.GetFirstAsync(x => x.SessionId == sessionId);
|
||||||
|
return data?.Store;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<Import Project="..\..\..\common.props" />
|
<Import Project="..\..\..\common.props" />
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.5.0" />
|
||||||
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="$(AbpVersion)" />
|
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="$(AbpVersion)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,18 @@ public class ChatManager : DomainService
|
|||||||
_aiGateWayManager = aiGateWayManager;
|
_aiGateWayManager = aiGateWayManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// agent流式对话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext"></param>
|
||||||
|
/// <param name="sessionId"></param>
|
||||||
|
/// <param name="content"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <param name="tokenId"></param>
|
||||||
|
/// <param name="modelId"></param>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="tools"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
public async Task AgentCompleteChatStreamAsync(HttpContext httpContext,
|
public async Task AgentCompleteChatStreamAsync(HttpContext httpContext,
|
||||||
Guid sessionId,
|
Guid sessionId,
|
||||||
string content,
|
string content,
|
||||||
@@ -120,11 +131,11 @@ public class ChatManager : DomainService
|
|||||||
currentThread = agent.GetNewThread();
|
currentThread = agent.GetNewThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//给agent塞入工具
|
||||||
var toolContents = GetTools();
|
var toolContents = GetTools();
|
||||||
var chatOptions = new ChatOptions()
|
var chatOptions = new ChatOptions()
|
||||||
{
|
{
|
||||||
Tools = toolContents.Select(x => (AITool)x).ToList(),
|
Tools = toolContents.Where(x=>tools.Contains(x.Code)).Select(x => (AITool)x.Tool).ToList(),
|
||||||
ToolMode = ChatToolMode.Auto
|
ToolMode = ChatToolMode.Auto
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,13 +241,13 @@ public class ChatManager : DomainService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<AIFunction> GetTools()
|
public List<(string Code, string Name, AIFunction Tool)> GetTools()
|
||||||
{
|
{
|
||||||
var toolClasses = typeof(YiFrameworkAiHubDomainModule).Assembly.GetTypes()
|
var toolClasses = typeof(YiFrameworkAiHubDomainModule).Assembly.GetTypes()
|
||||||
.Where(x => x.GetCustomAttribute<McpServerToolTypeAttribute>() is not null)
|
.Where(x => x.GetCustomAttribute<McpServerToolTypeAttribute>() is not null)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
List<AIFunction> mcpTools = new List<AIFunction>();
|
List<(string Code, string Name, AIFunction Tool)> mcpTools = new();
|
||||||
foreach (var toolClass in toolClasses)
|
foreach (var toolClass in toolClasses)
|
||||||
{
|
{
|
||||||
var instance = LazyServiceProvider.GetRequiredService(toolClass);
|
var instance = LazyServiceProvider.GetRequiredService(toolClass);
|
||||||
@@ -244,10 +255,11 @@ public class ChatManager : DomainService
|
|||||||
.Where(y => y.GetCustomAttribute<McpServerToolAttribute>() is not null).ToList();
|
.Where(y => y.GetCustomAttribute<McpServerToolAttribute>() is not null).ToList();
|
||||||
foreach (var toolMethod in toolMethods)
|
foreach (var toolMethod in toolMethods)
|
||||||
{
|
{
|
||||||
mcpTools.add(AIFunctionFactory.Create(toolMethod, instance));
|
var display = toolMethod.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName;
|
||||||
|
var tool = AIFunctionFactory.Create(toolMethod, instance);
|
||||||
|
mcpTools.add((tool.Name, display, tool));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mcpTools;
|
return mcpTools;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Yi.Framework.AiHub.Domain.Mcp;
|
|||||||
[McpServerToolType]
|
[McpServerToolType]
|
||||||
public class DeepThinkTool:ISingletonDependency
|
public class DeepThinkTool:ISingletonDependency
|
||||||
{
|
{
|
||||||
[McpServerTool, Description("进行深度思考")]
|
[McpServerTool, Description("进行深度思考"),DisplayName("深度思考")]
|
||||||
public void DeepThink()
|
public void DeepThink()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Yi.Framework.AiHub.Domain.Mcp;
|
|||||||
[McpServerToolType]
|
[McpServerToolType]
|
||||||
public class OnlineSearchTool:ISingletonDependency
|
public class OnlineSearchTool:ISingletonDependency
|
||||||
{
|
{
|
||||||
[McpServerTool, Description("进行在线搜索")]
|
[McpServerTool, Description("进行在线搜索"),DisplayName("在线搜索")]
|
||||||
public string OnlineSearch(string keyword)
|
public string OnlineSearch(string keyword)
|
||||||
{
|
{
|
||||||
return "奥德赛第一中学学生会会长是:郭老板";
|
return "奥德赛第一中学学生会会长是:郭老板";
|
||||||
|
|||||||
Reference in New Issue
Block a user