Browse Source

feat(ai): Optimize the configuration of AI tools

pull/1464/head
colin 2 months ago
parent
commit
4bcdc417b3
  1. 10
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDisabledState.cs
  2. 60
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
  3. 14
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IWorkspaceAIToolFinder.cs
  4. 70
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/WorkspaceAIToolFinder.cs
  5. 69
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationChangeNameHandler.cs

10
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDisabledState.cs

@ -0,0 +1,10 @@
namespace LINGYUN.Abp.AI.Tools;
public class AIToolDisabledState
{
public bool IsDisabled { get; private set; }
public AIToolDisabledState(bool isDisabled)
{
IsDisabled = isDisabled;
}
}

60
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs

@ -1,10 +1,9 @@
using LINGYUN.Abp.AI.Localization;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -34,55 +33,26 @@ public class AbpAIToolsModule : AbpModule
Configure<AbpAICoreOptions>(options =>
{
options.ChatClientBuildActions.Add((_, __, builder) =>
{
// 启用以支持函数式工具
builder.UseFunctionInvocation();
return Task.FromResult(builder);
});
options.ChatClientBuildActions.Add(async (workspace, sp, builder) =>
{
var useAITools = new List<AITool>();
var useAIToolDefinitions = new List<AIToolDefinition>();
var aiToolFactory = sp.GetRequiredService<IAIToolFactory>();
var aiToolDefinitionManager = sp.GetRequiredService<IAIToolDefinitionManager>();
var aiToolDefinitions = await aiToolDefinitionManager.GetAllAsync();
if (workspace.Tools.Count > 0)
IList<AITool>? workspaceAITools = default!;
var workspaceAIToolFinder = sp.GetService<IWorkspaceAIToolFinder>();
if (workspaceAIToolFinder != null && workspaceAIToolFinder.IsAIToolEnabled())
{
useAIToolDefinitions.AddRange(aiToolDefinitions.Where(aiTool => workspace.Tools.Contains(aiTool.Name)));
}
foreach (var globalAIToolDefinition in aiToolDefinitions.Where(aiTool => aiTool.IsGlobal))
{
if (!useAIToolDefinitions.Any(tool => tool.Name == globalAIToolDefinition.Name))
{
useAIToolDefinitions.Add(globalAIToolDefinition);
}
workspaceAITools = await workspaceAIToolFinder.GetToolsAsync(workspace);
}
foreach (var aiToolDefinition in useAIToolDefinitions)
{
var aiTools = await aiToolFactory.CreateTool(aiToolDefinition);
if (aiTools.Length > 0)
{
useAITools.AddRange(aiTools);
}
}
return builder.ConfigureOptions(ai =>
{
ai.ToolMode = ChatToolMode.Auto;
ai.AllowMultipleToolCalls = true;
ai.Tools ??= [];
foreach (var aiTool in useAITools)
return builder
.ConfigureOptions(config =>
{
ai.Tools.Add(aiTool);
}
});
config.ToolMode = ChatToolMode.Auto;
config.AllowMultipleToolCalls = true;
// 添加发现的工具
config.Tools = workspaceAITools;
})
// 启用以支持函数式工具
.UseFunctionInvocation();
});
});

14
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IWorkspaceAIToolFinder.cs

@ -0,0 +1,14 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using System;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tools;
public interface IWorkspaceAIToolFinder
{
IDisposable DisableAITool();
Task<AITool[]?> GetToolsAsync(WorkspaceDefinition workspace);
bool IsAIToolEnabled();
}

70
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/WorkspaceAIToolFinder.cs

@ -0,0 +1,70 @@
using LINGYUN.Abp.AI.Workspaces;
using Microsoft.Extensions.AI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace LINGYUN.Abp.AI.Tools;
public class WorkspaceAIToolFinder : IWorkspaceAIToolFinder, ITransientDependency
{
private const string AIToolDisabledScopeKey = "Abp.AI.Tools.DisabledAITool";
private readonly IAIToolFactory _aiToolFactory;
private readonly IAIToolDefinitionManager _aiToolDefinitionManager;
private readonly IAmbientScopeProvider<AIToolDisabledState> _aiToolDisabledState;
public WorkspaceAIToolFinder(
IAIToolFactory aiToolFactory,
IAIToolDefinitionManager aiToolDefinitionManager,
IAmbientScopeProvider<AIToolDisabledState> aiToolDisabledState)
{
_aiToolFactory = aiToolFactory;
_aiToolDefinitionManager = aiToolDefinitionManager;
_aiToolDisabledState = aiToolDisabledState;
}
public virtual IDisposable DisableAITool()
{
return _aiToolDisabledState.BeginScope(AIToolDisabledScopeKey, new AIToolDisabledState(true));
}
public async virtual Task<AITool[]?> GetToolsAsync(WorkspaceDefinition workspace)
{
var useAITools = new List<AITool>();
var useAIToolDefinitions = new List<AIToolDefinition>();
var aiToolDefinitions = await _aiToolDefinitionManager.GetAllAsync();
if (workspace.Tools.Count > 0)
{
useAIToolDefinitions.AddRange(aiToolDefinitions.Where(aiTool => workspace.Tools.Contains(aiTool.Name)));
}
foreach (var globalAIToolDefinition in aiToolDefinitions.Where(aiTool => aiTool.IsGlobal))
{
if (!useAIToolDefinitions.Any(tool => tool.Name == globalAIToolDefinition.Name))
{
useAIToolDefinitions.Add(globalAIToolDefinition);
}
}
foreach (var aiToolDefinition in useAIToolDefinitions)
{
var aiTools = await _aiToolFactory.CreateTool(aiToolDefinition);
if (aiTools.Length > 0)
{
useAITools.AddRange(aiTools);
}
}
return useAITools.ToArray();
}
public virtual bool IsAIToolEnabled()
{
var state = _aiToolDisabledState.GetValue(AIToolDisabledScopeKey);
return state == null || !state.IsDisabled;
}
}

