Browse Source

Merge pull request #1460 from colinin/ai

Optimization ai tool
dev
yx lin 21 hours ago
committed by GitHub
parent
commit
c2829d7f3b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionModal.vue
  2. 17
      apps/vben5/packages/@abp/ui/src/components/localizable-input/LocalizableInput.vue
  3. 383
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260327114905_Adjujst-AITool-Description-Length.Designer.cs
  4. 40
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260327114905_Adjujst-AITool-Description-Length.cs
  5. 4
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
  6. 61
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolProvider.cs
  7. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Tools/AIToolDefinitionRecordConsts.cs

15
apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionModal.vue

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { PropertyInfo } from '@abp/ui'; import type { PropertyInfo } from '@abp/ui';
import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface';
import type { FormInstance } from 'ant-design-vue/lib/form'; import type { FormInstance } from 'ant-design-vue/lib/form';
import type { import type {
DefaultOptionType, DefaultOptionType,
@ -152,6 +153,13 @@ function onProviderChange(_: SelectValue, option: DefaultOptionType) {
} }
} }
function onBoolPropChange(key: string, e: CheckboxChangeEvent) {
const propertites = formModel.value.extraProperties ?? {};
propertites[key] = {};
propertites[key] = e.target.checked;
formModel.value.extraProperties = propertites;
}
function onPropChange(key: string, prop: PropertyInfo) { function onPropChange(key: string, prop: PropertyInfo) {
const propertites = formModel.value.extraProperties ?? {}; const propertites = formModel.value.extraProperties ?? {};
propertites[key] = {}; propertites[key] = {};
@ -277,7 +285,8 @@ async function onSubmit() {
:required="prop.required" :required="prop.required"
> >
<Checkbox <Checkbox
v-model:checked="formModel.extraProperties[prop.name]" :checked="formModel.extraProperties[prop.name] === true"
@change="onBoolPropChange(prop.name, $event)"
> >
{{ prop.displayName }} {{ prop.displayName }}
</Checkbox> </Checkbox>
@ -305,8 +314,8 @@ async function onSubmit() {
<FormItemRest> <FormItemRest>
<PropertyTable <PropertyTable
:data="formModel.extraProperties[prop.name]" :data="formModel.extraProperties[prop.name]"
@change="(data) => onPropChange(prop.name, data)" @change="onPropChange(prop.name, $event)"
@delete="(data) => onPropDelete(prop.name, data)" @delete="onPropDelete(prop.name, $event)"
/> />
</FormItemRest> </FormItemRest>
</FormItem> </FormItem>

17
apps/vben5/packages/@abp/ui/src/components/localizable-input/LocalizableInput.vue

@ -11,7 +11,7 @@ import {
useAbpStore, useAbpStore,
useLocalizationSerializer, useLocalizationSerializer,
} from '@abp/core'; } from '@abp/core';
import { Form, Input, Select } from 'ant-design-vue'; import { Form, Input, Select, Textarea } from 'ant-design-vue';
const props = defineProps<{ const props = defineProps<{
allowClear?: boolean; allowClear?: boolean;
@ -125,7 +125,7 @@ function triggerDisplayNameChange(value?: string) {
</script> </script>
<template> <template>
<div class="w-full"> <div class="localizable-input w-full">
<ItemReset> <ItemReset>
<InputGroup> <InputGroup>
<div class="flex flex-row gap-4"> <div class="flex flex-row gap-4">
@ -143,7 +143,7 @@ function triggerDisplayNameChange(value?: string) {
/> />
</div> </div>
<div class="basis-3/5"> <div class="basis-3/5">
<Input <Textarea
v-if="getIsFixed" v-if="getIsFixed"
:allow-clear="props.allowClear" :allow-clear="props.allowClear"
:disabled="props.disabled" :disabled="props.disabled"
@ -151,7 +151,7 @@ function triggerDisplayNameChange(value?: string) {
$t('component.localizable_input.resources.fiexed.placeholder') $t('component.localizable_input.resources.fiexed.placeholder')
" "
:value="state.displayName" :value="state.displayName"
autocomplete="off" :auto-size="{ maxRows: 3 }"
class="w-full" class="w-full"
@change=" @change="
(e: any) => handleDisplayNameChange(e.target.value?.toString()) (e: any) => handleDisplayNameChange(e.target.value?.toString())
@ -179,3 +179,12 @@ function triggerDisplayNameChange(value?: string) {
</ItemReset> </ItemReset>
</div> </div>
</template> </template>
<style scoped lang="scss">
.localizable-input {
:deep(.ant-select-selector .ant-select-selection-item) {
word-break: break-all;
white-space: normal;
}
}
</style>

383
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260327114905_Adjujst-AITool-Description-Length.Designer.cs

@ -0,0 +1,383 @@
// <auto-generated />
using System;
using LINGYUN.Abp.MicroService.AIService;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Volo.Abp.EntityFrameworkCore;
#nullable disable
namespace LINGYUN.Abp.MicroService.AIService.Migrations
{
[DbContext(typeof(AIServiceMigrationsDbContext))]
[Migration("20260327114905_Adjujst-AITool-Description-Length")]
partial class AdjujstAIToolDescriptionLength
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.ToTable("AbpAIConversations", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ReplyMessage")
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITextChatMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<long?>("TotalTokenCount")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITokenUsages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tools.AIToolDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<bool>("IsGlobal")
.HasColumnType("boolean");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIAIToolDefinitionRecords", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("integer");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.Property<string>("Tools")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
#pragma warning restore 612, 618
}
}
}

40
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260327114905_Adjujst-AITool-Description-Length.cs

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LINGYUN.Abp.MicroService.AIService.Migrations
{
/// <inheritdoc />
public partial class AdjujstAIToolDescriptionLength : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "AbpAIAIToolDefinitionRecords",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128,
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "AbpAIAIToolDefinitionRecords",
type: "character varying(128)",
maxLength: 128,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
}
}
}

4
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs

@ -221,8 +221,8 @@ namespace LINGYUN.Abp.MicroService.AIService.Migrations
.HasColumnName("CreatorId"); .HasColumnName("CreatorId");
b.Property<string>("Description") b.Property<string>("Description")
.HasMaxLength(128) .HasMaxLength(1024)
.HasColumnType("character varying(128)"); .HasColumnType("character varying(1024)");
b.Property<string>("ExtraProperties") b.Property<string>("ExtraProperties")
.IsRequired() .IsRequired()

61
aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Mcp/LINGYUN/Abp/AI/Tools/Mcp/McpAIToolProvider.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.AI.Localization; using LINGYUN.Abp.AI.Localization;
using Microsoft.Extensions.AI; using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Client; using ModelContextProtocol.Client;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -61,37 +62,47 @@ public class McpAIToolProvider : IAIToolProvider, ITransientDependency
public async virtual Task<AITool[]> CreateToolsAsync(AIToolDefinition definition) public async virtual Task<AITool[]> CreateToolsAsync(AIToolDefinition definition)
{ {
var httpClient = HttpClientFactory.CreateMcpAIToolClient(); try
var httpClientTransportOptions = new HttpClientTransportOptions
{ {
Endpoint = new Uri(definition.GetMcpEndpoint()), var httpClient = HttpClientFactory.CreateMcpAIToolClient();
AdditionalHeaders = new Dictionary<string, string>(), var httpClientTransportOptions = new HttpClientTransportOptions
TransportMode = definition.GetMcpTransportMode(), {
ConnectionTimeout = definition.GetMcpConnectionTimeout(), Endpoint = new Uri(definition.GetMcpEndpoint()),
MaxReconnectionAttempts = definition.GetMcpMaxReconnectionAttempts(), AdditionalHeaders = new Dictionary<string, string>(),
}; TransportMode = definition.GetMcpTransportMode(),
ConnectionTimeout = definition.GetMcpConnectionTimeout(),
var headers = definition.GetMcpHeaders(); MaxReconnectionAttempts = definition.GetMcpMaxReconnectionAttempts(),
foreach (var header in headers) };
{
httpClientTransportOptions.AdditionalHeaders.TryAdd(header.Key, header.Value);
}
if (definition.IsUseMcpCurrentAccessToken()) var headers = definition.GetMcpHeaders();
{ foreach (var header in headers)
var accessTokenProvider = ServiceProvider.GetRequiredService<IAbpAccessTokenProvider>(); {
httpClientTransportOptions.AdditionalHeaders.TryAdd(header.Key, header.Value);
}
var token = await accessTokenProvider.GetTokenAsync(); if (definition.IsUseMcpCurrentAccessToken())
if (!token.IsNullOrWhiteSpace())
{ {
// TODO: 使用OAuth配置? var accessTokenProvider = ServiceProvider.GetRequiredService<IAbpAccessTokenProvider>();
httpClientTransportOptions.AdditionalHeaders.TryAdd("Authorization", $"Bearer {token}");
var token = await accessTokenProvider.GetTokenAsync();
if (!token.IsNullOrWhiteSpace())
{
// TODO: 使用OAuth配置?
httpClientTransportOptions.AdditionalHeaders.TryAdd("Authorization", $"Bearer {token}");
}
} }
}
var mcpClient = await McpClient.CreateAsync( var mcpClient = await McpClient.CreateAsync(
new HttpClientTransport(httpClientTransportOptions, httpClient)); new HttpClientTransport(httpClientTransportOptions, httpClient));
return (await mcpClient.ListToolsAsync()).ToArray(); return (await mcpClient.ListToolsAsync()).ToArray();
}
catch (Exception ex)
{
ServiceProvider
.GetService<ILogger<McpAIToolProvider>>()
?.LogWarning(ex, "Mcp tool connection failed: {message}", ex.Message);
return [];
}
} }
} }

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Tools/AIToolDefinitionRecordConsts.cs

@ -3,6 +3,6 @@ public static class AIToolDefinitionRecordConsts
{ {
public static int MaxNameLength { get; set; } = 64; public static int MaxNameLength { get; set; } = 64;
public static int MaxProviderLength { get; set; } = 20; public static int MaxProviderLength { get; set; } = 20;
public static int MaxDescriptionLength { get; set; } = 128; public static int MaxDescriptionLength { get; set; } = 1024;
public static int MaxStateCheckersLength { get; set; } = 256; public static int MaxStateCheckersLength { get; set; } = 256;
} }

Loading…
Cancel
Save