feat: 初始化NewLife Studio项目,完成基础框架与数据管理模块
何炳宏 authored at 2026-05-26 12:09:09
3.15 KiB
NewLife.Studio
using System.Text.Json;
using NewLife.Studio.AI.Models;
using NewLife.Log;

namespace NewLife.Studio.AI.ToolCalling;

/// <summary>AI 服务 — 管理对话历史和 Tool Calling 循环</summary>
public class AIService
{
    private readonly IAIProvider _provider;
    private readonly ToolRegistry _toolRegistry;
    private readonly List<ChatMessage> _history = [];
    private string? _systemPrompt;

    public AIService(IAIProvider provider, ToolRegistry toolRegistry, string? systemPrompt = null)
    {
        _provider = provider;
        _toolRegistry = toolRegistry;
        _systemPrompt = systemPrompt;

        if (_systemPrompt != null)
        {
            _history.Add(new ChatMessage { Role = "system", Content = _systemPrompt });
        }
    }

    public IReadOnlyList<ChatMessage> History => _history.AsReadOnly();

    /// <summary>发送用户消息,执行完整的 Tool Calling 循环</summary>
    public async Task<string> ChatAsync(string userMessage, Action<ToolCall, ToolResult>? onToolCall = null)
    {
        _history.Add(new ChatMessage { Role = "user", Content = userMessage });

        var tools = _toolRegistry.GetAllDefinitions();

        for (int loop = 0; loop < 5; loop++) // 最多 5 轮
        {
            var request = new ChatRequest
            {
                Messages = [.._history],
                Tools = tools.Count > 0 ? tools : null
            };

            var response = await _provider.ChatAsync(request);

            var choice = response.Choices.FirstOrDefault();
            if (choice == null)
                break;

            var msg = choice.Message;

            // 检查是否有 tool_calls
            if (msg.ToolCalls is { Count: > 0 })
            {
                // 添加 assistant 消息(带 tool_calls)
                _history.Add(new ChatMessage
                {
                    Role = "assistant",
                    Content = msg.Content,
                    ToolCalls = msg.ToolCalls
                });

                // 执行每个工具调用
                foreach (var tc in msg.ToolCalls)
                {
                    XTrace.WriteLine($"AI ToolCall: {tc.Function.Name}({tc.Function.Arguments})");
                    var result = await _toolRegistry.ExecuteAsync(tc);
                    onToolCall?.Invoke(tc, result);

                    _history.Add(new ChatMessage
                    {
                        Role = "tool",
                        ToolCallId = tc.Id,
                        Content = result.Error ?? result.Output
                    });
                }

                continue; // 继续循环,让 AI 处理工具结果
            }

            // 无 tool_calls,返回内容
            if (msg.Content != null)
            {
                _history.Add(new ChatMessage { Role = "assistant", Content = msg.Content });
                return msg.Content;
            }

            break;
        }

        return "AI 未返回有效响应";
    }

    public void ClearHistory()
    {
        _history.Clear();
        if (_systemPrompt != null)
        {
            _history.Add(new ChatMessage { Role = "system", Content = _systemPrompt });
        }
    }
}