69
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationChangeNameHandler.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.AI;
using LINGYUN.Abp.AI.Tools;
using LINGYUN.Abp.AIManagement.Localization;
using LINGYUN.Abp.AIManagement.Tokens;
using Microsoft.Extensions.AI;
@ -25,6 +26,7 @@ public class ConversationChangeNameHandler :
private readonly IGuidGenerator _guidGenerator;
private readonly IAbpDistributedLock _distributedLock;
private readonly IChatClientFactory _chatClientFactory;
private readonly IWorkspaceAIToolFinder _workspaceAIToolFinder;
private readonly IStringLocalizer<AIManagementResource> _stringLocalizer;
private readonly ITokenUsageRecordRepository _tokenUsageRecordRepository;
private readonly IConversationRecordRepository _conversationRecordRepository;
@ -34,7 +36,8 @@ public class ConversationChangeNameHandler :
IServiceProvider serviceProvider,
IGuidGenerator guidGenerator,
IAbpDistributedLock distributedLock,
IChatClientFactory chatClientFactory,
IChatClientFactory chatClientFactory,
IWorkspaceAIToolFinder workspaceAIToolFinder,
IStringLocalizer<AIManagementResource> stringLocalizer,
ITokenUsageRecordRepository tokenUsageRecordRepository,
IConversationRecordRepository conversationRecordRepository,
@ -44,6 +47,7 @@ public class ConversationChangeNameHandler :
_guidGenerator = guidGenerator;
_distributedLock = distributedLock;
_chatClientFactory = chatClientFactory;
_workspaceAIToolFinder = workspaceAIToolFinder;
_stringLocalizer = stringLocalizer;
_tokenUsageRecordRepository = tokenUsageRecordRepository;
_conversationRecordRepository = conversationRecordRepository;
@ -96,42 +100,41 @@ public class ConversationChangeNameHandler :
{
var chatClient = await _chatClientFactory.CreateAsync(chatMessage.Workspace);
var instructions = _stringLocalizer["DesignConversationNamePrompt", ConversationRecordConsts.MaxNameLength].Value;
var aiAgent = chatClient
.AsBuilder()
.ConfigureOptions(options =>
{
// 不受工具影响
options.Tools = [];
})
.BuildAIAgent(
instructions: instructions,
services: _serviceProvider);
var agentRunRes = await aiAgent.RunAsync([
new ChatMessage(ChatRole.System, instructions),
new ChatMessage(ChatRole.User, chatMessage.Content)]);
// 禁用AI工具
using (_workspaceAIToolFinder.DisableAITool())
{
var aiAgent = chatClient
.CreateAIAgent(
instructions: instructions,
services: _serviceProvider);
conversation.SetName(
agentRunRes.Text.Length > ConversationRecordConsts.MaxNameLength
? agentRunRes.Text[..ConversationRecordConsts.MaxNameLength]
: agentRunRes.Text);
var agentRunRes = await aiAgent.RunAsync([
new ChatMessage(ChatRole.System, instructions),
new ChatMessage(ChatRole.User, chatMessage.Content)]);
await _conversationRecordRepository.UpdateAsync(conversation);
conversation.SetName(
agentRunRes.Text.Length > ConversationRecordConsts.MaxNameLength
? chatMessage.Content[..ConversationRecordConsts.MaxNameLength]
: agentRunRes.Text);
if (agentRunRes.Usage != null)
{
var tokenUsageRecord = new TokenUsageRecord(
_guidGenerator.Create(),
chatMessage.Id,
conversation.Id,
agentRunRes.Usage.InputTokenCount,
agentRunRes.Usage.OutputTokenCount,
agentRunRes.Usage.TotalTokenCount,
agentRunRes.Usage.CachedInputTokenCount,
agentRunRes.Usage.ReasoningTokenCount,
chatMessage.TenantId);
await _tokenUsageRecordRepository.InsertAsync(tokenUsageRecord);
await _conversationRecordRepository.UpdateAsync(conversation);
if (agentRunRes.Usage != null)
{
var tokenUsageRecord = new TokenUsageRecord(
_guidGenerator.Create(),
chatMessage.Id,
conversation.Id,
agentRunRes.Usage.InputTokenCount,
agentRunRes.Usage.OutputTokenCount,
agentRunRes.Usage.TotalTokenCount,
agentRunRes.Usage.CachedInputTokenCount,
agentRunRes.Usage.ReasoningTokenCount,
chatMessage.TenantId);
await _tokenUsageRecordRepository.InsertAsync(tokenUsageRecord);
}
}
}
}

Loading…
Cancel
Save