feat: 完成agent功能

This commit is contained in:
chenchun
2025-12-24 14:17:32 +08:00
parent 9ca3cd0b1a
commit ee4cb20eef
6 changed files with 100 additions and 70 deletions

View File

@@ -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; }
}

View File

@@ -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,6 +159,43 @@ public class AiChatService : ApplicationService
CurrentUser.Id, sessionId, null, cancellationToken); CurrentUser.Id, sessionId, null, cancellationToken);
} }
/// <summary>
/// 发送消息
/// </summary>
/// <param name="input"></param>
/// <param name="cancellationToken"></param>
[HttpPost("ai-chat/FileMaster/send")]
public async Task PostFileMasterSendAsync([FromBody] ThorChatCompletionsRequest input,
CancellationToken cancellationToken)
{
if (!string.IsNullOrWhiteSpace(input.Model))
{
throw new BusinessException("当前接口不支持第三方使用");
}
if (CurrentUser.IsAuthenticated)
{
await _aiBlacklistManager.VerifiyAiBlacklist(CurrentUser.GetId());
if (CurrentUser.IsAiVip())
{
input.Model = "gpt-5-chat";
}
else
{
input.Model = "gpt-4.1-mini";
}
}
else
{
input.Model = "DeepSeek-R1-0528";
}
//ai网关代理httpcontext
await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
CurrentUser.Id, null, null, cancellationToken);
}
/// <summary> /// <summary>
/// Agent 发送消息 /// Agent 发送消息
/// </summary> /// </summary>
@@ -199,62 +241,29 @@ public class AiChatService : ApplicationService
} }
/// <summary> /// <summary>
/// 发送消息 /// 获取 Agent 工具
/// </summary> /// </summary>
/// <param name="input"></param> /// <returns></returns>
/// <param name="cancellationToken"></param> [HttpPost("ai-chat/agent/tool")]
[HttpPost("ai-chat/FileMaster/send")] public List<AgentToolOutput> GetAgentToolAsync()
public async Task PostFileMasterSendAsync([FromBody] ThorChatCompletionsRequest input,
CancellationToken cancellationToken)
{ {
if (!string.IsNullOrWhiteSpace(input.Model)) var agentTools = _chatManager.GetTools().Select(x => new AgentToolOutput
{ {
throw new BusinessException("当前接口不支持第三方使用"); Code = x.Code,
} Name = x.Name
}).ToList();
if (CurrentUser.IsAuthenticated) return agentTools;
{
await _aiBlacklistManager.VerifiyAiBlacklist(CurrentUser.GetId());
if (CurrentUser.IsAiVip())
{
input.Model = "gpt-5-chat";
}
else
{
input.Model = "gpt-4.1-mini";
}
}
else
{
input.Model = "DeepSeek-R1-0528";
}
//ai网关代理httpcontext
await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
CurrentUser.Id, null, null, cancellationToken);
} }
[HttpPost("ai-chat/tool")] /// <summary>
public string GetTool() /// 获取 Agent 上下文
/// </summary>
/// <returns></returns>
[HttpPost("ai-chat/agent/context/{sessionId}")]
[Authorize]
public async Task<string?> GetAgentContextAsync([FromRoute] Guid sessionId)
{ {
var toolClasses = typeof(YiFrameworkAiHubDomainModule).Assembly.GetTypes() var data = await _agentStoreRepository.GetFirstAsync(x => x.SessionId == sessionId);
.Where(x => x.GetCustomAttribute<McpServerToolTypeAttribute>() is not null) return data?.Store;
.ToList();
List<McpServerTool> mcpTools = new List<McpServerTool>();
foreach (var toolClass in toolClasses)
{
var instance = LazyServiceProvider.GetRequiredService(toolClass);
var toolMethods = toolClass.GetMethods()
.Where(y => y.GetCustomAttribute<McpServerToolAttribute>() is not null).ToList();
foreach (var toolMethod in toolMethods)
{
mcpTools.add(McpServerTool.Create(toolMethod, instance));
}
}
var json = System.Text.Json.JsonSerializer.Serialize(mcpTools.Select(x => x.ProtocolTool).ToList(),
McpJsonUtilities.DefaultOptions);
return json;
} }
} }

View File

@@ -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>

View File

@@ -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;
} }

View File

@@ -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()
{ {

View File

@@ -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 "奥德赛第一中学学生会会长是:郭老板";